From 4a8efef9d0e86b3b8f908d3600244f2409a603af Mon Sep 17 00:00:00 2001 From: dkaraush Date: Tue, 20 Feb 2024 12:03:54 +0400 Subject: [PATCH] update to 10.8.1 (4404) --- .../release/AndroidManifest_standalone.xml | 10 + TMessagesProj/jni/audio.c | 171 ++- TMessagesProj/jni/opus/src/opus_encoder.c | 2 + TMessagesProj/jni/tgnet/Connection.cpp | 2 +- TMessagesProj/jni/tgnet/ConnectionSocket.cpp | 11 +- .../jni/tgnet/ConnectionsManager.cpp | 25 +- TMessagesProj/jni/tgnet/ConnectionsManager.h | 1 - .../telegram/messenger/ApplicationLoader.java | 31 + .../telegram/messenger/BillingController.java | 68 +- .../messenger/ChannelBoostsController.java | 17 + .../ChatMessagesMetadataController.java | 2 +- .../org/telegram/messenger/ChatObject.java | 74 +- .../telegram/messenger/FileLoadOperation.java | 37 +- .../org/telegram/messenger/FileLoader.java | 8 +- .../messenger/FileLoaderPriorityQueue.java | 6 + .../org/telegram/messenger/ImageReceiver.java | 3 + .../telegram/messenger/LocaleController.java | 5 +- .../telegram/messenger/MediaController.java | 194 ++- .../messenger/MediaDataController.java | 113 +- .../org/telegram/messenger/MessageObject.java | 115 +- .../messenger/MessagesController.java | 401 ++++--- .../telegram/messenger/MessagesStorage.java | 9 +- .../messenger/NotificationCenter.java | 6 +- .../messenger/PushListenerController.java | 4 + .../messenger/SavedMessagesController.java | 4 +- .../messenger/SendMessagesHelper.java | 4 +- .../org/telegram/messenger/SharedConfig.java | 9 + .../messenger/camera/Camera2Session.java | 538 +++++++++ .../messenger/camera/CameraController.java | 375 +++--- .../camera/CameraSessionWrapper.java | 206 ++++ .../telegram/messenger/camera/CameraView.java | 145 ++- .../messenger/camera/DefaultCameraAPI.java | 4 - .../main/java/org/telegram/tgnet/TLRPC.java | 648 +++++++++- .../org/telegram/tgnet/tl/TL_stories.java | 158 ++- .../ui/ActionBar/ActionBarMenuItem.java | 3 + .../ui/ActionBar/ActionBarMenuSubItem.java | 13 +- .../ui/ActionBar/ActionBarPopupWindow.java | 2 +- .../telegram/ui/ActionBar/EmojiThemes.java | 26 +- .../telegram/ui/ActionBar/SimpleTextView.java | 2 +- .../ui/Adapters/DrawerLayoutAdapter.java | 33 +- .../java/org/telegram/ui/ArticleViewer.java | 154 ++- .../java/org/telegram/ui/BoostsActivity.java | 846 +++++++++++++ .../org/telegram/ui/CameraScanActivity.java | 8 +- .../telegram/ui/Cells/ChatMessageCell.java | 149 ++- .../org/telegram/ui/Cells/DialogCell.java | 59 +- .../telegram/ui/Cells/DialogsHintCell.java | 17 +- .../telegram/ui/Cells/DrawerActionCell.java | 10 + .../org/telegram/ui/Cells/LanguageCell.java | 4 +- .../org/telegram/ui/Cells/MentionCell.java | 6 +- .../org/telegram/ui/Cells/StickerSetCell.java | 98 +- .../java/org/telegram/ui/Cells/TextCell.java | 14 +- .../ui/Cells/TextSelectionHelper.java | 8 + .../ui/Cells/ThemePreviewMessagesCell.java | 9 +- .../telegram/ui/ChannelAdminLogActivity.java | 7 + .../org/telegram/ui/ChannelBoostLayout.java | 21 +- .../org/telegram/ui/ChannelColorActivity.java | 442 +++++-- .../telegram/ui/ChannelWallpaperActivity.java | 7 +- .../java/org/telegram/ui/ChatActivity.java | 262 +++- .../org/telegram/ui/ChatEditActivity.java | 33 +- .../telegram/ui/ChatRightsEditActivity.java | 6 + .../org/telegram/ui/ChatUsersActivity.java | 120 +- .../ui/Components/AnimatedEmojiDrawable.java | 9 + .../ui/Components/BulletinFactory.java | 6 +- .../ui/Components/ChatActivityEnterView.java | 521 +++++--- .../ui/Components/ChatAttachAlert.java | 60 +- .../ChatAttachAlertPhotoLayout.java | 35 +- .../ChatAttachRestrictedLayout.java | 3 +- .../ui/Components/ChatAvatarContainer.java | 8 - .../ui/Components/ChatGreetingsView.java | 2 + .../ui/Components/ChatThemeBottomSheet.java | 11 +- .../telegram/ui/Components/EditTextEmoji.java | 2 +- .../ui/Components/EmojiTabsStrip.java | 1 + .../org/telegram/ui/Components/EmojiView.java | 97 +- .../ui/Components/InstantCameraView.java | 243 +++- .../ui/Components/JoinGroupAlert.java | 43 +- .../org/telegram/ui/Components/Loadable.java | 6 + .../telegram/ui/Components/MediaActivity.java | 1 + .../ui/Components/MentionsContainerView.java | 9 +- .../ui/Components/MessagePreviewView.java | 5 + .../Components/Premium/LimitPreviewView.java | 231 +++- .../Premium/LimitReachedBottomSheet.java | 622 ++++++++-- .../Components/Premium/PremiumButtonView.java | 8 +- .../Components/Premium/PremiumGradient.java | 28 +- .../Components/Premium/StarParticlesView.java | 19 +- .../Premium/boosts/BoostCounterSpan.java | 100 ++ .../Premium/boosts/BoostDialogs.java | 52 +- .../Premium/boosts/BoostRepository.java | 9 +- .../boosts/BoostViaGiftsBottomSheet.java | 14 +- .../Premium/boosts/DiscountSpan.java | 2 +- .../Premium/boosts/SelectorBottomSheet.java | 11 +- .../Premium/boosts/adapters/BoostAdapter.java | 39 +- .../Premium/boosts/cells/AddChannelCell.java | 2 +- .../Premium/boosts/cells/ChatCell.java | 32 +- .../cells/DurationWithDiscountCell.java | 15 +- .../Premium/boosts/cells/HeaderCell.java | 6 +- .../boosts/cells/ParticipantsTypeCell.java | 8 +- .../Premium/boosts/cells/TableCell.java | 7 +- .../boosts/cells/msg/GiveawayMessageCell.java | 7 +- .../cells/selector/SelectorUserCell.java | 21 +- .../Components/Reactions/ReactionsUtils.java | 10 +- .../Components/ReactionsContainerLayout.java | 21 +- .../ui/Components/SearchTagsList.java | 7 +- .../ui/Components/SharedMediaLayout.java | 6 +- .../ui/Components/SlideChooseView.java | 34 + .../telegram/ui/Components/StickersAlert.java | 2 +- .../ui/Components/ThemeSmallPreviewView.java | 14 +- .../ui/Components/TranscribeButton.java | 16 + .../org/telegram/ui/Components/UndoView.java | 2 +- .../org/telegram/ui/ContentPreviewViewer.java | 13 +- .../java/org/telegram/ui/DialogsActivity.java | 77 +- .../telegram/ui/GradientHeaderActivity.java | 520 ++++++++ .../org/telegram/ui/GroupColorActivity.java | 316 +++++ .../telegram/ui/GroupStickersActivity.java | 483 ++++++-- .../java/org/telegram/ui/LaunchActivity.java | 37 +- .../org/telegram/ui/PeerColorActivity.java | 47 +- .../telegram/ui/PremiumPreviewFragment.java | 9 +- .../java/org/telegram/ui/ProfileActivity.java | 105 +- .../org/telegram/ui/StatisticActivity.java | 25 +- .../ui/Stories/ChannelBoostUtilities.java | 4 +- .../telegram/ui/Stories/PeerStoriesView.java | 273 +++-- .../ui/Stories/StoriesController.java | 64 +- .../telegram/ui/Stories/StoriesStorage.java | 3 + .../telegram/ui/Stories/StoriesUtilities.java | 43 +- .../recorder/ButtonWithCounterView.java | 57 +- .../recorder/CaptionContainerView.java | 13 +- .../ui/Stories/recorder/DualCameraView.java | 9 +- .../ui/Stories/recorder/HintView2.java | 18 +- .../ui/Stories/recorder/PreviewView.java | 2 +- .../Stories/recorder/RoundVideoRecorder.java | 2 +- .../recorder/StoryPrivacyBottomSheet.java | 11 +- .../ui/Stories/recorder/StoryRecorder.java | 12 +- .../org/telegram/ui/ThemePreviewActivity.java | 12 +- .../java/org/telegram/ui/TopicsFragment.java | 31 +- .../res/drawable-hdpi/filled_boost_plus.png | Bin 0 -> 759 bytes .../main/res/drawable-hdpi/filled_info.png | Bin 0 -> 657 bytes .../main/res/drawable-hdpi/large_boosts.png | Bin 0 -> 1572 bytes .../drawable-hdpi/menu_edit_appearance.png | Bin 0 -> 1251 bytes .../res/drawable-hdpi/menu_feature_pack.png | Bin 0 -> 1172 bytes .../drawable-hdpi/menu_feature_translate.png | Bin 0 -> 946 bytes .../res/drawable-hdpi/menu_feature_voice.png | Bin 0 -> 1128 bytes .../mini_boost_profile_badge.png | Bin 0 -> 401 bytes .../mini_boost_profile_badge2.png | Bin 0 -> 505 bytes .../res/drawable-mdpi/filled_boost_plus.png | Bin 0 -> 557 bytes .../main/res/drawable-mdpi/filled_info.png | Bin 0 -> 475 bytes .../main/res/drawable-mdpi/large_boosts.png | Bin 0 -> 1093 bytes .../drawable-mdpi/menu_edit_appearance.png | Bin 0 -> 815 bytes .../res/drawable-mdpi/menu_feature_pack.png | Bin 0 -> 806 bytes .../drawable-mdpi/menu_feature_translate.png | Bin 0 -> 627 bytes .../res/drawable-mdpi/menu_feature_voice.png | Bin 0 -> 764 bytes .../mini_boost_profile_badge.png | Bin 0 -> 318 bytes .../mini_boost_profile_badge2.png | Bin 0 -> 369 bytes .../res/drawable-xhdpi/filled_boost_plus.png | Bin 0 -> 987 bytes .../main/res/drawable-xhdpi/filled_info.png | Bin 0 -> 1032 bytes .../main/res/drawable-xhdpi/large_boosts.png | Bin 0 -> 2216 bytes .../drawable-xhdpi/menu_edit_appearance.png | Bin 0 -> 1680 bytes .../res/drawable-xhdpi/menu_feature_pack.png | Bin 0 -> 1645 bytes .../drawable-xhdpi/menu_feature_translate.png | Bin 0 -> 1218 bytes .../res/drawable-xhdpi/menu_feature_voice.png | Bin 0 -> 1523 bytes .../mini_boost_profile_badge.png | Bin 0 -> 494 bytes .../mini_boost_profile_badge2.png | Bin 0 -> 696 bytes .../res/drawable-xxhdpi/filled_boost_plus.png | Bin 0 -> 1352 bytes .../main/res/drawable-xxhdpi/filled_info.png | Bin 0 -> 1392 bytes .../main/res/drawable-xxhdpi/large_boosts.png | Bin 0 -> 3559 bytes .../drawable-xxhdpi/menu_edit_appearance.png | Bin 0 -> 2554 bytes .../res/drawable-xxhdpi/menu_feature_pack.png | Bin 0 -> 2412 bytes .../menu_feature_translate.png | Bin 0 -> 1860 bytes .../drawable-xxhdpi/menu_feature_voice.png | Bin 0 -> 2246 bytes .../mini_boost_profile_badge.png | Bin 0 -> 688 bytes .../mini_boost_profile_badge2.png | Bin 0 -> 970 bytes TMessagesProj/src/main/res/raw/done.json | 1 + .../main/res/raw/instant_lanczos_frag.glsl | 31 + .../res/raw/instant_lanczos_frag_oes.glsl | 33 + .../main/res/raw/instant_lanczos_vert.glsl | 37 + TMessagesProj/src/main/res/values/strings.xml | 169 ++- .../messenger/ApplicationLoaderImpl.java | 134 +++ .../telegram/messenger/SMSJobController.java | 725 +++++++++++ .../telegram/messenger/SMSResultService.java | 12 + .../java/org/telegram/tgnet/TL_smsjobs.java | 238 ++++ .../org/telegram/ui/SMSStatsActivity.java | 1065 +++++++++++++++++ .../org/telegram/ui/SMSSubscribeSheet.java | 397 ++++++ .../main/res/drawable-hdpi/large_sms_code.png | Bin 0 -> 2350 bytes .../res/drawable-hdpi/menu_feature_gift.png | Bin 0 -> 1188 bytes .../drawable-hdpi/menu_feature_premium.png | Bin 0 -> 1231 bytes .../res/drawable-hdpi/menu_feature_sms.png | Bin 0 -> 1459 bytes .../src/main/res/drawable-hdpi/menu_intro.png | Bin 0 -> 603 bytes .../res/drawable-hdpi/menu_premium_main.png | Bin 0 -> 1068 bytes .../res/drawable-hdpi/menu_sms_history.png | Bin 0 -> 1136 bytes .../res/drawable-hdpi/menu_storage_path.png | Bin 0 -> 679 bytes .../res/drawable-hdpi/permissions_sms.png | Bin 0 -> 2537 bytes .../main/res/drawable-mdpi/large_sms_code.png | Bin 0 -> 1560 bytes .../res/drawable-mdpi/menu_feature_gift.png | Bin 0 -> 793 bytes .../drawable-mdpi/menu_feature_premium.png | Bin 0 -> 786 bytes .../res/drawable-mdpi/menu_feature_sms.png | Bin 0 -> 848 bytes .../src/main/res/drawable-mdpi/menu_intro.png | Bin 0 -> 522 bytes .../res/drawable-mdpi/menu_premium_main.png | Bin 0 -> 728 bytes .../res/drawable-mdpi/menu_sms_history.png | Bin 0 -> 768 bytes .../res/drawable-mdpi/menu_storage_path.png | Bin 0 -> 529 bytes .../res/drawable-mdpi/permissions_sms.png | Bin 0 -> 1621 bytes .../res/drawable-xhdpi/large_sms_code.png | Bin 0 -> 3467 bytes .../res/drawable-xhdpi/menu_feature_gift.png | Bin 0 -> 1523 bytes .../drawable-xhdpi/menu_feature_premium.png | Bin 0 -> 1668 bytes .../res/drawable-xhdpi/menu_feature_sms.png | Bin 0 -> 1991 bytes .../main/res/drawable-xhdpi/menu_intro.png | Bin 0 -> 910 bytes .../res/drawable-xhdpi/menu_premium_main.png | Bin 0 -> 1441 bytes .../res/drawable-xhdpi/menu_sms_history.png | Bin 0 -> 1501 bytes .../res/drawable-xhdpi/menu_storage_path.png | Bin 0 -> 938 bytes .../res/drawable-xhdpi/permissions_sms.png | Bin 0 -> 3433 bytes .../res/drawable-xxhdpi/large_sms_code.png | Bin 0 -> 5414 bytes .../res/drawable-xxhdpi/menu_feature_gift.png | Bin 0 -> 2236 bytes .../drawable-xxhdpi/menu_feature_premium.png | Bin 0 -> 2572 bytes .../res/drawable-xxhdpi/menu_feature_sms.png | Bin 0 -> 3086 bytes .../main/res/drawable-xxhdpi/menu_intro.png | Bin 0 -> 1025 bytes .../res/drawable-xxhdpi/menu_premium_main.png | Bin 0 -> 2101 bytes .../res/drawable-xxhdpi/menu_sms_history.png | Bin 0 -> 2229 bytes .../res/drawable-xxhdpi/menu_storage_path.png | Bin 0 -> 1226 bytes .../res/drawable-xxhdpi/permissions_sms.png | Bin 0 -> 5587 bytes .../src/main/res/drawable/left_sms.xml | 37 + .../src/main/res/values/strings.xml | 69 ++ gradle.properties | 4 +- 219 files changed, 11556 insertions(+), 1754 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/camera/Camera2Session.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSessionWrapper.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/camera/DefaultCameraAPI.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/BoostsActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Loadable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterSpan.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/GradientHeaderActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/GroupColorActivity.java create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/filled_boost_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/filled_info.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/large_boosts.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_edit_appearance.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_feature_pack.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_feature_translate.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_feature_voice.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/mini_boost_profile_badge.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/mini_boost_profile_badge2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/filled_boost_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/filled_info.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/large_boosts.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_edit_appearance.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_feature_pack.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_feature_translate.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_feature_voice.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/mini_boost_profile_badge.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/mini_boost_profile_badge2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/filled_boost_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/filled_info.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/large_boosts.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_edit_appearance.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_pack.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_translate.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_voice.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/mini_boost_profile_badge.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/mini_boost_profile_badge2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/filled_boost_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/filled_info.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/large_boosts.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_edit_appearance.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_pack.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_translate.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_voice.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/mini_boost_profile_badge.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/mini_boost_profile_badge2.png create mode 100644 TMessagesProj/src/main/res/raw/done.json create mode 100644 TMessagesProj/src/main/res/raw/instant_lanczos_frag.glsl create mode 100644 TMessagesProj/src/main/res/raw/instant_lanczos_frag_oes.glsl create mode 100644 TMessagesProj/src/main/res/raw/instant_lanczos_vert.glsl create mode 100644 TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/SMSJobController.java create mode 100644 TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/SMSResultService.java create mode 100644 TMessagesProj_AppStandalone/src/main/java/org/telegram/tgnet/TL_smsjobs.java create mode 100644 TMessagesProj_AppStandalone/src/main/java/org/telegram/ui/SMSStatsActivity.java create mode 100644 TMessagesProj_AppStandalone/src/main/java/org/telegram/ui/SMSSubscribeSheet.java create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/large_sms_code.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_feature_gift.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_feature_premium.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_feature_sms.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_intro.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_premium_main.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_sms_history.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_storage_path.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/permissions_sms.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/large_sms_code.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_feature_gift.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_feature_premium.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_feature_sms.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_intro.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_premium_main.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_sms_history.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_storage_path.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/permissions_sms.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/large_sms_code.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_feature_gift.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_feature_premium.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_feature_sms.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_intro.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_premium_main.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_sms_history.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_storage_path.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/permissions_sms.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/large_sms_code.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_feature_gift.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_feature_premium.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_feature_sms.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_intro.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_premium_main.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_sms_history.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_storage_path.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/permissions_sms.png create mode 100644 TMessagesProj_AppStandalone/src/main/res/drawable/left_sms.xml create mode 100644 TMessagesProj_AppStandalone/src/main/res/values/strings.xml diff --git a/TMessagesProj/config/release/AndroidManifest_standalone.xml b/TMessagesProj/config/release/AndroidManifest_standalone.xml index 344cba957..854a516c2 100644 --- a/TMessagesProj/config/release/AndroidManifest_standalone.xml +++ b/TMessagesProj/config/release/AndroidManifest_standalone.xml @@ -20,6 +20,10 @@ + + + + + + + + pos > p->maxlen - 4) { return 0; @@ -233,6 +246,7 @@ ogg_int32_t _packetId; OpusEncoder *_encoder = 0; uint8_t *_packet = 0; ogg_stream_state os; +const char *_filePath; FILE *_fileOs = 0; oe_enc_opt inopt; OpusHeader header; @@ -277,6 +291,10 @@ void cleanupRecorder() { size_segments = 0; last_segments = 0; last_granulepos = 0; + if (_filePath) { + free(_filePath); + _filePath = 0; + } memset(&os, 0, sizeof(ogg_stream_state)); memset(&inopt, 0, sizeof(oe_enc_opt)); memset(&header, 0, sizeof(OpusHeader)); @@ -294,7 +312,11 @@ int initRecorder(const char *path, opus_int32 sampleRate) { LOGE("path is null"); return 0; } - + + int length = strlen(path); + _filePath = (char*) malloc(length + 1); + strcpy(_filePath, path); + _fileOs = fopen(path, "w"); if (!_fileOs) { LOGE("error cannot open file: %s", path); @@ -416,6 +438,134 @@ int initRecorder(const char *path, opus_int32 sampleRate) { return 1; } + +void saveResumeData() { + if (_filePath == NULL) { + return; + } + const char* ext = ".resume"; + char* _resumeFilePath = (char*) malloc(strlen(_filePath) + strlen(ext) + 1); + strcpy(_resumeFilePath, _filePath); + strcat(_resumeFilePath, ext); + + FILE* resumeFile = fopen(_resumeFilePath, "wb"); + if (!resumeFile) { + LOGE("error cannot open resume file to write: %s", _resumeFilePath); + free(_resumeFilePath); + return; + } + resume_data data; + data._packetId = _packetId; + data.bytes_written = bytes_written; + data.pages_out = pages_out; + data.total_samples = total_samples; + data.enc_granulepos = enc_granulepos; + data.size_segments = size_segments; + data.last_segments = last_segments; + data.last_granulepos = last_granulepos; + data.min_bytes = min_bytes; + data.max_frame_bytes = max_frame_bytes; + + if (fwrite(&data, sizeof(resume_data), 1, resumeFile) != 1) { + LOGE("error writing resume data to file: %s", _resumeFilePath); + } + fclose(resumeFile); + + free(_resumeFilePath); +} + +resume_data readResumeData(const char* filePath) { + + const char* ext = ".resume"; + char* _resumeFilePath = (char*) malloc(strlen(filePath) + strlen(ext) + 1); + strcpy(_resumeFilePath, filePath); + strcat(_resumeFilePath, ext); + + resume_data data; + + FILE* resumeFile = fopen(_resumeFilePath, "rb"); + if (!resumeFile) { + LOGE("error cannot open resume file to read: %s", _resumeFilePath); + memset(&data, 0, sizeof(resume_data)); + return data; + } + + if (fread(&data, sizeof(resume_data), 1, resumeFile) != 1) { + LOGE("error cannot read resume file: %s", _resumeFilePath); + memset(&data, 0, sizeof(resume_data)); + } + + fclose(resumeFile); + free(_resumeFilePath); + + return data; +} + +int resumeRecorder(const char *path, opus_int32 sampleRate) { + cleanupRecorder(); + + coding_rate = sampleRate; + rate = sampleRate; + + if (!path) { + LOGE("path is null"); + return 0; + } + + int length = strlen(path); + _filePath = (char*) malloc(length + 1); + strcpy(_filePath, path); + + resume_data resumeData = readResumeData(path); + _packetId = resumeData._packetId; + bytes_written = resumeData.bytes_written; + pages_out = resumeData.pages_out; + total_samples = resumeData.total_samples; + enc_granulepos = resumeData.enc_granulepos; + size_segments = resumeData.size_segments; + last_segments = resumeData.last_segments; + last_granulepos = resumeData.last_granulepos; + min_bytes = resumeData.min_bytes; + max_frame_bytes = resumeData.max_frame_bytes; + + _fileOs = fopen(path, "a"); + if (!_fileOs) { + LOGE("error cannot open resume file: %s", path); + return 0; + } + + int result = OPUS_OK; + _encoder = opus_encoder_create(coding_rate, 1, OPUS_APPLICATION_VOIP, &result); + if (result != OPUS_OK) { + LOGE("Error cannot create encoder: %s", opus_strerror(result)); + return 0; + } + + _packet = malloc(max_frame_bytes); + + result = opus_encoder_ctl(_encoder, OPUS_SET_BITRATE(bitrate)); + //result = opus_encoder_ctl(_encoder, OPUS_SET_COMPLEXITY(10)); + if (result != OPUS_OK) { + LOGE("Error OPUS_SET_BITRATE returned: %s", opus_strerror(result)); + return 0; + } + +#ifdef OPUS_SET_LSB_DEPTH + result = opus_encoder_ctl(_encoder, OPUS_SET_LSB_DEPTH(MAX(8, MIN(24, 16)))); + if (result != OPUS_OK) { + LOGE("Warning OPUS_SET_LSB_DEPTH returned: %s", opus_strerror(result)); + } +#endif + + if (ogg_stream_init(&os, rand()) == -1) { + LOGE("Error: stream init failed"); + return 0; + } + + return 1; +} + + int writeFrame(uint8_t *framePcmBytes, uint32_t frameByteCount) { size_t cur_frame_size = frame_size; _packetId++; @@ -433,7 +583,7 @@ int writeFrame(uint8_t *framePcmBytes, uint32_t frameByteCount) { if (nb_samples != 0) { uint8_t *paddedFrameBytes = framePcmBytes; int freePaddedFrameBytes = 0; - + if (nb_samples < cur_frame_size) { paddedFrameBytes = malloc(cur_frame_size * 2); freePaddedFrameBytes = 1; @@ -503,6 +653,18 @@ JNIEXPORT jint Java_org_telegram_messenger_MediaController_startRecord(JNIEnv *e const char *pathStr = (*env)->GetStringUTFChars(env, path, 0); int32_t result = initRecorder(pathStr, sampleRate); + + if (pathStr != 0) { + (*env)->ReleaseStringUTFChars(env, path, pathStr); + } + + return result; +} + +JNIEXPORT jint Java_org_telegram_messenger_MediaController_resumeRecord(JNIEnv *env, jclass class, jstring path, jint sampleRate) { + const char *pathStr = (*env)->GetStringUTFChars(env, path, 0); + + int32_t result = resumeRecorder(pathStr, sampleRate); if (pathStr != 0) { (*env)->ReleaseStringUTFChars(env, path, pathStr); @@ -516,7 +678,10 @@ JNIEXPORT jint Java_org_telegram_messenger_MediaController_writeFrame(JNIEnv *en return writeFrame((uint8_t *) frameBytes, (uint32_t) len); } -JNIEXPORT void Java_org_telegram_messenger_MediaController_stopRecord(JNIEnv *env, jclass class) { +JNIEXPORT void Java_org_telegram_messenger_MediaController_stopRecord(JNIEnv *env, jclass class, jboolean allowResuming) { + if (allowResuming && _filePath != NULL) { + saveResumeData(); + } cleanupRecorder(); } diff --git a/TMessagesProj/jni/opus/src/opus_encoder.c b/TMessagesProj/jni/opus/src/opus_encoder.c index 1c5a8b338..0c55e7a91 100644 --- a/TMessagesProj/jni/opus/src/opus_encoder.c +++ b/TMessagesProj/jni/opus/src/opus_encoder.c @@ -47,6 +47,8 @@ #include "tuning_parameters.h" #ifdef FIXED_POINT #include "fixed/structs_FIX.h" +#include "c_utils.h" + #else #include "float/structs_FLP.h" #endif diff --git a/TMessagesProj/jni/tgnet/Connection.cpp b/TMessagesProj/jni/tgnet/Connection.cpp index 6457d8957..63e677ccd 100644 --- a/TMessagesProj/jni/tgnet/Connection.cpp +++ b/TMessagesProj/jni/tgnet/Connection.cpp @@ -114,7 +114,7 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { parseLaterBuffer = buffer->hasRemaining() ? buffer : nullptr; buffer = restOfTheData; } else { - if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received packet size less(%u) then message size(%u)", this, currentDatacenter->instanceNum, currentDatacenter->getDatacenterId(), connectionType, restOfTheData->position(), lastPacketLength); +// if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received packet size less(%u) then message size(%u)", this, currentDatacenter->instanceNum, currentDatacenter->getDatacenterId(), connectionType, restOfTheData->position(), lastPacketLength); return; } } diff --git a/TMessagesProj/jni/tgnet/ConnectionSocket.cpp b/TMessagesProj/jni/tgnet/ConnectionSocket.cpp index 0315aad5c..14dea9c58 100644 --- a/TMessagesProj/jni/tgnet/ConnectionSocket.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionSocket.cpp @@ -655,7 +655,12 @@ void ConnectionSocket::onEvent(uint32_t events) { while (true) { buffer->rewind(); readCount = recv(socketFd, buffer->bytes(), READ_BUFFER_SIZE, 0); + int err = errno; +// if (LOGS_ENABLED) DEBUG_D("connection(%p) recv resulted with %d, errno=%d", this, readCount, err); if (readCount < 0) { + if (err == EAGAIN) { + break; + } closeSocket(1, -1); if (LOGS_ENABLED) DEBUG_E("connection(%p) recv failed", this); return; @@ -850,10 +855,12 @@ void ConnectionSocket::onEvent(uint32_t events) { onReceivedData(buffer); } } - } - if (readCount != READ_BUFFER_SIZE) { + } else if (readCount == 0) { break; } +// if (readCount != READ_BUFFER_SIZE) { +// break; +// } } } } diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp index 94e97c4f7..79fda991f 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -970,11 +970,13 @@ void ConnectionsManager::onConnectionDataReceived(Connection *connection, Native sendMessagesToConnectionWithConfirmation(messages, connection, false); } } else { + if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received unparsed packet on 0x%" PRIx64, connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), messageId); if (delegate != nullptr) { delegate->onUnparsedMessageReceived(messageId, data, connection->getConnectionType(), instanceNum); } } } else { + if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received unprocessed packet on 0x%" PRIx64, connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), messageId); std::vector> messages; sendMessagesToConnectionWithConfirmation(messages, connection, false); } @@ -1052,6 +1054,9 @@ TLObject *ConnectionsManager::TLdeserialize(TLObject *request, uint32_t bytes, N } } } else { + if (constructor == 0x96a18d5) { + if (LOGS_ENABLED) DEBUG_D("not found file 0x%x", constructor); + } if (LOGS_ENABLED) DEBUG_D("not found request to parse constructor 0x%x", constructor); } } @@ -1621,6 +1626,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag processServerResponse(object, messageId, messageSeqNo, messageSalt, connection, innerMsgId, containerMessageId); delete object; } else { + if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received unparsed from gzip object on %0x" PRIx64, connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), messageId); if (delegate != nullptr) { delegate->onUnparsedMessageReceived(messageId, data, connection->getConnectionType(), instanceNum); } @@ -1969,7 +1975,7 @@ bool ConnectionsManager::cancelRequestInternal(int32_t token, int64_t messageId, Request *request = iter->get(); if ((token != 0 && request->requestToken == token) || (messageId != 0 && request->respondsToMessageId(messageId))) { request->cancelled = true; - if (LOGS_ENABLED) DEBUG_D("cancelled queued rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); + if (LOGS_ENABLED) DEBUG_D("cancelled queued rpc request %p - %s of messageId 0x%" PRIx64, request->rawRequest, typeid(*request->rawRequest).name(), request->messageId); requestsQueue.erase(iter); if (removeFromClass) { removeRequestFromGuid(token); @@ -1982,7 +1988,7 @@ bool ConnectionsManager::cancelRequestInternal(int32_t token, int64_t messageId, Request *request = iter->get(); if ((token != 0 && request->requestToken == token) || (messageId != 0 && request->respondsToMessageId(messageId))) { request->cancelled = true; - if (LOGS_ENABLED) DEBUG_D("cancelled waiting login rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); + if (LOGS_ENABLED) DEBUG_D("cancelled waiting login rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); waitingLoginRequests.erase(iter); if (removeFromClass) { removeRequestFromGuid(token); @@ -2000,7 +2006,7 @@ bool ConnectionsManager::cancelRequestInternal(int32_t token, int64_t messageId, sendRequest(dropAnswer, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagFailOnServerErrors | RequestFlagIsCancel, request->datacenterId, request->connectionType, true); } request->cancelled = true; - if (LOGS_ENABLED) DEBUG_D("cancelled running rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); + if (LOGS_ENABLED) DEBUG_D("cancelled running rpc request %p - %s, of messageId 0x%" PRIx64, request->rawRequest, typeid(*request->rawRequest).name(), request->messageId); runningRequests.erase(iter); if (removeFromClass) { removeRequestFromGuid(token); @@ -2352,12 +2358,13 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t forceThisRequest = false; } - if (forceThisRequest || (abs(currentTime - request->startTime) > maxTimeout && - (currentTime >= request->minStartTime || - (request->failedByFloodWait != 0 && (request->minStartTime - currentTime) > request->failedByFloodWait) || - (request->failedByFloodWait == 0 && abs(currentTime - request->minStartTime) >= 60)) - ) - ) { + if (forceThisRequest || ( + abs(currentTime - request->startTime) > maxTimeout && ( + currentTime >= request->minStartTime || + (request->failedByFloodWait != 0 && (request->minStartTime - currentTime) > request->failedByFloodWait) || + (request->failedByFloodWait == 0 && abs(currentTime - request->minStartTime) >= 60) + ) + )) { if (!forceThisRequest && request->connectionToken > 0) { if ((request->connectionType & ConnectionTypeGeneric || request->connectionType & ConnectionTypeTemp) && request->connectionToken == connection->getConnectionToken()) { if (LOGS_ENABLED) DEBUG_D("request token is valid, not retrying %s (%p)", typeInfo.name(), request->rawRequest); diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.h b/TMessagesProj/jni/tgnet/ConnectionsManager.h index 765e9db35..7ab328353 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.h +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.h @@ -259,7 +259,6 @@ private: friend class Config; friend class FileLog; friend class Handshake; - }; #ifdef ANDROID diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index 3d09a03c5..e9cbc86b0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -37,15 +37,18 @@ import androidx.multidex.MultiDex; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; +import org.json.JSONObject; import org.telegram.messenger.voip.VideoCapturerDevice; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Adapters.DrawerLayoutAdapter; import org.telegram.ui.Components.ForegroundDetector; import org.telegram.ui.Components.Premium.boosts.BoostRepository; import org.telegram.ui.IUpdateLayout; import org.telegram.ui.LauncherIconController; import java.io.File; +import java.util.ArrayList; public class ApplicationLoader extends Application { @@ -595,4 +598,32 @@ public class ApplicationLoader extends Application { return null; } + public TLRPC.Update parseTLUpdate(int constructor) { + return null; + } + + public void processUpdate(int currentAccount, TLRPC.Update update) { + + } + + public boolean onSuggestionFill(String suggestion, String[] output, boolean[] closeable) { + return false; + } + + public boolean onSuggestionClick(String suggestion) { + return false; + } + + public boolean extendDrawer(ArrayList items) { + return false; + } + + public boolean checkRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) { + return false; + } + + public boolean consumePush(int account, JSONObject json) { + return false; + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java b/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java index c55c47411..16ea6dc17 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java @@ -135,6 +135,14 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.billingProductDetailsUpdated); } + private void switchBackFromInvoice() { + if (!billingClientEmpty) { + return; + } + billingClientEmpty = false; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.billingProductDetailsUpdated); + } + public boolean isReady() { return billingClient.isReady(); } @@ -328,28 +336,19 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien AndroidUtilities.runOnUIThread(() -> startConnection(), delay); } + private int triesLeft = 0; + @Override public void onBillingSetupFinished(@NonNull BillingResult setupBillingResult) { FileLog.d("Billing: Setup finished with result " + setupBillingResult); if (setupBillingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { isDisconnected = false; - queryProductDetails(Collections.singletonList(PREMIUM_PRODUCT), (billingResult, list) -> { - FileLog.d("Billing: Query product details finished " + billingResult + ", " + list); - if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { - for (ProductDetails details : list) { - if (details.getProductId().equals(PREMIUM_PRODUCT_ID)) { - PREMIUM_PRODUCT_DETAILS = details; - } - } - if (PREMIUM_PRODUCT_DETAILS == null) { - switchToInvoice(); - } else { - NotificationCenter.getGlobalInstance().postNotificationNameOnUIThread(NotificationCenter.billingProductDetailsUpdated); - } - } else { - switchToInvoice(); - } - }); + triesLeft = 3; + try { + queryProductDetails(Collections.singletonList(PREMIUM_PRODUCT), this::onQueriedPremiumProductDetails); + } catch (Exception e) { + FileLog.e(e); + } queryPurchases(BillingClient.ProductType.INAPP, this::onPurchasesUpdated); queryPurchases(BillingClient.ProductType.SUBS, this::onPurchasesUpdated); } else { @@ -358,4 +357,39 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien } } } + + private void onQueriedPremiumProductDetails(BillingResult billingResult, List list) { + FileLog.d("Billing: Query product details finished " + billingResult + ", " + list); + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + for (ProductDetails details : list) { + if (details.getProductId().equals(PREMIUM_PRODUCT_ID)) { + PREMIUM_PRODUCT_DETAILS = details; + } + } + if (PREMIUM_PRODUCT_DETAILS == null) { + switchToInvoice(); + } else { + switchBackFromInvoice(); + NotificationCenter.getGlobalInstance().postNotificationNameOnUIThread(NotificationCenter.billingProductDetailsUpdated); + } + } else { + switchToInvoice(); + triesLeft--; + if (triesLeft > 0) { + long delay; + if (triesLeft == 2) { + delay = 1000; + } else { + delay = 10000; + } + AndroidUtilities.runOnUIThread(() -> { + try { + queryProductDetails(Collections.singletonList(PREMIUM_PRODUCT), this::onQueriedPremiumProductDetails); + } catch (Exception e) { + FileLog.e(e); + } + }, delay); + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java index 8a4ae4192..3b4a9215d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java @@ -103,6 +103,23 @@ public class ChannelBoostsController { public boolean boostedNow; public boolean isMaxLvl; + public CanApplyBoost copy() { + CanApplyBoost canApplyBoost = new CanApplyBoost(); + canApplyBoost.canApply = canApply; + canApplyBoost.empty = empty; + canApplyBoost.replaceDialogId = replaceDialogId; + canApplyBoost.alreadyActive = alreadyActive; + canApplyBoost.needSelector = needSelector; + canApplyBoost.slot = slot; + canApplyBoost.myBoosts = myBoosts; + canApplyBoost.boostCount = boostCount; + canApplyBoost.currentPeer = currentPeer; + canApplyBoost.currentDialogId = currentDialogId; + canApplyBoost.currentChat = currentChat; + canApplyBoost.isMaxLvl = isMaxLvl; + return canApplyBoost; + } + public void setMyBoosts(TL_stories.TL_premium_myBoosts myBoosts) { this.myBoosts = myBoosts; boostCount = 0; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java index 3a65cc5bc..e51e5c2a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java @@ -76,7 +76,7 @@ public class ChatMessagesMetadataController { storyItem.dialogId = messageObject.messageOwner.media.user_id; } else if (messageObject.messageOwner.reply_to != null) { storyItem = messageObject.messageOwner.replyStory; - storyItem.dialogId = messageObject.messageOwner.reply_to.user_id; + storyItem.dialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.reply_to.peer); } else { continue; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index 1113b1c70..5168aafb3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -97,7 +97,31 @@ public class ChatObject { } public static boolean canSendAnyMedia(TLRPC.Chat currentChat) { - return canSendPhoto(currentChat) || canSendVideo(currentChat) || canSendRoundVideo(currentChat)|| canSendVoice(currentChat) || canSendDocument(currentChat) || canSendMusic(currentChat) || canSendStickers(currentChat); + return canSendPhoto(currentChat) || canSendVideo(currentChat) || canSendRoundVideo(currentChat) || canSendVoice(currentChat) || canSendDocument(currentChat) || canSendMusic(currentChat) || canSendStickers(currentChat); + } + + public static boolean isIgnoredChatRestrictionsForBoosters(TLRPC.ChatFull chatFull) { + return chatFull != null && chatFull.boosts_unrestrict > 0 && (chatFull.boosts_applied - chatFull.boosts_unrestrict) >= 0; + } + + public static boolean isIgnoredChatRestrictionsForBoosters(TLRPC.Chat chat) { + if (chat != null) { + TLRPC.ChatFull chatFull = MessagesController.getInstance(UserConfig.selectedAccount).getChatFull(chat.id); + return isIgnoredChatRestrictionsForBoosters(chatFull); + } + return false; + } + + public static boolean isPossibleRemoveChatRestrictionsByBoosts(TLRPC.Chat chat) { + if (chat != null) { + TLRPC.ChatFull chatFull = MessagesController.getInstance(UserConfig.selectedAccount).getChatFull(chat.id); + return isPossibleRemoveChatRestrictionsByBoosts(chatFull); + } + return false; + } + + public static boolean isPossibleRemoveChatRestrictionsByBoosts(TLRPC.ChatFull chatFull) { + return chatFull != null && chatFull.boosts_unrestrict > 0; } public static String getAllowedSendString(TLRPC.Chat chat) { @@ -1695,6 +1719,18 @@ public class ChatObject { return isChannel(chat) && !isMegagroup(chat); } + public static boolean isBoostSupported(TLRPC.Chat chat) { + return isChannelAndNotMegaGroup(chat) || isMegagroup(chat); + } + + public static boolean isBoosted(TLRPC.ChatFull chatFull) { + return chatFull != null && chatFull.boosts_applied > 0; + } + + public static boolean isGroupAndSupportBoost(TLRPC.Chat chat) { + return isMegagroup(chat); + } + public static boolean isForum(TLRPC.Chat chat) { return chat != null && chat.forum; } @@ -1725,49 +1761,79 @@ public class ChatObject { } public static boolean canSendStickers(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND_STICKERS); } public static boolean canSendEmbed(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_EMBED_LINKS); } - // public static boolean canSendMedia(TLRPC.Chat chat) { -// return canUserDoAction(chat, ACTION_SEND_MEDIA); -// } public static boolean canSendPhoto(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND_PHOTO); } public static boolean canSendVideo(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND_VIDEO); } public static boolean canSendMusic(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND_MUSIC); } public static boolean canSendDocument(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND_DOCUMENTS); } public static boolean canSendVoice(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND_VOICE); } public static boolean canSendRoundVideo(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND_ROUND); } public static boolean canSendPolls(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND_POLLS); } public static boolean canSendMessages(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND); } public static boolean canSendPlain(TLRPC.Chat chat) { + if (isIgnoredChatRestrictionsForBoosters(chat)) { + return true; + } return canUserDoAction(chat, ACTION_SEND_PLAIN); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index d07867269..7242bc8cc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -252,6 +252,8 @@ public class FileLoadOperation { private int priority; private FilePathDatabase.FileMeta fileMetadata; + private volatile boolean writingToFilePartsStream, closeFilePartsStreamOnWriteEnd; + private boolean ungzip; private int currentType; @@ -285,6 +287,7 @@ public class FileLoadOperation { public FileLoadOperation(ImageLocation imageLocation, Object parent, String extension, long size) { updateParams(); parentObject = parent; + isStory = parentObject instanceof TL_stories.TL_storyItem; fileMetadata = FileLoader.getFileMetadataFromParent(currentAccount, parentObject); isStream = imageLocation.imageType == FileLoader.IMAGE_TYPE_ANIMATION; if (imageLocation.isEncrypted()) { @@ -392,6 +395,7 @@ public class FileLoadOperation { updateParams(); try { parentObject = parent; + isStory = parentObject instanceof TL_stories.TL_storyItem; fileMetadata = FileLoader.getFileMetadataFromParent(currentAccount, parentObject); if (documentLocation instanceof TLRPC.TL_documentEncrypted) { location = new TLRPC.TL_inputEncryptedFileLocation(); @@ -583,6 +587,9 @@ public class FileLoadOperation { if (fileWriteRunnable != null) { filesQueue.cancelRunnable(fileWriteRunnable); } + synchronized (FileLoadOperation.this) { + writingToFilePartsStream = true; + } filesQueue.postRunnable(fileWriteRunnable = () -> { long time = System.currentTimeMillis(); try { @@ -608,6 +615,16 @@ public class FileLoadOperation { } filePartsStream.seek(0); filePartsStream.write(filesQueueByteBuffer.buf, 0, bufferSize); + writingToFilePartsStream = false; + if (closeFilePartsStreamOnWriteEnd) { + try { + filePartsStream.getChannel().close(); + } catch (Exception e) { + FileLog.e(e); + } + filePartsStream.close(); + filePartsStream = null; + } } } catch (Exception e) { FileLog.e(e, false); @@ -780,7 +797,6 @@ public class FileLoadOperation { public boolean start(final FileLoadOperationStream stream, final long streamOffset, final boolean streamPriority) { startTime = System.currentTimeMillis(); updateParams(); - isStory = parentObject instanceof TL_stories.TL_storyItem; if (currentDownloadChunkSize == 0) { if (forceSmallChunk) { if (BuildVars.LOGS_ENABLED) { @@ -1350,7 +1366,7 @@ public class FileLoadOperation { } for (int i = 0; i < 2; i++) { int connectionType = i == 0 ? ConnectionsManager.ConnectionTypeDownload : ConnectionsManager.ConnectionTypeDownload2; - if (waitingDownloadSize[i] > 512 * 1024 * 2) { + if (waitingDownloadSize[i] > 1024 * 1024) { int datacenterId = isCdn ? cdnDatacenterId : this.datacenterId; ConnectionsManager.getInstance(currentAccount).discardConnection(datacenterId, connectionType); } @@ -1402,13 +1418,17 @@ public class FileLoadOperation { try { if (filePartsStream != null) { synchronized (FileLoadOperation.this) { - try { - filePartsStream.getChannel().close(); - } catch (Exception e) { - FileLog.e(e); + if (!writingToFilePartsStream) { + try { + filePartsStream.getChannel().close(); + } catch (Exception e) { + FileLog.e(e); + } + filePartsStream.close(); + filePartsStream = null; + } else { + closeFilePartsStreamOnWriteEnd = true; } - filePartsStream.close(); - filePartsStream = null; } } } catch (Exception e) { @@ -2104,6 +2124,7 @@ public class FileLoadOperation { MessageObject messageObject = (MessageObject) parentObject; if (messageObject.getId() < 0 && messageObject.messageOwner != null && messageObject.messageOwner.media != null && messageObject.messageOwner.media.webpage != null) { parentObject = messageObject.messageOwner.media.webpage; + isStory = false; } } if (BuildVars.LOGS_ENABLED) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 02d68cfd2..948cfdcb1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -776,7 +776,7 @@ public class FileLoader extends BaseController { if (priorityChanged) { operation.getQueue().checkLoadingOperations(); } - FileLog.d("load operation update position fileName=" + finalFileName + " position in queue " + operation.getPositionInQueue() + " preloadFinish " + operation.isPreloadFinished()); + FileLog.d("load operation update position fileName=" + finalFileName + " position in queue " + operation.getPositionInQueue() + " preloadFinish " + operation.isPreloadFinished() + " priority=" + operation.getPriority()); return operation; } @@ -981,10 +981,10 @@ public class FileLoader extends BaseController { } loaderQueue.add(operation); - loaderQueue.checkLoadingOperations(operation.isStory && priority >= PRIORITY_HIGH); + loaderQueue.checkLoadingOperations(operation.isStory && priority >= FileLoaderPriorityQueue.PRIORITY_VALUE_MAX); if (BuildVars.LOGS_ENABLED) { - FileLog.d("create load operation fileName=" + finalFileName + " documentName=" + getDocumentFileName(document) + " size=" + AndroidUtilities.formatFileSize(operation.totalBytesCount) + " position in queue " + operation.getPositionInQueue() + " account=" + currentAccount + " cacheType=" + cacheType); + FileLog.d("create load operation fileName=" + finalFileName + " documentName=" + getDocumentFileName(document) + " size=" + AndroidUtilities.formatFileSize(operation.totalBytesCount) + " position in queue " + operation.getPositionInQueue() + " account=" + currentAccount + " cacheType=" + cacheType + " priority=" + operation.getPriority()); } return operation; } @@ -1114,7 +1114,7 @@ public class FileLoader extends BaseController { fileLoaderQueue.postRunnable(() -> { if (queue.remove(operation)) { loadOperationPaths.remove(operation.getFileName()); - queue.checkLoadingOperations(); + queue.checkLoadingOperations(operation.isStory); } }, delay); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoaderPriorityQueue.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoaderPriorityQueue.java index 820b2c4e4..9cb0eb756 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoaderPriorityQueue.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoaderPriorityQueue.java @@ -109,11 +109,17 @@ public class FileLoaderPriorityQueue { //operation will not use connections //just skip max++; + if (BuildVars.DEBUG_PRIVATE_VERSION) + FileLog.d("{"+name+"}.checkLoadingOperationInternal: #" + i + " "+operation.getFileName()+" priority="+operation.getPriority()+" isStory="+operation.isStory+" preFinished="+ operation.preFinished+" pauseAllNextOperations=" + pauseAllNextOperations + " max=" + max + " => skip"); continue; } else if (!pauseAllNextOperations && i < max) { + if (BuildVars.DEBUG_PRIVATE_VERSION) + FileLog.d("{"+name+"}.checkLoadingOperationInternal: #" + i + " " +operation.getFileName()+" priority="+operation.getPriority()+" isStory="+operation.isStory+" preFinished="+ operation.preFinished+" pauseAllNextOperations=" + pauseAllNextOperations + " max=" + max + " => start"); tmpListOperations.add(operation); activeCount++; } else { + if (BuildVars.DEBUG_PRIVATE_VERSION) + FileLog.d("{"+name+"}.checkLoadingOperationInternal: #" + i + " " +operation.getFileName()+" priority="+operation.getPriority()+" isStory="+operation.isStory+" preFinished="+ operation.preFinished+" pauseAllNextOperations=" + pauseAllNextOperations + " max=" + max + " => pause"); if (operation.wasStarted()) { operation.pause(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index bfa725edf..661318cf2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -1644,6 +1644,9 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg svgDrawable = (SvgHelper.SvgDrawable) drawable; svgDrawable.setParent(this); } + if (colorFilter != null && drawable != null) { + drawable.setColorFilter(colorFilter); + } try { drawable.setAlpha(alpha); if (backgroundThreadDrawHolder != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index c68b0c0b9..c1aadfada 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -1626,6 +1626,9 @@ public class LocaleController { } public static String formatSmallDateChat(long date) { + return formatSmallDateChat(date, false); + } + public static String formatSmallDateChat(long date, boolean full) { try { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); @@ -1633,7 +1636,7 @@ public class LocaleController { date *= 1000; calendar.setTimeInMillis(date); - if (currentYear == calendar.get(Calendar.YEAR)) { + if (!full && currentYear == calendar.get(Calendar.YEAR)) { return getInstance().formatterDayMonth.format(date); } return getInstance().formatterDayMonth.format(date) + ", " + calendar.get(Calendar.YEAR); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 5c6fc9a97..934b8481a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -54,6 +54,8 @@ import android.provider.OpenableColumns; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.Log; +import android.util.LongSparseArray; import android.util.Pair; import android.util.SparseArray; import android.view.HapticFeedbackConstants; @@ -112,9 +114,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, private native int startRecord(String path, int sampleRate); + private native int resumeRecord(String path, int sampleRate); + private native int writeFrame(ByteBuffer frame, int len); - private native void stopRecord(); + private native void stopRecord(boolean allowResuming); public static native int isOpusFile(String path); @@ -755,20 +759,21 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, private boolean audioRecorderPaused; private AudioRecord audioRecorder; - private TLRPC.TL_document recordingAudio; + public TLRPC.TL_document recordingAudio; private int recordingGuid = -1; private int recordingCurrentAccount; private File recordingAudioFile; private long recordStartTime; - private long recordTimeCount; - private int writedFrame; + public long recordTimeCount; + public int writedFrame; private long writedFileLenght; private long recordDialogId; + private long recordTopicId; private MessageObject recordReplyingMsg; private MessageObject recordReplyingTopMsg; private TL_stories.StoryItem recordReplyingStory; - private short[] recordSamples = new short[1024]; - private long samplesCount; + public short[] recordSamples = new short[1024]; + public long samplesCount; private final Object sync = new Object(); @@ -1944,7 +1949,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, private void raiseToSpeakUpdated(boolean raised) { if (recordingAudio != null) { - toggleRecordingPause(); + toggleRecordingPause(false); } else if (raised) { startRecording(raiseChat.getCurrentAccount(), raiseChat.getDialogId(), null, raiseChat.getThreadMessage(), null, raiseChat.getClassGuid(), false); } else { @@ -3824,9 +3829,96 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } } - public void toggleRecordingPause() { + public void prepareResumedRecording(int currentAccount, MediaDataController.DraftVoice draft, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem replyStory, int guid, boolean manual) { + manualRecording = manual; + requestAudioFocus(true); + recordQueue.cancelRunnable(recordStartRunnable); recordQueue.postRunnable(() -> { - if (recordingAudio == null || recordingAudioFile == null) { + setBluetoothScoOn(true); + sendAfterDone = 0; + recordingAudio = new TLRPC.TL_document(); + recordingGuid = guid; + recordingAudio.dc_id = Integer.MIN_VALUE; + recordingAudio.id = draft.id; + recordingAudio.user_id = UserConfig.getInstance(currentAccount).getClientUserId(); + recordingAudio.mime_type = "audio/ogg"; + recordingAudio.file_reference = new byte[0]; + SharedConfig.saveConfig(); + + recordingAudioFile = new File(draft.path) { + @Override + public boolean delete() { + if (BuildVars.LOGS_ENABLED) { + FileLog.e("delete voice file"); + } + return super.delete(); + } + }; + FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE).mkdirs(); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("start recording internal " + recordingAudioFile.getPath() + " " + recordingAudioFile.exists()); + } + AutoDeleteMediaTask.lockFile(recordingAudioFile); + try { + audioRecorderPaused = true; + recordTimeCount = draft.recordTimeCount; + writedFrame = draft.writedFrame; + samplesCount = draft.samplesCount; + recordSamples = draft.recordSamples; + recordDialogId = dialogId; + recordTopicId = replyToTopMsg == null ? 0 : MessageObject.getTopicId(recordingCurrentAccount, replyToTopMsg.messageOwner, false); + recordingCurrentAccount = currentAccount; + recordReplyingMsg = replyToMsg; + recordReplyingTopMsg = replyToTopMsg; + recordReplyingStory = replyStory; + } catch (Exception e) { + FileLog.e(e); + recordingAudio = null; + AutoDeleteMediaTask.unlockFile(recordingAudioFile); + recordingAudioFile.delete(); + recordingAudioFile = null; + try { + audioRecorder.release(); + audioRecorder = null; + } catch (Exception e2) { + FileLog.e(e2); + } + setBluetoothScoOn(false); + + AndroidUtilities.runOnUIThread(() -> { + MediaDataController.getInstance(currentAccount).pushDraftVoiceMessage(dialogId, recordTopicId, null); + recordStartRunnable = null; + }); + return; + } + + final TLRPC.TL_document audioToSend = recordingAudio; + final File recordingAudioFileToSend = recordingAudioFile; + AndroidUtilities.runOnUIThread(() -> { + boolean fileExist = recordingAudioFileToSend.exists(); + if (!fileExist && BuildVars.DEBUG_VERSION) { + FileLog.e(new RuntimeException("file not found :( recordTimeCount " + recordTimeCount + " writedFrames" + writedFrame)); + } + audioToSend.date = ConnectionsManager.getInstance(recordingCurrentAccount).getCurrentTime(); + audioToSend.size = (int) recordingAudioFileToSend.length(); + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.voice = true; + attributeAudio.waveform = getWaveform2(recordSamples, recordSamples.length); + if (attributeAudio.waveform != null) { + attributeAudio.flags |= 4; + } + attributeAudio.duration = recordTimeCount / 1000.0; + audioToSend.attributes.clear(); + audioToSend.attributes.add(attributeAudio); + NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.recordPaused); + NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.audioDidSent, recordingGuid, audioToSend, recordingAudioFileToSend.getAbsolutePath(), true); + }); + }); + } + + public void toggleRecordingPause(boolean voiceOnce) { + recordQueue.postRunnable(() -> { + if (audioRecorder == null || recordingAudio == null || recordingAudioFile == null) { return; } audioRecorderPaused = !audioRecorderPaused; @@ -3836,38 +3928,62 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, audioRecorder.stop(); audioRecorder.release(); audioRecorder = null; + recordQueue.postRunnable(() -> { + stopRecord(true); - final TLRPC.TL_document audioToSend = recordingAudio; - final File recordingAudioFileToSend = recordingAudioFile; - AndroidUtilities.runOnUIThread(() -> { - boolean fileExist = recordingAudioFileToSend.exists(); - if (!fileExist && BuildVars.DEBUG_VERSION) { - FileLog.e(new RuntimeException("file not found :( recordTimeCount " + recordTimeCount + " writedFrames" + writedFrame)); + final TLRPC.TL_document audioToSend = recordingAudio; + final File recordingAudioFileToSend = recordingAudioFile; + if (recordingAudio == null || recordingAudioFile == null) { + return; } - audioToSend.date = ConnectionsManager.getInstance(recordingCurrentAccount).getCurrentTime(); - audioToSend.size = (int) recordingAudioFileToSend.length(); - TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); - attributeAudio.voice = true; - attributeAudio.waveform = getWaveform2(recordSamples, recordSamples.length); - if (attributeAudio.waveform != null) { - attributeAudio.flags |= 4; - } - attributeAudio.duration = recordTimeCount / 1000.0; - audioToSend.attributes.clear(); - audioToSend.attributes.add(attributeAudio); - NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.recordPaused); - NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.audioDidSent, recordingGuid, audioToSend, recordingAudioFileToSend.getAbsolutePath()); + AndroidUtilities.runOnUIThread(() -> { + boolean fileExist = recordingAudioFileToSend.exists(); + if (!fileExist && BuildVars.DEBUG_VERSION) { + FileLog.e(new RuntimeException("file not found :( recordTimeCount " + recordTimeCount + " writedFrames" + writedFrame)); + } + if (fileExist) { + MediaDataController.getInstance(recordingCurrentAccount).pushDraftVoiceMessage(recordDialogId, recordTopicId, MediaDataController.DraftVoice.of(this, recordingAudioFileToSend.getAbsolutePath(), voiceOnce)); + } + audioToSend.date = ConnectionsManager.getInstance(recordingCurrentAccount).getCurrentTime(); + audioToSend.size = (int) recordingAudioFileToSend.length(); + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.voice = true; + attributeAudio.waveform = getWaveform2(recordSamples, recordSamples.length); + if (attributeAudio.waveform != null) { + attributeAudio.flags |= 4; + } + attributeAudio.duration = recordTimeCount / 1000.0; + audioToSend.attributes.clear(); + audioToSend.attributes.add(attributeAudio); + NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.recordPaused); + NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.audioDidSent, recordingGuid, audioToSend, recordingAudioFileToSend.getAbsolutePath()); + }); }); } else { recordQueue.cancelRunnable(recordRunnable); - audioRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize); - recordStartTime = System.currentTimeMillis(); - fileBuffer.rewind(); - audioRecorder.startRecording(); - recordQueue.postRunnable(recordRunnable); + recordQueue.postRunnable(() -> { + if (resumeRecord(recordingAudioFile.getPath(), sampleRate) == 0) { + AndroidUtilities.runOnUIThread(() -> { + recordStartRunnable = null; + NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.recordStartError, recordingGuid); + }); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("cant resume encoder"); + } + return; + } - AndroidUtilities.runOnUIThread(() -> { - NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.recordResumed); + AndroidUtilities.runOnUIThread(() -> { + MediaDataController.getInstance(recordingCurrentAccount).pushDraftVoiceMessage(recordDialogId, recordTopicId, null); + + audioRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize); + recordStartTime = System.currentTimeMillis(); + fileBuffer.rewind(); + audioRecorder.startRecording(); + recordQueue.postRunnable(recordRunnable); + + NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.recordResumed); + }); }); } }); @@ -3943,6 +4059,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, writedFrame = 0; samplesCount = 0; recordDialogId = dialogId; + recordTopicId = replyToTopMsg == null ? 0 : MessageObject.getTopicId(recordingCurrentAccount, replyToTopMsg.messageOwner, false); recordingCurrentAccount = currentAccount; recordReplyingMsg = replyToMsg; recordReplyingTopMsg = replyToTopMsg; @@ -3953,7 +4070,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } catch (Exception e) { FileLog.e(e); recordingAudio = null; - stopRecord(); + stopRecord(false); AutoDeleteMediaTask.unlockFile(recordingAudioFile); recordingAudioFile.delete(); recordingAudioFile = null; @@ -4028,7 +4145,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, FileLog.d("stop recording internal filename " + recordingAudioFile.getPath()); } fileEncodingQueue.postRunnable(() -> { - stopRecord(); + stopRecord(false); if (BuildVars.LOGS_ENABLED) { FileLog.d("stop recording internal in queue " + recordingAudioFileToSend.exists() + " " + recordingAudioFileToSend.length()); } @@ -4040,6 +4157,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, if (!fileExist && BuildVars.DEBUG_VERSION) { FileLog.e(new RuntimeException("file not found :( recordTimeCount " + recordTimeCount + " writedFrames" + writedFrame)); } + MediaDataController.getInstance(recordingCurrentAccount).pushDraftVoiceMessage(recordDialogId, recordTopicId, null); audioToSend.date = ConnectionsManager.getInstance(recordingCurrentAccount).getCurrentTime(); audioToSend.size = (int) recordingAudioFileToSend.length(); TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); @@ -4187,7 +4305,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, if (path == null || path.length() == 0) { path = null; TLRPC.Document document = message.getDocument(); - if (!TextUtils.isEmpty(FileLoader.getDocumentFileName(document)) && FileLoader.canSaveAsFile(message)) { + if (!TextUtils.isEmpty(FileLoader.getDocumentFileName(document)) && !(message.messageOwner instanceof TLRPC.TL_message_secret) && FileLoader.canSaveAsFile(message)) { String filename = FileLoader.getDocumentFileName(document); File newDir = FileLoader.getDirectory(FileLoader.MEDIA_DIR_FILES); if (newDir != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 156c5ca78..00a969dfb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -75,6 +75,7 @@ import org.telegram.ui.Components.StickersArchiveAlert; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; +import org.telegram.ui.Components.voip.PrivateVideoPreviewDialog; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.Stories.StoriesStorage; @@ -89,6 +90,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; @@ -5840,7 +5842,7 @@ public class MediaDataController extends BaseController { } } else if (messageObject.getId() > 0 && messageObject.isReplyToStory()) { if (messageObject.messageOwner.replyStory == null) { - long storyDialogId = messageObject.messageOwner.reply_to.user_id; + long storyDialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.reply_to.peer); if (messagesWithUnknownStories == null) { messagesWithUnknownStories = new LongSparseArray<>(); } @@ -5851,7 +5853,7 @@ public class MediaDataController extends BaseController { } array.add(messageObject); } else { - long storyDialogId = messageObject.messageOwner.reply_to.user_id; + long storyDialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.reply_to.peer); messageObject.messageOwner.replyStory = StoriesStorage.checkExpiredStateLocal(currentAccount, storyDialogId, messageObject.messageOwner.replyStory); } } else if (messageObject.getId() > 0 && messageObject.isReply()) { @@ -7078,7 +7080,7 @@ public class MediaDataController extends BaseController { return a.reply_to_msg_id == b.reply_to_msg_id; } if (a instanceof TLRPC.TL_inputReplyToStory) { - return a.user_id == b.user_id && a.story_id == b.story_id; + return MessageObject.peersEqual(a.peer, b.peer) && a.story_id == b.story_id; } return true; } @@ -7086,7 +7088,7 @@ public class MediaDataController extends BaseController { private static TLRPC.InputReplyTo toInputReplyTo(int currentAccount, TLRPC.MessageReplyHeader reply_to) { if (reply_to instanceof TLRPC.TL_messageReplyStoryHeader) { TLRPC.TL_inputReplyToStory inputReplyTo = new TLRPC.TL_inputReplyToStory(); - inputReplyTo.user_id = MessagesController.getInstance(currentAccount).getInputUser(reply_to.user_id); + inputReplyTo.peer = MessagesController.getInstance(currentAccount).getInputPeer(reply_to.peer); inputReplyTo.story_id = reply_to.story_id; return inputReplyTo; } else if (reply_to instanceof TLRPC.TL_messageReplyHeader) { @@ -8996,4 +8998,107 @@ public class MediaDataController extends BaseController { })); } } + + private boolean draftVoicesLoaded = false; + public LongSparseArray draftVoices = new LongSparseArray<>(); + private void loadDraftVoiceMessages() { + if (draftVoicesLoaded) return; + SharedPreferences prefs = ApplicationLoader.applicationContext.getSharedPreferences("voicedrafts_" + currentAccount, Context.MODE_PRIVATE); + Set> entries = prefs.getAll().entrySet(); + draftVoices.clear(); + for (Map.Entry entry : entries) { + String key = entry.getKey(); + String value = (String) entry.getValue(); + DraftVoice draft = DraftVoice.fromString(value); + if (draft == null) continue; + draftVoices.put(Long.parseLong(key), draft); + } + draftVoicesLoaded = true; + } + public void toggleDraftVoiceOnce(long dialog_id, long topic_id, boolean once) { + DraftVoice draft = getDraftVoice(dialog_id, topic_id); + if (draft != null && draft.once != once) { + draft.once = once; + SharedPreferences prefs = ApplicationLoader.applicationContext.getSharedPreferences("voicedrafts_" + currentAccount, Context.MODE_PRIVATE); + prefs.edit().putString(Objects.hash(dialog_id, topic_id) + "", draft.toString()).apply(); + } + } + public void pushDraftVoiceMessage(long dialog_id, long topic_id, DraftVoice draft) { + SharedPreferences prefs = ApplicationLoader.applicationContext.getSharedPreferences("voicedrafts_" + currentAccount, Context.MODE_PRIVATE); + final long hash = Objects.hash(dialog_id, topic_id); + final String key = hash + ""; + if (draft == null) { + prefs.edit().remove(key).apply(); + draftVoices.remove(hash); + } else { + prefs.edit().putString(key, draft.toString()).apply(); + draftVoices.put(hash, draft); + } + } + public DraftVoice getDraftVoice(long dialog_id, long topic_id) { + loadDraftVoiceMessages(); + return draftVoices.get(Objects.hash(dialog_id, topic_id)); + } + + public static class DraftVoice { + public String path; + public long samplesCount; + public int writedFrame; + public long recordTimeCount; + public long id; + public short[] recordSamples; + public boolean once; + + public static DraftVoice of(MediaController mediaController, String path, boolean once) { + if (mediaController.recordingAudio == null) { + return null; + } + DraftVoice draft = new DraftVoice(); + draft.path = path; + draft.samplesCount = mediaController.samplesCount; + draft.writedFrame = mediaController.writedFrame; + draft.recordTimeCount = mediaController.recordTimeCount; + draft.id = mediaController.recordingAudio.id; + draft.recordSamples = mediaController.recordSamples; + draft.once = once; + return draft; + } + + @NonNull + @Override + public String toString() { + char[] recordSamplesArray = new char[recordSamples.length]; + for (int i = 0; i < recordSamples.length; ++i) { + recordSamplesArray[i] = (char) recordSamples[i]; + } + return path + "\n" + samplesCount + "\n" + writedFrame + "\n" + recordTimeCount + "\n" + (once ? 1 : 0) + "\n" + new String(recordSamplesArray); + } + + public static DraftVoice fromString(String string) { + try { + if (string == null) return null; + String[] parts = string.split("\n"); + if (parts.length < 6) return null; + DraftVoice draft = new DraftVoice(); + draft.path = parts[0]; + draft.samplesCount = Long.parseLong(parts[1]); + draft.writedFrame = Integer.parseInt(parts[2]); + draft.recordTimeCount = Long.parseLong(parts[3]); + draft.once = Integer.parseInt(parts[4]) != 0; + String[] recordSamplesParts = new String[parts.length - 5]; + for (int i = 0; i < recordSamplesParts.length; ++i) { + recordSamplesParts[i] = parts[5 + i]; + } + String recordSamplesString = TextUtils.join("\n", recordSamplesParts); + draft.recordSamples = new short[recordSamplesString.length()]; + for (int i = 0; i < draft.recordSamples.length; ++i) { + draft.recordSamples[i] = (short) recordSamplesString.charAt(i); + } + return draft; + } catch (Exception e) { + FileLog.e(e); + return null; + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 0559a9c46..3f808f42e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -1979,18 +1979,18 @@ public class MessageObject { rights.append('\n').append(n.edit_messages ? '+' : '-').append(' '); rights.append(LocaleController.getString("EventLogPromotedEditMessages", R.string.EventLogPromotedEditMessages)); } - if (o.post_stories != n.post_stories) { - rights.append('\n').append(n.post_stories ? '+' : '-').append(' '); - rights.append(LocaleController.getString("EventLogPromotedPostStories", R.string.EventLogPromotedPostStories)); - } - if (o.edit_stories != n.edit_stories) { - rights.append('\n').append(n.edit_messages ? '+' : '-').append(' '); - rights.append(LocaleController.getString("EventLogPromotedEditStories", R.string.EventLogPromotedEditStories)); - } - if (o.delete_stories != n.delete_stories) { - rights.append('\n').append(n.delete_stories ? '+' : '-').append(' '); - rights.append(LocaleController.getString("EventLogPromotedDeleteStories", R.string.EventLogPromotedDeleteStories)); - } + } + if (o.post_stories != n.post_stories) { + rights.append('\n').append(n.post_stories ? '+' : '-').append(' '); + rights.append(LocaleController.getString("EventLogPromotedPostStories", R.string.EventLogPromotedPostStories)); + } + if (o.edit_stories != n.edit_stories) { + rights.append('\n').append(n.edit_stories ? '+' : '-').append(' '); + rights.append(LocaleController.getString("EventLogPromotedEditStories", R.string.EventLogPromotedEditStories)); + } + if (o.delete_stories != n.delete_stories) { + rights.append('\n').append(n.delete_stories ? '+' : '-').append(' '); + rights.append(LocaleController.getString("EventLogPromotedDeleteStories", R.string.EventLogPromotedDeleteStories)); } if (o.delete_messages != n.delete_messages) { rights.append('\n').append(n.delete_messages ? '+' : '-').append(' '); @@ -2474,6 +2474,14 @@ public class MessageObject { message.media.webpage.display_url = ""; message.media.webpage.url = ""; } + } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeEmojiStickerSet) { + TLRPC.InputStickerSet newPack = ((TLRPC.TL_channelAdminLogEventActionChangeEmojiStickerSet) event.action).new_stickerset; + TLRPC.InputStickerSet oldPack = ((TLRPC.TL_channelAdminLogEventActionChangeEmojiStickerSet) event.action).new_stickerset; + if (newPack == null || newPack instanceof TLRPC.TL_inputStickerSetEmpty) { + messageText = replaceWithLink(LocaleController.getString("EventLogRemovedEmojiPack", R.string.EventLogRemovedEmojiPack), "un1", fromUser); + } else { + messageText = replaceWithLink(LocaleController.getString("EventLogChangedEmojiPack", R.string.EventLogChangedEmojiPack), "un1", fromUser); + } } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeStickerSet) { TLRPC.InputStickerSet newStickerset = ((TLRPC.TL_channelAdminLogEventActionChangeStickerSet) event.action).new_stickerset; TLRPC.InputStickerSet oldStickerset = ((TLRPC.TL_channelAdminLogEventActionChangeStickerSet) event.action).new_stickerset; @@ -2784,11 +2792,13 @@ public class MessageObject { fromUser ); } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeColor) { + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); TLRPC.TL_channelAdminLogEventActionChangeColor action = (TLRPC.TL_channelAdminLogEventActionChangeColor) event.action; - messageText = replaceWithLink(LocaleController.formatString(R.string.EventLogChangedColor, AvatarDrawable.colorName(action.prev_value).toLowerCase(), AvatarDrawable.colorName(action.new_value).toLowerCase()), "un1", fromUser); + messageText = replaceWithLink(LocaleController.formatString(isChannel ? R.string.EventLogChangedColor : R.string.EventLogChangedColorGroup, AvatarDrawable.colorName(action.prev_value).toLowerCase(), AvatarDrawable.colorName(action.new_value).toLowerCase()), "un1", fromUser); } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangePeerColor) { + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); TLRPC.TL_channelAdminLogEventActionChangePeerColor action = (TLRPC.TL_channelAdminLogEventActionChangePeerColor) event.action; - SpannableStringBuilder ssb = new SpannableStringBuilder(LocaleController.getString(R.string.EventLogChangedPeerColorIcon)); + SpannableStringBuilder ssb = new SpannableStringBuilder(LocaleController.getString(isChannel ? R.string.EventLogChangedPeerColorIcon : R.string.EventLogChangedPeerColorIconGroup)); SpannableStringBuilder prev = new SpannableStringBuilder(); if ((action.prev_value.flags & 1) != 0) { @@ -2825,8 +2835,9 @@ public class MessageObject { messageText = replaceWithLink(ssb, "un1", fromUser); } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeProfilePeerColor) { + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); TLRPC.TL_channelAdminLogEventActionChangeProfilePeerColor action = (TLRPC.TL_channelAdminLogEventActionChangeProfilePeerColor) event.action; - SpannableStringBuilder ssb = new SpannableStringBuilder(LocaleController.getString(R.string.EventLogChangedProfileColorIcon)); + SpannableStringBuilder ssb = new SpannableStringBuilder(LocaleController.getString(isChannel ? R.string.EventLogChangedProfileColorIcon : R.string.EventLogChangedProfileColorIconGroup)); SpannableStringBuilder prev = new SpannableStringBuilder(); if ((action.prev_value.flags & 1) != 0) { @@ -2863,6 +2874,7 @@ public class MessageObject { messageText = replaceWithLink(ssb, "un1", fromUser); } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeEmojiStatus) { + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); TLRPC.TL_channelAdminLogEventActionChangeEmojiStatus action = (TLRPC.TL_channelAdminLogEventActionChangeEmojiStatus) event.action; boolean prevNone = false; @@ -2887,9 +2899,9 @@ public class MessageObject { SpannableStringBuilder ssb = new SpannableStringBuilder(LocaleController.getString( prevNone ? ( - hasUntil ? R.string.EventLogChangedEmojiStatusFor : R.string.EventLogChangedEmojiStatus + hasUntil ? (isChannel ? R.string.EventLogChangedEmojiStatusFor : R.string.EventLogChangedEmojiStatusForGroup) : (isChannel ? R.string.EventLogChangedEmojiStatus : R.string.EventLogChangedEmojiStatusGroup) ) : ( - hasUntil ? R.string.EventLogChangedEmojiStatusFromFor : R.string.EventLogChangedEmojiStatusFrom + hasUntil ? (isChannel ? R.string.EventLogChangedEmojiStatusFromFor : R.string.EventLogChangedEmojiStatusFromForGroup) : (isChannel ? R.string.EventLogChangedEmojiStatusFrom : R.string.EventLogChangedEmojiStatusFromGroup) ) )); @@ -2903,19 +2915,21 @@ public class MessageObject { messageText = replaceWithLink(ssb, "un1", fromUser); } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeWallpaper) { TLRPC.TL_channelAdminLogEventActionChangeWallpaper action = (TLRPC.TL_channelAdminLogEventActionChangeWallpaper) event.action; + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); if (action.new_value instanceof TLRPC.TL_wallPaperNoFile && action.new_value.id == 0 && action.new_value.settings == null) { - messageText = replaceWithLink(LocaleController.getString(R.string.EventLogRemovedWallpaper), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(isChannel ? R.string.EventLogRemovedWallpaper : R.string.EventLogRemovedWallpaperGroup), "un1", fromUser); } else { photoThumbs = new ArrayList<>(); if (action.new_value.document != null) { photoThumbs.addAll(action.new_value.document.thumbs); photoThumbsObject = action.new_value.document; } - messageText = replaceWithLink(LocaleController.getString(R.string.EventLogChangedWallpaper), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(isChannel ? R.string.EventLogChangedWallpaper : R.string.EventLogChangedWallpaperGroup), "un1", fromUser); } } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeBackgroundEmoji) { + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); TLRPC.TL_channelAdminLogEventActionChangeBackgroundEmoji action = (TLRPC.TL_channelAdminLogEventActionChangeBackgroundEmoji) event.action; - messageText = replaceWithLink(LocaleController.getString(R.string.EventLogChangedEmoji), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(isChannel ? R.string.EventLogChangedEmoji : R.string.EventLogChangedEmojiGroup), "un1", fromUser); SpannableString emoji1; if (action.prev_value == 0) { @@ -3789,7 +3803,9 @@ public class MessageObject { messageText = LocaleController.formatString(R.string.ActionSetSameWallpaperForThisChat, user.first_name); } } else if (fromChat != null) { - messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChannel); + messageText = LocaleController.getString(ChatObject.isChannelAndNotMegaGroup(fromChat) ? R.string.ActionSetWallpaperForThisChannel : R.string.ActionSetWallpaperForThisGroup); + } else if (fromUser != null) { + messageText = LocaleController.formatString(R.string.ActionSetWallpaperForThisGroupByUser, UserObject.getFirstName(fromUser)); } } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { contentType = 1; @@ -3829,7 +3845,9 @@ public class MessageObject { messageText = AndroidUtilities.replaceCharSequence("%s", messageText, userName); } } else if (fromChat != null) { - messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChannel); + messageText = LocaleController.getString(ChatObject.isChannelAndNotMegaGroup(fromChat) ? R.string.ActionSetWallpaperForThisChannel : R.string.ActionSetWallpaperForThisGroup); + } else if (fromUser != null) { + messageText = LocaleController.formatString(R.string.ActionSetWallpaperForThisGroupByUser, UserObject.getFirstName(fromUser)); } } else if (messageOwner.action instanceof TLRPC.TL_messageActionGroupCallScheduled) { TLRPC.TL_messageActionGroupCallScheduled action = (TLRPC.TL_messageActionGroupCallScheduled) messageOwner.action; @@ -4017,14 +4035,43 @@ public class MessageObject { } } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiveawayLaunch) { TLRPC.Chat chat = messageOwner.peer_id != null && messageOwner.peer_id.channel_id != 0 ? getChat(chats, sChats, messageOwner.peer_id.channel_id) : null; - messageText = LocaleController.formatString("BoostingGiveawayJustStarted", R.string.BoostingGiveawayJustStarted, chat != null ? chat.title : ""); + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); + messageText = LocaleController.formatString(isChannel ? R.string.BoostingGiveawayJustStarted : R.string.BoostingGiveawayJustStartedGroup, chat != null ? chat.title : ""); + } else if (messageOwner.action instanceof TLRPC.TL_messageActionBoostApply) { + TLRPC.Chat chat = messageOwner.peer_id != null && messageOwner.peer_id.channel_id != 0 ? getChat(chats, sChats, messageOwner.peer_id.channel_id) : null; + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); + TLRPC.TL_messageActionBoostApply messageActionBoostApply = (TLRPC.TL_messageActionBoostApply) messageOwner.action; + String name = ""; + boolean self = false; + if (fromObject instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) fromObject; + self = UserObject.isUserSelf(user); + name = UserObject.getFirstName(user); + } else if (fromObject instanceof TLRPC.Chat) { + name = ((TLRPC.Chat) fromObject).title; + } + if (self) { + if (messageActionBoostApply.boosts <= 1) { + messageText = LocaleController.getString(isChannel ? R.string.BoostingBoostsChannelByYouServiceMsg : R.string.BoostingBoostsGroupByYouServiceMsg); + } else { + messageText = LocaleController.formatPluralString(isChannel ? "BoostingBoostsChannelByYouServiceMsgCount" : "BoostingBoostsGroupByYouServiceMsgCount", messageActionBoostApply.boosts); + } + } else { + if (messageActionBoostApply.boosts <= 1) { + messageText = LocaleController.formatString(isChannel ? R.string.BoostingBoostsChannelByUserServiceMsg : R.string.BoostingBoostsGroupByUserServiceMsg, name); + } else { + messageText = LocaleController.formatPluralString(isChannel ? "BoostingBoostsChannelByUserServiceMsgCount" : "BoostingBoostsGroupByUserServiceMsgCount", messageActionBoostApply.boosts, name); + } + } } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiveawayResults) { + TLRPC.Chat chat = messageOwner.peer_id != null && messageOwner.peer_id.channel_id != 0 ? getChat(chats, sChats, messageOwner.peer_id.channel_id) : null; + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); TLRPC.TL_messageActionGiveawayResults giveawayResults = (TLRPC.TL_messageActionGiveawayResults) messageOwner.action; SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); stringBuilder.append(LocaleController.formatPluralString("BoostingGiveawayServiceWinnersSelected", giveawayResults.winners_count)); if (giveawayResults.unclaimed_count > 0) { stringBuilder.append("\n"); - stringBuilder.append(LocaleController.formatPluralString("BoostingGiveawayServiceUndistributed", giveawayResults.unclaimed_count)); + stringBuilder.append(LocaleController.formatPluralString(isChannel ? "BoostingGiveawayServiceUndistributed" : "BoostingGiveawayServiceUndistributedGroup", giveawayResults.unclaimed_count)); } messageText = stringBuilder; } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftCode && ((TLRPC.TL_messageActionGiftCode) messageOwner.action).boost_peer != null) { @@ -4537,7 +4584,14 @@ public class MessageObject { } else if (!isMediaEmpty()) { // messageText = getMediaTitle(getMedia(messageOwner)); // I'm afraid doing this if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGiveaway) { - messageText = LocaleController.getString("BoostingGiveawayChannelStarted", R.string.BoostingGiveawayChannelStarted); + boolean isChannel; + if (messageOwner.fwd_from != null && messageOwner.fwd_from.from_id instanceof TLRPC.TL_peerChannel) { + TLRPC.Chat chat = getChat(chats, sChats, messageOwner.fwd_from.from_id.channel_id); + isChannel = ChatObject.isChannelAndNotMegaGroup(chat); + } else { + isChannel = ChatObject.isChannelAndNotMegaGroup(fromChat); + } + messageText = LocaleController.getString(isChannel ? R.string.BoostingGiveawayChannelStarted : R.string.BoostingGiveawayGroupStarted); } else if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGiveawayResults) { messageText = LocaleController.getString("BoostingGiveawayResults", R.string.BoostingGiveawayResults); } else if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaStory) { @@ -7294,8 +7348,12 @@ public class MessageObject { return isOutOwnerCached; } long selfUserId = UserConfig.getInstance(currentAccount).getClientUserId(); - if ((isSaved || getDialogId() == selfUserId) && messageOwner.fwd_from != null) { - return isOutOwnerCached = messageOwner.fwd_from.from_id != null && messageOwner.fwd_from.from_id.user_id == selfUserId || messageOwner.fwd_from.saved_out; + if ((isSaved || getDialogId() == selfUserId)) { + if (messageOwner.fwd_from != null) { + return isOutOwnerCached = messageOwner.fwd_from.from_id != null && messageOwner.fwd_from.from_id.user_id == selfUserId || messageOwner.fwd_from.saved_out; + } else { + return isOutOwnerCached = true; + } } TLRPC.Chat chat = messageOwner.peer_id != null && messageOwner.peer_id.channel_id != 0 ? getChat(null, null, messageOwner.peer_id.channel_id) : null; if (!messageOwner.out || !(messageOwner.from_id instanceof TLRPC.TL_peerUser) && (!(messageOwner.from_id instanceof TLRPC.TL_peerChannel) || ChatObject.isChannel(chat) && !chat.megagroup) || messageOwner.post) { @@ -9844,6 +9902,7 @@ public class MessageObject { !"telegram_user".equals(webpageType) && // drawInstantViewType = 13 !"telegram_story".equals(webpageType) && // drawInstantViewType = 17 !"telegram_channel_boost".equals(webpageType) && // drawInstantViewType = 18 + !"telegram_group_boost".equals(webpageType) && // drawInstantViewType = 21 !"telegram_chat".equals(webpageType) ; } @@ -9857,7 +9916,7 @@ public class MessageObject { "article".equals(webpageType) || "telegram_bot".equals(webpageType) || "telegram_user".equals(webpageType) || "telegram_channel".equals(webpageType) || "telegram_megagroup".equals(webpageType) || "telegram_voicechat".equals(webpageType) || - "telegram_livestream".equals(webpageType) || "telegram_channel_boost".equals(webpageType) || + "telegram_livestream".equals(webpageType) || "telegram_channel_boost".equals(webpageType) || "telegram_group_boost".equals(webpageType) || "telegram_chat".equals(webpageType) ); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 1421c7ff5..0274455dc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -69,6 +69,7 @@ import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.JoinCallAlert; +import org.telegram.ui.Components.JoinGroupAlert; import org.telegram.ui.Components.MotionBackgroundDrawable; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; @@ -84,8 +85,6 @@ import org.telegram.ui.Stories.StoriesController; import org.telegram.ui.TopicsFragment; import java.io.File; -import java.io.PrintWriter; -import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -581,6 +580,13 @@ public class MessagesController extends BaseController implements NotificationCe public int channelEmojiStatusLevelMin; public int channelWallpaperLevelMin; public int channelCustomWallpaperLevelMin; + public int groupProfileBgIconLevelMin; + public int groupEmojiStatusLevelMin; + public int groupEmojiStickersLevelMin; + public int groupWallpaperLevelMin; + public int groupCustomWallpaperLevelMin; + public int groupTranscribeLevelMin; + public int savedDialogsPinnedLimitDefault; public int savedDialogsPinnedLimitPremium; @@ -1453,6 +1459,12 @@ public class MessagesController extends BaseController implements NotificationCe channelBgIconLevelMin = mainPreferences.getInt("channelBgIconLevelMin", 1); channelProfileIconLevelMin = mainPreferences.getInt("channelProfileIconLevelMin", 1); channelEmojiStatusLevelMin = mainPreferences.getInt("channelEmojiStatusLevelMin", 1); + groupProfileBgIconLevelMin = mainPreferences.getInt("groupProfileBgIconLevelMin", 1); + groupEmojiStatusLevelMin = mainPreferences.getInt("groupEmojiStatusLevelMin", 1); + groupEmojiStickersLevelMin = mainPreferences.getInt("groupEmojiStickersLevelMin", 1); + groupWallpaperLevelMin = mainPreferences.getInt("groupWallpaperLevelMin", 1); + groupCustomWallpaperLevelMin = mainPreferences.getInt("groupCustomWallpaperLevelMin", 1); + groupTranscribeLevelMin = mainPreferences.getInt("groupTranscribeLevelMin", 1); channelWallpaperLevelMin = mainPreferences.getInt("channelWallpaperLevelMin", 1); channelCustomWallpaperLevelMin = mainPreferences.getInt("channelCustomWallpaperLevelMin", 1); chatlistInvitesLimitPremium = mainPreferences.getInt("chatlistInvitesLimitPremium", isTest ? 5 : 20); @@ -3664,6 +3676,72 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + case "group_custom_wallpaper_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != groupCustomWallpaperLevelMin) { + groupCustomWallpaperLevelMin = (int) num.value; + editor.putInt("groupCustomWallpaperLevelMin", groupCustomWallpaperLevelMin); + changed = true; + } + } + break; + } + case "group_transcribe_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != groupTranscribeLevelMin) { + groupTranscribeLevelMin = (int) num.value; + editor.putInt("groupTranscribeLevelMin", groupTranscribeLevelMin); + changed = true; + } + } + break; + } + case "group_wallpaper_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != groupWallpaperLevelMin) { + groupWallpaperLevelMin = (int) num.value; + editor.putInt("groupWallpaperLevelMin", groupWallpaperLevelMin); + changed = true; + } + } + break; + } + case "group_emoji_status_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != groupEmojiStatusLevelMin) { + groupEmojiStatusLevelMin = (int) num.value; + editor.putInt("groupEmojiStatusLevelMin", groupEmojiStatusLevelMin); + changed = true; + } + } + break; + } + case "group_emoji_stickers_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != groupEmojiStickersLevelMin) { + groupEmojiStickersLevelMin = (int) num.value; + editor.putInt("groupEmojiStickersLevelMin", groupEmojiStickersLevelMin); + changed = true; + } + } + break; + } + case "group_profile_bg_icon_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != groupProfileBgIconLevelMin) { + groupProfileBgIconLevelMin = (int) num.value; + editor.putInt("groupProfileBgIconLevelMin", groupProfileBgIconLevelMin); + changed = true; + } + } + break; + } case "channel_wallpaper_level_min": { if (value.value instanceof TLRPC.TL_jsonNumber) { TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; @@ -3794,20 +3872,31 @@ public class MessagesController extends BaseController implements NotificationCe boolean noLevels = true; boolean hasStandardColors = false; for (int i = 0; i < colors.size(); ++i) { - if (colors.get(i).lvl > 0) { + if (colors.get(i).channelLvl > 0) { noLevels = false; } if (colors.get(i).id < 7) { hasStandardColors = true; } } + + if (type == TYPE_PROFILE && !noLevels) { + noLevels = true; + for (PeerColor color : colors) { + if (color.groupLvl > 0) { + noLevels = false; + break; + } + } + } return noLevels || type == TYPE_NAME && !hasStandardColors; } - public int colorsAvailable(int lvl) { + public int colorsAvailable(int lvl, boolean isGroup) { int count = 0; for (int i = 0; i < colors.size(); ++i) { - if (!colors.get(i).hidden && lvl >= colors.get(i).lvl) { + MessagesController.PeerColor peerColor = colors.get(i); + if (!peerColor.hidden && lvl >= peerColor.getLvl(isGroup)) { count++; } } @@ -3815,20 +3904,30 @@ public class MessagesController extends BaseController implements NotificationCe } public int maxLevel() { + return maxLevel(false); + } + + public int maxLevel(boolean isGroup) { int maxLvl = 0; for (int i = 0; i < colors.size(); ++i) { - if (!colors.get(i).hidden) { - maxLvl = Math.max(maxLvl, colors.get(i).lvl); + MessagesController.PeerColor peerColor = colors.get(i); + if (!peerColor.hidden) { + maxLvl = Math.max(maxLvl, peerColor.getLvl(isGroup)); } } return maxLvl; } public int minLevel() { - int minLvl = maxLevel(); + return minLevel(false); + } + + public int minLevel(boolean isGroup) { + int minLvl = maxLevel(isGroup); for (int i = 0; i < colors.size(); ++i) { - if (!colors.get(i).hidden) { - minLvl = Math.min(minLvl, colors.get(i).lvl); + MessagesController.PeerColor peerColor = colors.get(i); + if (!peerColor.hidden) { + minLvl = Math.min(minLvl, peerColor.getLvl(isGroup)); } } return minLvl; @@ -3980,7 +4079,8 @@ public class MessagesController extends BaseController implements NotificationCe public boolean isDefaultName; public int id; public boolean hidden; - public int lvl; + public int channelLvl; + public int groupLvl; private final int[] colors = new int[6]; private final int[] darkColors = new int[6]; public int getColor(int i, Theme.ResourcesProvider resourcesProvider) { @@ -3991,6 +4091,9 @@ public class MessagesController extends BaseController implements NotificationCe final boolean isDark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); return (isDark ? darkColors : colors)[i]; } + public int getLvl(boolean isGroup) { + return isGroup ? groupLvl : channelLvl; + } public int getColor1(boolean isDark) { return (isDark ? darkColors : colors)[0]; } @@ -4060,8 +4163,8 @@ public class MessagesController extends BaseController implements NotificationCe public void appendString(StringBuilder sb) { sb.append("#"); if (hidden) sb.append("H"); - if (lvl > 0) { - sb.append("[").append(lvl).append("]"); + if (channelLvl != 0 || groupLvl != 0) { + sb.append("[").append(channelLvl).append(",").append(groupLvl).append("]"); } sb.append(id); sb.append("{"); @@ -4112,7 +4215,10 @@ public class MessagesController extends BaseController implements NotificationCe peerColor.id = tl.color_id; peerColor.hidden = tl.hidden; if ((tl.flags & 8) != 0) { - peerColor.lvl = tl.channel_min_level; + peerColor.channelLvl = tl.channel_min_level; + } + if ((tl.flags & 16) != 0) { + peerColor.groupLvl = tl.group_min_level; } System.arraycopy(optionToColors(tl.colors), 0, peerColor.colors, 0, 6); @@ -4162,11 +4268,19 @@ public class MessagesController extends BaseController implements NotificationCe if (hidden) { startIndex++; } - int lvl = 0; + int channelLvl = 0; + int groupLvl = 0; if (string.length() > startIndex && string.charAt(startIndex) == '[') { int eindex = string.indexOf(']'); if (eindex > startIndex) { - lvl = Utilities.parseInt(string.substring(startIndex + 1, eindex)); + String subStr = string.substring(startIndex + 1, eindex); + if (subStr.contains(",")) { + String[] splits = subStr.split(","); + channelLvl = Utilities.parseInt(splits[0]); + groupLvl = Utilities.parseInt(splits[1]); + } else { + channelLvl = Utilities.parseInt(subStr); + } startIndex = eindex + 1; } } @@ -4176,7 +4290,8 @@ public class MessagesController extends BaseController implements NotificationCe final PeerColor peerColor = new PeerColor(); peerColor.id = Utilities.parseInt(string.substring(startIndex, index)); peerColor.hidden = hidden; - peerColor.lvl = lvl; + peerColor.channelLvl = channelLvl; + peerColor.groupLvl = groupLvl; final String[] parts = string.substring(index + 1, string.length() - 1).split("@"); String[] colorsString = parts[0].split(","); for (int i = 0; i < 6; ++i) @@ -5997,6 +6112,9 @@ public class MessagesController extends BaseController implements NotificationCe if (res.full_chat.stickerset != null) { getMediaDataController().getGroupStickerSetById(res.full_chat.stickerset); } + if (res.full_chat.emojiset != null) { + getMediaDataController().getGroupStickerSetById(res.full_chat.emojiset); + } getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, res.full_chat, classGuid, false, true); TLRPC.Dialog dialog = dialogs_dict.get(-chatId); @@ -6972,6 +7090,18 @@ public class MessagesController extends BaseController implements NotificationCe }); } + public void setBoostsToUnblockRestrictions(long chatId, int boosts) { + TLRPC.TL_channels_setBoostsToUnblockRestrictions req = new TLRPC.TL_channels_setBoostsToUnblockRestrictions(); + req.boosts = boosts; + req.channel = getInputChannel(chatId); + getConnectionsManager().sendRequest(req, (response, error) -> { + if (error == null) { + getMessagesController().processUpdates((TLRPC.Updates) response, false); + AndroidUtilities.runOnUIThread(() -> loadFullChat(chatId, 0, true), 1000); + } + }); + } + public void setDefaultBannedRole(long chatId, TLRPC.TL_chatBannedRights rights, boolean isChannel, BaseFragment parentFragment) { if (rights == null) { return; @@ -8305,6 +8435,9 @@ public class MessagesController extends BaseController implements NotificationCe if (info.stickerset != null) { getMediaDataController().getGroupStickerSetById(info.stickerset); } + if (info.emojiset != null) { + getMediaDataController().getGroupStickerSetById(info.emojiset); + } getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, byChannelUsers, false); } if (pinnedMessages != null) { @@ -9397,7 +9530,7 @@ public class MessagesController extends BaseController implements NotificationCe if (loadDialog && isTopic && load_type == 2 && last_message_id == 0) { TLRPC.TL_forumTopic topic = topicsController.findTopic(-dialogId, threadMessageId); if (topic != null) { - loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, false, minDate, classGuid, load_type, topic.top_message, 0, threadMessageId, loadIndex, first_unread, topic.unread_count, last_date, queryFromServer, topic.unread_mentions_count, false, processMessages, isTopic, loaderLogger, 0L); + loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, false, minDate, classGuid, load_type, topic.top_message, mode, threadMessageId, loadIndex, first_unread, topic.unread_count, last_date, queryFromServer, topic.unread_mentions_count, false, processMessages, isTopic, loaderLogger, 0L); return; } } @@ -11657,12 +11790,12 @@ public class MessagesController extends BaseController implements NotificationCe for (int a = 0; a < dialogsRes.messages.size(); a++) { TLRPC.Message message = dialogsRes.messages.get(a); if (promoDialogId == 0 || promoDialogId != message.dialog_id) { - if (message.peer_id.channel_id != 0) { + if (message.peer_id != null && message.peer_id.channel_id != 0) { TLRPC.Chat chat = chatsDict.get(message.peer_id.channel_id); if (chat != null && ChatObject.isNotInChat(chat)) { continue; } - } else if (message.peer_id.chat_id != 0) { + } else if (message.peer_id != null && message.peer_id.chat_id != 0) { TLRPC.Chat chat = chatsDict.get(message.peer_id.chat_id); if (chat != null && (chat.migrated_to != null || ChatObject.isNotInChat(chat))) { continue; @@ -16220,16 +16353,6 @@ public class MessagesController extends BaseController implements NotificationCe getNotificationCenter().postNotificationName(NotificationCenter.blockedUsersDidLoad); getStoriesController().updateBlockUser(id, finalUpdate.blocked_my_stories_from, false); })); - } else if (baseUpdate instanceof TLRPC.TL_updateNotifySettings) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateNewAuthorization) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateServiceNotification) { TLRPC.TL_updateServiceNotification update = (TLRPC.TL_updateServiceNotification) baseUpdate; if (update.popup && update.message != null && update.message.length() > 0) { @@ -16282,32 +16405,12 @@ public class MessagesController extends BaseController implements NotificationCe } pushMessages.add(obj); } - } else if (baseUpdate instanceof TL_stories.TL_updateStoriesStealthMode) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateDialogPinned) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updatePinnedDialogs) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateFolderPeers) { TLRPC.TL_updateFolderPeers update = (TLRPC.TL_updateFolderPeers) baseUpdate; if (folderUpdates == null) { folderUpdates = new ArrayList<>(); } folderUpdates.add(update); - } else if (baseUpdate instanceof TLRPC.TL_updatePrivacy) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateWebPage) { TLRPC.TL_updateWebPage update = (TLRPC.TL_updateWebPage) baseUpdate; if (webPages == null) { @@ -16470,36 +16573,6 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new ArrayList<>(); } updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateStickerSets) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateStickerSetsOrder) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateNewStickerSet) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateDraftMessage) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateMoveStickerSetToTop) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateSavedGifs) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateEditChannelMessage || baseUpdate instanceof TLRPC.TL_updateEditMessage) { TLRPC.Message message; if (baseUpdate instanceof TLRPC.TL_updateEditChannelMessage) { @@ -16592,54 +16665,14 @@ public class MessagesController extends BaseController implements NotificationCe } else if (baseUpdate instanceof TLRPC.TL_updatePinnedMessages) { TLRPC.TL_updatePinnedMessages update = (TLRPC.TL_updatePinnedMessages) baseUpdate; getMessagesStorage().updatePinnedMessages(MessageObject.getPeerId(update.peer), update.messages, update.pinned, -1, 0, false, null); - } else if (baseUpdate instanceof TLRPC.TL_updateReadFeaturedStickers) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateReadFeaturedEmojiStickers) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updatePhoneCall) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateGroupCallParticipants) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateGroupCall) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateGroupCallConnection) { - } else if (baseUpdate instanceof TLRPC.TL_updateBotCommands) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updatePhoneCallSignalingData) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateLangPack) { TLRPC.TL_updateLangPack update = (TLRPC.TL_updateLangPack) baseUpdate; AndroidUtilities.runOnUIThread(() -> LocaleController.getInstance().saveRemoteLocaleStringsForCurrentLocale(update.difference, currentAccount)); } else if (baseUpdate instanceof TLRPC.TL_updateLangPackTooLong) { TLRPC.TL_updateLangPackTooLong update = (TLRPC.TL_updateLangPackTooLong) baseUpdate; LocaleController.getInstance().reloadCurrentRemoteLocale(currentAccount, update.lang_code, false, null); - } else if (baseUpdate instanceof TLRPC.TL_updateRecentReactions || baseUpdate instanceof TLRPC.TL_updateSavedReactionTags) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateFavedStickers) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); @@ -16710,53 +16743,8 @@ public class MessagesController extends BaseController implements NotificationCe } updatesOnMainThread.add(baseUpdate); } - } else if (baseUpdate instanceof TLRPC.TL_updatePeerLocated) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateTheme) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateGeoLiveViewed) { getLocationController().setNewLocationEndWatchTime(); - } else if (baseUpdate instanceof TLRPC.TL_updateDialogFilter) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateDialogFilterOrder) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateDialogFilters) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateRecentEmojiStatuses) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateWebViewResultSent) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateAttachMenuBots) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateBotMenuButton) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateReadChannelDiscussionInbox) { TLRPC.TL_updateReadChannelDiscussionInbox update = (TLRPC.TL_updateReadChannelDiscussionInbox) baseUpdate; if (updatesOnMainThread == null) { @@ -16782,42 +16770,51 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new ArrayList<>(); } updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updatePeerHistoryTTL) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updatePendingJoinRequests) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateSavedRingtones) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateTranscribeAudio) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateTranscribedAudio) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateChannelViewForumAsMessages) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updatePinnedSavedDialogs) { - if (updatesOnMainThread == null) { - updatesOnMainThread = new ArrayList<>(); - } - updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateSavedDialogPinned) { +// } else if ( +// baseUpdate instanceof TLRPC.TL_updateStickerSets || +// baseUpdate instanceof TLRPC.TL_updateStickerSetsOrder || +// baseUpdate instanceof TLRPC.TL_updateNewStickerSet || +// baseUpdate instanceof TLRPC.TL_updateDraftMessage || +// baseUpdate instanceof TLRPC.TL_updateMoveStickerSetToTop || +// baseUpdate instanceof TLRPC.TL_updateSavedGifs || +// baseUpdate instanceof TLRPC.TL_updateReadFeaturedStickers || +// baseUpdate instanceof TLRPC.TL_updatePhoneCallSignalingData || +// baseUpdate instanceof TLRPC.TL_updateBotCommands || +// baseUpdate instanceof TLRPC.TL_updateGroupCall || +// baseUpdate instanceof TLRPC.TL_updateReadFeaturedEmojiStickers || +// baseUpdate instanceof TLRPC.TL_updateGroupCallParticipants || +// baseUpdate instanceof TLRPC.TL_updatePhoneCall || +// baseUpdate instanceof TLRPC.TL_updateRecentReactions || +// baseUpdate instanceof TLRPC.TL_updateSavedReactionTags || +// baseUpdate instanceof TLRPC.TL_updatePeerLocated || +// baseUpdate instanceof TLRPC.TL_updateTheme || +// baseUpdate instanceof TLRPC.TL_updateDialogFilter || +// baseUpdate instanceof TLRPC.TL_updateDialogFilterOrder || +// baseUpdate instanceof TLRPC.TL_updateDialogFilters || +// baseUpdate instanceof TLRPC.TL_updateRecentEmojiStatuses || +// baseUpdate instanceof TLRPC.TL_updateWebViewResultSent || +// baseUpdate instanceof TLRPC.TL_updateAttachMenuBots || +// baseUpdate instanceof TLRPC.TL_updateBotMenuButton || +// baseUpdate instanceof TLRPC.TL_updatePeerHistoryTTL || +// baseUpdate instanceof TLRPC.TL_updatePendingJoinRequests || +// baseUpdate instanceof TLRPC.TL_updateSavedRingtones || +// baseUpdate instanceof TLRPC.TL_updateTranscribedAudio || +// baseUpdate instanceof TLRPC.TL_updateTranscribeAudio || +// baseUpdate instanceof TLRPC.TL_updateChannelViewForumAsMessages || +// baseUpdate instanceof TLRPC.TL_updatePinnedSavedDialogs || +// baseUpdate instanceof TLRPC.TL_updateSavedDialogPinned || +// baseUpdate instanceof TLRPC.TL_updateNewAuthorization || +// baseUpdate instanceof TLRPC.TL_updateNotifySettings || +// baseUpdate instanceof TL_stories.TL_updateStoriesStealthMode || +// baseUpdate instanceof TLRPC.TL_updateDialogPinned || +// baseUpdate instanceof TLRPC.TL_updatePinnedDialogs || +// baseUpdate instanceof TLRPC.TL_updatePrivacy +// ) { +// if (updatesOnMainThread == null) { +// updatesOnMainThread = new ArrayList<>(); +// } +// updatesOnMainThread.add(baseUpdate); + } else { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); } @@ -17661,6 +17658,8 @@ public class MessagesController extends BaseController implements NotificationCe } } else if (baseUpdate instanceof TLRPC.TL_updatePinnedSavedDialogs || baseUpdate instanceof TLRPC.TL_updateSavedDialogPinned) { getSavedMessagesController().processUpdate(baseUpdate); + } else if (ApplicationLoader.applicationLoaderInstance != null) { + ApplicationLoader.applicationLoaderInstance.processUpdate(currentAccount, baseUpdate); } } if (editor != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index a5a18c909..d8d2ec73d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -1363,6 +1363,8 @@ public class MessagesStorage extends BaseController { database.executeFast("DELETE FROM story_pushes").stepThis().dispose(); database.executeFast("DELETE FROM dialog_photos").stepThis().dispose(); database.executeFast("DELETE FROM dialog_photos_count").stepThis().dispose(); + database.executeFast("DELETE FROM saved_reaction_tags").stepThis().dispose(); + cursor = database.queryFinalized("SELECT did FROM dialogs WHERE 1"); while (cursor.next()) { @@ -14835,6 +14837,9 @@ public class MessagesStorage extends BaseController { } } } + if (message.media.storyItem != null && message.media.storyItem.from_id != null) { + addLoadPeerInfo(message.media.storyItem.from_id, usersToLoad, chatsToLoad); + } } if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage != null && message.media.webpage.attributes != null) { for (int i = 0; i < message.media.webpage.attributes.size(); ++i) { @@ -14852,6 +14857,9 @@ public class MessagesStorage extends BaseController { } } } + if (attr.storyItem != null && attr.storyItem.from_id != null) { + addLoadPeerInfo(attr.storyItem.from_id, usersToLoad, chatsToLoad); + } } } } @@ -15246,7 +15254,6 @@ public class MessagesStorage extends BaseController { } public static void createFirstHoles(long did, SQLitePreparedStatement state5, SQLitePreparedStatement state6, int messageId, long topicId) throws Exception { - FileLog.d("createFirstHoles " + did + " " + messageId + " " + topicId); state5.requery(); int pointer = 1; state5.bindLong(pointer++, did); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 3c6756039..554ee8680 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -9,7 +9,6 @@ package org.telegram.messenger; import android.os.SystemClock; -import android.util.Log; import android.util.SparseArray; import android.view.View; @@ -231,7 +230,12 @@ public class NotificationCenter { public static final int userIsPremiumBlockedUpadted = totalEvents++; public static final int savedMessagesForwarded = totalEvents++; public static final int emojiKeywordsLoaded = totalEvents++; + public static final int smsJobStatusUpdate = totalEvents++; public static final int storyQualityUpdate = totalEvents++; + public static final int openBoostForUsersDialog = totalEvents++; + public static final int groupRestrictionsUnlockedByBoosts = totalEvents++; + public static final int chatWasBoostedByUser = totalEvents++; + public static final int groupPackUpdated = 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 f80b2397d..afee56ae8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java @@ -150,6 +150,10 @@ public class PushListenerController { jsonString = new String(strBytes); JSONObject json = new JSONObject(jsonString); + if (ApplicationLoader.applicationLoaderInstance != null && ApplicationLoader.applicationLoaderInstance.consumePush(currentAccount, json)) { + return; + } + if (json.has("loc_key")) { loc_key = json.getString("loc_key"); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java index 7d354ba0d..677635b2a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java @@ -492,11 +492,11 @@ public class SavedMessagesController { } } if (d != null) { - if (Math.max(0, d.messagesCount - ids.size()) != d.messagesCount) { + if (d.messagesCountLoaded && Math.max(0, d.messagesCount - ids.size()) != d.messagesCount) { d.messagesCount = Math.max(0, d.messagesCount - ids.size()); changed = true; } - if (d.messagesCount <= 0) { + if (d.messagesCountLoaded && d.messagesCount <= 0) { removeDialog(d.dialogId); changed = true; } else if (d.top_message_id <= maxId) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 811681743..b690f6733 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -132,7 +132,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe public TLRPC.InputReplyTo createReplyInput(TL_stories.StoryItem storyItem) { TLRPC.TL_inputReplyToStory replyTo = new TLRPC.TL_inputReplyToStory(); replyTo.story_id = storyItem.id; - replyTo.user_id = getMessagesController().getInputUser(storyItem.dialogId); + replyTo.peer = getMessagesController().getInputPeer(storyItem.dialogId); return replyTo; } @@ -3840,7 +3840,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (replyToStoryItem != null) { newMsg.reply_to = new TLRPC.TL_messageReplyStoryHeader(); newMsg.reply_to.story_id = replyToStoryItem.id; - newMsg.reply_to.user_id = replyToStoryItem.dialogId; + newMsg.reply_to.peer = getMessagesController().getPeer(replyToStoryItem.dialogId); newMsg.replyStory = replyToStoryItem; newMsg.flags |= TLRPC.MESSAGE_FLAG_REPLY; } else if (replyToMsg != null && (replyToTopMsg == null || replyToMsg != replyToTopMsg || replyToTopMsg.getId() != 1)) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index f3b976f3e..876fad719 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -254,6 +254,7 @@ public class SharedConfig { public static boolean forceDisableTabletMode; public static boolean updateStickersOrderOnSend = true; public static boolean bigCameraForRound; + public static boolean useCamera2; public static boolean useSurfaceInStories; public static boolean photoViewerBlur = true; public static boolean payByInvoice; @@ -642,6 +643,7 @@ public class SharedConfig { updateStickersOrderOnSend = preferences.getBoolean("updateStickersOrderOnSend", true); dayNightWallpaperSwitchHint = preferences.getInt("dayNightWallpaperSwitchHint", 0); bigCameraForRound = preferences.getBoolean("bigCameraForRound", false); + useCamera2 = preferences.getBoolean("useCamera2", false); useSurfaceInStories = preferences.getBoolean("useSurfaceInStories", Build.VERSION.SDK_INT >= 30); payByInvoice = preferences.getBoolean("payByInvoice", false); photoViewerBlur = preferences.getBoolean("photoViewerBlur", true); @@ -1737,6 +1739,13 @@ public class SharedConfig { .apply(); } + public static void toggleUseCamera2() { + ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE) + .edit() + .putBoolean("useCamera2", useCamera2 = !useCamera2) + .apply(); + } + @Deprecated public static int getLegacyDevicePerformanceClass() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/Camera2Session.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/Camera2Session.java new file mode 100644 index 000000000..6374e2d9a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/Camera2Session.java @@ -0,0 +1,538 @@ +package org.telegram.messenger.camera; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.ImageFormat; +import android.graphics.Rect; +import android.graphics.SurfaceTexture; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.CameraMetadata; +import android.hardware.camera2.CaptureFailure; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.StreamConfigurationMap; +import android.media.Image; +import android.media.ImageReader; +import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Log; +import android.util.Size; +import android.util.SizeF; +import android.view.Surface; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +public class Camera2Session { + + private boolean isError; + private boolean isSuccess; + private boolean isClosed; + + private final CameraManager cameraManager; + private final boolean isFront; + public final String cameraId; + private CameraCharacteristics cameraCharacteristics; + + private HandlerThread thread; + private Handler handler; + + private CameraDevice cameraDevice; + private SurfaceTexture surfaceTexture; + private CameraCaptureSession captureSession; + private Surface surface; + + private final CameraDevice.StateCallback cameraStateCallback; + private final CameraCaptureSession.StateCallback captureStateCallback; + private CaptureRequest.Builder captureRequestBuilder; + private Rect sensorSize; + private float maxZoom = 1f; + private float currentZoom = 1f; + + private final Size previewSize; + + private ImageReader imageReader; + + private long lastTime; + + public static Camera2Session create(boolean round, boolean front, int viewWidth, int viewHeight) { + final Context context = ApplicationLoader.applicationContext; + final CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); + + float bestAspectRatio = 0; + Size bestSize = null; + String cameraId = null; + try { + String[] cameraIds = cameraManager.getCameraIdList(); + for (int i = 0; i < cameraIds.length; ++i) { + final String id = cameraIds[i]; + CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); + if (characteristics == null) continue; + if (characteristics.get(CameraCharacteristics.LENS_FACING) != (front ? CameraCharacteristics.LENS_FACING_FRONT : CameraCharacteristics.LENS_FACING_BACK)) { + continue; + } + StreamConfigurationMap confMap = (StreamConfigurationMap) characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + Size pixelSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); + float cameraAspectRatio = pixelSize == null ? 0 : (float) pixelSize.getWidth() / pixelSize.getHeight(); + final Size targetAspectRatio = round ? new Size(1, 1) : new Size(9, 16); + final int targetWidth = round ? MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize : viewWidth; + final int targetHeight = round ? MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize : viewHeight; + if (bestAspectRatio <= 0 || Math.abs((float) targetAspectRatio.getWidth() / targetAspectRatio.getHeight() - bestAspectRatio) > Math.abs((float) targetAspectRatio.getWidth() / targetAspectRatio.getHeight() - cameraAspectRatio)) { + if (confMap != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + Size size = chooseOptimalSize(confMap.getOutputSizes(SurfaceTexture.class), targetWidth, targetHeight, targetAspectRatio, false); + if (size != null) { + bestAspectRatio = cameraAspectRatio; + cameraId = id; + bestSize = size; + } + } + } else { + + } + } + } catch (Exception e) { + FileLog.e(e); + } + + if (cameraId == null || bestSize == null) { + return null; + } + return new Camera2Session(context, front, cameraId, bestSize); + } + + private Camera2Session(Context context, boolean isFront, String cameraId, Size size) { + thread = new HandlerThread("tg_camera2"); + thread.start(); + handler = new Handler(thread.getLooper()); + + cameraStateCallback = new CameraDevice.StateCallback() { + @Override + public void onOpened(@NonNull CameraDevice camera) { + Camera2Session.this.cameraDevice = camera; + Camera2Session.this.lastTime = System.currentTimeMillis(); + FileLog.d("Camera2Session camera #" + cameraId + " opened"); + checkOpen(); + } + + @Override + public void onDisconnected(@NonNull CameraDevice camera) { + Camera2Session.this.cameraDevice = camera; + FileLog.d("Camera2Session camera #" + cameraId + " disconnected"); + } + + @Override + public void onError(@NonNull CameraDevice camera, int error) { + Camera2Session.this.cameraDevice = camera; + FileLog.e("Camera2Session camera #" + cameraId + " received " + error + " error"); + AndroidUtilities.runOnUIThread(() -> { + isError = true; + }); + } + }; + + captureStateCallback = new CameraCaptureSession.StateCallback() { + @Override + public void onConfigured(@NonNull CameraCaptureSession session) { + captureSession = session; + FileLog.e("Camera2Session camera #" + cameraId + " capture session configured"); + Camera2Session.this.lastTime = System.currentTimeMillis(); + try { + updateCaptureRequest(); + AndroidUtilities.runOnUIThread(() -> { + isSuccess = true; + if (doneCallback != null) { + doneCallback.run(); + doneCallback = null; + } + }); + } catch (Exception e) { + FileLog.e(e); + } + } + + @Override + public void onConfigureFailed(@NonNull CameraCaptureSession session) { + captureSession = session; + FileLog.e("Camera2Session camera #" + cameraId + " capture session failed to configure"); + AndroidUtilities.runOnUIThread(() -> { + isError = true; + }); + } + }; + + this.isFront = isFront; + this.cameraId = cameraId; + this.previewSize = size; + this.lastTime = System.currentTimeMillis(); + this.imageReader = ImageReader.newInstance(size.getWidth(), size.getHeight(), ImageFormat.JPEG, 1); + cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); + try { + cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId); + sensorSize = cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); + final Float value = cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM); + maxZoom = (value == null || value < 1f) ? 1f : value; + cameraManager.openCamera(cameraId, cameraStateCallback, handler); + } catch (Exception e) { + FileLog.e(e); + AndroidUtilities.runOnUIThread(() -> { + isError = true; + }); + } + } + + private Runnable doneCallback; + public void whenDone(Runnable doneCallback) { + if (isInitiated()) { + doneCallback.run(); + this.doneCallback = null; + } else { + this.doneCallback = doneCallback; + } + } + + public void open(SurfaceTexture surfaceTexture) { + handler.post(() -> { + this.surfaceTexture = surfaceTexture; + if (surfaceTexture != null) { + surfaceTexture.setDefaultBufferSize(getPreviewWidth(), getPreviewHeight()); + } + checkOpen(); + }); + } + + private boolean opened = false; + private void checkOpen() { + if (opened) return; + if (surfaceTexture == null || cameraDevice == null) return; + opened = true; + + surface = new Surface(surfaceTexture); + + try { + ArrayList surfaces = new ArrayList<>(); + surfaces.add(surface); + surfaces.add(imageReader.getSurface()); + cameraDevice.createCaptureSession(surfaces, captureStateCallback, null); + } catch (Exception e) { + FileLog.e(e); + AndroidUtilities.runOnUIThread(() -> { + isError = true; + }); + } + } + + public boolean isInitiated() { + return !isError && isSuccess && !isClosed; + } + + public int getDisplayOrientation() { + // TODO + return 0; + } + + public int getWorldAngle() { + // TODO + return 0; + } + + public int getCurrentOrientation() { + // TODO + return 0; + } + + private final Rect cropRegion = new Rect(); + public void setZoom(float value) { + if (!isInitiated()) return; + if (captureRequestBuilder == null || cameraDevice == null || sensorSize == null) return; + + currentZoom = Utilities.clamp(value, maxZoom, 1f); + updateCaptureRequest(); + + try { + captureSession.setRepeatingRequest(captureRequestBuilder.build(), null, handler); + } catch (Exception e) { + FileLog.e(e); + } + } + + public float getZoom() { + return currentZoom; + } + + public float getMaxZoom() { + return maxZoom; + } + + public float getMinZoom() { + // TODO: support wide zoom camera switching + return 1f; + } + + public int getPreviewWidth() { + return previewSize.getWidth(); + } + + public int getPreviewHeight() { + return previewSize.getHeight(); + } + + public void destroy(boolean async) { + destroy(async, null); + } + + public void destroy(boolean async, Runnable afterCallback) { + isClosed = true; + if (async) { + handler.post(() -> { + if (captureSession != null) { + captureSession.close(); + captureSession = null; + } + if (cameraDevice != null) { + cameraDevice.close(); + cameraDevice = null; + } + if (imageReader != null) { + imageReader.close(); + imageReader = null; + } + AndroidUtilities.runOnUIThread(() -> { + thread.quitSafely(); + try { + thread.join(); + } catch (Exception e) { + FileLog.e(e); + } + if (afterCallback != null) { + afterCallback.run(); + } + }); + }); + } else { + if (captureSession != null) { + captureSession.close(); + captureSession = null; + } + if (cameraDevice != null) { + cameraDevice.close(); + cameraDevice = null; + } + if (imageReader != null) { + imageReader.close(); + imageReader = null; + } + thread.quitSafely(); + try { + thread.join(); + } catch (Exception e) { + FileLog.e(e); + } + if (afterCallback != null) { + AndroidUtilities.runOnUIThread(afterCallback); + } + } + } + + private boolean recordingVideo; + public void setRecordingVideo(boolean recording) { + if (recordingVideo != recording) { + recordingVideo = recording; + updateCaptureRequest(); + } + } + + private boolean scanningBarcode; + public void setScanningBarcode(boolean scanning) { + if (scanningBarcode != scanning) { + scanningBarcode = scanning; + updateCaptureRequest(); + } + } + + private boolean nightMode; + public void setNightMode(boolean enable) { + if (nightMode != enable) { + nightMode = enable; + updateCaptureRequest(); + } + } + + private void updateCaptureRequest() { + if (cameraDevice == null || surface == null || captureSession == null) return; + try { + int template; + if (recordingVideo) { + template = CameraDevice.TEMPLATE_RECORD; + } else if (scanningBarcode) { + template = CameraDevice.TEMPLATE_STILL_CAPTURE; + } else { + template = CameraDevice.TEMPLATE_PREVIEW; + } + captureRequestBuilder = cameraDevice.createCaptureRequest(template); + + if (scanningBarcode) { + captureRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_BARCODE); + } else if (nightMode) { + captureRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, isFront ? CameraMetadata.CONTROL_SCENE_MODE_NIGHT_PORTRAIT : CameraMetadata.CONTROL_SCENE_MODE_NIGHT); + } + + if (sensorSize != null && Math.abs(currentZoom - 1f) >= 0.01f) { + final int centerX = sensorSize.width() / 2; + final int centerY = sensorSize.height() / 2; + final int deltaX = (int) ((0.5f * sensorSize.width()) / currentZoom); + final int deltaY = (int) ((0.5f * sensorSize.height()) / currentZoom); + cropRegion.set( + centerX - deltaX, + centerY - deltaY, + centerX + deltaX, + centerY + deltaY + ); + captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegion); + } + + captureRequestBuilder.addTarget(surface); + captureSession.setRepeatingRequest(captureRequestBuilder.build(), null, handler); + } catch (Exception e) { + FileLog.e("Camera2Sessions setRepeatingRequest error in updateCaptureRequest", e); + } + } + + public boolean takePicture(final File file, Utilities.Callback whenDone) { + if (cameraDevice == null || captureSession == null) return false; + try { + CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); + imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { + @Override + public void onImageAvailable(ImageReader reader) { + Image image = reader.acquireLatestImage(); + ByteBuffer buffer = image.getPlanes()[0].getBuffer(); + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + + FileOutputStream output = null; + try { + output = new FileOutputStream(file); + output.write(bytes); + } catch (IOException e) { + e.printStackTrace(); + } finally { + image.close(); + if (null != output) { + try { + output.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + AndroidUtilities.runOnUIThread(() -> { + if (whenDone != null) { + whenDone.run(0); + } + }); + } + }, null); + if (scanningBarcode) { + captureRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_BARCODE); + } + captureRequestBuilder.addTarget(imageReader.getSurface()); + captureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() { + @Override + public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) { + super.onCaptureStarted(session, request, timestamp, frameNumber); + } + + @Override + public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { + super.onCaptureProgressed(session, request, partialResult); + } + + @Override + public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { + super.onCaptureCompleted(session, request, result); + } + + @Override + public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { + super.onCaptureFailed(session, request, failure); + } + + @Override + public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session, int sequenceId, long frameNumber) { + super.onCaptureSequenceCompleted(session, sequenceId, frameNumber); + } + + @Override + public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session, int sequenceId) { + super.onCaptureSequenceAborted(session, sequenceId); + } + + @Override + public void onCaptureBufferLost(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull Surface target, long frameNumber) { + super.onCaptureBufferLost(session, request, target, frameNumber); + } + }, null); + return true; + } catch (Exception e) { + FileLog.e("Camera2Sessions takePicture error", e); + return false; + } + } + + + public static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio, boolean notBigger) { + List bigEnoughWithAspectRatio = new ArrayList<>(choices.length); + List bigEnough = new ArrayList<>(choices.length); + int w = aspectRatio.getWidth(); + int h = aspectRatio.getHeight(); + for (int a = 0; a < choices.length; a++) { + Size option = choices[a]; + if (notBigger && (option.getHeight() > height || option.getWidth() > width)) { + continue; + } + if (option.getHeight() == option.getWidth() * h / w && option.getWidth() >= width && option.getHeight() >= height) { + bigEnoughWithAspectRatio.add(option); + } else if (option.getHeight() * option.getWidth() <= width * height * 4 && option.getWidth() >= width && option.getHeight() >= height) { + bigEnough.add(option); + } + } + if (bigEnoughWithAspectRatio.size() > 0) { + return Collections.min(bigEnoughWithAspectRatio, new CompareSizesByArea()); + } else if (bigEnough.size() > 0) { + return Collections.min(bigEnough, new CompareSizesByArea()); + } else { + return Collections.max(Arrays.asList(choices), new CompareSizesByArea()); + } + } + static class CompareSizesByArea implements Comparator { + @Override + public int compare(Size lhs, Size rhs) { + return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight()); + } + } + +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraController.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraController.java index b89580efb..180a77d66 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraController.java @@ -401,90 +401,99 @@ public class CameraController implements MediaRecorder.OnInfoListener { return value; } - public boolean takePicture(final File path, final boolean ignoreOrientation, final CameraSession session, final Utilities.Callback callback) { - if (session == null) { + public boolean takePicture(final File path, final boolean ignoreOrientation, final Object sessionObject, final Utilities.Callback callback) { + if (sessionObject == null) { return false; } - final CameraInfo info = session.cameraInfo; - final boolean flipFront = session.isFlipFront(); - Camera camera = info.camera; - try { - camera.takePicture(null, null, (data, camera1) -> { - Bitmap bitmap = null; - int orientation = 0; - int size = (int) (AndroidUtilities.getPhotoSize() / AndroidUtilities.density); - String key = String.format(Locale.US, "%s@%d_%d", Utilities.MD5(path.getAbsolutePath()), size, size); - try { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeByteArray(data, 0, data.length, options); -// float scaleFactor = Math.max((float) options.outWidth / AndroidUtilities.getPhotoSize(), (float) options.outHeight / AndroidUtilities.getPhotoSize()); -// if (scaleFactor < 1) { -// scaleFactor = 1; -// } - options.inJustDecodeBounds = false; - // options.inSampleSize = (int) scaleFactor; - options.inPurgeable = true; - bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options); - } catch (Throwable e) { - FileLog.e(e); - } - try { - orientation = getOrientation(data); - if (info.frontCamera != 0 && flipFront) { - try { - Matrix matrix = new Matrix(); - if (!ignoreOrientation && orientation != -1) { - matrix.setRotate(orientation); + if (sessionObject instanceof CameraSession) { + CameraSession session = (CameraSession) sessionObject; + final CameraInfo info = session.cameraInfo; + final boolean flipFront = session.isFlipFront(); + Camera camera = info.camera; + try { + camera.takePicture(null, null, (data, camera1) -> { + Bitmap bitmap = null; + int orientation = 0; + int size = (int) (AndroidUtilities.getPhotoSize() / AndroidUtilities.density); + String key = String.format(Locale.US, "%s@%d_%d", Utilities.MD5(path.getAbsolutePath()), size, size); + try { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeByteArray(data, 0, data.length, options); + // float scaleFactor = Math.max((float) options.outWidth / AndroidUtilities.getPhotoSize(), (float) options.outHeight / AndroidUtilities.getPhotoSize()); + // if (scaleFactor < 1) { + // scaleFactor = 1; + // } + options.inJustDecodeBounds = false; + // options.inSampleSize = (int) scaleFactor; + options.inPurgeable = true; + bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options); + } catch (Throwable e) { + FileLog.e(e); + } + try { + orientation = getOrientation(data); + if (info.frontCamera != 0 && flipFront) { + try { + Matrix matrix = new Matrix(); + if (!ignoreOrientation && orientation != -1) { + matrix.setRotate(orientation); + } + orientation = 0; + matrix.postScale(-1, 1); + Bitmap scaled = Bitmaps.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + if (scaled != bitmap) { + bitmap.recycle(); + } + FileOutputStream outputStream = new FileOutputStream(path); + scaled.compress(Bitmap.CompressFormat.JPEG, 80, outputStream); + outputStream.flush(); + outputStream.getFD().sync(); + outputStream.close(); + if (scaled != null) { + ImageLoader.getInstance().putImageToCache(new BitmapDrawable(scaled), key, false); + } + if (callback != null) { + callback.run(orientation); + } + return; + } catch (Throwable e) { + FileLog.e(e); } - orientation = 0; - matrix.postScale(-1, 1); - Bitmap scaled = Bitmaps.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); - if (scaled != bitmap) { - bitmap.recycle(); - } - FileOutputStream outputStream = new FileOutputStream(path); - scaled.compress(Bitmap.CompressFormat.JPEG, 80, outputStream); - outputStream.flush(); - outputStream.getFD().sync(); - outputStream.close(); - if (scaled != null) { - ImageLoader.getInstance().putImageToCache(new BitmapDrawable(scaled), key, false); - } - if (callback != null) { - callback.run(orientation); - } - return; - } catch (Throwable e) { - FileLog.e(e); } + FileOutputStream outputStream = new FileOutputStream(path); + outputStream.write(data); + outputStream.flush(); + outputStream.getFD().sync(); + outputStream.close(); + if (bitmap != null) { + ImageLoader.getInstance().putImageToCache(new BitmapDrawable(bitmap), key, false); + } + } catch (Exception e) { + FileLog.e(e); } - FileOutputStream outputStream = new FileOutputStream(path); - outputStream.write(data); - outputStream.flush(); - outputStream.getFD().sync(); - outputStream.close(); - if (bitmap != null) { - ImageLoader.getInstance().putImageToCache(new BitmapDrawable(bitmap), key, false); + if (callback != null) { + callback.run(orientation); } - } catch (Exception e) { - FileLog.e(e); - } - if (callback != null) { - callback.run(orientation); - } - }); - return true; - } catch (Exception e) { - FileLog.e(e); + }); + return true; + } catch (Exception e) { + FileLog.e(e); + } + return false; + } else if (sessionObject instanceof Camera2Session) { + Camera2Session session = (Camera2Session) sessionObject; + return session.takePicture(path, callback); + } else { + return false; } - return false; } - public void startPreview(final CameraSession session) { - if (session == null) { + public void startPreview(final Object sessionObject) { + if (sessionObject == null || !(sessionObject instanceof CameraSession)) { return; } + CameraSession session = (CameraSession) sessionObject; threadPool.execute(() -> { Camera camera = session.cameraInfo.camera; try { @@ -503,10 +512,11 @@ public class CameraController implements MediaRecorder.OnInfoListener { }); } - public void stopPreview(final CameraSession session) { - if (session == null) { + public void stopPreview(final Object sessionObject) { + if (sessionObject == null || !(sessionObject instanceof CameraSession)) { return; } + CameraSession session = (CameraSession) sessionObject; threadPool.execute(() -> { Camera camera = session.cameraInfo.camera; try { @@ -615,39 +625,44 @@ public class CameraController implements MediaRecorder.OnInfoListener { }); } - public void recordVideo(final CameraSession session, final File path, boolean mirror, final VideoTakeCallback callback, final Runnable onVideoStartRecord, ICameraView cameraView) { + public void recordVideo(final Object session, final File path, boolean mirror, final VideoTakeCallback callback, final Runnable onVideoStartRecord, ICameraView cameraView) { recordVideo(session, path, mirror, callback, onVideoStartRecord, cameraView, true); } - public void recordVideo(final CameraSession session, final File path, boolean mirror, final VideoTakeCallback callback, final Runnable onVideoStartRecord, ICameraView cameraView, boolean createThumbnail) { - if (session == null) { + public void recordVideo(final Object sessionObject, final File path, boolean mirror, final VideoTakeCallback callback, final Runnable onVideoStartRecord, ICameraView cameraView, boolean createThumbnail) { + if (sessionObject == null) { return; } - final CameraInfo info = session.cameraInfo; - final Camera camera = info.camera; if (cameraView != null) { recordingCurrentCameraView = cameraView; onVideoTakeCallback = callback; recordedFile = path.getAbsolutePath(); threadPool.execute(() -> { try { - if (camera != null) { - try { - Camera.Parameters params = camera.getParameters(); - params.setFlashMode(session.getCurrentFlashMode().equals(Camera.Parameters.FLASH_MODE_ON) ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF); - camera.setParameters(params); - session.onStartRecord(); - } catch (Exception e) { - FileLog.e(e); - } - AndroidUtilities.runOnUIThread(() -> { - cameraView.startRecording(path, () -> finishRecordingVideo(createThumbnail)); - - if (onVideoStartRecord != null) { - onVideoStartRecord.run(); + if (sessionObject instanceof CameraSession) { + CameraSession session = (CameraSession) sessionObject; + final CameraInfo info = session.cameraInfo; + final Camera camera = info.camera; + if (camera != null) { + try { + Camera.Parameters params = camera.getParameters(); + params.setFlashMode(session.getCurrentFlashMode().equals(Camera.Parameters.FLASH_MODE_ON) ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF); + camera.setParameters(params); + session.onStartRecord(); + } catch (Exception e) { + FileLog.e(e); } - }); + } + } else if (sessionObject instanceof Camera2Session) { + Camera2Session session = (Camera2Session) sessionObject; + session.setRecordingVideo(true); } + AndroidUtilities.runOnUIThread(() -> { + cameraView.startRecording(path, () -> finishRecordingVideo(createThumbnail)); + if (onVideoStartRecord != null) { + onVideoStartRecord.run(); + } + }); } catch (Exception e) { FileLog.e(e); } @@ -656,60 +671,66 @@ public class CameraController implements MediaRecorder.OnInfoListener { return; } - - threadPool.execute(() -> { - try { - if (camera != null) { - try { - Camera.Parameters params = camera.getParameters(); - params.setFlashMode(session.getCurrentFlashMode().equals(Camera.Parameters.FLASH_MODE_ON) ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF); - camera.setParameters(params); - } catch (Exception e) { - FileLog.e(e); - } - camera.unlock(); + if (sessionObject instanceof CameraSession) { + CameraSession session = (CameraSession) sessionObject; + final CameraInfo info = session.cameraInfo; + final Camera camera = info.camera; + threadPool.execute(() -> { + try { + if (camera != null) { + try { + Camera.Parameters params = camera.getParameters(); + params.setFlashMode(session.getCurrentFlashMode().equals(Camera.Parameters.FLASH_MODE_ON) ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF); + camera.setParameters(params); + } catch (Exception e) { + FileLog.e(e); + } + camera.unlock(); // camera.stopPreview(); - try { - mirrorRecorderVideo = mirror; - recorder = new MediaRecorder(); - recorder.setCamera(camera); - recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); - recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); - session.configureRecorder(1, recorder); - recorder.setOutputFile(path.getAbsolutePath()); - recorder.setMaxFileSize(1024 * 1024 * 1024); - recorder.setVideoFrameRate(30); - recorder.setMaxDuration(0); - Size pictureSize; - pictureSize = new Size(16, 9); - pictureSize = CameraController.chooseOptimalSize(info.getPictureSizes(), 720, 480, pictureSize, false); - int bitrate; - if (Math.min(pictureSize.mHeight,pictureSize.mWidth) >= 720) { - bitrate = 3500000; - } else { - bitrate = 1800000; - } - recorder.setVideoEncodingBitRate(bitrate); - recorder.setVideoSize(pictureSize.getWidth(), pictureSize.getHeight()); - recorder.setOnInfoListener(CameraController.this); - recorder.prepare(); - recorder.start(); + try { + mirrorRecorderVideo = mirror; + recorder = new MediaRecorder(); + recorder.setCamera(camera); + recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); + recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); + session.configureRecorder(1, recorder); + recorder.setOutputFile(path.getAbsolutePath()); + recorder.setMaxFileSize(1024 * 1024 * 1024); + recorder.setVideoFrameRate(30); + recorder.setMaxDuration(0); + Size pictureSize; + pictureSize = new Size(16, 9); + pictureSize = CameraController.chooseOptimalSize(info.getPictureSizes(), 720, 480, pictureSize, false); + int bitrate; + if (Math.min(pictureSize.mHeight, pictureSize.mWidth) >= 720) { + bitrate = 3500000; + } else { + bitrate = 1800000; + } + recorder.setVideoEncodingBitRate(bitrate); + recorder.setVideoSize(pictureSize.getWidth(), pictureSize.getHeight()); + recorder.setOnInfoListener(CameraController.this); + recorder.prepare(); + recorder.start(); - onVideoTakeCallback = callback; - recordedFile = path.getAbsolutePath(); - if (onVideoStartRecord != null) { - AndroidUtilities.runOnUIThread(onVideoStartRecord); + onVideoTakeCallback = callback; + recordedFile = path.getAbsolutePath(); + if (onVideoStartRecord != null) { + AndroidUtilities.runOnUIThread(onVideoStartRecord); + } + } catch (Exception e) { + recorder.release(); + recorder = null; + FileLog.e(e); } - } catch (Exception e) { - recorder.release(); - recorder = null; - FileLog.e(e); } + } catch (Exception e) { + FileLog.e(e); } - } catch (Exception e) { - FileLog.e(e); - } - }); + }); + } else { + return; + } } private void finishRecordingVideo(boolean createThumbnail) { @@ -796,11 +817,11 @@ public class CameraController implements MediaRecorder.OnInfoListener { } } - public void stopVideoRecording(final CameraSession session, final boolean abandon) { - stopVideoRecording(session, abandon, true); + public void stopVideoRecording(final Object sessionObject, final boolean abandon) { + stopVideoRecording(sessionObject, abandon, true); } - public void stopVideoRecording(final CameraSession session, final boolean abandon, final boolean createThumbnail) { + public void stopVideoRecording(final Object sessionObject, final boolean abandon, final boolean createThumbnail) { if (recordingCurrentCameraView != null) { recordingCurrentCameraView.stopRecording(); recordingCurrentCameraView = null; @@ -808,9 +829,7 @@ public class CameraController implements MediaRecorder.OnInfoListener { } threadPool.execute(() -> { try { - CameraInfo info = session.cameraInfo; - final Camera camera = info.camera; - if (camera != null && recorder != null) { + if (recorder != null) { MediaRecorder tempRecorder = recorder; recorder = null; try { @@ -823,34 +842,44 @@ public class CameraController implements MediaRecorder.OnInfoListener { } catch (Exception e) { FileLog.e(e); } - try { - camera.reconnect(); - camera.startPreview(); - } catch (Exception e) { - FileLog.e(e); - } - try { - session.stopVideoRecording(); - } catch (Exception e) { - FileLog.e(e); - } } - try { - Camera.Parameters params = camera.getParameters(); - params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); - camera.setParameters(params); - } catch (Exception e) { - FileLog.e(e); - } - threadPool.execute(() -> { + if (sessionObject instanceof CameraSession) { + CameraSession session = (CameraSession) sessionObject; + CameraInfo info = session.cameraInfo; + final Camera camera = info.camera; + if (camera != null) { + try { + camera.reconnect(); + camera.startPreview(); + } catch (Exception e) { + FileLog.e(e); + } + try { + session.stopVideoRecording(); + } catch (Exception e) { + FileLog.e(e); + } + } try { Camera.Parameters params = camera.getParameters(); - params.setFlashMode(session.getCurrentFlashMode()); + params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); camera.setParameters(params); } catch (Exception e) { FileLog.e(e); } - }); + threadPool.execute(() -> { + try { + Camera.Parameters params = camera.getParameters(); + params.setFlashMode(session.getCurrentFlashMode()); + camera.setParameters(params); + } catch (Exception e) { + FileLog.e(e); + } + }); + } else if (sessionObject instanceof Camera2Session) { + Camera2Session session = (Camera2Session) sessionObject; + session.setRecordingVideo(false); + } if (!abandon && onVideoTakeCallback != null) { finishRecordingVideo(createThumbnail); } else { @@ -894,7 +923,7 @@ public class CameraController implements MediaRecorder.OnInfoListener { } public interface ErrorCallback { - public default void onError(int errorId, Camera camera, CameraSession cameraSession) { + public default void onError(int errorId, Camera camera, CameraSessionWrapper cameraSession) { } } @@ -920,7 +949,7 @@ public class CameraController implements MediaRecorder.OnInfoListener { for (int i = 0; i < errorCallbacks.size(); ++i) { ErrorCallback callback = errorCallbacks.get(i); if (callback != null) { - callback.onError(errorId, camera, session); + callback.onError(errorId, camera, CameraSessionWrapper.of(session)); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSessionWrapper.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSessionWrapper.java new file mode 100644 index 000000000..ad1c71d38 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSessionWrapper.java @@ -0,0 +1,206 @@ +package org.telegram.messenger.camera; + +import android.hardware.Camera; + +import androidx.annotation.Nullable; + +import org.telegram.messenger.AndroidUtilities; + +import java.util.concurrent.CountDownLatch; + +public class CameraSessionWrapper { + public CameraSession camera1Session; + public Camera2Session camera2Session; + + public boolean isInitiated() { + if (camera2Session != null) { + return camera2Session.isInitiated(); + } else if (camera1Session != null) { + return camera1Session.isInitied(); + } else { + return false; + } + } + + public int getWorldAngle() { + if (camera2Session != null) { + return camera2Session.getWorldAngle(); + } else if (camera1Session != null) { + return camera1Session.getWorldAngle(); + } else { + return 0; + } + } + + public int getCurrentOrientation() { + if (camera2Session != null) { + return camera2Session.getCurrentOrientation(); + } else if (camera1Session != null) { + return camera1Session.getCurrentOrientation(); + } else { + return 0; + } + } + + public int getDisplayOrientation() { + if (camera2Session != null) { + return camera2Session.getDisplayOrientation(); + } else if (camera1Session != null) { + return camera1Session.getDisplayOrientation(); + } else { + return 0; + } + } + + @Deprecated + public int getCameraId() { + if (camera2Session != null) { + return camera2Session.cameraId.hashCode(); + } else if (camera1Session != null) { + return camera1Session.cameraInfo.cameraId; + } else { + return 0; + } + } + + public void stopVideoRecording() { + if (camera2Session != null) { + camera2Session.setRecordingVideo(false); + } else if (camera1Session != null) { + camera1Session.stopVideoRecording(); + } + } + + public void setOptimizeForBarcode(boolean optimize) { + if (camera2Session != null) { + camera2Session.setScanningBarcode(optimize); + } else if (camera1Session != null) { + camera1Session.setOptimizeForBarcode(optimize); + } + } + + + public void setCurrentFlashMode(String flashMode) { + if (camera2Session != null) { + // TODO + } else if (camera1Session != null) { + camera1Session.setCurrentFlashMode(flashMode); + } + } + + public String getCurrentFlashMode() { + if (camera2Session != null) { + // TODO + return Camera.Parameters.FLASH_MODE_OFF; + } else if (camera1Session != null) { + return camera1Session.getNextFlashMode(); + } + return null; + } + + public String getNextFlashMode() { + if (camera2Session != null) { + // TODO + return Camera.Parameters.FLASH_MODE_OFF; + } else if (camera1Session != null) { + return camera1Session.getNextFlashMode(); + } + return null; + } + + public boolean hasFlashModes() { + if (camera2Session != null) { + // TODO + return false; + } else if (camera1Session != null) { + return !camera1Session.availableFlashModes.isEmpty(); + } + return false; + } + + public void setFlipFront(boolean flip) { + if (camera2Session != null) { + // TODO + } else if (camera1Session != null) { + camera1Session.setFlipFront(flip); + } + } + + public boolean isSameTakePictureOrientation() { + if (camera2Session != null) { + // TODO + } else if (camera1Session != null) { + return camera1Session.isSameTakePictureOrientation(); + } + return true; + } + + public void updateRotation() { + if (camera2Session != null) { + // TODO + } else if (camera1Session != null) { + camera1Session.updateRotation(); + } + } + + public void setZoom(float zoom) { + if (camera2Session != null) { + camera2Session.setZoom(AndroidUtilities.lerp(camera2Session.getMinZoom(), camera2Session.getMaxZoom(), zoom)); + } else if (camera1Session != null) { + camera1Session.setZoom(zoom); + } + } + + public void focusToRect(android.graphics.Rect focusRect, android.graphics.Rect meteringRect) { + if (camera2Session != null) { + // TODO + } else if (camera1Session != null) { + camera1Session.focusToRect(focusRect, meteringRect); + } + } + + public void destroy(boolean async, Runnable before, Runnable after) { + if (camera2Session != null) { + if (before != null) { + before.run(); + } + camera2Session.destroy(async, after); + } else if (camera1Session != null) { + CameraController.getInstance().close(camera1Session, !async ? new CountDownLatch(1) : null, before, after); + } + } + + public Object getObject() { + if (camera2Session != null) { + return camera2Session; + } else if (camera1Session != null) { + return camera1Session; + } + return null; + } + + public static CameraSessionWrapper of(CameraSession session) { + CameraSessionWrapper wrapper = new CameraSessionWrapper(); + wrapper.camera1Session = session; + return wrapper; + } + + public static CameraSessionWrapper of(Camera2Session session) { + CameraSessionWrapper wrapper = new CameraSessionWrapper(); + wrapper.camera2Session = session; + return wrapper; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj instanceof CameraSession) { + return obj == camera1Session; + } else if (obj instanceof Camera2Session) { + return obj == camera2Session; + } else if (obj instanceof CameraSessionWrapper) { + CameraSessionWrapper wrapper = (CameraSessionWrapper) obj; + return wrapper == this || wrapper.camera1Session == camera1Session && wrapper.camera2Session == camera2Session; + } + return false; + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java index 031e0a7e4..f836368b9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java @@ -98,7 +98,7 @@ import javax.microedition.khronos.egl.EGLSurface; import javax.microedition.khronos.opengles.GL; @SuppressLint("NewApi") -public class CameraView extends FrameLayout implements TextureView.SurfaceTextureListener, CameraController.ICameraView { +public class CameraView extends FrameLayout implements TextureView.SurfaceTextureListener, CameraController.ICameraView, CameraController.ErrorCallback { public boolean WRITE_TO_FILE_IN_BACKGROUND = false; @@ -110,7 +110,6 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur private boolean lazy; private TextureView textureView; private ImageView blurredStubView; - private CameraSession[] cameraSession = new CameraSession[2]; private boolean inited; private CameraViewDelegate delegate; private int clipTop; @@ -121,6 +120,10 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur private int focusAreaSize; private Drawable thumbDrawable; + private final boolean useCamera2 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.useCamera2; + private final CameraSessionWrapper[] cameraSession = new CameraSessionWrapper[2]; + private CameraSessionWrapper cameraSessionRecording; + private boolean useMaxPreview; private long lastDrawTime; @@ -162,8 +165,6 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur Runnable onRecordingFinishRunnable; - private CameraSession cameraSessionRecording; - public boolean startRecording(File path, Runnable onFinished) { cameraSessionRecording = cameraSession[0]; cameraThread.startRecording(path); @@ -267,7 +268,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur return; } closingDualCamera = true; - CameraController.getInstance().close(cameraSession[1], null, null, () -> { + cameraSession[1].destroy(false, null, () -> { closingDualCamera = false; enableDualInternal(); }); @@ -283,11 +284,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur if (handler != null) { cameraThread.sendMessage(handler.obtainMessage(cameraThread.BLUR_CAMERA1), 0); } - CameraController.getInstance().close(cameraSession[0], null, null, () -> { -// inited = false; -// synchronized (layoutLock) { -// firstFrameRendered = false; -// } + cameraSession[0].destroy(false, null, () -> { initFirstCameraAfterSecond = true; updateCameraInfoSize(1); if (handler != null) { @@ -322,7 +319,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur } enableDualInternal(); } else { - if (cameraSession[1] == null || !cameraSession[1].isInitied()) { + if (cameraSession[1] == null || !cameraSession[1].isInitiated()) { dual = !dual; return; } @@ -331,7 +328,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur if (cameraSessionRecording == cameraSession[1]) { cameraSessionRecording = null; } - CameraController.getInstance().close(cameraSession[1], null, null, () -> { + cameraSession[1].destroy(false, null, () -> { closingDualCamera = false; dualCameraAppeared = false; addToDualWait(400L); @@ -390,6 +387,9 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur public CameraView(Context context, boolean frontface, boolean lazy) { super(context, null); + + CameraController.getInstance().addOnErrorListener(this); + initialFrontface = isFrontface = frontface; textureView = new TextureView(context); if (!(this.lazy = lazy)) { @@ -603,7 +603,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur pictureSize[0] = pictureSize[1]; pictureSize[1] = pictureSize0; - CameraSession cameraSession0 = cameraSession[0]; + CameraSessionWrapper cameraSession0 = cameraSession[0]; cameraSession[0] = cameraSession[1]; cameraSession[1] = cameraSession0; @@ -620,7 +620,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur if (cameraSessionRecording == cameraSession[0]) { cameraSessionRecording = null; } - CameraController.getInstance().close(cameraSession[0], null, null, () -> { + cameraSession[0].destroy(false, null, () -> { inited = false; synchronized (layoutLock) { firstFrameRendered = false; @@ -642,7 +642,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur if (handler != null) { cameraThread.sendMessage(handler.obtainMessage(cameraThread.BLUR_CAMERA1), 0); } - CameraController.getInstance().close(cameraSession[0], null, null, () -> { + cameraSession[0].destroy(false, null, () -> { inited = false; synchronized (layoutLock) { firstFrameRendered = false; @@ -770,17 +770,17 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur cameraThread.postRunnable(() -> this.cameraThread = null); } if (cameraSession[0] != null) { - CameraController.getInstance().close(cameraSession[0], null, null); + cameraSession[0].destroy(false, null, null); } if (cameraSession[1] != null) { - CameraController.getInstance().close(cameraSession[1], null, null); + cameraSession[1].destroy(false, null, null); } return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { - if (!inited && cameraSession[0] != null && cameraSession[0].isInitied()) { + if (!inited && cameraSession[0] != null && cameraSession[0].isInitiated()) { if (delegate != null) { delegate.onCameraInit(); } @@ -931,25 +931,30 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur return inited; } - public CameraSession getCameraSession() { + public CameraSessionWrapper getCameraSession() { return getCameraSession(0); } - public CameraSession getCameraSession(int i) { + public Object getCameraSessionObject() { + if (cameraSession[0] == null) return null; + return cameraSession[0].getObject(); + } + + public CameraSessionWrapper getCameraSession(int i) { return cameraSession[i]; } - public CameraSession getCameraSessionRecording() { + public CameraSessionWrapper getCameraSessionRecording() { return cameraSessionRecording; } public void destroy(boolean async, final Runnable beforeDestroyRunnable) { for (int i = 0; i < 2; ++i) { if (cameraSession[i] != null) { - cameraSession[i].destroy(); - CameraController.getInstance().close(cameraSession[i], !async ? new CountDownLatch(1) : null, beforeDestroyRunnable); + cameraSession[i].destroy(async, beforeDestroyRunnable, null); } } + CameraController.getInstance().removeOnErrorListener(this); } public Matrix getMatrix() { @@ -1068,7 +1073,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur private EGLConfig eglConfig; private boolean initied; - private CameraSession currentSession[] = new CameraSession[2]; + private final CameraSessionWrapper currentSession[] = new CameraSessionWrapper[2]; private final SurfaceTexture[] cameraSurface = new SurfaceTexture[2]; @@ -1381,7 +1386,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur } } - public void setCurrentSession(CameraSession session, int i) { + public void setCurrentSession(CameraSessionWrapper session, int i) { Handler handler = getHandler(); if (handler != null) { sendMessage(handler.obtainMessage(DO_SETSESSION_MESSAGE, i, 0, session), 0); @@ -1460,7 +1465,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur } } - if (currentSession[0] == null || currentSession[0].cameraInfo.cameraId != cameraId1) { + if (currentSession[0] == null || currentSession[0].getCameraId() != cameraId1) { return; } @@ -1497,7 +1502,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur if (cameraSurface[i] == null) { continue; } - if (i != 0 && (currentSession[i] == null || !currentSession[i].isInitied()) || i == 0 && cameraId1 < 0 && !dual || i == 1 && cameraId2 < 0) { + if (i != 0 && (currentSession[i] == null || !currentSession[i].isInitiated()) || i == 0 && cameraId1 < 0 && !dual || i == 1 && cameraId2 < 0) { continue; } @@ -1677,13 +1682,13 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur } case DO_SETSESSION_MESSAGE: { final int i = inputMessage.arg1; - CameraSession newSession = (CameraSession) inputMessage.obj; + CameraSessionWrapper newSession = (CameraSessionWrapper) inputMessage.obj; if (newSession == null) { return; } if (currentSession[i] != newSession) { currentSession[i] = newSession; - cameraId[i] = newSession.cameraInfo.cameraId; + cameraId[i] = newSession.getCameraId(); } // currentSession[i].updateRotation(); int rotationAngle = currentSession[i].getWorldAngle(); @@ -1752,7 +1757,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur cameraId[0] = cameraId[1]; cameraId[1] = cameraId0; - CameraSession cameraSession0 = currentSession[0]; + CameraSessionWrapper cameraSession0 = currentSession[0]; currentSession[0] = currentSession[1]; currentSession[1] = cameraSession0; @@ -1935,39 +1940,58 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur return; } if (BuildVars.LOGS_ENABLED) { - FileLog.d("CameraView " + "create camera session " + i); + FileLog.d("CameraView " + "create camera"+(useCamera2 ? "2" : "")+" session " + i); } - if (previewSize[i] == null) { - updateCameraInfoSize(i); - } - if (previewSize[i] == null) { - return; - } - surfaceTexture.setDefaultBufferSize(previewSize[i].getWidth(), previewSize[i].getHeight()); - cameraSession[i] = new CameraSession(info[i], previewSize[i], pictureSize[i], ImageFormat.JPEG, false); - cameraSession[i].setCurrentFlashMode(Camera.Parameters.FLASH_MODE_OFF); - cameraThread.setCurrentSession(cameraSession[i], i); - requestLayout(); - - CameraController.getInstance().open(cameraSession[i], surfaceTexture, () -> { - if (cameraSession[i] != null) { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("CameraView " + "camera initied " + i); - } - cameraSession[i].setInitied(); + if (useCamera2) { + Camera2Session session = Camera2Session.create(false, i == 0 ? isFrontface : !isFrontface, surfaceWidth, surfaceHeight); + if (session == null) return; + cameraSession[i] = CameraSessionWrapper.of(session); + cameraThread.setCurrentSession(cameraSession[i], i); + session.whenDone(() -> { requestLayout(); + if (dual && i == 1 && initFirstCameraAfterSecond) { + initFirstCameraAfterSecond = false; + AndroidUtilities.runOnUIThread(() -> { + updateCameraInfoSize(0); + cameraThread.reinitForNewCamera(); + addToDualWait(350L); + }); + } + }); + session.open(surfaceTexture); + } else { + if (previewSize[i] == null) { + updateCameraInfoSize(i); } + if (previewSize[i] == null) { + return; + } + surfaceTexture.setDefaultBufferSize(previewSize[i].getWidth(), previewSize[i].getHeight()); + CameraSession session = new CameraSession(info[i], previewSize[i], pictureSize[i], ImageFormat.JPEG, false); + session.setCurrentFlashMode(Camera.Parameters.FLASH_MODE_OFF); + cameraSession[i] = CameraSessionWrapper.of(session); + cameraThread.setCurrentSession(cameraSession[i], i); + requestLayout(); + CameraController.getInstance().open(session, surfaceTexture, () -> { + if (cameraSession[i] != null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("CameraView " + "camera initied " + i); + } + session.setInitied(); + requestLayout(); + } - if (dual && i == 1 && initFirstCameraAfterSecond) { - initFirstCameraAfterSecond = false; - AndroidUtilities.runOnUIThread(() -> { - updateCameraInfoSize(0); - cameraThread.reinitForNewCamera(); - addToDualWait(350L); - }); - } - }, () -> cameraThread.setCurrentSession(cameraSession[i], i)); + if (dual && i == 1 && initFirstCameraAfterSecond) { + initFirstCameraAfterSecond = false; + AndroidUtilities.runOnUIThread(() -> { + updateCameraInfoSize(0); + cameraThread.reinitForNewCamera(); + addToDualWait(350L); + }); + } + }, () -> cameraThread.setCurrentSession(cameraSession[i], i)); + } }); } @@ -3039,4 +3063,9 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur cameraThread.pause(600); } } + + @Override + public void onError(int errorId, Camera camera, CameraSessionWrapper cameraSession) { + + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/DefaultCameraAPI.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/DefaultCameraAPI.java deleted file mode 100644 index 47ab5bf9f..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/DefaultCameraAPI.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.telegram.messenger.camera; - -public class DefaultCameraAPI { -} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index c488f5ad8..7e148191f 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -77,7 +77,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 = 173; + public static final int LAYER = 175; public static class TL_stats_megagroupStats extends TLObject { public static final int constructor = 0xef7ff916; @@ -13103,7 +13103,9 @@ public class TLRPC { public ChatReactions available_reactions; public TL_stories.PeerStories stories; public WallPaper wallpaper; - + public int boosts_applied; + public int boosts_unrestrict; + public StickerSet emojiset; public long inviterId; //custom public int invitesCount; //custom @@ -13119,6 +13121,9 @@ public class TLRPC { case TL_channelFull_layer167.constructor: result = new TL_channelFull_layer167(); break; + case TL_channelFull_layer173.constructor: + result = new TL_channelFull_layer173(); + break; case 0xf2355507: result = new TL_channelFull_layer162(); break; @@ -15567,6 +15572,302 @@ public class TLRPC { } public static class TL_channelFull extends ChatFull { + public static final int constructor = 0x44c054a7; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_view_participants = (flags & 8) != 0; + can_set_username = (flags & 64) != 0; + can_set_stickers = (flags & 128) != 0; + hidden_prehistory = (flags & 1024) != 0; + can_set_location = (flags & 65536) != 0; + has_scheduled = (flags & 524288) != 0; + can_view_stats = (flags & 1048576) != 0; + blocked = (flags & 4194304) != 0; + flags2 = stream.readInt32(exception); + can_delete_channel = (flags2 & 1) != 0; + antispam = (flags2 & 2) != 0; + participants_hidden = (flags2 & 4) != 0; + translations_disabled = (flags2 & 8) != 0; + stories_pinned_available = (flags2 & 32) != 0; + view_forum_as_messages = (flags2 & 64) != 0; + id = stream.readInt64(exception); + about = stream.readString(exception); + if ((flags & 1) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + admins_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + kicked_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + banned_count = stream.readInt32(exception); + } + if ((flags & 8192) != 0) { + online_count = stream.readInt32(exception); + } + read_inbox_max_id = stream.readInt32(exception); + read_outbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 8388608) != 0) { + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + } + 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++) { + BotInfo object = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bot_info.add(object); + } + if ((flags & 16) != 0) { + migrated_from_chat_id = stream.readInt64(exception); + } + if ((flags & 16) != 0) { + migrated_from_max_id = stream.readInt32(exception); + } + if ((flags & 32) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + if ((flags & 256) != 0) { + stickerset = StickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 512) != 0) { + available_min_id = stream.readInt32(exception); + } + if ((flags & 2048) != 0) { + folder_id = stream.readInt32(exception); + } + if ((flags & 16384) != 0) { + linked_chat_id = stream.readInt64(exception); + } + if ((flags & 32768) != 0) { + location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + slowmode_seconds = stream.readInt32(exception); + } + if ((flags & 262144) != 0) { + slowmode_next_send_date = stream.readInt32(exception); + } + if ((flags & 4096) != 0) { + stats_dc = stream.readInt32(exception); + } + pts = stream.readInt32(exception); + if ((flags & 2097152) != 0) { + call = TL_inputGroupCall.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16777216) != 0) { + ttl_period = stream.readInt32(exception); + } + if ((flags & 33554432) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + pending_suggestions.add(stream.readString(exception)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 134217728) != 0) { + theme_emoticon = stream.readString(exception); + } + if ((flags & 268435456) != 0) { + requests_pending = stream.readInt32(exception); + } + if ((flags & 268435456) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + recent_requesters.add(stream.readInt64(exception)); + } + } + if ((flags & 536870912) != 0) { + default_send_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 1073741824) != 0) { + available_reactions = ChatReactions.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 16) != 0) { + stories = TL_stories.PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 128) != 0) { + wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 256) != 0) { + boosts_applied = stream.readInt32(exception); + } + if ((flags2 & 512) != 0) { + boosts_unrestrict = stream.readInt32(exception); + } + if ((flags2 & 1024) != 0) { + emojiset = StickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_view_participants ? (flags | 8) : (flags &~ 8); + flags = can_set_username ? (flags | 64) : (flags &~ 64); + flags = can_set_stickers ? (flags | 128) : (flags &~ 128); + flags = hidden_prehistory ? (flags | 1024) : (flags &~ 1024); + flags = can_set_location ? (flags | 65536) : (flags &~ 65536); + flags = has_scheduled ? (flags | 524288) : (flags &~ 524288); + flags = can_view_stats ? (flags | 1048576) : (flags &~ 1048576); + flags = blocked ? (flags | 4194304) : (flags &~ 4194304); + stream.writeInt32(flags); + flags2 = can_delete_channel ? (flags2 | 1) : (flags2 &~ 1); + flags2 = antispam ? (flags2 | 2) : (flags2 &~ 2); + flags2 = participants_hidden ? (flags2 | 4) : (flags2 &~ 4); + flags2 = translations_disabled ? (flags2 | 8) : (flags2 &~ 8); + flags2 = stories_pinned_available ? (flags2 | 32) : (flags2 &~ 32); + flags2 = view_forum_as_messages ? (flags2 | 64) : (flags2 &~ 64); + stream.writeInt32(flags2); + stream.writeInt64(id); + stream.writeString(about); + if ((flags & 1) != 0) { + stream.writeInt32(participants_count); + } + if ((flags & 2) != 0) { + stream.writeInt32(admins_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(kicked_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(banned_count); + } + if ((flags & 8192) != 0) { + stream.writeInt32(online_count); + } + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(read_outbox_max_id); + stream.writeInt32(unread_count); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + if ((flags & 8388608) != 0) { + exported_invite.serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + int count = bot_info.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bot_info.get(a).serializeToStream(stream); + } + if ((flags & 16) != 0) { + stream.writeInt64(migrated_from_chat_id); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_max_id); + } + if ((flags & 32) != 0) { + stream.writeInt32(pinned_msg_id); + } + if ((flags & 256) != 0) { + stickerset.serializeToStream(stream); + } + if ((flags & 512) != 0) { + stream.writeInt32(available_min_id); + } + if ((flags & 2048) != 0) { + stream.writeInt32(folder_id); + } + if ((flags & 16384) != 0) { + stream.writeInt64(linked_chat_id); + } + if ((flags & 32768) != 0) { + location.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(slowmode_seconds); + } + if ((flags & 262144) != 0) { + stream.writeInt32(slowmode_next_send_date); + } + if ((flags & 4096) != 0) { + stream.writeInt32(stats_dc); + } + stream.writeInt32(pts); + if ((flags & 2097152) != 0) { + call.serializeToStream(stream); + } + if ((flags & 16777216) != 0) { + stream.writeInt32(ttl_period); + } + if ((flags & 33554432) != 0) { + stream.writeInt32(0x1cb5c415); + count = pending_suggestions.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(pending_suggestions.get(a)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as.serializeToStream(stream); + } + if ((flags & 134217728) != 0) { + stream.writeString(theme_emoticon); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(requests_pending); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(0x1cb5c415); + count = recent_requesters.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(recent_requesters.get(a)); + } + } + if ((flags & 536870912) != 0) { + default_send_as.serializeToStream(stream); + } + if ((flags & 1073741824) != 0) { + available_reactions.serializeToStream(stream); + } + if ((flags2 & 16) != 0) { + stories.serializeToStream(stream); + } + if ((flags2 & 128) != 0) { + wallpaper.serializeToStream(stream); + } + if ((flags2 & 256) != 0) { + stream.writeInt32(boosts_applied); + } + if ((flags2 & 512) != 0) { + stream.writeInt32(boosts_unrestrict); + } + if ((flags2 & 1024) != 0) { + emojiset.serializeToStream(stream); + } + } + } + + public static class TL_channelFull_layer173 extends ChatFull { public static final int constructor = 0xf2bcb6f; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -26725,6 +27026,9 @@ public class TLRPC { case 0xb3a07661: result = new TL_messageActionGroupCallScheduled(); break; + case TL_messageActionBoostApply.constructor: + result = new TL_messageActionBoostApply(); + break; case 0x8f31b327: result = new TL_messageActionPaymentSentMe(); break; @@ -27784,6 +28088,21 @@ public class TLRPC { } } + public static class TL_messageActionBoostApply extends MessageAction { + public static final int constructor = 0xcc02aa6d; + + public int boosts; + + public void readParams(AbstractSerializedData stream, boolean exception) { + boosts = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(boosts); + } + } + public static class TL_messageActionPaymentSentMe extends MessageAction { public static final int constructor = 0x8f31b327; @@ -29645,7 +29964,7 @@ public class TLRPC { public ArrayList quote_entities = new ArrayList<>(); public int quote_offset; - public long user_id; + public Peer peer; public int story_id; public static MessageReplyHeader TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -29654,6 +29973,9 @@ public class TLRPC { case TL_messageReplyStoryHeader.constructor: result = new TL_messageReplyStoryHeader(); break; + case TL_messageReplyStoryHeader_layer174.constructor: + result = new TL_messageReplyStoryHeader_layer174(); + break; case TL_messageReplyHeader.constructor: result = new TL_messageReplyHeader(); break; @@ -29677,17 +29999,33 @@ public class TLRPC { } } - public static class TL_messageReplyStoryHeader extends MessageReplyHeader { + public static class TL_messageReplyStoryHeader_layer174 extends TL_messageReplyStoryHeader { public static final int constructor = 0x9c98bfc1; public void readParams(AbstractSerializedData stream, boolean exception) { - user_id = stream.readInt64(exception); + peer = new TLRPC.TL_peerUser(); + peer.user_id = stream.readInt64(exception); story_id = stream.readInt32(exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeInt64(user_id); + stream.writeInt64(peer == null ? 0 : peer.user_id); + stream.writeInt32(story_id); + } + } + + public static class TL_messageReplyStoryHeader extends MessageReplyHeader { + public static final int constructor = 0xe5af939; + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + story_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); stream.writeInt32(story_id); } } @@ -34635,6 +34973,9 @@ public class TLRPC { result = new TL_updatePinnedSavedDialogs(); break; } + if (result == null && ApplicationLoader.applicationLoaderInstance != null) { + result = ApplicationLoader.applicationLoaderInstance.parseTLUpdate(constructor); + } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in Update", constructor)); } @@ -44985,6 +45326,9 @@ public class TLRPC { case 0xb1c3caa7: result = new TL_channelAdminLogEventActionChangeStickerSet(); break; + case TL_channelAdminLogEventActionChangeEmojiStickerSet.constructor: + result = new TL_channelAdminLogEventActionChangeEmojiStickerSet(); + break; case 0xf92424d2: result = new TL_channelAdminLogEventActionParticipantMute(); break; @@ -45170,6 +45514,24 @@ public class TLRPC { } } + public static class TL_channelAdminLogEventActionChangeEmojiStickerSet extends ChannelAdminLogEventAction { + public static final int constructor = 0x46d840ab; + + public InputStickerSet prev_stickerset; + public InputStickerSet new_stickerset; + + public void readParams(AbstractSerializedData stream, boolean exception) { + prev_stickerset = InputStickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + new_stickerset = InputStickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + prev_stickerset.serializeToStream(stream); + new_stickerset.serializeToStream(stream); + } + } + public static class TL_channelAdminLogEventActionParticipantMute extends ChannelAdminLogEventAction { public static final int constructor = 0xf92424d2; @@ -62102,6 +62464,27 @@ public class TLRPC { } } + public static class TL_messages_searchEmojiStickerSets extends TLObject { + public static int constructor = 0x92b4494c; + + public int flags; + public boolean exclude_featured; + public String q; + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_FoundStickerSets.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = exclude_featured ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeString(q); + stream.writeInt64(hash); + } + } + public static class TL_messages_markDialogUnread extends TLObject { public static final int constructor = 0xc286d98f; @@ -65304,6 +65687,7 @@ public class TLRPC { public static class Message extends TLObject { public int id; public Peer from_id; + public int from_boosts_applied; public Peer peer_id; public Peer saved_peer_id; public int date; @@ -65460,6 +65844,9 @@ public class TLRPC { case TL_message_layer169.constructor: result = new TL_message_layer169(); break; + case TL_message_layer173.constructor: + result = new TL_message_layer173(); + break; case 0x9e19a1f6: result = new TL_messageService_layer118(); break; @@ -66160,6 +66547,202 @@ public class TLRPC { } public static class TL_message extends Message { + public static final int constructor = 0x1e4c8a69; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + post = (flags & 16384) != 0; + from_scheduled = (flags & 262144) != 0; + legacy = (flags & 524288) != 0; + edit_hide = (flags & 2097152) != 0; + pinned = (flags & 16777216) != 0; + noforwards = (flags & 67108864) != 0; + invert_media = (flags & 134217728) != 0; + id = stream.readInt32(exception); + if ((flags & 256) != 0) { + from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 536870912) != 0) { + from_boosts_applied = stream.readInt32(exception); + } + peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 268435456) != 0) { + saved_peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + fwd_from = MessageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2048) != 0) { + via_bot_id = stream.readInt64(exception); + } + if ((flags & 8) != 0) { + reply_to = MessageReplyHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 512) != 0) { + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if (media != null) { + ttl = media.ttl_seconds; + } + if (media != null && !TextUtils.isEmpty(media.captionLegacy)) { + message = media.captionLegacy; + } + } + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 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); + } + } + if ((flags & 1024) != 0) { + views = stream.readInt32(exception); + } + if ((flags & 1024) != 0) { + forwards = stream.readInt32(exception); + } + if ((flags & 8388608) != 0) { + replies = MessageReplies.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + edit_date = stream.readInt32(exception); + } + if ((flags & 65536) != 0) { + post_author = stream.readString(exception); + } + if ((flags & 131072) != 0) { + grouped_id = stream.readInt64(exception); + } + if ((flags & 1048576) != 0) { + reactions = MessageReactions.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4194304) != 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++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + if ((flags & 33554432) != 0) { + ttl_period = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + flags = silent ? (flags | 8192) : (flags &~ 8192); + flags = post ? (flags | 16384) : (flags &~ 16384); + flags = from_scheduled ? (flags | 262144) : (flags &~ 262144); + flags = legacy ? (flags | 524288) : (flags &~ 524288); + flags = edit_hide ? (flags | 2097152) : (flags &~ 2097152); + flags = pinned ? (flags | 16777216) : (flags &~ 16777216); + flags = noforwards ? (flags | 67108864) : (flags &~ 67108864); + flags = invert_media ? (flags | 134217728) : (flags &~ 134217728); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 256) != 0) { + from_id.serializeToStream(stream); + } + if ((flags & 536870912) != 0) { + stream.writeInt32(from_boosts_applied); + } + peer_id.serializeToStream(stream); + if ((flags & 268435456) != 0) { + saved_peer_id.serializeToStream(stream); + } + if ((flags & 4) != 0) { + fwd_from.serializeToStream(stream); + } + if ((flags & 2048) != 0) { + stream.writeInt64(via_bot_id); + } + if ((flags & 8) != 0) { + reply_to.serializeToStream(stream); + } + stream.writeInt32(date); + stream.writeString(message); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 1024) != 0) { + stream.writeInt32(views); + } + if ((flags & 1024) != 0) { + stream.writeInt32(forwards); + } + if ((flags & 8388608) != 0) { + replies.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + stream.writeInt32(edit_date); + } + if ((flags & 65536) != 0) { + stream.writeString(post_author); + } + if ((flags & 131072) != 0) { + stream.writeInt64(grouped_id); + } + if ((flags & 1048576) != 0) { + reactions.serializeToStream(stream); + } + if ((flags & 4194304) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + if ((flags & 33554432) != 0) { + stream.writeInt32(ttl_period); + } + writeAttachPath(stream); + } + } + + public static class TL_message_layer173 extends TL_message { public static final int constructor = 0x76bec211; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -72323,6 +72906,40 @@ public class TLRPC { } } + public static class TL_channels_setEmojiStickers extends TLObject { + public static final int constructor = 0x3cd930b7; + + public InputChannel channel; + public InputStickerSet stickerset; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stickerset.serializeToStream(stream); + } + } + + public static class TL_channels_setBoostsToUnblockRestrictions extends TLObject { + public static final int constructor = 0xad399cee; + + public InputChannel channel; + public int boosts; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(boosts); + } + } + public static class TL_account_reorderUsernames extends TLObject { public static final int constructor = 0xef500eab; @@ -73108,7 +73725,7 @@ public class TLRPC { public ArrayList quote_entities = new ArrayList<>(); public int quote_offset; - public InputUser user_id; + public InputPeer peer; public int story_id; public static InputReplyTo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -73257,16 +73874,16 @@ public class TLRPC { } public static class TL_inputReplyToStory extends InputReplyTo { - public static final int constructor = 0x15b0f283; + public static final int constructor = 0x5881323a; public void readParams(AbstractSerializedData stream, boolean exception) { - user_id = InputUser.TLdeserialize(stream, stream.readInt32(exception), exception); + peer = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); story_id = stream.readInt32(exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - user_id.serializeToStream(stream); + peer.serializeToStream(stream); stream.writeInt32(story_id); } } @@ -74528,7 +75145,7 @@ public class TLRPC { } public static class TL_help_peerColorOption extends TLObject { - public static final int constructor = 0xef8430ab; + public static final int constructor = 0xadec6ebe; public int flags; public boolean hidden; @@ -74536,6 +75153,7 @@ public class TLRPC { public help_PeerColorSet colors; public help_PeerColorSet dark_colors; public int channel_min_level; + public int group_min_level; public static TL_help_peerColorOption TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_help_peerColorOption.constructor != constructor) { @@ -74550,7 +75168,6 @@ public class TLRPC { return result; } - @Override public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); hidden = (flags & 1) != 0; @@ -74564,9 +75181,11 @@ public class TLRPC { if ((flags & 8) != 0) { channel_min_level = stream.readInt32(exception); } + if ((flags & 16) != 0) { + group_min_level = stream.readInt32(exception); + } } - @Override public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = hidden ? (flags | 1) : (flags &~ 1); @@ -74581,6 +75200,9 @@ public class TLRPC { if ((flags & 8) != 0) { stream.writeInt32(channel_min_level); } + if ((flags & 16) != 0) { + stream.writeInt32(group_min_level); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java b/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java index 2aa0bf5de..cb0a88566 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java @@ -1926,6 +1926,7 @@ public class TL_stories { public boolean out; public int id; public int date; + public TLRPC.Peer from_id; public StoryFwdHeader fwd_from; public int expire_date; public String caption; @@ -1953,19 +1954,22 @@ public class TL_stories { public static StoryItem TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { StoryItem result = null; switch (constructor) { - case 0xaf6365a1: + case TL_storyItem.constructor: result = new TL_storyItem(); break; - case 0x44c457ce: + case TL_storyItem_layer174.constructor: + result = new TL_storyItem_layer174(); + break; + case TL_storyItem_layer166.constructor: result = new TL_storyItem_layer166(); break; - case 0x562aa637: + case TL_storyItem_layer160.constructor: result = new TL_storyItem_layer160(); break; - case 0x51e6ee4f: + case TL_storyItemDeleted.constructor: result = new TL_storyItemDeleted(); break; - case 0xffadc913: + case TL_storyItemSkipped.constructor: result = new TL_storyItemSkipped(); break; } @@ -2241,6 +2245,150 @@ public class TL_stories { } public static class TL_storyItem extends StoryItem { + public static final int constructor = 0x79b26a24; + + 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; + out = (flags & 65536) != 0; + id = stream.readInt32(exception); + date = stream.readInt32(exception); + if ((flags & 262144) != 0) { + from_id = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + fwd_from = TL_storyFwdHeader.TLdeserialize(stream, stream.readInt32(exception), 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++) { + TLRPC.MessageEntity object = TLRPC.MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + media = TLRPC.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++) { + TLRPC.PrivacyRule object = TLRPC.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 = TLRPC.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); + flags = out ? (flags | 65536) : (flags &~ 65536); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(date); + if ((flags & 262144) != 0) { + from_id.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + fwd_from.serializeToStream(stream); + } + 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_layer174 extends TL_storyItem { public static final int constructor = 0xaf6365a1; public void readParams(AbstractSerializedData stream, boolean exception) { 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 1121b5970..1325b30ae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -2456,6 +2456,9 @@ public class ActionBarMenuItem extends FrameLayout { public Item lazilyAddSubItem(int id, int icon, CharSequence text) { return lazilyAddSubItem(id, icon, null, text, true, false); } + public Item lazilyAddSubItem(int id, Drawable iconDrawable, CharSequence text) { + return lazilyAddSubItem(id, 0, iconDrawable, text, true, false); + } public Item lazilyAddSubItem(int id, int icon, Drawable iconDrawable, CharSequence text, boolean dismiss, boolean needCheck) { return putLazyItem(Item.asSubItem(id, icon, iconDrawable, text, dismiss, needCheck)); } 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 9469cf1e4..a0ea22468 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java @@ -32,6 +32,7 @@ public class ActionBarMenuSubItem extends FrameLayout { private int iconColor; private int selectorColor; + int selectorRad = 6; boolean top; boolean bottom; @@ -281,8 +282,18 @@ public class ActionBarMenuSubItem extends FrameLayout { updateBackground(); } + public void updateSelectorBackground(boolean top, boolean bottom, int selectorRad) { + if (this.top == top && this.bottom == bottom && this.selectorRad == selectorRad) { + return; + } + this.top = top; + this.bottom = bottom; + this.selectorRad = selectorRad; + updateBackground(); + } + public void updateBackground() { - setBackground(Theme.createRadSelectorDrawable(selectorColor, top ? 6 : 0, bottom ? 6 : 0)); + setBackground(Theme.createRadSelectorDrawable(selectorColor, top ? selectorRad : 0, bottom ? selectorRad : 0)); } private int getThemedColor(int key) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java index 7644a3a39..9d68424f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java @@ -400,7 +400,7 @@ public class ActionBarPopupWindow extends PopupWindow { } public int precalculateHeight() { - int MOST_SPEC = View.MeasureSpec.makeMeasureSpec(999999, View.MeasureSpec.AT_MOST); + int MOST_SPEC = View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST); linearLayout.measure(MOST_SPEC, MOST_SPEC); return linearLayout.getMeasuredHeight(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/EmojiThemes.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/EmojiThemes.java index bc9282cb7..b8d67b8e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/EmojiThemes.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/EmojiThemes.java @@ -26,7 +26,10 @@ import java.util.ArrayList; public class EmojiThemes { + public static final String REMOVED_EMOJI = "❌"; + public boolean showAsDefaultStub; + public boolean showAsRemovedStub; public String emoji; public TLRPC.WallPaper wallpaper; int currentIndex = 0; @@ -65,6 +68,10 @@ public class EmojiThemes { } } + public boolean isAnyStub() { + return showAsDefaultStub || showAsRemovedStub; + } + public static EmojiThemes createPreviewFullTheme(int currentAccount, TLRPC.TL_theme tl_theme) { EmojiThemes chatTheme = new EmojiThemes(currentAccount); chatTheme.emoji = tl_theme.emoticon; @@ -82,7 +89,7 @@ public class EmojiThemes { public static EmojiThemes createChatThemesDefault(int currentAccount) { EmojiThemes themeItem = new EmojiThemes(currentAccount); - themeItem.emoji = "❌"; + themeItem.emoji = REMOVED_EMOJI; themeItem.showAsDefaultStub = true; ThemeItem lightTheme = new ThemeItem(); @@ -96,6 +103,23 @@ public class EmojiThemes { return themeItem; } + public static EmojiThemes createChatThemesRemoved(int currentAccount) { + + EmojiThemes themeItem = new EmojiThemes(currentAccount); + themeItem.emoji = REMOVED_EMOJI; + themeItem.showAsRemovedStub = true; + + ThemeItem lightTheme = new ThemeItem(); + lightTheme.themeInfo = getDefaultThemeInfo(true); + themeItem.items.add(lightTheme); + + ThemeItem darkTheme = new ThemeItem(); + darkTheme.themeInfo = getDefaultThemeInfo(false); + themeItem.items.add(darkTheme); + + return themeItem; + } + public static EmojiThemes createPreviewCustom(int currentAccount) { EmojiThemes themeItem = new EmojiThemes(currentAccount); themeItem.emoji = "\uD83C\uDFA8"; 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 4ad9103c0..8f64af7e8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -1095,7 +1095,7 @@ public class SimpleTextView extends View implements Drawable.Callback { return rightDrawableY; } - private int getMaxTextWidth() { + public int getMaxTextWidth() { return getMeasuredWidth() - (rightDrawableOutside && rightDrawable != null ? rightDrawable.getIntrinsicWidth() + drawablePadding : 0) - (rightDrawableOutside && rightDrawable2 != null ? rightDrawable2.getIntrinsicWidth() + drawablePadding : 0); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java index 319f5576c..00f2078bd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java @@ -323,6 +323,11 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { items.add(new Item(16, LocaleController.getString("ProfileMyStories", R.string.ProfileMyStories), R.drawable.msg_menu_stories)); showDivider = true; } + if (ApplicationLoader.applicationLoaderInstance != null) { + if (ApplicationLoader.applicationLoaderInstance.extendDrawer(items)) { + showDivider = true; + } + } TLRPC.TL_attachMenuBots menuBots = MediaDataController.getInstance(UserConfig.selectedAccount).getAttachMenuBots(); if (menuBots != null && menuBots.bots != null) { for (int i = 0; i < menuBots.bots.size(); i++) { @@ -351,6 +356,22 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { items.add(new Item(13, LocaleController.getString("TelegramFeatures", R.string.TelegramFeatures), helpIcon)); } + public boolean click(View view, int position) { + position -= 2; + if (accountsShown) { + position -= getAccountRowsCount(); + } + if (position < 0 || position >= items.size()) { + return false; + } + Item item = items.get(position); + if (item != null && item.listener != null) { + item.listener.onClick(view); + return true; + } + return false; + } + public int getId(int position) { position -= 2; if (accountsShown) { @@ -389,13 +410,14 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { return item != null ? item.bot : null; } - private static class Item { + public static class Item { public int icon; - public String text; + public CharSequence text; public int id; TLRPC.TL_attachMenuBot bot; + View.OnClickListener listener; - public Item(int id, String text, int icon) { + public Item(int id, CharSequence text, int icon) { this.icon = icon; this.id = id; this.text = text; @@ -413,5 +435,10 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { actionCell.setTextAndIcon(id, text, icon); } } + + public Item onClick(View.OnClickListener listener) { + this.listener = listener; + return this; + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index 0a643c808..0e560a24d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -3807,7 +3807,13 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg boolean allowPlayer = !PhotoViewer.getInstance().isVisibleOrAnimating(); if (!allowPlayer || (currentPlayer != null && currentPlayer != bestView && videoPlayer != null)) { if (videoPlayer != null) { - currentPlayer.playFrom = videoPlayer.getCurrentPosition(); + videoStates.put(currentPlayer.currentBlock.video_id, currentPlayer.setState(BlockVideoCellState.fromPlayer(videoPlayer, currentPlayer))); + if (currentPlayer.videoState != null) { + if (currentPlayer.videoState.lastFrameBitmap != null) { + currentPlayer.imageView.setImageBitmap(currentPlayer.videoState.lastFrameBitmap); + } + currentPlayer.updateButtonState(false); + } videoPlayer.release(null); } videoPlayer = null; @@ -4724,6 +4730,15 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg containerView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } animatorSet.start(); + + for (int i = 0; i < videoStates.size(); ++i) { + BlockVideoCellState state = videoStates.valueAt(i); + if (state.lastFrameBitmap != null) { + state.lastFrameBitmap.recycle(); + state.lastFrameBitmap = null; + } + } + videoStates.clear(); } private void onClosed() { @@ -4963,6 +4978,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } } + private LongSparseArray videoStates = new LongSparseArray<>(); + private class WebpageAdapter extends RecyclerListView.SelectionAdapter { private Context context; @@ -5729,7 +5746,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } case 5: { BlockVideoCell cell = (BlockVideoCell) holder.itemView; - cell.setBlock((TLRPC.TL_pageBlockVideo) block, position == 0, position == total - 1); + TLRPC.TL_pageBlockVideo blockVideo = (TLRPC.TL_pageBlockVideo) block; + cell.setBlock(blockVideo, videoStates.get(blockVideo.video_id), position == 0, position == total - 1); cell.setParentBlock(channelBlock, originalBlock); break; } @@ -6044,9 +6062,58 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } } + private static class BlockVideoCellState { + long playFrom; + Bitmap lastFrameBitmap; + + public static BlockVideoCellState fromPlayer(VideoPlayerHolderBase player, BlockVideoCell videoCell) { + BlockVideoCellState state = new BlockVideoCellState(); + state.playFrom = player.getCurrentPosition(); + if (player.firstFrameRendered && videoCell.textureView != null && videoCell.textureView.getSurfaceTexture() != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Surface surface = new Surface(videoCell.textureView.getSurfaceTexture()); + Bitmap bitmap = Bitmap.createBitmap(videoCell.textureView.getMeasuredWidth(), videoCell.textureView.getMeasuredHeight(), Bitmap.Config.ARGB_8888); + AndroidUtilities.getBitmapFromSurface(surface, bitmap); + surface.release(); + state.lastFrameBitmap = bitmap; + } else { + state.lastFrameBitmap = videoCell.textureView.getBitmap(); + } + } + return state; + } + + public static BlockVideoCellState fromPlayer(VideoPlayer player, BlockVideoCell videoCell, TextureView textureView) { + BlockVideoCellState state = new BlockVideoCellState(); + state.playFrom = player.getCurrentPosition(); + if (textureView != null && textureView.getSurfaceTexture() != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Surface surface = new Surface(textureView.getSurfaceTexture()); + Bitmap bitmap = Bitmap.createBitmap(textureView.getMeasuredWidth(), textureView.getMeasuredHeight(), Bitmap.Config.ARGB_8888); + AndroidUtilities.getBitmapFromSurface(surface, bitmap); + surface.release(); + state.lastFrameBitmap = bitmap; + } else { + state.lastFrameBitmap = textureView.getBitmap(); + } + } + return state; + } + + public static BlockVideoCellState fromPlayer(VideoPlayer player, BlockVideoCell videoCell, SurfaceView surfaceView) { + BlockVideoCellState state = new BlockVideoCellState(); + state.playFrom = player.getCurrentPosition(); + if (surfaceView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Bitmap bitmap = Bitmap.createBitmap(surfaceView.getMeasuredWidth(), surfaceView.getMeasuredHeight(), Bitmap.Config.ARGB_8888); + AndroidUtilities.getBitmapFromSurface(surfaceView, bitmap); + state.lastFrameBitmap = bitmap; + } + return state; + } + } + private class BlockVideoCell extends FrameLayout implements DownloadController.FileDownloadProgressListener, TextSelectionHelper.ArticleSelectableView { - public long playFrom; private DrawingText captionLayout; private DrawingText creditLayout; private ImageReceiver imageView; @@ -6070,6 +6137,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg private int TAG; private TLRPC.TL_pageBlockVideo currentBlock; + private BlockVideoCellState videoState; private TLRPC.PageBlock parentBlock; private TLRPC.Document currentDocument; private boolean isGif; @@ -6118,8 +6186,12 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg return super.drawChild(canvas, child, drawingTime); } - public void setBlock(TLRPC.TL_pageBlockVideo block, boolean first, boolean last) { + public void setBlock(TLRPC.TL_pageBlockVideo block, BlockVideoCellState state, boolean first, boolean last) { + if (currentBlock != null && videoPlayer != null && currentPlayer == this) { + videoStates.put(currentBlock.video_id, videoState = BlockVideoCellState.fromPlayer(videoPlayer, this)); + } currentBlock = block; + videoState = state; parentBlock = null; currentDocument = parentAdapter.getDocumentWithId(currentBlock.video_id); isGif = MessageObject.isVideoDocument(currentDocument) || MessageObject.isGifDocument(currentDocument)/* && currentBlock.autoplay*/; @@ -6255,15 +6327,20 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg int photoY = (isFirst || currentType == 1 || currentType == 2 || currentBlock.level > 0) ? 0 : AndroidUtilities.dp(8); imageView.setImageCoords(photoX, photoY, photoWidth, photoHeight); if (isGif) { - autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(DownloadController.AUTODOWNLOAD_TYPE_VIDEO, currentDocument.size); - File path = FileLoader.getInstance(currentAccount).getPathToAttach(currentDocument); - File path2 = FileLoader.getInstance(currentAccount).getPathToAttach(currentDocument, true); - if (autoDownload || path.exists() || path2.exists()) { + if (videoState != null && videoState.lastFrameBitmap != null) { imageView.setStrippedLocation(null); - imageView.setImage(null, null, ImageLocation.getForDocument(currentDocument), "200_200_pframe", ImageLocation.getForDocument(thumb, currentDocument), "80_80_b", null, currentDocument.size, null, parentAdapter.currentPage, 1); + imageView.setImageBitmap(videoState.lastFrameBitmap); } else { - imageView.setStrippedLocation(ImageLocation.getForDocument(currentDocument)); - imageView.setImage(null, null, null, null, ImageLocation.getForDocument(thumb, currentDocument), "80_80_b", null, currentDocument.size, null, parentAdapter.currentPage, 1); + autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(DownloadController.AUTODOWNLOAD_TYPE_VIDEO, currentDocument.size); + File path = FileLoader.getInstance(currentAccount).getPathToAttach(currentDocument); + File path2 = FileLoader.getInstance(currentAccount).getPathToAttach(currentDocument, true); + if (autoDownload || path.exists() || path2.exists()) { + imageView.setStrippedLocation(null); + imageView.setImage(null, null, ImageLocation.getForDocument(currentDocument), "200_200_pframe", ImageLocation.getForDocument(thumb, currentDocument), "80_80_b", null, currentDocument.size, null, parentAdapter.currentPage, 1); + } else { + imageView.setStrippedLocation(ImageLocation.getForDocument(currentDocument)); + imageView.setImage(null, null, null, null, ImageLocation.getForDocument(thumb, currentDocument), "80_80_b", null, currentDocument.size, null, parentAdapter.currentPage, 1); + } } } else { imageView.setStrippedLocation(null); @@ -6382,7 +6459,9 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, null, this); float setProgress = 0; boolean progressVisible = false; - if (!FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { + if (videoState != null && videoState.lastFrameBitmap != null) { + buttonState = -1; + } else if (!FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { if (!cancelLoading && autoDownload && isGif) { progressVisible = true; buttonState = 1; @@ -6437,13 +6516,28 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg @Override protected void onDetachedFromWindow() { + if (currentBlock != null && videoPlayer != null && currentPlayer == this) { + videoStates.put(currentBlock.video_id, setState(BlockVideoCellState.fromPlayer(videoPlayer, this))); + } super.onDetachedFromWindow(); imageView.onDetachedFromWindow(); DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); - playFrom = 0; firstFrameRendered = false; } + public BlockVideoCellState setState(BlockVideoCellState newState) { + if (videoState != null && newState != null && newState.lastFrameBitmap != null && videoState.lastFrameBitmap != null && newState.lastFrameBitmap != videoState.lastFrameBitmap) { + videoState.lastFrameBitmap.recycle(); + videoState.lastFrameBitmap = null; + } + if (videoState != null && newState != null && newState.lastFrameBitmap == null && videoState.lastFrameBitmap != null) { + newState.playFrom = videoState.playFrom; + newState.lastFrameBitmap = videoState.lastFrameBitmap; + } + videoState = newState; + return videoState; + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -6470,6 +6564,10 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (!firstFrameRendered) { firstFrameRendered = true; textureView.setAlpha(1f); + + if (currentBlock != null) { + videoStates.put(currentBlock.video_id, setState(BlockVideoCellState.fromPlayer(videoPlayer, BlockVideoCell.this))); + } } } }.with(textureView); @@ -6486,7 +6584,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg return; } - videoPlayer.seekTo(playFrom); + videoPlayer.seekTo(videoState == null ? 0 : videoState.playFrom); videoPlayer.preparePlayer(uri, true, 1f); videoPlayer.play(); @@ -8398,7 +8496,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg default: { BlockVideoCell cell = (BlockVideoCell) holder.itemView; cell.groupPosition = group.positions.get(pageBlock); - cell.setBlock((TLRPC.TL_pageBlockVideo) pageBlock, true, true); + TLRPC.TL_pageBlockVideo blockVideo = (TLRPC.TL_pageBlockVideo) pageBlock; + cell.setBlock(blockVideo, videoStates.get(blockVideo.video_id), true, true); break; } } @@ -8637,7 +8736,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg ((BlockPhotoCell) view).setBlock((TLRPC.TL_pageBlockPhoto) block, true, true); } else { view = new BlockVideoCell(getContext(), parentAdapter, 1); - ((BlockVideoCell) view).setBlock((TLRPC.TL_pageBlockVideo) block, true, true); + TLRPC.TL_pageBlockVideo videoBlock = (TLRPC.TL_pageBlockVideo) block; + ((BlockVideoCell) view).setBlock(videoBlock, videoStates.get(videoBlock.video_id), true, true); } container.addView(view); ObjectContainer objectContainer = new ObjectContainer(); @@ -11680,28 +11780,20 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg SurfaceView surfaceView = PhotoViewer.getInstance().getVideoSurfaceView(); BlockVideoCell videoCell = getViewFromListView(listView[0], pageBlock); if (videoCell != null && player != null && textureView != null) { - videoCell.playFrom = player.getCurrentPosition(); + videoStates.put(videoCell.currentBlock.video_id, videoCell.setState(BlockVideoCellState.fromPlayer(player, videoCell, textureView))); videoCell.firstFrameRendered = false; videoCell.textureView.setAlpha(0); - if (textureView.getSurfaceTexture() != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - Surface surface = new Surface(textureView.getSurfaceTexture()); - Bitmap bitmap = Bitmap.createBitmap(textureView.getMeasuredWidth(), textureView.getMeasuredHeight(), Bitmap.Config.ARGB_8888); - AndroidUtilities.getBitmapFromSurface(surface, bitmap); - surface.release(); - videoCell.imageView.setImageBitmap(bitmap); - } else { - videoCell.imageView.setImageBitmap(textureView.getBitmap()); - } + if (videoCell.videoState != null && videoCell.videoState.lastFrameBitmap != null) { + videoCell.imageView.setImageBitmap(videoCell.videoState.lastFrameBitmap); } } if (videoCell != null && player != null && surfaceView != null) { - videoCell.playFrom = player.getCurrentPosition(); + videoStates.put(videoCell.currentBlock.video_id, videoCell.setState(BlockVideoCellState.fromPlayer(player, videoCell, surfaceView))); videoCell.firstFrameRendered = false; videoCell.textureView.setAlpha(0); - Bitmap bitmap = Bitmap.createBitmap(surfaceView.getMeasuredWidth(), surfaceView.getMeasuredHeight(), Bitmap.Config.ARGB_8888); - AndroidUtilities.getBitmapFromSurface(surfaceView, bitmap); - videoCell.imageView.setImageBitmap(bitmap); + if (videoCell.videoState != null && videoCell.videoState.lastFrameBitmap != null) { + videoCell.imageView.setImageBitmap(videoCell.videoState.lastFrameBitmap); + } } checkVideoPlayer(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/BoostsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/BoostsActivity.java new file mode 100644 index 000000000..812701c41 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/BoostsActivity.java @@ -0,0 +1,846 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.tgnet.TLRPC.TL_payments_checkedGiftCode.NO_USER_ID; +import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_FEATURES; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +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.text.TextUtils; +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.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChannelBoostsController; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.ContactsController; +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.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.FixedHeightEmptyCell; +import org.telegram.ui.Cells.ManageChatTextCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Charts.view_data.ChartHeaderView; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.CircularProgressDrawable; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkActionView; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.Premium.LimitPreviewView; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.Components.Premium.boosts.BoostDialogs; +import org.telegram.ui.Components.Premium.boosts.BoostPagerBottomSheet; +import org.telegram.ui.Components.Premium.boosts.GiftInfoBottomSheet; +import org.telegram.ui.Components.Premium.boosts.cells.statistics.GiftedUserCell; +import org.telegram.ui.Components.Premium.boosts.cells.statistics.GiveawayCell; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.ScrollSlidingTextTabStrip; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; + +public class BoostsActivity extends GradientHeaderActivity implements NotificationCenter.NotificationCenterDelegate { + + private final static int OVERVIEW_TYPE = 0; + private final static int HEADER_VIEW_TYPE = 1; + private final static int DIVIDER_VIEW_TYPE = 2; + private final static int LINK_VIEW_TYPE = 3; + private final static int BOOST_VIEW = 4; + private final static int USER_VIEW_TYPE = 5; + private final static int DIVIDER_TEXT_VIEW_TYPE = 6; + private final static int EMPTY_VIEW_8DP = 7; + private final static int NO_USERS_HINT = 8; + private final static int SHOW_MORE_VIEW_TYPE = 9; + private final static int SHOW_BOOST_BY_GIFTS = 10; + private final static int SHOW_PREPARED_GIVE_AWAY = 11; + private final static int HEADER_VIEW_TYPE_SMALL = 12; + private final static int HEADER_VIEW_TYPE_TABS = 13; + private final static int HEADER_PADDING = 14; + private final static int BOTTOM_PADDING = 15; + private final static int HEADER_VIEW_TYPE_OVERVIEW = 16; + + private static final int TAB_BOOSTS = 0; + private static final int TAB_GIFTS = 1; + + private final long dialogId; + int currentAccount = UserConfig.selectedAccount; + + private TL_stories.TL_premium_boostsStatus boostsStatus; + private ChannelBoostsController.CanApplyBoost canApplyBoost; + private ScrollSlidingTextTabStrip boostsTabs; + + private final ArrayList boosters = new ArrayList<>(); + private final ArrayList gifts = new ArrayList<>(); + private boolean hasBoostsNext; + private int nextBoostRemaining; + private boolean hasGiftsNext; + private int nextGiftsRemaining; + private final ArrayList items = new ArrayList<>(); + private int selectedTab = TAB_BOOSTS; + private LimitPreviewView limitPreviewView; + + public void setBoostsStatus(TL_stories.TL_premium_boostsStatus boostsStatus) { + this.boostsStatus = boostsStatus; + loadCanApplyBoosts(); + } + + AdapterWithDiffUtils adapter = new AdapterWithDiffUtils() { + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return items.get(holder.getAdapterPosition()).selectable; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case BOTTOM_PADDING: + view = new View(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int h = Math.max(0, layoutManager.getLastItemHeight()) ; + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)); + } + }; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + break; + case HEADER_PADDING: + view = getHeader(getContext()); + break; + case DIVIDER_TEXT_VIEW_TYPE: + view = new TextInfoPrivacyCell(parent.getContext(), 20, resourceProvider); + break; + case DIVIDER_VIEW_TYPE: + view = new ShadowSectionCell(parent.getContext(), 12, Theme.getColor(Theme.key_windowBackgroundGray)); + break; + case OVERVIEW_TYPE: + view = new StatisticActivity.OverviewCell(getContext()); + break; + case HEADER_VIEW_TYPE_OVERVIEW: + case HEADER_VIEW_TYPE: + view = new ChartHeaderView(getContext()); + view.setPadding(view.getPaddingLeft(), AndroidUtilities.dp(16), view.getRight(), AndroidUtilities.dp(16)); + break; + case HEADER_VIEW_TYPE_SMALL: + view = new ChartHeaderView(getContext()); + view.setPadding(view.getPaddingLeft(), AndroidUtilities.dp(16), view.getRight(), AndroidUtilities.dp(8)); + break; + case HEADER_VIEW_TYPE_TABS: + boostsTabs = new ScrollSlidingTextTabStrip(getContext(), resourceProvider); + boostsTabs.setColors(Theme.key_profile_tabSelectedLine, Theme.key_profile_tabSelectedText, Theme.key_profile_tabText, Theme.key_profile_tabSelector); + FrameLayout frameLayoutWrapper = new FrameLayout(getContext()) { + private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + dividerPaint.setColor(Theme.getColor(Theme.key_windowBackgroundGray, resourceProvider)); + canvas.drawRect(0, getHeight() - 2, getWidth(), getHeight(), dividerPaint); + } + }; + boostsTabs.setDelegate(new ScrollSlidingTextTabStrip.ScrollSlidingTabStripDelegate() { + @Override + public void onPageSelected(int id, boolean forward) { + selectedTab = id; + updateRows(true); + } + + @Override + public void onSamePageSelected() { + + } + + @Override + public void onPageScrolled(float progress) { + + } + }); + frameLayoutWrapper.addView(boostsTabs, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 48)); + view = frameLayoutWrapper; + break; + case SHOW_BOOST_BY_GIFTS: + TextCell textCell = new TextCell(getContext()); + textCell.setTextAndIcon(LocaleController.formatString("BoostingGetBoostsViaGifts", R.string.BoostingGetBoostsViaGifts), R.drawable.msg_gift_premium, false); + textCell.offsetFromImage = 64; + textCell.setColors(Theme.key_windowBackgroundWhiteBlueText4, Theme.key_windowBackgroundWhiteBlueText4); + view = textCell; + break; + case LINK_VIEW_TYPE: + LinkActionView linkActionView = new LinkActionView(getContext(), BoostsActivity.this, null, 0, false, false); + view = linkActionView; + linkActionView.hideOptions(); + view.setPadding(AndroidUtilities.dp(11), 0, AndroidUtilities.dp(11), AndroidUtilities.dp(24)); + break; + case SHOW_PREPARED_GIVE_AWAY: + view = new GiveawayCell(getContext(), 0, 0, false); + break; + case USER_VIEW_TYPE: + view = new GiftedUserCell(getContext(), 0, 0, false); + break; + case EMPTY_VIEW_8DP: + view = new FixedHeightEmptyCell(getContext(), 8); + break; + case NO_USERS_HINT: + FrameLayout frameLayout = new FrameLayout(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); + } + }; + TextView textView = new TextView(getContext()); + textView.setText(LocaleController.getString(isChannel() ? R.string.NoBoostersHint : R.string.NoBoostersGroupHint)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + textView.setGravity(Gravity.CENTER); + frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 16, 0, 0)); + view = frameLayout; + break; + case SHOW_MORE_VIEW_TYPE: + ManageChatTextCell actionCell = new ManageChatTextCell(getContext()) { + @Override + protected int getFullHeight() { + return AndroidUtilities.dp(50); + } + }; + actionCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); + view = actionCell; + break; + default: + throw new UnsupportedOperationException(); + } + 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 (holder.getItemViewType() == BOOST_VIEW || holder.getItemViewType() == HEADER_PADDING || holder.getItemViewType() == BOTTOM_PADDING) { + + } else if (holder.getItemViewType() == HEADER_VIEW_TYPE || holder.getItemViewType() == HEADER_VIEW_TYPE_SMALL || holder.getItemViewType() == HEADER_VIEW_TYPE_OVERVIEW) { + ChartHeaderView headerCell = (ChartHeaderView) holder.itemView; + headerCell.setTitle(items.get(position).title); + headerCell.showDate(false); + if (holder.getItemViewType() == HEADER_VIEW_TYPE_SMALL) { + headerCell.setPadding(dp(3), headerCell.getPaddingTop(), headerCell.getPaddingRight(), headerCell.getPaddingBottom()); + } + if (holder.getItemViewType() == HEADER_VIEW_TYPE_OVERVIEW) { + headerCell.setPadding(dp(6), 0, dp(6), headerCell.getPaddingBottom()); + } + } else if (holder.getItemViewType() == OVERVIEW_TYPE) { + StatisticActivity.OverviewCell overviewCell = (StatisticActivity.OverviewCell) holder.itemView; + overviewCell.setData(0, Integer.toString(boostsStatus.level), null, LocaleController.getString("BoostsLevel2", R.string.BoostsLevel2)); + if (boostsStatus.premium_audience != null && boostsStatus.premium_audience.total != 0) { + float percent = (((float) boostsStatus.premium_audience.part / (float) boostsStatus.premium_audience.total) * 100f); + overviewCell.setData(1, "~" + (int) boostsStatus.premium_audience.part, String.format(Locale.US, "%.1f", percent) + "%", LocaleController.getString(isChannel() ? R.string.PremiumSubscribers : R.string.PremiumMembers)); + } else { + overviewCell.setData(1, "~0", "0%", LocaleController.getString(isChannel() ? R.string.PremiumSubscribers : R.string.PremiumMembers)); + } + overviewCell.setData(2, String.valueOf(boostsStatus.boosts), null, LocaleController.getString("BoostsExisting", R.string.BoostsExisting)); + overviewCell.setData(3, String.valueOf(Math.max(0, boostsStatus.next_level_boosts - boostsStatus.boosts)), null, LocaleController.getString("BoostsToLevel", R.string.BoostsToLevel)); + overviewCell.setPadding(dp(23), overviewCell.getPaddingTop(), dp(23), overviewCell.getPaddingBottom()); + } else if (holder.getItemViewType() == USER_VIEW_TYPE) { + TL_stories.TL_boost booster = items.get(position).booster; + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(booster.user_id); + GiftedUserCell userCell = (GiftedUserCell) holder.itemView; + String str = booster.multiplier > 1 + ? LocaleController.formatString("BoostsExpireOn", R.string.BoostsExpireOn, LocaleController.formatDate(booster.expires)) + : LocaleController.formatString("BoostExpireOn", R.string.BoostExpireOn, LocaleController.formatDate(booster.expires)); + userCell.setData(user, ContactsController.formatName(user), str, 0, !items.get(position).isLast); + userCell.setStatus(booster); + userCell.setAvatarPadding(5); + } else if (holder.getItemViewType() == DIVIDER_TEXT_VIEW_TYPE) { + TextInfoPrivacyCell privacyCell = (TextInfoPrivacyCell) holder.itemView; + privacyCell.setText(items.get(position).title); + boolean isLast = position == items.size() - 2; + Drawable shadowDrawable = Theme.getThemedDrawable(getContext(), isLast ? R.drawable.greydivider_bottom : R.drawable.greydivider, Theme.getColor(Theme.key_windowBackgroundGrayShadow, resourceProvider)); + Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)); + CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); + combinedDrawable.setFullsize(true); + privacyCell.setBackground(combinedDrawable); + } else if (holder.getItemViewType() == SHOW_MORE_VIEW_TYPE) { + ManageChatTextCell actionCell = (ManageChatTextCell) holder.itemView; + if (selectedTab == TAB_BOOSTS) { + actionCell.setText(LocaleController.formatPluralString("BoostingShowMoreBoosts", nextBoostRemaining), null, R.drawable.arrow_more, false); + } else { + actionCell.setText(LocaleController.formatPluralString("BoostingShowMoreGifts", nextGiftsRemaining), null, R.drawable.arrow_more, false); + } + } else if (holder.getItemViewType() == LINK_VIEW_TYPE) { + LinkActionView linkActionView = (LinkActionView) holder.itemView; + linkActionView.setLink(items.get(position).title); + } else if (holder.getItemViewType() == SHOW_PREPARED_GIVE_AWAY) { + ItemInternal item = items.get(position); + TL_stories.TL_prepaidGiveaway prepaidGiveaway = item.prepaidGiveaway; + GiveawayCell giveawayCell = (GiveawayCell) holder.itemView; + String name = LocaleController.formatPluralString("BoostingTelegramPremiumCountPlural", prepaidGiveaway.quantity); + String info = LocaleController.formatPluralString("BoostingSubscriptionsCountPlural", prepaidGiveaway.quantity, LocaleController.formatPluralString("PrepaidGiveawayMonths", prepaidGiveaway.months)); + giveawayCell.setData(prepaidGiveaway, name, info, 0, !item.isLast); + giveawayCell.setImage(prepaidGiveaway); + giveawayCell.setAvatarPadding(5); + } else if (holder.getItemViewType() == HEADER_VIEW_TYPE_TABS) { + if (boostsTabs.getTag() == null || (int) boostsTabs.getTag() != Objects.hash(totalBoosts, totalGifts)) { + boostsTabs.setTag(Objects.hash(totalBoosts, totalGifts)); + boostsTabs.removeTabs(); + boostsTabs.addTextTab(TAB_BOOSTS, LocaleController.formatPluralString("BoostingBoostsCount", totalBoosts)); + if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable && totalGifts > 0 && totalGifts != totalBoosts) { + boostsTabs.addTextTab(TAB_GIFTS, LocaleController.formatPluralString("BoostingGiftsCount", totalGifts)); + } + boostsTabs.setInitialTabId(selectedTab); + boostsTabs.finishAddingTabs(); + } + } + } + + @Override + public int getItemCount() { + return items.size(); + } + + @Override + public int getItemViewType(int position) { + return items.get(position).viewType; + } + }; + + boolean usersLoading; + private LinearLayout progressLayout; + private final TLRPC.Chat currentChat; + + public BoostsActivity(long dialogId) { + this.dialogId = dialogId; + this.currentChat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + } + + public void updateRows(boolean animated) { + ArrayList oldItems = new ArrayList<>(items); + items.clear(); + items.add(new ItemInternal(HEADER_PADDING, false)); + if (boostsStatus != null) { + items.add(new ItemInternal(HEADER_VIEW_TYPE_OVERVIEW, LocaleController.getString("StatisticOverview", R.string.StatisticOverview))); + items.add(new ItemInternal(OVERVIEW_TYPE, false)); + items.add(new ItemInternal(DIVIDER_VIEW_TYPE, false)); + + if (boostsStatus.prepaid_giveaways.size() > 0) { + items.add(new ItemInternal(HEADER_VIEW_TYPE_SMALL, LocaleController.getString("BoostingPreparedGiveaways", R.string.BoostingPreparedGiveaways))); + for (int i = 0; i < boostsStatus.prepaid_giveaways.size(); i++) { + TL_stories.TL_prepaidGiveaway prepaidGiveaway = boostsStatus.prepaid_giveaways.get(i); + items.add(new ItemInternal(SHOW_PREPARED_GIVE_AWAY, prepaidGiveaway, i == boostsStatus.prepaid_giveaways.size() - 1)); + } + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString("BoostingSelectPaidGiveaway", R.string.BoostingSelectPaidGiveaway))); + } + + items.add(new ItemInternal(HEADER_VIEW_TYPE_TABS, LocaleController.getString("Boosters", R.string.Boosters))); + if (selectedTab == TAB_BOOSTS) { + if (boosters.isEmpty()) { + items.add(new ItemInternal(NO_USERS_HINT, false)); + items.add(new ItemInternal(DIVIDER_VIEW_TYPE, false)); + } else { + for (int i = 0; i < boosters.size(); i++) { + items.add(new ItemInternal(USER_VIEW_TYPE, boosters.get(i), i == boosters.size() - 1 && !hasBoostsNext, selectedTab)); + } + if (hasBoostsNext) { + items.add(new ItemInternal(SHOW_MORE_VIEW_TYPE, true)); + } else { + items.add(new ItemInternal(EMPTY_VIEW_8DP, false)); + } + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString(isChannel() ? R.string.BoostersInfoDescription : R.string.BoostersInfoGroupDescription))); + } + } else { + if (gifts.isEmpty()) { + items.add(new ItemInternal(NO_USERS_HINT, false)); + items.add(new ItemInternal(DIVIDER_VIEW_TYPE, false)); + } else { + for (int i = 0; i < gifts.size(); i++) { + items.add(new ItemInternal(USER_VIEW_TYPE, gifts.get(i), i == gifts.size() - 1 && !hasGiftsNext, selectedTab)); + } + if (hasGiftsNext) { + items.add(new ItemInternal(SHOW_MORE_VIEW_TYPE, true)); + } else { + items.add(new ItemInternal(EMPTY_VIEW_8DP, false)); + } + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString(isChannel() ? R.string.BoostersInfoDescription : R.string.BoostersInfoGroupDescription))); + } + } + + items.add(new ItemInternal(HEADER_VIEW_TYPE, LocaleController.getString("LinkForBoosting", R.string.LinkForBoosting))); + items.add(new ItemInternal(LINK_VIEW_TYPE, boostsStatus.boost_url)); + if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable && ChatObject.hasAdminRights(currentChat)) { + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString(isChannel() ? R.string.BoostingShareThisLink : R.string.BoostingShareThisLinkGroup))); + items.add(new ItemInternal(SHOW_BOOST_BY_GIFTS, true)); + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString(isChannel() ? R.string.BoostingGetMoreBoosts : R.string.BoostingGetMoreBoostsGroup))); + } else { + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, "")); + } + items.add(new ItemInternal(BOTTOM_PADDING, false)); + } + if (animated) { + adapter.setItems(oldItems, items); + } else { + adapter.notifyDataSetChanged(); + } + } + + private boolean isChannel() { + return ChatObject.isChannelAndNotMegaGroup(currentChat); + } + + private void loadStatistic() { + progressLayout.setAlpha(0); + if (boostsStatus == null) { + progressLayout.animate().alpha(1f).setDuration(200).setStartDelay(500).start(); + getMessagesController().getBoostsController().getBoostsStats(dialogId, tl_stories_boostsStatus -> AndroidUtilities.runOnUIThread(() -> { + boostsStatus = tl_stories_boostsStatus; + loadCanApplyBoosts(); + progressLayout.animate().cancel(); + progressLayout.animate().alpha(0).setDuration(100).setStartDelay(0).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressLayout.setVisibility(View.GONE); + } + }); + resetHeader(true); + updateRows(true); + loadUsers(null); + })); + } else { + progressLayout.setVisibility(View.GONE); + loadUsers(null); + } + } + + private void loadCanApplyBoosts() { + if (boostsStatus == null) { + return; + } + getMessagesController().getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> this.canApplyBoost = canApplyBoost); + } + + private String lastBoostsOffset = ""; + private String lastGiftsOffset = ""; + private int limitGifts = 5; + private int limitBoosts = 5; + private int totalGifts; + private int totalBoosts; + + private void loadUsers(Boolean isGift) { + if (usersLoading) { + return; + } + usersLoading = true; + if (isGift == null) { + Utilities.globalQueue.postRunnable(() -> { + CountDownLatch latch = new CountDownLatch(2); + loadOnlyBoosts(latch, null); + loadOnlyGifts(latch, null); + try { + latch.await(); + } catch (InterruptedException ignore) { + + } + NotificationCenter.getInstance(currentAccount).doOnIdle(() -> AndroidUtilities.runOnUIThread(() -> { + usersLoading = false; + updateRows(true); + })); + }); + } else if (isGift) { + loadOnlyGifts(null, () -> { + usersLoading = false; + updateRows(true); + }); + } else { + loadOnlyBoosts(null, () -> { + usersLoading = false; + updateRows(true); + }); + } + } + + private void loadOnlyBoosts(CountDownLatch latch, Runnable after) { + TL_stories.TL_premium_getBoostsList listReq = new TL_stories.TL_premium_getBoostsList(); + listReq.limit = limitBoosts; + listReq.offset = lastBoostsOffset; + listReq.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + + ConnectionsManager.getInstance(currentAccount).sendRequest(listReq, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (latch != null) { + latch.countDown(); + } + if (response != null) { + limitBoosts = 20; + TL_stories.TL_premium_boostsList list = (TL_stories.TL_premium_boostsList) response; + MessagesController.getInstance(currentAccount).putUsers(list.users, false); + lastBoostsOffset = list.next_offset; + boosters.addAll(list.boosts); + int shownBoosts = 0; + for (TL_stories.TL_boost booster : boosters) { + shownBoosts += booster.multiplier > 0 ? booster.multiplier : 1; + } + nextBoostRemaining = Math.max(0, list.count - shownBoosts); + hasBoostsNext = !TextUtils.isEmpty(list.next_offset) && nextBoostRemaining > 0; + totalBoosts = list.count; + if (after != null) { + after.run(); + } + } + }), ConnectionsManager.RequestFlagFailOnServerErrors); + } + + private void loadOnlyGifts(CountDownLatch latch, Runnable after) { + TL_stories.TL_premium_getBoostsList listReq = new TL_stories.TL_premium_getBoostsList(); + listReq.limit = limitGifts; + listReq.gifts = true; + listReq.offset = lastGiftsOffset; + listReq.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + + ConnectionsManager.getInstance(currentAccount).sendRequest(listReq, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (latch != null) { + latch.countDown(); + } + if (response != null) { + limitGifts = 20; + TL_stories.TL_premium_boostsList list = (TL_stories.TL_premium_boostsList) response; + MessagesController.getInstance(currentAccount).putUsers(list.users, false); + lastGiftsOffset = list.next_offset; + gifts.addAll(list.boosts); + int shownGifts = 0; + for (TL_stories.TL_boost booster : gifts) { + shownGifts += booster.multiplier > 0 ? booster.multiplier : 1; + } + nextGiftsRemaining = Math.max(0, list.count - shownGifts); + hasGiftsNext = !TextUtils.isEmpty(list.next_offset) && nextGiftsRemaining > 0; + totalGifts = list.count; + if (after != null) { + after.run(); + } + } + }), ConnectionsManager.RequestFlagFailOnServerErrors); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.boostByChannelCreated) { + TLRPC.Chat chat = (TLRPC.Chat) args[0]; + boolean isGiveaway = (boolean) args[1]; + List fragmentStack = getParentLayout().getFragmentStack(); + BaseFragment chatEditFragment = fragmentStack.size() >= 2 ? fragmentStack.get(fragmentStack.size() - 2) : null; + if (chatEditFragment instanceof ChatEditActivity) { + getParentLayout().removeFragmentFromStack(chatEditFragment); + } + fragmentStack = getParentLayout().getFragmentStack(); + BaseFragment secondFragment = fragmentStack.size() >= 2 ? fragmentStack.get(fragmentStack.size() - 2) : null; + if (isGiveaway) { + BaseFragment thirdFragment = fragmentStack.size() >= 3 ? fragmentStack.get(fragmentStack.size() - 3) : null; + if (secondFragment instanceof ProfileActivity) { + getParentLayout().removeFragmentFromStack(secondFragment); + } + finishFragment(); + if (thirdFragment instanceof ChatActivity) { + BoostDialogs.showBulletin(thirdFragment, chat, true); + } + if (secondFragment instanceof ChatActivity) { + BoostDialogs.showBulletin(secondFragment, chat, true); + } + } else { + finishFragment(); + if (secondFragment instanceof ProfileActivity || secondFragment instanceof ChatActivity) { + BoostDialogs.showBulletin(secondFragment, chat, false); + } + } + } else if (id == NotificationCenter.chatWasBoostedByUser) { + if (dialogId == (long) args[2]) { + boostsStatus = (TL_stories.TL_premium_boostsStatus) args[0]; + canApplyBoost = (ChannelBoostsController.CanApplyBoost) args[1]; + } + } + } + + @Override + public boolean onFragmentCreate() { + getNotificationCenter().addObserver(this, NotificationCenter.boostByChannelCreated); + getNotificationCenter().addObserver(this, NotificationCenter.chatWasBoostedByUser); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + getNotificationCenter().removeObserver(this, NotificationCenter.boostByChannelCreated); + getNotificationCenter().removeObserver(this, NotificationCenter.chatWasBoostedByUser); + super.onFragmentDestroy(); + } + + private class ItemInternal extends AdapterWithDiffUtils.Item { + + String title; + TL_stories.TL_boost booster; + TL_stories.TL_prepaidGiveaway prepaidGiveaway; + boolean isLast; + int tab; + + public ItemInternal(int viewType, String title) { + super(viewType, false); + this.title = title; + } + + public ItemInternal(int viewType, TL_stories.TL_boost booster, boolean isLast, int tab) { + super(viewType, true); + this.booster = booster; + this.isLast = isLast; + this.tab = tab; + } + + public ItemInternal(int viewType, TL_stories.TL_prepaidGiveaway prepaidGiveaway, boolean isLast) { + super(viewType, true); + this.prepaidGiveaway = prepaidGiveaway; + this.isLast = isLast; + } + + public ItemInternal(int viewType, boolean selectable) { + super(viewType, selectable); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ItemInternal that = (ItemInternal) o; + if (prepaidGiveaway != null && that.prepaidGiveaway != null) { + return prepaidGiveaway.id == that.prepaidGiveaway.id && isLast == that.isLast; + } else if (booster != null && that.booster != null) { + return booster.id.hashCode() == that.booster.id.hashCode() && isLast == that.isLast && tab == that.tab; + } else { + return true; + } + } + + @Override + public int hashCode() { + return Objects.hash(title, booster, prepaidGiveaway, isLast, tab); + } + } + + public void createEmptyView(Context context) { + progressLayout = new LinearLayout(context); + progressLayout.setOrientation(LinearLayout.VERTICAL); + + View view = new View(context) { + private final CircularProgressDrawable drawable; + + { + drawable = new CircularProgressDrawable(dp(30), dp(3), Theme.getColor(Theme.key_dialogTextBlue)); + } + + @Override + protected void onDraw(Canvas canvas) { + drawable.setBounds(0, 0, getWidth(), getHeight()); + drawable.setAlpha(255); + drawable.draw(canvas); + invalidate(); + super.onDraw(canvas); + } + }; + progressLayout.addView(view, LayoutHelper.createLinear(100, 100, Gravity.CENTER, 0, 120, 0, 0)); + ((ViewGroup) fragmentView).addView(progressLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + } + + @Override + protected RecyclerView.Adapter createAdapter() { + return adapter; + } + + private void resetHeader(boolean animate) { + if (getContext() == null) return; + if (limitPreviewView == null) { + limitPreviewView = new LimitPreviewView(getContext(), R.drawable.filled_limit_boost, 0, 0, resourceProvider); + limitPreviewView.isStatistic = true; + limitPreviewView.setDarkGradientProvider(this::setDarkGradientLocation); + } + + if (limitPreviewView.getParent() != null) { + ((ViewGroup) limitPreviewView.getParent()).removeView(limitPreviewView); + } + + if (boostsStatus != null) { + limitPreviewView.setBoosts(boostsStatus, false); + if (animate) { + limitPreviewView.setAlpha(0f); + limitPreviewView.animate().alpha(1f).start(); + } + } + + CharSequence title = LocaleController.getString(isChannel() ? R.string.BoostingBoostForChannels : R.string.BoostingBoostForGroups); + CharSequence subTitle = AndroidUtilities.replaceTags(LocaleController.getString(isChannel() ? R.string.BoostingBoostForChannelsInfo : R.string.BoostingBoostForGroupsInfo)); + + View aboveTitleView = new FrameLayout(getContext()) { + { + addView(boostsStatus != null ? limitPreviewView : new View(getContext()), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, boostsStatus != null ? LayoutHelper.WRAP_CONTENT : 110, 0, 8, 46, 8, 33)); + } + }; + + View underSubTitleView = new FrameLayout(getContext()) { + + private final HeaderButtonView buttonView1; + private final HeaderButtonView buttonView2; + private final HeaderButtonView buttonView3; + + { + setWillNotDraw(false); + buttonView1 = new HeaderButtonView(getContext()); + buttonView2 = new HeaderButtonView(getContext()); + buttonView3 = new HeaderButtonView(getContext()); + + buttonView1.setTextAndIcon(LocaleController.getString(R.string.BoostBtn), R.drawable.filled_boost_plus); + buttonView2.setTextAndIcon(LocaleController.getString(R.string.GiveawayBtn), R.drawable.filled_gift_premium); + buttonView3.setTextAndIcon(LocaleController.getString(R.string.FeaturesBtn), R.drawable.filled_info); + buttonView1.setOnClickListener(v -> { + LimitReachedBottomSheet.openBoostsForUsers(BoostsActivity.this, true, dialogId, canApplyBoost, boostsStatus, null); + }); + buttonView2.setOnClickListener(v -> { + updateDialogVisibility(true); + BoostPagerBottomSheet.show(BoostsActivity.this, dialogId, resourceProvider); + BoostPagerBottomSheet.getInstance().setOnHideListener(dialog -> updateDialogVisibility(false)); + }); + buttonView3.setOnClickListener(v -> { + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(BoostsActivity.this, getContext(), TYPE_FEATURES, currentAccount, getResourceProvider()); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + showDialog(limitReachedBottomSheet); + }); + LinearLayout linearLayout = new LinearLayout(getContext()); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.addView(buttonView1, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 6, 0, 6, 0)); + if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable && ChatObject.hasAdminRights(currentChat)) { + linearLayout.addView(buttonView2, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 6, 0, 6, 0)); + } + linearLayout.addView(buttonView3, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 6, 0, 6, 0)); + + addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 19, 0, 0)); + } + }; + configureHeader(title, subTitle, aboveTitleView, underSubTitleView); + } + + private class HeaderButtonView extends FrameLayout { + + private final ImageView imageView; + private final TextView textView; + private final RectF rect = new RectF(); + + public HeaderButtonView(@NonNull Context context) { + super(context); + setWillNotDraw(false); + imageView = new ImageView(context); + textView = new TextView(context); + textView.setTextColor(Color.WHITE); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 25, 0, 0)); + setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + setMinimumWidth(AndroidUtilities.dp(100)); + setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(10), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.BLACK, 80))); + } + + public void setTextAndIcon(CharSequence text, int icon) { + textView.setText(text); + imageView.setImageDrawable(ContextCompat.getDrawable(getContext(), icon)); + } + + @Override + public void draw(Canvas canvas) { + rect.set(0, 0, getWidth(), getHeight()); + Paint p = setDarkGradientLocation((((ViewGroup) getParent()).getX() + getX()), ((ViewGroup) getParent().getParent().getParent()).getY()); + canvas.drawRoundRect(rect, AndroidUtilities.dp(10), AndroidUtilities.dp(10), p); + invalidate(); + super.draw(canvas); + } + } + + @Override + public View createView(Context context) { + View rootView = super.createView(context); + resetHeader(false); + DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator(); + defaultItemAnimator.setSupportsChangeAnimations(false); + defaultItemAnimator.setDelayAnimations(false); + listView.setItemAnimator(defaultItemAnimator); + listView.setOnItemClickListener((view, position) -> { + if (view instanceof GiftedUserCell) { + GiftedUserCell cell = (GiftedUserCell) view; + TL_stories.TL_boost boost = cell.getBoost(); + if (((boost.gift || boost.giveaway) && boost.user_id >= 0) || boost.unclaimed) { + TLRPC.TL_payments_checkedGiftCode giftCode = new TLRPC.TL_payments_checkedGiftCode(); + giftCode.giveaway_msg_id = boost.giveaway_msg_id; + giftCode.to_id = boost.user_id; + giftCode.from_id = MessagesController.getInstance(UserConfig.selectedAccount).getPeer(-currentChat.id); + giftCode.date = boost.date; + giftCode.via_giveaway = boost.giveaway; + giftCode.months = (boost.expires - boost.date) / 30 / 86400; + if (boost.unclaimed) { + giftCode.to_id = NO_USER_ID; + giftCode.flags = -1; + } else { + giftCode.boost = boost; + } + new GiftInfoBottomSheet(this, false, true, giftCode, boost.used_gift_slug).show(); + } else if (boost.giveaway && boost.user_id == NO_USER_ID) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getParentActivity(), getResourceProvider()); + layout.setAnimation(R.raw.chats_infotip, 36, 36); + layout.textView.setText(LocaleController.getString("BoostingRecipientWillBeSelected", R.string.BoostingRecipientWillBeSelected)); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(2); + Bulletin.make(this, layout, Bulletin.DURATION_LONG).show(); + } else if (!boost.gift && !boost.giveaway) { + presentFragment(ProfileActivity.of(cell.getDialogId())); + } + } + if (view instanceof TextCell) { + BoostPagerBottomSheet.show(this, dialogId, resourceProvider); + } + if (view instanceof GiveawayCell) { + BoostPagerBottomSheet.show(this, resourceProvider, dialogId, ((GiveawayCell) view).getPrepaidGiveaway()); + } + if (items.get(position).viewType == SHOW_MORE_VIEW_TYPE) { + loadUsers(selectedTab == TAB_GIFTS); + } + }); + + createEmptyView(getContext()); + loadStatistic(); + updateRows(false); + return rootView; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java index 69f471c5f..c778b81c8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java @@ -24,6 +24,7 @@ import android.graphics.Point; import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.ShapeDrawable; +import android.hardware.Camera; import android.net.Uri; import android.os.Build; import android.os.Handler; @@ -74,6 +75,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.camera.CameraController; import org.telegram.messenger.camera.CameraSession; +import org.telegram.messenger.camera.CameraSessionWrapper; import org.telegram.messenger.camera.CameraView; import org.telegram.messenger.camera.Size; import org.telegram.ui.ActionBar.ActionBar; @@ -710,7 +712,7 @@ public class CameraScanActivity extends BaseFragment { if (cameraView == null) { return; } - CameraSession session = cameraView.getCameraSession(); + CameraSessionWrapper session = cameraView.getCameraSession(); if (session != null) { ShapeDrawable shapeDrawable = (ShapeDrawable) flashButton.getBackground(); if (flashAnimator != null) { @@ -732,10 +734,10 @@ public class CameraScanActivity extends BaseFragment { flashAnimator.start(); if (flashButton.getTag() == null) { flashButton.setTag(1); - session.setTorchEnabled(true); + session.setCurrentFlashMode(Camera.Parameters.FLASH_MODE_TORCH); } else { flashButton.setTag(null); - session.setTorchEnabled(false); + session.setCurrentFlashMode(Camera.Parameters.FLASH_MODE_OFF); } } }); 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 811ec9955..1798e37bc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -62,7 +62,7 @@ import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.LeadingMarginSpan; import android.text.style.URLSpan; -import android.util.Log; +import android.util.Pair; import android.util.Property; import android.util.SparseArray; import android.util.StateSet; @@ -154,6 +154,7 @@ import org.telegram.ui.Components.MessageBackgroundDrawable; import org.telegram.ui.Components.MotionBackgroundDrawable; import org.telegram.ui.Components.MsgClockDrawable; import org.telegram.ui.Components.Point; +import org.telegram.ui.Components.Premium.boosts.BoostCounterSpan; import org.telegram.ui.Components.Premium.boosts.cells.msg.GiveawayMessageCell; import org.telegram.ui.Components.Premium.boosts.cells.msg.GiveawayResultsMessageCell; import org.telegram.ui.Components.QuoteHighlight; @@ -473,6 +474,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate default void didPressViaBot(ChatMessageCell cell, String username) { } + default void didPressBoostCounter(ChatMessageCell cell) { + } + default void didPressChannelAvatar(ChatMessageCell cell, TLRPC.Chat chat, int postId, float touchX, float touchY) { } @@ -937,6 +941,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private int nameLayoutSelectorColor; private Drawable nameLayoutSelector; private boolean nameLayoutPressed; + private boolean boostCounterPressed; + private int boostCounterSelectorColor; + private Drawable boostCounterLayoutSelector; private int nameStatusSelectorColor; private Drawable nameStatusSelector; @@ -1262,6 +1269,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private StaticLayout nameLayout; private int nameLayoutWidth; private StaticLayout adminLayout; + private RectF boostCounterBounds; + private BoostCounterSpan boostCounterSpan; private int nameWidth; private float nameOffsetX; private float nameX; @@ -1666,6 +1675,38 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return new int[]{start, end}; } + private boolean checkAdminMotionEvent(MotionEvent event) { + if (adminLayout == null || boostCounterBounds == null || currentUser == null && currentChat == null) { + boostCounterPressed = false; + return false; + } + final boolean pressed = boostCounterBounds.contains((int) event.getX(), (int) event.getY()); + if (event.getAction() == MotionEvent.ACTION_DOWN) { + SpannableString spannableString = new SpannableString(adminLayout.getText()); + BoostCounterSpan[] spans = spannableString.getSpans(0, spannableString.length(), BoostCounterSpan.class); + boostCounterPressed = pressed && spans != null && spans.length > 0; + if (boostCounterPressed) { + if (boostCounterLayoutSelector != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + boostCounterLayoutSelector.setHotspot((int) event.getX(), (int) event.getY()); + } + boostCounterLayoutSelector.setState(pressedState); + } + } + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (event.getAction() == MotionEvent.ACTION_UP && boostCounterPressed) { + if (delegate != null) { + delegate.didPressBoostCounter(this); + } + } + if (boostCounterLayoutSelector != null) { + boostCounterLayoutSelector.setState(StateSet.NOTHING); + } + boostCounterPressed = false; + } + return boostCounterPressed; + } + private boolean checkNameMotionEvent(MotionEvent event) { if (!drawNameLayout || nameLayout == null || nameLayoutSelector == null || currentUser == null && currentChat == null) { nameLayoutPressed = false; @@ -2301,7 +2342,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (delegate != null) { delegate.didPressInstantButton(this, drawInstantViewType); } - } else if (drawPhotoImage && authorLayout == null && titleLayout == null && descriptionLayout == null && siteNameLayout == null) { + } else if (drawPhotoImage && (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || authorLayout == null && titleLayout == null && descriptionLayout == null && siteNameLayout == null)) { if (delegate != null) { delegate.didPressImage(this, lastTouchX, lastTouchY); } @@ -3421,6 +3462,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate disallowLongPress = true; } } + if(!result) { + result = checkAdminMotionEvent(event); + } if (!result) { result = checkNameMotionEvent(event); } @@ -5022,6 +5066,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate isReplyQuote = false; replyNameLayout = null; adminLayout = null; + boostCounterBounds = null; + boostCounterSpan = null; checkOnlyButtonPressed = false; replyTextLayout = null; AnimatedEmojiSpan.release(this, animatedEmojiReplyStack); @@ -5424,6 +5470,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if ("telegram_channel_boost".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 18; + } else if ("telegram_group_boost".equals(webpageType)) { + drawInstantView = true; + drawInstantViewType = 22; } else if ("telegram_giftcode".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 20; @@ -5787,8 +5836,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate "article".equals(type) || "telegram_bot".equals(type) || "telegram_user".equals(type) || "telegram_channel".equals(type) || "telegram_megagroup".equals(type) || "telegram_voicechat".equals(type) || - "telegram_livestream".equals(type) || "telegram_channel_boost".equals(type); - smallImage = !slideshow && (!drawInstantView || drawInstantViewType == 1 || drawInstantViewType == 2 || drawInstantViewType == 9 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 18 || drawInstantViewType == 20) && document == null && isSmallImageType; + "telegram_livestream".equals(type) || "telegram_channel_boost".equals(type) || "telegram_group_boost".equals(type); + smallImage = !slideshow && (!drawInstantView || drawInstantViewType == 1 || drawInstantViewType == 2 || drawInstantViewType == 9 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 18 || drawInstantViewType == 20 || drawInstantViewType == 22) && document == null && isSmallImageType; TLRPC.MessageMedia media = MessageObject.getMedia(messageObject.messageOwner); if (media != null) { if (media.force_large_media) { @@ -5835,6 +5884,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (drawInstantViewType == 18) { site_name = LocaleController.getString("BoostChannel", R.string.BoostChannel); + } else if (drawInstantViewType == 22) { + site_name = LocaleController.getString("BoostGroup", R.string.BoostGroup); } else if (drawInstantViewType == 11) { site_name = LocaleController.getString("VoipChannelVoiceChat", R.string.VoipChannelVoiceChat); } else if (drawInstantViewType == 9) { @@ -6029,15 +6080,17 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate totalHeight += height; descriptionLayoutWidth = 0; - descriptionLayoutLeft = descriptionLayout.getWidth(); + int descriptionLayoutLeft = descriptionLayout.getWidth(), descriptionLayoutRight = 0; for (int a = 0; a < descriptionLayout.getLineCount(); a++) { descriptionLayoutLeft = (int) Math.min(descriptionLayoutLeft, descriptionLayout.getLineLeft(a)); - float width = Math.min(descriptionLayout.getWidth(), descriptionLayout.getLineWidth(a)); + int addright = 0; if (a < restLines || restLines != 0 && descriptionLayoutLeft != 0 && isSmallImage) { - width += smallImageSide + smallSideMargin; + addright = smallImageSide + smallSideMargin; } - descriptionLayoutWidth = (int) Math.max(descriptionLayoutWidth, width); + descriptionLayoutRight = (int) Math.max(descriptionLayoutRight, descriptionLayout.getLineRight(a) + addright); } + descriptionLayoutWidth = Math.abs(descriptionLayoutRight - descriptionLayoutLeft); + this.descriptionLayoutLeft = descriptionLayoutLeft; if (maxWebWidth < descriptionLayoutWidth + additinalWidth) { maxWebWidth = descriptionLayoutWidth + additinalWidth; } @@ -8983,6 +9036,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (nameLayoutSelector != null) { nameLayoutSelector.setState(StateSet.NOTHING); } + if (boostCounterLayoutSelector != null) { + boostCounterLayoutSelector.setState(StateSet.NOTHING); + } resetCodeSelectors(); if (replyBounce != null) { replyBounce.setPressed(false); @@ -10099,7 +10155,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate str = LocaleController.getString("OpenLink").toUpperCase(); } else if (drawInstantViewType == 17) { str = LocaleController.getString("ViewStory").toUpperCase(); - } else if (drawInstantViewType == 18) { + } else if (drawInstantViewType == 18 || drawInstantViewType == 22) { str = LocaleController.getString("BoostLinkButton", R.string.BoostLinkButton); } else if (drawInstantViewType == 19) { str = LocaleController.getString("BoostingHowItWork", R.string.BoostingHowItWork); @@ -11820,8 +11876,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } Theme.chat_replyNamePaint.setColor(linkLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_LINK)); - final boolean drawPhotoImageBefore = drawInstantView && (drawInstantViewType != 9 && drawInstantViewType != 2 && drawInstantViewType != 13 && drawInstantViewType != 11 && drawInstantViewType != 1 && drawInstantViewType != 18) || drawInstantViewType == 6 && imageBackgroundColor != 0; - final boolean drawPhotoImageAfter = !drawInstantView || drawInstantViewType == 9 || drawInstantViewType == 2 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 1 || drawInstantViewType == 18 || isSmallImage; + final boolean drawPhotoImageBefore = drawInstantView && (drawInstantViewType != 9 && drawInstantViewType != 2 && drawInstantViewType != 13 && drawInstantViewType != 11 && drawInstantViewType != 1 && drawInstantViewType != 18 && drawInstantViewType != 22) || drawInstantViewType == 6 && imageBackgroundColor != 0; + final boolean drawPhotoImageAfter = !drawInstantView || drawInstantViewType == 9 || drawInstantViewType == 2 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 1 || drawInstantViewType == 18 || drawInstantViewType == 22 || isSmallImage; boolean restore = false; boolean drawInstantButtonInside = false; @@ -14499,27 +14555,39 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (nameWidth < 0) { nameWidth = AndroidUtilities.dp(100); } - int adminWidth; - String adminString; + int adminWidth = 0; + SpannableStringBuilder adminString = null; String adminLabel; if (isMegagroup && currentChat != null && messageObject.messageOwner.post_author != null && currentChat.id == -currentMessageObject.getFromChatId()) { - adminString = messageObject.messageOwner.post_author.replace("\n", ""); - adminWidth = (int) Math.ceil(Theme.chat_adminPaint.measureText(adminString)); - nameWidth -= adminWidth; + adminString = new SpannableStringBuilder(messageObject.messageOwner.post_author.replace("\n", "")); } else if (isMegagroup && currentChat != null && currentMessageObject.isForwardedChannelPost()) { - adminString = LocaleController.getString("DiscussChannel", R.string.DiscussChannel); - adminWidth = (int) Math.ceil(Theme.chat_adminPaint.measureText(adminString)); - nameWidth -= adminWidth; + adminString = new SpannableStringBuilder(LocaleController.getString("DiscussChannel", R.string.DiscussChannel)); } else if ((currentUser != null || currentChat != null) && !currentMessageObject.isOutOwner() && !currentMessageObject.isAnyKindOfSticker() && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO && delegate != null && (adminLabel = delegate.getAdminRank(currentUser != null ? currentUser.id : currentChat.id)) != null) { if (adminLabel.length() == 0) { adminLabel = LocaleController.getString("ChatAdmin", R.string.ChatAdmin); } - adminString = adminLabel; - adminWidth = (int) Math.ceil(Theme.chat_adminPaint.measureText(adminString)); + adminString = new SpannableStringBuilder(adminLabel); + } + + int boosts = currentMessageObject.messageOwner.from_boosts_applied; + if (boosts > 0) { + if (adminString == null) { + adminString = new SpannableStringBuilder(); + } + Pair pair = BoostCounterSpan.create(this, Theme.chat_namePaint, boosts); + boostCounterSpan = pair.second; + boostCounterSpan.isRtl = AndroidUtilities.isRTL(adminString); + if (boostCounterSpan.isRtl) { + adminString.insert(0, pair.first); + } else { + adminString.append(pair.first); + } + } + + if (adminString != null) { + StaticLayout staticLayout = new StaticLayout(adminString, Theme.chat_adminPaint, dp(300), Layout.Alignment.ALIGN_NORMAL, 0f, 0f, false); + adminWidth = (int) staticLayout.getLineWidth(0); nameWidth -= adminWidth; - } else { - adminString = null; - adminWidth = 0; } currentNameStatus = null; @@ -14585,8 +14653,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (adminString != null) { adminLayout = new StaticLayout(adminString, Theme.chat_adminPaint, adminWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); nameWidth += adminLayout.getLineWidth(0) + AndroidUtilities.dp(8); + boostCounterBounds = new RectF(); } else { adminLayout = null; + boostCounterBounds = null; } } catch (Exception e) { FileLog.e(e); @@ -14797,7 +14867,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } final TextPaint textPaint = isReplyQuote && messageObject.shouldDrawWithoutBackground() ? Theme.chat_quoteTextPaint : Theme.chat_replyTextPaint; if (messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.story_id != 0) { - name = getNameFromDialogId(messageObject.messageOwner.reply_to.user_id); + name = getNameFromDialogId(DialogObject.getPeerDialogId(messageObject.messageOwner.reply_to.peer)); if (messageObject.messageOwner.replyStory == null || messageObject.messageOwner.replyStory instanceof TL_stories.TL_storyItemDeleted) { if (messageObject.messageOwner.replyStory == null) { stringFinalText = LocaleController.getString("Loading", R.string.Loading); @@ -16916,7 +16986,24 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } Theme.chat_adminPaint.setColor(color); canvas.save(); - final float ax = end - AndroidUtilities.dp(11) - adminLayout.getLineWidth(0); + final float ax = end - dp(11) - adminLayout.getLineWidth(0); + final float ay = nameY + dp(0.5f); + + if (boostCounterSpan != null && boostCounterBounds != null) { + final float bx = end - dp(boostCounterSpan.isRtl ? 5f : 7.5f) - boostCounterSpan.getWidth(); + boostCounterBounds.set(bx, ay, bx + boostCounterSpan.getWidth(), ay + adminLayout.getHeight()); + int selectorColor = Theme.multAlpha(Theme.chat_namePaint.getColor(), .12f); + if (boostCounterLayoutSelector == null) { + boostCounterLayoutSelector = Theme.createRadSelectorDrawable(boostCounterSelectorColor = selectorColor, 6, 6); + boostCounterLayoutSelector.setCallback(this); + } else if (boostCounterSelectorColor != selectorColor) { + Theme.setSelectorDrawableColor(boostCounterLayoutSelector, boostCounterSelectorColor = selectorColor, true); + } + boostCounterLayoutSelector.setBounds((int) boostCounterBounds.left - dp(4), (int) boostCounterBounds.top, (int) (int) boostCounterBounds.right, (int) boostCounterBounds.bottom); + boostCounterLayoutSelector.setAlpha((int) (0xFF * nameAlpha)); + boostCounterLayoutSelector.draw(canvas); + } + canvas.translate(ax, nameY + AndroidUtilities.dp(0.5f)); if (transitionParams.animateSign) { Theme.chat_adminPaint.setAlpha((int) (Color.alpha(color) * transitionParams.animateChangeProgress)); @@ -20047,6 +20134,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate AndroidUtilities.rectTmp.set(radialProgress.getProgressRect()); AndroidUtilities.rectTmp.inset(-dp(15), -dp(15)); canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (0xFF * radialProgressAlpha), Canvas.ALL_SAVE_FLAG); + } else { + canvas.save(); + final int type = currentMessageObject.type; + if (drawPhotoImage && (type == MessageObject.TYPE_VIDEO || type == MessageObject.TYPE_PHOTO || type == MessageObject.TYPE_GIF)) { + canvas.clipRect(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); + } } if (currentMessageObject.needDrawBluredPreview()) { @@ -20091,9 +20184,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate oncePeriod.draw(canvas, 1f); canvas.restore(); - - canvas.restore(); } + + canvas.restore(); } protected void drawPhotoBlurRect(Canvas canvas, RectF rect) { 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 436877697..478109bd1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -403,6 +403,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava private TLRPC.EncryptedChat encryptedChat; private CharSequence lastPrintString; private int printingStringType; + private boolean draftVoice; private TLRPC.DraftMessage draftMessage; private final AnimatedFloat premiumBlockedT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); @@ -1228,24 +1229,29 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } if (isTopic) { - draftMessage = MediaDataController.getInstance(currentAccount).getDraft(currentDialogId, getTopicId()); + draftVoice = MediaDataController.getInstance(currentAccount).getDraftVoice(currentDialogId, getTopicId()) != null; + draftMessage = !draftVoice ? MediaDataController.getInstance(currentAccount).getDraft(currentDialogId, getTopicId()) : null; if (draftMessage != null && TextUtils.isEmpty(draftMessage.message)) { draftMessage = null; } } else if (isDialogCell || isSavedDialogCell) { - draftMessage = MediaDataController.getInstance(currentAccount).getDraft(currentDialogId, 0); + draftVoice = MediaDataController.getInstance(currentAccount).getDraftVoice(currentDialogId, getTopicId()) != null; + draftMessage = !draftVoice ? MediaDataController.getInstance(currentAccount).getDraft(currentDialogId, 0) : null; } else { + draftVoice = false; draftMessage = null; } - if (draftMessage != null && (TextUtils.isEmpty(draftMessage.message) && (draftMessage.reply_to == null || draftMessage.reply_to.reply_to_msg_id == 0) || lastDate > draftMessage.date && unreadCount != 0) || + if ((draftVoice || draftMessage != null) && (!draftVoice && draftMessage != null && TextUtils.isEmpty(draftMessage.message) && (draftMessage.reply_to == null || draftMessage.reply_to.reply_to_msg_id == 0) || draftMessage != null && lastDate > draftMessage.date && unreadCount != 0) || ChatObject.isChannel(chat) && !chat.megagroup && !chat.creator && (chat.admin_rights == null || !chat.admin_rights.post_messages) || chat != null && (chat.left || chat.kicked) || forbidDraft || ChatObject.isForum(chat) && !isTopic) { draftMessage = null; + draftVoice = false; } if (isForumCell()) { draftMessage = null; + draftVoice = false; needEmoji = true; updateMessageThumbs(); messageNameString = getMessageNameString(); @@ -1285,10 +1291,10 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava lastPrintString = null; printingStringType = -1; } - if (draftMessage != null) { + if (draftVoice || draftMessage != null) { checkMessage = false; messageNameString = LocaleController.getString("Draft", R.string.Draft); - if (TextUtils.isEmpty(draftMessage.message)) { + if (draftMessage != null && TextUtils.isEmpty(draftMessage.message)) { if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { messageString = ""; } else { @@ -1297,14 +1303,25 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava messageString = stringBuilder; } } else { - String mess = draftMessage.message; - if (mess.length() > 150) { - mess = mess.substring(0, 150); + String mess; + if (draftVoice) { + mess = LocaleController.getString(R.string.AttachAudio); + } else if (draftMessage != null) { + mess = draftMessage.message; + if (mess.length() > 150) { + mess = mess.substring(0, 150); + } + } else { + mess = ""; } Spannable messSpan = new SpannableStringBuilder(mess); - MediaDataController.addTextStyleRuns(draftMessage, messSpan, TextStyleSpan.FLAG_STYLE_SPOILER | TextStyleSpan.FLAG_STYLE_STRIKE); - if (draftMessage != null && draftMessage.entities != null) { - MediaDataController.addAnimatedEmojiSpans(draftMessage.entities, messSpan, currentMessagePaint == null ? null : currentMessagePaint.getFontMetricsInt()); + if (draftMessage != null) { + MediaDataController.addTextStyleRuns(draftMessage, messSpan, TextStyleSpan.FLAG_STYLE_SPOILER | TextStyleSpan.FLAG_STYLE_STRIKE); + if (draftMessage != null && draftMessage.entities != null) { + MediaDataController.addAnimatedEmojiSpans(draftMessage.entities, messSpan, currentMessagePaint == null ? null : currentMessagePaint.getFontMetricsInt()); + } + } else if (draftVoice) { + messSpan.setSpan(new ForegroundColorSpanThemable(Theme.key_chats_actionMessage, resourcesProvider), 0, messSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } SpannableStringBuilder stringBuilder = formatInternal(messageFormatType, AndroidUtilities.replaceNewLines(messSpan), messageNameString); @@ -1556,7 +1573,13 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava currentMessagePaint = Theme.dialogs_messagePrintingPaint[paintIndex]; } else { if (message.messageOwner.media instanceof TLRPC.TL_messageMediaGiveaway) { - messageString = LocaleController.getString("BoostingGiveawayChannelStarted", R.string.BoostingGiveawayChannelStarted); + boolean isChannel; + if (message.messageOwner.fwd_from != null && message.messageOwner.fwd_from.from_id instanceof TLRPC.TL_peerChannel) { + isChannel = ChatObject.isChannelAndNotMegaGroup(message.messageOwner.fwd_from.from_id.channel_id, currentAccount); + } else { + isChannel = ChatObject.isChannelAndNotMegaGroup(chat); + } + messageString = LocaleController.getString(isChannel ? R.string.BoostingGiveawayChannelStarted : R.string.BoostingGiveawayGroupStarted); } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults) { messageString = LocaleController.getString("BoostingGiveawayResults", R.string.BoostingGiveawayResults); } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { @@ -2800,7 +2823,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } if (!continueUpdate && (mask & MessagesController.UPDATE_MASK_CHAT) != 0 && chat != null) { TLRPC.Chat newChat = MessagesController.getInstance(currentAccount).getChat(chat.id); - if ((newChat.call_active && newChat.call_not_empty) != hasCall) { + if ((newChat != null && newChat.call_active && newChat.call_not_empty) != hasCall) { continueUpdate = true; } } @@ -5162,14 +5185,17 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } } + boolean draftVoice = false; TLRPC.DraftMessage draftMessage = null; if (isTopic) { - draftMessage = MediaDataController.getInstance(currentAccount).getDraft(currentDialogId, getTopicId()); + draftVoice = MediaDataController.getInstance(currentAccount).getDraftVoice(currentDialogId, getTopicId()) != null; + draftMessage = !draftVoice ? MediaDataController.getInstance(currentAccount).getDraft(currentDialogId, getTopicId()) : null; if (draftMessage != null && TextUtils.isEmpty(draftMessage.message)) { draftMessage = null; } } else if (isDialogCell) { - draftMessage = MediaDataController.getInstance(currentAccount).getDraft(currentDialogId, 0); + draftVoice = MediaDataController.getInstance(currentAccount).getDraftVoice(currentDialogId, 0) != null; + draftMessage = !draftVoice ? MediaDataController.getInstance(currentAccount).getDraft(currentDialogId, 0) : null; } int draftHash = draftMessage == null ? 0 : draftMessage.message.hashCode() + (draftMessage.reply_to != null ? (draftMessage.reply_to.reply_to_msg_id << 16) : 0); boolean hasCall = chat != null && chat.call_active && chat.call_not_empty; @@ -5184,7 +5210,8 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava lastTopicsCount == topicCount && draftHash == lastDrawnDraftHash && lastDrawnPinned == drawPin && - lastDrawnHasCall == hasCall) { + lastDrawnHasCall == hasCall && + DialogCell.this.draftVoice == draftVoice) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java index 03d271f78..820b376f0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java @@ -19,6 +19,7 @@ import androidx.annotation.NonNull; 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.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; @@ -53,6 +54,15 @@ public class DialogsHintCell extends FrameLayout { messageView.setEllipsize(TextUtils.TruncateAt.END); contentView.addView(messageView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.TOP)); + NotificationCenter.getGlobalInstance().listen(this, NotificationCenter.emojiLoaded, args -> { + if (titleView != null) { + titleView.invalidate(); + } + if (messageView != null) { + messageView.invalidate(); + } + }); + chevronView = new ImageView(context); chevronView.setImageResource(R.drawable.arrow_newchat); addView(chevronView, LayoutHelper.createFrame(16, 16, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL)); @@ -83,15 +93,10 @@ public class DialogsHintCell extends FrameLayout { closeView.setVisibility(GONE); } - public void setChristmasStyle(OnClickListener closeListener) { + public void setOnCloseListener(OnClickListener closeListener) { chevronView.setVisibility(INVISIBLE); closeView.setVisibility(VISIBLE); closeView.setOnClickListener(closeListener); - Emoji.EmojiDrawable drawable = Emoji.getEmojiDrawable("\uD83C\uDF84"); - if (drawable != null) { - drawable.setBounds(dp(2), -dp(2), Emoji.drawImgSize + dp(2), Emoji.drawImgSize - dp(2)); - titleView.setCompoundDrawables(null, null, drawable, null); - } } @Override 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 e6515b0a3..d1f96e747 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java @@ -112,6 +112,16 @@ public class DrawerActionCell extends FrameLayout { } } + public void setTextAndIcon(int id, CharSequence text, int resId) { + currentId = id; + try { + textView.setText(text); + imageView.setImageResource(resId); + } catch (Throwable e) { + FileLog.e(e); + } + } + public void updateTextAndIcon(String text, int resId) { try { textView.setText(text); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/LanguageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/LanguageCell.java index 62a745bd9..7af8c3d35 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/LanguageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/LanguageCell.java @@ -26,7 +26,7 @@ public class LanguageCell extends FrameLayout { private RadioButton radioButton; private TextView textView; - private TextView textView2; + public TextView textView2; private boolean needDivider; private LocaleController.LocaleInfo currentLocale; private int marginStartDp = 62, marginEndDp = 23; @@ -73,7 +73,7 @@ public class LanguageCell extends FrameLayout { needDivider = divider; } - public void setValue(String name, String nameEnglish) { + public void setValue(CharSequence name, CharSequence nameEnglish) { textView.setText(name); textView2.setText(nameEnglish); radioButton.setChecked(false, false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java index f96144722..0b0535e2e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java @@ -61,7 +61,6 @@ public class MentionCell extends LinearLayout { super.setText(text, type); } }; - NotificationCenter.listenEmojiLoading(nameTextView); nameTextView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); nameTextView.setSingleLine(true); @@ -78,6 +77,11 @@ public class MentionCell extends LinearLayout { addView(usernameTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 12, 0, 8, 0)); } + public void invalidateEmojis() { + nameTextView.invalidate(); + usernameTextView.invalidate(); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(36), MeasureSpec.EXACTLY)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java index 92881b60f..0388ba27a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java @@ -8,6 +8,8 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -42,9 +44,11 @@ import org.telegram.messenger.MessageObject; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.Easings; @@ -71,6 +75,7 @@ public class StickerSetCell extends FrameLayout { private ImageView optionsButton; private ImageView reorderButton; private TLRPC.TL_messages_stickerSet stickersSet; + private boolean groupSearch; private Rect rect = new Rect(); private boolean emojis; @@ -78,6 +83,7 @@ public class StickerSetCell extends FrameLayout { private TextView addButtonView; private TextView removeButtonView; private PremiumButtonView premiumButtonView; + private ImageView deleteView; public StickerSetCell(Context context, int option) { this(context, null, option); @@ -201,7 +207,15 @@ public class StickerSetCell extends FrameLayout { valueTextView.setSingleLine(true); valueTextView.setGravity(LayoutHelper.getAbsoluteGravityStart()); addView(valueTextView, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START, 71, 32, 70, 0)); - + if (option == 3) { + deleteView = new ImageView(context); + deleteView.setImageResource(R.drawable.msg_close); + deleteView.setPadding(dp(8), dp(8), dp(8), dp(8)); + deleteView.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText), PorterDuff.Mode.SRC_IN); + deleteView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); + deleteView.setVisibility(GONE); + addView(deleteView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, LocaleController.isRTL ? 4 : 0, 0, LocaleController.isRTL ? 0 : 4, 0)); + } updateButtonState(BUTTON_STATE_EMPTY, false); } @@ -276,9 +290,10 @@ public class StickerSetCell extends FrameLayout { } @SuppressLint("SetTextI18n") - public void setStickersSet(TLRPC.TL_messages_stickerSet set, boolean divider, boolean groupSearch) { + public void setStickersSet(TLRPC.TL_messages_stickerSet set, boolean divider, boolean search) { needDivider = divider; stickersSet = set; + groupSearch = search; imageView.setVisibility(VISIBLE); if (progressView != null) { @@ -305,7 +320,6 @@ public class StickerSetCell extends FrameLayout { ArrayList documents = set.documents; if (documents != null && !documents.isEmpty()) { valueTextView.setText(LocaleController.formatPluralString(emojis ? "EmojiCount" : "Stickers", documents.size())); - TLRPC.Document sticker = null; for (int i = 0; i < documents.size(); ++i) { TLRPC.Document d = documents.get(i); @@ -352,6 +366,17 @@ public class StickerSetCell extends FrameLayout { } else { valueTextView.setText(LocaleController.formatPluralString(set.set.emojis ? "EmojiCount" : "Stickers", 0)); imageView.setImageDrawable(null); + if (set.set.thumb_document_id != 0) { + AnimatedEmojiDrawable.getDocumentFetcher(UserConfig.selectedAccount) + .fetchDocument(set.set.thumb_document_id, document -> { + AndroidUtilities.runOnUIThread(() -> { + if (stickersSet.documents.isEmpty() && stickersSet.set.thumb_document_id == document.id) { + stickersSet.documents.add(document); + setStickersSet(stickersSet, needDivider, groupSearch); + } + }); + }); + } } if (groupSearch) { valueTextView.setText((set.set.emojis ? LINK_PREFIX_EMOJI : LINK_PREFIX) + set.set.short_name); @@ -375,39 +400,16 @@ public class StickerSetCell extends FrameLayout { return false; } + public void setDeleteAction(OnClickListener action) { + if (deleteView != null) { + deleteView.setVisibility(action == null ? View.GONE : View.VISIBLE); + deleteView.setOnClickListener(action); + } + } + public void setChecked(boolean checked, boolean animated) { if (option == 1) { checkBox.setChecked(checked, animated); - } else if (emojis) { - if (animated) { - sideButtons.animate().cancel(); - sideButtons.animate().setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (!checked) { - sideButtons.setVisibility(INVISIBLE); - } - } - - @Override - public void onAnimationStart(Animator animation) { - if (checked) { - sideButtons.setVisibility(VISIBLE); - } - } - }).alpha(checked ? 1 : 0).scaleX(checked ? 1 : 0.1f).scaleY(checked ? 1 : 0.1f).setDuration(150).start(); - } else { - sideButtons.setVisibility(checked ? VISIBLE : INVISIBLE); - if (!checked) { - sideButtons.setAlpha(0f); - sideButtons.setScaleX(0.1f); - sideButtons.setScaleY(0.1f); - } else { - sideButtons.setAlpha(1f); - sideButtons.setScaleX(1f); - sideButtons.setScaleY(1f); - } - } } else if (option == 3) { if (animated) { optionsButton.animate().cancel(); @@ -438,6 +440,36 @@ public class StickerSetCell extends FrameLayout { optionsButton.setScaleY(1f); } } + } else if (emojis) { + if (animated) { + sideButtons.animate().cancel(); + sideButtons.animate().setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!checked) { + sideButtons.setVisibility(INVISIBLE); + } + } + + @Override + public void onAnimationStart(Animator animation) { + if (checked) { + sideButtons.setVisibility(VISIBLE); + } + } + }).alpha(checked ? 1 : 0).scaleX(checked ? 1 : 0.1f).scaleY(checked ? 1 : 0.1f).setDuration(150).start(); + } else { + sideButtons.setVisibility(checked ? VISIBLE : INVISIBLE); + if (!checked) { + sideButtons.setAlpha(0f); + sideButtons.setScaleX(0.1f); + sideButtons.setScaleY(0.1f); + } else { + sideButtons.setAlpha(1f); + sideButtons.setScaleX(1f); + sideButtons.setScaleY(1f); + } + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java index f6a957bc3..0534ebc7e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java @@ -286,7 +286,7 @@ public class TextCell extends FrameLayout { private CharSequence valueText; - public void setText(String text, boolean divider) { + public void setText(CharSequence text, boolean divider) { imageLeft = 21; textView.setText(text); textView.setRightDrawable(null); @@ -300,8 +300,12 @@ public class TextCell extends FrameLayout { } public void setLockLevel(boolean plus, int level) { - textView.setRightDrawable(new PeerColorActivity.LevelLock(getContext(), plus, level, resourcesProvider)); - textView.setDrawablePadding(dp(6)); + if (level <= 0) { + textView.setRightDrawable(null); + } else { + textView.setRightDrawable(new PeerColorActivity.LevelLock(getContext(), plus, level, resourcesProvider)); + textView.setDrawablePadding(dp(6)); + } } public void setTextAndIcon(CharSequence text, int resId, boolean divider) { @@ -382,6 +386,10 @@ public class TextCell extends FrameLayout { } } + public void setValue(String value, boolean animated) { + valueTextView.setText(TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); + } + public void setTextAndValueAndColorfulIcon(String text, CharSequence value, boolean animated, int resId, int color, boolean divider) { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); 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 46dca248e..959f6dc62 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java @@ -1424,6 +1424,10 @@ public abstract class TextSelectionHelper= charSequence.length() - 1) { @@ -3304,4 +3308,8 @@ public abstract class TextSelectionHelper oldItems = new ArrayList<>(items); items.clear(); @@ -420,7 +423,7 @@ public class ChannelBoostLayout extends FrameLayout { } else { items.add(new ItemInternal(EMPTY_VIEW_8DP, false)); } - items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString("BoostersInfoDescription", R.string.BoostersInfoDescription))); + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString(isChannel() ? R.string.BoostersInfoDescription : R.string.BoostersInfoGroupDescription))); } } else { if (gifts.isEmpty()) { @@ -435,16 +438,16 @@ public class ChannelBoostLayout extends FrameLayout { } else { items.add(new ItemInternal(EMPTY_VIEW_8DP, false)); } - items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString("BoostersInfoDescription", R.string.BoostersInfoDescription))); + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString(isChannel() ? R.string.BoostersInfoDescription : R.string.BoostersInfoGroupDescription))); } } items.add(new ItemInternal(HEADER_VIEW_TYPE, LocaleController.getString("LinkForBoosting", R.string.LinkForBoosting))); items.add(new ItemInternal(LINK_VIEW_TYPE, boostsStatus.boost_url)); - if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable && ChatObject.hasAdminRights(currentChat) && ChatObject.canPost(currentChat)) { - items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString("BoostingShareThisLink", R.string.BoostingShareThisLink))); + if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable && ChatObject.hasAdminRights(currentChat)) { + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString(isChannel() ? R.string.BoostingShareThisLink : R.string.BoostingShareThisLinkGroup))); items.add(new ItemInternal(SHOW_BOOST_BY_GIFTS, true)); - items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString("BoostingGetMoreBoosts", R.string.BoostingGetMoreBoosts))); + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString(isChannel() ? R.string.BoostingGetMoreBoosts : R.string.BoostingGetMoreBoostsGroup))); } } if (animated) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java index c255fb169..47fb2d037 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java @@ -2,6 +2,7 @@ package org.telegram.ui; import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.AndroidUtilities.dpf2; +import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -11,6 +12,7 @@ import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; @@ -22,21 +24,22 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.Build; -import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.util.SparseIntArray; +import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; @@ -54,7 +57,6 @@ import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; -import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.ResultCallback; @@ -75,6 +77,7 @@ import org.telegram.ui.Cells.ThemePreviewMessagesCell; import org.telegram.ui.Cells.ThemesHorizontalListCell; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.ChatThemeBottomSheet; @@ -97,11 +100,12 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -public class ChannelColorActivity extends BaseFragment { +public class ChannelColorActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { public final long dialogId; public int currentLevel; public TL_stories.TL_premium_boostsStatus boostsStatus; + protected boolean isGroup; public int currentReplyColor, selectedReplyColor; public long currentReplyEmoji, selectedReplyEmoji; @@ -119,7 +123,7 @@ public class ChannelColorActivity extends BaseFragment { MessagesController.PeerColors peerColors = getMessagesController().peerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(selectedReplyColor); if (peerColor != null) { - lvl = Math.max(lvl, peerColor.lvl); + lvl = Math.max(lvl, peerColor.getLvl(isGroup)); } } if (currentReplyEmoji != selectedReplyEmoji) { @@ -129,25 +133,45 @@ public class ChannelColorActivity extends BaseFragment { MessagesController.PeerColors peerColors = getMessagesController().profilePeerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(selectedProfileColor); if (peerColor != null) { - lvl = Math.max(lvl, peerColor.lvl); + lvl = Math.max(lvl, peerColor.getLvl(isGroup)); } } if (currentProfileEmoji != selectedProfileEmoji) { - lvl = Math.max(lvl, getMessagesController().channelProfileIconLevelMin); + lvl = Math.max(lvl, getProfileIconLevelMin()); } if (!DialogObject.emojiStatusesEqual(currentStatusEmoji, selectedStatusEmoji)) { - lvl = Math.max(lvl, getMessagesController().channelEmojiStatusLevelMin); + lvl = Math.max(lvl, getEmojiStatusLevelMin()); } if (!ChatThemeController.wallpaperEquals(currentWallpaper, selectedWallpaper)) { if (!TextUtils.isEmpty(ChatThemeController.getWallpaperEmoticon(selectedWallpaper))) { - lvl = Math.max(lvl, getMessagesController().channelWallpaperLevelMin); + lvl = Math.max(lvl, getWallpaperLevelMin()); } else { - lvl = Math.max(lvl, getMessagesController().channelCustomWallpaperLevelMin); + lvl = Math.max(lvl, getCustomWallpaperLevelMin()); } } return lvl; } + protected int getProfileIconLevelMin() { + return getMessagesController().channelProfileIconLevelMin; + } + + protected int getCustomWallpaperLevelMin() { + return getMessagesController().channelCustomWallpaperLevelMin; + } + + protected int getWallpaperLevelMin() { + return getMessagesController().channelWallpaperLevelMin; + } + + protected int getEmojiStatusLevelMin() { + return getMessagesController().channelEmojiStatusLevelMin; + } + + protected int getEmojiStickersLevelMin() { + return 0; + } + private SpannableStringBuilder lock; public void updateButton(boolean animated) { if (boostsStatus == null) { @@ -190,6 +214,20 @@ public class ChannelColorActivity extends BaseFragment { if (drawableKey.equals(Theme.key_drawable_msgInSelected)) { return msgInDrawableSelected; } + if (drawableKey.equals(Theme.key_drawable_msgOut)) { + return msgOutDrawable; + } + if (drawableKey.equals(Theme.key_drawable_msgOutSelected)) { + return msgOutDrawableSelected; + } + if (drawableKey.equals(Theme.key_drawable_msgOutCheckRead)) { + msgOutCheckReadDrawable.setColorFilter(getColor(Theme.key_chat_outSentCheckRead), PorterDuff.Mode.MULTIPLY); + return msgOutCheckReadDrawable; + } + if (drawableKey.equals(Theme.key_drawable_msgOutHalfCheck)) { + msgOutHalfCheckDrawable.setColorFilter(getColor(Theme.key_chat_outSentCheckRead), PorterDuff.Mode.MULTIPLY); + return msgOutHalfCheckDrawable; + } if (parentResourcesProvider != null) { return parentResourcesProvider.getDrawable(drawableKey); } @@ -219,9 +257,18 @@ public class ChannelColorActivity extends BaseFragment { @Override public boolean onFragmentCreate() { getMediaDataController().loadRestrictedStatusEmojis(); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.boostByChannelCreated); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatWasBoostedByUser); return super.onFragmentCreate(); } + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.boostByChannelCreated); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatWasBoostedByUser); + } + public ChannelColorActivity(long dialogId) { super(); this.dialogId = dialogId; @@ -247,6 +294,8 @@ public class ChannelColorActivity extends BaseFragment { resourceProvider = new ThemeDelegate(); msgInDrawable = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, false, resourceProvider); msgInDrawableSelected = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, true, resourceProvider); + msgOutDrawable = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, true, false, resourceProvider); + msgOutDrawableSelected = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, true, true, resourceProvider); } @Override @@ -258,10 +307,14 @@ public class ChannelColorActivity extends BaseFragment { private RLottieDrawable sunDrawable; private ActionBarMenuItem dayNightItem; - private RecyclerListView listView; - private Adapter adapter; - private FrameLayout buttonContainer; - private ButtonWithCounterView button; + protected RecyclerListView listView; + protected Adapter adapter; + protected FrameLayout buttonContainer; + protected ButtonWithCounterView button; + + protected void createListView() { + listView = new RecyclerListView(getContext(), resourceProvider); + } @Override public View createView(Context context) { @@ -318,7 +371,7 @@ public class ChannelColorActivity extends BaseFragment { FrameLayout contentView = new FrameLayout(context); updateRows(); - listView = new RecyclerListView(context, resourceProvider); + createListView(); listView.setAdapter(adapter = new Adapter()); listView.setLayoutManager(new LinearLayoutManager(context)); listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); @@ -333,6 +386,20 @@ public class ChannelColorActivity extends BaseFragment { } else if (position == statusEmojiRow) { selectedEmojiId = DialogObject.getEmojiStatusDocumentId(selectedStatusEmoji); } + if (position == packEmojiRow) { + final int requiredLvl = getEmojiStickersLevelMin(); + if (boostsStatus != null && boostsStatus.level < requiredLvl) { + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK, currentAccount, getResourceProvider()); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + showDialog(limitReachedBottomSheet); + return; + } + GroupStickersActivity fragment = new GroupStickersActivity(-dialogId, true); + fragment.setInfo(chatFull); + presentFragment(fragment); + return; + } showSelectStatusDialog((EmojiCell) view, selectedEmojiId, position == statusEmojiRow, (documentId, until) -> { if (position == replyEmojiRow) { selectedReplyEmoji = documentId; @@ -365,18 +432,33 @@ public class ChannelColorActivity extends BaseFragment { updateButton(true); updateRows(); } else if (position == wallpaperRow) { - ChannelWallpaperActivity activity = new ChannelWallpaperActivity(dialogId, boostsStatus); - activity.setResourceProvider(resourceProvider); - activity.setSelectedWallpaper(selectedWallpaper, galleryWallpaper); - activity.setOnSelectedWallpaperChange((currentWallpaper, selectedWallpaper, galleryWallpaper) -> { - this.currentWallpaper = currentWallpaper; - this.selectedWallpaper = selectedWallpaper; - this.galleryWallpaper = galleryWallpaper; - + ChatThemeBottomSheet.openGalleryForBackground(getParentActivity(), this, dialogId, resourceProvider, wallpaper -> { + this.currentWallpaper = wallpaper; + this.selectedWallpaper = wallpaper; + this.galleryWallpaper = wallpaper; updateButton(false); updateMessagesPreview(false); - }); - presentFragment(activity); + AndroidUtilities.runOnUIThread(() -> BulletinFactory.of(this).createSimpleBulletin(R.raw.done, LocaleController.getString(R.string.ChannelWallpaperUpdated)).show(), 350); + }, new ThemePreviewActivity.DayNightSwitchDelegate() { + @Override + public boolean isDark() { + return ChannelColorActivity.this.resourceProvider != null ? ChannelColorActivity.this.resourceProvider.isDark() : Theme.isCurrentThemeDark(); + } + + @Override + public void switchDayNight(boolean animated) { + if (resourceProvider instanceof ChannelColorActivity.ThemeDelegate) { + ((ChannelColorActivity.ThemeDelegate) resourceProvider).toggle(); + } + setForceDark(isDark(), false); + updateColors(); + } + + @Override + public boolean supportsAnimation() { + return false; + } + }, boostsStatus); } }); DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); @@ -396,6 +478,12 @@ public class ChannelColorActivity extends BaseFragment { buttonContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 10, 10, 10, 10)); contentView.addView(buttonContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 68, Gravity.BOTTOM)); + Bulletin.addDelegate(this, new Bulletin.Delegate() { + @Override + public int getBottomOffset(int tag) { + return buttonContainer.getMeasuredHeight(); + } + }); return fragmentView = contentView; } @@ -623,26 +711,26 @@ public class ChannelColorActivity extends BaseFragment { if (currentReplyColor != selectedReplyColor) { MessagesController.PeerColors peerColors = getMessagesController().peerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(selectedReplyColor); - if (peerColor != null && peerColor.lvl > currentLevel) { + if (peerColor != null && peerColor.getLvl(isGroup) > currentLevel) { type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_COLOR; - lvl = peerColor.lvl; + lvl = peerColor.getLvl(isGroup); } } if (currentProfileColor != selectedProfileColor) { MessagesController.PeerColors peerColors = getMessagesController().profilePeerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(selectedProfileColor); - if (peerColor != null && peerColor.lvl > currentLevel) { + if (peerColor != null && peerColor.getLvl(isGroup) > currentLevel) { type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_PROFILE_COLOR; - lvl = peerColor.lvl; + lvl = peerColor.getLvl(isGroup); } } if (currentReplyEmoji != selectedReplyEmoji && getMessagesController().channelBgIconLevelMin > currentLevel) { type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_REPLY_ICON; } - if (currentProfileEmoji != selectedProfileEmoji && getMessagesController().channelProfileIconLevelMin > currentLevel) { + if (currentProfileEmoji != selectedProfileEmoji && getProfileIconLevelMin() > currentLevel) { type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_PROFILE_ICON; } - if (!DialogObject.emojiStatusesEqual(currentStatusEmoji, selectedStatusEmoji) && getMessagesController().channelEmojiStatusLevelMin > currentLevel) { + if (!DialogObject.emojiStatusesEqual(currentStatusEmoji, selectedStatusEmoji) && getEmojiStatusLevelMin() > currentLevel) { type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_EMOJI_STATUS; } if (!ChatThemeController.wallpaperEquals(currentWallpaper, selectedWallpaper)) { @@ -653,6 +741,7 @@ public class ChannelColorActivity extends BaseFragment { } } final int level = lvl; + if (getContext() == null || getParentActivity() == null) return; LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), type, currentAccount, getResourceProvider()) { @Override protected int channelColorLevelMin() { @@ -665,16 +754,7 @@ public class ChannelColorActivity extends BaseFragment { TLRPC.Chat channel = getMessagesController().getChat(-dialogId); if (channel != null) { limitReachedBottomSheet.showStatisticButtonInLink(() -> { - Bundle args = new Bundle(); - args.putLong("chat_id", -dialogId); - args.putBoolean("is_megagroup", channel.megagroup); - args.putBoolean("start_from_boosts", true); - TLRPC.ChatFull chatInfo = getMessagesController().getChatFull(-dialogId); - if (chatInfo == null || !chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - } - StatisticActivity fragment = new StatisticActivity(args); - presentFragment(fragment); + presentFragment(StatisticActivity.create(channel)); }); } showDialog(limitReachedBottomSheet); @@ -714,6 +794,7 @@ public class ChannelColorActivity extends BaseFragment { final int popupHeight = (int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f); final int popupWidth = (int) Math.min(dp(340 - 16), AndroidUtilities.displaySize.x * .95f); if (cell != null) { + cell.imageDrawable.removeOldDrawable(); scrimDrawable = cell.imageDrawable; scrimDrawableParent = cell; if (cell.imageDrawable != null) { @@ -775,29 +856,32 @@ public class ChannelColorActivity extends BaseFragment { private static final int VIEW_TYPE_BUTTON_EMOJI = 6; private static final int VIEW_TYPE_SHADOW = 7; - private int rowsCount = 0; + protected int rowsCount = 0; - private int messagesPreviewRow; - private int replyColorListRow; - private int replyEmojiRow; - private int replyHintRow; + protected int messagesPreviewRow; + protected int replyColorListRow; + protected int replyEmojiRow; + protected int replyHintRow; - private int wallpaperThemesRow; - private int wallpaperRow; - private int wallpaperHintRow; + protected int wallpaperThemesRow; + protected int wallpaperRow; + protected int wallpaperHintRow; - private int profilePreviewRow; - private int profileColorGridRow; - private int profileEmojiRow; - private int profileHintRow; + protected int profilePreviewRow; + protected int profileColorGridRow; + protected int profileEmojiRow; + protected int profileHintRow; - private int removeProfileColorRow; - private int removeProfileColorShadowRow; + protected int removeProfileColorRow; + protected int removeProfileColorShadowRow; - private int statusEmojiRow; - private int statusHintRow; + protected int statusEmojiRow; + protected int statusHintRow; - private void updateRows() { + protected int packEmojiRow; + protected int packEmojiHintRow; + + protected void updateRows() { rowsCount = 0; messagesPreviewRow = rowsCount++; replyColorListRow = rowsCount++; @@ -829,28 +913,69 @@ public class ChannelColorActivity extends BaseFragment { statusHintRow = rowsCount++; } - private class Adapter extends RecyclerListView.SelectionAdapter { + protected int getProfileInfoStrRes() { + return R.string.ChannelProfileInfo; + } + + protected int getEmojiStatusStrRes() { + return R.string.ChannelEmojiStatus; + } + + protected int getEmojiPackStrRes() { + return 0; + } + + protected int getEmojiPackInfoStrRes() { + return 0; + } + + protected int getEmojiStatusInfoStrRes() { + return R.string.ChannelEmojiStatusInfo; + } + + protected int getWallpaperStrRes() { + return R.string.ChannelWallpaper; + } + + protected int getWallpaper2InfoStrRes() { + return R.string.ChannelWallpaper2Info; + } + + protected int getMessagePreviewType() { + return ThemePreviewMessagesCell.TYPE_PEER_COLOR; + } + + private String getThemeChooserEmoticon() { + String emoticon = ChatThemeController.getWallpaperEmoticon(selectedWallpaper); + if (emoticon == null && selectedWallpaper == null && galleryWallpaper != null) { + return EmojiThemes.REMOVED_EMOJI; + } + return emoticon; + } + + protected class Adapter extends RecyclerListView.SelectionAdapter { @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; if (viewType == VIEW_TYPE_MESSAGE_PREVIEW) { - ThemePreviewMessagesCell messagesCell = new ThemePreviewMessagesCell(getContext(), parentLayout, ThemePreviewMessagesCell.TYPE_PEER_COLOR, dialogId, resourceProvider); + ThemePreviewMessagesCell messagesCell = new ThemePreviewMessagesCell(getContext(), parentLayout, getMessagePreviewType(), dialogId, resourceProvider); messagesCell.customAnimation = true; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - messagesCell.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - } + messagesCell.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); messagesCell.fragment = ChannelColorActivity.this; messagesCell.setOverrideBackground(backgroundDrawable = PreviewView.getBackgroundDrawable(backgroundDrawable, currentAccount, selectedWallpaper, isDark)); view = messagesCell; } else if (viewType == VIEW_TYPE_WALLPAPER_THEMES) { ThemeChooser themesWallpaper = new ThemeChooser(getContext(), false, currentAccount, resourceProvider); - themesWallpaper.setSelectedEmoticon(ChatThemeController.getWallpaperEmoticon(selectedWallpaper), false); + themesWallpaper.setWithRemovedStub(true); + themesWallpaper.setSelectedEmoticon(getThemeChooserEmoticon(), false); themesWallpaper.setGalleryWallpaper(galleryWallpaper); themesWallpaper.setOnEmoticonSelected(emoticon -> { if (emoticon == null) { selectedWallpaper = galleryWallpaper; + } else if (emoticon.equals(EmojiThemes.REMOVED_EMOJI)) { + selectedWallpaper = null; } else { selectedWallpaper = new TLRPC.TL_wallPaperNoFile(); selectedWallpaper.id = 0; @@ -922,9 +1047,11 @@ public class ChannelColorActivity extends BaseFragment { if (position == removeProfileColorRow) { textCell.setText(LocaleController.getString(R.string.ChannelProfileColorReset), false); } else { - textCell.setText(LocaleController.getString(R.string.ChannelWallpaper), false); - if (currentLevel < getMessagesController().channelWallpaperLevelMin) { - textCell.setLockLevel(false, getMessagesController().channelWallpaperLevelMin); + textCell.setText(LocaleController.getString(getWallpaperStrRes()), false); + if (currentLevel < getCustomWallpaperLevelMin()) { + textCell.setLockLevel(false, getCustomWallpaperLevelMin()); + } else { + textCell.setLockLevel(false, 0); } } break; @@ -936,23 +1063,43 @@ public class ChannelColorActivity extends BaseFragment { emojiCell.setText(LocaleController.getString(R.string.ChannelReplyLogo)); if (currentLevel < getMessagesController().channelBgIconLevelMin) { emojiCell.setLockLevel(getMessagesController().channelBgIconLevelMin); + } else { + emojiCell.setLockLevel(0); } emojiCell.setEmoji(selectedReplyEmoji, false); } else if (position == profileEmojiRow) { emojiCell.setAdaptiveEmojiColor(currentAccount, selectedProfileColor, false); emojiCell.setText(LocaleController.getString(R.string.ChannelProfileLogo)); emojiCell.setDivider(removeProfileColorRow >= 0); - if (currentLevel < getMessagesController().channelProfileIconLevelMin) { - emojiCell.setLockLevel(getMessagesController().channelProfileIconLevelMin); + if (currentLevel < getProfileIconLevelMin()) { + emojiCell.setLockLevel(getProfileIconLevelMin()); + } else { + emojiCell.setLockLevel(0); } emojiCell.setEmoji(selectedProfileEmoji, false); } else if (position == statusEmojiRow) { emojiCell.setAdaptiveEmojiColor(currentAccount, selectedProfileColor, false); - emojiCell.setText(LocaleController.getString(R.string.ChannelEmojiStatus)); - if (currentLevel < getMessagesController().channelEmojiStatusLevelMin) { - emojiCell.setLockLevel(getMessagesController().channelEmojiStatusLevelMin); + emojiCell.setText(LocaleController.getString(getEmojiStatusStrRes())); + if (currentLevel < getEmojiStatusLevelMin()) { + emojiCell.setLockLevel(getEmojiStatusLevelMin()); + } else { + emojiCell.setLockLevel(0); } emojiCell.setEmoji(DialogObject.getEmojiStatusDocumentId(selectedStatusEmoji), false); + } else if (position == packEmojiRow) { + emojiCell.setAdaptiveEmojiColor(currentAccount, selectedProfileColor, false); + emojiCell.setText(LocaleController.getString(getEmojiPackStrRes())); + if (currentLevel < getEmojiStickersLevelMin()) { + emojiCell.setLockLevel(getEmojiStickersLevelMin()); + } else { + emojiCell.setLockLevel(0); + } + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null && chatFull.emojiset != null) { + emojiCell.setEmoji(getEmojiSetThumbId(chatFull.emojiset), false); + } else { + emojiCell.setEmoji(0, false); + } } break; case VIEW_TYPE_SHADOW: @@ -961,11 +1108,13 @@ public class ChannelColorActivity extends BaseFragment { if (position == replyHintRow) { infoCell.setText(LocaleController.getString(R.string.ChannelReplyInfo)); } else if (position == wallpaperHintRow) { - infoCell.setText(LocaleController.getString(R.string.ChannelWallpaper2Info)); + infoCell.setText(LocaleController.getString(getWallpaper2InfoStrRes())); } else if (position == profileHintRow) { - infoCell.setText(LocaleController.getString(R.string.ChannelProfileInfo)); + infoCell.setText(LocaleController.getString(getProfileInfoStrRes())); } else if (position == statusHintRow) { - infoCell.setText(LocaleController.getString(R.string.ChannelEmojiStatusInfo)); + infoCell.setText(LocaleController.getString(getEmojiStatusInfoStrRes())); + } else if (position == packEmojiHintRow) { + infoCell.setText(LocaleController.getString(getEmojiPackInfoStrRes())); } else if (position == removeProfileColorShadowRow) { infoCell.setText(""); infoCell.setFixedSize(12); @@ -1019,7 +1168,7 @@ public class ChannelColorActivity extends BaseFragment { return VIEW_TYPE_COLOR_REPLY_GRID; } else if (position == profileColorGridRow) { return VIEW_TYPE_COLOR_PROFILE_GRID; - } else if (position == replyEmojiRow || position == profileEmojiRow || position == statusEmojiRow) { + } else if (position == replyEmojiRow || position == profileEmojiRow || position == statusEmojiRow || position == packEmojiRow) { return VIEW_TYPE_BUTTON_EMOJI; } else if (position == wallpaperRow || position == removeProfileColorRow) { return VIEW_TYPE_BUTTON; @@ -1073,7 +1222,7 @@ public class ChannelColorActivity extends BaseFragment { ((EmojiCell) emojiPicker).setEmoji(selectedReplyEmoji, animated); } if (wallpaperPicker instanceof ThemeChooser) { - ((ThemeChooser) wallpaperPicker).setSelectedEmoticon(ChatThemeController.getWallpaperEmoticon(selectedWallpaper), animated); + ((ThemeChooser) wallpaperPicker).setSelectedEmoticon(getThemeChooserEmoticon(), animated); ((ThemeChooser) wallpaperPicker).setGalleryWallpaper(galleryWallpaper); } } @@ -1083,6 +1232,7 @@ public class ChannelColorActivity extends BaseFragment { View colorPicker = findChildAt(profileColorGridRow); View emojiPicker = findChildAt(profileEmojiRow); View emojiStatusPicker = findChildAt(statusEmojiRow); + View packEmojiPicker = findChildAt(packEmojiRow); if (profilePreview instanceof ProfilePreview) { ((ProfilePreview) profilePreview).setColor(selectedProfileColor, animated); @@ -1103,10 +1253,33 @@ public class ChannelColorActivity extends BaseFragment { ((EmojiCell) emojiStatusPicker).setAdaptiveEmojiColor(currentAccount, selectedProfileColor, false); ((EmojiCell) emojiStatusPicker).setEmoji(DialogObject.getEmojiStatusDocumentId(selectedStatusEmoji), animated); } + if (packEmojiPicker instanceof EmojiCell) { + ((EmojiCell) packEmojiPicker).setAdaptiveEmojiColor(currentAccount, selectedProfileColor, false); + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null && chatFull.emojiset != null) { + ((EmojiCell) packEmojiPicker).setEmoji(getEmojiSetThumbId(chatFull.emojiset), false); + } else { + ((EmojiCell) packEmojiPicker).setEmoji(0, false); + } + } updateRows(); } + private long getEmojiSetThumbId(TLRPC.StickerSet emojiSet) { + if (emojiSet == null) { + return 0; + } + long thumbDocumentId = emojiSet.thumb_document_id; + if (thumbDocumentId == 0) { + TLRPC.TL_messages_stickerSet stickerSet = getMediaDataController().getGroupStickerSetById(emojiSet); + if (!stickerSet.documents.isEmpty()) { + thumbDocumentId = stickerSet.documents.get(0).id; + } + } + return thumbDocumentId; + } + public View findChildAt(int position) { for (int i = 0; i < listView.getChildCount(); ++i) { View child = listView.getChildAt(i); @@ -1117,23 +1290,74 @@ public class ChannelColorActivity extends BaseFragment { return null; } - private class ProfilePreview extends FrameLayout { + protected boolean needBoostInfoSection() { + return false; + } + + protected class ProfilePreview extends FrameLayout { public final PeerColorActivity.ColoredActionBar backgroundView; public final PeerColorActivity.ProfilePreview profileView; + public SimpleTextView title; + public TextView textInfo1; + public TextView textInfo2; + public LinearLayout infoLayout; + + public void setTitleSize() { + boolean isLandScape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + title.setTextSize(!AndroidUtilities.isTablet() && isLandScape ? 18 : 20); + title.setTranslationY(dp(AndroidUtilities.isTablet() ? -2 : (isLandScape ? 4 : 0))); + } + public ProfilePreview(Context context) { super(context); backgroundView = new PeerColorActivity.ColoredActionBar(getContext(), resourceProvider); backgroundView.setProgressToGradient(1f); backgroundView.ignoreMeasure = true; - addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 134, Gravity.FILL)); - profileView = new PeerColorActivity.ProfilePreview(getContext(), currentAccount, dialogId, resourceProvider); - addView(profileView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 104, Gravity.BOTTOM)); + addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, isGroup ? 194 : 134, Gravity.FILL)); + profileView = new PeerColorActivity.ProfilePreview(getContext(), currentAccount, dialogId, resourceProvider){ + @Override + public void setColor(int colorId, boolean animated) { + super.setColor(colorId, animated); + if (textInfo1 != null) { + textInfo1.setTextColor(profileView.subtitleView.getTextColor()); + } + } + }; + addView(profileView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 104, Gravity.BOTTOM, 0, 0, 0, isGroup ? 24: 0)); + + if (needBoostInfoSection()) { + title = new SimpleTextView(getContext()); + title.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); + title.setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle)); + title.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + title.setText(LocaleController.getString(R.string.ChangeChannelNameColor2)); + title.setAlpha(0f); + setTitleSize(); + addView(title, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM,72,0,0,16)); + infoLayout = new LinearLayout(context); + infoLayout.setOrientation(LinearLayout.HORIZONTAL); + infoLayout.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.multAlpha(Color.BLACK, 0.15f), Theme.multAlpha(Color.BLACK, 0.35f))); + infoLayout.setGravity(Gravity.CENTER); + infoLayout.setPadding(dp(4), dp(4), dp(4), dp(4)); + textInfo1 = new TextView(context); + textInfo1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + textInfo1.setTextColor(profileView.subtitleView.getTextColor()); + textInfo2 = new TextView(context); + textInfo2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + textInfo2.setTextColor(Color.WHITE); + textInfo1.setText(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingGroupBoostCount", boostsStatus != null ? boostsStatus.boosts : 0))); + textInfo2.setText(LocaleController.getString(R.string.BoostingGroupBoostWhatAreBoosts)); + infoLayout.addView(textInfo1); + infoLayout.addView(textInfo2, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 3,0,0,0)); + addView(infoLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + } } public void setColor(int colorId, boolean animated) { profileView.setColor(colorId, animated); backgroundView.setColor(currentAccount, colorId, animated); } + public void setEmoji(long emojiId, boolean animated) { profileView.setEmoji(emojiId, animated); } @@ -1282,6 +1506,7 @@ public class ChannelColorActivity extends BaseFragment { public final List items = new ArrayList<>(); private final RecyclerListView listView; private FlickerLoadingView progressView; + private boolean withRemovedStub; private final RecyclerListView.SelectionAdapter adapter; @@ -1290,6 +1515,10 @@ public class ChannelColorActivity extends BaseFragment { private Utilities.Callback onEmoticonSelected; private String currentEmoticon; + public void setWithRemovedStub(boolean withRemovedStub) { + this.withRemovedStub = withRemovedStub; + } + public void setOnEmoticonSelected(Utilities.Callback callback) { onEmoticonSelected = callback; } @@ -1316,9 +1545,13 @@ public class ChannelColorActivity extends BaseFragment { this.fallbackWallpaper = wallPaper; AndroidUtilities.forEachViews(listView, child -> { if (child instanceof ThemeSmallPreviewView) { - ((ThemeSmallPreviewView) child).setFallbackWallpaper(fallbackWallpaper); + ((ThemeSmallPreviewView) child).setFallbackWallpaper(((ThemeSmallPreviewView) child).chatThemeItem.chatTheme.showAsRemovedStub ? null : fallbackWallpaper); } }); + if (fallbackWallpaper != null && (items.isEmpty() || items.get(0).chatTheme.showAsDefaultStub) && withRemovedStub) { + items.add(0, new ChatThemeBottomSheet.ChatThemeItem(EmojiThemes.createChatThemesRemoved(currentAccount))); + adapter.notifyDataSetChanged(); + } } private void updateSelected() { @@ -1415,7 +1648,7 @@ public class ChannelColorActivity extends BaseFragment { view.setBackgroundColor(Theme.getColor(Theme.key_dialogBackgroundGray)); view.setItem(newItem, false); view.setSelected(newItem.isSelected, false); - view.setFallbackWallpaper(fallbackWallpaper); + view.setFallbackWallpaper(newItem.chatTheme.showAsRemovedStub ? null : fallbackWallpaper); } @Override @@ -1426,7 +1659,7 @@ public class ChannelColorActivity extends BaseFragment { } ChatThemeBottomSheet.ChatThemeItem newItem = items.get(position); ((ThemeSmallPreviewView) holder.itemView).setSelected(newItem.isSelected, false); - ((ThemeSmallPreviewView) holder.itemView).setFallbackWallpaper(fallbackWallpaper); + ((ThemeSmallPreviewView) holder.itemView).setFallbackWallpaper(newItem.chatTheme.showAsRemovedStub ? null : fallbackWallpaper); } @Override @@ -1501,6 +1734,10 @@ public class ChannelColorActivity extends BaseFragment { ChatThemeBottomSheet.ChatThemeItem noThemeItem = new ChatThemeBottomSheet.ChatThemeItem(result.get(0)); items.add(0, noThemeItem); + if (fallbackWallpaper != null && withRemovedStub) { + items.add(0, new ChatThemeBottomSheet.ChatThemeItem(EmojiThemes.createChatThemesRemoved(currentAccount))); + } + final boolean isDark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); for (int i = 1; i < result.size(); ++i) { EmojiThemes chatTheme = result.get(i); @@ -1711,8 +1948,8 @@ public class ChannelColorActivity extends BaseFragment { ((ChatEditActivity) bulletinFragment).updateColorCell(); } BulletinFactory.of(bulletinFragment).createSimpleBulletin( - R.raw.contact_check, - LocaleController.getString(R.string.ChannelAppearanceUpdated) + R.raw.contact_check, + LocaleController.getString(isGroup ? R.string.GroupAppearanceUpdated : R.string.ChannelAppearanceUpdated) ).show(); bulletinFragment = null; } @@ -2120,10 +2357,14 @@ public class ChannelColorActivity extends BaseFragment { private Theme.ResourcesProvider parentResourcesProvider; private final SparseIntArray currentColors = new SparseIntArray(); private final Theme.MessageDrawable msgInDrawable, msgInDrawableSelected; + private final Theme.MessageDrawable msgOutDrawable, msgOutDrawableSelected; + private final Drawable msgOutCheckReadDrawable, msgOutHalfCheckDrawable; private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); { dividerPaint.setStrokeWidth(1); dividerPaint.setColor(Theme.getColor(Theme.key_divider, resourceProvider)); + msgOutCheckReadDrawable = ContextCompat.getDrawable(ApplicationLoader.applicationContext, R.drawable.msg_check_s).mutate(); + msgOutHalfCheckDrawable = ContextCompat.getDrawable(ApplicationLoader.applicationContext, R.drawable.msg_halfcheck).mutate(); } public void updateThemeColors() { @@ -2182,4 +2423,33 @@ public class ChannelColorActivity extends BaseFragment { ((ThemePreviewMessagesCell) messagesCellPreview).setOverrideBackground(backgroundDrawable); } } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.chatWasBoostedByUser) { + if (dialogId == (long) args[2]) { + updateBoostsAndLevels((TL_stories.TL_premium_boostsStatus) args[0]); + } + } else if (id == NotificationCenter.boostByChannelCreated) { + boolean isGiveaway = (boolean) args[1]; + if (!isGiveaway) { + getMessagesController().getBoostsController().getBoostsStats(dialogId, this::updateBoostsAndLevels); + } + } + } + + private void updateBoostsAndLevels(TL_stories.TL_premium_boostsStatus boostsStatus) { + if (boostsStatus != null) { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + this.boostsStatus = boostsStatus; + this.currentLevel = boostsStatus.level; + if (chat != null) { + chat.level = currentLevel; + } + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + updateButton(true); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelWallpaperActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelWallpaperActivity.java index 4bda72b24..b4f640812 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelWallpaperActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelWallpaperActivity.java @@ -25,6 +25,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.ChatThemeController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.LocaleController; @@ -55,12 +56,14 @@ public class ChannelWallpaperActivity extends BaseFragment { public TL_stories.TL_premium_boostsStatus boostsStatus; public TLRPC.WallPaper galleryWallpaper; public TLRPC.WallPaper currentWallpaper, selectedWallpaper; + private boolean isChannel; public ChannelWallpaperActivity(long dialogId, TL_stories.TL_premium_boostsStatus boostsStatus) { super(); this.dialogId = dialogId; TLRPC.Chat chat = getMessagesController().getChat(-dialogId); if (chat != null) { + isChannel = ChatObject.isChannelAndNotMegaGroup(chat); currentLevel = chat.level; } this.boostsStatus = boostsStatus; @@ -111,7 +114,7 @@ public class ChannelWallpaperActivity extends BaseFragment { @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); - actionBar.setTitle(LocaleController.getString(R.string.ChannelWallpaper)); + actionBar.setTitle(LocaleController.getString(isChannel ? R.string.ChannelWallpaper : R.string.GroupWallpaper)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -308,7 +311,7 @@ public class ChannelWallpaperActivity extends BaseFragment { ((TextCell) holder.itemView).setTextAndIcon(LocaleController.getString(R.string.ChannelWallpaperRemove), R.drawable.msg_delete, false); ((TextCell) holder.itemView).setColors(Theme.key_text_RedRegular, Theme.key_text_RedRegular); } else if (position == infoRow) { - ((TextInfoPrivacyCell) holder.itemView).setText(LocaleController.getString(R.string.ChannelWallpaperInfo)); + ((TextInfoPrivacyCell) holder.itemView).setText(LocaleController.getString(isChannel ? R.string.ChannelWallpaperInfo : R.string.GroupWallpaperInfo)); ((TextInfoPrivacyCell) holder.itemView).setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); ((TextInfoPrivacyCell) holder.itemView).setForeground(Theme.getThemedDrawableByKey(getContext(), R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow, resourceProvider)); } else if (position == themesRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 6f3000f7d..6222492fe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -71,7 +71,6 @@ 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.Property; import android.util.SparseArray; @@ -107,6 +106,7 @@ import androidx.collection.LongSparseArray; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.core.graphics.ColorUtils; +import androidx.core.graphics.drawable.DrawableCompat; import androidx.dynamicanimation.animation.FloatValueHolder; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; @@ -127,6 +127,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChannelBoostsController; import org.telegram.messenger.ChatMessageSharedResources; import org.telegram.messenger.ChatMessagesMetadataController; import org.telegram.messenger.ChatObject; @@ -203,12 +204,14 @@ import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.MentionCell; import org.telegram.ui.Cells.ShareDialogCell; import org.telegram.ui.Cells.StickerCell; +import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextSelectionHelper; import org.telegram.ui.Components.*; import org.telegram.ui.Components.FloatingDebug.FloatingDebugController; import org.telegram.ui.Components.FloatingDebug.FloatingDebugProvider; import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.Components.Premium.GiftPremiumBottomSheet; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumPreviewBottomSheet; import org.telegram.ui.Components.Premium.boosts.BoostDialogs; @@ -365,12 +368,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private HintView2 savedMessagesHint; private HintView2 savedMessagesSearchHint; private HintView2 savedMessagesTagHint; + private HintView2 groupEmojiPackHint; private int reactionsMentionCount; private FrameLayout reactionsMentiondownButton; private CounterView reactionsMentiondownButtonCounter; private ImageView reactionsMentiondownButtonImage; + private TL_stories.TL_premium_boostsStatus boostsStatus; + private ChannelBoostsController.CanApplyBoost canApplyBoosts; + private BackupImageView replyImageView; private SimpleTextView replyNameTextView; private SimpleTextView replyObjectTextView; @@ -1297,6 +1304,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private final static int auto_delete_timer = 26; private final static int change_colors = 27; private final static int tag_message = 28; + private final static int boost_group = 29; private final static int bot_help = 30; private final static int bot_settings = 31; @@ -1708,6 +1716,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + public boolean checkCanRemoveRestrictionsByBoosts() { + return ChatActivity.this.checkCanRemoveRestrictionsByBoosts(); + } + @Override public void onTextSelectionChanged(int start, int end) { if (editTextItem == null) { @@ -2382,6 +2395,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().addObserver(this, NotificationCenter.messageReceivedByAck); getNotificationCenter().addObserver(this, NotificationCenter.messageSendError); getNotificationCenter().addObserver(this, NotificationCenter.chatInfoDidLoad); + getNotificationCenter().addObserver(this, NotificationCenter.groupRestrictionsUnlockedByBoosts); getNotificationCenter().addObserver(this, NotificationCenter.contactsDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.messagePlayingProgressDidChanged); getNotificationCenter().addObserver(this, NotificationCenter.messagePlayingDidReset); @@ -2404,6 +2418,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().addObserver(this, NotificationCenter.userInfoDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.pinnedInfoDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.topicsDidLoaded); + getNotificationCenter().addObserver(this, NotificationCenter.chatWasBoostedByUser); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didSetNewWallpapper); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didApplyNewTheme); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.goingToPreviewTheme); @@ -2459,7 +2474,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else { getMessagesController().setLastCreatedDialogId(dialog_id, chatMode == MODE_SCHEDULED, true); - if (chatMode == 0) { + if (chatMode == 0 || chatMode == MODE_SAVED) { if (currentEncryptedChat == null) { getMediaDataController().loadBotKeyboard(MessagesStorage.TopicKey.of(dialog_id, getTopicId())); } @@ -2742,6 +2757,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().removeObserver(this, NotificationCenter.messageReceivedByAck); getNotificationCenter().removeObserver(this, NotificationCenter.messageSendError); getNotificationCenter().removeObserver(this, NotificationCenter.chatInfoDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.groupRestrictionsUnlockedByBoosts); getNotificationCenter().removeObserver(this, NotificationCenter.didLoadChatInviter); getNotificationCenter().removeObserver(this, NotificationCenter.groupCallUpdated); getNotificationCenter().removeObserver(this, NotificationCenter.encryptedChatUpdated); @@ -2778,6 +2794,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().removeObserver(this, NotificationCenter.userInfoDidLoad); getNotificationCenter().removeObserver(this, NotificationCenter.pinnedInfoDidLoad); getNotificationCenter().removeObserver(this, NotificationCenter.topicsDidLoaded); + getNotificationCenter().removeObserver(this, NotificationCenter.chatWasBoostedByUser); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewWallpapper); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didApplyNewTheme); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.goingToPreviewTheme); @@ -3183,6 +3200,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } catch (Exception e) { FileLog.e(e); } + } else if (id == boost_group) { + if (ChatObject.hasAdminRights(currentChat)) { + BoostsActivity boostsActivity = new BoostsActivity(dialog_id); + boostsActivity.setBoostsStatus(boostsStatus); + presentFragment(boostsActivity); + } else { + getNotificationCenter().postNotificationName(NotificationCenter.openBoostForUsersDialog, dialog_id); + } } else if (id == report) { AlertsCreator.createReportAlert(getParentActivity(), dialog_id, 0, 0, ChatActivity.this, themeDelegate, null); } else if (id == star) { @@ -3354,7 +3379,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override protected boolean canSearch() { - return searchItem != null && !searching; + return !isInsideContainer && !isInPreviewMode() && !inBubbleMode && searchItem != null && !searching; } @Override @@ -3588,6 +3613,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (searchItem != null) { headerItem.lazilyAddSubItem(search, R.drawable.msg_search, LocaleController.getString(R.string.Search)); } + if (ChatObject.isGroupAndSupportBoost(currentChat) && (getUserConfig().isPremium() || ChatObject.isBoosted(chatInfo) || ChatObject.hasAdminRights(currentChat))) { + RLottieDrawable drawable = new RLottieDrawable(R.raw.boosts, "" + R.raw.boosts, dp(24), dp(24)); + headerItem.lazilyAddSubItem(boost_group, drawable, TextCell.applyNewSpan(LocaleController.getString("BoostingBoostGroupMenu", R.string.BoostingBoostGroupMenu))); + } translateItem = headerItem.lazilyAddSubItem(translate, R.drawable.msg_translate, LocaleController.getString("TranslateMessage", R.string.TranslateMessage)); updateTranslateItemVisibility(); if (currentChat != null && !currentChat.creator && !ChatObject.hasAdminRights(currentChat)) { @@ -5681,6 +5710,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateVisibleRows(); scrollByTouch = false; } else { + if (groupEmojiPackHint != null && groupEmojiPackHint.shown()) { + groupEmojiPackHint.hide(); + } if (searchOtherButton != null && searchOtherButton.getVisibility() == View.VISIBLE && isKeyboardVisible()) { AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); } @@ -7102,7 +7134,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not bottomOverlayText.setEllipsize(TextUtils.TruncateAt.END); bottomOverlayText.setLineSpacing(AndroidUtilities.dp(2), 1); bottomOverlayText.setTextColor(getThemedColor(Theme.key_chat_secretChatStatusText)); - bottomOverlay.addView(bottomOverlayText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 24, 0, 24, 0)); + bottomOverlayText.setPadding(dp(24), 0, dp(24), 0); + bottomOverlay.addView(bottomOverlayText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER, 0, 0, 0, 0)); bottomOverlayChat = new BlurredFrameLayout(context, contentView) { @Override @@ -7707,7 +7740,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not setFilterMessages(filter, false, true); } private void setFilterMessages(boolean filter, boolean ignoreMessageNotFound, boolean animated) { - if (chatAdapter.isFiltered == filter) return; + if (chatAdapter == null || chatAdapter.isFiltered == filter) return; chatAdapter.isFiltered = filter; createEmptyView(true); if (filter) { @@ -10482,7 +10515,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not presentFragment(fragment); } - private void showBottomOverlayProgress(boolean show, boolean animated) { + public void showBottomOverlayProgress(boolean show, boolean animated) { if (show && bottomOverlayProgress.getTag() != null || !show && bottomOverlayProgress.getTag() == null) { return; } @@ -10911,7 +10944,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (inlineReturn != 0) { getMessagesController().sendBotStart(currentUser, value); } else { - botUser = value; + sentBotStart = true; + getMessagesController().sendBotStart(currentUser, botUser = value); updateBottomOverlay(); } } @@ -11240,6 +11274,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (userInfo != null && userInfo.voice_messages_forbidden) { mediaBanTooltip.setText(AndroidUtilities.replaceTags(LocaleController.formatString(chatActivityEnterView.isInVideoMode() ? R.string.VideoMessagesRestrictedByPrivacy : R.string.VoiceMessagesRestrictedByPrivacy, currentUser.first_name))); } else if (!ChatObject.canSendVoice(currentChat) && !ChatObject.canSendRoundVideo(currentChat)) { + if (checkCanRemoveRestrictionsByBoosts()) { + return; + } if (chatActivityEnterView.isInVideoMode()) { mediaBanTooltip.setText(ChatObject.getRestrictedErrorText(currentChat, ChatObject.ACTION_SEND_ROUND)); } else { @@ -15843,6 +15880,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } boolean hideKeyboard = false; + bottomOverlayText.setBackground(null); + bottomOverlayText.setOnClickListener(null); if (chatMode == MODE_SAVED && getSavedDialogId() == UserObject.ANONYMOUS) { bottomOverlayText.setText(LocaleController.getString(R.string.AuthorHiddenDescription)); bottomOverlay.setVisibility(View.VISIBLE); @@ -15859,7 +15898,26 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (currentChat != null && !ChatObject.canSendMessages(currentChat) && !ChatObject.canSendAnyMedia(currentChat) && !currentChat.gigagroup && (!ChatObject.isChannel(currentChat) || currentChat.megagroup)) { if (currentChat.default_banned_rights != null && currentChat.default_banned_rights.send_messages) { - bottomOverlayText.setText(LocaleController.getString("GlobalSendMessageRestricted", R.string.GlobalSendMessageRestricted)); + boolean unlockByBoosts = ChatObject.isPossibleRemoveChatRestrictionsByBoosts(currentChat); + if (unlockByBoosts) { + Drawable drawable = ContextCompat.getDrawable(getContext(), R.drawable.filled_limit_boost).mutate(); + DrawableCompat.setTint(drawable, getThemedColor(Theme.key_featuredStickers_addButton)); + drawable.setBounds(0, 0, dp(14), dp(14)); + CombinedDrawable combinedDrawable = new CombinedDrawable(null, drawable, dp(-6), dp(-6)); + combinedDrawable.setIconSize(dp(14), dp(14)); + combinedDrawable.setCustomSize(dp(14), dp(14)); + + SpannableStringBuilder builder = new SpannableStringBuilder("d " + LocaleController.getString(R.string.BoostingBoostToSendMessages)); + builder.setSpan(new ForegroundColorSpan(getThemedColor(Theme.key_featuredStickers_addButton)), 0, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.setSpan(new ImageSpan(combinedDrawable, ImageSpan.ALIGN_BASELINE), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + bottomOverlayText.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector))); + bottomOverlayText.setText(builder); + bottomOverlayText.setOnClickListener(v -> LimitReachedBottomSheet.openBoostsForRemoveRestrictions(this, boostsStatus, canApplyBoosts, dialog_id, false)); + } else { + bottomOverlayText.setText(LocaleController.getString("GlobalSendMessageRestricted", R.string.GlobalSendMessageRestricted)); + } } else if (AndroidUtilities.isBannedForever(currentChat.banned_rights)) { bottomOverlayText.setText(LocaleController.getString("SendMessageRestrictedForever", R.string.SendMessageRestrictedForever)); } else { @@ -17268,6 +17326,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } boolean visible = (!endReached[0] || mergeDialogId != 0 && !endReached[1] || messages.isEmpty()) && loading && maxTop > chatListViewPaddingTop && (messages.isEmpty() ? animateProgressViewTo : childHeight != 0); + if (visible && inTransitionAnimation && emptyViewContainer != null && emptyViewContainer.getVisibility() == View.VISIBLE && emptyViewContainer.getChildCount() > 0) { + return false; + } if (!visible && startMessageAppearTransitionMs == 0) { checkDispatchHideSkeletons(fragmentBeginToShow); } @@ -18986,9 +19047,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } updateInfoTopView(openAnimationStartTime != 0 && SystemClock.elapsedRealtime() >= openAnimationStartTime + 150); } + } else if (id == NotificationCenter.groupRestrictionsUnlockedByBoosts) { + if (chatActivityEnterView != null) { + chatActivityEnterView.checkChannelRights(); + chatActivityEnterView.setSlowModeTimer(0); + } + dismissCurrentDialog(); + updateSecretStatus(); } else if (id == NotificationCenter.chatInfoDidLoad) { TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; if (currentChat != null && chatFull.id == currentChat.id) { + checkGroupEmojiPackHint(); if (chatFull instanceof TLRPC.TL_channelFull) { if (currentChat.megagroup) { int lastDate = 0; @@ -19008,6 +19077,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showGigagroupConvertAlert(); long prevLinkedChatId = chatInfo != null ? chatInfo.linked_chat_id : 0; chatInfo = chatFull; + if (ChatObject.isBoostSupported(currentChat)) { + getMessagesController().getBoostsController().getBoostsStats(dialog_id, boostsStatus -> { + if (boostsStatus == null) { + return; + } + this.boostsStatus = boostsStatus; + getMessagesController().getBoostsController().userCanBoostChannel(dialog_id, boostsStatus, canApplyBoost -> this.canApplyBoosts = canApplyBoost); + }); + } groupCall = getMessagesController().getGroupCall(currentChat.id, true); if (ChatObject.isChannel(currentChat) && currentChat.megagroup && fragmentContextView != null) { fragmentContextView.checkCall(openAnimationStartTime == 0 || SystemClock.elapsedRealtime() < openAnimationStartTime + 150); @@ -19040,7 +19118,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (chatActivityEnterView != null) { chatActivityEnterView.setChatInfo(chatInfo); + chatActivityEnterView.checkChannelRights(); } + updateSecretStatus(); if (mentionContainer != null && mentionContainer.getAdapter() != null) { mentionContainer.getAdapter().setChatInfo(chatInfo); } @@ -19743,7 +19823,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messagePreviewParams != null) { messagePreviewParams.checkEdits(messageObjects); } - if (did != dialog_id && did != mergeDialogId || chatMode == MODE_SAVED) { + if (did != dialog_id && did != mergeDialogId) { return; } int loadIndex = did == dialog_id ? 0 : 1; @@ -20542,6 +20622,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } updateReactionsMentionButton(true); } + } else if (id == NotificationCenter.chatWasBoostedByUser) { + if (dialog_id == (long) args[2]) { + boostsStatus = (TL_stories.TL_premium_boostsStatus) args[0]; + canApplyBoosts = (ChannelBoostsController.CanApplyBoost) args[1]; + } } else if (id == NotificationCenter.topicsDidLoaded) { if (isTopic) { if (getParentActivity() == null) { @@ -21386,7 +21471,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (newChat != null) { currentChat = newChat; if (!newChat.gigagroup && newChat.slowmode_enabled && messageObject.isSent() && chatMode != MODE_SCHEDULED) { - if (chatInfo != null) { + if (chatInfo != null && !ChatObject.isIgnoredChatRestrictionsForBoosters(chatInfo)) { int date = messageObject.messageOwner.date + chatInfo.slowmode_seconds; int currentTime = getConnectionsManager().getCurrentTime(); if (date > getConnectionsManager().getCurrentTime()) { @@ -23010,6 +23095,65 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not openAttachBotLayout(attachMenuBotToOpen); attachMenuBotToOpen = null; } + checkGroupEmojiPackHint(); + } + + private void checkGroupEmojiPackHint() { + if (groupEmojiPackHint == null && ChatObject.isMegagroup(currentChat)) { + final TLRPC.ChatFull chatFull = getMessagesController().getChatFull(currentChat.id); + if (chatFull == null || chatFull.emojiset == null || chatActivityEnterView == null || getContext() == null) { + return; + } + if (MessagesController.getGlobalMainSettings().getBoolean("groupEmojiPackHintShown", false)) { + return; + } + TLRPC.StickerSet emojiSet = chatFull.emojiset; + long thumbDocumentId = emojiSet.thumb_document_id; + if (thumbDocumentId == 0) { + TLRPC.TL_messages_stickerSet stickerSet = getMediaDataController().getGroupStickerSetById(emojiSet); + if (stickerSet != null && !stickerSet.documents.isEmpty()) { + thumbDocumentId = stickerSet.documents.get(0).id; + } + } + if (thumbDocumentId == 0) { + return; + } + MessagesController.getGlobalMainSettings().edit().putBoolean("groupEmojiPackHintShown", true).apply(); + groupEmojiPackHint = new HintView2(getContext(), HintView2.DIRECTION_BOTTOM); + groupEmojiPackHint.setCloseButton(true); + groupEmojiPackHint.setMultilineText(true); + groupEmojiPackHint.setTextAlign(Layout.Alignment.ALIGN_CENTER); + groupEmojiPackHint.setRounding(12); + SpannableStringBuilder packFullName = new SpannableStringBuilder("d"); + packFullName.setSpan(new AnimatedEmojiSpan(thumbDocumentId, groupEmojiPackHint.getTextPaint().getFontMetricsInt()), 0, packFullName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + SpannableStringBuilder titleBuilder = new SpannableStringBuilder(chatFull.emojiset.title); + titleBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, titleBuilder.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE); + packFullName.append(" "); + packFullName.append(titleBuilder); + groupEmojiPackHint.setText(AndroidUtilities.replaceCharSequence("%s", LocaleController.getString(R.string.GroupEmojiPackHint), packFullName)); + groupEmojiPackHint.setMaxWidthPx(HintView2.cutInFancyHalf(groupEmojiPackHint.getText(), groupEmojiPackHint.getTextPaint())); + groupEmojiPackHint.setDuration(-1); + groupEmojiPackHint.setPadding(dp(6), 0, dp(6), 0); + AndroidUtilities.runOnUIThread(() -> { + FrameLayout.LayoutParams lp = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, 0); + lp.bottomMargin = chatActivityEnterView.getMeasuredHeight(); + contentView.addView(groupEmojiPackHint, lp); + groupEmojiPackHint.setJointPx(0, chatActivityEnterView.getEmojiButton().getX() + dp(18)); + groupEmojiPackHint.show(); + }, 300); + } + } + + public boolean groupEmojiPackHintWasVisible() { + boolean result = false; + if (groupEmojiPackHint != null) { + result = true; + if (groupEmojiPackHint.shown()) { + groupEmojiPackHint.hide(); + } + } + groupEmojiPackHint = null; + return result; } public void openAttachBotLayout(String botUsername) { @@ -23306,6 +23450,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { bottomOverlayChatText.setText(LocaleController.getString("Unblock", R.string.Unblock)); } + bottomOverlayChatText.setVisibility(View.VISIBLE); if (botButtons != null) { botButtons = null; if (chatActivityEnterView != null) { @@ -23513,8 +23658,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (sentBotStart) { - getMessagesController().sendBotStart(currentUser, botUser); - bottomOverlayChat.setVisibility(View.GONE); chatActivityEnterView.setVisibility(View.VISIBLE); chatActivityEnterView.setBotInfo(botInfo); @@ -25351,7 +25494,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } getMediaDataController().saveDraft(dialog_id, draftThreadId, message[0], entities, (replyMessage != null && !replyMessage.isTopicMainMessage && replyMessage.replyToForumTopic == null && !ignoreDraft) ? replyMessage.messageOwner : null, replyingQuote, !searchWebpage, false); getMessagesController().cancelTyping(0, dialog_id, threadMessageId); - + } + if (chatMode == 0 || chatMode == MODE_SAVED) { if (!pausedOnLastMessage && !firstLoading && (!isThreadChat() || isTopic)) { SharedPreferences.Editor editor = MessagesController.getNotificationsSettings(currentAccount).edit(); int messageId = 0; @@ -25460,9 +25604,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { draftMessage = getMediaDataController().getDraft(dialog_id, chatMode == MODE_SAVED ? 0 : threadMessageId); } + MediaDataController.DraftVoice voiceDraft = MediaDataController.getInstance(currentAccount).getDraftVoice(dialog_id, getTopicId()); TLRPC.Message draftReplyMessage = draftMessage != null && draftMessage.reply_to != null && draftMessage.reply_to.reply_to_msg_id != 0 ? getMediaDataController().getDraftMessage(dialog_id, topicId != null ? topicId : threadMessageId) : null; if (chatActivityEnterView.getFieldText() == null || chatMode == 0 && getUserConfig().getClientUserId() == getDialogId() && draftMessage != null && appliedDraftDate < draftMessage.date) { - if (draftMessage != null) { + if (voiceDraft != null) { + chatActivityEnterView.setVoiceDraft(voiceDraft); + } else if (draftMessage != null) { appliedDraftDate = draftMessage.date; chatActivityEnterView.setWebPage(null, !draftMessage.no_webpage); CharSequence message; @@ -25914,6 +26061,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!single && (message.messageOwner.action instanceof TLRPC.TL_messageActionGiftPremium || message.messageOwner.action instanceof TLRPC.TL_messageActionGiftCode)) { return false; } + FileLog.d("open menu msg_id=" + message.getId()); final int type = getMessageType(message); if (single) { boolean isGiveawayResultsMessage = false; @@ -25972,9 +26120,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; } } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionSetChatTheme) { - if (currentChat == null || ChatObject.canChangeChatInfo(currentChat)) { - showChatThemeBottomSheet(); - } + showChatThemeBottomSheet(); return true; } } @@ -27215,7 +27361,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Layout layout = getLayout(); int width = 0; for (int i = 0; i < layout.getLineCount(); ++i) { - width = Math.max(width, (int) layout.getLineWidth(i)); + width = Math.max(width, (int) Math.ceil(layout.getLineWidth(i))); } widthMeasureSpec = MeasureSpec.makeMeasureSpec(getPaddingLeft() + width + getPaddingRight(), MeasureSpec.EXACTLY); } @@ -27560,6 +27706,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showDialog(alert); }); popupLayout.addView(button, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + popupLayout.precalculateHeight(); } } } @@ -27769,9 +27916,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (emptyViewContainer == null) { emptyViewContainer = new FrameLayout(getContext()); - emptyViewContainer.setOnTouchListener((v, event) -> true); +// emptyViewContainer.setOnTouchListener((v, event) -> true); emptyViewContainer.setVisibility(View.INVISIBLE); - contentView.addView(emptyViewContainer, 1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + contentView.addView(emptyViewContainer, 3, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); } else { emptyViewContainer.removeAllViews(); } @@ -30922,7 +31069,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (cell.hasButton()) { ThemePreviewActivity.showFor(ChatActivity.this, message); - } else if (currentChat == null || ChatObject.canChangeChatInfo(currentChat)) { + } else { showChatThemeBottomSheet(); } return; @@ -33160,7 +33307,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void didPressChannelRecommendation(ChatMessageCell cell, TLRPC.Chat chat, boolean longPress) { - if (chat == null || parentLayout != null && parentLayout.isInPreviewMode()) { + if (getContext() == null || chat == null || parentLayout != null && parentLayout.isInPreviewMode()) { return; } Bundle args = new Bundle(); @@ -33322,7 +33469,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not BulletinFactory.of(ChatActivity.this).createSimpleBulletin(R.raw.story_bomb1, LocaleController.getString("StoryNotFound", R.string.StoryNotFound)).show(); } else { TL_stories.StoryItem storyItem = messageObject.messageOwner.replyStory; - storyItem.dialogId = messageObject.messageOwner.reply_to.user_id; + storyItem.dialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.reply_to.peer); storyItem.messageId = messageObject.getId(); storyItem.messageType = 3; StoriesUtilities.applyViewedUser(storyItem, currentUser); @@ -33479,6 +33626,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + public void didPressBoostCounter(ChatMessageCell cell) { + getNotificationCenter().postNotificationName(NotificationCenter.openBoostForUsersDialog, dialog_id, cell); + } + @Override public void didStartVideoStream(MessageObject message) { if (message.isVideo()) { @@ -33776,7 +33928,42 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (messageObject.sponsoredWebPage != null) { Browser.openUrl(getContext(), messageObject.sponsoredWebPage.url, true, false); } else if (messageObject.sponsoredChatInvite != null) { - showDialog(new JoinGroupAlert(getContext(), messageObject.sponsoredChatInvite, messageObject.sponsoredChatInviteHash, ChatActivity.this, themeDelegate)); + final TLRPC.TL_messages_checkChatInvite req = new TLRPC.TL_messages_checkChatInvite(); + req.hash = messageObject.sponsoredChatInviteHash; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + TLRPC.ChatInvite invite = (TLRPC.ChatInvite) response; + if (invite.chat != null && (!ChatObject.isLeftFromChat(invite.chat) || !invite.chat.kicked && (ChatObject.isPublic(invite.chat) || invite instanceof TLRPC.TL_chatInvitePeek || invite.chat.has_geo))) { + MessagesController.getInstance(currentAccount).putChat(invite.chat, false); + ArrayList chats = new ArrayList<>(); + chats.add(invite.chat); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(null, chats, false, true); + args.putLong("chat_id", invite.chat.id); + if (MessagesController.getInstance(currentAccount).checkCanOpenChat(args, ChatActivity.this)) { + ChatActivity fragment = new ChatActivity(args); + if (invite instanceof TLRPC.TL_chatInvitePeek) { + fragment.setChatInvite(invite); + } + presentFragment(fragment); + } + } else { + showDialog(new JoinGroupAlert(getContext(), messageObject.sponsoredChatInvite, messageObject.sponsoredChatInviteHash, ChatActivity.this, themeDelegate, JoinGroupAlert.ORIGINATION_SPONSORED_CHAT)); + } + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), themeDelegate); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + if (error.text.startsWith("FLOOD_WAIT")) { + builder.setMessage(LocaleController.getString("FloodWait", R.string.FloodWait)); + } else if (error.text.startsWith("INVITE_HASH_EXPIRED")) { + builder.setTitle(LocaleController.getString("ExpiredLink", R.string.ExpiredLink)); + builder.setMessage(LocaleController.getString("InviteExpired", R.string.InviteExpired)); + } else { + builder.setMessage(LocaleController.getString("JoinToGroupErrorNotExist", R.string.JoinToGroupErrorNotExist)); + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + } + }), ConnectionsManager.RequestFlagFailOnServerErrors); } else { long peerId = MessageObject.getPeerId(messageObject.messageOwner.from_id); if (peerId == getDialogId() && messageObject.sponsoredChannelPost != 0) { @@ -35009,8 +35196,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); switchingFromTopics = true; - actionBar.invalidate(); - contentView.invalidate(); + if (actionBar != null) { + actionBar.invalidate(); + } + if (contentView != null) { + contentView.invalidate(); + } fragmentTransition = new AnimatorSet(); fragmentTransition.addListener(new AnimatorListenerAdapter() { @@ -35063,7 +35254,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void showChatThemeBottomSheet() { if (currentChat != null) { - presentFragment(new ChannelColorActivity(getDialogId()).setOnApplied(ChatActivity.this)); + if (ChatObject.isMegagroup(currentChat)) { + if (ChatObject.hasAdminRights(currentChat)) { + presentFragment(new GroupColorActivity(getDialogId()).setOnApplied(ChatActivity.this)); + } + } else { + if (ChatObject.canChangeChatInfo(currentChat)) { + presentFragment(new ChannelColorActivity(getDialogId()).setOnApplied(ChatActivity.this)); + } + } return; } chatThemeBottomSheet = new ChatThemeBottomSheet(ChatActivity.this, themeDelegate); @@ -36130,4 +36329,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; getMessagesController().invalidateUserPremiumBlocked(getDialogId(), classGuid); } + + public boolean checkCanRemoveRestrictionsByBoosts() { + boolean result = ChatObject.isPossibleRemoveChatRestrictionsByBoosts(chatInfo); + if (result) { + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); + LimitReachedBottomSheet.openBoostsForRemoveRestrictions(ChatActivity.this, boostsStatus, canApplyBoosts, dialog_id, false); + } + return result; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index 9e5936526..cb10718d9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -45,7 +45,6 @@ import android.widget.ScrollView; import androidx.annotation.NonNull; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ChannelBoostsController; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; @@ -60,6 +59,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.AlertDialog; @@ -105,7 +105,6 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image private AlertDialog progressDialog; private UndoView undoView; - private LinearLayout avatarContainer; private BackupImageView avatarImage; private View avatarOverlay; @@ -174,6 +173,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image private boolean historyHidden; private TLRPC.ChatReactions availableReactions; + private TL_stories.TL_premium_boostsStatus boostsStatus; private boolean createAfterUpload; private boolean donePressed; @@ -890,7 +890,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image if (ChatObject.isChannelAndNotMegaGroup(currentChat) && ChatObject.canChangeChatInfo(currentChat)) { colorCell = new PeerColorActivity.ChangeNameColorCell(currentAccount, -currentChat.id, context, getResourceProvider()); - colorCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); + colorCell.setBackground(Theme.getSelectorDrawable(true)); typeEditContainer.addView(colorCell, LayoutHelper.createLinear(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); colorCell.setOnClickListener(v -> { presentFragment(new ChannelColorActivity(-currentChat.id).setOnApplied(this)); @@ -952,6 +952,19 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image }); } + if (ChatObject.isMegagroup(currentChat) && ChatObject.hasAdminRights(currentChat)) { + MessagesController.getInstance(currentAccount).getBoostsController().getBoostsStats(-currentChat.id, boostsStatus -> this.boostsStatus = boostsStatus); + colorCell = new PeerColorActivity.ChangeNameColorCell(currentAccount, -currentChat.id, context, getResourceProvider()); + colorCell.setBackground(Theme.getSelectorDrawable(true)); + typeEditContainer.addView(colorCell, LayoutHelper.createLinear(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + colorCell.setOnClickListener(v -> { + GroupColorActivity activity = new GroupColorActivity(-currentChat.id); + activity.boostsStatus = boostsStatus; + activity.setOnApplied(this); + presentFragment(activity); + }); + } + if (isChannel) { signCell = new TextCell(context, 23, false, true, null); signCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); @@ -1088,19 +1101,12 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image logCell.setOnClickListener(v -> presentFragment(new ChannelAdminLogActivity(currentChat))); } - if (ChatObject.isChannelAndNotMegaGroup(currentChat)) { + if (ChatObject.isBoostSupported(currentChat)) { statsAndBoosts = new TextCell(context); statsAndBoosts.setTextAndIcon(LocaleController.getString("StatisticsAndBoosts", R.string.StatisticsAndBoosts), R.drawable.msg_stats, true); statsAndBoosts.setBackground(Theme.getSelectorDrawable(false)); statsAndBoosts.setOnClickListener(v -> { - Bundle args = new Bundle(); - args.putLong("chat_id", chatId); - args.putBoolean("is_megagroup", currentChat.megagroup); - TLRPC.ChatFull chatInfo = getMessagesController().getChatFull(chatId); - if (chatInfo == null || !chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - }; - presentFragment(new StatisticActivity(args)); + presentFragment(StatisticActivity.create(currentChat, false)); }); } @@ -1138,6 +1144,9 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image groupStickersActivity.setInfo(info); presentFragment(groupStickersActivity); }); + if (statsAndBoosts != null) { + infoContainer.addView(statsAndBoosts, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } } else { if (statsAndBoosts != null) { infoContainer.addView(statsAndBoosts, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index 103ba2e42..3004c1067 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -1181,6 +1181,12 @@ public class ChatRightsEditActivity extends BaseFragment { banUsersRow = rowCount++; addUsersRow = rowCount++; pinMessagesRow = rowCount++; + channelStoriesRow = rowCount++; + if (channelStoriesExpanded) { + channelPostStoriesRow = rowCount++; + channelEditStoriesRow = rowCount++; + channelDeleteStoriesRow = rowCount++; + } startVoiceChatRow = rowCount++; addAdminsRow = rowCount++; anonymousRow = rowCount++; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index 506c3bf39..7a9c3c781 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -15,6 +15,7 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -29,6 +30,7 @@ import android.widget.EditText; import android.widget.FrameLayout; import androidx.collection.LongSparseArray; +import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.LinearLayoutManager; @@ -88,6 +90,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private static final int VIEW_TYPE_INNER_CHECK = 13; private static final int VIEW_TYPE_EXPANDABLE_SWITCH = 14; + private static final int VIEW_TYPE_NOT_RESTRICT_BOOSTERS_SLIDER = 15; private ListAdapter listViewAdapter; private StickerEmptyView emptyView; @@ -163,6 +166,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private int slowmodeRow; private int slowmodeSelectRow; private int slowmodeInfoRow; + private int dontRestrictBoostersRow; + private int dontRestrictBoostersInfoRow; + private int dontRestrictBoostersSliderRow; private int contactsHeaderRow; private int contactsStartRow; @@ -192,6 +198,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private int selectedSlowmode; private int initialSlowmode; + private boolean isEnabledNotRestrictBoosters; + private int notRestrictBoosters; private final static int search_button = 0; private final static int done_button = 1; @@ -314,6 +322,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente slowmodeRow = -1; slowmodeSelectRow = -1; slowmodeInfoRow = -1; + dontRestrictBoostersRow = -1; + dontRestrictBoostersInfoRow = -1; + dontRestrictBoostersSliderRow = -1; loadingProgressRow = -1; loadingUserCellRow = -1; loadingHeaderRow = -1; @@ -367,6 +378,18 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente slowmodeSelectRow = rowCount++; slowmodeInfoRow = rowCount++; } + + if (isNotRestrictBoostersVisible()) { + if (participantsDivider2Row == -1) { + participantsDivider2Row = rowCount++; + } + dontRestrictBoostersRow = rowCount++; + if (isEnabledNotRestrictBoosters) { + dontRestrictBoostersSliderRow = rowCount++; + } + dontRestrictBoostersInfoRow = rowCount++; + } + if (ChatObject.isChannel(currentChat)) { if (participantsDivider2Row == -1) { participantsDivider2Row = rowCount++; @@ -754,6 +777,17 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente checkBoxCell.setChecked(!checkBoxCell.isChecked(), true); AndroidUtilities.updateVisibleRows(listView); + DiffCallback diffCallback = saveState(); + updateRows(); + updateListAnimated(diffCallback); + } else if (position == dontRestrictBoostersRow) { + TextCheckCell2 checkBoxCell = (TextCheckCell2) view; + isEnabledNotRestrictBoosters = !checkBoxCell.isChecked(); + checkBoxCell.setChecked(isEnabledNotRestrictBoosters); + AndroidUtilities.updateVisibleRows(listView); + DiffCallback diffCallback = saveState(); + updateRows(); + updateListAnimated(diffCallback); } else if (position == addNewRow) { if (type == TYPE_BANNED || type == TYPE_KICKED) { Bundle bundle = new Bundle(); @@ -1048,6 +1082,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (sendMediaRow >= 0) { listViewAdapter.notifyItemChanged(sendMediaRow); } + DiffCallback diffCallback = saveState(); + updateRows(); + updateListAnimated(diffCallback); } else if (position == sendMediaRow) { DiffCallback diffCallback = saveState(); sendMediaExpanded = !sendMediaExpanded; @@ -1854,6 +1891,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente info = chatFull; if (!hadInfo) { selectedSlowmode = initialSlowmode = getCurrentSlowmode(); + isEnabledNotRestrictBoosters = info.boosts_unrestrict > 0; + notRestrictBoosters = info.boosts_unrestrict; } AndroidUtilities.runOnUIThread(() -> loadChatParticipants(0, 200)); } @@ -1917,7 +1956,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private boolean checkDiscard() { String newBannedRights = ChatObject.getBannedRightsString(defaultBannedRights); - if (!newBannedRights.equals(initialBannedRights) || initialSlowmode != selectedSlowmode) { + if (!newBannedRights.equals(initialBannedRights) || initialSlowmode != selectedSlowmode || hasNotRestrictBoostersChanges()) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("UserRestrictionsApplyChanges", R.string.UserRestrictionsApplyChanges)); if (isChannel) { @@ -2064,13 +2103,40 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente info.flags |= 131072; getMessagesController().setChannelSlowMode(chatId, info.slowmode_seconds); } + + if (hasNotRestrictBoostersChanges()) { + boolean isEnabledNotRestrictBoosters = this.isEnabledNotRestrictBoosters && isNotRestrictBoostersVisible(); + if (isEnabledNotRestrictBoosters && notRestrictBoosters == 0) { + getMessagesController().setBoostsToUnblockRestrictions(chatId, 1); + } else if (!isEnabledNotRestrictBoosters && notRestrictBoosters != 0) { + getMessagesController().setBoostsToUnblockRestrictions(chatId, 0); + } else { + getMessagesController().setBoostsToUnblockRestrictions(chatId, notRestrictBoosters); + } + } finishFragment(); } + private boolean hasNotRestrictBoostersChanges() { + boolean isEnabledNotRestrictBoosters = this.isEnabledNotRestrictBoosters && isNotRestrictBoostersVisible(); + return info != null && (info.boosts_unrestrict != notRestrictBoosters + || (isEnabledNotRestrictBoosters && notRestrictBoosters == 0) + || (!isEnabledNotRestrictBoosters && notRestrictBoosters != 0)); + } + + private boolean isNotRestrictBoostersVisible() { + return currentChat.megagroup && !currentChat.gigagroup && ChatObject.canUserDoAdminAction(currentChat,ChatObject.ACTION_DELETE_MESSAGES) && + (selectedSlowmode > 0 || defaultBannedRights.send_plain || defaultBannedRights.send_media || defaultBannedRights.send_photos || defaultBannedRights.send_videos + || defaultBannedRights.send_stickers || defaultBannedRights.send_audios || defaultBannedRights.send_docs + || defaultBannedRights.send_voices || defaultBannedRights.send_roundvideos || defaultBannedRights.embed_links || defaultBannedRights.send_polls); + } + public void setInfo(TLRPC.ChatFull chatFull) { info = chatFull; if (info != null) { selectedSlowmode = initialSlowmode = getCurrentSlowmode(); + isEnabledNotRestrictBoosters = info.boosts_unrestrict > 0; + notRestrictBoosters = info.boosts_unrestrict; } } @@ -3062,10 +3128,33 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (info == null) { return; } + boolean needRowsUpdate = (selectedSlowmode > 0 && which == 0) || (selectedSlowmode == 0 && which > 0); selectedSlowmode = which; + if (needRowsUpdate) { + DiffCallback diffCallback = saveState(); + updateRows(); + updateListAnimated(diffCallback); + } listViewAdapter.notifyItemChanged(slowmodeInfoRow); }); break; + case VIEW_TYPE_NOT_RESTRICT_BOOSTERS_SLIDER: { + SlideChooseView slider = new SlideChooseView(mContext); + view = slider; + slider.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + Drawable[] drawables = new Drawable[]{ + ContextCompat.getDrawable(getContext(), R.drawable.mini_boost_profile_badge), + ContextCompat.getDrawable(getContext(), R.drawable.mini_boost_profile_badge2), + ContextCompat.getDrawable(getContext(), R.drawable.mini_boost_profile_badge2), + ContextCompat.getDrawable(getContext(), R.drawable.mini_boost_profile_badge2), + ContextCompat.getDrawable(getContext(), R.drawable.mini_boost_profile_badge2) + }; + slider.setOptions(notRestrictBoosters > 0 ? (notRestrictBoosters - 1) : 0, drawables, "1", "2", "3", "4", "5"); + slider.setCallback(which -> { + notRestrictBoosters = which + 1; + }); + break; + } case VIEW_TYPE_INNER_CHECK: CheckBoxCell checkBoxCell = new CheckBoxCell(mContext, 4, 21, getResourceProvider()); checkBoxCell.getCheckBoxRound().setDrawBackgroundAsArc(14); @@ -3218,6 +3307,13 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente privacyCell.setText(LocaleController.getString("ChannelHideMembersInfo", R.string.ChannelHideMembersInfo)); } else if (position == gigaInfoRow) { privacyCell.setText(LocaleController.getString("BroadcastGroupConvertInfo", R.string.BroadcastGroupConvertInfo)); + } else if (position == dontRestrictBoostersInfoRow) { + privacyCell.setBackground(Theme.getThemedDrawableByKey(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + if (isEnabledNotRestrictBoosters) { + privacyCell.setText(LocaleController.getString(R.string.GroupNotRestrictBoostersInfo2)); + } else { + privacyCell.setText(LocaleController.getString(R.string.GroupNotRestrictBoostersInfo)); + } } break; case 2: @@ -3288,6 +3384,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente case VIEW_TYPE_EXPANDABLE_SWITCH: case 7: TextCheckCell2 checkCell = (TextCheckCell2) holder.itemView; + checkCell.getCheckBox().setDrawIconType(1); + checkCell.getCheckBox().setColors(Theme.key_fill_RedNormal, Theme.key_switch2TrackChecked, Theme.key_windowBackgroundWhite, Theme.key_windowBackgroundWhite); boolean animated = checkCell.getTag() != null && (Integer) checkCell.getTag() == position; checkCell.setTag(position); if (position == changeInfoRow) { @@ -3298,6 +3396,10 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsPinMessages", R.string.UserRestrictionsPinMessages), !defaultBannedRights.pin_messages && !ChatObject.isPublic(currentChat), true, animated); } else if (position == sendMessagesRow) { checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendText", R.string.UserRestrictionsSendText), !defaultBannedRights.send_plain, true, animated); + } else if(position == dontRestrictBoostersRow) { + checkCell.setTextAndCheck(LocaleController.getString(R.string.GroupNotRestrictBoosters), isEnabledNotRestrictBoosters, false, animated); + checkCell.getCheckBox().setDrawIconType(0); + checkCell.getCheckBox().setColors(Theme.key_switchTrack, Theme.key_switchTrackChecked, Theme.key_windowBackgroundWhite, Theme.key_windowBackgroundWhite); } else if (position == sendMediaRow) { int sentMediaCount = getSendMediaSelectedCount(); checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), sentMediaCount > 0, true, animated); @@ -3307,7 +3409,6 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente boolean checked = !checkCell.isChecked(); checkCell.setChecked(checked); setSendMediaEnabled(checked); - } }); } else if (position == sendStickersRow) { @@ -3419,14 +3520,14 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente return 3; } else if (position == restricted1SectionRow || position == permissionsSectionRow || position == slowmodeRow || position == gigaHeaderRow) { return 5; - } else if (position == participantsInfoRow || position == slowmodeInfoRow || position == gigaInfoRow || position == antiSpamInfoRow || position == hideMembersInfoRow) { + } else if (position == participantsInfoRow || position == slowmodeInfoRow || position == dontRestrictBoostersInfoRow || position == gigaInfoRow || position == antiSpamInfoRow || position == hideMembersInfoRow) { return 1; } else if (position == blockedEmptyRow) { return 4; } else if (position == removedUsersRow) { return 6; } else if (position == changeInfoRow || position == addUsersRow || position == pinMessagesRow || position == sendMessagesRow || - position == sendStickersRow || position == embedLinksRow || position == manageTopicsRow) { + position == sendStickersRow || position == embedLinksRow || position == manageTopicsRow || position == dontRestrictBoostersRow) { return 7; } else if (position == membersHeaderRow || position == contactsHeaderRow || position == botHeaderRow || position == loadingHeaderRow) { return 8; @@ -3442,6 +3543,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente return VIEW_TYPE_INNER_CHECK; } else if (position == sendMediaRow) { return VIEW_TYPE_EXPANDABLE_SWITCH; + } else if (position == dontRestrictBoostersSliderRow) { + return VIEW_TYPE_NOT_RESTRICT_BOOSTERS_SLIDER; } return 0; } @@ -3460,6 +3563,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private void setSendMediaEnabled(boolean enabled) { defaultBannedRights.send_media = !enabled; + defaultBannedRights.send_gifs = !enabled; + defaultBannedRights.send_inline = !enabled; + defaultBannedRights.send_games = !enabled; defaultBannedRights.send_photos = !enabled; defaultBannedRights.send_videos = !enabled; defaultBannedRights.send_stickers = !enabled; @@ -3470,6 +3576,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente defaultBannedRights.embed_links = !enabled; defaultBannedRights.send_polls = !enabled; AndroidUtilities.updateVisibleRows(listView); + DiffCallback diffCallback = saveState(); + updateRows(); + updateListAnimated(diffCallback); } private boolean isExpandableSendMediaRow(int position) { @@ -3609,6 +3718,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente put(++pointer, slowmodeRow, sparseIntArray); put(++pointer, slowmodeSelectRow, sparseIntArray); put(++pointer, slowmodeInfoRow, sparseIntArray); + put(++pointer, dontRestrictBoostersRow, sparseIntArray); + put(++pointer, dontRestrictBoostersSliderRow, sparseIntArray); + put(++pointer, dontRestrictBoostersInfoRow, sparseIntArray); put(++pointer, loadingProgressRow, sparseIntArray); put(++pointer, loadingUserCellRow, sparseIntArray); put(++pointer, loadingHeaderRow, sparseIntArray); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java index 4cb085afb..25845ccaa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java @@ -1112,6 +1112,15 @@ public class AnimatedEmojiDrawable extends Drawable { set(document, cacheType, animated); } + public void removeOldDrawable() { + if (drawables[1] != null) { + if (drawables[1] instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) drawables[1]).removeView(this); + } + drawables[1] = null; + } + } + public void set(TLRPC.Document document, int cacheType, boolean animated) { if (drawables[0] instanceof AnimatedEmojiDrawable && document != null && ((AnimatedEmojiDrawable) drawables[0]).getDocumentId() == document.id) { return; 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 8a91c6e50..12b0d0c76 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -80,10 +80,14 @@ public final class BulletinFactory { if (BuildVars.DEBUG_VERSION) { createErrorBulletin(error.code + " " + error.text).show(); } else { - createErrorBulletin(LocaleController.getString("UnknownError", R.string.UnknownError)).show(); + createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); } } + public static void showError(TLRPC.TL_error error) { + global().createErrorBulletin(LocaleController.formatString(R.string.UnknownErrorCode, error.text)).show(); + } + public enum FileType { PHOTO("PhotoSavedHint", R.string.PhotoSavedHint, Icon.SAVED_TO_GALLERY), 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 cbe99c606..3e026d75a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -96,6 +96,7 @@ import androidx.annotation.Nullable; import androidx.collection.LongSparseArray; import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; +import androidx.core.graphics.drawable.DrawableCompat; import androidx.core.math.MathUtils; import androidx.core.os.BuildCompat; import androidx.core.view.ViewCompat; @@ -156,6 +157,7 @@ import org.telegram.ui.BasePermissionsActivity; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.Premium.GiftPremiumBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; +import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.ContentPreviewViewer; import org.telegram.ui.DialogsActivity; import org.telegram.ui.GroupStickersActivity; @@ -171,6 +173,8 @@ import org.telegram.ui.Stories.recorder.HintView2; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -264,6 +268,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific void onUpdateSlowModeButton(View button, boolean show, CharSequence time); + default boolean checkCanRemoveRestrictionsByBoosts() { + return false; + } + default void scrollToSendingMessage() { } @@ -392,7 +400,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private boolean sendRoundEnabled = true; private boolean sendVoiceEnabled = true; - private boolean sendPlainEnabled = true; + public boolean sendPlainEnabled = true; private boolean emojiButtonRestricted; @@ -451,6 +459,92 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } + private static class SlowModeBtn extends FrameLayout { + private final SimpleTextView textView; + private final RectF bgRect = new RectF(); + private final Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Drawable closeDrawable; + private boolean isPremiumMode = false; + + public SlowModeBtn(@NonNull Context context) { + super(context); + textView = new SimpleTextView(context); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + setWillNotDraw(false); + closeDrawable = ContextCompat.getDrawable(context, R.drawable.msg_mini_close_tooltip); + closeDrawable.setBounds(0, 0, closeDrawable.getIntrinsicWidth(), closeDrawable.getIntrinsicHeight()); + setClipToPadding(false); + setClipChildren(false); + ScaleStateListAnimator.apply(this); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + gradientPaint.setShader(new LinearGradient(0, 0, getMeasuredWidth(), 0, new int[]{0xff7593ff, 0xffa472ff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); + } + + public void setTextSize(int size) { + textView.setTextSize(size); + invalidate(); + } + + public void setTextColor(int color) { + textView.setTextColor(color); + invalidate(); + } + + public void setGravity(int gravity) { + textView.setGravity(gravity); + invalidate(); + } + + public void setText(CharSequence text) { + textView.setText(text); + invalidate(); + } + + public void setPremiumMode(boolean premiumMode) { + this.isPremiumMode = premiumMode; + invalidate(); + } + + public CharSequence getText() { + return textView.getText(); + } + + @Override + protected void onDraw(Canvas canvas) { + if (isPremiumMode) { + canvas.save(); + int heightRect = dp(26); + canvas.translate(0, ((getMeasuredHeight() - heightRect) / 2f) - dp(1)); + bgRect.set(0, 0f, (float) getMeasuredWidth() - getPaddingEnd(), (float) heightRect); + canvas.drawRoundRect(bgRect, heightRect / 2f, heightRect / 2f, gradientPaint); + canvas.translate(getMeasuredWidth() - getPaddingEnd() - dp(6) - closeDrawable.getIntrinsicWidth(), dp(5)); + closeDrawable.draw(canvas); + canvas.restore(); + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child instanceof SimpleTextView && isPremiumMode) { + SimpleTextView simpleTextView = (SimpleTextView) child; + canvas.save(); + canvas.scale(0.8f, 0.8f); + canvas.translate(-dp(16), dp(5)); + int oldColor = simpleTextView.getTextPaint().getColor(); + simpleTextView.getTextPaint().setColor(Color.WHITE); + boolean result = super.drawChild(canvas, child, drawingTime); + simpleTextView.getTextPaint().setColor(oldColor); + canvas.restore(); + return result; + } + return super.drawChild(canvas, child, drawingTime); + } + } + @SuppressWarnings("FieldCanBeLocal") private View.AccessibilityDelegate mediaMessageButtonsDelegate = new View.AccessibilityDelegate() { @Override @@ -464,7 +558,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific @Nullable protected EditTextCaption messageEditText; - private SimpleTextView slowModeButton; + private SlowModeBtn slowModeButton; private int slowModeTimer; private Runnable updateSlowModeRunnable; private View sendButton; @@ -799,7 +893,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } if (!recordingAudioVideo) { recordingAudioVideo = true; - updateRecordInterface(RECORD_STATE_ENTER); + updateRecordInterface(RECORD_STATE_ENTER, true); if (recordCircle != null) { recordCircle.showWaves(false, false); } @@ -818,7 +912,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific TL_stories.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; MediaController.getInstance().startRecording(currentAccount, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, recordingGuid, true); recordingAudioVideo = true; - updateRecordInterface(RECORD_STATE_ENTER); + updateRecordInterface(RECORD_STATE_ENTER, true); if (recordTimerView != null) { recordTimerView.start(0); } @@ -1559,7 +1653,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } delegate.toggleVideoRecordingPause(); } else { - MediaController.getInstance().toggleRecordingPause(); + MediaController.getInstance().toggleRecordingPause(voiceOnce); delegate.needStartRecordAudio(0); if (slideText != null) { slideText.setEnabled(false); @@ -1570,6 +1664,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else if (oncePressed && onceRect.contains(x, y)) { voiceOnce = !voiceOnce; periodDrawable.setValue(1, voiceOnce, true); + MediaDataController.getInstance(currentAccount).toggleDraftVoiceOnce(dialog_id, parentFragment != null && parentFragment.isTopic ? parentFragment.getTopicId() : 0, voiceOnce); if (voiceOnce) { showHintView(); } else { @@ -2520,7 +2615,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (!isPopupShowing() || currentPopupContentType != 0) { showPopup(1, 0); - emojiView.onOpen(messageEditText != null && messageEditText.length() > 0); + emojiView.onOpen(messageEditText != null && messageEditText.length() > 0, parentFragment != null && parentFragment.groupEmojiPackHintWasVisible()); } else { if (searchingType != 0) { setSearchingTypeInternal(0, true); @@ -2668,7 +2763,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific messageTransitionIsRunning = false; AndroidUtilities.runOnUIThread(moveToSendStateRunnable = () -> { moveToSendStateRunnable = null; - updateRecordInterface(RECORD_STATE_SENDING); + updateRecordInterface(RECORD_STATE_SENDING, true); }, 200); } getParent().requestDisallowInterceptTouchEvent(true); @@ -2702,7 +2797,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } millisecondsRecorded = 0; recordingAudioVideo = false; - updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE); + updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE, true); } else { sendButtonVisible = true; startLockTransition(); @@ -2729,7 +2824,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } millisecondsRecorded = 0; recordingAudioVideo = false; - updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE); + updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE, true); } else { if (recordAudioVideoRunnableStarted) { AndroidUtilities.cancelRunOnUIThread(recordAudioVideoRunnable); @@ -2759,7 +2854,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific messageTransitionIsRunning = false; AndroidUtilities.runOnUIThread(moveToSendStateRunnable = () -> { moveToSendStateRunnable = null; - updateRecordInterface(RECORD_STATE_SENDING); + updateRecordInterface(RECORD_STATE_SENDING, true); }, shouldDrawBackground ? 500 : 0); } } @@ -2809,7 +2904,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); } recordingAudioVideo = false; - updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE); + updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE, true); } return true; } @@ -3172,19 +3267,22 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific }); sendButton.setOnLongClickListener(this::onSendLongClick); - slowModeButton = new SimpleTextView(context); + slowModeButton = new SlowModeBtn(context); slowModeButton.setTextSize(18); slowModeButton.setVisibility(INVISIBLE); slowModeButton.setSoundEffectsEnabled(false); slowModeButton.setScaleX(0.1f); slowModeButton.setScaleY(0.1f); slowModeButton.setAlpha(0.0f); - slowModeButton.setPadding(0, 0, dp(13), 0); + slowModeButton.setPadding(0, 0, dp(10), 0); slowModeButton.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL); slowModeButton.setTextColor(getThemedColor(Theme.key_chat_messagePanelIcons)); - sendButtonContainer.addView(slowModeButton, LayoutHelper.createFrame(64, 48, Gravity.RIGHT | Gravity.TOP)); + sendButtonContainer.addView(slowModeButton, LayoutHelper.createFrame(74, 48, Gravity.RIGHT | Gravity.TOP)); slowModeButton.setOnClickListener(v -> { if (delegate != null) { + if (delegate.checkCanRemoveRestrictionsByBoosts()) { + return; + } delegate.onUpdateSlowModeButton(slowModeButton, true, slowModeButton.getText()); } }); @@ -3550,6 +3648,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } new File(audioToSendPath).delete(); } + MediaDataController.getInstance(currentAccount).pushDraftVoiceMessage(dialog_id, parentFragment != null && parentFragment.isTopic ? parentFragment.getTopicId() : 0, null); MediaController.getInstance().stopRecording(0, false, 0, false); millisecondsRecorded = 0; hideRecordedAudioPanel(false); @@ -3933,6 +4032,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } private void showRestrictedHint() { + if (delegate != null && delegate.checkCanRemoveRestrictionsByBoosts()) { + return; + } if (DialogObject.isChatDialog(dialog_id)) { TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); BulletinFactory.of(parentFragment).createSimpleBulletin(R.raw.passcode_lock_close, LocaleController.formatString("SendPlainTextRestrictionHint", R.string.SendPlainTextRestrictionHint, ChatObject.getAllowedSendString(chat)), 3).show(); @@ -5104,7 +5206,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific MediaController.getInstance().stopRecording(0, false, 0, false); } recordingAudioVideo = false; - updateRecordInterface(RECORD_STATE_CANCEL); + updateRecordInterface(RECORD_STATE_CANCEL, true); } public void showContextProgress(boolean show) { @@ -5144,7 +5246,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific (isUploading = SendMessagesHelper.getInstance(currentAccount).isUploadingMessageIdDialog(dialog_id)) || SendMessagesHelper.getInstance(currentAccount).isSendingMessageIdDialog(dialog_id))) { TLRPC.Chat chat = accountInstance.getMessagesController().getChat(info.id); - if (!ChatObject.hasAdminRights(chat)) { + if (!ChatObject.hasAdminRights(chat) && !ChatObject.isIgnoredChatRestrictionsForBoosters(info)) { currentTime = info.slowmode_seconds; slowModeTimer = isUploading ? Integer.MAX_VALUE : Integer.MAX_VALUE - 1; } else { @@ -5598,13 +5700,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific stickersEnabled = ChatObject.canSendStickers(chat); sendPlainEnabled = ChatObject.canSendPlain(chat); - sendPlainEnabled = ChatObject.canSendPlain(chat); emojiButtonRestricted = !stickersEnabled && !sendPlainEnabled; emojiButtonAlpha = emojiButtonRestricted ? 0.5f : 1.0f; updateEmojiButtonParams(); if (!emojiButtonRestricted) { if (emojiView != null) { - emojiView.setStickersBanned(!ChatObject.canSendPlain(chat), !ChatObject.canSendStickers(chat), chat.id); + emojiView.setStickersBanned(!sendPlainEnabled, !stickersEnabled, -dialog_id); } } sendRoundEnabled = ChatObject.canSendRoundVideo(chat); @@ -5758,6 +5859,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (emojiView != null) { emojiView.setChatInfo(info); } + if (slowModeButton != null) { + slowModeButton.setPremiumMode(ChatObject.isPossibleRemoveChatRestrictionsByBoosts(chatInfo)); + } + if (ChatObject.isIgnoredChatRestrictionsForBoosters(chatInfo)) { + return; + } setSlowModeTimer(chatInfo.slowmode_next_send_date); } @@ -6243,12 +6350,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordCircle.setSendButtonInvisible(); } }, 100); + millisecondsRecorded = 0; return; } else if (audioToSend != null) { MessageObject playing = MediaController.getInstance().getPlayingMessageObject(); if (playing != null && playing == audioToSendMessageObject) { MediaController.getInstance().cleanupPlayer(true, true); } + MediaDataController.getInstance(currentAccount).pushDraftVoiceMessage(dialog_id, parentFragment != null && parentFragment.isTopic ? parentFragment.getTopicId() : 0, null); SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(audioToSend, null, audioToSendPath, dialog_id, replyingMessageObject, getThreadMessage(), null, null, null, null, notify, scheduleDate, voiceOnce ? 0x7FFFFFFF : 0, null, null, false); applyStoryToSendMessageParams(params); SendMessagesHelper.getInstance(currentAccount).sendMessage(params); @@ -6262,6 +6371,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordCircle.setSendButtonInvisible(); } }, 100); + millisecondsRecorded = 0; return; } CharSequence message = messageEditText == null ? "" : messageEditText.getText(); @@ -6382,6 +6492,21 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } } + + if (emoji != null) { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + if (chatFull != null && chatFull.emojiset != null) { + TLRPC.TL_messages_stickerSet stickerSet = MediaDataController.getInstance(currentAccount).getGroupStickerSetById(chatFull.emojiset); + if (stickerSet != null) { + for (TLRPC.Document document : stickerSet.documents) { + if (document.id == documentId) { + return false; + } + } + } + } + } + if (emoji == null || !MessageObject.isFreeEmoji(emoji)) { BulletinFactory.of(parentFragment) .createEmojiBulletin( @@ -7361,7 +7486,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private void setSlowModeButtonVisible(boolean visible) { slowModeButton.setVisibility(visible ? VISIBLE : GONE); - int padding = visible ? dp(16) : 0; + int padding = visible ? dp(slowModeButton.isPremiumMode ? 26 : 16) : 0; if (messageEditText != null && messageEditText.getPaddingRight() != padding) { messageEditText.setPadding(0, dp(11), padding, dp(12)); } @@ -7417,7 +7542,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } private int lastRecordState; - protected void updateRecordInterface(int recordState) { + protected void updateRecordInterface(int recordState, boolean animated) { if (moveToSendStateRunnable != null) { AndroidUtilities.cancelRunOnUIThread(moveToSendStateRunnable); moveToSendStateRunnable = null; @@ -7437,6 +7562,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (controlsView != null) { controlsView.periodDrawable.setValue(1, false, false); } + MediaDataController.getInstance(currentAccount).toggleDraftVoiceOnce(dialog_id, parentFragment != null && parentFragment.isTopic ? parentFragment.getTopicId() : 0, voiceOnce); millisecondsRecorded = 0; } @@ -7702,10 +7828,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific isRecordingStateChanged(); runningAnimationAudio.setDuration(150); } else if (recordState == RECORD_STATE_PREPARING) { + createRecordAudioPanel(); + createRecordCircle(); if (slideText != null) { slideText.setEnabled(false); } - createRecordAudioPanel(); if (isInVideoMode()) { if (recordedAudioBackground != null) { recordedAudioBackground.setVisibility(GONE); @@ -7775,29 +7902,6 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordDeleteImageView.stopAnimation(); } - ValueAnimator transformToSeekbar = ValueAnimator.ofFloat(0, 1f); - transformToSeekbar.addUpdateListener(animation -> { - float value = (float) animation.getAnimatedValue(); - recordCircle.setTransformToSeekbar(value); - if (!isInVideoMode()) { - seekBarWaveform.setWaveScaling(recordCircle.getTransformToSeekbarProgressStep3()); - recordedAudioTimeTextView.setAlpha(recordCircle.getTransformToSeekbarProgressStep3()); - recordedAudioPlayButton.setAlpha(recordCircle.getTransformToSeekbarProgressStep3()); - recordedAudioPlayButton.setScaleX(recordCircle.getTransformToSeekbarProgressStep3()); - recordedAudioPlayButton.setScaleY(recordCircle.getTransformToSeekbarProgressStep3()); - recordedAudioSeekBar.setAlpha(recordCircle.getTransformToSeekbarProgressStep3()); - recordedAudioSeekBar.invalidate(); - } - isRecordingStateChanged(); - }); - transformToSeekbar.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - recordCircle.setTransformToSeekbar(1); - isRecordingStateChanged(); - } - }); - ViewGroup.LayoutParams oldLayoutParams = null; ViewGroup parent = null; if (!isInVideoMode() && !shouldDrawRecordedAudioPanelInParent) { @@ -7814,108 +7918,200 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } isRecordingStateChanged(); - if (recordDeleteImageView != null) { - recordDeleteImageView.setAlpha(0f); - recordDeleteImageView.setScaleX(0f); - recordDeleteImageView.setScaleY(0f); - } + AnimatorSet videoAdditionalAnimations = new AnimatorSet(); + if (!animated) { + createRecordPanel(); - AnimatorSet iconsAnimator = new AnimatorSet(); + recordCircleScale.set(recordCircle, 1f); + recordCircle.setTransformToSeekbar(1f); + if (!isInVideoMode()) { + if (transformToSeekbar != 0 && recordedAudioBackground != null) { + float step1Time = 0.38f; + float step2Time = 0.25f; + float step3Time = 1f - step1Time - step2Time; - iconsAnimator.playTogether( - ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), - ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0), - ObjectAnimator.ofFloat(recordTimerView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordTimerView, View.TRANSLATION_X, -dp(20)), - ObjectAnimator.ofFloat(slideText, View.ALPHA, 0), - ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 1), - ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_Y, 1f), - ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_X, 1f), - ObjectAnimator.ofFloat(emojiButton, EMOJI_BUTTON_SCALE, 0), - ObjectAnimator.ofFloat(emojiButton, EMOJI_BUTTON_ALPHA, 0), - ObjectAnimator.ofFloat(messageEditText, View.ALPHA, 0) - ); - if (audioVideoSendButton != null) { - iconsAnimator.playTogether( - ObjectAnimator.ofFloat(audioVideoSendButton, View.ALPHA, 1), - ObjectAnimator.ofFloat(audioVideoSendButton, View.SCALE_X, 1), - ObjectAnimator.ofFloat(audioVideoSendButton, View.SCALE_Y, 1) - ); - audioVideoSendButton.setState(isInVideoMode() ? ChatActivityEnterViewAnimatedIconView.State.VIDEO : ChatActivityEnterViewAnimatedIconView.State.VOICE, true); - } + float progressToSeekbarStep3 = Math.max(0, (transformToSeekbar - step1Time - step2Time) / step3Time); + progressToSeekbarStep3 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(progressToSeekbarStep3); - if (botCommandsMenuButton != null) { - iconsAnimator.playTogether( - ObjectAnimator.ofFloat(botCommandsMenuButton, View.ALPHA, 0), - ObjectAnimator.ofFloat(botCommandsMenuButton, View.SCALE_X, 0), - ObjectAnimator.ofFloat(botCommandsMenuButton, View.SCALE_Y, 0) - ); - } - - iconsAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (audioVideoSendButton != null) { - audioVideoSendButton.setScaleX(1f); - audioVideoSendButton.setScaleY(1f); + seekBarWaveform.setWaveScaling(progressToSeekbarStep3); + recordedAudioTimeTextView.setAlpha(progressToSeekbarStep3); + recordedAudioPlayButton.setAlpha(progressToSeekbarStep3); + recordedAudioPlayButton.setScaleX(progressToSeekbarStep3); + recordedAudioPlayButton.setScaleY(progressToSeekbarStep3); + recordedAudioSeekBar.setAlpha(progressToSeekbarStep3); + recordedAudioSeekBar.invalidate(); } } - }); - iconsAnimator.setDuration(150); - iconsAnimator.setStartDelay(150); + recordDot.setScaleY(0); + recordDot.setScaleX(0); + recordTimerView.setAlpha(0f); + recordTimerView.setTranslationX(-dp(20)); + slideText.setAlpha(0); + recordDeleteImageView.setAlpha(1f); + recordDeleteImageView.setScaleY(1f); + recordDeleteImageView.setScaleX(1f); + EMOJI_BUTTON_SCALE.set(emojiButton, 0f); + EMOJI_BUTTON_ALPHA.set(emojiButton, 0f); + messageEditText.setAlpha(0f); - AnimatorSet videoAdditionalAnimations = new AnimatorSet(); - if (isInVideoMode()) { - recordedAudioTimeTextView.setAlpha(0); - videoTimelineView.setAlpha(0); - videoAdditionalAnimations.playTogether( + if (audioVideoSendButton != null) { + audioVideoSendButton.setState(isInVideoMode() ? ChatActivityEnterViewAnimatedIconView.State.VIDEO : ChatActivityEnterViewAnimatedIconView.State.VOICE, animated); + audioVideoSendButton.setAlpha(1f); + audioVideoSendButton.setScaleX(1f); + audioVideoSendButton.setScaleY(1f); + } + if (botCommandsMenuButton != null) { + botCommandsMenuButton.setAlpha(0f); + botCommandsMenuButton.setScaleX(0f); + botCommandsMenuButton.setScaleY(0f); + } + + if (isInVideoMode()) { + recordedAudioTimeTextView.setAlpha(1f); + videoTimelineView.setAlpha(1f); + } + + ViewGroup finalParent = parent; + ViewGroup.LayoutParams finalOldLayoutParams = oldLayoutParams; + if (finalParent != null) { + sizeNotifierLayout.removeView(recordedAudioPanel); + finalParent.addView(recordedAudioPanel, finalOldLayoutParams); + } + recordedAudioPanel.setAlpha(1.0f); + recordedAudioBackground.setAlpha(1f); + recordedAudioTimeTextView.setAlpha(1f); + recordedAudioPlayButton.setAlpha(1f); + recordedAudioPlayButton.setScaleY(1f); + recordedAudioPlayButton.setScaleX(1f); + recordedAudioSeekBar.setAlpha(1f); + + emojiButtonAlpha = emojiButtonScale = 0f; + updateEmojiButtonParams(); + + isRecordingStateChanged(); + } else { + ValueAnimator transformToSeekbar = ValueAnimator.ofFloat(0, 1f); + transformToSeekbar.addUpdateListener(animation -> { + float value = (float) animation.getAnimatedValue(); + recordCircle.setTransformToSeekbar(value); + if (!isInVideoMode()) { + seekBarWaveform.setWaveScaling(recordCircle.getTransformToSeekbarProgressStep3()); + recordedAudioTimeTextView.setAlpha(recordCircle.getTransformToSeekbarProgressStep3()); + recordedAudioPlayButton.setAlpha(recordCircle.getTransformToSeekbarProgressStep3()); + recordedAudioPlayButton.setScaleX(recordCircle.getTransformToSeekbarProgressStep3()); + recordedAudioPlayButton.setScaleY(recordCircle.getTransformToSeekbarProgressStep3()); + recordedAudioSeekBar.setAlpha(recordCircle.getTransformToSeekbarProgressStep3()); + recordedAudioSeekBar.invalidate(); + } + isRecordingStateChanged(); + }); + transformToSeekbar.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + recordCircle.setTransformToSeekbar(1); + isRecordingStateChanged(); + } + }); + transformToSeekbar.setDuration(isInVideoMode() ? 490 : 580); + + AnimatorSet iconsAnimator = new AnimatorSet(); + + iconsAnimator.playTogether( + ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), + ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0), + ObjectAnimator.ofFloat(recordTimerView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(recordTimerView, View.TRANSLATION_X, -dp(20)), + ObjectAnimator.ofFloat(slideText, View.ALPHA, 0), + ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 1), + ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_Y, 1f), + ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_X, 1f), + ObjectAnimator.ofFloat(emojiButton, EMOJI_BUTTON_SCALE, 0), + ObjectAnimator.ofFloat(emojiButton, EMOJI_BUTTON_ALPHA, 0), + ObjectAnimator.ofFloat(messageEditText, View.ALPHA, 0) + ); + if (recordDeleteImageView != null) { + recordDeleteImageView.setAlpha(0f); + recordDeleteImageView.setScaleX(0f); + recordDeleteImageView.setScaleY(0f); + } + if (audioVideoSendButton != null) { + iconsAnimator.playTogether( + ObjectAnimator.ofFloat(audioVideoSendButton, View.ALPHA, 1), + ObjectAnimator.ofFloat(audioVideoSendButton, View.SCALE_X, 1), + ObjectAnimator.ofFloat(audioVideoSendButton, View.SCALE_Y, 1) + ); + audioVideoSendButton.setState(isInVideoMode() ? ChatActivityEnterViewAnimatedIconView.State.VIDEO : ChatActivityEnterViewAnimatedIconView.State.VOICE, true); + } + if (botCommandsMenuButton != null) { + iconsAnimator.playTogether( + ObjectAnimator.ofFloat(botCommandsMenuButton, View.ALPHA, 0), + ObjectAnimator.ofFloat(botCommandsMenuButton, View.SCALE_X, 0), + ObjectAnimator.ofFloat(botCommandsMenuButton, View.SCALE_Y, 0) + ); + } + iconsAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (audioVideoSendButton != null) { + audioVideoSendButton.setScaleX(1f); + audioVideoSendButton.setScaleY(1f); + } + } + }); + + iconsAnimator.setDuration(150); + iconsAnimator.setStartDelay(150); + + if (isInVideoMode()) { + recordedAudioTimeTextView.setAlpha(0); + videoTimelineView.setAlpha(0); + videoAdditionalAnimations.playTogether( ObjectAnimator.ofFloat(recordedAudioTimeTextView, View.ALPHA, 1), ObjectAnimator.ofFloat(videoTimelineView, View.ALPHA, 1) - ); - videoAdditionalAnimations.setDuration(150); - videoAdditionalAnimations.setStartDelay(430); - } - - - transformToSeekbar.setDuration(isInVideoMode() ? 490 : 580); - runningAnimationAudio.playTogether( - iconsAnimator, - transformToSeekbar, - videoAdditionalAnimations - ); - - ViewGroup finalParent = parent; - ViewGroup.LayoutParams finalOldLayoutParams = oldLayoutParams; - runningAnimationAudio.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (finalParent != null) { - sizeNotifierLayout.removeView(recordedAudioPanel); - finalParent.addView(recordedAudioPanel, finalOldLayoutParams); - } - recordedAudioPanel.setAlpha(1.0f); - recordedAudioBackground.setAlpha(1f); - recordedAudioTimeTextView.setAlpha(1f); - recordedAudioPlayButton.setAlpha(1f); - recordedAudioPlayButton.setScaleY(1f); - recordedAudioPlayButton.setScaleX(1f); - recordedAudioSeekBar.setAlpha(1f); - - emojiButtonAlpha = emojiButtonScale = 0f; - updateEmojiButtonParams(); - - if (botCommandsMenuButton != null) { - botCommandsMenuButton.setAlpha(0f); - botCommandsMenuButton.setScaleX(0f); - botCommandsMenuButton.setScaleY(0f); - } - - if (controlsView != null && onceVisible && !voiceOnce && (MessagesController.getGlobalMainSettings().getInt("voiceoncehint", 0) < 3)) { - controlsView.showHintView(); - } + ); + videoAdditionalAnimations.setDuration(150); + videoAdditionalAnimations.setStartDelay(430); } - }); + + runningAnimationAudio.playTogether( + iconsAnimator, + transformToSeekbar, + videoAdditionalAnimations + ); + + ViewGroup finalParent = parent; + ViewGroup.LayoutParams finalOldLayoutParams = oldLayoutParams; + runningAnimationAudio.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (finalParent != null) { + sizeNotifierLayout.removeView(recordedAudioPanel); + finalParent.addView(recordedAudioPanel, finalOldLayoutParams); + } + recordedAudioPanel.setAlpha(1.0f); + recordedAudioBackground.setAlpha(1f); + recordedAudioTimeTextView.setAlpha(1f); + recordedAudioPlayButton.setAlpha(1f); + recordedAudioPlayButton.setScaleY(1f); + recordedAudioPlayButton.setScaleX(1f); + recordedAudioSeekBar.setAlpha(1f); + + emojiButtonAlpha = emojiButtonScale = 0f; + updateEmojiButtonParams(); + + if (botCommandsMenuButton != null) { + botCommandsMenuButton.setAlpha(0f); + botCommandsMenuButton.setScaleX(0f); + botCommandsMenuButton.setScaleY(0f); + } + + if (controlsView != null && onceVisible && !voiceOnce && (MessagesController.getGlobalMainSettings().getInt("voiceoncehint", 0) < 3)) { + controlsView.showHintView(); + } + } + }); + } } else if (recordState == RECORD_STATE_CANCEL || recordState == RECORD_STATE_CANCEL_BY_GESTURE) { if (audioVideoSendButton != null) { @@ -8654,6 +8850,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } + public void setVoiceDraft(MediaDataController.DraftVoice draft) { + if (draft == null) return; + voiceOnce = draft.once; + if (controlsView != null) { + controlsView.periodDrawable.setValue(1, voiceOnce, true); + } + TL_stories.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; + MediaController.getInstance().prepareResumedRecording(currentAccount, draft, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, recordingGuid, true); + } + public void setSelection(int start) { if (messageEditText == null) { return; @@ -9873,6 +10079,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return stickersTabOpen && !(!stickersExpanded && messageEditText != null && messageEditText.length() > 0) && emojiView.areThereAnyStickers() && !waitingForKeyboardOpen; } }); + if (emojiView != null) { + emojiView.setStickersBanned(!sendPlainEnabled, !stickersEnabled, -dialog_id); + } attachEmojiView(); checkChannelRights(); } @@ -10614,10 +10823,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } if (state != RECORD_STATE_PREPARING) { - updateRecordInterface(state); + updateRecordInterface(state, true); } } else { - updateRecordInterface(RECORD_STATE_CANCEL); + updateRecordInterface(RECORD_STATE_CANCEL, true); } } } else if (id == NotificationCenter.recordStarted) { @@ -10632,7 +10841,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } if (!recordingAudioVideo) { recordingAudioVideo = true; - updateRecordInterface(RECORD_STATE_ENTER); + updateRecordInterface(RECORD_STATE_ENTER, true); } else if (recordCircle != null) { recordCircle.showWaves(true, true); } @@ -10651,7 +10860,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific videoToSendMessageObject = null; checkSendButton(true); recordingAudioVideo = true; - updateRecordInterface(RECORD_STATE_ENTER); + updateRecordInterface(RECORD_STATE_ENTER, true); } else if (id == NotificationCenter.audioDidSent) { int guid = (Integer) args[0]; if (guid != recordingGuid) { @@ -10673,11 +10882,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific videoTimelineView.setMinProgressDiff(1000.0f / videoToSendMessageObject.estimatedDuration); isRecordingStateChanged(); } - updateRecordInterface(RECORD_STATE_PREPARING); + updateRecordInterface(RECORD_STATE_PREPARING, true); checkSendButton(false); } else { audioToSend = (TLRPC.TL_document) args[1]; audioToSendPath = (String) args[2]; + boolean fromDraft = args.length >= 4 && (boolean) args[3]; if (audioToSend != null) { createRecordAudioPanel(); if (recordedAudioPanel == null) { @@ -10727,7 +10937,19 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific millisecondsRecorded = (long) (duration * 1000L); recordedAudioTimeTextView.setText(AndroidUtilities.formatShortDuration((int) (duration))); checkSendButton(false); - updateRecordInterface(RECORD_STATE_PREPARING); + if (fromDraft) { + createRecordCircle(); + createRecordPanel(); + createRecordAudioPanel(); + recordInterfaceState = 1; + recordCircle.resetLockTranslation(false); + recordControlsCircleScale.set(recordCircle, 1f); + if (controlsView != null) { + controlsView.setVisibility(VISIBLE); + controlsView.setAlpha(1f); + } + } + updateRecordInterface(RECORD_STATE_PREPARING, !fromDraft); } else { if (delegate != null) { delegate.onMessageSend(null, true, 0); @@ -10773,7 +10995,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific long did = (Long) args[3]; if (did == dialog_id && info != null && info.slowmode_seconds != 0) { TLRPC.Chat chat = accountInstance.getMessagesController().getChat(info.id); - if (chat != null && !ChatObject.hasAdminRights(chat)) { + if (chat != null && !ChatObject.hasAdminRights(chat) && !ChatObject.isIgnoredChatRestrictionsForBoosters(chat)) { info.slowmode_next_send_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + info.slowmode_seconds; info.flags |= 262144; setSlowModeTimer(info.slowmode_next_send_date); @@ -10786,7 +11008,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else if (id == NotificationCenter.audioRecordTooShort) { audioToSend = null; videoToSendMessageObject = null; - updateRecordInterface(RECORD_STATE_CANCEL_BY_TIME); + updateRecordInterface(RECORD_STATE_CANCEL_BY_TIME, true); } else if (id == NotificationCenter.updateBotMenuButton) { long botId = (long) args[0]; TLRPC.BotMenuButton botMenuButton = (TLRPC.BotMenuButton) args[1]; @@ -10971,7 +11193,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific stickersExpansionProgress = 1; setTranslationY(-(stickersExpandedHeight - origHeight)); emojiView.setTranslationY(-(stickersExpandedHeight - origHeight)); - stickersArrow.setAnimationProgress(1); + if (stickersArrow != null) { + stickersArrow.setAnimationProgress(1); + } } } else { if (stopAllHeavy) { @@ -11029,7 +11253,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific sizeNotifierLayout.requestLayout(); sizeNotifierLayout.setForeground(null); sizeNotifierLayout.setWillNotDraw(false); - stickersArrow.setAnimationProgress(0); + if (stickersArrow != null) { + stickersArrow.setAnimationProgress(0); + } } } if (expandStickersButton != null) { @@ -11203,7 +11429,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific videoToSendMessageObject = null; millisecondsRecorded = 0; recordingAudioVideo = false; - updateRecordInterface(RECORD_STATE_CANCEL); + MediaDataController.getInstance(currentAccount).pushDraftVoiceMessage(dialog_id, parentFragment != null && parentFragment.isTopic ? parentFragment.getTopicId() : 0, null); + updateRecordInterface(RECORD_STATE_CANCEL, true); checkSendButton(true); } 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 1ecdc91ef..4e1674b43 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -144,9 +144,16 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public boolean destroyed; public boolean allowEnterCaption; private ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate documentsDelegate; - private long dialogId; + public long dialogId; private boolean overrideBackgroundColor; + public TLRPC.Chat getChat() { + if (baseFragment instanceof ChatActivity) { + return ((ChatActivity) baseFragment).getCurrentChat(); + } else { + return MessagesController.getInstance(currentAccount).getChat(-dialogId); + } + } public void setCanOpenPreview(boolean canOpenPreview) { this.canOpenPreview = canOpenPreview; selectedArrowImageView.setVisibility(canOpenPreview && avatarPicker != 2 ? View.VISIBLE : View.GONE); @@ -2186,11 +2193,17 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N final Activity activity = lastFragment.getParentActivity(); int num = (Integer) view.getTag(); if (num == 1) { + if (!photosEnabled && !videosEnabled && checkCanRemoveRestrictionsByBoosts()) { + return; + } if (!photosEnabled && !videosEnabled) { showLayout(restrictedLayout = new ChatAttachRestrictedLayout(1, this, getContext(), resourcesProvider)); } showLayout(photoLayout); } else if (num == 3) { + if (!musicEnabled && checkCanRemoveRestrictionsByBoosts()) { + return; + } 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); @@ -2202,6 +2215,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } openAudioLayout(true); } else if (num == 4) { + if (!documentsEnabled && checkCanRemoveRestrictionsByBoosts()) { + return; + } 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) { @@ -2214,6 +2230,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } openDocumentsLayout(true); } else if (num == 5) { + if (!plainTextEnabled && checkCanRemoveRestrictionsByBoosts()) { + return; + } if (Build.VERSION.SDK_INT >= 23 && plainTextEnabled) { if (getContext().checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { AndroidUtilities.findActivity(getContext()).requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, BasePermissionsActivity.REQUEST_CODE_ATTACH_CONTACT); @@ -2222,6 +2241,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } openContactsLayout(); } else if (num == 6) { + if (!plainTextEnabled && checkCanRemoveRestrictionsByBoosts()) { + return; + } if (!AndroidUtilities.isMapsInstalled(baseFragment)) { return; } @@ -2236,6 +2258,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N showLayout(locationLayout); } } else if (num == 9) { + if (!pollsEnabled && checkCanRemoveRestrictionsByBoosts()) { + return; + } if (!pollsEnabled) { restrictedLayout = new ChatAttachRestrictedLayout(9, this, getContext(), resourcesProvider); showLayout(restrictedLayout); @@ -3230,6 +3255,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N showLayout(contactsLayout); } + public boolean checkCanRemoveRestrictionsByBoosts() { + return (baseFragment instanceof ChatActivity) && ((ChatActivity) baseFragment).checkCanRemoveRestrictionsByBoosts(); + } + private void openAudioLayout(boolean show) { if (!musicEnabled) { if (show) { @@ -4119,9 +4148,20 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N shadow.setAlpha(1f); shadow.setTranslationY(0); - if (baseFragment instanceof ChatActivity && avatarPicker != 2) { - TLRPC.Chat chat = ((ChatActivity) baseFragment).getCurrentChat(); - TLRPC.User user = ((ChatActivity) baseFragment).getCurrentUser(); + TLRPC.Chat chat = null; + TLRPC.User user = null; + if (avatarPicker != 2) { + if (baseFragment instanceof ChatActivity) { + chat = ((ChatActivity) baseFragment).getCurrentChat(); + user = ((ChatActivity) baseFragment).getCurrentUser(); + } else if (dialogId >= 0) { + user = MessagesController.getInstance(currentAccount).getUser(dialogId); + } else if (dialogId < 0) { + chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + } + } + + if (baseFragment instanceof ChatActivity && avatarPicker != 2 || (chat != null || user != null)) { if (chat != null) { // mediaEnabled = ChatObject.canSendMedia(chat); photosEnabled = ChatObject.canSendPhoto(chat); @@ -4133,12 +4173,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { pollsEnabled = user != null && user.bot; } - } else { - if (allowEnterCaption) { - commentTextView.setVisibility(View.VISIBLE); - } else { - commentTextView.setVisibility(View.INVISIBLE); - } + } + if (!(baseFragment instanceof ChatActivity && avatarPicker != 2)) { + commentTextView.setVisibility(allowEnterCaption ? View.VISIBLE : View.INVISIBLE); } photoLayout.onInit(videosEnabled, photosEnabled, documentsEnabled); commentTextView.hidePopup(true); @@ -4238,6 +4275,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N currentAttachLayout.onOpenAnimationEnd(); AndroidUtilities.makeAccessibilityAnnouncement(LocaleController.getString("AccDescrAttachButton", R.string.AccDescrAttachButton)); openTransitionFinished = true; + if (!videosEnabled && !photosEnabled) { + checkCanRemoveRestrictionsByBoosts(); + } } @Override 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 5950d27db..c37940f51 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -82,6 +82,7 @@ import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.camera.CameraController; import org.telegram.messenger.camera.CameraSession; +import org.telegram.messenger.camera.CameraSessionWrapper; import org.telegram.messenger.camera.CameraView; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -1032,7 +1033,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou return; } openPhotoViewer(null, false, false); - CameraController.getInstance().stopPreview(cameraView.getCameraSession()); + CameraController.getInstance().stopPreview(cameraView.getCameraSessionObject()); }); zoomControlView = new ZoomControlView(context); @@ -1094,7 +1095,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou AndroidUtilities.runOnUIThread(videoRecordRunnable, 1000); }; AndroidUtilities.lockOrientation(baseFragment.getParentActivity()); - CameraController.getInstance().recordVideo(cameraView.getCameraSession(), outputFile, parentAlert.avatarPicker != 0, (thumbPath, duration) -> { + CameraController.getInstance().recordVideo(cameraView.getCameraSessionObject(), outputFile, parentAlert.avatarPicker != 0, (thumbPath, duration) -> { if (outputFile == null || parentAlert.destroyed || cameraView == null) { return; } @@ -1151,7 +1152,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou final File cameraFile = AndroidUtilities.generatePicturePath(parentAlert.baseFragment instanceof ChatActivity && ((ChatActivity) parentAlert.baseFragment).isSecretChat(), null); final boolean sameTakePictureOrientation = cameraView.getCameraSession().isSameTakePictureOrientation(); cameraView.getCameraSession().setFlipFront(parentAlert.baseFragment instanceof ChatActivity || parentAlert.avatarPicker == 2); - takingPhoto = CameraController.getInstance().takePicture(cameraFile, false, cameraView.getCameraSession(), (orientation) -> { + takingPhoto = CameraController.getInstance().takePicture(cameraFile, false, cameraView.getCameraSessionObject(), (orientation) -> { takingPhoto = false; if (cameraFile == null || parentAlert.destroyed) { return; @@ -1484,11 +1485,17 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou private boolean checkSendMediaEnabled(MediaController.PhotoEntry photoEntry) { if (!videoEnabled && photoEntry.isVideo) { + if (parentAlert.checkCanRemoveRestrictionsByBoosts()) { + return true; + } BulletinFactory.of(parentAlert.sizeNotifierFrameLayout, resourcesProvider).createErrorBulletin( LocaleController.getString("GlobalAttachVideoRestricted", R.string.GlobalAttachVideoRestricted) ).show(); return true; } else if (!photoEnabled && !photoEntry.isVideo) { + if (parentAlert.checkCanRemoveRestrictionsByBoosts()) { + return true; + } BulletinFactory.of(parentAlert.sizeNotifierFrameLayout, resourcesProvider).createErrorBulletin( LocaleController.getString("GlobalAttachPhotoRestricted", R.string.GlobalAttachPhotoRestricted) ).show(); @@ -1744,7 +1751,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou zoomControlView.setZoom(0.0f, false); cameraZoom = 0.0f; cameraView.setZoom(0.0f); - CameraController.getInstance().startPreview(cameraView.getCameraSession()); + CameraController.getInstance().startPreview(cameraView.getCameraSessionObject()); } return; } @@ -2288,6 +2295,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou public void onCameraInit() { String current = cameraView.getCameraSession().getCurrentFlashMode(); String next = cameraView.getCameraSession().getNextFlashMode(); + if (current == null || next == null) return; if (current.equals(next)) { for (int a = 0; a < 2; a++) { flashModeButton[a].setVisibility(View.INVISIBLE); @@ -3002,9 +3010,8 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou @Override void onMenuItemClick(int id) { if (id == group || id == compress) { - if (parentAlert.maxSelectedPhotos > 0 && selectedPhotosOrder.size() > 1 && parentAlert.baseFragment instanceof ChatActivity) { - ChatActivity chatActivity = (ChatActivity) parentAlert.baseFragment; - TLRPC.Chat chat = chatActivity.getCurrentChat(); + if (parentAlert.maxSelectedPhotos > 0 && selectedPhotosOrder.size() > 1) { + TLRPC.Chat chat = parentAlert.getChat(); if (chat != null && !ChatObject.hasAdminRights(chat) && chat.slowmode_enabled) { AlertsCreator.createSimpleAlert(getContext(), LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSendError", R.string.SlowmodeSendError), resourcesProvider).show(); return; @@ -3325,13 +3332,13 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou cameraIcon.setAlpha(mediaEnabled ? 1.0f : 0.2f); cameraIcon.setEnabled(mediaEnabled); } - if (parentAlert.baseFragment instanceof ChatActivity && parentAlert.avatarPicker == 0) { + if ((parentAlert.baseFragment instanceof ChatActivity || parentAlert.getChat() != null) && parentAlert.avatarPicker == 0) { galleryAlbumEntry = MediaController.allMediaAlbumEntry; if (mediaEnabled) { progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); progressView.setLottie(0, 0, 0); } else { - TLRPC.Chat chat = ((ChatActivity) parentAlert.baseFragment).getCurrentChat(); + TLRPC.Chat chat = parentAlert.getChat(); progressView.setLottie(R.raw.media_forbidden, 150, 150); if (ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_MEDIA)) { progressView.setText(LocaleController.getString("GlobalAttachMediaRestricted", R.string.GlobalAttachMediaRestricted)); @@ -3538,10 +3545,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou private void pauseCameraPreview() { try { if (cameraView != null) { - CameraSession cameraSession = cameraView.getCameraSession(); - if (cameraSession != null) { - CameraController.getInstance().stopPreview(cameraSession); - } + CameraController.getInstance().stopPreview(cameraView.getCameraSessionObject()); } } catch (Exception e) { FileLog.e(e); @@ -3552,10 +3556,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou try { checkCamera(false); if (cameraView != null) { - CameraSession cameraSession = cameraView.getCameraSession(); - if (cameraSession != null) { - CameraController.getInstance().startPreview(cameraSession); - } + CameraController.getInstance().startPreview(cameraView.getCameraSessionObject()); } } catch (Exception e) { FileLog.e(e); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java index 133099d36..ea398a9cc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java @@ -15,6 +15,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -39,7 +40,7 @@ public class ChatAttachRestrictedLayout extends ChatAttachAlert.AttachAlertLayou addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); progressView.setLottie(R.raw.media_forbidden, 150, 150); - TLRPC.Chat chat = ((ChatActivity) parentAlert.baseFragment).getCurrentChat(); + TLRPC.Chat chat = parentAlert.getChat(); if (id == 1) { progressView.setText(ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_MEDIA)); } else if (id == 3) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java index d9b6b1cf6..8c41096a2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -316,14 +316,6 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } emojiStatusDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(titleTextView, AndroidUtilities.dp(24)); - - setOnLongClickListener(v -> { - if (canSearch()) { - openSearch(); - return true; - } - return false; - }); } private ButtonBounce bounce = new ButtonBounce(this); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java index e0a9e0091..72bf507e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java @@ -12,6 +12,7 @@ import android.graphics.PorterDuffColorFilter; import android.text.Layout; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; @@ -75,6 +76,7 @@ public class ChatGreetingsView extends LinearLayout { descriptionView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); descriptionView.setGravity(Gravity.CENTER_HORIZONTAL); stickerToSendView = new BackupImageView(context); + ScaleStateListAnimator.apply(stickerToSendView); updateLayout(); updateColors(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java index 4f2ad0a0b..f1b1ddbaa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java @@ -934,16 +934,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen limitReachedBottomSheet.setDialogId(chatActivity.getDialogId()); limitReachedBottomSheet.showStatisticButtonInLink(() -> { TLRPC.Chat chat = chatActivity.getMessagesController().getChat(-chatActivity.getDialogId()); - Bundle args = new Bundle(); - args.putLong("chat_id", -chatActivity.getDialogId()); - args.putBoolean("is_megagroup", chat.megagroup); - args.putBoolean("start_from_boosts", true); - TLRPC.ChatFull chatInfo = chatActivity.getMessagesController().getChatFull(-chatActivity.getDialogId()); - if (chatInfo == null || !chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - }; - StatisticActivity fragment = new StatisticActivity(args); - showAsSheet(fragment); + showAsSheet(StatisticActivity.create(chat)); }); limitReachedBottomSheet.show(); }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java index cf43d6dad..353145099 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java @@ -307,7 +307,7 @@ public class EditTextEmoji extends FrameLayout implements NotificationCenter.Not } } else if (!isPopupShowing()) { showPopup(1); - emojiView.onOpen(editText.length() > 0); + emojiView.onOpen(editText.length() > 0, false); editText.requestFocus(); } else { openKeyboardInternal(); 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 ec05c3f38..16c8a85f3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java @@ -500,6 +500,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { } else { currentPackButton.setAnimatedEmojiDocument(thumbDocument); } + currentPackButton.id = newPack.forGroup ? (long) "forGroup".hashCode() : null; currentPackButton.updateSelect(selected == i, false); if (currentType == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR || currentType == SelectAnimatedEmojiDialog.TYPE_CHAT_REACTIONS || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM) { currentPackButton.setLock(null, false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java index f87e28cb7..396605f12 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -34,7 +34,6 @@ 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.graphics.drawable.LayerDrawable; @@ -49,29 +48,24 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; -import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; -import android.view.KeyEvent; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewOutlineProvider; -import android.view.ViewTreeObserver; -import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.OvershootInterpolator; import android.view.inputmethod.EditorInfo; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.PopupWindow; import android.widget.TextView; import androidx.annotation.IntDef; @@ -134,14 +128,12 @@ import org.telegram.ui.Cells.StickerSetNameCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.ListView.RecyclerListViewWithOverlayDraw; import org.telegram.ui.Components.Premium.PremiumButtonView; -import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.ContentPreviewViewer; import org.telegram.ui.SelectAnimatedEmojiDialog; import org.telegram.ui.StickersActivity; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -149,7 +141,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -1282,6 +1273,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific long documentId = imageViewEmoji.getSpan().documentId; TLRPC.Document document = imageViewEmoji.getSpan().document; String emoticon = null; + boolean isGroupEmojis = imageViewEmoji.pack != null && imageViewEmoji.pack.forGroup; if (document == null) { for (int i = 0; i < emojipacksProcessed.size(); ++i) { EmojiPack pack = emojipacksProcessed.get(i); @@ -1299,7 +1291,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (emoticon == null && document != null) { emoticon = MessageObject.findAnimatedEmojiEmoticon(document); } - if (!MessageObject.isFreeEmoji(document) && !UserConfig.getInstance(currentAccount).isPremium() && !(delegate != null && delegate.isUserSelf()) && !allowEmojisForNonPremium) { + if (!MessageObject.isFreeEmoji(document) && !UserConfig.getInstance(currentAccount).isPremium() && !(delegate != null && delegate.isUserSelf()) && !allowEmojisForNonPremium && !isGroupEmojis) { showBottomTab(false, true); BulletinFactory factory = fragment != null ? BulletinFactory.of(fragment) : BulletinFactory.of(bulletinContainer, resourcesProvider); if (premiumBulletin || fragment == null) { @@ -3610,6 +3602,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific RLottieImageView lockView; SimpleTextView headerView; + TextView markView; FrameLayout buttonsView; TextView addButtonView; @@ -3638,8 +3631,17 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific openEmojiPackAlert(this.pack.set); } }); + markView = new TextView(context); + markView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11); + markView.setTextColor(getThemedColor(Theme.key_chat_emojiPanelStickerSetName)); + markView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + markView.setBackground(Theme.createRoundRectDrawable(dp(8), Theme.multAlpha(getThemedColor(Theme.key_chat_emojiPanelIcon), .12f))); + markView.setPadding(dp(6), dp(1.5f), dp(6), dp(1.5f)); + markView.setText(LocaleController.getString(R.string.GroupEmoji)); + headerView.setEllipsizeByGradient(true); addView(headerView, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.START, 15, 15, 0, 0)); + addView(markView, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START, 15, 10, 0, 0)); buttonsView = new FrameLayout(context); buttonsView.setPadding(AndroidUtilities.dp(11), AndroidUtilities.dp(11), AndroidUtilities.dp(11), 0); @@ -3778,7 +3780,15 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - headerView.setRightPadding(buttonsView.getWidth() + AndroidUtilities.dp(11)); + int padding = buttonsView.getWidth() + AndroidUtilities.dp(11) + (markView.getVisibility() == View.VISIBLE ? markView.getMeasuredWidth() : 0); + headerView.setRightPadding(padding); + if (markView.getVisibility() == View.VISIBLE) { + markView.setTranslationX(headerView.getTextWidth() + dp(4)); + int max = headerView.getMaxTextWidth() - padding + dp(4); + if (markView.getTranslationX() > max) { + markView.setTranslationX(max); + } + } } public void setStickerSet(EmojiPack pack, boolean divider) { @@ -3789,6 +3799,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific this.pack = pack; this.divider = divider; headerView.setText(pack.set.title); + markView.setVisibility(pack.forGroup ? View.VISIBLE : View.GONE); if (pack.installed && !pack.set.official) { premiumButtonView.setButton(LocaleController.getString("Restore", R.string.Restore), e -> openPremiumAnimatedEmojiFeature()); @@ -5632,7 +5643,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific forseMultiwindowLayout = value; } - public void onOpen(boolean forceEmoji) { + public void onOpen(boolean forceEmoji, boolean groupEmojiHintWasVisible) { if (currentPage != 0 && stickersBanned) { currentPage = 0; } @@ -5645,6 +5656,21 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (pager.getCurrentItem() != 0) { pager.setCurrentItem(0, !forceEmoji); } + if (groupEmojiHintWasVisible) { + AndroidUtilities.runOnUIThread(() -> { + ArrayList packs = getEmojipacks(); + for (int i = 0; i < packs.size(); i++) { + EmojiPack pack = packs.get(i); + if (pack.forGroup) { + int pos = emojiAdapter.sectionToPosition.get(i + EmojiData.dataColored.length); + emojiGridView.stopScroll(); + updateEmojiTabsPosition(pos); + scrollEmojisToPosition(pos, dp(-9)); + checkEmojiTabY(null, 0); + } + } + }, 350); + } } else if (currentPage == 1) { showBackspaceButton(false, false); showStickerSettingsButton(shouldDrawBackground, false); @@ -5684,6 +5710,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific super.onAttachedToWindow(); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.newEmojiSuggestionsAvailable); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.groupPackUpdated); if (stickersGridAdapter != null) { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.stickersDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recentDocumentsDidLoad); @@ -5734,6 +5761,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.newEmojiSuggestionsAvailable); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.stickersDidLoad); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.groupPackUpdated); if (stickersGridAdapter != null) { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recentDocumentsDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.featuredStickersDidLoad); @@ -5851,6 +5879,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (show) { if (!ChatObject.hasAdminRights(chat) && chat.default_banned_rights != null && (chat.default_banned_rights.send_stickers || (emoji && chat.default_banned_rights.send_plain))) { + if (fragment instanceof ChatActivity && ((ChatActivity) fragment).checkCanRemoveRestrictionsByBoosts()) { + return; + } if (emoji) { mediaBanTooltip.setText(LocaleController.getString("GlobalAttachEmojiRestricted", R.string.GlobalAttachEmojiRestricted)); } else if (gif) { @@ -5980,6 +6011,12 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific emojiAdapter.notifyDataSetChanged(false); } } + } else if (id == NotificationCenter.groupPackUpdated) { + long chatId = (long) args[0]; + boolean isEmoji = (boolean) args[1]; + if (info != null && info.id == chatId && isEmoji) { + emojiAdapter.notifyDataSetChanged(true); + } } else if (id == NotificationCenter.recentDocumentsDidLoad) { boolean isGif = (Boolean) args[0]; int type = (Integer) args[1]; @@ -6671,6 +6708,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific public boolean installed; public boolean featured; public boolean expanded; + public boolean forGroup; public int resId; } @@ -6986,6 +7024,16 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific return VIEW_TYPE_EMOJI; } + private void removeGroupEmojiPackFromInstalled(TLRPC.StickerSet pack, ArrayList installedEmojipacks) { + for (int i = 0; i < installedEmojipacks.size(); i++) { + TLRPC.TL_messages_stickerSet set = installedEmojipacks.get(i); + if (set != null && set.set.id == pack.id) { + installedEmojipacks.remove(i); + break; + } + } + } + public void processEmoji(boolean updateEmojipacks) { emojipacksProcessed.clear(); if (!allowAnimatedEmoji) { @@ -6999,6 +7047,24 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific ArrayList installedEmojipacks = frozenEmojiPacks; boolean isPremium = UserConfig.getInstance(currentAccount).isPremium() || allowEmojisForNonPremium; int index = 0; + + if (info != null && info.emojiset != null) { + TLRPC.TL_messages_stickerSet stickerSet = mediaDataController.getGroupStickerSetById(info.emojiset); + if (stickerSet != null) { + EmojiPack pack = new EmojiPack(); + pack.index = index++; + pack.set = info.emojiset; + pack.documents = new ArrayList<>(stickerSet.documents); + pack.free = true; + pack.installed = true; + pack.featured = false; + pack.expanded = true; + pack.forGroup = true; + emojipacksProcessed.add(pack); + removeGroupEmojiPackFromInstalled(pack.set, installedEmojipacks); + } + } + if (!isPremium) { for (int i = 0; i < installedEmojipacks.size(); ++i) { TLRPC.TL_messages_stickerSet set = installedEmojipacks.get(i); @@ -7224,7 +7290,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (!pack.expanded && pack.documents.size() > maxlen) { count--; } - rowHashCodes.add(Objects.hash(pack.featured ? 56345 : -495231, (pack.set == null ? b : pack.set.id))); + rowHashCodes.add(Objects.hash(pack.featured ? 56345 : -495231, (pack.set == null ? b : pack.set.id), pack.forGroup)); for (int i = 1; i < count; ++i) { rowHashCodes.add(Objects.hash(pack.featured ? 3442 : -9964, pack.documents.get(i - 1).id)); } @@ -7234,11 +7300,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific rowHashCodes.add(Objects.hash(pack.featured ? -65174 : 92242, pack.set.id)); itemCount++; } -// if (!pack.installed) { -// positionToUnlock.put(itemCount, b); -// itemCount++; -// rowHashCodes.add(Objects.hash(7, pack.set.id)); -// } } } } 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 05169bdd7..86f720c5d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java @@ -89,6 +89,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; +import org.telegram.messenger.camera.Camera2Session; import org.telegram.messenger.camera.CameraController; import org.telegram.messenger.camera.CameraInfo; import org.telegram.messenger.camera.CameraSession; @@ -99,6 +100,7 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.voip.CellFlickerDrawable; +import org.telegram.ui.Stories.recorder.DualCameraView; import org.telegram.ui.Stories.recorder.StoryEntry; import java.io.File; @@ -168,14 +170,26 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private boolean cancelled; private CameraGLThread cameraThread; + private volatile int previewWidth, previewHeight; private Size previewSize; private Size pictureSize; private Size aspectRatio = SharedConfig.roundCamera16to9 ? new Size(16, 9) : new Size(4, 3); private TextureView textureView; private BackupImageView textureOverlayView; + private final boolean useCamera2 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.useCamera2; + private final boolean supportHotSwap = useCamera2 && DualCameraView.dualAvailableStatic(ApplicationLoader.applicationContext); private CameraSession cameraSession; + private Camera2Session camera2Session; private boolean needDrawFlickerStub; + private boolean isCameraSessionInitiated() { + if (useCamera2) { + return camera2Session != null && camera2Session.isInitiated(); + } else { + return cameraSession != null && cameraSession.isInitied(); + } + } + private float panTranslationY; private float animationTranslationY; @@ -330,7 +344,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter switchCameraButton.setContentDescription(LocaleController.getString("AccDescrSwitchCamera", R.string.AccDescrSwitchCamera)); addView(switchCameraButton, LayoutHelper.createFrame(62, 62, Gravity.LEFT | Gravity.BOTTOM, 8, 0, 0, 0)); switchCameraButton.setOnClickListener(v -> { - if (!cameraReady || cameraSession == null || !cameraSession.isInitied() || cameraThread == null) { + if (!cameraReady || !isCameraSessionInitiated() || cameraThread == null) { return; } switchCamera(); @@ -487,10 +501,17 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } - public void destroy(boolean async, final Runnable beforeDestroyRunnable) { - if (cameraSession != null) { - cameraSession.destroy(); - CameraController.getInstance().close(cameraSession, !async ? new CountDownLatch(1) : null, beforeDestroyRunnable); + public void destroy(boolean async) { + if (useCamera2) { + if (camera2Session != null) { + camera2Session.destroy(async); + camera2Session = null; + } + } else { + if (cameraSession != null) { + cameraSession.destroy(); + CameraController.getInstance().close(cameraSession, !async ? new CountDownLatch(1) : null, null); + } } } @@ -666,6 +687,13 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter FileLog.d("InstantCamera show round camera " + cameraFile.getAbsolutePath()); } + if (useCamera2) { + camera2Session = Camera2Session.create(true, isFrontface, AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize); + if (camera2Session == null) return; + camera2Session.setRecordingVideo(true); + previewWidth = camera2Session.getPreviewWidth(); + previewHeight = camera2Session.getPreviewHeight(); + } textureView = new TextureView(getContext()); textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override @@ -699,8 +727,14 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter cameraThread.shutdown(0, 0); cameraThread = null; } - if (cameraSession != null) { - CameraController.getInstance().close(cameraSession, null, null); + if (useCamera2) { + if (camera2Session != null) { + camera2Session.destroy(false); + } + } else { + if (cameraSession != null) { + CameraController.getInstance().close(cameraSession, null, null); + } } return true; } @@ -957,7 +991,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } public void hideCamera(boolean async) { - destroy(async, null); + destroy(async); cameraContainer.setTranslationX(0); textureOverlayView.setTranslationX(0); animationTranslationY = 0; @@ -981,18 +1015,36 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter textureOverlayView.setImageBitmap(lastBitmap); textureOverlayView.setAlpha(1f); } - if (cameraSession != null) { - cameraSession.destroy(); - CameraController.getInstance().close(cameraSession, null, null); - cameraSession = null; - } isFrontface = !isFrontface; + if (useCamera2) { + if (camera2Session != null) { + camera2Session.destroy(false); + camera2Session = null; + } + camera2Session = Camera2Session.create(true, isFrontface, AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize); + if (camera2Session == null) return; + camera2Session.setRecordingVideo(true); + previewWidth = camera2Session.getPreviewWidth(); + previewHeight = camera2Session.getPreviewHeight(); + cameraThread.setCurrentSession(camera2Session); + } else { + if (cameraSession != null) { + cameraSession.destroy(); + CameraController.getInstance().close(cameraSession, null, null); + cameraSession = null; + } + } initCamera(); cameraReady = false; cameraThread.reinitForNewCamera(); } + // Old Camera1 API + @Deprecated private boolean initCamera() { + if (useCamera2) { + return true; + } ArrayList cameraInfos = CameraController.getInstance().getCameras(); if (cameraInfos == null) { return false; @@ -1063,6 +1115,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return true; } + @Deprecated // used for old Camera1 API only private Size chooseOptimalSize(ArrayList previewSizes) { ArrayList sortedSizes = new ArrayList<>(); boolean allowBigSizeCamera = allowBigSizeCamera(); @@ -1103,6 +1156,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return sortedSizes.get(0); } + @Deprecated // used for old Camera1 API only private boolean allowBigSizeCamera() { if (SharedConfig.bigCameraForRound) { return true; @@ -1123,6 +1177,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return false; } + @Deprecated // used for old Camera1 API only public static boolean allowBigSizeCameraDebug() { int devicePerformanceClass = Math.max(SharedConfig.getDevicePerformanceClass(), SharedConfig.getLegacyDevicePerformanceClass()); if (devicePerformanceClass == SharedConfig.PERFORMANCE_CLASS_HIGH) { @@ -1146,47 +1201,52 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter FileLog.d("InstantCamera create camera session"); } - surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); - cameraSession = new CameraSession(selectedCamera, previewSize, pictureSize, ImageFormat.JPEG, true); - cameraThread.setCurrentSession(cameraSession); - CameraController.getInstance().openRound(cameraSession, surfaceTexture, () -> { - if (cameraSession != null) { - boolean updateScale = false; - try { - Camera.Size size = cameraSession.getCurrentPreviewSize(); - if (size.width != previewSize.getWidth() || size.height != previewSize.getHeight()) { - previewSize = new Size(size.width, size.height); - FileLog.d("InstantCamera change preview size to w = " + previewSize.getWidth() + " h = " + previewSize.getHeight()); + if (useCamera2) { + cameraThread.setCurrentSession(camera2Session); + camera2Session.open(surfaceTexture); + } else { + surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); + cameraSession = new CameraSession(selectedCamera, previewSize, pictureSize, ImageFormat.JPEG, true); + cameraThread.setCurrentSession(cameraSession); + CameraController.getInstance().openRound(cameraSession, surfaceTexture, () -> { + if (cameraSession != null) { + boolean updateScale = false; + try { + Camera.Size size = cameraSession.getCurrentPreviewSize(); + if (size.width != previewSize.getWidth() || size.height != previewSize.getHeight()) { + previewSize = new Size(size.width, size.height); + FileLog.d("InstantCamera change preview size to w = " + previewSize.getWidth() + " h = " + previewSize.getHeight()); + } + } catch (Exception e) { + FileLog.e(e); } - } catch (Exception e) { - FileLog.e(e); - } - try { - Camera.Size size = cameraSession.getCurrentPictureSize(); - if (size.width != pictureSize.getWidth() || size.height != pictureSize.getHeight()) { - pictureSize = new Size(size.width, size.height); - FileLog.d("InstantCamera change picture size to w = " + pictureSize.getWidth() + " h = " + pictureSize.getHeight()); - updateScale = true; + try { + Camera.Size size = cameraSession.getCurrentPictureSize(); + if (size.width != pictureSize.getWidth() || size.height != pictureSize.getHeight()) { + pictureSize = new Size(size.width, size.height); + FileLog.d("InstantCamera change picture size to w = " + pictureSize.getWidth() + " h = " + pictureSize.getHeight()); + updateScale = true; + } + } catch (Exception e) { + FileLog.e(e); } - } catch (Exception e) { - FileLog.e(e); - } - if (BuildVars.LOGS_ENABLED) { - FileLog.d("InstantCamera camera initied"); - } - cameraSession.setInitied(); - if (updateScale) { - if (cameraThread != null) { - cameraThread.reinitForNewCamera(); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("InstantCamera camera initied"); + } + cameraSession.setInitied(); + if (updateScale) { + if (cameraThread != null) { + cameraThread.reinitForNewCamera(); + } } } - } - }, () -> { - if (cameraThread != null) { - cameraThread.setCurrentSession(cameraSession); - } - }); + }, () -> { + if (cameraThread != null) { + cameraThread.setCurrentSession(cameraSession); + } + }); + } }); } @@ -1293,7 +1353,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private EGLSurface eglSurface; private boolean initied; - private CameraSession currentSession; + private Object currentSession; private SurfaceTexture cameraSurface; @@ -1326,8 +1386,18 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } private void updateScale() { - int width = previewSize.getWidth(); - int height = previewSize.getHeight(); + int width, height; + if (useCamera2) { + width = previewWidth; + height = previewHeight; + } else { + if (previewSize != null) { + width = previewSize.getWidth(); + height = previewSize.getHeight(); + } else { + return; + } + } float scale = surfaceWidth / (float) Math.min(width, height); @@ -1552,6 +1622,13 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } + public void setCurrentSession(Camera2Session session) { + Handler handler = getHandler(); + if (handler != null) { + sendMessage(handler.obtainMessage(DO_SETSESSION_MESSAGE, session), 0); + } + } + private void onDraw(Integer cameraId) { if (!initied) { return; @@ -1581,7 +1658,14 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter captureFirstFrameThumb = true; } videoEncoder.startRecording(cameraFile, EGL14.eglGetCurrentContext()); - int orientation = currentSession.getCurrentOrientation(); + int orientation; + if (currentSession instanceof CameraSession) { + orientation = ((CameraSession) currentSession).getCurrentOrientation(); + } else if (currentSession instanceof Camera2Session) { + orientation = ((Camera2Session) currentSession).getCurrentOrientation(); + } else { + orientation = 0; + } if (orientation == 90 || orientation == 270) { float temp = scaleX; scaleX = scaleY; @@ -1688,7 +1772,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter cameraSurface.setOnFrameAvailableListener(surfaceTexture -> requestRender()); createCamera(cameraSurface); - cameraThread.updateScale(); + updateScale(); float tX = 1.0f / scaleX / 2.0f; float tY = 1.0f / scaleY / 2.0f; @@ -1708,9 +1792,16 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter if (BuildVars.LOGS_ENABLED) { FileLog.d("InstantCamera set gl rednderer session"); } - CameraSession newSession = (CameraSession) inputMessage.obj; + Object newSession = inputMessage.obj; if (currentSession == newSession) { - int rotationAngle = currentSession.getWorldAngle(); + int rotationAngle; + if (currentSession instanceof CameraSession) { + rotationAngle = ((CameraSession) currentSession).getWorldAngle(); + } else if (currentSession instanceof Camera2Session) { + rotationAngle = ((Camera2Session) currentSession).getWorldAngle(); + } else { + rotationAngle = 0; + } android.opengl.Matrix.setIdentityM(mMVPMatrix, 0); if (rotationAngle != 0) { android.opengl.Matrix.rotateM(mMVPMatrix, 0, rotationAngle, 0, 0, 1); @@ -1718,6 +1809,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } else { currentSession = newSession; } + updateScale(); break; } } @@ -3021,6 +3113,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER); + Size previewSize = InstantCameraView.this.previewSize; + if (previewSize == null && useCamera2) { + previewSize = new Size(previewWidth, previewHeight); + } int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, createFragmentShader(previewSize)); if (vertexShader != 0 && fragmentShader != 0) { drawProgram = GLES20.glCreateProgram(); @@ -3280,7 +3376,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } private String createFragmentShader(Size previewSize) { - if (SharedConfig.deviceIsLow() || !allowBigSizeCamera() || Math.max(previewSize.getHeight(), previewSize.getWidth()) * 0.7f < MessagesController.getInstance(currentAccount).roundVideoSize) { + if (useCamera2) { + // TODO: lanczos + } + if (SharedConfig.deviceIsLow() || !allowBigSizeCamera() || previewSize != null && Math.max(previewSize.getHeight(), previewSize.getWidth()) * 0.7f < MessagesController.getInstance(currentAccount).roundVideoSize) { return "#extension GL_OES_EGL_image_external : require\n" + "precision highp float;\n" + "varying vec2 vTextureCoord;\n" + @@ -3443,9 +3542,15 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return false; } pinchScale = (float) Math.hypot(ev.getX(index2) - ev.getX(index1), ev.getY(index2) - ev.getY(index1)) / pinchStartDistance; - float zoom = Math.min(1f, Math.max(0, pinchScale - 1f)); - - cameraSession.setZoom(zoom); + if (useCamera2) { + if (camera2Session != null) { + float zoom = Utilities.clamp(pinchScale, camera2Session.getMaxZoom(), camera2Session.getMinZoom()); + camera2Session.setZoom(zoom); + } + } else { + float zoom = Math.min(1f, Math.max(0, pinchScale - 1f)); + cameraSession.setZoom(zoom); + } } else if ((ev.getActionMasked() == MotionEvent.ACTION_UP || (ev.getActionMasked() == MotionEvent.ACTION_POINTER_UP && checkPointerIds(ev)) || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) && isInPinchToZoomTouchMode) { isInPinchToZoomTouchMode = false; finishZoom(); @@ -3460,13 +3565,25 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return; } - float zoom = Math.min(1f, Math.max(0, pinchScale - 1f)); + float zoom; + if (useCamera2) { + if (camera2Session == null) return; + zoom = Utilities.clamp(pinchScale, camera2Session.getMaxZoom(), camera2Session.getMinZoom()); + } else { + zoom = Math.min(1f, Math.max(0, pinchScale - 1f)); + } if (zoom > 0f) { finishZoomTransition = ValueAnimator.ofFloat(zoom, 0); finishZoomTransition.addUpdateListener(valueAnimator -> { - if (cameraSession != null) { - cameraSession.setZoom((float) valueAnimator.getAnimatedValue()); + if (useCamera2) { + if (camera2Session != null) { + camera2Session.setZoom((float) valueAnimator.getAnimatedValue()); + } + } else { + if (cameraSession != null) { + cameraSession.setZoom((float) valueAnimator.getAnimatedValue()); + } } }); finishZoomTransition.addListener(new AnimatorListenerAdapter() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinGroupAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinGroupAlert.java index ecb09bb49..2ea2bdd82 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinGroupAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinGroupAlert.java @@ -37,11 +37,13 @@ import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; -import androidx.core.content.ContextCompat; import androidx.core.widget.NestedScrollView; public class JoinGroupAlert extends BottomSheet { + public static final int ORIGINATION_OTHER = -1; + public static final int ORIGINATION_SPONSORED_CHAT = 0; + private final String hash; private final BaseFragment fragment; private TLRPC.ChatInvite chatInvite; @@ -50,6 +52,10 @@ public class JoinGroupAlert extends BottomSheet { private RadialProgressView requestProgressView; public JoinGroupAlert(final Context context, TLObject obj, String group, BaseFragment parentFragment, Theme.ResourcesProvider resourcesProvider) { + this(context, obj, group, parentFragment, resourcesProvider, ORIGINATION_OTHER); + } + + public JoinGroupAlert(final Context context, TLObject obj, String group, BaseFragment parentFragment, Theme.ResourcesProvider resourcesProvider, int origination) { super(context, false, resourcesProvider); setApplyBottomPadding(false); setApplyTopPadding(false); @@ -146,10 +152,15 @@ public class JoinGroupAlert extends BottomSheet { textView.setTextColor(getThemedColor(Theme.key_dialogTextGray3)); textView.setSingleLine(true); textView.setEllipsize(TextUtils.TruncateAt.END); - textView.setText(isChannel - ? LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate).toLowerCase() - : LocaleController.getString("MegaPrivate", R.string.MegaPrivate).toLowerCase() - ); + + if (chatInvite != null && origination == ORIGINATION_SPONSORED_CHAT) { + textView.setText(LocaleController.getString("ChannelPublic", R.string.ChannelPublic).toLowerCase()); + } else { + textView.setText(isChannel + ? LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate).toLowerCase() + : LocaleController.getString("MegaPrivate", R.string.MegaPrivate).toLowerCase() + ); + } linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 10, 0, 10, hasAbout ? 0 : 20)); if (hasAbout) { @@ -317,15 +328,14 @@ public class JoinGroupAlert extends BottomSheet { chat.kicked = false; MessagesController.getInstance(currentAccount).putUsers(updates.users, false); MessagesController.getInstance(currentAccount).putChats(updates.chats, false); - Bundle args = new Bundle(); - args.putLong("chat_id", chat.id); - if (MessagesController.getInstance(currentAccount).checkCanOpenChat(args, fragment)) { - ChatActivity chatActivity = new ChatActivity(args); - fragment.presentFragment(chatActivity, fragment instanceof ChatActivity); - } + openChat(chat.id); } } else { - AlertsCreator.processError(currentAccount, error, fragment, req); + if ("USER_ALREADY_PARTICIPANT".equals(error.text) && origination == ORIGINATION_SPONSORED_CHAT && chatInvite != null && chatInvite.chat != null) { + openChat(chatInvite.chat.id); + } else { + AlertsCreator.processError(currentAccount, error, fragment, req); + } } }); }, ConnectionsManager.RequestFlagFailOnServerErrors); @@ -372,4 +382,13 @@ public class JoinGroupAlert extends BottomSheet { // scamDrawable.setColor(getThemedColor(Theme.key_avatar_subtitleInProfileBlue)); return type == 0 ? Theme.dialogs_scamDrawable : Theme.dialogs_fakeDrawable; } + + private void openChat(long chatId) { + Bundle args = new Bundle(); + args.putLong("chat_id", chatId); + if (MessagesController.getInstance(currentAccount).checkCanOpenChat(args, fragment)) { + ChatActivity chatActivity = new ChatActivity(args); + fragment.presentFragment(chatActivity, fragment instanceof ChatActivity); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Loadable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Loadable.java new file mode 100644 index 000000000..6ce537c1e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Loadable.java @@ -0,0 +1,6 @@ +package org.telegram.ui.Components; + +public interface Loadable { + void setLoading(boolean loading); + boolean isLoading(); +} 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 69b182e82..b931b1468 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java @@ -62,6 +62,7 @@ import org.telegram.ui.Components.FloatingDebug.FloatingDebugProvider; import org.telegram.ui.Components.Paint.ShapeDetector; import org.telegram.ui.ProfileActivity; import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import org.telegram.ui.Stories.recorder.KeyboardNotifier; import org.telegram.ui.Stories.recorder.StoryRecorder; import java.util.ArrayList; 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 df84143da..459e72e80 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java @@ -44,6 +44,7 @@ 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.MentionCell; import org.telegram.ui.Cells.StickerCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.ContentPreviewViewer; @@ -882,7 +883,13 @@ public class MentionsContainerView extends BlurredFrameLayout implements Notific @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.emojiLoaded) { - getListView().invalidateViews(); + AndroidUtilities.forEachViews(listView, view -> { + if (view instanceof MentionCell) { + ((MentionCell) view).invalidateEmojis(); + } else { + view.invalidate(); + } + }); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java index e334d49cf..7b45a8f24 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java @@ -303,6 +303,11 @@ public class MessagePreviewView extends FrameLayout { resourcesProvider = MessagePreviewView.this.resourcesProvider; } + @Override + protected boolean canCopy() { + return messagePreviewParams == null || !messagePreviewParams.noforwards; + } + @Override protected Theme.ResourcesProvider getResourcesProvider() { return resourcesProvider; 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 a06c831e8..61ff832a5 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,6 @@ package org.telegram.ui.Components.Premium; +import static android.graphics.Canvas.ALL_SAVE_FLAG; import static org.telegram.messenger.AndroidUtilities.dp; import android.animation.Animator; @@ -13,6 +14,8 @@ import android.graphics.CornerPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathEffect; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.text.Layout; import android.text.SpannableStringBuilder; import android.text.StaticLayout; @@ -30,6 +33,8 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.math.MathUtils; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; @@ -46,6 +51,10 @@ import java.util.ArrayList; public class LimitPreviewView extends LinearLayout { + public interface DarkGradientProvider { + Paint setDarkGradientLocation(float x, float y); + } + private float percent; private final int premiumLimit; private int currentValue; @@ -72,6 +81,7 @@ public class LimitPreviewView extends LinearLayout { private final TextView defaultText; private final TextView premiumText; private boolean isBoostsStyle; + private boolean isSimpleStyle; Theme.ResourcesProvider resourcesProvider; private boolean animateIncrease; @@ -79,6 +89,7 @@ public class LimitPreviewView extends LinearLayout { float limitIconRotation; public boolean isStatistic; public boolean invalidationEnabled = true; + private DarkGradientProvider darkGradientProvider; public LimitPreviewView(@NonNull Context context, int icon, int currentValue, int premiumLimit, Theme.ResourcesProvider resourcesProvider) { this(context, icon, currentValue, premiumLimit, .5f, resourcesProvider); @@ -105,7 +116,7 @@ public class LimitPreviewView extends LinearLayout { addView(limitIcon, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.LEFT)); } - final FrameLayout defaultLayout = new FrameLayout(context); + final FrameLayout defaultLayout = new TextViewHolder(context, true); defaultText = new TextView(context); defaultText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -127,7 +138,7 @@ public class LimitPreviewView extends LinearLayout { defaultLayout.addView(defaultCount, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 30, Gravity.RIGHT, 12, 0, 12, 0)); } - final FrameLayout premiumLayout = new FrameLayout(context); + final FrameLayout premiumLayout = new TextViewHolder(context, false); premiumText = new TextView(context); premiumText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -135,7 +146,22 @@ public class LimitPreviewView extends LinearLayout { premiumText.setGravity(Gravity.CENTER_VERTICAL); premiumText.setTextColor(Color.WHITE); - premiumCount = new TextView(context); + premiumCount = new TextView(context) { + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + } + + @Override + public void setTextColor(int color) { + super.setTextColor(color); + } + + @Override + public void setText(CharSequence text, BufferType type) { + super.setText(text, type); + } + }; premiumCount.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); premiumCount.setText(String.format("%d", premiumLimit)); premiumCount.setGravity(Gravity.CENTER_VERTICAL); @@ -152,6 +178,11 @@ public class LimitPreviewView extends LinearLayout { limitsContainer = new FrameLayout(context) { Paint grayPaint = new Paint(); + Paint whitePaint = new Paint(); + + { + whitePaint.setColor(Color.WHITE); + } @Override protected void dispatchDraw(Canvas canvas) { @@ -165,13 +196,19 @@ public class LimitPreviewView extends LinearLayout { grayPaint.setColor(Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider)); } AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(6), dp(6), grayPaint); + + if (hasDarkGradientProvider()) { + Paint p = darkGradientProvider.setDarkGradientLocation((((ViewGroup) getParent()).getX() + getX()), (((ViewGroup) getParent()).getY() + getY())); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(6), dp(6), p); + } else { + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(6), dp(6), grayPaint); + } canvas.save(); if (!isBoostsStyle) { canvas.clipRect(width1, 0, getMeasuredWidth(), getMeasuredHeight()); } - Paint paint = PremiumGradient.getInstance().getMainGradientPaint(); + Paint paint = hasDarkGradientProvider() ? whitePaint : PremiumGradient.getInstance().getMainGradientPaint(); if (parentVideForGradient != null) { View parent = parentVideForGradient; if (staticGradient != null) { @@ -218,14 +255,14 @@ public class LimitPreviewView extends LinearLayout { if (isBoostsStyle) { if (percent == 0) { width1 = 0; - premiumCount.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); - defaultText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + premiumCount.setTextColor(hasDarkGradientProvider() ? Color.WHITE : Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + defaultText.setTextColor(hasDarkGradientProvider() ? Color.WHITE : Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); } else if (percent < 1f) { float leftWidth = defaultLayout.getMeasuredWidth() - AndroidUtilities.dp(8); float rightWidth = premiumLayout.getMeasuredWidth() - AndroidUtilities.dp(8); float availableWidth = width - leftWidth - rightWidth; width1 = (int) (leftWidth + availableWidth * percent); - premiumCount.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + premiumCount.setTextColor(hasDarkGradientProvider() ? Color.WHITE : Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); defaultText.setTextColor(Color.WHITE); } else { width1 = width; @@ -268,6 +305,14 @@ public class LimitPreviewView extends LinearLayout { addView(limitsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 30, 0, 0, 14, icon == 0 ? 0 : 12, 14, 0)); } + public void setDarkGradientProvider(DarkGradientProvider darkGradientProvider) { + this.darkGradientProvider = darkGradientProvider; + } + + private boolean hasDarkGradientProvider() { + return darkGradientProvider != null; + } + public void setIconValue(int currentValue, boolean animated) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append("d").setSpan(new ColoredImageSpan(icon), 0, 1, 0); @@ -300,6 +345,10 @@ public class LimitPreviewView extends LinearLayout { super.dispatchDraw(canvas); } + private ValueAnimator arrowAnimator; + private boolean animatingRotation; + private boolean lastProgressCenter; + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); @@ -311,13 +360,25 @@ public class LimitPreviewView extends LinearLayout { float toX = padding + Math.max(width1, (getMeasuredWidth() - padding * 2) * position) - limitIcon.getMeasuredWidth() / 2f; float fromProgressCenter = 0.5f; float toProgressCenter = 0.5f; - if (toX < padding) { - toX = padding; - fromProgressCenter = toProgressCenter = 0f; - } - if (toX > getMeasuredWidth() - padding - limitIcon.getMeasuredWidth()) { - toX = getMeasuredWidth() - padding - limitIcon.getMeasuredWidth(); - toProgressCenter = 1f; + if (isSimpleStyle) { + fromProgressCenter = limitIcon.getArrowCenter(); + toX = Utilities.clamp(toX, getMeasuredWidth() - padding - limitIcon.getMeasuredWidth(), padding); + if (width1 <= 0) { + toProgressCenter = 0f; + } else if (width1 >= getMeasuredWidth() - padding * 2) { + toProgressCenter = 1f; + } else { + toProgressCenter = Utilities.clamp((float) (width1 - (toX - padding)) / limitIcon.getMeasuredWidth(), 1f, 0f); + } + } else { + if (toX < padding) { + toX = padding; + fromProgressCenter = toProgressCenter = 0f; + } + if (toX > getMeasuredWidth() - padding - limitIcon.getMeasuredWidth()) { + toX = getMeasuredWidth() - padding - limitIcon.getMeasuredWidth(); + toProgressCenter = 1f; + } } limitIcon.setAlpha(1f); limitIcon.setTranslationX(fromX); @@ -329,7 +390,7 @@ public class LimitPreviewView extends LinearLayout { limitIcon.createAnimationLayouts(); } - ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); + arrowAnimator = ValueAnimator.ofFloat(0, 1f); float finalToX = toX; float finalToProgressCenter = toProgressCenter; float toWidth = width1; @@ -337,21 +398,28 @@ public class LimitPreviewView extends LinearLayout { width1 = animateIncreaseWidth; } float finalFromProgressCenter = fromProgressCenter; - valueAnimator.addUpdateListener(animation -> { + final boolean animatingRotate = !animatingRotation; + animatingRotation = true; + arrowAnimator.addUpdateListener(animation -> { float v = (float) animation.getAnimatedValue(); float moveValue = Math.min(1f, v); - if (v > 1f) { - if (!wasHaptic) { - wasHaptic = true; - limitIcon.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + if (animatingRotate) { + if (v > 1f) { + if (!wasHaptic) { + wasHaptic = true; + limitIcon.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } + limitIcon.setRotation(limitIconRotation + (v - 1f) * 60); + } else { + limitIcon.setRotation(limitIconRotation); } - limitIcon.setRotation(limitIconRotation + (v - 1f) * 60); - } else { - limitIcon.setRotation(limitIconRotation); } - limitIcon.setTranslationX(fromX * (1f - moveValue) + finalToX * moveValue); - float arrowCenter = finalFromProgressCenter * (1f - moveValue) + finalToProgressCenter * moveValue; - limitIcon.setArrowCenter(arrowCenter); + if (animation == arrowAnimator) { + limitIcon.setTranslationX(fromX * (1f - moveValue) + finalToX * moveValue); + float arrowCenter = finalFromProgressCenter * (1f - moveValue) + finalToProgressCenter * moveValue; + limitIcon.setArrowCenter(arrowCenter); + limitIcon.setPivotX(limitIcon.getMeasuredWidth() * arrowCenter); + } float scale = Math.min(1, moveValue * 2f); if (!animateIncreaseFinal) { limitIcon.setScaleX(scale); @@ -360,10 +428,17 @@ public class LimitPreviewView extends LinearLayout { width1 = (int) AndroidUtilities.lerp(animateIncreaseWidth, toWidth, moveValue); limitsContainer.invalidate(); } - limitIcon.setPivotX(limitIcon.getMeasuredWidth() * arrowCenter); + }); + arrowAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (animatingRotate) { + animatingRotation = false; + } + } }); - valueAnimator.setInterpolator(new OvershootInterpolator()); + arrowAnimator.setInterpolator(new OvershootInterpolator()); if (animateIncreaseFinal) { ValueAnimator valueAnimator1 = ValueAnimator.ofFloat(0, 1f); valueAnimator1.addUpdateListener(animation -> { @@ -374,12 +449,12 @@ public class LimitPreviewView extends LinearLayout { }); valueAnimator1.setDuration(500); valueAnimator1.start(); - valueAnimator.setDuration(600); + arrowAnimator.setDuration(600); } else { - valueAnimator.setDuration(1000); - valueAnimator.setStartDelay(200); + arrowAnimator.setDuration(1000); + arrowAnimator.setStartDelay(200); } - valueAnimator.start(); + arrowAnimator.start(); wasAnimation = true; } else if (isBoostsStyle) { @@ -477,6 +552,30 @@ public class LimitPreviewView extends LinearLayout { isBoostsStyle = true; } + public void setStatus(int currentLevel, int maxLevel, boolean animated) { + if (currentValue == currentLevel) { + animated = false; + } + currentValue = currentLevel; + percent = MathUtils.clamp(currentLevel / (float) maxLevel, 0, 1f); + if (animated) { + animateIncrease = true; + animateIncreaseWidth = width1; + limitsContainer.requestLayout(); + requestLayout(); + } + ((FrameLayout.LayoutParams) premiumCount.getLayoutParams()).gravity = Gravity.RIGHT; + defaultCount.setVisibility(View.GONE); + premiumText.setVisibility(View.GONE); + + defaultText.setText("0"); + premiumCount.setText("" + maxLevel); + + setIconValue(currentLevel, false); + isBoostsStyle = true; + isSimpleStyle = true; + } + public void increaseCurrentValue(int boosts, int value, int maxValue) { currentValue++; percent = MathUtils.clamp(value / (float) maxValue, 0f, 1f); @@ -487,6 +586,37 @@ public class LimitPreviewView extends LinearLayout { requestLayout(); } + private class TextViewHolder extends FrameLayout { + + private final Paint paint = new Paint(); + private final boolean isLeft; + + public TextViewHolder(@NonNull Context context, boolean isLeft) { + super(context); + setLayerType(LAYER_TYPE_HARDWARE, null); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + this.isLeft = isLeft; + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child instanceof TextView) { + boolean result = super.drawChild(canvas, child, drawingTime); + boolean leftGradient = percent != 0 && percent <= 1f && isLeft; + boolean rightGradient = percent == 1f && !isLeft; + if ((leftGradient || rightGradient) && hasDarkGradientProvider()) { + canvas.saveLayer(child.getLeft(), child.getTop(), child.getRight(), child.getBottom(), paint, ALL_SAVE_FLAG); + Paint p = darkGradientProvider.setDarkGradientLocation((((ViewGroup) getParent()).getX() + getX()), (((ViewGroup) getParent()).getY() + getY())); + canvas.drawRect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom(), p); + canvas.restore(); + invalidate(); + } + return result; + } + return super.drawChild(canvas, child, drawingTime); + } + } + private class CounterView extends View { Path path = new Path(); @@ -503,12 +633,16 @@ public class LimitPreviewView extends LinearLayout { float arrowCenter; boolean invalidatePath; + Paint dstOutPaint = new Paint(); + Paint overlayPaint = new Paint(); public CounterView(Context context) { super(context); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); textPaint.setTextSize(dp(22)); textPaint.setColor(Color.WHITE); + dstOutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + overlayPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)); } @Override @@ -523,8 +657,8 @@ public class LimitPreviewView extends LinearLayout { int h = getMeasuredHeight() - dp(8); float widthHalf = getMeasuredWidth() * arrowCenter; float x2 = Utilities.clamp(widthHalf + dp(8), getMeasuredWidth(), 0); - float x3 = Utilities.clamp(widthHalf + dp(10), getMeasuredWidth(), AndroidUtilities.dp(24)); - float x4 = Utilities.clamp(widthHalf - dp(24), getMeasuredWidth(), 0); + float x3 = Utilities.clamp(widthHalf + dp(10), getMeasuredWidth(), dp(24)); + float x4 = Utilities.clamp(widthHalf - dp(arrowCenter < 0.7f ? 10 : 24), getMeasuredWidth(), 0); float x5 = Utilities.clamp(widthHalf - dp(8), getMeasuredWidth(), 0); path.rewind(); @@ -555,15 +689,25 @@ public class LimitPreviewView extends LinearLayout { } PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, LimitPreviewView.this.getMeasuredWidth(), LimitPreviewView.this.getMeasuredHeight(), getGlobalXOffset() - getX(), -getTop()); AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), h); - canvas.drawRoundRect(AndroidUtilities.rectTmp, h / 2f, h / 2f, PremiumGradient.getInstance().getMainGradientPaint()); + canvas.drawRoundRect(AndroidUtilities.rectTmp, h / 2f, h / 2f, hasDarkGradientProvider() ? textPaint : PremiumGradient.getInstance().getMainGradientPaint()); PremiumGradient.getInstance().getMainGradientPaint().setPathEffect(pathEffect); - canvas.drawPath(path, PremiumGradient.getInstance().getMainGradientPaint()); + if (hasDarkGradientProvider()) { + textPaint.setPathEffect(pathEffect); + } + canvas.drawPath(path, hasDarkGradientProvider() ? textPaint : PremiumGradient.getInstance().getMainGradientPaint()); PremiumGradient.getInstance().getMainGradientPaint().setPathEffect(null); + if (hasDarkGradientProvider()) { + textPaint.setPathEffect(null); + } if (invalidationEnabled) { invalidate(); } } + if (hasDarkGradientProvider()) { + canvas.saveLayer(0, 0, getMeasuredWidth(), getMeasuredHeight(), dstOutPaint, ALL_SAVE_FLAG); + } + float x = (getMeasuredWidth() - textLayout.getWidth()) / 2f; float y = (h - textLayout.getHeight()) / 2f; if (!animationInProgress) { @@ -609,6 +753,14 @@ public class LimitPreviewView extends LinearLayout { canvas.restore(); } + + if (hasDarkGradientProvider()) { + canvas.restore(); + canvas.saveLayer(0, 0, getMeasuredWidth(), getMeasuredHeight(), overlayPaint, ALL_SAVE_FLAG); + Paint p = darkGradientProvider.setDarkGradientLocation(getX(), getY()); + canvas.drawRect(dp(12), dp(10), getMeasuredWidth() - dp(12), getMeasuredHeight() - dp(10), p); + canvas.restore(); + } } @Override @@ -730,7 +882,6 @@ public class LimitPreviewView extends LinearLayout { } } - private void checkAnimationComplete() { for (int i = 0; i < animatedLayouts.size(); i++) { if (animatedLayouts.get(i).valueAnimator != null) { @@ -760,6 +911,10 @@ public class LimitPreviewView extends LinearLayout { } } + public float getArrowCenter() { + return arrowCenter; + } + private class AnimatedLayout { public boolean replace; ArrayList staticLayouts = new ArrayList<>(); 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 b2c7ed183..2ef598a89 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 @@ -52,6 +52,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; 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; @@ -61,9 +62,11 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.AdminedChannelCell; +import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Cells.GroupCreateUserCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.ChannelColorActivity; import org.telegram.ui.ChatActivity; import org.telegram.ui.ChatEditActivity; import org.telegram.ui.Components.AvatarDrawable; @@ -76,6 +79,7 @@ import org.telegram.ui.Components.FireworksOverlay; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkSpanDrawable; +import org.telegram.ui.Components.Loadable; import org.telegram.ui.Components.LoginOrView; import org.telegram.ui.Components.Premium.boosts.BoostCounterView; import org.telegram.ui.Components.Premium.boosts.BoostDialogs; @@ -87,14 +91,19 @@ import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.TypefaceSpan; +import org.telegram.ui.DialogsActivity; +import org.telegram.ui.GroupColorActivity; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; +import org.telegram.ui.StatisticActivity; import org.telegram.ui.Stories.ChannelBoostUtilities; import org.telegram.ui.Stories.DarkThemeResourceProvider; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; import org.telegram.ui.Stories.recorder.StoryRecorder; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -129,7 +138,9 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp public static final int TYPE_BOOSTS_FOR_EMOJI_STATUS = 25; public static final int TYPE_BOOSTS_FOR_REPLY_ICON = 26; public static final int TYPE_BOOSTS_FOR_PROFILE_ICON = 27; - + public static final int TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK = 29; + public static final int TYPE_FEATURES = 30; + public static final int TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS = 31; public static final int TYPE_PIN_SAVED_DIALOGS = 28; private boolean canSendLink; @@ -140,6 +151,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp private HeaderView headerView; private boolean isCurrentChat; private boolean lockInvalidation = false; + private ChatMessageCell chatMessageCell; public static String limitTypeToServerString(int type) { switch (type) { @@ -268,6 +280,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp PremiumButtonView premiumButtonView; TextView actionBtn; + ButtonWithCounterView boostMiniBtn; public Runnable onSuccessRunnable; public Runnable onShowPremiumScreenRunnable; private boolean loading = false; @@ -280,6 +293,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp FireworksOverlay fireworksOverlay; Runnable statisticClickRunnable; private int requiredLvl = 0; + private ButtonWithCounterView boostToUnlockGroupBtn; public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, int currentAccount, Theme.ResourcesProvider resourcesProvider) { super(context, fragment, false, hasFixedSize(type), false, resourcesProvider); @@ -295,7 +309,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp loadInactiveChannels(); } updatePremiumButtonText(); - if (type == TYPE_BOOSTS_FOR_USERS) { + if (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS || type == TYPE_BOOSTS_FOR_POSTING) { fireworksOverlay = new FireworksOverlay(getContext()); container.addView(fireworksOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); } @@ -304,11 +318,13 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_PROFILE_COLOR || type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK || type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || type == TYPE_BOOSTS_FOR_REACTIONS || type == TYPE_BOOSTS_FOR_REPLY_ICON || - type == TYPE_BOOSTS_FOR_PROFILE_ICON + type == TYPE_BOOSTS_FOR_PROFILE_ICON || + type == TYPE_FEATURES ) { ((ViewGroup) premiumButtonView.getParent()).removeView(premiumButtonView); if (divider != null) { @@ -329,6 +345,36 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp }); actionBtn.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider), ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider), 120))); } + + if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + ((ViewGroup) premiumButtonView.getParent()).removeView(premiumButtonView); + boostToUnlockGroupBtn = new ButtonWithCounterView(context, resourcesProvider); + boostToUnlockGroupBtn.withCounterIcon(); + boostToUnlockGroupBtn.setText(LocaleController.getString(R.string.BoostGroup), false); + boostToUnlockGroupBtn.setOnClickListener(v -> { + if (premiumButtonView.isShowOverlay()) { + premiumButtonView.overlayTextView.performClick(); + } else { + premiumButtonView.buttonLayout.performClick(); + } + }); + containerView.addView(boostToUnlockGroupBtn, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 16, 2, 16, 12)); + containerView.post(() -> boostToUnlockGroupBtn.setCount(getNeededBoostsForUnlockGroup(), false)); + } + + if (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_POSTING) { + containerView.post(() -> { + if (ChatObject.hasAdminRights(getChat())) { + if (premiumButtonView.getParent() != null) { + ((ViewGroup) premiumButtonView.getParent()).removeView(premiumButtonView); + } + if (divider != null && divider.getParent() != null) { + ((ViewGroup) divider.getParent()).removeView(divider); + } + recyclerListView.setPadding(0, 0, 0, 0); + } + }); + } } @Override @@ -336,6 +382,16 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp super.onViewCreated(containerView); Context context = containerView.getContext(); + boostMiniBtn = new ButtonWithCounterView(context, resourcesProvider); + boostMiniBtn.setFlickeringLoading(true); + boostMiniBtn.setText(LocaleController.getString(R.string.BoostBtn), false); + boostMiniBtn.setOnClickListener(v -> { + if (premiumButtonView.isShowOverlay()) { + premiumButtonView.overlayTextView.performClick(); + } else { + premiumButtonView.buttonLayout.performClick(); + } + }); premiumButtonView = new PremiumButtonView(context, true, resourcesProvider) { @Override public void invalidate() { @@ -351,6 +407,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_PROFILE_COLOR || type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK || type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || type == TYPE_BOOSTS_FOR_REACTIONS || @@ -362,7 +419,11 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (chatEndRow - chatStartRow > 1) { - canvas.drawRect(0, 0, getMeasuredWidth(), 1, Theme.dividerPaint); + Paint dividerPaint = Theme.getThemePaint(Theme.key_paint_divider, resourcesProvider); + if (dividerPaint == null) { + dividerPaint = Theme.dividerPaint; + } + canvas.drawRect(0, 0, getMeasuredWidth(), 1, dividerPaint); } } }; @@ -408,14 +469,14 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp if (type == TYPE_ADD_MEMBERS_RESTRICTED) { return; } - if (type == TYPE_BOOSTS_FOR_USERS) { + if (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS || isMiniBoostBtnForAdminAvailable()) { if (canApplyBoost.empty) { if (UserConfig.getInstance(currentAccount).isPremium() && BoostRepository.isMultiBoostsAvailable()) { BoostDialogs.showMoreBoostsNeeded(dialogId, this); } else { AlertDialog.Builder builder = new AlertDialog.Builder(context, resourcesProvider); builder.setTitle(LocaleController.getString("PremiumNeeded", R.string.PremiumNeeded)); - builder.setMessage(AndroidUtilities.replaceTags(LocaleController.getString("PremiumNeededForBoosting", R.string.PremiumNeededForBoosting))); + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.getString(isGroup() ? R.string.PremiumNeededForBoostingGroup : R.string.PremiumNeededForBoosting))); builder.setPositiveButton(LocaleController.getString("CheckPhoneNumberYes", R.string.CheckPhoneNumberYes), (dialog, which) -> { parentFragment.presentFragment(new PremiumPreviewFragment(null)); LimitReachedBottomSheet.this.dismiss(); @@ -515,6 +576,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_PROFILE_COLOR || type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK || type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || type == TYPE_BOOSTS_FOR_REACTIONS || @@ -542,7 +604,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp dismiss(); }); premiumButtonView.overlayTextView.setOnClickListener(v -> { - if (type == TYPE_BOOSTS_FOR_USERS) { + if (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS || isMiniBoostBtnForAdminAvailable()) { if (canApplyBoost.canApply) { premiumButtonView.buttonLayout.callOnClick(); if (canApplyBoost.alreadyActive && canApplyBoost.boostedNow) { @@ -586,18 +648,28 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp (boostsStatus.next_level_boosts - boostsStatus.current_level_boosts)); } - private void boostChannel() { - if (premiumButtonView.isLoading()) { + private void boostChannel(Loadable button) { + boostChannel(button, false); + } + + private void boostChannel(Loadable button, boolean force) { + if (button.isLoading() && !force) { return; } - premiumButtonView.setLoading(true); + button.setLoading(true); MessagesController.getInstance(currentAccount).getBoostsController().applyBoost(dialogId, canApplyBoost.slot, arg -> { MessagesController.getInstance(currentAccount).getBoostsController().getBoostsStats(dialogId, tlPremiumBoostsStatus -> { - premiumButtonView.setLoading(false); + button.setLoading(false); if (tlPremiumBoostsStatus == null) { return; } boostsStatus.boosts += 1; + if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + TLRPC.ChatFull chatFull = getChatFull(); + if (chatFull != null) { + chatFull.boosts_applied++; + } + } limitPreviewIncreaseCurrentValue(); setBoostsStats(tlPremiumBoostsStatus, isCurrentChat); canApplyBoost.isMaxLvl = boostsStatus.next_level_boosts <= 0; @@ -607,13 +679,40 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp }); }, error -> { if (error.text.startsWith("FLOOD_WAIT")) { - BoostDialogs.showFloodWait(Utilities.parseInt(error.text)); + int seconds = Utilities.parseInt(error.text); + if (seconds <= 5) { + AndroidUtilities.runOnUIThread(() -> boostChannel(button, true), seconds * 1000L); + return; + } else { + BoostDialogs.showFloodWait(seconds); + } } - premiumButtonView.setLoading(false); + button.setLoading(false); }); } - private void onBoostSuccess() { + private void boostChannel() { + if (boostMiniBtn.isAttachedToWindow()) { + boostChannel(boostMiniBtn); + } else if (boostToUnlockGroupBtn != null && boostToUnlockGroupBtn.isAttachedToWindow()) { + boostChannel(boostToUnlockGroupBtn); + } else { + boostChannel(premiumButtonView); + } + } + + private boolean onBoostSuccess() { + NotificationCenter.getInstance(currentAccount).postNotificationNameOnUIThread(NotificationCenter.chatWasBoostedByUser, boostsStatus, canApplyBoost.copy(), dialogId); + if (boostToUnlockGroupBtn != null) { + int count = getNeededBoostsForUnlockGroup(); + if (count == 0) { + NotificationCenter.getInstance(currentAccount).postNotificationNameOnUIThread(NotificationCenter.groupRestrictionsUnlockedByBoosts); + dismiss(); + return false; + } + boostToUnlockGroupBtn.setCount(count, true); + } + TransitionSet transitionSet = new TransitionSet(); transitionSet.addTransition(new Visibility() { @Override @@ -643,12 +742,16 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp headerView.recreateTitleAndDescription(); headerView.title.setText(getBoostsTitleString()); - headerView.description.setText(AndroidUtilities.replaceTags(getBoostsDescriptionString())); + headerView.description.setText(AndroidUtilities.replaceTags(getBoostsDescriptionString(false))); updateButton(); fireworksOverlay.start(); fireworksOverlay.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); headerView.boostCounterView.setCount(canApplyBoost.boostCount, true); recyclerListView.smoothScrollToPosition(0); + if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + headerView.boostCounterView.setVisibility(View.GONE); + } + return true; } private void sendInviteMessages() { @@ -693,22 +796,23 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } public void updatePremiumButtonText() { - if (type == TYPE_BOOSTS_FOR_USERS) { + if (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS || isMiniBoostBtnForAdminAvailable()) { if (BoostRepository.isMultiBoostsAvailable()) { premiumButtonView.buttonTextView.setText(canApplyBoost != null && canApplyBoost.alreadyActive ? LocaleController.getString("BoostingBoostAgain", R.string.BoostingBoostAgain) - : LocaleController.getString("BoostChannel", R.string.BoostChannel)); + : LocaleController.getString(isGroup() ? R.string.BoostGroup : R.string.BoostChannel)); if (canApplyBoost != null && canApplyBoost.isMaxLvl) { premiumButtonView.buttonTextView.setText(LocaleController.getString("OK", R.string.OK)); } } else { - premiumButtonView.buttonTextView.setText(LocaleController.getString("BoostChannel", R.string.BoostChannel)); + premiumButtonView.buttonTextView.setText(LocaleController.getString(isGroup() ? R.string.BoostGroup : R.string.BoostChannel)); } } else if ( type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_PROFILE_COLOR || type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK || type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || type == TYPE_BOOSTS_FOR_REACTIONS || @@ -757,7 +861,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("ChatsLeaveAlert", R.string.ChatsLeaveAlert))); } builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setPositiveButton(LocaleController.getString("RevokeButton", R.string.RevokeButton), (dialogInterface, interface2) -> { + builder.setPositiveButton(LocaleController.getString(R.string.VoipGroupLeave), (dialogInterface, interface2) -> { dismiss(); for (int i = 0; i < chats.size(); i++) { TLRPC.Chat chat = chats.get(i); @@ -774,21 +878,37 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } private void updateButton() { - if (type == TYPE_BOOSTS_FOR_USERS) { + if (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS || isMiniBoostBtnForAdminAvailable()) { if (!canApplyBoost.canApply && !canApplyBoost.empty || canApplyBoost.boostedNow || canApplyBoost.alreadyActive) { if (canApplyBoost.canApply) { if (BoostRepository.isMultiBoostsAvailable()) { premiumButtonView.setOverlayText(LocaleController.getString("BoostingBoostAgain", R.string.BoostingBoostAgain), true, true); } else { - premiumButtonView.setOverlayText(LocaleController.getString("BoostChannel", R.string.BoostChannel), true, true); + premiumButtonView.setOverlayText(LocaleController.getString(isGroup() ? R.string.BoostGroup : R.string.BoostChannel), true, true); + } + boostMiniBtn.setText(LocaleController.getString(R.string.BoostBtn), true); + if (boostToUnlockGroupBtn != null) { + boostToUnlockGroupBtn.setText(LocaleController.getString(R.string.BoostGroup), true); } } else { if (canApplyBoost.isMaxLvl) { + boostMiniBtn.setText(LocaleController.getString(R.string.OK), true); + if (boostToUnlockGroupBtn != null) { + boostToUnlockGroupBtn.setText(LocaleController.getString(R.string.OK), true); + } premiumButtonView.setOverlayText(LocaleController.getString("OK", R.string.OK), true, true); } else { if (BoostRepository.isMultiBoostsAvailable()) { + if (boostToUnlockGroupBtn != null) { + boostToUnlockGroupBtn.setText(LocaleController.getString(R.string.BoostGroup), true); + } + boostMiniBtn.setText(LocaleController.getString(R.string.BoostBtn), true); premiumButtonView.setOverlayText(LocaleController.getString("BoostingBoostAgain", R.string.BoostingBoostAgain), true, true); } else { + if (boostToUnlockGroupBtn != null) { + boostToUnlockGroupBtn.setText(LocaleController.getString(R.string.OK), true); + } + boostMiniBtn.setText(LocaleController.getString(R.string.OK), true); premiumButtonView.setOverlayText(LocaleController.getString("OK", R.string.OK), true, true); } } @@ -845,14 +965,19 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp @Override public CharSequence getTitle() { switch (type) { + case TYPE_FEATURES: + return LocaleController.getString(R.string.BoostingAdditionalFeaturesTitle); + case TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS: + return LocaleController.getString(R.string.BoostGroup); case TYPE_BOOSTS_FOR_USERS: - return LocaleController.getString(R.string.BoostChannel); + return LocaleController.getString(isGroup() ? R.string.BoostGroup : R.string.BoostChannel); case TYPE_BOOSTS_FOR_POSTING: case TYPE_BOOSTS_FOR_COLOR: case TYPE_BOOSTS_FOR_WALLPAPER: case TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER: case TYPE_BOOSTS_FOR_REACTIONS: case TYPE_BOOSTS_FOR_EMOJI_STATUS: + case TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK: case TYPE_BOOSTS_FOR_REPLY_ICON: case TYPE_BOOSTS_FOR_PROFILE_ICON: case TYPE_BOOSTS_FOR_PROFILE_COLOR: @@ -907,6 +1032,37 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } return; } + if (lastFragment instanceof ChatActivity) { + if (isGiveaway) { + BoostDialogs.showBulletin(lastFragment, chat, true); + return; + } + } + if (lastFragment instanceof ChannelColorActivity) { + if (isGiveaway) { + List fragmentStack = getBaseFragment().getParentLayout().getFragmentStack(); + List removedFragments = new ArrayList<>(); + BaseFragment targetFragment = null; + for (int i = fragmentStack.size() - 2; i >= 0; i--) { + BaseFragment fragment = fragmentStack.get(i); + if (fragment instanceof ChatActivity || fragment instanceof DialogsActivity) { + targetFragment = fragment; + break; + } + removedFragments.add(fragment); + } + if (targetFragment == null) { + return; + } + for (BaseFragment removedFragment : removedFragments) { + getBaseFragment().getParentLayout().removeFragmentFromStack(removedFragment); + } + getBaseFragment().finishFragment(); + dismiss(); + BoostDialogs.showBulletin(targetFragment, chat, true); + return; + } + } if (isGiveaway) { if (StoryRecorder.isVisible()) { ChatActivity chatFragment = ChatActivity.of(-chat.id); @@ -946,17 +1102,24 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } boostsStatus.boosts += size; + if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + TLRPC.ChatFull chatFull = getChatFull(); + if (chatFull != null) { + chatFull.boosts_applied += size; + } + } + limitPreviewIncreaseCurrentValue(); setBoostsStats(tlPremiumBoostsStatus, isCurrentChat); canApplyBoost.isMaxLvl = boostsStatus.next_level_boosts <= 0; canApplyBoost.boostedNow = true; canApplyBoost.setMyBoosts(myBoosts); - onBoostSuccess(); - - String str = LocaleController.formatPluralString("BoostingReassignedFromPlural", size, - LocaleController.formatPluralString("BoostingFromOtherChannel", channels)); - BulletinFactory bulletinFactory = BulletinFactory.of(container, resourcesProvider); - bulletinFactory.createSimpleBulletinWithIconSize(R.raw.ic_boosts_replace, str, 30).setDuration(4000).show(true); + if (onBoostSuccess()) { + String str = LocaleController.formatPluralString("BoostingReassignedFromPlural", size, + LocaleController.formatPluralString("BoostingFromOtherChannel", channels)); + BulletinFactory bulletinFactory = BulletinFactory.of(container, resourcesProvider); + bulletinFactory.createSimpleBulletinWithIconSize(R.raw.ic_boosts_replace, str, 30).setDuration(4000).show(true); + } } else if (id == NotificationCenter.didStartedMultiGiftsSelector) { dismiss(); } @@ -998,7 +1161,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp LoginOrView orDividerView = new LoginOrView(context); TextView textView = new LinkSpanDrawable.LinksTextView(context); - SpannableStringBuilder text = AndroidUtilities.replaceTags(LocaleController.getString(R.string.BoostingStoriesByGifting)); + SpannableStringBuilder text = AndroidUtilities.replaceTags(LocaleController.getString(isGroup() ? R.string.BoostingStoriesByGiftingGroup : R.string.BoostingStoriesByGiftingChannel)); SpannableStringBuilder link = new SpannableStringBuilder(LocaleController.getString(R.string.BoostingStoriesByGiftingLink)); link.setSpan(new ClickableSpan() { @Override @@ -1023,6 +1186,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp arrow.setSpan(span, 0, arrow.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(TextUtils.concat(text, " ", AndroidUtilities.replaceCharSequence(">", link, arrow))); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setLineSpacing(dp(3), 1.0f); if (resourcesProvider instanceof DarkThemeResourceProvider) { textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); } else { @@ -1031,10 +1195,23 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp textView.setGravity(Gravity.CENTER_HORIZONTAL); textView.setOnClickListener(v -> BoostPagerBottomSheet.show(getBaseFragment(), dialogId, resourcesProvider)); orDividerView.setOnClickListener(v -> textView.performClick()); - wrapperLayout.addView(actionBtn, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 12, 12, 12, 8)); - wrapperLayout.addView(orDividerView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 0, 0, 0, 0)); - wrapperLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 12, 0, 12, 4)); + if (isMiniBoostBtnForAdminAvailable()) { + ButtonWithCounterView copyBtn = new ButtonWithCounterView(context, resourcesProvider); + copyBtn.setText(LocaleController.getString(R.string.Copy), false); + copyBtn.setOnClickListener(v -> { + AndroidUtilities.addToClipboard(getBoostLink()); + dismiss(); + }); + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.addView(boostMiniBtn, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44, 1f, 0,0,0,4,0)); + linearLayout.addView(copyBtn, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44, 1f, 0,4,0,0,0)); + wrapperLayout.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44, 12, 12, 12, 8)); + } else { + wrapperLayout.addView(actionBtn, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 12, 12, 12, 8)); + } + wrapperLayout.addView(orDividerView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 0, -5, 0, 0)); + wrapperLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 12, -6, 12, 17)); view = wrapperLayout; break; case VIEW_TYPE_BOOST_FEATURE: @@ -1044,6 +1221,11 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp FrameLayout frameLayout = new FrameLayout(getContext()); frameLayout.setPadding(backgroundPaddingLeft + dp(6), 0, backgroundPaddingLeft + dp(6), 0); TextView linkView = new TextView(context); + + if (statisticClickRunnable == null && ChatObject.hasAdminRights(getChat())) { + statisticClickRunnable = () -> getBaseFragment().presentFragment(StatisticActivity.create(getChat())); + } + linkView.setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(13), AndroidUtilities.dp(statisticClickRunnable == null ? 18 : 50), AndroidUtilities.dp(13)); linkView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); linkView.setEllipsize(TextUtils.TruncateAt.MIDDLE); @@ -1201,7 +1383,14 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp }; } + private boolean isMiniBoostBtnForAdminAvailable() { + return (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_POSTING) && ChatObject.hasAdminRights(getChat()); + } + private String getBoostLink() { + if (boostsStatus != null && !TextUtils.isEmpty(boostsStatus.boost_url)) { + return boostsStatus.boost_url; + } return ChannelBoostUtilities.createLink(currentAccount, dialogId); } @@ -1228,6 +1417,11 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp public void setDialogId(long dialogId) { this.dialogId = dialogId; + updateRows(); + } + + public void setChatMessageCell(ChatMessageCell chatMessageCell) { + this.chatMessageCell = chatMessageCell; } public void setBoostsStats(TL_stories.TL_premium_boostsStatus boostsStatus, boolean isCurrentChat) { @@ -1262,56 +1456,85 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp limitParams = getLimitParams(type, currentAccount); int icon = limitParams.icon; String descriptionStr; - boolean premiumLocked = MessagesController.getInstance(currentAccount).premiumFeaturesBlocked(); - if (type == TYPE_BOOSTS_FOR_USERS) { - descriptionStr = getBoostsDescriptionString(); + MessagesController messagesController = MessagesController.getInstance(currentAccount); + boolean premiumLocked = messagesController.premiumFeaturesBlocked(); + boolean isGroup = isGroup(); + if (type == TYPE_FEATURES) { + descriptionStr = LocaleController.getString(isGroup ? R.string.BoostingAdditionalFeaturesSubtitle : R.string.BoostingAdditionalFeaturesSubtitleChannel); + } else if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + descriptionStr = getBoostsDescriptionString(true); + } else if (type == TYPE_BOOSTS_FOR_USERS) { + if (chatMessageCell != null) { + int count = chatMessageCell.getMessageObject().messageOwner.from_boosts_applied; + TLRPC.Chat chat = getChat(); + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(LocaleController.formatPluralString("GroupBoostedByUserWithTimes", count, UserObject.getFirstName(chatMessageCell.getCurrentUser()))); + builder.append(" "); + builder.append(LocaleController.formatString(R.string.GroupBoostedByUserWithDescription, chat == null ? "" : chat.title)); + descriptionStr = builder.toString(); + } else { + if (getBaseFragment() instanceof GroupColorActivity) { + descriptionStr = LocaleController.formatPluralString("BoostingGroupBoostWhatAreBoostsDescription", BoostRepository.giveawayBoostsPerPremium()); + } else { + SpannableStringBuilder builder = new SpannableStringBuilder(getBoostsDescriptionString(true)); + if (ChatObject.hasAdminRights(getChat()) && isGroup) { + builder.append(" ").append(LocaleController.getString(R.string.BoostingPremiumUserCanBoostGroupWithLink)); + } + descriptionStr = builder.toString(); + } + } } else if (type == TYPE_BOOSTS_FOR_POSTING) { if (boostsStatus.level == 0) { descriptionStr = LocaleController.formatString( - "ChannelNeedBoostsDescription", R.string.ChannelNeedBoostsDescription, + isGroup ? R.string.GroupNeedBoostsDescription : R.string.ChannelNeedBoostsDescription, LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts, boostsStatus.next_level_boosts) ); } else { descriptionStr = LocaleController.formatString( - "ChannelNeedBoostsDescriptionNextLevel", R.string.ChannelNeedBoostsDescriptionNextLevel, + isGroup ? R.string.GroupNeedBoostsDescriptionNextLevel : R.string.ChannelNeedBoostsDescriptionNextLevel, LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts), LocaleController.formatPluralString("BoostStories", boostsStatus.level + 1) ); } } else if (type == TYPE_BOOSTS_FOR_COLOR) { descriptionStr = LocaleController.formatString( - R.string.ChannelNeedBoostsForColorDescription, + isGroup ? R.string.GroupNeedBoostsForColorDescription : R.string.ChannelNeedBoostsForColorDescription, channelColorLevelMin() ); } else if (type == TYPE_BOOSTS_FOR_PROFILE_COLOR) { descriptionStr = LocaleController.formatString( - R.string.ChannelNeedBoostsForProfileColorDescription, + isGroup ? R.string.GroupNeedBoostsForProfileColorDescription : R.string.ChannelNeedBoostsForProfileColorDescription, channelColorLevelMin() ); + } else if (type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK) { + descriptionStr = LocaleController.formatString( + R.string.GroupNeedBoostsForCustomEmojiPackDescription, + messagesController.groupEmojiStickersLevelMin + ); } else if (type == TYPE_BOOSTS_FOR_EMOJI_STATUS) { descriptionStr = LocaleController.formatString( - R.string.ChannelNeedBoostsForEmojiStatusDescription, - MessagesController.getInstance(currentAccount).channelEmojiStatusLevelMin + isGroup ? R.string.GroupNeedBoostsForEmojiStatusDescription : R.string.ChannelNeedBoostsForEmojiStatusDescription, + isGroup ? messagesController.groupEmojiStatusLevelMin : messagesController.channelEmojiStatusLevelMin ); } else if (type == TYPE_BOOSTS_FOR_REPLY_ICON) { descriptionStr = LocaleController.formatString( - R.string.ChannelNeedBoostsForReplyIconDescription, - MessagesController.getInstance(currentAccount).channelBgIconLevelMin + isGroup ? R.string.GroupNeedBoostsForReplyIconDescription : R.string.ChannelNeedBoostsForReplyIconDescription, + messagesController.channelBgIconLevelMin ); } else if (type == TYPE_BOOSTS_FOR_PROFILE_ICON) { descriptionStr = LocaleController.formatString( - R.string.ChannelNeedBoostsForProfileIconDescription, - MessagesController.getInstance(currentAccount).channelProfileIconLevelMin + isGroup ? R.string.GroupNeedBoostsForProfileIconDescription : R.string.ChannelNeedBoostsForProfileIconDescription, + isGroup ? messagesController.groupProfileBgIconLevelMin : messagesController.channelProfileIconLevelMin ); } else if (type == TYPE_BOOSTS_FOR_WALLPAPER) { descriptionStr = LocaleController.formatString( - R.string.ChannelNeedBoostsForWallpaperDescription, - MessagesController.getInstance(currentAccount).channelWallpaperLevelMin + isGroup ? R.string.GroupNeedBoostsForWallpaperDescription : R.string.ChannelNeedBoostsForWallpaperDescription, + isGroup ? messagesController.groupWallpaperLevelMin : messagesController.channelWallpaperLevelMin ); } else if (type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER) { descriptionStr = LocaleController.formatString( - R.string.ChannelNeedBoostsForCustomWallpaperDescription, - MessagesController.getInstance(currentAccount).channelCustomWallpaperLevelMin + isGroup ? R.string.GroupNeedBoostsForCustomWallpaperDescription : R.string.ChannelNeedBoostsForCustomWallpaperDescription, + isGroup ? messagesController.groupCustomWallpaperLevelMin : messagesController.channelCustomWallpaperLevelMin ); } else if (type == TYPE_BOOSTS_FOR_REACTIONS) { descriptionStr = LocaleController.formatPluralString("ReactionReachLvlForReaction", requiredLvl, requiredLvl); @@ -1400,59 +1623,80 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_PROFILE_COLOR || type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK || type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS || type == TYPE_BOOSTS_FOR_REPLY_ICON || - type == TYPE_BOOSTS_FOR_PROFILE_ICON + type == TYPE_BOOSTS_FOR_PROFILE_ICON || + type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS ); if (boostsType) { currentValue = 0; } - limitPreviewView = new LimitPreviewView(context, icon, currentValue, premiumLimit, percent, resourcesProvider) { - @Override - public void invalidate() { - if (lockInvalidation) { - return; - } - super.invalidate(); - } - }; - if (boostsType) { - if (boostsStatus != null) { - limitPreviewView.setBoosts(boostsStatus, canApplyBoost != null && canApplyBoost.boostedNow); - } - } else { - limitPreviewView.setBagePosition(position); - limitPreviewView.setType(type); - limitPreviewView.defaultCount.setVisibility(View.GONE); - if (premiumLocked) { - limitPreviewView.setPremiumLocked(); - } else { - if (UserConfig.getInstance(currentAccount).isPremium() || isVeryLargeFile) { - limitPreviewView.premiumCount.setVisibility(View.GONE); - if (type == TYPE_LARGE_FILE) { - limitPreviewView.defaultCount.setText("2 GB"); - } else { - limitPreviewView.defaultCount.setText(Integer.toString(defaultLimit)); + if (type != TYPE_FEATURES) { + limitPreviewView = new LimitPreviewView(context, icon, currentValue, premiumLimit, percent, resourcesProvider) { + @Override + public void invalidate() { + if (lockInvalidation) { + return; + } + super.invalidate(); + } + }; + if (boostsType) { + if (boostsStatus != null) { + limitPreviewView.setBoosts(boostsStatus, canApplyBoost != null && canApplyBoost.boostedNow); + } + } else { + limitPreviewView.setBagePosition(position); + limitPreviewView.setType(type); + limitPreviewView.defaultCount.setVisibility(View.GONE); + if (premiumLocked) { + limitPreviewView.setPremiumLocked(); + } else { + if (UserConfig.getInstance(currentAccount).isPremium() || isVeryLargeFile) { + limitPreviewView.premiumCount.setVisibility(View.GONE); + if (type == TYPE_LARGE_FILE) { + limitPreviewView.defaultCount.setText("2 GB"); + } else { + limitPreviewView.defaultCount.setText(Integer.toString(defaultLimit)); + } + limitPreviewView.defaultCount.setVisibility(View.VISIBLE); } - limitPreviewView.defaultCount.setVisibility(View.VISIBLE); } } + + if (type == TYPE_PUBLIC_LINKS || type == TYPE_TO0_MANY_COMMUNITIES) { + limitPreviewView.setDelayedAnimation(); + } + + addView(limitPreviewView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, -4, 0, -4, 0)); } - if (type == TYPE_PUBLIC_LINKS || type == TYPE_TO0_MANY_COMMUNITIES) { - limitPreviewView.setDelayedAnimation(); + if (type == TYPE_FEATURES) { + FrameLayout frameLayout = new FrameLayout(context); + ImageView imageView = new ImageView(context); + imageView.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.large_boosts)); + frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + frameLayout.setBackground(Theme.createCircleDrawable(dp(79), Theme.getColor(Theme.key_featuredStickers_addButton))); + addView(frameLayout, LayoutHelper.createLinear(79, 79, Gravity.CENTER_HORIZONTAL, 0, 23, 0, 0)); } - addView(limitPreviewView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, -4, 0, -4, 0)); - title = new TextView(context); title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - if (type == TYPE_BOOSTS_FOR_USERS) { + if (type == TYPE_FEATURES) { + title.setText(LocaleController.getString(R.string.BoostingAdditionalFeaturesTitle)); + } else if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { title.setText(getBoostsTitleString()); + } else if (type == TYPE_BOOSTS_FOR_USERS) { + if (getBaseFragment() instanceof GroupColorActivity) { + title.setText(LocaleController.getString(R.string.BoostingGroupBoostWhatAreBoosts)); + } else { + title.setText(getBoostsTitleString()); + } } else if (type == TYPE_BOOSTS_FOR_POSTING) { if (boostsStatus.level == 0) { title.setText(LocaleController.getString("BoostingEnableStories", R.string.BoostingEnableStories)); @@ -1471,6 +1715,8 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp title.setText(LocaleController.getString(R.string.BoostingEnableProfileIcon)); } else if (type == TYPE_BOOSTS_FOR_EMOJI_STATUS) { title.setText(LocaleController.getString(R.string.BoostingEnableEmojiStatus)); + } else if (type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK) { + title.setText(LocaleController.getString(R.string.BoostingEnableGroupEmojiPack)); } else if (type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER) { title.setText(LocaleController.getString(R.string.BoostingEnableWallpaper)); } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { @@ -1488,9 +1734,12 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); title.setGravity(Gravity.CENTER); - if (type == TYPE_BOOSTS_FOR_USERS) { + if (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS || isMiniBoostBtnForAdminAvailable()) { boostCounterView = new BoostCounterView(context, resourcesProvider); boostCounterView.setCount(canApplyBoost.boostCount, false); + if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + boostCounterView.setVisibility(GONE); + } if (isCurrentChat) { titleLinearLayout = new LinearLayout(context); titleLinearLayout.setOrientation(HORIZONTAL); @@ -1549,7 +1798,11 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp description.setGravity(Gravity.CENTER_HORIZONTAL); description.setLineSpacing(description.getLineSpacingExtra(), description.getLineSpacingMultiplier() * 1.1f); if (type == TYPE_BOOSTS_FOR_POSTING) { - description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + if (resourcesProvider instanceof DarkThemeResourceProvider) { + description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + } else { + description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + } } else { description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); } @@ -1558,6 +1811,11 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } else { addView(description, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, 0, 24, 24)); } + if(type == TYPE_FEATURES) { + ((MarginLayoutParams) description.getLayoutParams()).bottomMargin = dp(15); + ((MarginLayoutParams) title.getLayoutParams()).bottomMargin = dp(6); + ((MarginLayoutParams) title.getLayoutParams()).topMargin = dp(12); + } updatePremiumButtonText(); } @@ -1605,32 +1863,71 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp if (boostsStatus.next_level_boosts == 0) { return LocaleController.formatString("BoostsMaxLevelReached", R.string.BoostsMaxLevelReached); } else if (boostsStatus.level > 0 && !canApplyBoost.alreadyActive) { - return LocaleController.getString(R.string.BoostChannel); + return LocaleController.getString(isGroup() ? R.string.BoostGroup : R.string.BoostChannel); } else if (isCurrentChat) { + if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + return LocaleController.getString(isGroup() ? R.string.BoostGroup : R.string.BoostChannel); + } TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); if (canApplyBoost.alreadyActive) { return LocaleController.formatString("YouBoostedChannel2", R.string.YouBoostedChannel2, chat.title); } else { - return LocaleController.getString(R.string.BoostChannel); + return LocaleController.getString(isGroup() ? R.string.BoostGroup : R.string.BoostChannel); } } else { + if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + return LocaleController.getString(isGroup() ? R.string.BoostGroup : R.string.BoostChannel); + } if (canApplyBoost.alreadyActive) { - return LocaleController.getString("YouBoostedChannel", R.string.YouBoostedChannel); + return LocaleController.getString(isGroup() ? R.string.YouBoostedGroup : R.string.YouBoostedChannel); } else { - return LocaleController.getString("BoostingEnableStoriesForChannel", R.string.BoostingEnableStoriesForChannel); + return LocaleController.getString(isGroup() ? R.string.BoostingEnableStoriesForGroup : R.string.BoostingEnableStoriesForChannel); } } } - private String getBoostsDescriptionString() { + private TLRPC.Chat getChat() { + return MessagesController.getInstance(currentAccount).getChat(-dialogId); + } + + private TLRPC.ChatFull getChatFull() { + return MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + } + + private boolean isGroup() { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + return !ChatObject.isChannelAndNotMegaGroup(chat); + } + + private String getDescriptionForRemoveRestrictions() { + TLRPC.Chat chat = getChat(); + return LocaleController.formatPluralString("BoostingRemoveRestrictionsSubtitle", getNeededBoostsForUnlockGroup(), chat == null ? "" : chat.title); + } + + private int getNeededBoostsForUnlockGroup() { + TLRPC.ChatFull chatFull = getChatFull(); + return Math.max(chatFull.boosts_unrestrict - chatFull.boosts_applied, 0); + } + + private String getBoostsDescriptionString(boolean init) { + if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + return getDescriptionForRemoveRestrictions(); + } TLRPC.Chat channel = MessagesController.getInstance(currentAccount).getChat(-dialogId); - String channelTitle = channel == null ? LocaleController.getString(R.string.AccDescrChannel) : channel.title; + String channelTitle = channel == null ? LocaleController.getString(isGroup() ? R.string.AccDescrGroup : R.string.AccDescrChannel) : channel.title; boolean isZeroBoostsForNextLevel = boostsStatus.boosts == boostsStatus.current_level_boosts; + if (isMiniBoostBtnForAdminAvailable() && boostsStatus.next_level_boosts != 0 && init) { + return LocaleController.formatString( + isGroup() ? R.string.GroupNeedBoostsDescriptionForNewFeatures : R.string.ChannelNeedBoostsDescriptionForNewFeatures, + channelTitle, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) + ); + } if (isZeroBoostsForNextLevel && canApplyBoost.alreadyActive) { if (boostsStatus.level == 1) { - return LocaleController.formatString("ChannelBoostsJustReachedLevel1", R.string.ChannelBoostsJustReachedLevel1); + return LocaleController.formatString(isGroup() ? R.string.GroupBoostsJustReachedLevel1 : R.string.ChannelBoostsJustReachedLevel1); } else { - return LocaleController.formatString("ChannelBoostsJustReachedLevelNext", R.string.ChannelBoostsJustReachedLevelNext, + return LocaleController.formatString(isGroup() ? R.string.GroupBoostsJustReachedLevelNext : R.string.ChannelBoostsJustReachedLevelNext, boostsStatus.level, LocaleController.formatPluralString("BoostStories", boostsStatus.level)); } @@ -1638,38 +1935,38 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp if (canApplyBoost.alreadyActive) { if (boostsStatus.level == 0) { return LocaleController.formatString( - R.string.ChannelNeedBoostsDescriptionForNewFeatures, + isGroup() ? R.string.GroupNeedBoostsDescriptionForNewFeatures : R.string.ChannelNeedBoostsDescriptionForNewFeatures, channelTitle, LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) ); } else { if (boostsStatus.next_level_boosts == 0) { - return LocaleController.formatString("ChannelBoostsJustReachedLevelNext", R.string.ChannelBoostsJustReachedLevelNext, + return LocaleController.formatString(isGroup() ? R.string.GroupBoostsJustReachedLevelNext : R.string.ChannelBoostsJustReachedLevelNext, boostsStatus.level, LocaleController.formatPluralString("BoostStories", boostsStatus.level + 1)); } else { return LocaleController.formatString( - R.string.ChannelNeedBoostsDescriptionForNewFeatures, - channelTitle, - LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) + isGroup() ? R.string.GroupNeedBoostsDescriptionForNewFeatures : R.string.ChannelNeedBoostsDescriptionForNewFeatures, + channelTitle, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) ); } } } else { if (boostsStatus.level == 0) { return LocaleController.formatString( - R.string.ChannelNeedBoostsDescriptionForNewFeatures, + isGroup() ? R.string.GroupNeedBoostsDescriptionForNewFeatures : R.string.ChannelNeedBoostsDescriptionForNewFeatures, channelTitle, LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) ); } else { if (boostsStatus.next_level_boosts == 0) { - return LocaleController.formatString("ChannelBoostsJustReachedLevelNext", R.string.ChannelBoostsJustReachedLevelNext, + return LocaleController.formatString(isGroup() ? R.string.GroupBoostsJustReachedLevelNext : R.string.ChannelBoostsJustReachedLevelNext, boostsStatus.level, LocaleController.formatPluralString("BoostStories", boostsStatus.level + 1)); } else { return LocaleController.formatString( - R.string.ChannelNeedBoostsDescriptionForNewFeatures, + isGroup() ? R.string.GroupNeedBoostsDescriptionForNewFeatures : R.string.ChannelNeedBoostsDescriptionForNewFeatures, channelTitle, LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) ); @@ -1779,7 +2076,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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); - } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_PROFILE_COLOR || type == TYPE_BOOSTS_FOR_REPLY_ICON || type == TYPE_BOOSTS_FOR_PROFILE_ICON || type == TYPE_BOOSTS_FOR_EMOJI_STATUS || type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { + } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_PROFILE_COLOR || type == TYPE_BOOSTS_FOR_REPLY_ICON || type == TYPE_BOOSTS_FOR_PROFILE_ICON || type == TYPE_BOOSTS_FOR_EMOJI_STATUS || type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK || type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { limitParams.defaultLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitDefault; limitParams.premiumLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitPremium; limitParams.icon = R.drawable.filled_limit_boost; @@ -1846,9 +2143,10 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK || type == TYPE_BOOSTS_FOR_REACTIONS ) { - if (type != TYPE_BOOSTS_FOR_USERS) { + if (type != TYPE_BOOSTS_FOR_USERS || ChatObject.hasAdminRights(getChat())) { topPadding = .24f; linkRow = rowCount++; if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable) { @@ -1858,6 +2156,13 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp setupBoostFeatures(); boostFeaturesStartRow = rowCount++; rowCount += boostFeatures.size() - 1; + } else if (type == TYPE_FEATURES || type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { + topPadding = .24f; + setupBoostFeatures(); + chatStartRow = rowCount; + boostFeaturesStartRow = rowCount++; + rowCount += boostFeatures.size() - 1; + chatEndRow = rowCount; } else if (!hasFixedSize(type)) { dividerRow = rowCount++; chatsTitleRow = rowCount++; @@ -2015,17 +2320,24 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp if (boostsStatus != null) { startLevel = boostsStatus.level + 1; } - int maxlvl = 10; final MessagesController m = MessagesController.getInstance(currentAccount); if (m != null) { - maxlvl = Math.max(maxlvl, m.peerColors != null ? m.peerColors.maxLevel() : 0); - maxlvl = Math.max(maxlvl, m.profilePeerColors != null ? m.profilePeerColors.maxLevel() : 0); - maxlvl = Math.max(maxlvl, m.channelBgIconLevelMin); - maxlvl = Math.max(maxlvl, m.channelProfileIconLevelMin); - maxlvl = Math.max(maxlvl, m.channelEmojiStatusLevelMin); - maxlvl = Math.max(maxlvl, m.channelWallpaperLevelMin); - maxlvl = Math.max(maxlvl, m.channelCustomWallpaperLevelMin); + maxlvl = Math.max(maxlvl, m.peerColors != null ? m.peerColors.maxLevel(isGroup()) : 0); + maxlvl = Math.max(maxlvl, m.profilePeerColors != null ? m.profilePeerColors.maxLevel(isGroup()) : 0); + if (isGroup()) { + maxlvl = Math.max(maxlvl, m.groupTranscribeLevelMin); + maxlvl = Math.max(maxlvl, m.groupWallpaperLevelMin); + maxlvl = Math.max(maxlvl, m.groupCustomWallpaperLevelMin); + maxlvl = Math.max(maxlvl, m.groupEmojiStatusLevelMin); + maxlvl = Math.max(maxlvl, m.groupProfileBgIconLevelMin); + } else { + maxlvl = Math.max(maxlvl, m.channelBgIconLevelMin); + maxlvl = Math.max(maxlvl, m.channelProfileIconLevelMin); + maxlvl = Math.max(maxlvl, m.channelEmojiStatusLevelMin); + maxlvl = Math.max(maxlvl, m.channelWallpaperLevelMin); + maxlvl = Math.max(maxlvl, m.channelCustomWallpaperLevelMin); + } } for (int lvl = startLevel; lvl <= maxlvl; ++lvl) { @@ -2036,40 +2348,55 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp lastFeatureList = featureList; } } + + if (type == TYPE_FEATURES && boostFeatures.isEmpty()) { + boostFeatures.add(new BoostFeature.BoostFeatureLevel(10, true)); + boostFeatures.addAll(boostFeaturesForLevel(10)); + } } private ArrayList boostFeaturesForLevel(int level) { + boolean isGroup = isGroup(); ArrayList list = new ArrayList<>(); final MessagesController m = MessagesController.getInstance(currentAccount); if (m == null) return list; list.add(BoostFeature.of(R.drawable.menu_feature_stories, "BoostFeatureStoriesPerDay", level)); - list.add(BoostFeature.of(R.drawable.menu_feature_reactions, "BoostFeatureCustomReaction", level)); - final int nameColorsAvailable = m.peerColors != null ? m.peerColors.colorsAvailable(level) : 0; - final int profileColorsAvailable = m.profilePeerColors != null ? m.profilePeerColors.colorsAvailable(level) : 0; - if (nameColorsAvailable > 0) { + if (!isGroup) { + list.add(BoostFeature.of(R.drawable.menu_feature_reactions, "BoostFeatureCustomReaction", level)); + } + final int nameColorsAvailable = m.peerColors != null ? m.peerColors.colorsAvailable(level, false) : 0; + final int profileColorsAvailable = m.profilePeerColors != null ? m.profilePeerColors.colorsAvailable(level, isGroup) : 0; + if (!isGroup && nameColorsAvailable > 0) { list.add(BoostFeature.of(R.drawable.menu_feature_color_name, "BoostFeatureNameColor", 7)); } - if (nameColorsAvailable > 0) { + if (!isGroup && nameColorsAvailable > 0) { list.add(BoostFeature.of(R.drawable.menu_feature_links, "BoostFeatureReplyColor", nameColorsAvailable)); } - if (level >= m.channelBgIconLevelMin) { + if (!isGroup && level >= m.channelBgIconLevelMin) { list.add(BoostFeature.of(R.drawable.menu_feature_links2, R.string.BoostFeatureReplyIcon)); } - if (level >= m.channelEmojiStatusLevelMin) { + if (profileColorsAvailable > 0) { + list.add(BoostFeature.of(R.drawable.menu_feature_color_profile, isGroup ? "BoostFeatureProfileColorGroup" : "BoostFeatureProfileColor", profileColorsAvailable)); + } + if (isGroup && level >= m.groupEmojiStickersLevelMin) { + list.add(BoostFeature.of(R.drawable.menu_feature_pack, R.string.BoostFeatureCustomEmojiPack)); + } + if ((!isGroup && level >= m.channelProfileIconLevelMin) || (isGroup && level >= m.groupProfileBgIconLevelMin)) { + list.add(BoostFeature.of(R.drawable.menu_feature_cover, isGroup ? R.string.BoostFeatureProfileIconGroup : R.string.BoostFeatureProfileIcon)); + } + if (isGroup && level >= m.groupTranscribeLevelMin) { + list.add(BoostFeature.of(R.drawable.menu_feature_voice, R.string.BoostFeatureVoiceToTextConversion)); + } + if ((!isGroup && level >= m.channelEmojiStatusLevelMin) || (isGroup && level >= m.groupEmojiStatusLevelMin)) { list.add(BoostFeature.of(R.drawable.menu_feature_status, R.string.BoostFeatureEmojiStatuses, "1000+")); } - if (profileColorsAvailable > 0) { - list.add(BoostFeature.of(R.drawable.menu_feature_color_profile, "BoostFeatureProfileColor", profileColorsAvailable)); + if ((!isGroup && level >= m.channelWallpaperLevelMin) || (isGroup && level >= m.groupWallpaperLevelMin)) { + list.add(BoostFeature.of(R.drawable.menu_feature_wallpaper, isGroup ? "BoostFeatureBackgroundGroup" : "BoostFeatureBackground", 8)); } - if (level >= m.channelProfileIconLevelMin) { - list.add(BoostFeature.of(R.drawable.menu_feature_cover, R.string.BoostFeatureProfileIcon)); - } - if (level >= m.channelWallpaperLevelMin) { - list.add(BoostFeature.of(R.drawable.menu_feature_wallpaper, "BoostFeatureBackground", 8)); - } - if (level >= m.channelCustomWallpaperLevelMin) { - list.add(BoostFeature.of(R.drawable.menu_feature_custombg, R.string.BoostFeatureCustomBackground)); + if ((!isGroup && level >= m.channelCustomWallpaperLevelMin) || (isGroup && level >= m.groupCustomWallpaperLevelMin)) { + list.add(BoostFeature.of(R.drawable.menu_feature_custombg, isGroup ? R.string.BoostFeatureCustomBackgroundGroup : R.string.BoostFeatureCustomBackground)); } + Collections.reverse(list); return list; } @@ -2117,7 +2444,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp @Override protected void dispatchDraw(Canvas canvas) { - dividerPaint.setColor(Theme.getColor(Theme.key_divider, resourcesProvider)); + dividerPaint.setColor(Theme.getColor(Theme.key_sheet_scrollUp, resourcesProvider)); canvas.drawLine(dp(18), getHeight() / 2f, levelTextView.getLeft() - dp(20), getHeight() / 2f, dividerPaint); canvas.drawLine(levelTextView.getRight() + dp(20), getHeight() / 2f, getWidth() - dp(18), getHeight() / 2f, dividerPaint); @@ -2204,4 +2531,43 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } } + public static LimitReachedBottomSheet openBoostsForRemoveRestrictions(BaseFragment baseFragment, TL_stories.TL_premium_boostsStatus boostsStatus, ChannelBoostsController.CanApplyBoost canApplyBoos, long dialogId, boolean inFragment) { + if (baseFragment == null || boostsStatus == null || canApplyBoos == null || baseFragment.getContext() == null) { + return null; + } + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(baseFragment, baseFragment.getContext(), TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS, baseFragment.getCurrentAccount(), baseFragment.getResourceProvider()); + limitReachedBottomSheet.setCanApplyBoost(canApplyBoos); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + if (inFragment) { + baseFragment.showDialog(limitReachedBottomSheet); + } else { + limitReachedBottomSheet.show(); + } + return limitReachedBottomSheet; + } + + public static void openBoostsForUsers(BaseFragment baseFragment, boolean isCurrentChat, long dialogId, ChannelBoostsController.CanApplyBoost canApplyBoost, TL_stories.TL_premium_boostsStatus boostsStatus, ChatMessageCell chatMessageCell) { + if (baseFragment == null || canApplyBoost == null || boostsStatus == null || baseFragment.getContext() == null) { + return; + } + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(baseFragment, baseFragment.getContext(), TYPE_BOOSTS_FOR_USERS, baseFragment.getCurrentAccount(), baseFragment.getResourceProvider()); + limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); + limitReachedBottomSheet.setBoostsStats(boostsStatus, isCurrentChat); + limitReachedBottomSheet.setDialogId(dialogId); + limitReachedBottomSheet.setChatMessageCell(chatMessageCell); + baseFragment.showDialog(limitReachedBottomSheet); + } + + public static void openBoostsForPostingStories(BaseFragment baseFragment, long dialogId, ChannelBoostsController.CanApplyBoost canApplyBoost, TL_stories.TL_premium_boostsStatus boostsStatus, Runnable statisticAction) { + if (baseFragment == null || canApplyBoost == null || boostsStatus == null || baseFragment.getContext() == null) { + return; + } + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(baseFragment, baseFragment.getContext(), LimitReachedBottomSheet.TYPE_BOOSTS_FOR_POSTING, baseFragment.getCurrentAccount(), baseFragment.getResourceProvider()); + limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + limitReachedBottomSheet.showStatisticButtonInLink(statisticAction); + limitReachedBottomSheet.show(); + } } 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 6a9e3f480..4c891c19c 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 @@ -27,10 +27,11 @@ import org.telegram.ui.Components.CircularProgressDrawable; import org.telegram.ui.Components.CounterView; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Loadable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.voip.CellFlickerDrawable; -public class PremiumButtonView extends FrameLayout { +public class PremiumButtonView extends FrameLayout implements Loadable { private Paint paintOverlayPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -39,7 +40,6 @@ public class PremiumButtonView extends FrameLayout { public AnimatedTextView buttonTextView; public AnimatedTextView overlayTextView; private int radius; - private boolean showOverlay; private float overlayProgress; public FrameLayout buttonLayout; @@ -158,6 +158,10 @@ public class PremiumButtonView extends FrameLayout { } } + public boolean isShowOverlay() { + return showOverlay; + } + public RLottieImageView getIconView() { return iconView; } 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 be24d2481..baa90bbb1 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 @@ -2,6 +2,7 @@ package org.telegram.ui.Components.Premium; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.LinearGradient; import android.graphics.Matrix; @@ -160,6 +161,7 @@ public class PremiumGradient { final int colorKey1, colorKey2, colorKey3, colorKey4, colorKey5; final int colors[] = new int[5]; public boolean exactly; + public boolean darkColors; public float x1 = 0f, y1 = 1f, x2 = 1.5f, y2 = 0f; @@ -217,12 +219,28 @@ public class PremiumGradient { } } + protected int getThemeColorByKey(int key) { + return Theme.getColor(key, resourcesProvider); + } + + private int getColor(int key) { + int color = getThemeColorByKey(key); + if (darkColors) { + float a = Color.alpha(color); + float r = Color.red(color) - 15; + float g = Color.green(color) - 15; + float b = Color.blue(color) - 15; + return Color.argb((int) a, (int) r, (int) g, (int) b); + } + return color; + } + private void chekColors() { - 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); + int c1 = getColor(colorKey1); + int c2 = getColor(colorKey2); + int c3 = colorKey3 < 0 ? 0 : getColor(colorKey3); + int c4 = colorKey4 < 0 ? 0 : getColor(colorKey4); + int c5 = colorKey5 < 0 ? 0 : getColor(colorKey5); 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 9e02c3037..a94e1c3dc 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 @@ -67,7 +67,7 @@ public class StarParticlesView extends View { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int sizeInternal = getMeasuredWidth() << 16 + getMeasuredHeight(); - drawable.rect.set(0, 0, AndroidUtilities.dp(140), AndroidUtilities.dp(140)); + drawable.rect.set(0, 0, getStarsRectWidth(), AndroidUtilities.dp(140)); drawable.rect.offset((getMeasuredWidth() - drawable.rect.width()) / 2, (getMeasuredHeight() - drawable.rect.height()) / 2); drawable.rect2.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); if (size != sizeInternal) { @@ -76,6 +76,10 @@ public class StarParticlesView extends View { } } + protected int getStarsRectWidth() { + return AndroidUtilities.dp(140); + } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -329,11 +333,7 @@ public class StarParticlesView extends View { paint1.setPathEffect(null); paint1.setAlpha(255); } else { - if (type == 100) { - paint.setColor(ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 200)); - } else { - paint.setColor(Theme.getColor(colorKey, resourcesProvider)); - } + paint.setColor(getPathColor()); if (roundEffect) { paint.setPathEffect(new CornerPathEffect(AndroidUtilities.dpf2(size1 / 5f))); } @@ -345,6 +345,13 @@ public class StarParticlesView extends View { } } + protected int getPathColor() { + if (type == 100) { + return ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 200); + } else { + return Theme.getColor(colorKey, resourcesProvider); + } + } public void resetPositions() { long time = System.currentTimeMillis(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterSpan.java new file mode 100644 index 000000000..7e5a46d64 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterSpan.java @@ -0,0 +1,100 @@ +package org.telegram.ui.Components.Premium.boosts; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.style.ReplacementSpan; +import android.util.Pair; +import android.view.Gravity; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.CubicBezierInterpolator; + +public class BoostCounterSpan extends ReplacementSpan { + private final Drawable boostProfileBadge; + private final Drawable boostProfileBadge2; + public boolean isRtl; + + public static Pair create(View parent, TextPaint paint, int count) { + SpannableString spannableString = new SpannableString("d"); + BoostCounterSpan span = new BoostCounterSpan(parent, paint, count); + spannableString.setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return new Pair<>(spannableString, span); + } + + private final AnimatedTextView.AnimatedTextDrawable countText; + private final TextPaint namePaint; + private final View parent; + private int currentCount; + + public BoostCounterSpan(View parent, TextPaint namePaint, int count) { + this.namePaint = namePaint; + this.parent = parent; + countText = new AnimatedTextView.AnimatedTextDrawable(false, false, true); + countText.setAnimationProperties(.3f, 0, 250, CubicBezierInterpolator.EASE_OUT_QUINT); + countText.setCallback(parent); + countText.setTextSize(dp(11.5f)); + countText.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + countText.setText(""); + countText.setGravity(Gravity.CENTER); + boostProfileBadge = ContextCompat.getDrawable(parent.getContext(), R.drawable.mini_boost_profile_badge).mutate(); + boostProfileBadge2 = ContextCompat.getDrawable(parent.getContext(), R.drawable.mini_boost_profile_badge2).mutate(); + boostProfileBadge.setBounds(0, 0, boostProfileBadge.getIntrinsicWidth(), boostProfileBadge.getIntrinsicHeight()); + boostProfileBadge2.setBounds(0, 0, boostProfileBadge2.getIntrinsicWidth(), boostProfileBadge2.getIntrinsicHeight()); + setCount(count, false); + } + + public void setCount(int count, boolean animated) { + currentCount = count; + countText.setText(count <= 1 ? "" : String.valueOf(count), animated); + } + + public void setColor(int color) { + countText.setTextColor(color); + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + return getWidth(); + } + + public int getWidth() { + return (int) (dp(16) + countText.getWidth()); + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float _x, int top, int _y, int bottom, @NonNull Paint paint) { + if (this.namePaint.getColor() != countText.getTextColor()) { + countText.setTextColor(this.namePaint.getColor()); + boostProfileBadge.setColorFilter(new PorterDuffColorFilter(countText.getTextColor(), PorterDuff.Mode.MULTIPLY)); + boostProfileBadge2.setColorFilter(new PorterDuffColorFilter(countText.getTextColor(), PorterDuff.Mode.MULTIPLY)); + } + canvas.save(); + canvas.translate(_x, -dp(0.2f)); + if (currentCount == 1) { + canvas.translate(dp(1.5f), 0); + boostProfileBadge.draw(canvas); + } else { + boostProfileBadge2.draw(canvas); + } + canvas.translate(dp(16), 0); + AndroidUtilities.rectTmp2.set(0, 0, (int) countText.getCurrentWidth(), (int) countText.getHeight()); + countText.setBounds(AndroidUtilities.rectTmp2); + countText.draw(canvas); + canvas.restore(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java index 176fbef65..3f4f9dab5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java @@ -29,6 +29,7 @@ import android.widget.Toast; import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -45,6 +46,7 @@ import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.BoostsActivity; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; @@ -104,19 +106,13 @@ public class BoostDialogs { isGiveaway ? getString("BoostingGiveawayCreated", R.string.BoostingGiveawayCreated) : getString("BoostingAwardsCreated", R.string.BoostingAwardsCreated), AndroidUtilities.replaceSingleTag( - isGiveaway ? getString("BoostingCheckStatistic", R.string.BoostingCheckStatistic) : - getString("BoostingCheckGiftsStatistic", R.string.BoostingCheckGiftsStatistic), + isGiveaway ? getString(ChatObject.isChannelAndNotMegaGroup(chat) ? R.string.BoostingCheckStatistic : R.string.BoostingCheckStatisticGroup) : + getString(ChatObject.isChannelAndNotMegaGroup(chat) ? R.string.BoostingCheckGiftsStatistic : R.string.BoostingCheckGiftsStatisticGroup), Theme.key_undo_cancelColor, 0, () -> { if (chat != null) { - Bundle args = new Bundle(); - args.putLong("chat_id", chat.id); - args.putBoolean("is_megagroup", chat.megagroup); - args.putBoolean("start_from_boosts", true); - args.putBoolean("only_boosts", true); - StatisticActivity fragment = new StatisticActivity(args); BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); params.transitionFromLeft = true; - LaunchActivity.getLastFragment().showAsSheet(fragment, params); + LaunchActivity.getLastFragment().showAsSheet(new BoostsActivity(-chat.id), params); } }, resourcesProvider) ).setDuration(Bulletin.DURATION_PROLONG).show(), 300); @@ -506,7 +502,7 @@ public class BoostDialogs { return false; } - public static void showAbout(String from, long msgDate, TLRPC.TL_payments_giveawayInfo giveawayInfo, TLRPC.TL_messageMediaGiveaway giveaway, Context context, Theme.ResourcesProvider resourcesProvider) { + public static void showAbout(boolean isChannel, String from, long msgDate, TLRPC.TL_payments_giveawayInfo giveawayInfo, TLRPC.TL_messageMediaGiveaway giveaway, Context context, Theme.ResourcesProvider resourcesProvider) { int quantity = giveaway.quantity; String months = formatPluralString("BoldMonths", giveaway.months); String endDate = LocaleController.getInstance().formatterGiveawayMonthDay.format(new Date(giveaway.until_date * 1000L)); @@ -518,7 +514,7 @@ public class BoostDialogs { builder.setTitle(getString("BoostingGiveAwayAbout", R.string.BoostingGiveAwayAbout)); SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); - stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksText", quantity, from, quantity, months))); + stringBuilder.append(replaceTags(formatPluralString(isChannel ? "BoostingGiveawayHowItWorksText" : "BoostingGiveawayHowItWorksTextGroup", quantity, from, quantity, months))); stringBuilder.append("\n\n"); if (giveaway.prize_description != null && !giveaway.prize_description.isEmpty()) { @@ -555,7 +551,7 @@ public class BoostDialogs { } else if (giveawayInfo.admin_disallowed_chat_id != 0) { TLRPC.Chat badChat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(giveawayInfo.admin_disallowed_chat_id); String title = badChat != null ? badChat.title : ""; - stringBuilder.append(replaceTags(formatString("BoostingGiveawayNotEligibleAdmin", R.string.BoostingGiveawayNotEligibleAdmin, title))); + stringBuilder.append(replaceTags(formatString(isChannel ? R.string.BoostingGiveawayNotEligibleAdmin : R.string.BoostingGiveawayNotEligibleAdminGroup, title))); } else if (giveawayInfo.joined_too_early_date != 0) { String date = LocaleController.getInstance().formatterGiveawayMonthDayYear.format(new Date(giveawayInfo.joined_too_early_date * 1000L)); stringBuilder.append(replaceTags(formatString("BoostingGiveawayNotEligible", R.string.BoostingGiveawayNotEligible, date))); @@ -574,7 +570,7 @@ public class BoostDialogs { applyDialogStyle(builder.show(), false); } - public static void showAboutEnd(String from, long msgDate, TLRPC.TL_payments_giveawayInfoResults giveawayInfo, TLRPC.TL_messageMediaGiveaway giveaway, Context context, Theme.ResourcesProvider resourcesProvider) { + public static void showAboutEnd(boolean isChannel, String from, long msgDate, TLRPC.TL_payments_giveawayInfoResults giveawayInfo, TLRPC.TL_messageMediaGiveaway giveaway, Context context, Theme.ResourcesProvider resourcesProvider) { if (giveaway.until_date == 0) { giveaway.until_date = giveawayInfo.finish_date; } @@ -589,7 +585,7 @@ public class BoostDialogs { builder.setTitle(getString("BoostingGiveawayEnd", R.string.BoostingGiveawayEnd)); SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); - stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksTextEnd", quantity, from, quantity, months))); + stringBuilder.append(replaceTags(formatPluralString(isChannel ? "BoostingGiveawayHowItWorksTextEnd" : "BoostingGiveawayHowItWorksTextEndGroup", quantity, from, quantity, months))); stringBuilder.append("\n\n"); if (giveaway.prize_description != null && !giveaway.prize_description.isEmpty()) { @@ -676,11 +672,12 @@ public class BoostDialogs { } } - public static void showPrivateChannelAlert(Context context, Theme.ResourcesProvider resourcesProvider, Runnable onCanceled, Runnable onAccepted) { + public static void showPrivateChannelAlert(TLRPC.Chat chat, Context context, Theme.ResourcesProvider resourcesProvider, Runnable onCanceled, Runnable onAccepted) { final AtomicBoolean isAddButtonClicked = new AtomicBoolean(false); AlertDialog.Builder builder = new AlertDialog.Builder(context, resourcesProvider); - builder.setTitle(getString("BoostingGiveawayPrivateChannel", R.string.BoostingGiveawayPrivateChannel)); - builder.setMessage(getString("BoostingGiveawayPrivateChannelWarning", R.string.BoostingGiveawayPrivateChannelWarning)); + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); + builder.setTitle(getString(isChannel ? R.string.BoostingGiveawayPrivateChannel : R.string.BoostingGiveawayPrivateGroup)); + builder.setMessage(getString(isChannel ? R.string.BoostingGiveawayPrivateChannelWarning : R.string.BoostingGiveawayPrivateGroupWarning)); builder.setPositiveButton(getString("Add", R.string.Add), (dialogInterface, i) -> { isAddButtonClicked.set(true); onAccepted.run(); @@ -715,6 +712,7 @@ public class BoostDialogs { } final String fromName = getGiveawayCreatorName(messageObject); + final boolean isChannel = isChannel(messageObject); final long msgDate = messageObject.messageOwner.date * 1000L; BoostRepository.getGiveawayInfo(messageObject, result -> { if (isCanceled.get()) { @@ -723,10 +721,10 @@ public class BoostDialogs { progress.end(); if (result instanceof TLRPC.TL_payments_giveawayInfo) { TLRPC.TL_payments_giveawayInfo giveawayInfo = (TLRPC.TL_payments_giveawayInfo) result; - showAbout(fromName, msgDate, giveawayInfo, giveaway, context, resourcesProvider); + showAbout(isChannel, fromName, msgDate, giveawayInfo, giveaway, context, resourcesProvider); } else if (result instanceof TLRPC.TL_payments_giveawayInfoResults) { TLRPC.TL_payments_giveawayInfoResults giveawayInfoResults = (TLRPC.TL_payments_giveawayInfoResults) result; - showAboutEnd(fromName, msgDate, giveawayInfoResults, giveaway, context, resourcesProvider); + showAboutEnd(isChannel, fromName, msgDate, giveawayInfoResults, giveaway, context, resourcesProvider); } }, error -> { if (isCanceled.get()) { @@ -736,6 +734,15 @@ public class BoostDialogs { }); } + private static boolean isChannel(MessageObject messageObject) { + if (messageObject == null) { + return false; + } + final long chatId = messageObject.getFromChatId(); + TLRPC.Chat chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-chatId); + return chat != null && ChatObject.isChannelAndNotMegaGroup(chat); + } + private static String getGiveawayCreatorName(MessageObject messageObject) { if (messageObject == null) { return ""; @@ -743,7 +750,7 @@ public class BoostDialogs { String forwardedName = messageObject.getForwardedName(); final String name; if (forwardedName == null) { - final long chatId = messageObject.getFromChatId(); + final long chatId = MessageObject.getPeerId(messageObject.messageOwner.peer_id); TLRPC.Chat chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-chatId); name = chat != null ? chat.title : ""; } else { @@ -775,6 +782,7 @@ public class BoostDialogs { return; } final String fromName = getGiveawayCreatorName(messageObject); + final boolean isChannel = isChannel(messageObject); final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), fragment.getResourceProvider()); if (result instanceof TLRPC.TL_payments_giveawayInfoResults) { @@ -799,10 +807,10 @@ public class BoostDialogs { .setUndoAction(() -> { if (result instanceof TLRPC.TL_payments_giveawayInfo) { TLRPC.TL_payments_giveawayInfo giveawayInfo = (TLRPC.TL_payments_giveawayInfo) result; - showAbout(fromName, msgDate, giveawayInfo, giveaway, fragment.getParentActivity(), fragment.getResourceProvider()); + showAbout(isChannel, fromName, msgDate, giveawayInfo, giveaway, fragment.getParentActivity(), fragment.getResourceProvider()); } else if (result instanceof TLRPC.TL_payments_giveawayInfoResults) { TLRPC.TL_payments_giveawayInfoResults giveawayInfoResults = (TLRPC.TL_payments_giveawayInfoResults) result; - showAboutEnd(fromName, msgDate, giveawayInfoResults, giveaway, fragment.getParentActivity(), fragment.getResourceProvider()); + showAboutEnd(isChannel, fromName, msgDate, giveawayInfoResults, giveaway, fragment.getParentActivity(), fragment.getResourceProvider()); } })); Bulletin.make(fragment, layout, Bulletin.DURATION_LONG).show(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java index 59a64747f..88b3018d5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java @@ -95,7 +95,7 @@ public class BoostRepository { TLRPC.Dialog dialog = dialogs.get(i); if (DialogObject.isChatDialog(dialog.id)) { TLRPC.Chat chat = messagesController.getChat(-dialog.id); - if (ChatObject.isChannelAndNotMegaGroup(chat) && -dialog.id != currentChatId) { + if (ChatObject.isBoostSupported(chat) && -dialog.id != currentChatId) { peers.add(messagesController.getInputPeer(dialog.id)); } } @@ -602,7 +602,7 @@ public class BoostRepository { for (int a = 0; a < res.chats.size(); a++) { TLRPC.Chat chat = res.chats.get(a); TLRPC.InputPeer inputPeer = MessagesController.getInputPeer(chat); - if (chat.id != currentChatId && ChatObject.isChannelAndNotMegaGroup(chat)) { + if (chat.id != currentChatId && ChatObject.isBoostSupported(chat)) { result.add(inputPeer); } } @@ -676,9 +676,8 @@ public class BoostRepository { ConnectionsManager connection = ConnectionsManager.getInstance(UserConfig.selectedAccount); MessagesController controller = MessagesController.getInstance(UserConfig.selectedAccount); TLRPC.TL_payments_getGiveawayInfo req = new TLRPC.TL_payments_getGiveawayInfo(); - long selfId = UserConfig.getInstance(UserConfig.selectedAccount).getClientUserId(); req.msg_id = messageObject.getId(); - req.peer = controller.getInputPeer(messageObject.getFromChatId()); + req.peer = controller.getInputPeer(MessageObject.getPeerId(messageObject.messageOwner.peer_id)); int reqId = connection.sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error != null) { onError.run(error); @@ -726,6 +725,6 @@ public class BoostRepository { controller.putChats(myBoosts.chats, false); onDone.run(myBoosts); } - }), ConnectionsManager.RequestFlagDoNotWaitFloodWait); + }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostViaGiftsBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostViaGiftsBottomSheet.java index 33d178588..785b12c49 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostViaGiftsBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostViaGiftsBottomSheet.java @@ -11,6 +11,7 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; @@ -168,7 +169,7 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im } }); this.currentChat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - this.adapter.setItems(items, recyclerListView, sliderIndex -> { + this.adapter.setItems(currentChat, items, recyclerListView, sliderIndex -> { selectedSliderIndex = sliderIndex; actionBtn.updateCounter(getSelectedSliderValueWithBoosts()); updateRows(false, false); @@ -332,13 +333,14 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im items.add(Item.asBoost(BoostTypeCell.TYPE_SPECIFIC_USERS, selectedUsers.size(), selectedUsers.size() > 0 ? selectedUsers.get(0) : null, selectedBoostType)); } items.add(Item.asDivider()); + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(currentChat); if (selectedBoostType == BoostTypeCell.TYPE_GIVEAWAY) { if (!isPreparedGiveaway()) { items.add(Item.asSubTitleWithCounter(LocaleController.getString("BoostingQuantityPrizes", R.string.BoostingQuantityPrizes), getSelectedSliderValueWithBoosts())); items.add(Item.asSlider(sliderValues, selectedSliderIndex)); items.add(Item.asDivider(LocaleController.getString("BoostingChooseHowMany", R.string.BoostingChooseHowMany), false)); } - items.add(Item.asSubTitle(LocaleController.getString("BoostingChannelsIncludedGiveaway", R.string.BoostingChannelsIncludedGiveaway))); + items.add(Item.asSubTitle(LocaleController.getString("BoostingChannelsGroupsIncludedGiveaway", R.string.BoostingChannelsGroupsIncludedGiveaway))); if (isPreparedGiveaway()) { items.add(Item.asChat(currentChat, false, prepaidGiveaway.quantity * BoostRepository.giveawayBoostsPerPremium())); } else { @@ -355,11 +357,11 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im if (selectedChats.size() < BoostRepository.giveawayAddPeersMax()) { items.add(Item.asAddChannel()); } - items.add(Item.asDivider(LocaleController.getString("BoostingChooseChannelsNeedToJoin", R.string.BoostingChooseChannelsNeedToJoin), false)); + items.add(Item.asDivider(LocaleController.getString("BoostingChooseChannelsGroupsNeedToJoin", R.string.BoostingChooseChannelsGroupsNeedToJoin), false)); items.add(Item.asSubTitle(LocaleController.getString("BoostingEligibleUsers", R.string.BoostingEligibleUsers))); items.add(Item.asParticipants(ParticipantsTypeCell.TYPE_ALL, selectedParticipantsType, true, selectedCountries)); items.add(Item.asParticipants(ParticipantsTypeCell.TYPE_NEW, selectedParticipantsType, false, selectedCountries)); - items.add(Item.asDivider(LocaleController.getString("BoostingChooseLimitGiveaway", R.string.BoostingChooseLimitGiveaway), false)); + items.add(Item.asDivider(LocaleController.getString(isChannel ? R.string.BoostingChooseLimitGiveaway : R.string.BoostingChooseLimitGiveawayGroups), false)); } if (!isPreparedGiveaway()) { @@ -406,10 +408,10 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im items.add(Item.asDateEnd(selectedEndDate)); if (!isPreparedGiveaway()) { - items.add(Item.asDivider(LocaleController.formatPluralString("BoostingChooseRandom", getSelectedSliderValue()), false)); + items.add(Item.asDivider(LocaleController.formatPluralString(isChannel ? "BoostingChooseRandom" : "BoostingChooseRandomGroup", getSelectedSliderValue()), false)); } else { items.add(Item.asDivider(AndroidUtilities.replaceSingleTag( - LocaleController.formatPluralString("BoostingChooseRandom", prepaidGiveaway.quantity) + "\n\n" + LocaleController.getString("BoostingStoriesFeaturesAndTerms", R.string.BoostingStoriesFeaturesAndTerms), + LocaleController.formatPluralString(isChannel ? "BoostingChooseRandom" : "BoostingChooseRandomGroup", prepaidGiveaway.quantity) + "\n\n" + LocaleController.getString("BoostingStoriesFeaturesAndTerms", R.string.BoostingStoriesFeaturesAndTerms), Theme.key_chat_messageLinkIn, 0, () -> { PremiumPreviewBottomSheet previewBottomSheet = new PremiumPreviewBottomSheet(getBaseFragment(), currentAccount, null, resourcesProvider); previewBottomSheet.setOnDismissListener(dialog -> adapter.setPausedStars(false)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/DiscountSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/DiscountSpan.java index 00a72c9f3..530a0f310 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/DiscountSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/DiscountSpan.java @@ -71,7 +71,7 @@ public class DiscountSpan extends ReplacementSpan { } bgPaint.setColor(color); textPaint.setColor(AndroidUtilities.computePerceivedBrightness(color) > .721f ? Color.BLACK : Color.WHITE); - float x = _x + dp(6), y = _y - height + dp(2f); + float x = _x + dp(10), y = _y - height + dp(2f); AndroidUtilities.rectTmp.set(x, y, x + width, y + height); float r = dp(4f); AndroidUtilities.rectTmp.inset(dp(-4.5f), dp(-1.66f)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java index 103ad2ad5..ce9a776dd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java @@ -178,7 +178,7 @@ public class SelectorBottomSheet extends BottomSheetWithRecyclerListView { searchField.updateSpans(true, selectedIds, () -> updateList(true, false), null); updateList(true, false); if (chat != null && !ChatObject.isPublic(chat) && selectedIds.contains(id)) { - BoostDialogs.showPrivateChannelAlert(getBaseFragment().getContext(), resourcesProvider, () -> { + BoostDialogs.showPrivateChannelAlert(chat, getBaseFragment().getContext(), resourcesProvider, () -> { selectedIds.remove(id); searchField.updateSpans(true, selectedIds, () -> updateList(true, false), null); updateList(true, false); @@ -439,11 +439,12 @@ public class SelectorBottomSheet extends BottomSheetWithRecyclerListView { String text; switch (type) { case TYPE_CHANNEL: - text = LocaleController.formatPluralString("BoostingSelectUpToPlural", (int) BoostRepository.giveawayAddPeersMax()); + text = LocaleController.formatPluralString("BoostingSelectUpToGroupChannelPlural", (int) BoostRepository.giveawayAddPeersMax()); sectionCell.setLayerHeight(32); break; case TYPE_USER: - text = LocaleController.formatPluralStringComma("Subscribers", Math.max(0, selectorAdapter.getParticipantsCount(currentChat) - 1)); + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(currentChat); + text = LocaleController.formatPluralStringComma(isChannel ? "Subscribers" : "Members", Math.max(0, selectorAdapter.getParticipantsCount(currentChat) - 1)); sectionCell.setLayerHeight(32); break; case TYPE_COUNTRY: @@ -460,7 +461,7 @@ public class SelectorBottomSheet extends BottomSheetWithRecyclerListView { String text = ""; switch (type) { case TYPE_CHANNEL: - text = LocaleController.formatPluralString("BoostingSelectUpToWarningChannelsPlural", (int) BoostRepository.giveawayAddPeersMax()); + text = LocaleController.formatPluralString("BoostingSelectUpToWarningChannelsGroupsPlural", (int) BoostRepository.giveawayAddPeersMax()); break; case TYPE_USER: text = LocaleController.getString("BoostingSelectUpToWarningUsers", R.string.BoostingSelectUpToWarningUsers); @@ -671,7 +672,7 @@ public class SelectorBottomSheet extends BottomSheetWithRecyclerListView { protected CharSequence getTitle() { switch (type) { case TYPE_CHANNEL: - return LocaleController.getString("BoostingAddChannel", R.string.BoostingAddChannel); + return LocaleController.getString("BoostingAddChannelOrGroup", R.string.BoostingAddChannelOrGroup); case TYPE_USER: return LocaleController.getString("GiftPremium", R.string.GiftPremium); case TYPE_COUNTRY: diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/BoostAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/BoostAdapter.java index 0fddfb8dc..e5067eeae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/BoostAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/BoostAdapter.java @@ -18,6 +18,7 @@ import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.Premium.boosts.BoostRepository; import org.telegram.ui.Components.Premium.boosts.cells.AddChannelCell; import org.telegram.ui.Components.Premium.boosts.cells.BoostTypeCell; import org.telegram.ui.Components.Premium.boosts.cells.BoostTypeSingleCell; @@ -35,6 +36,7 @@ import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SlideChooseView; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public class BoostAdapter extends AdapterWithDiffUtils { @@ -64,19 +66,39 @@ public class BoostAdapter extends AdapterWithDiffUtils { private ChatCell.ChatDeleteListener chatDeleteListener; private HeaderCell headerCell; private EnterPrizeCell.AfterTextChangedListener afterTextChangedListener; + private TLRPC.Chat currentChat; + private HashMap chatsParticipantsCount = new HashMap<>(); public BoostAdapter(Theme.ResourcesProvider resourcesProvider) { this.resourcesProvider = resourcesProvider; + BoostRepository.loadParticipantsCount(result -> { + chatsParticipantsCount.clear(); + chatsParticipantsCount.putAll(result); + }); } - public void setItems(List items, RecyclerListView recyclerListView, SlideChooseView.Callback sliderCallback, ChatCell.ChatDeleteListener chatDeleteListener, EnterPrizeCell.AfterTextChangedListener afterTextChangedListener) { + public void setItems(TLRPC.Chat currentChat, List items, RecyclerListView recyclerListView, SlideChooseView.Callback sliderCallback, ChatCell.ChatDeleteListener chatDeleteListener, EnterPrizeCell.AfterTextChangedListener afterTextChangedListener) { this.items = items; + this.currentChat = currentChat; this.recyclerListView = recyclerListView; this.sliderCallback = sliderCallback; this.chatDeleteListener = chatDeleteListener; this.afterTextChangedListener = afterTextChangedListener; } + private int getParticipantsCount(TLRPC.Chat chat) { + TLRPC.ChatFull chatFull = MessagesController.getInstance(UserConfig.selectedAccount).getChatFull(chat.id); + if (chatFull != null && chatFull.participants_count > 0) { + return chatFull.participants_count; + } else if (!chatsParticipantsCount.isEmpty()) { + Integer count = chatsParticipantsCount.get(chat.id); + if (count != null) { + return count; + } + } + return chat.participants_count; + } + public void updateBoostCounter(int value) { for (int i = 0; i < recyclerListView.getChildCount(); ++i) { View child = recyclerListView.getChildAt(i); @@ -84,7 +106,8 @@ public class BoostAdapter extends AdapterWithDiffUtils { ((SubtitleWithCounterCell) child).updateCounter(true, value); } if (child instanceof ChatCell) { - ((ChatCell) child).setCounter(value); + ChatCell chatCell = ((ChatCell) child); + chatCell.setCounter(value, getParticipantsCount(chatCell.getChat())); } } notifyItemChanged(8); //update main channel @@ -256,7 +279,7 @@ public class BoostAdapter extends AdapterWithDiffUtils { switch (viewType) { case HOLDER_TYPE_HEADER: { headerCell = (HeaderCell) holder.itemView; - headerCell.setBoostViaGifsText(); + headerCell.setBoostViaGifsText(currentChat); break; } case HOLDER_TYPE_BOOST_TYPE: { @@ -297,19 +320,21 @@ public class BoostAdapter extends AdapterWithDiffUtils { if (item.peer != null) { TLRPC.InputPeer peer = item.peer; if (peer instanceof TLRPC.TL_inputPeerChat) { - cell.setChat(MessagesController.getInstance(UserConfig.selectedAccount).getChat(peer.chat_id), item.intValue, item.boolValue); + TLRPC.Chat chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(peer.chat_id); + cell.setChat(chat, item.intValue, item.boolValue, getParticipantsCount(chat)); } else if (peer instanceof TLRPC.TL_inputPeerChannel) { - cell.setChat(MessagesController.getInstance(UserConfig.selectedAccount).getChat(peer.channel_id), item.intValue, item.boolValue); + TLRPC.Chat chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(peer.channel_id); + cell.setChat(chat, item.intValue, item.boolValue, getParticipantsCount(chat)); } } else { - cell.setChat(item.chat, item.intValue, item.boolValue); + cell.setChat(item.chat, item.intValue, item.boolValue, getParticipantsCount(item.chat)); } cell.setChatDeleteListener(chatDeleteListener); break; } case HOLDER_TYPE_PARTICIPANTS: { ParticipantsTypeCell cell = (ParticipantsTypeCell) holder.itemView; - cell.setType(item.subType, item.selectable, item.boolValue, (List) item.user); + cell.setType(item.subType, item.selectable, item.boolValue, (List) item.user, currentChat); break; } case HOLDER_TYPE_DATE_END: { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/AddChannelCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/AddChannelCell.java index 29ecda88b..d5113255d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/AddChannelCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/AddChannelCell.java @@ -37,7 +37,7 @@ public class AddChannelCell extends FrameLayout { imageView.setScaleType(ImageView.ScaleType.CENTER); addView(imageView); - textView.setText(LocaleController.getString("BoostingAddChannel", R.string.BoostingAddChannel)); + textView.setText(LocaleController.getString("BoostingAddChannelOrGroup", R.string.BoostingAddChannelOrGroup)); Drawable drawable1 = getResources().getDrawable(R.drawable.poll_add_circle); Drawable drawable2 = getResources().getDrawable(R.drawable.poll_add_plus); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java index ed15c92af..14c768887 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java @@ -8,8 +8,10 @@ import android.view.Gravity; import android.widget.ImageView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.Emoji; 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; @@ -53,7 +55,11 @@ public class ChatCell extends BaseCell { return false; } - public void setChat(TLRPC.Chat chat, int boosts, boolean removable) { + public TLRPC.Chat getChat() { + return chat; + } + + public void setChat(TLRPC.Chat chat, int boosts, boolean removable, int participants_count) { this.removable = removable; this.chat = chat; avatarDrawable.setInfo(chat); @@ -64,10 +70,17 @@ public class ChatCell extends BaseCell { text = Emoji.replaceEmoji(text, titleTextView.getPaint().getFontMetricsInt(), false); titleTextView.setText(text); + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); if (removable) { - setSubtitle(null); + String subtitle; + if (participants_count >= 1) { + subtitle = LocaleController.formatPluralString(isChannel ? "Subscribers" : "Members", participants_count); + } else { + subtitle = LocaleController.getString(isChannel ? R.string.DiscussChannel : R.string.AccDescrGroup); + } + setSubtitle(subtitle); } else { - setSubtitle(LocaleController.formatPluralString("BoostingChannelWillReceiveBoost", boosts)); + setSubtitle(LocaleController.formatPluralString(isChannel ? "BoostingChannelWillReceiveBoost" : "BoostingGroupWillReceiveBoost", boosts)); } subtitleTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray3, resourcesProvider)); @@ -88,11 +101,18 @@ public class ChatCell extends BaseCell { this.chatDeleteListener = chatDeleteListener; } - public void setCounter(int count) { + public void setCounter(int count, int participants_count) { + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); if (removable) { - setSubtitle(null); + String subtitle; + if (participants_count >= 1) { + subtitle = LocaleController.formatPluralString(isChannel ? "Subscribers" : "Members", participants_count); + } else { + subtitle = LocaleController.getString(isChannel ? R.string.DiscussChannel : R.string.AccDescrGroup); + } + setSubtitle(subtitle); } else { - setSubtitle(LocaleController.formatPluralString("BoostingChannelWillReceiveBoost", count)); + setSubtitle(LocaleController.formatPluralString(isChannel ? "BoostingChannelWillReceiveBoost" : "BoostingGroupWillReceiveBoost", count)); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationWithDiscountCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationWithDiscountCell.java index 6cd927629..19951814e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationWithDiscountCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationWithDiscountCell.java @@ -2,6 +2,7 @@ package org.telegram.ui.Components.Premium.boosts.cells; import android.annotation.SuppressLint; import android.content.Context; +import android.text.SpannableStringBuilder; import android.view.Gravity; import android.view.View; @@ -38,6 +39,7 @@ public class DurationWithDiscountCell extends DurationCell { super.updateLayouts(); titleTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 20 : 102, 0, LocaleController.isRTL ? 102 : 20, 0)); subtitleTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 20 : 102, 0, LocaleController.isRTL ? 102 : 20, 0)); + if (checkBox != null) { checkBox.setLayoutParams(LayoutHelper.createFrame(22, 22, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 15 : 20, 0, LocaleController.isRTL ? 20 : 15, 0)); } @@ -54,19 +56,14 @@ public class DurationWithDiscountCell extends DurationCell { this.option = option; long price = option.amount; CharSequence currency = option.currency; - titleTextView.setText(LocaleController.formatPluralString("Months", option.months)); + SpannableStringBuilder titleBuilder = new SpannableStringBuilder(LocaleController.formatPluralString("Months", option.months)) ; int discount = (int) ((1.0 - (option.amount / (double) option.months) / (minOption.amount / (double) minOption.months)) * 100); - String subTitle; - if (usersCount > 1) { - subTitle = BillingController.getInstance().formatCurrency(price / usersCount, currency.toString()) + " x " + usersCount; - } else { - subTitle = LocaleController.formatString(R.string.PricePerMonth, BillingController.getInstance().formatCurrency(price / option.months, currency.toString())); - } if (discount > 0) { - setSubtitle(DiscountSpan.applySpan(subTitle, discount)); + titleTextView.setText(titleBuilder.append(DiscountSpan.applySpan("", discount))); } else { - setSubtitle(subTitle); + titleTextView.setText(titleBuilder); } + setSubtitle(null); totalTextView.setText(BillingController.getInstance().formatCurrency(usersCount > 0 ? price : 0, currency.toString())); setDivider(needDivider); checkBox.setChecked(selected, false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java index b3a38b3f9..35c71fc63 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java @@ -22,6 +22,7 @@ import androidx.annotation.NonNull; import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; @@ -126,7 +127,7 @@ public class HeaderCell extends FrameLayout { setWillNotDraw(false); } - public void setBoostViaGifsText() { + public void setBoostViaGifsText(TLRPC.Chat currentChat) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { setOutlineProvider(new ViewOutlineProvider() { @Override @@ -142,7 +143,8 @@ public class HeaderCell extends FrameLayout { setLayoutParams(lp); setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider)); titleView.setText(LocaleController.formatString("BoostingBoostsViaGifts", R.string.BoostingBoostsViaGifts)); - subtitleView.setText(LocaleController.formatString("BoostingGetMoreBoost", R.string.BoostingGetMoreBoost)); + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(currentChat); + subtitleView.setText(LocaleController.formatString(isChannel ? R.string.BoostingGetMoreBoost : R.string.BoostingGetMoreBoostGroup)); subtitleView.setTextColor(Theme.getColor(Theme.key_dialogTextGray3, resourcesProvider)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ParticipantsTypeCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ParticipantsTypeCell.java index c0f332409..415a7a785 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ParticipantsTypeCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ParticipantsTypeCell.java @@ -6,6 +6,7 @@ import android.annotation.SuppressLint; import android.content.Context; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; @@ -32,12 +33,13 @@ public class ParticipantsTypeCell extends BaseCell { return selectedType; } - public void setType(int type, boolean isSelected, boolean needDivider, List countries) { + public void setType(int type, boolean isSelected, boolean needDivider, List countries, TLRPC.Chat chat) { selectedType = type; + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); if (type == TYPE_ALL) { - titleTextView.setText(LocaleController.formatString("BoostingAllSubscribers", R.string.BoostingAllSubscribers)); + titleTextView.setText(LocaleController.formatString(isChannel ? R.string.BoostingAllSubscribers : R.string.BoostingAllMembers)); } else if (type == TYPE_NEW) { - titleTextView.setText(LocaleController.formatString("BoostingNewSubscribers", R.string.BoostingNewSubscribers)); + titleTextView.setText(LocaleController.formatString(isChannel ? R.string.BoostingNewSubscribers : R.string.BoostingNewMembers)); } radioButton.setChecked(isSelected, false); setDivider(needDivider); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java index 053255b72..1b1a110ea 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java @@ -28,6 +28,7 @@ import androidx.annotation.NonNull; import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; @@ -208,7 +209,8 @@ public class TableCell extends FrameLayout { dateTextView.setText(LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, monthTxt, timeTxt)); reasonTextView.setTextColor(Theme.getColor(giftCode.via_giveaway ? Theme.key_dialogTextBlue : Theme.key_dialogTextBlack, resourcesProvider)); - + TLRPC.Chat fromChat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-DialogObject.getPeerDialogId(giftCode.from_id)); + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(fromChat); if (giftCode.via_giveaway) { SpannableStringBuilder builder = new SpannableStringBuilder(); builder.append("**"); @@ -218,14 +220,13 @@ public class TableCell extends FrameLayout { reasonTextView.setText(builder); reasonTextView.setOnClickListener(v -> onObjectClicked.run(giftCode)); } else { - reasonTextView.setText(LocaleController.getString("BoostingYouWereSelected", R.string.BoostingYouWereSelected)); + reasonTextView.setText(LocaleController.getString(isChannel ? R.string.BoostingYouWereSelected : R.string.BoostingYouWereSelectedGroup)); reasonTextView.setOnClickListener(null); } String monthsStr = giftCode.months == 12 ? LocaleController.formatPluralString("Years", 1) : LocaleController.formatPluralString("Months", giftCode.months); giftTextView.setText(LocaleController.formatString("BoostingTelegramPremiumFor", R.string.BoostingTelegramPremiumFor, monthsStr)); - TLRPC.Chat fromChat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-DialogObject.getPeerDialogId(giftCode.from_id)); if (fromChat != null) { SpannableStringBuilder builder = new SpannableStringBuilder(); builder.append("**"); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java index 9893bb262..e6ed10bce 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java @@ -278,6 +278,9 @@ public class GiveawayMessageCell { maxWidth = parentWidth - AndroidUtilities.dp(80); } + MessagesController controller = MessagesController.getInstance(UserConfig.selectedAccount); + TLRPC.Chat fromChat = controller.getChat(-MessageObject.getPeerId(messageObject.isForwarded() ? messageObject.messageOwner.fwd_from.from_id : messageObject.messageOwner.peer_id)); + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(fromChat); CharSequence giveawayPrizes = replaceTags(getString("BoostingGiveawayPrizes", R.string.BoostingGiveawayPrizes)); SpannableStringBuilder titleStringBuilder = new SpannableStringBuilder(giveawayPrizes); titleStringBuilder.setSpan(new RelativeSizeSpan(1.05f), 0, giveawayPrizes.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -299,9 +302,9 @@ public class GiveawayMessageCell { topStringBuilder.append("\n"); if (giveaway.only_new_subscribers) { - topStringBuilder.append(formatPluralString("BoostingGiveawayMsgNewSubsPlural", giveaway.channels.size())); + topStringBuilder.append(formatPluralString(isChannel ? "BoostingGiveawayMsgNewSubsPlural" : "BoostingGiveawayMsgNewSubsGroupPlural", giveaway.channels.size())); } else { - topStringBuilder.append(formatPluralString("BoostingGiveawayMsgAllSubsPlural", giveaway.channels.size())); + topStringBuilder.append(formatPluralString(isChannel ? "BoostingGiveawayMsgAllSubsPlural" : "BoostingGiveawayMsgAllSubsGroupPlural", giveaway.channels.size())); } CharSequence dateTitle = replaceTags(getString("BoostingWinnersDate", R.string.BoostingWinnersDate)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorUserCell.java index 5fd143334..fc28f0bc1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorUserCell.java @@ -21,6 +21,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Premium.boosts.cells.BaseCell; +import org.telegram.ui.Components.StatusBadgeComponent; import java.util.Date; @@ -32,9 +33,11 @@ public class SelectorUserCell extends BaseCell { private TLRPC.User user; private TLRPC.Chat chat; private TL_stories.TL_myBoost boost; + StatusBadgeComponent statusBadgeComponent; public SelectorUserCell(Context context, Theme.ResourcesProvider resourcesProvider, boolean isGreen) { super(context, resourcesProvider); + statusBadgeComponent = new StatusBadgeComponent(this); titleTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); radioButton.setVisibility(View.GONE); checkBox = new CheckBox2(context, 21, resourcesProvider); @@ -50,6 +53,18 @@ public class SelectorUserCell extends BaseCell { checkBox.setLayoutParams(LayoutHelper.createFrame(24, 24, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 13, 0, 14, 0)); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + statusBadgeComponent.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + statusBadgeComponent.onDetachedFromWindow(); + } + public TLRPC.User getUser() { return user; } @@ -91,6 +106,7 @@ public class SelectorUserCell extends BaseCell { setSubtitle(LocaleController.formatUserStatus(UserConfig.selectedAccount, user, isOnline)); subtitleTextView.setTextColor(Theme.getColor(isOnline[0] ? Theme.key_dialogTextBlue2 : Theme.key_dialogTextGray3, resourcesProvider)); checkBox.setAlpha(1f); + titleTextView.setRightDrawable(statusBadgeComponent.updateDrawable(user, Theme.getColor(Theme.key_chats_verifiedBackground), false)); } public void setChat(TLRPC.Chat chat, int participants_count) { @@ -106,10 +122,11 @@ public class SelectorUserCell extends BaseCell { if (participants_count <= 0) { participants_count = chat.participants_count; } + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); if (participants_count >= 1) { - subtitle = LocaleController.formatPluralString("Subscribers", participants_count); + subtitle = LocaleController.formatPluralString(isChannel? "Subscribers" : "Members", participants_count); } else { - subtitle = LocaleController.getString(R.string.DiscussChannel); + subtitle = LocaleController.getString(isChannel ? R.string.DiscussChannel : R.string.AccDescrGroup); } setSubtitle(subtitle); subtitleTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray3, resourcesProvider)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java index 7fb97beb5..04e922d16 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java @@ -122,15 +122,7 @@ public class ReactionsUtils { limitReachedBottomSheet.setDialogId(dialogId); limitReachedBottomSheet.showStatisticButtonInLink(() -> { TLRPC.Chat chat = fragment.getMessagesController().getChat(-dialogId); - Bundle args = new Bundle(); - args.putLong("chat_id", -dialogId); - args.putBoolean("is_megagroup", chat.megagroup); - args.putBoolean("start_from_boosts", true); - TLRPC.ChatFull chatInfo = fragment.getMessagesController().getChatFull(-dialogId); - if (chatInfo == null || !chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - } - fragment.presentFragment(new StatisticActivity(args)); + fragment.presentFragment(StatisticActivity.create(chat)); }); limitReachedBottomSheet.show(); } 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 545691ae8..abceed44e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -1288,6 +1288,17 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio // } } } + for (int i = 0; i < topReactions.size(); i++) { + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(topReactions.get(i)); + if (!hashSet.contains(visibleReaction)) { + hashSet.add(visibleReaction); + visibleReactions.add(visibleReaction); + added++; + } + // if (added == 16) { + // break; + // } + } } else { for (int i = 0; i < topReactions.size(); i++) { ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(topReactions.get(i)); @@ -1873,15 +1884,15 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio pressedBackupImageView.getImageReceiver().clearImage(); loopImageView.getImageReceiver().clearImage(); AnimatedEmojiDrawable pressedDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_LARGE, currentAccount, currentReaction.documentId); - pressedBackupImageView.setAnimatedEmojiDrawable(pressedDrawable); AnimatedEmojiDrawable loopDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW, currentAccount, currentReaction.documentId); if (type == TYPE_STORY || type == TYPE_STORY_LIKES) { - pressedDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); - loopDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); + pressedDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + loopDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); } else { - pressedDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); - loopDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); + pressedDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueIcon, resourcesProvider), PorterDuff.Mode.SRC_IN)); + loopDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueIcon, resourcesProvider), PorterDuff.Mode.SRC_IN)); } + pressedBackupImageView.setAnimatedEmojiDrawable(pressedDrawable); loopImageView.setAnimatedEmojiDrawable(loopDrawable); if (lockIconView != null) { lockIconView.setAnimatedEmojiDrawable(loopDrawable); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchTagsList.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchTagsList.java index ac65f1497..5f9f55a26 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchTagsList.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchTagsList.java @@ -35,6 +35,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; @@ -68,6 +69,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; +import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; import java.util.ArrayList; @@ -367,9 +369,11 @@ public class SearchTagsList extends BlurredFrameLayout implements NotificationCe return false; } public static void openRenameTagAlert(Context context, int currentAccount, TLRPC.Reaction reaction, Theme.ResourcesProvider resourcesProvider, boolean forceNotAdaptive) { + BaseFragment fragment = LaunchActivity.getLastFragment(); Activity activity = AndroidUtilities.findActivity(context); View currentFocus = activity != null ? activity.getCurrentFocus() : null; - final boolean adaptive = currentFocus instanceof EditText && !forceNotAdaptive; + final boolean isKeyboardVisible = fragment != null && fragment.getFragmentView() instanceof SizeNotifierFrameLayout && ((SizeNotifierFrameLayout) fragment.getFragmentView()).measureKeyboardHeight() > dp(20); + final boolean adaptive = isKeyboardVisible && !forceNotAdaptive; AlertDialog[] dialog = new AlertDialog[1]; AlertDialog.Builder builder; if (adaptive) { @@ -377,7 +381,6 @@ public class SearchTagsList extends BlurredFrameLayout implements NotificationCe } else { builder = new AlertDialog.Builder(context, resourcesProvider); } - String[] hintText = new String[1]; String name = MessagesController.getInstance(currentAccount).getSavedTagName(reaction); builder.setTitle(new SpannableStringBuilder(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(reaction).toCharSequence(20)).append(" ").append(LocaleController.getString(TextUtils.isEmpty(name) ? R.string.SavedTagLabelTag : R.string.SavedTagRenameTag))); 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 5555fb858..1e257a49b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -2258,7 +2258,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } int width = getMeasuredWidth() - dp(60); if (archivedHintLayout == null || archivedHintLayout.getWidth() != width) { - archivedHintLayout = new StaticLayout(LocaleController.getString(isArchivedOnlyStoriesView() ? R.string.ProfileStoriesArchiveChannelHint : R.string.ProfileStoriesArchiveHint), archivedHintPaint, width, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false); + boolean isChannel = profileActivity != null && ChatObject.isChannelAndNotMegaGroup(profileActivity.getMessagesController().getChat(-dialog_id)); + archivedHintLayout = new StaticLayout(LocaleController.getString(isArchivedOnlyStoriesView() ? (isChannel ? R.string.ProfileStoriesArchiveChannelHint : R.string.ProfileStoriesArchiveGroupHint) : R.string.ProfileStoriesArchiveHint), archivedHintPaint, width, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false); archivedHintLayoutWidth = 0; archivedHintLayoutLeft = width; for (int i = 0; i < archivedHintLayout.getLineCount(); ++i) { @@ -4432,6 +4433,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter searchAlpha = getSearchAlpha(0); updateSearchItemIcon(0); } + if (searching && getSelectedTab() == TAB_SAVED_DIALOGS) { + return false; + } updateOptionsSearch(); getParent().requestDisallowInterceptTouchEvent(true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SlideChooseView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SlideChooseView.java index 195aee15f..4c00cd0b6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SlideChooseView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SlideChooseView.java @@ -4,6 +4,8 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.DashPathEffect; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.TextPaint; import android.view.HapticFeedbackConstants; @@ -42,6 +44,7 @@ public class SlideChooseView extends View { private String[] optionsStr; private int[] optionsSizes; + private Drawable[] leftDrawables; private int selectedIndex; private float selectedIndexTouch; @@ -96,12 +99,22 @@ public class SlideChooseView extends View { } public void setOptions(int selected, String... options) { + setOptions(selected, null, options); + } + + public void setOptions(int selected, Drawable[] leftDrawables, String... options) { this.optionsStr = options; + this.leftDrawables = leftDrawables; selectedIndex = selected; optionsSizes = new int[optionsStr.length]; for (int i = 0; i < optionsStr.length; i++) { optionsSizes[i] = (int) Math.ceil(textPaint.measureText(optionsStr[i])); } + if (this.leftDrawables != null) { + for (Drawable drawable : this.leftDrawables) { + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + } + } requestLayout(); } @@ -227,6 +240,23 @@ public class SlideChooseView extends View { int size = optionsSizes[a]; String text = optionsStr[a]; textPaint.setColor(ColorUtils.blendARGB(getThemedColor(Theme.key_windowBackgroundWhiteGrayText), getThemedColor(Theme.key_windowBackgroundWhiteBlueText), t)); + + if (leftDrawables != null) { + canvas.save(); + if (a == 0) { + canvas.translate(AndroidUtilities.dp(12), AndroidUtilities.dp(15.5f)); + } else if (a == optionsStr.length - 1) { + canvas.translate(getMeasuredWidth() - size - AndroidUtilities.dp(22) - AndroidUtilities.dp(10), AndroidUtilities.dp(28) - AndroidUtilities.dp(12.5f)); + } else { + canvas.translate(cx - size / 2 - AndroidUtilities.dp(10), AndroidUtilities.dp(28) - AndroidUtilities.dp(12.5f)); + } + leftDrawables[a].setColorFilter(textPaint.getColor(), PorterDuff.Mode.MULTIPLY); + leftDrawables[a].draw(canvas); + canvas.restore(); + canvas.save(); + canvas.translate((leftDrawables[a].getIntrinsicWidth() / 2f) - AndroidUtilities.dp(a == 0 ? 3 : 2), 0); + } + if (a == 0) { canvas.drawText(text, AndroidUtilities.dp(22), AndroidUtilities.dp(28), textPaint); } else if (a == optionsStr.length - 1) { @@ -234,6 +264,10 @@ public class SlideChooseView extends View { } else { canvas.drawText(text, cx - size / 2, AndroidUtilities.dp(28), textPaint); } + + if (leftDrawables != null) { + canvas.restore(); + } } float cx = sideSide + (lineSize + gapSize * 2 + circleSize) * selectedIndexAnimated + circleSize / 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java index 070bf2ec7..5aea3c823 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java @@ -1111,7 +1111,7 @@ public class StickersAlert extends BottomSheet implements NotificationCenter.Not } layoutManager.setSpanCount(adapter.stickersPerRow); - if (stickerSet != null && stickerSet.set != null && stickerSet.set.emojis && !UserConfig.getInstance(currentAccount).isPremium()) { + if (stickerSet != null && stickerSet.set != null && stickerSet.set.emojis && !UserConfig.getInstance(currentAccount).isPremium() && customButtonDelegate == null) { boolean hasPremiumEmoji = false; if (stickerSet.documents != null) { for (int i = 0; i < stickerSet.documents.size(); ++i) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeSmallPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeSmallPreviewView.java index c47e1176b..960ad7bcb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeSmallPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeSmallPreviewView.java @@ -237,7 +237,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe chatBackgroundDrawable = null; } } - backupImageView.setVisibility(item.chatTheme.showAsDefaultStub && fallbackWallpaper != null ? View.GONE : View.VISIBLE); + backupImageView.setVisibility(item.chatTheme.isAnyStub() && fallbackWallpaper != null ? View.GONE : View.VISIBLE); if (itemChanged || darkModeChanged) { if (animated) { @@ -332,7 +332,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe } } - if (chatThemeItem.chatTheme == null || chatThemeItem.chatTheme.showAsDefaultStub) { + if (chatThemeItem.chatTheme == null || chatThemeItem.chatTheme.isAnyStub()) { setContentDescription(LocaleController.getString(R.string.ChatNoTheme)); } else { setContentDescription(chatThemeItem.chatTheme.getEmoticon()); @@ -423,7 +423,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe color = themeItem.outBubbleColor; themeDrawable.outBubblePaintSecond.setColor(color); - int strokeColor = chatThemeItem.chatTheme.showAsDefaultStub + int strokeColor = chatThemeItem.chatTheme.isAnyStub() ? getThemedColor(Theme.key_featuredStickers_addButton) : themeItem.outLineColor; int strokeAlpha = themeDrawable.strokePaint.getAlpha(); @@ -513,7 +513,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe bitmapDrawable.setFilterBitmap(true); drawable = bitmapDrawable; } - } else if (!(chatThemeItem.chatTheme != null && chatThemeItem.chatTheme.showAsDefaultStub)) { + } else if (!(chatThemeItem.chatTheme != null && chatThemeItem.chatTheme.isAnyStub())) { drawable = new MotionBackgroundDrawable(0xffdbddbb, 0xff6ba587, 0xffd5d88d, 0xff88b884, true); } } @@ -627,7 +627,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe outlineBackgroundPaint.setAlpha(wasAlpha); } canvas.restore(); - } else if (!(chatThemeItem != null && chatThemeItem.chatTheme != null && chatThemeItem.chatTheme.showAsDefaultStub && chatBackgroundDrawable != null)) { + } else if (!(chatThemeItem != null && chatThemeItem.chatTheme != null && chatThemeItem.chatTheme.isAnyStub() && chatBackgroundDrawable != null)) { canvas.drawRoundRect(rectF, INNER_RADIUS, INNER_RADIUS, backgroundFillPaint); } } @@ -635,7 +635,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe public void draw(Canvas canvas, float alpha) { if (isSelected || strokeAlphaAnimator != null) { EmojiThemes.ThemeItem themeItem = chatThemeItem.chatTheme.getThemeItem(chatThemeItem.themeIndex); - int strokeColor = chatThemeItem.chatTheme.showAsDefaultStub + int strokeColor = chatThemeItem.chatTheme.isAnyStub() ? getThemedColor(Theme.key_featuredStickers_addButton) : themeItem.outLineColor; strokePaint.setColor(strokeColor); @@ -648,7 +648,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe inBubblePaint.setAlpha((int) (255 * alpha)); rectF.set(INNER_RECT_SPACE, INNER_RECT_SPACE, getWidth() - INNER_RECT_SPACE, getHeight() - INNER_RECT_SPACE); - if (chatThemeItem.chatTheme == null || (chatThemeItem.chatTheme.showAsDefaultStub && chatThemeItem.chatTheme.wallpaper == null)) { + if (chatThemeItem.chatTheme == null || (chatThemeItem.chatTheme.isAnyStub() && chatThemeItem.chatTheme.wallpaper == null)) { if (fallbackWallpaper == null) { canvas.drawRoundRect(rectF, INNER_RADIUS, INNER_RADIUS, backgroundFillPaint); canvas.save(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java index e846e2978..a4d50b9d0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java @@ -31,6 +31,7 @@ import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.MessageObject; @@ -813,12 +814,24 @@ public class TranscribeButton { } ConnectionsManager cc = ConnectionsManager.getInstance(messageObject.currentAccount); MessagesController mc = MessagesController.getInstance(messageObject.currentAccount); + if (isFreeTranscribeInChat(messageObject)) { + return true; + } if (mc.transcribeAudioTrialWeeklyNumber <= 0 || messageObject.getDuration() > mc.transcribeAudioTrialDurationMax) { return false; } return mc.transcribeAudioTrialCooldownUntil == 0 || cc.getCurrentTime() > mc.transcribeAudioTrialCooldownUntil || mc.transcribeAudioTrialCurrentNumber > 0; } + public static boolean isFreeTranscribeInChat(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return false; + } + MessagesController mc = MessagesController.getInstance(messageObject.currentAccount); + TLRPC.Chat chat = mc.getChat(messageObject.getChatId()); + return ChatObject.isMegagroup(chat) && chat.level >= mc.groupTranscribeLevelMin; + } + public static int getTranscribeTrialCount(int currentAccount) { ConnectionsManager cc = ConnectionsManager.getInstance(currentAccount); MessagesController mc = MessagesController.getInstance(currentAccount); @@ -834,6 +847,9 @@ public class TranscribeButton { if (messageObject == null || messageObject.messageOwner == null) { return false; } + if (isFreeTranscribeInChat(messageObject)) { + return false; + } if (!TextUtils.isEmpty(messageObject.messageOwner.voiceTranscription)) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java index dc37db13d..525d9d24a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -1376,7 +1376,7 @@ public class UndoView extends FrameLayout { infoTextView.setText(LocaleController.getString("BoostingSelectUpToWarningUsers", R.string.BoostingSelectUpToWarningUsers)); break; case ACTION_BOOSTING_SELECTOR_WARNING_CHANNEL: - infoTextView.setText(LocaleController.formatPluralString("BoostingSelectUpToWarningChannelsPlural", (int) BoostRepository.giveawayAddPeersMax())); + infoTextView.setText(LocaleController.formatPluralString("BoostingSelectUpToWarningChannelsGroupsPlural", (int) BoostRepository.giveawayAddPeersMax())); break; case ACTION_BOOSTING_SELECTOR_WARNING_COUNTRY: infoTextView.setText(LocaleController.formatPluralString("BoostingSelectUpToWarningCountriesPlural", (int) BoostRepository.giveawayCountriesMax())); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java index 2e31f826b..d4d821d89 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java @@ -52,6 +52,7 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.WebFile; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; @@ -202,6 +203,7 @@ public class ContentPreviewViewer { return; } closeOnDismiss = true; + ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(containerView.getContext(), R.drawable.popup_fixed_alert3, resourcesProvider); if (currentContentType == CONTENT_TYPE_STICKER) { if (MessageObject.isPremiumSticker(currentDocument) && !AccountInstance.getInstance(currentAccount).getUserConfig().isPremium()) { showUnlockPremiumView(); @@ -297,7 +299,6 @@ public class ContentPreviewViewer { } } }; - ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(containerView.getContext(), R.drawable.popup_fixed_alert3, resourcesProvider); for (int i = 0; i < items.size(); i++) { View item = ActionBarMenuItem.addItem(previewMenu, icons.get(i), items.get(i), false, resourcesProvider); @@ -402,8 +403,6 @@ public class ContentPreviewViewer { ic[a] = icons.get(a); } - ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(containerView.getContext(), R.drawable.popup_fixed_alert2, resourcesProvider); - View.OnClickListener onItemClickListener = v -> { if (parentActivity == null || delegate == null) { return; @@ -537,8 +536,6 @@ public class ContentPreviewViewer { ic[a] = icons.get(a); } - ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(containerView.getContext(), R.drawable.popup_fixed_alert2, resourcesProvider); - View.OnClickListener onItemClickListener = v -> { if (parentActivity == null) { return; @@ -631,6 +628,12 @@ public class ContentPreviewViewer { valueAnimator.start(); } } + for (int i = 0; i < previewMenu.getItemsCount(); ++i) { + View child = previewMenu.getItemAt(i); + if (child instanceof ActionBarMenuSubItem) { + ((ActionBarMenuSubItem) child).updateSelectorBackground(i == 0, i == previewMenu.getItemsCount() - 1, 8); + } + } } }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 6691b5e75..1403e1647 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -94,6 +94,7 @@ import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; +import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.FilesMigrationService; @@ -2695,6 +2696,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. getNotificationCenter().addObserver(this, NotificationCenter.storiesUpdated); getNotificationCenter().addObserver(this, NotificationCenter.storiesEnabledUpdate); getNotificationCenter().addObserver(this, NotificationCenter.unconfirmedAuthUpdate); + getNotificationCenter().addObserver(this, NotificationCenter.premiumPromoUpdated); if (initialDialogsType == DIALOGS_TYPE_DEFAULT) { getNotificationCenter().addObserver(this, NotificationCenter.chatlistFolderUpdate); @@ -2848,6 +2850,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. getNotificationCenter().removeObserver(this, NotificationCenter.storiesUpdated); getNotificationCenter().removeObserver(this, NotificationCenter.storiesEnabledUpdate); getNotificationCenter().removeObserver(this, NotificationCenter.unconfirmedAuthUpdate); + getNotificationCenter().removeObserver(this, NotificationCenter.premiumPromoUpdated); if (initialDialogsType == DIALOGS_TYPE_DEFAULT) { getNotificationCenter().removeObserver(this, NotificationCenter.chatlistFolderUpdate); @@ -4927,6 +4930,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. presentFragment(new MediaActivity(args, null)); }); } else { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); final String key = NotificationsController.getSharedPrefKey(dialogId, 0); boolean muted = !NotificationsCustomSettingsActivity.areStoriesNotMuted(currentAccount, dialogId); filterOptions @@ -4936,7 +4940,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. .addIf(dialogId > 0, R.drawable.msg_openprofile, LocaleController.getString("OpenProfile", R.string.OpenProfile), () -> { presentFragment(ProfileActivity.of(dialogId)); }) - .addIf(dialogId < 0, R.drawable.msg_channel, LocaleController.getString("OpenChannel2", R.string.OpenChannel2), () -> { + .addIf(dialogId < 0, R.drawable.msg_channel, LocaleController.getString(ChatObject.isChannelAndNotMegaGroup(chat) ? R.string.OpenChannel2 : R.string.OpenGroup2), () -> { presentFragment(ChatActivity.of(dialogId)); }).addIf(!muted && dialogId > 0, R.drawable.msg_mute, LocaleController.getString("NotificationsStoryMute2", R.string.NotificationsStoryMute2), () -> { MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, false).apply(); @@ -5445,7 +5449,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. public boolean isPremiumRestoreHintVisible() { if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && folderId == 0) { - return MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_RESTORE") && !getUserConfig().isPremium(); + return MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_RESTORE") && !getUserConfig().isPremium() && MediaDataController.getInstance(currentAccount).getPremiumHintAnnualDiscount(false) != null; } return false; } @@ -5705,16 +5709,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. dialogsHintCellVisible = true; dialogsHintCell.setVisibility(View.VISIBLE); dialogsHintCell.setOnClickListener(v -> UserSelectorBottomSheet.open()); - dialogsHintCell.setText( - AndroidUtilities.replaceSingleTag( - LocaleController.getString("BoostingPremiumChristmasTitle", R.string.BoostingPremiumChristmasTitle), - Theme.key_windowBackgroundWhiteValueText, - AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD, - null - ), - LocaleController.formatString("BoostingPremiumChristmasSubTitle", R.string.BoostingPremiumChristmasSubTitle) - ); - dialogsHintCell.setChristmasStyle(v -> { + dialogsHintCell.setText(Emoji.replaceEmoji(AndroidUtilities.replaceSingleTag( + LocaleController.getString("GiftPremiumEventAdsTitle", R.string.GiftPremiumEventAdsTitle), + Theme.key_windowBackgroundWhiteValueText, + AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD, + null + ), null, false), LocaleController.formatString("BoostingPremiumChristmasSubTitle", R.string.BoostingPremiumChristmasSubTitle)); + dialogsHintCell.setOnCloseListener(v -> { MessagesController.getInstance(currentAccount).removeSuggestion(0, "PREMIUM_CHRISTMAS"); ChangeBounds transition = new ChangeBounds(); transition.setDuration(200); @@ -5787,9 +5788,53 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ); updateAuthHintCellVisibility(false); } else { - dialogsHintCellVisible = false; - dialogsHintCell.setVisibility(View.GONE); - updateAuthHintCellVisibility(false); + if (folderId == 0 && ApplicationLoader.applicationLoaderInstance != null) { + String foundSuggestion = null; + String[] output = new String[2]; + boolean[] closeable = new boolean[1]; + for (String suggestion : MessagesController.getInstance(currentAccount).pendingSuggestions) { + if (ApplicationLoader.applicationLoaderInstance.onSuggestionFill(suggestion, output, closeable)) { + foundSuggestion = suggestion; + break; + } + } + if (foundSuggestion != null) { + final String finalSuggestion = foundSuggestion; + dialogsHintCellVisible = true; + dialogsHintCell.setVisibility(View.VISIBLE); + dialogsHintCell.setOnClickListener(v -> { + if (ApplicationLoader.applicationLoaderInstance != null) { + ApplicationLoader.applicationLoaderInstance.onSuggestionClick(finalSuggestion); + } + }); + dialogsHintCell.setText( + AndroidUtilities.replaceSingleTag( + output[0], + Theme.key_windowBackgroundWhiteValueText, + AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD, + null + ), + AndroidUtilities.replaceTags(output[1]) + ); + if (closeable[0]) { + dialogsHintCell.setOnCloseListener(v -> { + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).removeSuggestion(0, finalSuggestion); + updateDialogsHint(); + }, 250); + }); + } + updateAuthHintCellVisibility(false); + } else { + dialogsHintCellVisible = false; + dialogsHintCell.setVisibility(View.GONE); + updateAuthHintCellVisibility(false); + } + } else { + dialogsHintCellVisible = false; + dialogsHintCell.setVisibility(View.GONE); + updateAuthHintCellVisibility(false); + } } } @@ -10438,6 +10483,8 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. updateStoriesPosting(); } else if (id == NotificationCenter.unconfirmedAuthUpdate) { updateDialogsHint(); + } else if (id == NotificationCenter.premiumPromoUpdated) { + updateDialogsHint(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GradientHeaderActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GradientHeaderActivity.java new file mode 100644 index 000000000..ca3c06340 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/GradientHeaderActivity.java @@ -0,0 +1,520 @@ +package org.telegram.ui; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build; +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.content.ContextCompat; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.FillLastLinearLayoutManager; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumGradient; +import org.telegram.ui.Components.Premium.StarParticlesView; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SimpleThemeDescription; + +import java.util.ArrayList; + +public abstract class GradientHeaderActivity extends BaseFragment { + + private final PremiumGradient.PremiumGradientTools gradientTools = new PremiumGradient.PremiumGradientTools( + Theme.key_premiumGradientBackground1, + Theme.key_premiumGradientBackground2, + Theme.key_premiumGradientBackground3, + Theme.key_premiumGradientBackground4) { + @Override + protected int getThemeColorByKey(int key) { + return Theme.getDefaultColor(key); + } + }; + private final PremiumGradient.PremiumGradientTools darkGradientTools = new PremiumGradient.PremiumGradientTools( + Theme.key_premiumGradientBackground1, + Theme.key_premiumGradientBackground2, + Theme.key_premiumGradientBackground3, + Theme.key_premiumGradientBackground4) { + @Override + protected int getThemeColorByKey(int key) { + return Theme.getDefaultColor(key); + } + }; + + protected RecyclerListView listView; + + private Drawable shadowDrawable; + private StarParticlesView particlesView; + private boolean isDialogVisible; + private boolean inc; + private float progress; + private int currentYOffset; + private FrameLayout contentView; + private float totalProgress; + private final Bitmap gradientTextureBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + private final Canvas gradientCanvas = new Canvas(gradientTextureBitmap); + private float progressToFull; + public BackgroundView backgroundView; + protected FillLastLinearLayoutManager layoutManager; + private boolean isLandscapeMode; + private int statusBarHeight; + private int firstViewHeight; + private final Paint headerBgPaint = new Paint(); + + { + darkGradientTools.darkColors = true; + } + + abstract protected RecyclerView.Adapter createAdapter(); + + protected void configureHeader(CharSequence title, CharSequence subTitle, View aboveTitleView, View underSubTitleView) { + backgroundView.setData(title, subTitle, aboveTitleView, underSubTitleView); + } + + protected View getHeader(Context context) { + return new View(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (isLandscapeMode) { + firstViewHeight = statusBarHeight + actionBar.getMeasuredHeight() - AndroidUtilities.dp(16); + } else { + int h = AndroidUtilities.dp(140) + statusBarHeight; + if (backgroundView.getMeasuredHeight() + AndroidUtilities.dp(24) > h) { + h = backgroundView.getMeasuredHeight() + AndroidUtilities.dp(24); + } + firstViewHeight = h; + } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(firstViewHeight, MeasureSpec.EXACTLY)); + } + }; + } + + @Override + public boolean isSwipeBackEnabled(MotionEvent event) { + return true; + } + + @Override + public View createView(Context context) { + hasOwnBackground = true; + + Rect padding = new Rect(); + shadowDrawable = ContextCompat.getDrawable(context, R.drawable.sheet_shadow_round).mutate(); + shadowDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); + shadowDrawable.getPadding(padding); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + statusBarHeight = AndroidUtilities.isTablet() ? 0 : AndroidUtilities.statusBarHeight; + } + + contentView = new FrameLayout(context) { + + int lastSize; + boolean topInterceptedTouch; + boolean bottomInterceptedTouch; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + isLandscapeMode = MeasureSpec.getSize(widthMeasureSpec) > MeasureSpec.getSize(heightMeasureSpec); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + statusBarHeight = AndroidUtilities.isTablet() ? 0 : AndroidUtilities.statusBarHeight; + } + backgroundView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + particlesView.getLayoutParams().height = backgroundView.getMeasuredHeight(); + layoutManager.setAdditionalHeight(actionBar.getMeasuredHeight()); + layoutManager.setMinimumLastViewHeight(0); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int size = getMeasuredHeight() + getMeasuredWidth() << 16; + if (lastSize != size) { + updateBackgroundImage(); + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + float topX = backgroundView.getX() + backgroundView.aboveTitleLayout.getX(); + float topY = backgroundView.getY() + backgroundView.aboveTitleLayout.getY(); + boolean isClickableTop = backgroundView.aboveTitleLayout.isClickable(); + AndroidUtilities.rectTmp.set(topX, topY, + topX + backgroundView.aboveTitleLayout.getMeasuredWidth(), + topY + backgroundView.aboveTitleLayout.getMeasuredHeight()); + if ((AndroidUtilities.rectTmp.contains(ev.getX(), ev.getY()) || topInterceptedTouch) && !listView.scrollingByUser && isClickableTop && progressToFull < 1) { + ev.offsetLocation(-topX, -topY); + if (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) { + topInterceptedTouch = true; + } else if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + topInterceptedTouch = false; + } + backgroundView.aboveTitleLayout.dispatchTouchEvent(ev); + return true; + } + + float bottomX = backgroundView.getX() + backgroundView.belowSubTitleLayout.getX(); + float bottomY = backgroundView.getY() + backgroundView.belowSubTitleLayout.getY(); + AndroidUtilities.rectTmp.set(bottomX, bottomY, + bottomX + backgroundView.belowSubTitleLayout.getMeasuredWidth(), + bottomY + backgroundView.belowSubTitleLayout.getMeasuredHeight()); + if ((AndroidUtilities.rectTmp.contains(ev.getX(), ev.getY()) || bottomInterceptedTouch) && !listView.scrollingByUser && progressToFull < 1) { + ev.offsetLocation(-bottomX, -bottomY); + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + bottomInterceptedTouch = true; + } else if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + bottomInterceptedTouch = false; + } + backgroundView.belowSubTitleLayout.dispatchTouchEvent(ev); + if (bottomInterceptedTouch) { + return true; + } + } + return super.dispatchTouchEvent(ev); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (!isDialogVisible) { + if (inc) { + progress += 16f / 1000f; + if (progress > 3) { + inc = false; + } + } else { + progress -= 16f / 1000f; + if (progress < 1) { + inc = true; + } + } + } + View firstView = null; + if (listView.getLayoutManager() != null) { + firstView = listView.getLayoutManager().findViewByPosition(0); + } + + currentYOffset = firstView == null ? 0 : firstView.getBottom(); + int h = actionBar.getBottom() + AndroidUtilities.dp(16); + totalProgress = (1f - (currentYOffset - h) / (float) (firstViewHeight - h)); + totalProgress = Utilities.clamp(totalProgress, 1f, 0f); + + int maxTop = actionBar.getBottom() + AndroidUtilities.dp(16); + if (currentYOffset < maxTop) { + currentYOffset = maxTop; + } + + float oldProgress = progressToFull; + progressToFull = 0; + if (currentYOffset < maxTop + AndroidUtilities.dp(30)) { + progressToFull = (maxTop + AndroidUtilities.dp(30) - currentYOffset) / (float) AndroidUtilities.dp(30); + } + + if (isLandscapeMode) { + progressToFull = 1f; + totalProgress = 1f; + } + if (oldProgress != progressToFull) { + listView.invalidate(); + } + float fromTranslation = currentYOffset - (actionBar.getMeasuredHeight() + backgroundView.getMeasuredHeight() - statusBarHeight) + AndroidUtilities.dp(16); + float toTranslation = ((actionBar.getMeasuredHeight() - statusBarHeight - backgroundView.titleView.getMeasuredHeight()) / 2f) + statusBarHeight - backgroundView.getTop() - backgroundView.titleView.getTop(); + + float translationsY = Math.max(toTranslation, fromTranslation); + float iconTranslationsY = -translationsY / 4f + AndroidUtilities.dp(16); + backgroundView.setTranslationY(translationsY); + + backgroundView.aboveTitleLayout.setTranslationY(iconTranslationsY + AndroidUtilities.dp(16)); + float s = 0.6f + (1f - totalProgress) * 0.4f; + float alpha = 1f - (totalProgress > 0.5f ? (totalProgress - 0.5f) / 0.5f : 0f); + backgroundView.aboveTitleLayout.setScaleX(s); + backgroundView.aboveTitleLayout.setScaleY(s); + backgroundView.aboveTitleLayout.setAlpha(alpha); + backgroundView.belowSubTitleLayout.setAlpha(alpha); + backgroundView.subtitleView.setAlpha(alpha); + particlesView.setAlpha(1f - totalProgress); + particlesView.setTranslationY(backgroundView.getY() + backgroundView.aboveTitleLayout.getY() - AndroidUtilities.dp(30)); + float toX = AndroidUtilities.dp(72) - backgroundView.titleView.getLeft(); + float f = totalProgress > 0.3f ? (totalProgress - 0.3f) / 0.7f : 0f; + backgroundView.titleView.setTranslationX(toX * (1f - CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(1 - f))); + + if (!isDialogVisible) { + invalidate(); + } + + gradientTools.gradientMatrix(0, 0, getMeasuredWidth(), getMeasuredHeight(), -getMeasuredWidth() * 0.1f * progress, 0); + canvas.drawRect(0, 0, getMeasuredWidth(), currentYOffset + AndroidUtilities.dp(20), gradientTools.paint); + + int titleColor = ColorUtils.blendARGB(getThemedColor(Theme.key_dialogTextBlack), getThemedColor(Theme.key_premiumGradientBackgroundOverlay), alpha); + actionBar.getBackButton().setColorFilter(titleColor); + backgroundView.titleView.setTextColor(titleColor); + headerBgPaint.setAlpha((int) (255 * (1f - alpha))); + setLightStatusBar(Theme.blendOver(Theme.getColor(Theme.key_premiumGradientBackground4, resourceProvider), headerBgPaint.getColor())); + canvas.drawRect(0, 0, getMeasuredWidth(), currentYOffset + AndroidUtilities.dp(20), headerBgPaint); + super.dispatchDraw(canvas); + parentLayout.drawHeaderShadow(canvas, alpha <= 0.01f ? 255 : 0, actionBar.getMeasuredHeight()); + } + + private Boolean lightStatusBar; + private void setLightStatusBar(int color) { + boolean colorLight = AndroidUtilities.computePerceivedBrightness(color) >= .721f; + if (lightStatusBar == null || lightStatusBar != colorLight) { + AndroidUtilities.setLightStatusBar(fragmentView, lightStatusBar = colorLight); + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == listView) { + canvas.save(); + canvas.clipRect(0, actionBar.getBottom(), getMeasuredWidth(), getMeasuredHeight()); + super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return true; + } + return super.drawChild(canvas, child, drawingTime); + } + }; + contentView.setFitsSystemWindows(true); + listView = new RecyclerListView(context) { + @Override + public void onDraw(Canvas canvas) { + shadowDrawable.setBounds((int) (-padding.left - AndroidUtilities.dp(16) * progressToFull), currentYOffset - padding.top - AndroidUtilities.dp(16), (int) (getMeasuredWidth() + padding.right + AndroidUtilities.dp(16) * progressToFull), getMeasuredHeight()); + shadowDrawable.draw(canvas); + super.onDraw(canvas); + } + }; + listView.setLayoutManager(layoutManager = new FillLastLinearLayoutManager(context, AndroidUtilities.dp(68) + statusBarHeight - AndroidUtilities.dp(16), listView)); + layoutManager.setFixedLastItemHeight(); + + listView.setAdapter(createAdapter()); + listView.addOnScrollListener(new RecyclerView.OnScrollListener() { + + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + int maxTop = actionBar.getBottom() + AndroidUtilities.dp(16); + if (totalProgress > 0.5f) { + listView.smoothScrollBy(0, currentYOffset - maxTop); + } else { + View firstView = null; + if (listView.getLayoutManager() != null) { + firstView = listView.getLayoutManager().findViewByPosition(0); + } + if (firstView != null && firstView.getTop() < 0) { + listView.smoothScrollBy(0, firstView.getTop()); + } + } + } + } + + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + contentView.invalidate(); + } + }); + + backgroundView = new BackgroundView(context) { + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return true; + } + }; + particlesView = new StarParticlesView(context) { + @Override + protected void configure() { + drawable = new Drawable(50) { + @Override + protected int getPathColor() { + return ColorUtils.setAlphaComponent(Theme.getDefaultColor(colorKey), 200); + } + }; + drawable.type = 100; + drawable.roundEffect = false; + drawable.useRotate = false; + drawable.useBlur = true; + drawable.checkBounds = true; + drawable.isCircle = false; + drawable.size1 = 4; + drawable.k1 = drawable.k2 = drawable.k3 = 0.98f; + drawable.init(); + } + + @Override + protected int getStarsRectWidth() { + return getMeasuredWidth(); + } + }; + + contentView.addView(particlesView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + contentView.addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + contentView.addView(listView); + + fragmentView = contentView; + actionBar.setBackground(null); + actionBar.setCastShadows(false); + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + actionBar.setForceSkipTouches(true); + updateColors(); + return fragmentView; + } + + public Paint setDarkGradientLocation(float x, float y) { + darkGradientTools.gradientMatrix(0, 0, contentView.getMeasuredWidth(), contentView.getMeasuredHeight(), -x - (contentView.getMeasuredWidth() * 0.1f * progress), -y); + return darkGradientTools.paint; + } + + @Override + public boolean isActionBarCrossfadeEnabled() { + return false; + } + + private void updateBackgroundImage() { + if (contentView.getMeasuredWidth() == 0 || contentView.getMeasuredHeight() == 0 || backgroundView == null) { + return; + } + gradientTools.gradientMatrix(0, 0, contentView.getMeasuredWidth(), contentView.getMeasuredHeight(), 0, 0); + gradientCanvas.save(); + gradientCanvas.scale(100f / contentView.getMeasuredWidth(), 100f / contentView.getMeasuredHeight()); + gradientCanvas.drawRect(0, 0, contentView.getMeasuredWidth(), contentView.getMeasuredHeight(), gradientTools.paint); + gradientCanvas.restore(); + } + + @Override + public Dialog showDialog(Dialog dialog) { + Dialog d = super.showDialog(dialog); + updateDialogVisibility(d != null); + return d; + } + + @Override + protected void onDialogDismiss(Dialog dialog) { + super.onDialogDismiss(dialog); + updateDialogVisibility(false); + } + + protected void updateDialogVisibility(boolean isVisible) { + if (isVisible != isDialogVisible) { + isDialogVisible = isVisible; + particlesView.setPaused(isVisible); + contentView.invalidate(); + } + } + + private void updateColors() { + if (backgroundView == null || actionBar == null) { + return; + } + headerBgPaint.setColor(getThemedColor(Theme.key_dialogBackground)); + actionBar.setItemsColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay), false); + actionBar.setItemsBackgroundColor(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay), 60), false); + particlesView.drawable.updateColors(); + if (backgroundView != null) { + backgroundView.titleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); + backgroundView.subtitleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); + } + updateBackgroundImage(); + } + + @Override + public ArrayList getThemeDescriptions() { + return SimpleThemeDescription.createThemeDescriptions(this::updateColors, + Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4, + Theme.key_premiumGradientBackground1, Theme.key_premiumGradientBackground2, Theme.key_premiumGradientBackground3, Theme.key_premiumGradientBackground4, + Theme.key_premiumGradientBackgroundOverlay, Theme.key_premiumStartGradient1, Theme.key_premiumStartGradient2, Theme.key_premiumStartSmallStarsColor, Theme.key_premiumStartSmallStarsColor2 + ); + } + + @Override + public boolean isLightStatusBar() { + return false; + } + + @Override + public void onResume() { + super.onResume(); + particlesView.setPaused(false); + } + + @Override + public void onPause() { + super.onPause(); + if (particlesView != null) { + particlesView.setPaused(true); + } + } + + protected static class BackgroundView extends LinearLayout { + + private final TextView titleView; + private final TextView subtitleView; + private final FrameLayout aboveTitleLayout; + private final FrameLayout belowSubTitleLayout; + + public BackgroundView(Context context) { + super(context); + setOrientation(VERTICAL); + aboveTitleLayout = new FrameLayout(context); + addView(aboveTitleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); + aboveTitleLayout.setClipChildren(false); + setClipChildren(false); + + titleView = new TextView(context); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 22); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleView.setGravity(Gravity.CENTER_HORIZONTAL); + addView(titleView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.CENTER_HORIZONTAL, 16, 20, 16, 0)); + + subtitleView = new TextView(context); + subtitleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + subtitleView.setLineSpacing(AndroidUtilities.dp(2), 1f); + subtitleView.setGravity(Gravity.CENTER_HORIZONTAL); + addView(subtitleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 24, 7, 24, 0)); + + belowSubTitleLayout = new FrameLayout(context); + addView(belowSubTitleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); + belowSubTitleLayout.setClipChildren(false); + } + + public void setData(CharSequence title, CharSequence subTitle, View aboveTitleView, View underSubTitleView) { + titleView.setText(title); + subtitleView.setText(subTitle); + if (aboveTitleView != null) { + aboveTitleLayout.removeAllViews(); + aboveTitleLayout.addView(aboveTitleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); + } + if (underSubTitleView != null) { + belowSubTitleLayout.removeAllViews(); + belowSubTitleLayout.addView(underSubTitleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); + } + requestLayout(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupColorActivity.java new file mode 100644 index 000000000..d3b39e6a8 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupColorActivity.java @@ -0,0 +1,316 @@ +package org.telegram.ui; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChannelBoostsController; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +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.Cells.ThemePreviewMessagesCell; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.Components.RecyclerListView; + +public class GroupColorActivity extends ChannelColorActivity { + + private ChannelColorActivity.ProfilePreview profilePreview; + private float profilePreviewPercent; + private boolean isLoading; + + public GroupColorActivity(long dialogId) { + super(dialogId); + isGroup = true; + } + + @Override + protected int getProfileIconLevelMin() { + return getMessagesController().groupProfileBgIconLevelMin; + } + + @Override + protected int getCustomWallpaperLevelMin() { + return getMessagesController().groupCustomWallpaperLevelMin; + } + + @Override + protected int getWallpaperLevelMin() { + return getMessagesController().groupWallpaperLevelMin; + } + + @Override + protected int getEmojiStatusLevelMin() { + return getMessagesController().groupEmojiStatusLevelMin; + } + + @Override + protected int getEmojiStickersLevelMin() { + return getMessagesController().groupEmojiStickersLevelMin; + } + + @Override + protected void updateRows() { + rowsCount = 0; + profilePreviewRow = rowsCount++; + profileColorGridRow = rowsCount++; + profileEmojiRow = rowsCount++; + if (selectedProfileEmoji != 0 || selectedProfileColor >= 0) { + boolean wasButton = removeProfileColorRow >= 0; + removeProfileColorRow = rowsCount++; + if (!wasButton && adapter != null) { + adapter.notifyItemInserted(removeProfileColorRow); + adapter.notifyItemChanged(profileEmojiRow); + listView.scrollToPosition(0); + } + } else { + int wasIndex = removeProfileColorRow; + removeProfileColorRow = -1; + if (wasIndex >= 0 && adapter != null) { + adapter.notifyItemRemoved(wasIndex); + adapter.notifyItemChanged(profileEmojiRow); + } + } + profileHintRow = rowsCount++; + packEmojiRow = rowsCount++; + packEmojiHintRow = rowsCount++; + statusEmojiRow = rowsCount++; + statusHintRow = rowsCount++; + messagesPreviewRow = rowsCount++; + wallpaperThemesRow = rowsCount++; + wallpaperRow = rowsCount++; + wallpaperHintRow = rowsCount++; + } + + @Override + public void updateButton(boolean animated) { + super.updateButton(animated); + if (profilePreview != null) { + profilePreview.textInfo1.setText(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingGroupBoostCount", boostsStatus != null ? boostsStatus.boosts : 0))); + } + } + + @Override + protected int getEmojiPackStrRes() { + return R.string.GroupEmojiPack; + } + + @Override + protected int getEmojiPackInfoStrRes() { + return R.string.GroupEmojiPackInfo; + } + + @Override + protected int getProfileInfoStrRes() { + return R.string.GroupProfileInfo; + } + + @Override + protected int getEmojiStatusStrRes() { + return R.string.GroupEmojiStatus; + } + + @Override + protected int getEmojiStatusInfoStrRes() { + return R.string.GroupEmojiStatusInfo; + } + + @Override + protected int getWallpaperStrRes() { + return R.string.GroupWallpaper; + } + + @Override + protected int getWallpaper2InfoStrRes() { + return R.string.GroupWallpaper2Info; + } + + @Override + protected int getMessagePreviewType() { + return ThemePreviewMessagesCell.TYPE_GROUP_PEER_COLOR; + } + + @Override + public View createView(Context context) { + View view = super.createView(context); + updateColors(); + + actionBar.setAddToContainer(false); + actionBar.setTitle(""); + ((ViewGroup) view).addView(actionBar); + + view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + view.getViewTreeObserver().removeOnGlobalLayoutListener(this); + initProfilePreview(); + profilePreview.infoLayout.setOnClickListener(v -> openBoostDialog()); + } + }); + return view; + } + + @Override + protected boolean needBoostInfoSection() { + return true; + } + + private void initProfilePreview() { + if (profilePreview == null) { + profilePreview = (ChannelColorActivity.ProfilePreview) findChildAt(profilePreviewRow); + } + } + + @Override + protected void createListView() { + listView = new RecyclerListView(getContext(), resourceProvider) { + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (profilePreview != null && profilePreviewPercent >= 1f) { + canvas.save(); + canvas.translate(0, -(profilePreview.getMeasuredHeight() - actionBar.getMeasuredHeight())); + profilePreview.draw(canvas); + canvas.restore(); + } + } + }; + + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + initProfilePreview(); + int profileHeight = profilePreview.getMeasuredHeight(); + int actionBarHeight = actionBar.getMeasuredHeight(); + int max = profileHeight - actionBarHeight; + float y = profilePreview.getTop() * -1; + profilePreviewPercent = Math.max(Math.min(1f, y / max), 0f); + float profileAlphaPercent = Math.min(profilePreviewPercent * 2f, 1f); + float titleAlphaPercent = Math.min(Math.max(profilePreviewPercent - 0.45f, 0f) * 2f, 1f); + profilePreview.profileView.setAlpha(AndroidUtilities.lerp(1f, 0f, profileAlphaPercent)); + profilePreview.infoLayout.setAlpha(AndroidUtilities.lerp(1f, 0f, profileAlphaPercent)); + profilePreview.title.setAlpha(AndroidUtilities.lerp(0f, 1f, titleAlphaPercent)); + if (profilePreviewPercent >= 1f) { + profilePreview.setTranslationY(y - max); + } else { + profilePreview.setTranslationY(0); + } + } + + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + if (profilePreviewPercent >= 0.5f && profilePreviewPercent < 1f) { + int maxTop = actionBar.getBottom(); + RecyclerView.LayoutManager layoutManager = listView.getLayoutManager(); + if (layoutManager != null) { + View view = layoutManager.findViewByPosition(0); + if (view != null) { + listView.smoothScrollBy(0, view.getBottom() - maxTop); + } + } + } else if (profilePreviewPercent < 0.5f) { + View firstView = null; + if (listView.getLayoutManager() != null) { + firstView = listView.getLayoutManager().findViewByPosition(0); + } + if (firstView != null && firstView.getTop() < 0) { + listView.smoothScrollBy(0, firstView.getTop()); + } + } + } + } + }); + } + + private void openBoostDialog() { + if (boostsStatus == null || isLoading) { + return; + } + isLoading = true; + ChannelBoostsController boostsController = MessagesController.getInstance(currentAccount).getBoostsController(); + boostsController.userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { + if (canApplyBoost == null || getContext() == null) { + isLoading = false; + return; + } + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), LimitReachedBottomSheet.TYPE_BOOSTS_FOR_USERS, currentAccount, resourceProvider) { + @Override + public void onOpenAnimationEnd() { + isLoading = false; + } + + @Override + public void dismiss() { + super.dismiss(); + isLoading = false; + } + }; + limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + limitReachedBottomSheet.show(); + }); + } + + @Override + public void updateColors() { + super.updateColors(); + actionBar.setBackgroundColor(Color.TRANSPARENT); + Drawable shadowDrawable = Theme.getThemedDrawableByKey(getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow); + Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundWhite, resourceProvider)); + CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); + combinedDrawable.setFullsize(true); + buttonContainer.setBackground(combinedDrawable); + if (profilePreview != null) { + profilePreview.backgroundView.setColor(currentAccount, selectedProfileColor, false); + profilePreview.profileView.setColor(selectedProfileColor, false); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (profilePreview != null) { + profilePreview.setTitleSize(); + } + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + super.didReceivedNotification(id, account, args); + if (id == NotificationCenter.chatInfoDidLoad) { + TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; + if (chatFull.id == -dialogId) { + updateProfilePreview(true); + } + } + } + + @Override + public boolean onFragmentCreate() { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatInfoDidLoad); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatInfoDidLoad); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java index 09788178e..7b8f02324 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java @@ -10,13 +10,23 @@ package org.telegram.ui; import android.annotation.SuppressLint; import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.text.Editable; +import android.text.InputType; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.TypedValue; +import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; @@ -33,6 +43,7 @@ import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; 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; @@ -45,6 +56,9 @@ import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.StickerSetCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.EditTextCaption; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; @@ -82,19 +96,31 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC private int stickersStartRow; private int stickersEndRow; private int rowCount; + private int addEmojiPackTitleRow; + private int addEmojiPackRow; + private int currentEmojiPackRow; + private int addEmojiPackHintRow; private ActionBarMenuItem searchItem; private boolean searching; + private boolean isEmoji; + private AddEmojiCell addEmojiCell; public GroupStickersActivity(long id) { super(); chatId = id; } + public GroupStickersActivity(long id, boolean isEmoji) { + super(); + chatId = id; + this.isEmoji = isEmoji; + } + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); - MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_IMAGE); + MediaDataController.getInstance(currentAccount).checkStickers(getStickerSetType()); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.stickersDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatInfoDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.groupStickersDidLoad); @@ -118,7 +144,7 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); - actionBar.setTitle(LocaleController.getString("GroupStickers", R.string.GroupStickers)); + actionBar.setTitle(LocaleController.getString(isEmoji ? R.string.GroupEmojiPack : R.string.GroupStickers)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -169,6 +195,7 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC listView = new RecyclerListView(context); DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator(); + defaultItemAnimator.setDurations(200); defaultItemAnimator.setSupportsChangeAnimations(true); listView.setItemAnimator(defaultItemAnimator); layoutManager = new LinearLayoutManager(context); @@ -200,16 +227,20 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC } if (searching) { if (position > searchAdapter.searchEntries.size()) { - onStickerSetClicked(view, searchAdapter.localSearchEntries.get(position - searchAdapter.searchEntries.size() - 1), false); + onStickerSetClicked(((StickerSetCell) view).isChecked(), searchAdapter.localSearchEntries.get(position - searchAdapter.searchEntries.size() - 1), false); } else if (position != searchAdapter.searchEntries.size()) { - onStickerSetClicked(view, searchAdapter.searchEntries.get(position), true); + onStickerSetClicked(((StickerSetCell) view).isChecked(), searchAdapter.searchEntries.get(position), true); } return; } if (position >= stickersStartRow && position < stickersEndRow) { - TLRPC.TL_messages_stickerSet stickerSet = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_IMAGE).get(position - stickersStartRow); - onStickerSetClicked(view, stickerSet, false); + TLRPC.TL_messages_stickerSet stickerSet = MediaDataController.getInstance(currentAccount).getStickerSets(getStickerSetType()).get(position - stickersStartRow); + onStickerSetClicked(((StickerSetCell) view).isChecked(), stickerSet, false); + } + + if (position == currentEmojiPackRow) { + onStickerSetClicked(true, selectedStickerSet, false); } }); listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -224,7 +255,7 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC return fragmentView; } - private void onStickerSetClicked(View view, TLRPC.TL_messages_stickerSet stickerSet, boolean remote) { + private void onStickerSetClicked(boolean isSelected, TLRPC.TL_messages_stickerSet stickerSet, boolean remote) { TLRPC.InputStickerSet inputStickerSet = null; if (remote) { TLRPC.TL_inputStickerSetShortName inputStickerSetShortName = new TLRPC.TL_inputStickerSetShortName(); @@ -232,7 +263,6 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC inputStickerSet = inputStickerSetShortName; } StickersAlert stickersAlert = new StickersAlert(getParentActivity(), GroupStickersActivity.this, inputStickerSet, !remote ? stickerSet : null, null); - boolean isSelected = ((StickerSetCell) view).isChecked(); stickersAlert.setCustomButtonDelegate(new StickersAlert.StickersAlertCustomButtonDelegate() { @Override public int getCustomButtonTextColorKey() { @@ -251,6 +281,9 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC @Override public String getCustomButtonText() { + if (isEmoji) { + return LocaleController.getString(isSelected ? R.string.RemoveGroupEmojiPackSet : R.string.SetAsGroupEmojiPackSet); + } return LocaleController.getString(isSelected ? R.string.RemoveGroupStickerSet : R.string.SetAsGroupStickerSet); } @@ -270,7 +303,11 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC selectedStickerSet = stickerSet; removeStickerSet = false; } + if (isEmoji) { + AndroidUtilities.runOnUIThread(() -> BulletinFactory.of(GroupStickersActivity.this).createSimpleBulletin(R.raw.done, LocaleController.getString(R.string.GroupsEmojiPackUpdated)).show(), 350); + } updateSelectedStickerSetIndex(); + updateCurrentPackVisibility(selectedStickerSet, true); if (prevIndex != -1) { boolean found = false; @@ -305,7 +342,7 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC } } - if (top != Integer.MAX_VALUE) { + if (top != Integer.MAX_VALUE && !isEmoji) { layoutManager.scrollToPositionWithOffset(row + 1, top); } if (searching) { @@ -315,70 +352,116 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC return true; } }); + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); stickersAlert.show(); } @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.stickersDidLoad) { - if ((Integer) args[0] == MediaDataController.TYPE_IMAGE) { + int type = (Integer) args[0]; + if (type == getStickerSetType()) { updateRows(); } } else if (id == NotificationCenter.chatInfoDidLoad) { TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; if (chatFull.id == chatId) { - if (info == null && chatFull.stickerset != null) { - selectedStickerSet = MediaDataController.getInstance(currentAccount).getGroupStickerSetById(chatFull.stickerset); + if (info == null && getStickerSet(chatFull) != null) { + selectedStickerSet = MediaDataController.getInstance(currentAccount).getGroupStickerSetById(getStickerSet(chatFull)); } info = chatFull; updateRows(); } } else if (id == NotificationCenter.groupStickersDidLoad) { long setId = (Long) args[0]; - if (info != null && info.stickerset != null && info.stickerset.id == setId) { + if (getStickerSet(info) != null && getStickerSet(info).id == setId) { updateRows(); } } } + private TLRPC.StickerSet getStickerSet(TLRPC.ChatFull info) { + if (info == null) { + return null; + } + if (isEmoji) { + return info.emojiset; + } else { + return info.stickerset; + } + } + public void setInfo(TLRPC.ChatFull chatFull) { info = chatFull; - if (info != null && info.stickerset != null) { - selectedStickerSet = MediaDataController.getInstance(currentAccount).getGroupStickerSetById(info.stickerset); + if (getStickerSet(info) != null) { + selectedStickerSet = MediaDataController.getInstance(currentAccount).getGroupStickerSetById(getStickerSet(info)); + } + } + + private void setStickerSet(TLRPC.StickerSet set) { + if (isEmoji) { + info.emojiset = set; + } else { + info.stickerset = set; } } private void saveStickerSet() { - if (info == null || info.stickerset != null && selectedStickerSet != null && selectedStickerSet.set.id == info.stickerset.id || info.stickerset == null && selectedStickerSet == null) { + if (info == null || getStickerSet(info) != null && selectedStickerSet != null && selectedStickerSet.set.id == getStickerSet(info).id || getStickerSet(info) == null && selectedStickerSet == null) { return; } - TLRPC.TL_channels_setStickers req = new TLRPC.TL_channels_setStickers(); - req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); - if (removeStickerSet) { - req.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + TLObject reqObject; + if (isEmoji) { + TLRPC.TL_channels_setEmojiStickers req = new TLRPC.TL_channels_setEmojiStickers(); + req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); + if (removeStickerSet) { + req.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + } else { + req.stickerset = new TLRPC.TL_inputStickerSetID(); + req.stickerset.id = selectedStickerSet.set.id; + req.stickerset.access_hash = selectedStickerSet.set.access_hash; + } + reqObject = req; } else { - MessagesController.getEmojiSettings(currentAccount).edit().remove("group_hide_stickers_" + info.id).apply(); - req.stickerset = new TLRPC.TL_inputStickerSetID(); - req.stickerset.id = selectedStickerSet.set.id; - req.stickerset.access_hash = selectedStickerSet.set.access_hash; + TLRPC.TL_channels_setStickers req = new TLRPC.TL_channels_setStickers(); + req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); + if (removeStickerSet) { + req.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + } else { + MessagesController.getEmojiSettings(currentAccount).edit().remove("group_hide_stickers_" + info.id).apply(); + req.stickerset = new TLRPC.TL_inputStickerSetID(); + req.stickerset.id = selectedStickerSet.set.id; + req.stickerset.access_hash = selectedStickerSet.set.access_hash; + } + reqObject = req; } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + ConnectionsManager.getInstance(currentAccount).sendRequest(reqObject, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error == null) { if (selectedStickerSet == null) { - info.stickerset = null; + setStickerSet(null); } else { - info.stickerset = selectedStickerSet.set; + setStickerSet(selectedStickerSet.set); MediaDataController.getInstance(currentAccount).putGroupStickerSet(selectedStickerSet); } updateSelectedStickerSetIndex(); - if (info.stickerset == null) { - info.flags |= 256; + if (isEmoji) { + if (info.emojiset != null) { + info.flags2 |= 1024; + } else { + info.flags2 = info.flags2 & ~1024; + } } else { - info.flags = info.flags &~ 256; + if (info.stickerset == null) { + info.flags |= 256; + } else { + info.flags = info.flags & ~256; + } } + MessagesStorage.getInstance(currentAccount).updateChatInfo(info, false); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, true, false); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.groupPackUpdated, info.id, isEmoji); finishFragment(); } else { if (getParentActivity() != null) { @@ -388,8 +471,12 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC })); } + private int getStickerSetType() { + return isEmoji ? MediaDataController.TYPE_EMOJIPACKS : MediaDataController.TYPE_IMAGE; + } + private void updateSelectedStickerSetIndex() { - ArrayList stickerSets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_IMAGE); + ArrayList stickerSets = MediaDataController.getInstance(currentAccount).getStickerSets(getStickerSetType()); selectedStickerSetIndex = -1; long selectedSet; @@ -398,8 +485,8 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC selectedSet = 0; } else if (selectedStickerSet != null) { selectedSet = selectedStickerSet.set.id; - } else if (info != null && info.stickerset != null) { - selectedSet = info.stickerset.id; + } else if (getStickerSet(info) != null) { + selectedSet = getStickerSet(info).id; } else { selectedSet = 0; } @@ -415,10 +502,28 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC } } - @SuppressLint("NotifyDataSetChanged") private void updateRows() { + updateRows(true); + } + + @SuppressLint("NotifyDataSetChanged") + private void updateRows(boolean notify) { + addEmojiPackTitleRow = -1; + addEmojiPackRow = -1; + currentEmojiPackRow = -1; + addEmojiPackHintRow = -1; rowCount = 0; - ArrayList stickerSets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_IMAGE); + + if (isEmoji) { + addEmojiPackTitleRow = rowCount++; + addEmojiPackRow = rowCount++; + if (selectedStickerSet != null) { + currentEmojiPackRow = rowCount++; + } + addEmojiPackHintRow = rowCount++; + } + + ArrayList stickerSets = MediaDataController.getInstance(currentAccount).getStickerSets(getStickerSetType()); if (!stickerSets.isEmpty()) { headerRow = rowCount++; stickersStartRow = rowCount; @@ -432,14 +537,14 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC infoRow = rowCount++; updateSelectedStickerSetIndex(); - if (listAdapter != null) { + if (notify && listAdapter != null) { listAdapter.notifyDataSetChanged(); } } private class SearchAdapter extends RecyclerListView.SelectionAdapter { private final static int TYPE_STICKER_SET = 0, - TYPE_MY_STICKERS_HEADER = 1; + TYPE_MY_STICKERS_HEADER = 1; private Context mContext; private List searchEntries = new ArrayList<>(); @@ -465,8 +570,19 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC return -1; } + private void changeBackgroundColor(String query) { + if (isEmoji) { + if (!TextUtils.isEmpty(query)) { + listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + } else { + listView.setBackground(null); + } + } + } + @SuppressLint("NotifyDataSetChanged") private void onSearchStickers(String query) { + changeBackgroundColor(query); if (reqId != 0) { getConnectionsManager().cancelRequest(reqId, true); reqId = 0; @@ -497,13 +613,23 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC } else { emptyView.showProgress(true, true); } - AndroidUtilities.runOnUIThread(lastCallback = ()-> { + AndroidUtilities.runOnUIThread(lastCallback = () -> { lastQuery = query; - - TLRPC.TL_messages_searchStickerSets searchStickerSets = new TLRPC.TL_messages_searchStickerSets(); - searchStickerSets.q = query; - reqId = getConnectionsManager().sendRequest(searchStickerSets, (response, error) -> { - if (!Objects.equals(lastQuery, searchStickerSets.q)) { + TLObject req; + final String q; + if (isEmoji) { + TLRPC.TL_messages_searchEmojiStickerSets searchEmojiStickerSets = new TLRPC.TL_messages_searchEmojiStickerSets(); + searchEmojiStickerSets.q = query; + q = searchEmojiStickerSets.q; + req = searchEmojiStickerSets; + } else { + TLRPC.TL_messages_searchStickerSets searchStickerSets = new TLRPC.TL_messages_searchStickerSets(); + searchStickerSets.q = query; + q = searchStickerSets.q; + req = searchStickerSets; + } + reqId = getConnectionsManager().sendRequest(req, (response, error) -> { + if (!Objects.equals(lastQuery, q)) { return; } @@ -514,16 +640,18 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC TLRPC.TL_messages_stickerSet set = new TLRPC.TL_messages_stickerSet(); set.set = stickerSetCovered.set; set.documents = stickerSetCovered.covers; - newSearchEntries.add(set); + if (!isEmoji || set.set.emojis) { + newSearchEntries.add(set); + } } String lowQuery = query.toLowerCase(Locale.ROOT).trim(); List newLocalEntries = new ArrayList<>(); - for (TLRPC.TL_messages_stickerSet localSet : MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_IMAGE)) { + for (TLRPC.TL_messages_stickerSet localSet : MediaDataController.getInstance(currentAccount).getStickerSets(getStickerSetType())) { if (localSet.set.short_name.toLowerCase(Locale.ROOT).contains(lowQuery) || localSet.set.title.toLowerCase(Locale.ROOT).contains(lowQuery)) { newLocalEntries.add(localSet); } } - AndroidUtilities.runOnUIThread(()->{ + AndroidUtilities.runOnUIThread(() -> { searchEntries = newSearchEntries; localSearchEntries = newLocalEntries; notifyDataSetChanged(); @@ -549,8 +677,11 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC default: case TYPE_MY_STICKERS_HEADER: view = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteGrayText4, 21, 0, 0, false, getResourceProvider()); - view.setBackground(Theme.getThemedDrawableByKey(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); - ((HeaderCell) view).setText(LocaleController.getString(R.string.ChooseStickerMyStickerSets)); + Drawable drawable = Theme.getThemedDrawableByKey(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow); + CombinedDrawable combinedDrawable = new CombinedDrawable(new ColorDrawable(getThemedColor(Theme.key_windowBackgroundGray)), drawable); + combinedDrawable.setFullsize(true); + view.setBackground(combinedDrawable); + ((HeaderCell) view).setText(LocaleController.getString(isEmoji ? R.string.ChooseStickerMyEmojiPacks : R.string.ChooseStickerMyStickerSets)); break; } view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); @@ -571,8 +702,8 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC long id; if (selectedStickerSet != null) { id = selectedStickerSet.set.id; - } else if (info != null && info.stickerset != null) { - id = info.stickerset.id; + } else if (getStickerSet(info) != null) { + id = getStickerSet(info).id; } else { id = 0; } @@ -602,9 +733,10 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC private class ListAdapter extends RecyclerListView.SelectionAdapter { private final static int TYPE_STICKER_SET = 0, TYPE_INFO = 1, - TYPE_CHOOSE_HEADER = 4; + TYPE_CHOOSE_HEADER = 4, + TYPE_ENTER_LINK = 5; - private Context mContext; + private final Context mContext; public ListAdapter(Context context) { mContext = context; @@ -618,26 +750,38 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { + case TYPE_ENTER_LINK: { + AddEmojiCell cell = (AddEmojiCell) holder.itemView; + cell.bind(currentEmojiPackRow > 0, selectedStickerSet); + break; + } case TYPE_STICKER_SET: { - ArrayList arrayList = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_IMAGE); - int row = position - stickersStartRow; StickerSetCell cell = (StickerSetCell) holder.itemView; - TLRPC.TL_messages_stickerSet set = arrayList.get(row); - cell.setStickersSet(arrayList.get(row), row != arrayList.size() - 1); - long id; - if (selectedStickerSet != null) { - id = selectedStickerSet.set.id; - } else if (info != null && info.stickerset != null) { - id = info.stickerset.id; + if (position == currentEmojiPackRow) { + cell.setChecked(false, false); + cell.setStickersSet(selectedStickerSet, false); + cell.setDeleteAction(v -> selectSetAfterSearch(null)); } else { - id = 0; + ArrayList arrayList = MediaDataController.getInstance(currentAccount).getStickerSets(getStickerSetType()); + int row = position - stickersStartRow; + TLRPC.TL_messages_stickerSet set = arrayList.get(row); + cell.setStickersSet(arrayList.get(row), row != arrayList.size() - 1); + cell.setDeleteAction(null); + long id; + if (selectedStickerSet != null) { + id = selectedStickerSet.set.id; + } else if (getStickerSet(info) != null) { + id = getStickerSet(info).id; + } else { + id = 0; + } + cell.setChecked(set.set.id == id, false); } - cell.setChecked(set.set.id == id, false); break; } case TYPE_INFO: { if (position == infoRow) { - String text = LocaleController.getString("ChooseStickerSetMy", R.string.ChooseStickerSetMy); + String text = LocaleController.getString(isEmoji ? R.string.ChooseEmojiPackMy : R.string.ChooseStickerSetMy); String botName = "@stickers"; int index = text.indexOf(botName); if (index != -1) { @@ -658,11 +802,17 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC } else { ((TextInfoPrivacyCell) holder.itemView).setText(text); } + } else if (position == addEmojiPackHintRow) { + ((TextInfoPrivacyCell) holder.itemView).setText(LocaleController.getString(R.string.AddGroupEmojiPackHint)); } break; } case TYPE_CHOOSE_HEADER: { - ((HeaderCell) holder.itemView).setText(LocaleController.getString(R.string.ChooseStickerSetHeader)); + if (position == addEmojiPackTitleRow) { + ((HeaderCell) holder.itemView).setText(LocaleController.getString(R.string.AddEmojiPackHeader)); + } else { + ((HeaderCell) holder.itemView).setText(LocaleController.getString(isEmoji ? R.string.ChooseEmojiPackHeader : R.string.ChooseStickerSetHeader)); + } break; } } @@ -679,6 +829,10 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; switch (viewType) { + case TYPE_ENTER_LINK: + addEmojiCell = new AddEmojiCell(mContext); + view = addEmojiCell; + break; case TYPE_STICKER_SET: view = new StickerSetCell(mContext, 3); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -699,17 +853,210 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC @Override public int getItemViewType(int i) { - if (i >= stickersStartRow && i < stickersEndRow) { + if ((i >= stickersStartRow && i < stickersEndRow) || i == currentEmojiPackRow) { return TYPE_STICKER_SET; - } else if (i == headerRow) { + } else if (i == headerRow || i == addEmojiPackTitleRow) { return TYPE_CHOOSE_HEADER; - } else if (i == infoRow) { + } else if (i == infoRow || i == addEmojiPackHintRow) { return TYPE_INFO; + } else if (i == addEmojiPackRow) { + return TYPE_ENTER_LINK; } return TYPE_STICKER_SET; } } + private void updateCurrentPackVisibility(TLRPC.TL_messages_stickerSet set, boolean notifyTextChanges) { + if (!isEmoji) { + return; + } + if (set != null) { + boolean inserted = currentEmojiPackRow == -1; + selectedStickerSet = set; + updateRows(false); + if (inserted) { + listAdapter.notifyItemInserted(currentEmojiPackRow); + } else { + listAdapter.notifyItemChanged(currentEmojiPackRow); + } + if (notifyTextChanges) { + listAdapter.notifyItemChanged(addEmojiPackRow); + } + addEmojiCell.setNeedDivider(true); + } else { + boolean removed = currentEmojiPackRow > 0; + selectedStickerSet = null; + if (removed) { + listAdapter.notifyItemRemoved(currentEmojiPackRow); + if (notifyTextChanges) { + listAdapter.notifyItemChanged(addEmojiPackRow); + } + } + updateRows(false); + addEmojiCell.setNeedDivider(false); + } + } + + private void selectSetAfterSearch(TLRPC.TL_messages_stickerSet set) { + int prevIndex = selectedStickerSetIndex; + if (set == null) { + if (selectedStickerSet != null) { + BulletinFactory.of(GroupStickersActivity.this).createSimpleBulletin(R.raw.done, LocaleController.getString(R.string.GroupsEmojiPackUpdated)).show(); + } + selectedStickerSet = null; + removeStickerSet = true; + } else { + selectedStickerSet = set; + removeStickerSet = false; + BulletinFactory.of(GroupStickersActivity.this).createSimpleBulletin(R.raw.done, LocaleController.getString(R.string.GroupsEmojiPackUpdated)).show(); + } + updateSelectedStickerSetIndex(); + updateCurrentPackVisibility(selectedStickerSet, false); + + if (prevIndex != -1) { + boolean found = false; + if (!searching) { + for (int i = 0; i < listView.getChildCount(); i++) { + View ch = listView.getChildAt(i); + if (listView.getChildViewHolder(ch).getAdapterPosition() == stickersStartRow + prevIndex) { + ((StickerSetCell) ch).setChecked(false, true); + found = true; + break; + } + } + } + if (!found) { + listAdapter.notifyItemChanged(stickersStartRow + prevIndex); + } + } + if (selectedStickerSetIndex != -1) { + boolean found = false; + if (!searching) { + for (int i = 0; i < listView.getChildCount(); i++) { + View ch = listView.getChildAt(i); + if (listView.getChildViewHolder(ch).getAdapterPosition() == stickersStartRow + selectedStickerSetIndex) { + ((StickerSetCell) ch).setChecked(true, true); + found = true; + break; + } + } + } + if (!found) { + listAdapter.notifyItemChanged(stickersStartRow + selectedStickerSetIndex); + } + } + } + + private class AddEmojiCell extends LinearLayout { + + private final EditTextCaption editText; + private boolean needDivider; + private int reqId; + private Runnable lastCallback; + private String lastQuery; + private final TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + String query = s.toString().trim(); + if (reqId != 0) { + getConnectionsManager().cancelRequest(reqId, true); + reqId = 0; + } + if (lastCallback != null) { + AndroidUtilities.cancelRunOnUIThread(lastCallback); + } + lastQuery = null; + + if (query.isEmpty()) { + selectSetAfterSearch(null); + return; + } + + AndroidUtilities.runOnUIThread(lastCallback = () -> { + lastQuery = query; + final String q = query; + TLRPC.TL_messages_getStickerSet req = new TLRPC.TL_messages_getStickerSet(); + req.stickerset = new TLRPC.TL_inputStickerSetShortName(); + ((TLRPC.TL_inputStickerSetShortName) req.stickerset).short_name = q; + reqId = getConnectionsManager().sendRequest(req, (response, error) -> { + if (!Objects.equals(lastQuery, q)) { + return; + } + AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + selectSetAfterSearch((TLRPC.TL_messages_stickerSet) response); + } else { + selectSetAfterSearch(null); + } + }); + }, ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); + }, 300); + } + }; + + public AddEmojiCell(Context context) { + super(context); + TextView textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + textView.setText("t.me/addemoji/"); + editText = new EditTextCaption(context, null); + editText.setLines(1); + editText.setSingleLine(true); + editText.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + editText.setTextColor(Theme.getColor(Theme.key_chat_messagePanelText)); + editText.setLinkTextColor(Theme.getColor(Theme.key_chat_messageLinkOut)); + editText.setHighlightColor(Theme.getColor(Theme.key_chat_inTextSelectionHighlight)); + editText.setHintColor(Theme.getColor(Theme.key_chat_messagePanelHint)); + editText.setHintTextColor(Theme.getColor(Theme.key_chat_messagePanelHint)); + editText.setCursorColor(Theme.getColor(Theme.key_chat_messagePanelCursor)); + editText.setHandlesColor(Theme.getColor(Theme.key_chat_TextSelectionCursor)); + editText.setBackground(null); + editText.setHint(LocaleController.getString(R.string.AddEmojiPackLinkHint)); + addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 20, 0, 0, 0)); + addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, -4, 0, 0, 0)); + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + setPadding(0, AndroidUtilities.dp(5), 0, AndroidUtilities.dp(5)); + setWillNotDraw(false); + } + + public void setNeedDivider(boolean needDivider) { + this.needDivider = needDivider; + invalidate(); + } + + public void bind(boolean needDivider, TLRPC.TL_messages_stickerSet selectedStickerSe) { + this.needDivider = needDivider; + editText.removeTextChangedListener(textWatcher); + if (selectedStickerSe == null) { + editText.setText(""); + } else { + String link = selectedStickerSe.set.short_name; + editText.setText(link); + editText.setSelection(link.length()); + } + editText.addTextChangedListener(textWatcher); + } + + @Override + protected void onDraw(Canvas canvas) { + if (needDivider) { + canvas.drawLine(AndroidUtilities.dp(20), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, Theme.dividerPaint); + } + } + } + @Override public ArrayList getThemeDescriptions() { ArrayList themeDescriptions = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 739c51209..b1979e33b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -135,6 +135,7 @@ import org.telegram.ui.ActionBar.DrawerLayoutContainer; import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.DrawerLayoutAdapter; +import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Cells.DrawerActionCell; import org.telegram.ui.Cells.DrawerAddCell; import org.telegram.ui.Cells.DrawerProfileCell; @@ -503,6 +504,10 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati layoutParams.height = LayoutHelper.MATCH_PARENT; sideMenuContainer.setLayoutParams(layoutParams); sideMenu.setOnItemClickListener((view, position, x, y) -> { + if (drawerLayoutAdapter.click(view, position)) { + drawerLayoutContainer.closeDrawer(false); + return; + } if (position == 0) { DrawerProfileCell profileCell = (DrawerProfileCell) view; if (profileCell.isInAvatar(x, y)) { @@ -1418,6 +1423,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati private void checkCurrentAccount() { if (currentAccount != UserConfig.selectedAccount) { + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.openBoostForUsersDialog); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.appDidLogout); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.mainUserInfoChanged); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.attachMenuBotsDidLoad); @@ -1439,6 +1445,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesEnabledUpdate); } currentAccount = UserConfig.selectedAccount; + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.openBoostForUsersDialog); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.appDidLogout); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.mainUserInfoChanged); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.attachMenuBotsDidLoad); @@ -3915,7 +3922,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (isBoost) { TLRPC.Chat chat = MessagesController.getInstance(intentAccount).getChat(-peerId); - if (ChatObject.isChannelAndNotMegaGroup(chat)) { + if (ChatObject.isBoostSupported(chat)) { processBoostDialog(peerId, dismissLoading, progress); return; } @@ -4762,7 +4769,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati args.putInt("message_id", messageId); } TLRPC.Chat chatLocal = MessagesController.getInstance(currentAccount).getChat(channelId); - if (chatLocal != null && ChatObject.isChannelAndNotMegaGroup(chatLocal) && isBoost) { + if (chatLocal != null && ChatObject.isBoostSupported(chatLocal) && isBoost) { processBoostDialog(-channelId, dismissLoading, progress); } else if (chatLocal != null && chatLocal.forum) { openForumFromLink(-channelId, messageId, () -> { @@ -4794,7 +4801,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati notFound = false; MessagesController.getInstance(currentAccount).putChats(res.chats, false); TLRPC.Chat chat = res.chats.get(0); - if (chat != null && isBoost && ChatObject.isChannelAndNotMegaGroup(chat)) { + if (chat != null && isBoost && ChatObject.isBoostSupported(chat)) { processBoostDialog(-channelId, null, progress); } else if (chat != null && chat.forum) { if (threadId != null) { @@ -4933,8 +4940,11 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } - private void processBoostDialog(Long peerId, Runnable dismissLoading, Browser.Progress progress) { + processBoostDialog(peerId, dismissLoading, progress, null); + } + + private void processBoostDialog(Long peerId, Runnable dismissLoading, Browser.Progress progress, ChatMessageCell chatMessageCell) { ChannelBoostsController boostsController = MessagesController.getInstance(currentAccount).getBoostsController(); if (progress != null) { progress.init(); @@ -4944,7 +4954,9 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (progress != null) { progress.end(); } - dismissLoading.run(); + if (dismissLoading != null) { + dismissLoading.run(); + } return; } boostsController.userCanBoostChannel(peerId, boostsStatus, canApplyBoost -> { @@ -4965,9 +4977,14 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati boolean isCurrentChat = false; if (lastFragment instanceof ChatActivity) { isCurrentChat = ((ChatActivity) lastFragment).getDialogId() == peerId; + } else if (lastFragment instanceof DialogsActivity) { + DialogsActivity dialogsActivity = ((DialogsActivity) lastFragment); + isCurrentChat = dialogsActivity.rightSlidingDialogContainer != null && dialogsActivity.rightSlidingDialogContainer.getCurrentFragmetDialogId() == peerId; } limitReachedBottomSheet.setBoostsStats(boostsStatus, isCurrentChat); limitReachedBottomSheet.setDialogId(peerId); + limitReachedBottomSheet.setChatMessageCell(chatMessageCell); + lastFragment.showDialog(limitReachedBottomSheet); try { if (dismissLoading != null) { @@ -5799,6 +5816,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (!checkPermissionsResult(requestCode, permissions, grantResults)) return; + if (ApplicationLoader.applicationLoaderInstance != null && ApplicationLoader.applicationLoaderInstance.checkRequestPermissionResult(requestCode, permissions, grantResults)) return; if (actionBarLayout.getFragmentStack().size() != 0) { BaseFragment fragment = actionBarLayout.getFragmentStack().get(actionBarLayout.getFragmentStack().size() - 1); @@ -6135,6 +6153,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati public void didReceivedNotification(int id, final int account, Object... args) { if (id == NotificationCenter.appDidLogout) { switchToAvailableAccountOrLogout(); + } else if (id == NotificationCenter.openBoostForUsersDialog) { + long dialogId = (long) args[0]; + ChatMessageCell chatMessageCell = null; + if (args.length > 1) { + chatMessageCell = (ChatMessageCell) args[1]; + } + processBoostDialog(dialogId, null, null, chatMessageCell); } else if (id == NotificationCenter.closeOtherAppActivities) { if (args[0] != this) { onFinish(); @@ -7459,7 +7484,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati getActionBarLayout().presentFragment(params.setNoAnimation(forceWithoutAnimation).setCheckPresentFromDelegate(false)); } return result; - } else if (!tabletFullSize && layout != rightActionBarLayout) { + } else if (!tabletFullSize && layout != rightActionBarLayout && rightActionBarLayout != null) { if (rightActionBarLayout.getView() != null) { rightActionBarLayout.getView().setVisibility(View.VISIBLE); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java index bdbb25a60..da59edd3d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java @@ -27,11 +27,8 @@ import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.os.Build; -import android.os.Bundle; -import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.text.TextUtils; import android.text.style.ReplacementSpan; import android.util.SparseIntArray; import android.util.TypedValue; @@ -50,15 +47,10 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.google.common.io.CharSource; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; -import org.telegram.messenger.ChatThemeController; -import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; @@ -92,13 +84,11 @@ import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.Easings; import org.telegram.ui.Components.FilledTabsView; import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SimpleThemeDescription; -import org.telegram.ui.Components.SpannableStringLight; import org.telegram.ui.Components.Text; import org.telegram.ui.Components.ViewPagerFixed; import org.telegram.ui.Stories.StoriesUtilities; @@ -1345,7 +1335,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente public static class ChangeNameColorCell extends View { private final int currentAccount; - private final boolean isChannel; + private final boolean isChannelOrGroup; + private final boolean isGroup; private final Theme.ResourcesProvider resourcesProvider; private final Drawable drawable; @@ -1362,16 +1353,18 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente public ChangeNameColorCell(int currentAccount, long dialogId, Context context, Theme.ResourcesProvider resourcesProvider) { super(context); + MessagesController mc = MessagesController.getInstance(currentAccount); + TLRPC.Chat chat = mc.getChat(-dialogId); this.currentAccount = currentAccount; - this.isChannel = dialogId < 0; + this.isChannelOrGroup = dialogId < 0; + this.isGroup = isChannelOrGroup && !ChatObject.isChannelAndNotMegaGroup(chat); this.resourcesProvider = resourcesProvider; - drawable = context.getResources().getDrawable(R.drawable.msg_palette).mutate(); + drawable = context.getResources().getDrawable(R.drawable.menu_edit_appearance).mutate(); drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider), PorterDuff.Mode.SRC_IN)); - CharSequence button = LocaleController.getString(isChannel ? R.string.ChangeChannelNameColor2 : R.string.ChangeUserNameColor); - if (isChannel && MessagesController.getInstance(currentAccount).getMainSettings().getInt("boostingappearance", 0) < 3) { - MessagesController mc = MessagesController.getInstance(currentAccount); + CharSequence button = LocaleController.getString(isChannelOrGroup ? (isGroup ? R.string.ChangeGroupAppearance : R.string.ChangeChannelNameColor2) : R.string.ChangeUserNameColor); + if (isChannelOrGroup && !isGroup && MessagesController.getInstance(currentAccount).getMainSettings().getInt("boostingappearance", 0) < 3) { int minlvl = Integer.MAX_VALUE, maxlvl = 0; if (mc.peerColors != null) { minlvl = Math.min(minlvl, mc.peerColors.maxLevel()); @@ -1395,13 +1388,12 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente maxlvl = Math.max(maxlvl, mc.channelWallpaperLevelMin); minlvl = Math.min(minlvl, mc.channelCustomWallpaperLevelMin); maxlvl = Math.max(maxlvl, mc.channelCustomWallpaperLevelMin); - TLRPC.Chat chat = mc.getChat(-dialogId); int currentLevel = chat == null ? 0 : chat.level; if (currentLevel < maxlvl) { lock = new LevelLock(context, true, Math.max(currentLevel, minlvl), resourcesProvider); } } - if (isChannel && lock == null) { + if (isChannelOrGroup && lock == null) { button = TextCell.applyNewSpan(button); } buttonText = new Text(button, 16); @@ -1409,8 +1401,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } public void updateColors() { - drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(isChannel ? Theme.key_windowBackgroundWhiteGrayIcon : Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider), PorterDuff.Mode.SRC_IN)); - buttonText.setColor(Theme.getColor(isChannel ? Theme.key_windowBackgroundWhiteBlackText : Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider)); + drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(isChannelOrGroup ? Theme.key_windowBackgroundWhiteGrayIcon : Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider), PorterDuff.Mode.SRC_IN)); + buttonText.setColor(Theme.getColor(isChannelOrGroup ? Theme.key_windowBackgroundWhiteBlackText : Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider)); if (userText != null && userTextBackgroundPaint != null && userTextColorKey != -1) { final int color = Theme.getColor(userTextColorKey, resourcesProvider); @@ -1511,7 +1503,12 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente lock.draw(canvas); } - if (color1Drawable != null && color2Drawable != null) { + if (isGroup && color2Drawable != null) { + int x = LocaleController.isRTL ? dp(24 + 16 + 18) : getMeasuredWidth() - dp(24); + color2Drawable.setBounds(x - dp(11), (getMeasuredHeight() - dp(11)) / 2, x, (getMeasuredHeight() + dp(11)) / 2); + color2Drawable.stroke(dpf2(3), Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + color2Drawable.draw(canvas); + } else if (color1Drawable != null && color2Drawable != null) { int x = LocaleController.isRTL ? dp(24 + 16 + 18) : getMeasuredWidth() - dp(24); color2Drawable.setBounds(x - dp(11), (getMeasuredHeight() - dp(11)) / 2, x, (getMeasuredHeight() + dp(11)) / 2); @@ -1523,7 +1520,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente color1Drawable.stroke(dpf2(3), Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); color1Drawable.draw(canvas); - } else if (userText != null) { + } else if (userText != null && !isGroup) { final int maxWidth = (int) (getMeasuredWidth() - dp(64 + 7 + 15 + 9 + 9 + 12) - Math.min(buttonText.getWidth() + (lock == null ? 0 : lock.getIntrinsicWidth() + dp(6 + 6)), getMeasuredWidth() - dp(64 + 100))); final int w = (int) Math.min(userText.getWidth(), maxWidth); @@ -2112,9 +2109,9 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente private final long dialogId; private final boolean isChannel; - private final ImageReceiver imageReceiver = new ImageReceiver(this); - private final AvatarDrawable avatarDrawable = new AvatarDrawable(); - private final SimpleTextView titleView, subtitleView; + protected final ImageReceiver imageReceiver = new ImageReceiver(this); + protected final AvatarDrawable avatarDrawable = new AvatarDrawable(); + protected final SimpleTextView titleView, subtitleView; private final AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable statusEmoji; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java index 3e4dfd7f4..628c678d0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -1293,12 +1293,17 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification paint.setColor(Theme.getColor(Theme.key_dialogBackground)); } + private Path path = new Path(); @Override public void draw(Canvas c) { + path.rewind(); AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); - c.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(12), AndroidUtilities.dp(12), paint); - + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(12), AndroidUtilities.dp(12), Path.Direction.CW); + c.drawPath(path, paint); + c.save(); + c.clipPath(path); super.draw(c); + c.restore(); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 5f757deab..700980aa8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -66,7 +66,6 @@ import android.text.TextPaint; import android.text.TextUtils; import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; -import android.text.style.ReplacementSpan; import android.util.Property; import android.util.SparseIntArray; import android.util.TypedValue; @@ -212,6 +211,7 @@ import org.telegram.ui.Components.IdenticonDrawable; import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.InstantCameraView; import org.telegram.ui.Components.ItemOptions; +import org.telegram.ui.Components.JoinGroupAlert; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.MediaActivity; @@ -1792,7 +1792,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. getNotificationCenter().addObserver(this, NotificationCenter.chatOnlineCountDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.groupCallUpdated); getNotificationCenter().addObserver(this, NotificationCenter.channelRightsUpdated); - + getNotificationCenter().addObserver(this, NotificationCenter.chatWasBoostedByUser); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.uploadStoryEnd); sortedUsers = new ArrayList<>(); updateOnlineCount(true); if (chatInfo == null) { @@ -1908,6 +1909,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.reloadInterface); getMessagesController().cancelLoadFullUser(userId); } else if (chatId != 0) { + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.uploadStoryEnd); + getNotificationCenter().removeObserver(this, NotificationCenter.chatWasBoostedByUser); getNotificationCenter().removeObserver(this, NotificationCenter.chatInfoDidLoad); getNotificationCenter().removeObserver(this, NotificationCenter.chatOnlineCountDidLoad); getNotificationCenter().removeObserver(this, NotificationCenter.groupCallUpdated); @@ -2316,14 +2319,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. openAddMember(); } else if (id == statistics) { TLRPC.Chat chat = getMessagesController().getChat(chatId); - Bundle args = new Bundle(); - args.putLong("chat_id", chatId); - args.putBoolean("is_megagroup", chat.megagroup); - if (!chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - } - StatisticActivity fragment = new StatisticActivity(args); - presentFragment(fragment); + presentFragment(StatisticActivity.create(chat, false)); } else if (id == view_discussion) { openDiscussion(); } else if (id == gift_premium) { @@ -3552,7 +3548,27 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. presentFragment(fragment); } } else if (position == joinRow) { - getMessagesController().addUserToChat(currentChat.id, getUserConfig().getCurrentUser(), 0, null, ProfileActivity.this, null); + getMessagesController().addUserToChat(currentChat.id, getUserConfig().getCurrentUser(), 0, null, ProfileActivity.this, true, () -> { + updateRowsIds(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + }, err -> { + if (err != null && "INVITE_REQUEST_SENT".equals(err.text)) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + preferences.edit().putLong("dialog_join_requested_time_" + dialogId, System.currentTimeMillis()).commit(); + JoinGroupAlert.showBulletin(context, ProfileActivity.this, ChatObject.isChannel(currentChat) && !currentChat.megagroup); + updateRowsIds(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + if (lastFragment instanceof ChatActivity) { + ((ChatActivity) lastFragment).showBottomOverlayProgress(false, true); + } + return false; + } + return true; + }); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.closeSearchByActiveAction); } else if (position == subscribersRow) { Bundle args = new Bundle(); @@ -3683,7 +3699,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. BuildVars.DEBUG_VERSION ? (SharedConfig.useSurfaceInStories ? "back to TextureView in stories" : "use SurfaceView in stories") : null, BuildVars.DEBUG_PRIVATE_VERSION ? (SharedConfig.photoViewerBlur ? "do not blur in photoviewer" : "blur in photoviewer") : null, !SharedConfig.payByInvoice ? "Enable Invoice Payment" : "Disable Invoice Payment", - BuildVars.DEBUG_PRIVATE_VERSION ? "Update Attach Bots" : null + BuildVars.DEBUG_PRIVATE_VERSION ? "Update Attach Bots" : null, + null // Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? (!SharedConfig.useCamera2 ? "Use Camera 2 API" : "Use old Camera 1 API") : null }; builder.setItems(items, (dialog, which) -> { @@ -3717,7 +3734,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").remove("askNotificationsAfter").remove("askNotificationsDuration").remove("viewoncehint").remove("taptostorysoundhint").remove("nothanos").remove("voiceoncehint").remove("savedhint").remove("savedsearchhint").remove("savedsearchtaghint").apply(); + 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").remove("viewoncehint").remove("taptostorysoundhint").remove("nothanos").remove("voiceoncehint").remove("savedhint").remove("savedsearchhint").remove("savedsearchtaghint").remove("groupEmojiPackHintShown").remove("newppsms").apply(); MessagesController.getEmojiSettings(currentAccount).edit().remove("featured_hidden").remove("emoji_featured_hidden").commit(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; @@ -3926,6 +3943,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. SharedConfig.togglePaymentByInvoice(); } else if (which == 26) { getMediaDataController().loadAttachMenuBots(false, true); + } else if (which == 27) { + SharedConfig.toggleUseCamera2(); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -4698,6 +4717,20 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private final AccelerateDecelerateInterpolator floatingInterpolator = new AccelerateDecelerateInterpolator(); + private void checkCanSendStoryForPosting() { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chatId); + if (!ChatObject.isBoostSupported(chat)) { + return; + } + StoriesController storiesController = getMessagesController().getStoriesController(); + waitCanSendStoryRequest = true; + storiesController.canSendStoryFor(getDialogId(), canSend -> { + waitCanSendStoryRequest = false; + showBoostsAlert = !canSend; + hideFloatingButton(false); + }, false, resourcesProvider); + } + private void createFloatingActionButton(Context context) { if (!getMessagesController().storiesEnabled()) { return; @@ -4705,19 +4738,15 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (getDialogId() > 0L) { return; } - if (!ChatObject.isChannelAndNotMegaGroup(-getDialogId(), currentAccount)) { + TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); + if (!ChatObject.isBoostSupported(currentChat)) { return; } StoriesController storiesController = getMessagesController().getStoriesController(); if (!storiesController.canPostStories(getDialogId())) { return; } else { - waitCanSendStoryRequest = true; - storiesController.canSendStoryFor(getDialogId(), canSend -> { - waitCanSendStoryRequest = false; - showBoostsAlert = !canSend; - hideFloatingButton(false); - }, false, resourcesProvider); + checkCanSendStoryForPosting(); } long dialogId = getDialogId(); floatingButtonContainer = new FrameLayout(context); @@ -4735,23 +4764,16 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (boostsStatus == null) { return; } - BaseFragment lastFragment = LaunchActivity.getLastFragment(); - LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(lastFragment, lastFragment.getContext(), LimitReachedBottomSheet.TYPE_BOOSTS_FOR_POSTING, currentAccount, resourcesProvider); - limitReachedBottomSheet.setBoostsStats(boostsStatus, false); - limitReachedBottomSheet.setDialogId(dialogId); - limitReachedBottomSheet.showStatisticButtonInLink(() -> { - TLRPC.Chat chat = getMessagesController().getChat(chatId); - Bundle args = new Bundle(); - args.putLong("chat_id", chatId); - args.putBoolean("is_megagroup", chat.megagroup); - args.putBoolean("start_from_boosts", true); - if (chatInfo == null || !chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - }; - StatisticActivity fragment = new StatisticActivity(args); - presentFragment(fragment); + messagesController.getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { + if (canApplyBoost == null) { + return; + } + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + LimitReachedBottomSheet.openBoostsForPostingStories(lastFragment, dialogId, canApplyBoost, boostsStatus, () -> { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + presentFragment(StatisticActivity.create(chat)); + }); }); - limitReachedBottomSheet.show(); }); return; } @@ -6795,7 +6817,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @SuppressWarnings("unchecked") @Override public void didReceivedNotification(int id, int account, final Object... args) { - if (id == NotificationCenter.updateInterfaces) { + if (id == NotificationCenter.uploadStoryEnd || id == NotificationCenter.chatWasBoostedByUser) { + checkCanSendStoryForPosting(); + } else if (id == NotificationCenter.updateInterfaces) { int mask = (Integer) args[0]; boolean infoChanged = (mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0 || (mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0; if (userId != 0) { @@ -8095,8 +8119,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } if (lastSectionRow == -1 && currentChat.left && !currentChat.kicked) { - joinRow = rowCount++; - lastSectionRow = rowCount++; + long requestedTime = MessagesController.getNotificationsSettings(currentAccount).getLong("dialog_join_requested_time_" + dialogId, -1); + if (!(requestedTime > 0 && System.currentTimeMillis() - requestedTime < 1000 * 60 * 2)) { + joinRow = rowCount++; + lastSectionRow = rowCount++; + } } } else if (chatInfo != null) { if (!isTopic && chatInfo.participants != null && chatInfo.participants.participants != null && !(chatInfo.participants instanceof TLRPC.TL_chatParticipantsForbidden)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java index 3f31757d8..0cd503aa9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java @@ -100,6 +100,22 @@ import java.util.Locale; public class StatisticActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + public static BaseFragment create(TLRPC.Chat chat) { + return create(chat, true); + } + + public static BaseFragment create(TLRPC.Chat chat, boolean startFromBoosts) { + Bundle args = new Bundle(); + args.putLong("chat_id", chat.id); + args.putBoolean("is_megagroup", chat.megagroup); + args.putBoolean("start_from_boosts", startFromBoosts); + TLRPC.ChatFull chatInfo = MessagesController.getInstance(UserConfig.selectedAccount).getChatFull(chat.id); + if (chatInfo == null || !chatInfo.can_view_stats) { + return new BoostsActivity(-chat.id); + } + return new StatisticActivity(args); + } + private TLRPC.ChatFull chat; private final long chatId; @@ -528,7 +544,8 @@ public class StatisticActivity extends BaseFragment implements NotificationCente @Override public View createView(Context context) { sharedUi = new BaseChartView.SharedUiComponents(); - boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chatId, currentAccount); + TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); + boolean isBoostSupported = ChatObject.isBoostSupported(currentChat); BottomPagerTabs storiesTabsView = new BottomPagerTabs(context, getResourceProvider()) { @Override public Tab[] createTabs() { @@ -567,10 +584,10 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } }); FrameLayout statisticLayout = new FrameLayout(context); - if (isChannel) { + if (isBoostSupported) { boostLayout = new ChannelBoostLayout(StatisticActivity.this, -chatId, getResourceProvider()); } - boolean showTabs = isChannel && !onlyBoostsStat; + boolean showTabs = isBoostSupported && !onlyBoostsStat; if (showTabs && startFromBoosts) { viewPagerFixed.setPosition(1); } @@ -580,7 +597,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente if (onlyBoostsStat) { return 1; } - if (isChannel) { + if (isBoostSupported) { return 2; } return 1; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ChannelBoostUtilities.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ChannelBoostUtilities.java index 8db44201d..d7faccd4e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ChannelBoostUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ChannelBoostUtilities.java @@ -11,9 +11,9 @@ public class ChannelBoostUtilities { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); String username = ChatObject.getPublicUsername(chat); if (!TextUtils.isEmpty(username)) { - return "https://t.me/" + ChatObject.getPublicUsername(chat) + "?boost"; + return "https://t.me/boost/" + ChatObject.getPublicUsername(chat); } else { - return "https://t.me/c/" + -dialogId + "?boost"; + return "https://t.me/boost/?c=" + -dialogId; } } } 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 3f5a680b2..1d8ac37e6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java @@ -12,7 +12,6 @@ import android.content.ClipData; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -36,7 +35,6 @@ import android.text.TextUtils; import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.URLSpan; -import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -60,12 +58,14 @@ import androidx.core.graphics.ColorUtils; import androidx.core.math.MathUtils; import androidx.recyclerview.widget.ChatListItemAnimator; +import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChannelBoostsController; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; @@ -125,7 +125,6 @@ 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.ChatGreetingsView; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -136,7 +135,6 @@ import org.telegram.ui.Components.EmojiPacksAlert; import org.telegram.ui.Components.HintView; import org.telegram.ui.Components.InstantCameraView; import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.LoadingDrawable; import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.MentionsContainerView; @@ -267,6 +265,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private long dialogId; boolean isSelf; boolean isChannel; + boolean isGroup; boolean isPremiumBlocked; private float alpha = 1f; @@ -2208,7 +2207,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica premiumBlockedText1 = new TextView(getContext()); premiumBlockedText1.setTextColor(0xFF858585); premiumBlockedText1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - premiumBlockedText1.setText(LocaleController.getString(R.string.StoryRepliesLocked)); + premiumBlockedText1.setText(LocaleController.getString(isGroup ? R.string.StoryGroupRepliesLocked : R.string.StoryRepliesLocked)); premiumBlockedText2 = new TextView(getContext()); premiumBlockedText2.setTextColor(0xFFFFFFFF); @@ -2228,14 +2227,99 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private void updatePremiumBlockedText() { if (premiumBlockedText1 != null) { - premiumBlockedText1.setText(LocaleController.getString(R.string.StoryRepliesLocked)); + premiumBlockedText1.setText(LocaleController.getString(isGroup ? R.string.StoryGroupRepliesLocked : R.string.StoryRepliesLocked)); } if (premiumBlockedText2 != null) { premiumBlockedText2.setText(LocaleController.getString(R.string.StoryRepliesLockedButton)); } } + private Activity findActivity() { + Activity _activity; + if (storyViewer != null && storyViewer.parentActivity != null) { + _activity = storyViewer.parentActivity; + } else { + _activity = AndroidUtilities.findActivity(getContext()); + } + if (_activity == null) { + return LaunchActivity.instance; + } + return _activity; + } + + private BaseFragment fragmentForLimit() { + return new BaseFragment() { + @Override + public boolean isLightStatusBar() { + return false; + } + + @Override + public Activity getParentActivity() { + return findActivity(); + } + + @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) { + if (PeerStoriesView.this.storyViewer != null) { + PeerStoriesView.this.storyViewer.presentFragment(fragment); + } + return true; + } + + @Override + public Dialog showDialog(Dialog dialog) { + if (PeerStoriesView.this.storyViewer != null) { + PeerStoriesView.this.storyViewer.showDialog(dialog); + } else if (dialog != null) { + dialog.show(); + } + return dialog; + } + }; + } + + private TL_stories.TL_premium_boostsStatus boostsStatus; + private ChannelBoostsController.CanApplyBoost canApplyBoost; + private void showPremiumBlockedToast() { + if (isGroup) { + if (boostsStatus != null && canApplyBoost != null) { + LimitReachedBottomSheet.openBoostsForRemoveRestrictions(fragmentForLimit(), boostsStatus, canApplyBoost, dialogId, true); + return; + } + if (storyViewer != null) { + storyViewer.setOverlayVisible(true); + } + MessagesController.getInstance(currentAccount).getBoostsController().getBoostsStats(dialogId, boostsStatus -> { + if (boostsStatus == null) { + if (storyViewer != null) { + storyViewer.setOverlayVisible(false); + } + return; + } + this.boostsStatus = boostsStatus; + MessagesController.getInstance(currentAccount).getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { + this.canApplyBoost = canApplyBoost; + LimitReachedBottomSheet.openBoostsForRemoveRestrictions(fragmentForLimit(), boostsStatus, canApplyBoost, dialogId, true); + if (storyViewer != null) { + storyViewer.setOverlayVisible(false); + } + }); + }); + return; + } AndroidUtilities.shakeViewSpring(chatActivityEnterView, shiftDp = -shiftDp); BotWebViewVibrationEffect.APP_ERROR.vibrate(); String username = ""; @@ -2412,8 +2496,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } @Override - protected void updateRecordInterface(int recordState) { - super.updateRecordInterface(recordState); + protected void updateRecordInterface(int recordState, boolean animated) { + super.updateRecordInterface(recordState, animated); checkRecording(); } @@ -2558,12 +2642,23 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica @Override public void needShowMediaBanHint() { + if (isGroup) { + showPremiumBlockedToast(); + return; + } if (mediaBanTooltip == null) { mediaBanTooltip = new HintView(getContext(), 9, resourcesProvider); mediaBanTooltip.setVisibility(View.GONE); addView(mediaBanTooltip, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 10, 0, 10, 0)); } - mediaBanTooltip.setText(AndroidUtilities.replaceTags(LocaleController.formatString(chatActivityEnterView.isInVideoMode() ? R.string.VideoMessagesRestrictedByPrivacy : R.string.VoiceMessagesRestrictedByPrivacy, MessagesController.getInstance(currentAccount).getUser(dialogId).first_name))); + String title; + if (dialogId >= 0) { + title = UserObject.getFirstName(MessagesController.getInstance(currentAccount).getUser(dialogId)); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + title = chat != null ? chat.title : ""; + } + mediaBanTooltip.setText(AndroidUtilities.replaceTags(LocaleController.formatString(chatActivityEnterView.isInVideoMode() ? R.string.VideoMessagesRestrictedByPrivacy : R.string.VoiceMessagesRestrictedByPrivacy, title))); mediaBanTooltip.showForView(chatActivityEnterView.getAudioVideoButtonContainer(), true); } @@ -2735,23 +2830,15 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica chatActivityEnterView.closeKeyboard(); } chatAttachAlert.setMaxSelectedPhotos(-1, true); + chatAttachAlert.setDialogId(dialogId); chatAttachAlert.init(); chatAttachAlert.getCommentTextView().setText(chatActivityEnterView.getFieldText()); - chatAttachAlert.setDialogId(dialogId); delegate.showDialog(chatAttachAlert); } private void createChatAttachView() { if (chatAttachAlert == null) { chatAttachAlert = new ChatAttachAlert(getContext(), null, false, false, true, resourcesProvider) { - @Override - public void dismissInternal() { -// if (chatAttachAlert != null && chatAttachAlert.isShowing()) { -// AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); -// } - super.dismissInternal(); - } - @Override public void onDismissAnimationStart() { if (chatAttachAlert != null) { @@ -2760,12 +2847,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (chatActivityEnterView != null && chatActivityEnterView.getEditField() != null) { chatActivityEnterView.getEditField().requestFocus(); } -// if (chatAttachAlert != null && chatAttachAlert.isShowing()) { -// AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); -// } -// onEditTextDialogClose(false, false); } - }; chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { @@ -3132,6 +3214,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica forceUpdateOffsets = true; userCanSeeViews = false; isChannel = false; + isGroup = false; if (dialogId >= 0) { isSelf = dialogId == UserConfig.getInstance(currentAccount).getClientUserId(); TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); @@ -3163,12 +3246,16 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } else { isSelf = false; isChannel = true; - isPremiumBlocked = false; if (storiesController.canEditStories(dialogId) || BuildVars.DEBUG_PRIVATE_VERSION) { userCanSeeViews = true; } TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + isGroup = !ChatObject.isChannelAndNotMegaGroup(chat); + if (isGroup && MessagesController.getInstance(currentAccount).getChatFull(-dialogId) == null) { + MessagesStorage.getInstance(currentAccount).loadChatInfo(-dialogId, true, new CountDownLatch(1), false, false); + } + isPremiumBlocked = isGroup && !ChatObject.canSendPlain(chat); avatarDrawable.setInfo(currentAccount, chat); headerView.backupImageView.getImageReceiver().setForUserOrChat(chat, avatarDrawable); headerView.titleView.setText(chat.title); @@ -3194,10 +3281,19 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } currentImageTime = 0; switchEventSent = false; + boostsStatus = null; + canApplyBoost = null; if (isChannel) { createSelfPeerView(); + if (chatActivityEnterView == null && isGroup) { + createEnterView(); + } if (chatActivityEnterView != null) { - chatActivityEnterView.setVisibility(View.GONE); + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + chatActivityEnterView.setVisibility(isGroup && (ChatObject.canSendPlain(chat) || ChatObject.isPossibleRemoveChatRestrictionsByBoosts(chat)) ? View.VISIBLE : View.GONE); + chatActivityEnterView.getEditField().setText(storyViewer.getDraft(dialogId, currentStory.storyItem)); + chatActivityEnterView.setDialogId(dialogId, currentAccount); + chatActivityEnterView.updateRecordButton(chat, null); } if (reactionsCounter == null) { reactionsCounter = new AnimatedTextView.AnimatedTextDrawable(); @@ -3295,6 +3391,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica storyContainer.invalidate(); invalidate(); } + checkStealthMode(false); } private void createUnsupportedContainer() { @@ -3625,6 +3722,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica preloadReactionHolders.get(i).onAttachedToWindow(true); } // sharedResources.muteDrawable.addView(muteIconView); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatInfoDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storyQualityUpdate); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesListUpdated); @@ -3658,6 +3756,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica preloadReactionHolders.get(i).onAttachedToWindow(false); } //sharedResources.muteDrawable.removeView(muteIconView); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatInfoDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storyQualityUpdate); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesListUpdated); @@ -3709,46 +3808,21 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (storyLimit == null || delegate == null) { return; } - final Activity activity = storyViewer != null && storyViewer.parentActivity != null ? storyViewer.parentActivity : AndroidUtilities.findActivity(getContext()); - if (activity == null) { - 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) { - if (storyViewer != null) { - storyViewer.presentFragment(fragment); - } - return true; - } - }, activity, storyLimit.getLimitReachedType(), currentAccount, null); + final LimitReachedBottomSheet sheet = new LimitReachedBottomSheet(fragmentForLimit(), findActivity(), storyLimit.getLimitReachedType(), currentAccount, null); delegate.showDialog(sheet); } else if (id == NotificationCenter.userIsPremiumBlockedUpadted) { boolean wasPremiumBlocked = isPremiumBlocked; isPremiumBlocked = dialogId >= 0 && !UserConfig.getInstance(currentAccount).isPremium() && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(dialogId); if (isPremiumBlocked != wasPremiumBlocked) { updatePosition(); + checkStealthMode(true); + } + } else if (id == NotificationCenter.chatInfoDidLoad) { + if (args[0] instanceof TLRPC.ChatFull) { + TLRPC.ChatFull chatInfo = (TLRPC.ChatFull) args[0]; + if (dialogId == -chatInfo.id) { + updatePosition(); + } } } } @@ -3782,7 +3856,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } else { stealthModeIsActive = false; chatActivityEnterView.setEnabled(true); - chatActivityEnterView.setOverrideHint(LocaleController.getString("ReplyPrivately", R.string.ReplyPrivately), animated); + chatActivityEnterView.setOverrideHint(LocaleController.getString(isGroup ? R.string.ReplyToGroupStory : R.string.ReplyPrivately), animated); } } @@ -4053,6 +4127,42 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica dotDividerSpan.setSize(5); dot.setSpan(dotDividerSpan, 0, dot.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(" ").append(dot).append(" ").append(LocaleController.formatShortDate(currentStory.storyItem.date)); + headerView.setSubtitle(ssb, false); + } else if (isGroup && currentStory.storyItem != null && currentStory.storyItem.from_id != null) { + SpannableStringBuilder ssb = new SpannableStringBuilder(); + AvatarSpan avatar = new AvatarSpan(headerView.subtitleView[0], currentAccount, 15); + SpannableString avatarStr = new SpannableString("a"); + avatarStr.setSpan(avatar, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(avatarStr).append(" "); + final long peerId = DialogObject.getPeerDialogId(currentStory.storyItem.from_id); + if (peerId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(peerId); + avatar.setUser(user); + ssb.append(UserObject.getUserName(user)); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-peerId); + avatar.setChat(chat); + if (chat != null) { + ssb.append(chat.title); + } + } + headerView.setOnSubtitleClick(v -> { + Bundle args = new Bundle(); + if (peerId >= 0) { + args.putLong("user_id", peerId); + } else { + args.putLong("chat_id", -peerId); + } + storyViewer.presentFragment(new ProfileActivity(args)); + }); + + SpannableString dot = new SpannableString("."); + DotDividerSpan dotDividerSpan = new DotDividerSpan(); + dotDividerSpan.setTopPadding(AndroidUtilities.dp(1.5f)); + dotDividerSpan.setSize(5); + dot.setSpan(dotDividerSpan, 0, dot.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(" ").append(dot).append(" ").append(LocaleController.formatShortDate(currentStory.storyItem.date)); headerView.setSubtitle(ssb, false); } else { @@ -4105,9 +4215,10 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica bottomActionsLinearLayout.setVisibility(View.VISIBLE); } } else { + TLRPC.Chat chat = dialogId < 0 ? MessagesController.getInstance(currentAccount).getChat(-dialogId) : null; if (UserObject.isService(dialogId) && chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.GONE); - } else if (!isSelf && !isChannel && chatActivityEnterView != null) { + } else if (!isSelf && (!isChannel || isGroup && (ChatObject.canSendPlain(chat) || ChatObject.isPossibleRemoveChatRestrictionsByBoosts(chat))) && chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.VISIBLE); } if (isPremiumBlocked && premiumBlockedText == null) { @@ -4257,7 +4368,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica sharedResources.setIconMuted(!storyViewer.soundEnabled(), false); if (isActive && currentStory.storyItem != null) { - FileLog.d("StoryViewer displayed story dialogId=" + dialogId + " storyId=" + currentStory.storyItem.id); + FileLog.d("StoryViewer displayed story dialogId=" + dialogId + " storyId=" + currentStory.storyItem.id + " " + currentStory.getMediaDebugString()); } if (isSelf) { SelfStoryViewsPage.preload(currentAccount, dialogId, currentStory.storyItem); @@ -4421,7 +4532,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica isVideo = storyItem.attachPath.toLowerCase().endsWith(".mp4"); } if (isVideo) { - imageReceiver.setImage(ImageLocation.getForPath(storyItem.attachPath), filter +"_pframe", ImageLocation.getForPath(storyItem.firstFramePath), filter, null, null, /*messageObject.strippedThumb*/null, 0, null, null, 0); + imageReceiver.setImage(ImageLocation.getForPath(storyItem.attachPath), filter + "_pframe", ImageLocation.getForPath(storyItem.firstFramePath), filter, null, null, /*messageObject.strippedThumb*/null, 0, null, null, 0); } else { imageReceiver.setImage(ImageLocation.getForPath(storyItem.attachPath), filter, null, null, /*messageObject.strippedThumb*/null, 0, null, null, 0); } @@ -4499,7 +4610,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica repostCounterProgress.set(repostCounterVisible ? 1f : 0, true); } } - if (storyItem.views.views_count > 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (!(isGroup && (ChatObject.canSendPlain(chat) || ChatObject.isPossibleRemoveChatRestrictionsByBoosts(chat))) && storyItem.views.views_count > 0) { selfStatusView.setText(storyViewer.storiesList == null ? LocaleController.getString("NobodyViews", R.string.NobodyViews) : LocaleController.getString("NobodyViewsArchived", R.string.NobodyViewsArchived)); selfStatusView.setTranslationX(AndroidUtilities.dp(16)); SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); @@ -4865,7 +4977,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica isActive = true; headerView.backupImageView.getImageReceiver().setVisible(true, true); if (currentStory.storyItem != null) { - FileLog.d("StoryViewer displayed story dialogId=" + dialogId + " storyId=" + currentStory.storyItem.id); + FileLog.d("StoryViewer displayed story dialogId=" + dialogId + " storyId=" + currentStory.storyItem.id + " " + currentStory.getMediaDebugString()); } } else { cancelTextSelection(); @@ -5417,6 +5529,19 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private StoryCaptionView.Reply reply; + private String getMediaDebugString() { + if (storyItem != null && storyItem.media != null) { + if (storyItem.media.photo != null) { + return "photo#" + storyItem.media.photo.id + "at" + storyItem.media.photo.dc_id + "dc"; + } else if (storyItem.media.document != null) { + return "doc#" + storyItem.media.document.id + "at" + storyItem.media.document.dc_id + "dc"; + } + } else if (uploadingStory != null) { + return "uploading from " + uploadingStory.path; + } + return "unknown"; + } + public StoryCaptionView.Reply getReply() { if (reply == null) { if (storyItem != null) { @@ -6056,7 +6181,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica getMeasuredWidth() + AndroidUtilities.dp(20), getMeasuredHeight() ); - float rightOffset = (allowShare ? AndroidUtilities.dp(SHARE_BUTTON_OFFSET) : 0) + AndroidUtilities.dp(40); + float rightOffset = (allowShare ? AndroidUtilities.dp(SHARE_BUTTON_OFFSET) : 0) + (allowRepost && isChannel ? 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) - rightOffset, @@ -6179,7 +6304,11 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private void openChat() { Bundle bundle = new Bundle(); - bundle.putLong("user_id", dialogId); + if (dialogId < 0) { + bundle.putLong("chat_id", -dialogId); + } else { + bundle.putLong("user_id", dialogId); + } TLRPC.Dialog dialog = MessagesController.getInstance(currentAccount).getDialog(dialogId); if (dialog != null) { bundle.putInt("message_id", dialog.top_message); @@ -6219,7 +6348,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica sparseIntArray.put(Theme.key_chat_emojiPanelBackground, ColorUtils.setAlphaComponent(Color.WHITE, 30)); } }); - reactionsContainerLayout.setHint(LocaleController.getString(R.string.StoryReactionsHint)); + reactionsContainerLayout.setHint(LocaleController.getString(isGroup ? R.string.StoryGroupReactionsHint : R.string.StoryReactionsHint)); reactionsContainerLayout.skipEnterAnimation = true; addView(reactionsContainerLayout, reactionsContainerIndex, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 52 + 20, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 64)); reactionsContainerLayout.setDelegate(new ReactionsContainerLayout.ReactionsContainerDelegate() { @@ -6265,6 +6394,13 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } else { document = AnimatedEmojiDrawable.findDocument(currentAccount, visibleReaction.documentId); String emoticon = MessageObject.findAnimatedEmojiEmoticon(document, null); + if (emoticon == null) { + if (reactionsContainerLayout.getReactionsWindow() != null) { + reactionsContainerLayout.getReactionsWindow().dismissWithAlpha(); + } + closeKeyboardOrEmoji(); + return; + } SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(emoticon, dialogId); params.entities = new ArrayList<>(); TLRPC.TL_messageEntityCustomEmoji customEmojiEntitiy = new TLRPC.TL_messageEntityCustomEmoji(); @@ -6319,6 +6455,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica reactionsContainerLayout.setMessage(null, null); } reactionsContainerLayout.setFragment(LaunchActivity.getLastFragment()); + reactionsContainerLayout.setHint(LocaleController.getString(isGroup ? R.string.StoryGroupReactionsHint : R.string.StoryReactionsHint)); } void checkReactionsLayoutForLike() { 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 d094850b8..1969c0f78 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java @@ -20,6 +20,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.ChannelBoostsController; import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.DownloadController; @@ -664,7 +665,8 @@ public class StoriesController { } public int getMyStoriesCount() { - int count = uploadingAndEditingStories.size(); + ArrayList myUploadingStories = uploadingAndEditingStories.get(getSelfUserId()); + int count = myUploadingStories == null ? 0 : myUploadingStories.size(); TL_stories.PeerStories userStories = getStories(getSelfUserId()); if (userStories != null && userStories.stories != null) { count += userStories.stories.size(); @@ -2470,6 +2472,14 @@ public class StoriesController { loadChatIds.add(channel_id); } } + if (storyItem.from_id != null) { + long did = DialogObject.getPeerDialogId(storyItem.from_id); + if (did >= 0) { + loadUserIds.add(did); + } else { + loadChatIds.add(-did); + } + } msg.generateThumbs(false); cacheResult.add(msg); data.reuse(); @@ -3252,32 +3262,32 @@ public class StoriesController { consumer.accept(false); return; } - BaseFragment lastFragment = LaunchActivity.getLastFragment(); - LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(lastFragment, lastFragment.getContext(), LimitReachedBottomSheet.TYPE_BOOSTS_FOR_POSTING, currentAccount, resourcesProvider); - limitReachedBottomSheet.setBoostsStats(boostsStatus, false); - limitReachedBottomSheet.setDialogId(dialogId); - if (canPostStories(dialogId)) { - limitReachedBottomSheet.showStatisticButtonInLink(() -> { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - Bundle args = new Bundle(); - args.putLong("chat_id", -dialogId); - args.putBoolean("is_megagroup", chat.megagroup); - args.putBoolean("start_from_boosts", true); - args.putBoolean("only_boosts", true); - StatisticActivity fragment = new StatisticActivity(args); - BaseFragment lastFragment1 = LaunchActivity.getLastFragment(); - if (lastFragment1 != null) { - if (StoryRecorder.isVisible()) { - BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); - params.transitionFromLeft = true; - lastFragment1.showAsSheet(fragment, params); - } else { - lastFragment1.presentFragment(fragment); + messagesController.getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { + if (canApplyBoost == null) { + consumer.accept(false); + return; + } + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + Runnable runnable = null; + if (canPostStories(dialogId)) { + runnable = () -> { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + BaseFragment fragment = StatisticActivity.create(chat); + BaseFragment lastFragment1 = LaunchActivity.getLastFragment(); + if (lastFragment1 != null) { + if (StoryRecorder.isVisible()) { + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + lastFragment1.showAsSheet(fragment, params); + } else { + lastFragment1.presentFragment(fragment); + } } - } - }); - } - limitReachedBottomSheet.show(); + }; + } + LimitReachedBottomSheet.openBoostsForPostingStories(lastFragment, dialogId, canApplyBoost, boostsStatus, runnable); + consumer.accept(false); + }); consumer.accept(false); }); } else { @@ -3425,7 +3435,7 @@ public class StoriesController { public boolean canPostStories(long dialogId) { if (dialogId < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - if (chat == null || !ChatObject.isChannelAndNotMegaGroup(chat)) { + if (chat == null || !ChatObject.isBoostSupported(chat)) { return false; } return chat.creator || chat.admin_rights != null && chat.admin_rights.post_stories; 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 936155b99..e778ea294 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java @@ -88,6 +88,9 @@ public class StoriesStorage { chatsToLoad.add(channel_id); } } + if (storyItem.from_id != null) { + MessagesStorage.addLoadPeerInfo(storyItem.from_id, usersToLoad, chatsToLoad); + } StoryCustomParamsHelper.readLocalParams(storyItem, customData); storyItems.add(storyItem); data.reuse(); 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 a26808d75..d3900f3c3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java @@ -24,6 +24,7 @@ import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLoader; @@ -110,7 +111,7 @@ public class StoriesUtilities { int state; int unreadState = 0; boolean showProgress = storiesController.isLoading(dialogId); - + boolean isForum = ChatObject.isForum(UserConfig.selectedAccount, dialogId) && !params.isStoryCell; if (params.drawHiddenStoriesAsSegments) { hasStories = storiesController.hasHiddenStories(); } @@ -219,7 +220,7 @@ public class StoriesUtilities { rectTmp.set(params.originalAvatarRect); rectTmp.inset(inset, inset); - drawCircleInternal(canvas, avatarImage.getParentView(), params, gradientTools.paint); + drawCircleInternal(canvas, avatarImage.getParentView(), params, gradientTools.paint, isForum); } if ((params.prevState == STATE_READ && params.progressToSate != 1f) || params.currentState == STATE_READ) { boolean animateOut = params.prevState == STATE_READ && params.progressToSate != 1f; @@ -256,9 +257,9 @@ public class StoriesUtilities { rectTmp.set(params.originalAvatarRect); rectTmp.inset(inset, inset); if (params.drawSegments) { - drawSegmentsInternal(canvas, storiesController, avatarImage, params, paint, unreadPaint, closeFriendsPaint); + drawSegmentsInternal(canvas, storiesController, avatarImage, params, paint, unreadPaint, closeFriendsPaint, isForum); } else { - drawCircleInternal(canvas, avatarImage.getParentView(), params, paint); + drawCircleInternal(canvas, avatarImage.getParentView(), params, paint, isForum); } } if ((params.prevState == STATE_PROGRESS && params.progressToSate != 1f) || params.currentState == STATE_PROGRESS) { @@ -309,7 +310,7 @@ public class StoriesUtilities { } float progressToSegments = params.progressToSegments; params.progressToSegments = 1f - params.progressToProgressSegments; - drawSegmentsInternal(canvas, storiesController, avatarImage, params, paint, unreadPaint, closeFriendsPaint); + drawSegmentsInternal(canvas, storiesController, avatarImage, params, paint, unreadPaint, closeFriendsPaint, isForum); params.progressToSegments = progressToSegments; if (avatarImage.getParentView() != null) { avatarImage.invalidate(); @@ -345,7 +346,7 @@ public class StoriesUtilities { } } - private static void drawSegmentsInternal(Canvas canvas, StoriesController storiesController, ImageReceiver avatarImage, AvatarStoryParams params, Paint paint, Paint unreadPaint, Paint closeFriendsPaint) { + private static void drawSegmentsInternal(Canvas canvas, StoriesController storiesController, ImageReceiver avatarImage, AvatarStoryParams params, Paint paint, Paint unreadPaint, Paint closeFriendsPaint, boolean isForum) { checkGrayPaint(params.resourcesProvider); checkStoryCellGrayPaint(params.isArchive, params.resourcesProvider); int globalState; @@ -384,19 +385,19 @@ public class StoriesUtilities { } float startAngle = -90; float endAngle = 90; - drawSegment(canvas, rectTmp, localPaint, startAngle, endAngle, params); + drawSegment(canvas, rectTmp, localPaint, startAngle, endAngle, params, isForum); startAngle = 90; endAngle = 270; - drawSegment(canvas, rectTmp, localPaint, startAngle, endAngle, params); + drawSegment(canvas, rectTmp, localPaint, startAngle, endAngle, params, isForum); if (params.progressToSegments != 1 && localPaint != globalPaint) { globalPaint.setAlpha((int) (255 * (1f - params.progressToSegments))); startAngle = -90; endAngle = 90; - drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params); + drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params, isForum); startAngle = 90; endAngle = 270; - drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params); + drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params, isForum); globalPaint.setAlpha(255); } // canvas.drawCircle(rectTmp.centerX(), rectTmp.centerY(), rectTmp.width() / 2f, localPaint); @@ -435,12 +436,12 @@ public class StoriesUtilities { startAngle += gapLen; endAngle -= gapLen; - drawSegment(canvas, rectTmp, segmentPaint, startAngle, endAngle, params); + drawSegment(canvas, rectTmp, segmentPaint, startAngle, endAngle, params, isForum); 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); + drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params, isForum); // globalPaint.setStrokeWidth(strokeWidth); globalPaint.setAlpha(255); } @@ -547,7 +548,15 @@ public class StoriesUtilities { } } - private static void drawCircleInternal(Canvas canvas, View view, AvatarStoryParams params, Paint paint) { + private static final RectF forumRect = new RectF(); + + private static void drawCircleInternal(Canvas canvas, View view, AvatarStoryParams params, Paint paint, boolean isForum) { + if (isForum) { + forumRect.set(rectTmp); + forumRect.inset(AndroidUtilities.dp(0.5f), AndroidUtilities.dp(0.5f)); + canvas.drawRoundRect(forumRect, AndroidUtilities.dp(18), AndroidUtilities.dp(18), paint); + return; + } if (params.progressToArc == 0) { canvas.drawCircle(rectTmp.centerX(), rectTmp.centerY(), rectTmp.width() / 2f, paint); } else { @@ -555,7 +564,13 @@ public class StoriesUtilities { } } - private static void drawSegment(Canvas canvas, RectF rectTmp, Paint paint, float startAngle, float endAngle, AvatarStoryParams params) { + private static void drawSegment(Canvas canvas, RectF rectTmp, Paint paint, float startAngle, float endAngle, AvatarStoryParams params, boolean isForum) { + if (isForum) { + forumRect.set(rectTmp); + forumRect.inset(AndroidUtilities.dp(0.5f), AndroidUtilities.dp(0.5f)); + canvas.drawRoundRect(forumRect, AndroidUtilities.dp(18), AndroidUtilities.dp(18), paint); + return; + } if (!params.isFirst && !params.isLast) { if (startAngle < 90) { drawArcExcludeArc(canvas, rectTmp, paint, startAngle, endAngle, -params.progressToArc / 2, params.progressToArc / 2); 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 4e5b85509..192df6b7c 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 @@ -7,6 +7,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -29,9 +30,11 @@ import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.CircularProgressDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Loadable; +import org.telegram.ui.Components.LoadingDrawable; import org.telegram.ui.Components.ScaleStateListAnimator; -public class ButtonWithCounterView extends FrameLayout { +public class ButtonWithCounterView extends FrameLayout implements Loadable { private Theme.ResourcesProvider resourcesProvider; @@ -96,6 +99,12 @@ public class ButtonWithCounterView extends FrameLayout { setWillNotDraw(false); } + public void setColor(int color) { + if (filled) { + setBackground(Theme.createRoundRectDrawable(dp(8), color)); + } + } + public void updateColors() { rippleView.setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), 8, 8)); text.setTextColor(Theme.getColor(filled ? Theme.key_featuredStickers_buttonText : Theme.key_featuredStickers_addButton, resourcesProvider)); @@ -215,16 +224,23 @@ public class ButtonWithCounterView extends FrameLayout { } } + private LoadingDrawable flickeringLoadingDrawable; + private boolean flickeringLoading; private float loadingT = 0; private boolean loading; private ValueAnimator loadingAnimator; public void setLoading(boolean loading) { if (this.loading != loading) { + if (flickeringLoading) { + this.loading = loading; + invalidate(); + return; + } + if (loadingAnimator != null) { loadingAnimator.cancel(); loadingAnimator = null; } - loadingAnimator = ValueAnimator.ofFloat(loadingT, (this.loading = loading) ? 1 : 0); loadingAnimator.addUpdateListener(anm -> { loadingT = (float) anm.getAnimatedValue(); @@ -243,6 +259,10 @@ public class ButtonWithCounterView extends FrameLayout { } } + public void setFlickeringLoading(boolean flickeringLoading) { + this.flickeringLoading = flickeringLoading; + } + public boolean isLoading() { return loading; } @@ -332,9 +352,14 @@ public class ButtonWithCounterView extends FrameLayout { } } + @Override + public boolean isEnabled() { + return enabled; + } + @Override protected boolean verifyDrawable(@NonNull Drawable who) { - return text == who || subText == who || countText == who || super.verifyDrawable(who); + return flickeringLoadingDrawable == who || text == who || subText == who || countText == who || super.verifyDrawable(who); } @Override @@ -355,6 +380,32 @@ public class ButtonWithCounterView extends FrameLayout { protected void onDraw(Canvas canvas) { rippleView.draw(canvas); + if (flickeringLoading) { + if (loading) { + if (flickeringLoadingDrawable == null) { + flickeringLoadingDrawable = new LoadingDrawable(resourcesProvider); + flickeringLoadingDrawable.setCallback(this); + flickeringLoadingDrawable.setGradientScale(2f); + flickeringLoadingDrawable.setAppearByGradient(true); + flickeringLoadingDrawable.strokePaint.setStrokeWidth(0); + flickeringLoadingDrawable.setColors( + Theme.multAlpha(Color.WHITE, 0.02f), + Theme.multAlpha(Color.WHITE, 0.375f) + ); + } + flickeringLoadingDrawable.resetDisappear(); + flickeringLoadingDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + flickeringLoadingDrawable.setRadiiDp(8); + flickeringLoadingDrawable.draw(canvas); + } else if (flickeringLoadingDrawable != null) { + flickeringLoadingDrawable.disappear(); + flickeringLoadingDrawable.draw(canvas); + if (flickeringLoadingDrawable.isDisappeared()) { + flickeringLoadingDrawable.reset(); + } + } + } + if (loadingT > 0) { if (loadingDrawable == null) { loadingDrawable = new CircularProgressDrawable(text.getTextColor()); 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 3ccbc7134..fb20faacb 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 @@ -375,7 +375,7 @@ public class CaptionContainerView extends FrameLayout { @Override public boolean dispatchTouchEvent(MotionEvent ev) { - if (ignoreTouches || ev.getAction() == MotionEvent.ACTION_DOWN && ignoreTouches(ev.getX(), ev.getY()) || !bounds.contains(ev.getX(), ev.getY()) && !keyboardShown) { + if (ignoreTouches || ev.getAction() == MotionEvent.ACTION_DOWN && ignoreTouches(ev.getX(), ev.getY()) || !clickBounds.contains(ev.getX(), ev.getY()) && !keyboardShown) { return false; } if (ev.getAction() == MotionEvent.ACTION_DOWN && !keyboardShown) { @@ -764,6 +764,7 @@ public class CaptionContainerView extends FrameLayout { private final RectF rectF = new RectF(); private final RectF bounds = new RectF(); + private final RectF clickBounds = new RectF(); protected void onEditHeightChange(int height) {} @@ -886,19 +887,25 @@ public class CaptionContainerView extends FrameLayout { editText.getEditText().setTranslationY(lastHeightTranslation = heightTranslation); } - final float pad = lerp(AndroidUtilities.dp(12), 0, keyboardT); + final float pad = lerp(dp(12), 0, keyboardT); bounds.set( pad, getHeight() - pad - heightAnimated, getWidth() - pad, getHeight() - pad ); + clickBounds.set( + 0, + getHeight() - heightAnimated - dp(24), + getWidth(), + getHeight() + ); canvas.save(); final float s = bounce.getScale(.018f); canvas.scale(s, s, bounds.centerX(), bounds.centerY()); - final float r = lerp(AndroidUtilities.dp(21), 0, keyboardT); + final float r = lerp(dp(21), 0, keyboardT); if (customBlur()) { drawBlur(backgroundBlur, canvas, bounds, r, false, 0, 0, true); backgroundPaint.setAlpha((int) (lerp(0x26, 0x40, keyboardT))); 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 4ced1ab84..16baca8ae 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 @@ -28,6 +28,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.camera.CameraController; import org.telegram.messenger.camera.CameraSession; +import org.telegram.messenger.camera.CameraSessionWrapper; import org.telegram.messenger.camera.CameraView; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; @@ -36,13 +37,12 @@ import org.telegram.ui.ActionBar.AlertDialog; import java.util.Arrays; import java.util.Locale; -public class DualCameraView extends CameraView implements CameraController.ErrorCallback { +public class DualCameraView extends CameraView { private boolean dualAvailable; public DualCameraView(Context context, boolean frontface, boolean lazy) { super(context, frontface, lazy); - CameraController.getInstance().addOnErrorListener(this); dualAvailable = dualAvailableStatic(context); } @@ -56,7 +56,6 @@ public class DualCameraView extends CameraView implements CameraController.Error public void destroy(boolean async, Runnable beforeDestroyRunnable) { saveDual(); super.destroy(async, beforeDestroyRunnable); - CameraController.getInstance().removeOnErrorListener(this); } private final PointF lastTouch = new PointF(); @@ -484,7 +483,7 @@ public class DualCameraView extends CameraView implements CameraController.Error } @Override - public void onError(int error, Camera camera, CameraSession session) { + public void onError(int error, Camera camera, CameraSessionWrapper session) { if (isDual()) { if (!dualAvailableDefault(getContext(), false)) { MessagesController.getGlobalMainSettings().edit().putBoolean("dual_available", dualAvailable = false).apply(); @@ -497,7 +496,7 @@ public class DualCameraView extends CameraView implements CameraController.Error log(false); toggleDual(); } - if (getCameraSession(0) == session) { + if (getCameraSession(0) != null && getCameraSession(0).equals(session)) { resetCamera(); } onCameraError(); 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 ce0bfd7e8..127c9020d 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 @@ -11,16 +11,13 @@ 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; @@ -32,22 +29,20 @@ import android.text.Spanned; 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; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; -import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.ButtonBounce; @@ -95,6 +90,7 @@ public class HintView2 extends View { private final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); private Layout.Alignment textLayoutAlignment = Layout.Alignment.ALIGN_NORMAL; private StaticLayout textLayout; + private AnimatedEmojiSpan.EmojiGroupedSpans emojiGroupedSpans; private float textLayoutLeft, textLayoutWidth, textLayoutHeight; private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(); private float textX, textY; @@ -589,6 +585,13 @@ public class HintView2 extends View { textLayoutWidth = Math.max(0, right - left); textLayoutHeight = textLayout.getHeight(); textLayoutLeft = left; + emojiGroupedSpans = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, emojiGroupedSpans, textLayout); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + AnimatedEmojiSpan.release(this, emojiGroupedSpans); } private final ButtonBounce bounce = new ButtonBounce(this, 2f, 5f); @@ -710,6 +713,7 @@ public class HintView2 extends View { invalidate(); } textLayout.draw(canvas); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, textLayout, emojiGroupedSpans, 0, null, 0, 0, 0, 1f); canvas.restore(); } else { if (textToSet != null) { 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 e90825ba8..f74374c8d 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 @@ -1613,7 +1613,7 @@ public class PreviewView extends FrameLayout { public static Drawable getBackgroundDrawableFromTheme(int currentAccount, EmojiThemes chatTheme, int prevPhase, boolean isDark, boolean preview) { Drawable drawable; - if (chatTheme.showAsDefaultStub) { + if (chatTheme.isAnyStub()) { Theme.ThemeInfo themeInfo = EmojiThemes.getDefaultThemeInfo(isDark); SparseIntArray currentColors = chatTheme.getPreviewColors(currentAccount, isDark ? 1 : 0); String wallpaperLink = chatTheme.getWallpaperLink(isDark ? 1 : 0); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java index 526926326..4fbff8bf8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java @@ -77,7 +77,7 @@ public class RoundVideoRecorder extends FrameLayout { addView(cameraView); cameraView.setDelegate(() -> { if (recordingStarted > 0) return; - CameraController.getInstance().recordVideo(cameraView.getCameraSession(), file, false, (thumbPath, duration) -> { + CameraController.getInstance().recordVideo(cameraView.getCameraSessionObject(), file, false, (thumbPath, duration) -> { recordingStopped = System.currentTimeMillis(); AndroidUtilities.cancelRunOnUIThread(stopRunnable); if (cancelled) { 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 574ce1168..6d35d50a0 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 @@ -982,6 +982,7 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification // items.add(ItemInner.asPad(dp(84) + 4 * dp(56) + (sendAsMessageEnabled ? dp(120) : dp(64)))); List sendAs = MessagesController.getInstance(currentAccount).getStoriesController().sendAs; boolean containsPrivacy = true; + boolean isChannel = false; if (canChangePeer && (isEdit || sendAs == null || sendAs.size() <= 1)) { items.add(ItemInner.asHeader2( isEdit ? @@ -1003,6 +1004,7 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(selectedPeer.channel_id); items.add(ItemInner.asChat(chat, false).asSendAs()); containsPrivacy = false; + isChannel = ChatObject.isChannelAndNotMegaGroup(chat); } else if (selectedPeer instanceof TLRPC.TL_inputPeerChat) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(selectedPeer.chat_id); items.add(ItemInner.asChat(chat, false).asSendAs()); @@ -1066,8 +1068,8 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification } if (!isEdit) { items.add(ItemInner.asCheck(LocaleController.getString(R.string.StoryAllowScreenshots), 0, allowScreenshots)); - items.add(ItemInner.asCheck(LocaleController.getString(containsPrivacy ? R.string.StoryKeep : R.string.StoryKeepChannel), 1, keepOnMyPage)); - items.add(ItemInner.asShadow(LocaleController.formatPluralString(containsPrivacy ? "StoryKeepInfo" : "StoryKeepChannelInfo", (storyPeriod == Integer.MAX_VALUE ? 86400 : storyPeriod) / 3600))); + items.add(ItemInner.asCheck(LocaleController.getString(containsPrivacy ? R.string.StoryKeep : (isChannel ? R.string.StoryKeepChannel : R.string.StoryKeepGroup)), 1, keepOnMyPage)); + items.add(ItemInner.asShadow(LocaleController.formatPluralString(containsPrivacy ? "StoryKeepInfo" : (isChannel ? "StoryKeepChannelInfo" : "StoryKeepGroupInfo"), (storyPeriod == Integer.MAX_VALUE ? 86400 : storyPeriod) / 3600))); } } else if (pageType == PAGE_TYPE_CLOSE_FRIENDS) { headerView.setText(LocaleController.getString("StoryPrivacyAlertCloseFriendsTitle", R.string.StoryPrivacyAlertCloseFriendsTitle)); @@ -2757,10 +2759,11 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification if (participants_count <= 0) { participants_count = chat.participants_count; } + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); if (participants_count >= 1) { - subtitle = LocaleController.formatPluralString("Subscribers", participants_count); + subtitle = LocaleController.formatPluralString(isChannel ? "Subscribers" : "Members", participants_count); } else { - subtitle = LocaleController.getString(R.string.DiscussChannel); + subtitle = LocaleController.getString(isChannel ? R.string.DiscussChannel : R.string.AccDescrGroup); } } else if (ChatObject.isChannel(chat) && !chat.megagroup) { if (participants_count >= 1) { 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 580f3a08f..2f4d6f195 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 @@ -104,6 +104,7 @@ import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.camera.CameraController; import org.telegram.messenger.camera.CameraSession; +import org.telegram.messenger.camera.CameraSessionWrapper; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -2959,8 +2960,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg bitmap.recycle(); } if (!savedFromTextureView) { - final CameraSession cameraSession = cameraView.getCameraSession(); - takingPhoto = CameraController.getInstance().takePicture(outputFile, true, cameraSession, (orientation) -> { + takingPhoto = CameraController.getInstance().takePicture(outputFile, true, cameraView.getCameraSessionObject(), (orientation) -> { if (useDisplayFlashlight()) { try { windowView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); @@ -3044,7 +3044,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } private void startRecording(boolean byLongPress, Runnable whenStarted) { - CameraController.getInstance().recordVideo(cameraView.getCameraSession(), outputFile, false, (thumbPath, duration) -> { + CameraController.getInstance().recordVideo(cameraView.getCameraSessionObject(), outputFile, false, (thumbPath, duration) -> { if (recordControl != null) { recordControl.stopRecordingLoading(true); } @@ -5331,7 +5331,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (cameraView == null || cameraView.getCameraSession() == null) { return null; } - if (cameraView.isFrontface() && cameraView.getCameraSession().availableFlashModes.isEmpty()) { + if (cameraView.isFrontface() && !cameraView.getCameraSession().hasFlashModes()) { checkFrontfaceFlashModes(); return frontfaceFlashModes.get(frontfaceFlashMode); } @@ -5342,7 +5342,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (cameraView == null || cameraView.getCameraSession() == null) { return null; } - if (cameraView.isFrontface() && cameraView.getCameraSession().availableFlashModes.isEmpty()) { + if (cameraView.isFrontface() && !cameraView.getCameraSession().hasFlashModes()) { checkFrontfaceFlashModes(); return frontfaceFlashModes.get(frontfaceFlashMode + 1 >= frontfaceFlashModes.size() ? 0 : frontfaceFlashMode + 1); } @@ -5353,7 +5353,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (cameraView == null || cameraView.getCameraSession() == null) { return; } - if (cameraView.isFrontface() && cameraView.getCameraSession().availableFlashModes.isEmpty()) { + if (cameraView.isFrontface() && !cameraView.getCameraSession().hasFlashModes()) { int index = frontfaceFlashModes.indexOf(mode); if (index >= 0) { frontfaceFlashMode = index; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java index 34a725026..be6980942 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java @@ -2467,17 +2467,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro if (!insideBottomSheet()) { limitReachedBottomSheet.showStatisticButtonInLink(() -> { TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - Bundle args = new Bundle(); - args.putLong("chat_id", -dialogId); - args.putBoolean("is_megagroup", chat.megagroup); - args.putBoolean("start_from_boosts", true); - TLRPC.ChatFull chatInfo = getMessagesController().getChatFull(-dialogId); - if (chatInfo == null || !chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - } - ; - StatisticActivity fragment = new StatisticActivity(args); - presentFragment(fragment); + presentFragment(StatisticActivity.create(chat)); }); } showDialog(limitReachedBottomSheet); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java index 2518147d2..d7332b9f8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java @@ -72,6 +72,7 @@ import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; @@ -88,6 +89,7 @@ import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ProfileSearchCell; +import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TopicSearchCell; import org.telegram.ui.Cells.UserCell; import org.telegram.ui.Components.AlertsCreator; @@ -113,6 +115,7 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.PullForegroundDrawable; +import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.RecyclerAnimationScrollHelper; @@ -190,6 +193,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N private static final int delete_chat_id = 11; private static final int hide_id = 12; private static final int show_id = 13; + private static final int boost_group_id = 14; private boolean removeFragmentOnTransitionEnd; private boolean finishDialogRightSlidingPreviewOnTransitionEnd; @@ -204,8 +208,10 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N private ActionBarMenuSubItem createTopicSubmenu; private ActionBarMenuSubItem addMemberSubMenu; private ActionBarMenuSubItem deleteChatSubmenu; + private ActionBarMenuSubItem boostGroupSubmenu; private boolean bottomPannelVisible = true; private float searchAnimationProgress = 0f; + private TL_stories.TL_premium_boostsStatus boostsStatus; private long startArchivePullingTime; private boolean scrollingManually; @@ -578,6 +584,17 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N bottomSheet.show(); } break; + case boost_group_id: { + TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); + if (ChatObject.hasAdminRights(chatLocal)) { + BoostsActivity boostsActivity = new BoostsActivity(-chatId); + boostsActivity.setBoostsStatus(boostsStatus); + presentFragment(boostsActivity); + } else { + getNotificationCenter().postNotificationName(NotificationCenter.openBoostForUsersDialog, -chatId); + } + break; + } case create_topic_id: TopicCreateFragment fragment = TopicCreateFragment.create(chatId, 0); presentFragment(fragment); @@ -728,6 +745,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N other = menu.addItem(0, R.drawable.ic_ab_other, themeDelegate); other.addSubItem(toggle_id, R.drawable.msg_discussion, LocaleController.getString("TopicViewAsMessages", R.string.TopicViewAsMessages)); addMemberSubMenu = other.addSubItem(add_member_id, R.drawable.msg_addcontact, LocaleController.getString("AddMember", R.string.AddMember)); + boostGroupSubmenu = other.addSubItem(boost_group_id, 0, new RLottieDrawable(R.raw.boosts, "" + R.raw.boosts, AndroidUtilities.dp(24), AndroidUtilities.dp(24)), TextCell.applyNewSpan(LocaleController.getString(R.string.BoostingBoostGroupMenu)), true, false); createTopicSubmenu = other.addSubItem(create_topic_id, R.drawable.msg_topic_create, LocaleController.getString("CreateTopic", R.string.CreateTopic)); deleteChatSubmenu = other.addSubItem(delete_chat_id, R.drawable.msg_leave, LocaleController.getString("LeaveMegaMenu", R.string.LeaveMegaMenu), themeDelegate); @@ -1352,6 +1370,10 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N updateChatInfo(); updateColors(); + if (ChatObject.isBoostSupported(getCurrentChat())) { + getMessagesController().getBoostsController().getBoostsStats(-chatId, boostsStatus -> this.boostsStatus = boostsStatus); + } + return fragmentView; } @@ -2485,7 +2507,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N other.setVisibility(opnendForSelect ? View.GONE : View.VISIBLE); addMemberSubMenu.setVisibility(ChatObject.canAddUsers(chatLocal) ? View.VISIBLE : View.GONE); - + boostGroupSubmenu.setVisibility(ChatObject.isBoostSupported(chatLocal) && (getUserConfig().isPremium() || ChatObject.isBoosted(chatFull) || ChatObject.hasAdminRights(chatLocal)) ? View.VISIBLE : View.GONE); deleteChatSubmenu.setVisibility(chatLocal != null && !chatLocal.creator && !ChatObject.isNotInChat(chatLocal) ? View.VISIBLE : View.GONE); updateCreateTopicButton(true); groupCall = getMessagesController().getGroupCall(chatId, true); @@ -2521,6 +2543,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N @Override public boolean onFragmentCreate() { getMessagesController().loadFullChat(chatId, 0, true); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatWasBoostedByUser); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatInfoDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.topicsDidLoaded); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.updateInterfaces); @@ -2558,7 +2581,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N @Override public void onFragmentDestroy() { notificationsLocker.unlock(); - + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatWasBoostedByUser); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatInfoDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.topicsDidLoaded); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.updateInterfaces); @@ -2648,6 +2671,10 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N pendingRequestsDelegate.setChatInfo(chatFull, true); } } + } else if (id == NotificationCenter.chatWasBoostedByUser) { + if (chatId == -(long) args[2]) { + boostsStatus = (TL_stories.TL_premium_boostsStatus) args[0]; + } } else if (id == NotificationCenter.topicsDidLoaded) { Long chatId = (Long) args[0]; if (this.chatId == chatId) { diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_boost_plus.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_boost_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..299802f0de3ac2567641bc9c36be3f9ffc1fb7e7 GIT binary patch literal 759 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM315=`>i(^Ox z=iBMF9ZQNauL|#liH==D7<<>t5}n-)X}Iv8Cy1X7>%CnWOW@L@O-JOf#rcs^*_td1B3-cRPQ_@iFoJxqEZw&YAmn7w`Vg)mnYBlGSTz z5O2kl;+tQJ1Tq<<9a7Y6wbZp)ggyk$koYMOyi4tw;&J2EH;zwvAMo<$sx>Fp#EO~j zJ2ky^C0k=)!OD(^t=8pEA$4r$beK)&Ex!KLtD|Y}gMOujSMNp`1^W6v<>RVjKHGO_ zzsxtEVgtn!TPA(A&iI^i|NDlBLSits* za}$5#{>advKSc&&2ctKn|FQ1z)vDd$)s#C~Cq=->KiBk2)d#sBeVo#9AHE5AvUS$* zmc-b87GJ=+r+4W#cw5@oM$%}-L&Zi9}owb{@ zd>t;RN{g(K_@ecf>94Q_gHxKYi}%u&mNN{0H;SHJaEbjT@6WPr^JQI69(n;@#)7K=tbhddBjLPG`4y+16r0s2 zO3N|*ot%F3Xp=?dY!|gyL($uw_sU`)J?sCIbFKW&+CM+44zOhGc)H?S3)AHUNs}<^ g@3s5>7qPBm*xG$N$lopCJt)z6y85}Sb4q9e05lXivj6}9 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_info.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_info.png new file mode 100644 index 0000000000000000000000000000000000000000..a3ebd48a4fb0a66bc039991ac62ff1d036fe043a GIT binary patch literal 657 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*>6u5$B+ol zw-MHU%!VR&Tsu12tO9}?FI_Hbj8PDOz~*s5z>05z2D^gzf+j6ha|f^9mW-dKB09zs zb9-<2zeyEdFQ9Du^Jv}tlbbjHo}=>9y_EIRtEYdmrlm&Dux)GmM_cnNN zG8WGXwQ4ZjuJz@53HSV5Tq4oU&~#(hneOdV2=HA zh5x8u>CAN@>}uZ+Wd!^Dw7N0z{JvMLOz)%~3&*Q(O!j-WZ}LtR#|wfgVs6uV!aDR% zSv@%Y`IN=Hq$k(fmF7z?oq1j7{E@Ww|4Y((cJ@BxGgZ6ccIDt^icw8vG literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_boosts.png b/TMessagesProj/src/main/res/drawable-hdpi/large_boosts.png new file mode 100644 index 0000000000000000000000000000000000000000..4f7db9b9a2ea7a0008ab582b356db1aed80dc5fd GIT binary patch literal 1572 zcmaJ>c~H^`6#gNYN}5KPgya=@7b+;GR!DeIN^Ihp=8;!wB_5UKu2-cc9#kr7DP>Bj znbbzwtXC0{LS?lcG-W2PsnOvXWU~0r?ms*G$M?Q>eDmJCc{A@EmExrXMM41p&>?%1 z_Nkb*0?kz_i%Qh%Q4uJ0pBE8md4`%)1*DiDa;&c}V6E~s0Z{%S0J0)c0jUB2fY~4b ztYXkgj;;1jmBt4D>#qp!$BPL7pk7QSxzkR7WYy$?jWK%Jv*y^?9t7Q;&(6!;Pl9aM zG-nlf!nNHY^bX55%n7)orrEW4YJma9?EJ}66TZ3*g`wf$vE35p_VF}{s!N8C!P1wk zeJqqsfy$Ae@8+f}KDQVrC~hm78kLHZCo?)k)e~YZXOP8v$mQ&H$!e7D{|MH&s$sF% zb;9qFcSSI|tmKz7GGGhSN@3j9!x<$0)dxE`Jxmh)N~S z`|ITOOf!{44qM4xI9j%*;Eft0U~#<;gcDXi)+{rXjUYDycvG(OcgC=lsU9OP4$O>k zEvfBpLo%@^8V~D6?lzwI0Ry?-Q`*gQBh9~9;0Z0=;l)L>sULWVv5E~m(Okg5Au){A zq}LvSc{y+uSaXNSRAvP z)1GI=JcsK!PxhhH{p~g=@ON~xV}y&|UA`2zb*AvS^mFL&{7(OQ8&&^h2=roK%~KF` zsdQ}gH~k99Td$OM+ORkz!U(LrEw<(=8}5H=Yy#I~SOiIl%@VibA3;Q$g&bk1WG40n z>!7|~C?lzQH96|In2szvqdSj)7O2ziXid7f>QdiofcXq`bUY!)>dC|)({VG+iQF0D z_V8o-bQtkl%A%Lk>po$6jI>(J%^&}qE0^lgT?5rePA`iRp&io$;dVy^kg>W+heH`e zxthb&!ddg~(>$q9qlM>$@Krvy?`TB*{l9Lt<$g0}q)XpoTca2_{mLOl$@r26&2ee1 zO$fZas1q2z!XoVTL4;@2o@=4_@OrOef`bRQ?8wQHN%&|H%iW~By|30;2-#gMFV3t; zb(nhaSi@UhwvZMb7VE>u4~9yDYshC>~1b=a#sU#(ejwiKF^B=#?fPGj!CmjU#33GK1^$>f%7IJ}L`+ z!361NlROY@71Xjis{~#XSB~Fvq*&VF3PTlfXI?+^?5`j}F;Sg^)~s&BwV*ghtf1F# zkD>m~NdK^I-aBhnTa(^!{jFF*P)0&x-4v#|H#O;bu==`Gdov5erb^XFiR6aj1e%u^ zLgg>OUe4x$-pGXq_zAH-hkG8IQ^sdfl6J~`FF#4&krZdP(+gH<@8Y#74d8EW+v4Ph zFqnGCy~6lJXm&coRh=lFLE(CgAmyl$%@2~3QiMarL1NXi$huwcQH8mYKi2Pm&cO~9 z6Qe9}*arKr&BSb`0+BNcK3vt+m*&Rv5c0rA9a$p8l{&f$>YXg6KSr)4OAB-6(Mg@> z?^bQ7OT|(0`9$=5!;Fz&{7Qez*~8iy>fEXgugcgrp}4L03Pcjf9JJ}!Cxzc5TVI@@ z_m#6Dyhh}GqdpUUs@~sjVJNRFo>9hOI=#=VC!Dvg)v3aeBEoIfcoqt9u+V19?xjQB z?VCoGt)rNRcpuxqO|tBvMqoS38a|SEsq4m57OhiI1R6t=jsyv9?D10lf)Y1_ldI&b znG*zYC#O>5dNZ9+K7XUV*($^6f1loE!nD?sZei%8pNDK*vhtzH9u!gwF(UVGmBPee literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_edit_appearance.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_edit_appearance.png new file mode 100644 index 0000000000000000000000000000000000000000..9711b42ec150f757fd4343924e73fea9d16a9366 GIT binary patch literal 1251 zcmV<91RVQ`P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz1O-V#SR9Fe^m|KiZR~W~gaT(Vp z)M(sqMPot}>QX|3l!ymjG)6>(G$QqaL^SchgqJ3+k!aHwArhA&;*t_^d*ERvQ8Hy* zMnn;9l(ZD39KZjb{cYdbvu9=>jt5D<>a z`9t6+c-etboVpLmMX<+pxQ0F|b%TUN>L){u>-iJ9Hb>(^;!0Oof!--zg|7o>#q?_j z#N$aedF|m8m<&zI%khyp5p;Vbze2m5gwVjR$(U5ca|n!qMbN{?us;B;&Jk$kV|8>A z^xS9?lE0vToutq~Oeqg{jE%lW02`N`(1Q(qqI=goytKfJbU?nF)${Mz3C zx~lO$o{vrs|BO~)kAUIu3rHSC{V;wAT-of+$Qdg5b*OEJ`SDm|wF;WRpZ~`R~A_JSmf4OVIMK0j;nOP!qk~gLfHYcks8c5r=^+=IEqU^(7r|U-fd;{!O@E=H`9b`H9O5l-#q1<9@{0q?<_>sa+)`jtmkC~2t zw9EP2{C*^UBFy=Nv5Sx8t>MFie;5o5omDx(LK$3SCwS2bUXs)w|GqF$EBI+r zPLi)E$=QJKSS(hFopZamcsI~3nil4+Wd+a2>I!FaF`X&ezFw|koQ4|jMAu22>XY}a zX2?bQ!Ct6ObR4XP;FXcj#qv8XW1YERFI-ch6m)3n;l2pF-}L{6UI8^Gcg)s`SOx$9 N002ovPDHLkV1kC8M8W_7 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_pack.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_pack.png new file mode 100644 index 0000000000000000000000000000000000000000..b97cdec4f359bf11ef959d4c19b88d63519e8250 GIT binary patch literal 1172 zcmV;F1Z(?=P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0{z*hZR9Fe!m`{jJQ5?sOKl!(r zros3#{!Wx+QbR1LS!gI3vLJu5P@08}ER@)on8lQhB1KP%l?_c4DMhhjquB^C{>)-# zkQ!sq^ZDL)e%G1%?s@K;c`W?u^Um-7{+x5}J^$`~L?!O6>`G{O8VzrR zt*{*CKpo_v$MK5tCfu&7sv4%OywH*Pkb^4D}vO~J2 zew)<0()=TA1m{4~HNsKB3+m3c>Y$W7C={u`i#@Ba zd*(>>eZHQId*}>n%`x5-N}bx0cZDML_r7QKbzlS zWR`b*2K~Fc4h|XqtZ{v=t{U|L(JM@}H|PcHha1lt7xdQ)+MD6p{6?vVQrOO2&-z^t z%6}~web;TMdhO}>bEwzVyJ+tQZG=9nd`>=?uo=Tml*tMz#;pKW@m(T9UR$HQ|btrNbD zr^qDQ^m6d$rR^Guj(opSU#FrPPT_%sO+%)?W46Fb(21>&$~@?R)4Tl)o2b=$^@*h8BD0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz097#k$R9Fe^mrF=hQ51%~8a+&V zU_lTOWDrQu1A0ggjDiLY8&$J{D1@RA8Z@gQa1!P$Dj^5iW8$!ej!LvZB7%}0BcY;@ zw5OiF|G4(`c)927bFcSA0~h?Rwb%OBT6^!a&%Vd1syV6f4g^845nKih6)s&~IVREz zByHtYNY1KG4i}Bqo7d^0q;j3}Tp}wzjJ?~96ZCqE9VBN-0#Bg{(38vM20XlcI46t3 zi%_E=KSB8`B>hZiN7`E91W5SKq%M%OH)Wz8^<)88yQ_o#77STTJ9OLZf2UZ?HsGWs zv(9vA0$Y6z;PlvR27TPJ<21;Dui!Umjw?iLt#MGn(Kud3{4{u?F32D#dPU&x5CQoB zvUn+`*FuBsU=m19O-H6Ie4BuFP;$O7p2?U-H^X*8@EN_rHNma{0~ULMp6_CrY8tHs zU#xMjYsR?Ed=u!M&i_v|4UbuKsWYGvjA?*e_e}y$J-7sp__(R#6zc+#AK*=B1;KlC zov#R-N5+>rM3;U|khB0iup(0TL3kUZo52W>=yGf=oD{xi3L;&Kp;v)lav-Js z%#g4g^eNNi7P=PT#j&Gb0Qv7B{BD7Lj_cJVtp+cFlXi^oW3Dh6e=WFY z#10o{tOZD(JD)V;{h@d2Pg67&Ys2ldByI1BSYjjqZvzP5TJ%z&b0fI|Hb<}p+a2!C zNQrop1RdIkAnh0AjAG>J-=s96vsXJKIg0^Jq8F%dV#l+XL%t^6wYyICVCeA`!(Aiw z=aaKAXwq$so+j0Y6P>vCGdZbNY>XxiKtH|`@1uY-6f%S0Mr_g91So#m8t7ZxdsyML z8eg}5c;SYx>1-xZkUPRS0PXy*rypaVbVC>h%F9Mr>B3SfYiHcQFAw&{ Uw6HT#7XSbN07*qoM6N<$g1iEg%m4rY literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_voice.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_voice.png new file mode 100644 index 0000000000000000000000000000000000000000..2818c4f3fcfb97e533fdb7599fcf2b9ea2eaa852 GIT binary patch literal 1128 zcmV-u1eg1XP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0(n&-?R9Fe^mRU#^Q51mv)v#=_ z#i%Hx1u8O?urjbBd}&dn2z<#lqo9Z$+K`B#jUXb7dI+i)Uy6tb3TYJ|3X;eIU!o{1 zGLW(j4Ks53&UlaBhM94cAtE~P{pZZt?#%t~%)LoT|0U)ba2zKGwnJvjt^3!G8_0%- zpmNOHfj|lDf)sDez9zm2TA&t2+ObGBMMdx#R32mGdW-QrHwkCGF})_90pCoXsKXkI zq$wB;tx}1+f(1c^#404o$UeV3Vlq3nNY8{{uCI^eQ>OYodYo^P|`&({oc|lHK%lMrz2A08f2o{RwnI{mH9-P@5A#W-CkOJhKMzHf-kK=S1 z?Nyf~x33w}evvdI%pviL>05)|Y8A>l5orWjV=5CdRzNBBezUE4?tk2`8KU76^VpBj zLwh^9yemeUcj@-hYYI&E%fX)l3n6@hNQmu*{BFe07k)>~s9#Z#j|Y&=^*-bU<@Dw6xgnY) z;2hX{P>0oEgk=Yrdk7T5N==~Obhrjf)E7xpFbhO}f@}-&C6$d;MPAK7AxYkrHj}(X z6S+Qae3#W1rh8_Hq*jwCKKath8zB2qgV@NnZWZ{uj)=bM@}{X|8AJQ4KV0(^@`N4c zX;y1C*UODhRHgcDjejoadFi|-)+mLDy%g+}V4I>Ex72Z}?JRt9R8YB#Q4YCK3{{|8 zg?#*a)*ALyP?>M{jAT=}*;LDk&i&h@5IY^tK+rx!$f<`J_CQ>pmH_e=`t`=TeJC1Y zic!u*ySdo-il7#BMlhXcup53mM{_+J^Z>TQ+bi-lO*VqcPQOBesW2YW1LB#)UV_LA zaL+n^xsiM{sFqGf4xuAYH@P!G5BqJ{xse79OQJ~{+yWI@AM$qv-WW0YW*vog5D{G* zHjZB`YyepkC&B*zo4LLXuR*>mX)pog9JCnpeDwx<72mN2biBe-7C;?DkuN0e2j8_7 z<<0_U$Xm=H)9}e2l@Br_GvPbPSGft~EOd`qvG+e*e?Yjo4It7K_i*-J7I*If_4{XT u=&N~r)dQN1*os&?gW&)yimmD2+UOU8Gb%DDoJi3C0000bPN0}Blo^trZ(=qX&V-j!r!Q}!Oi*y3&^aZ>Ztz>4M$~ftU zt()61e~+3&J_{HhIn;1>bTYEG___o$nwSc9yjOgfZ;=zlDw6JW+0RNm!$Vw*yNv1R z4G(kPZoUPM$1mzwustbG4D{M1a6y4l;a_vgK~;t52_=&YUNA_B^`!ieRfuM45Bk*7 z$abzJ>Vt@f_M~(!xmX8h$8~kwM{ZS2nW)cdvO}O_qOsV|w%%7usyP@K?tZiVx83vH R17I*Pc)I$ztaD0e0sy)veW?Hd literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_boost_profile_badge2.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_boost_profile_badge2.png new file mode 100644 index 0000000000000000000000000000000000000000..dd35952dea6a9b77ffb39277efd9aacf5651a100 GIT binary patch literal 505 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEZNh=F~o!S z?G$|v7Dtg|`F{^f9$AoN@wUlvLnND0}_|ncN;8~KWD*beIfc+ z{|Od9hm8!23;5*?0G-r{7IDZ+v|V z@81tvr{wQo-sx@^GGpHRB4@|sewReN)^fq(a8(8U+H)mp7=mp88`f=K) zR6<$;c`s$G=3Cf5_t2|={1CaxuGy()8ja(>l}_=D6HF7n(4@Ehpv~vCAB1H@zf5!S3nm=d#Wzp$P!GCBT>f literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_boost_plus.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_boost_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..d5e7a5fdff9810f8f1a29116845a60c62619553b GIT binary patch literal 557 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`Uk5V~7Xu z-6^}hm>oshV&6Yn$|)vz(Md;jrAkw1mbYNe+BLeL#P&5W=#5yBu+pxfb?%DR){2)R z`YcLb*WULVC(iLTla6t;`B0d4e$MClJKyBFACKQ^z*Ak9n#;kyfiqRYYcJ=b*9z6` z_d=uc?IcUaQF}ieW1G%uMS4??{@*;a6OCThd0Yh ze={B_)xRyEzHXDworbnEgsUH&7*ZL*+*sn6s2 z2e#JAeNvmyAKWW5aZ=>jZe6D*jT`5GcUyD+NkqQ)zMngiH*^N`us!4|GMTP>^Q3%r z*@le1B++=L@8yZhviv?yx_{yRF8lTAwI??fTC~VsI6bjZNv65authlIe8g0}kTAx- zzQ30==r^npSU%$k-y6PD9I^%fc0DNRxypO}+K;WjD#NG#V7YU0_s4C=M9L3}>1+x8 cv3`<0qq2j$N_f$p{h+AwboFyt=akR{0BW+=VE_OC literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_info.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_info.png new file mode 100644 index 0000000000000000000000000000000000000000..935e1dda371e9c3c50b036760a6eadc1b7dc63c7 GIT binary patch literal 475 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%+=GyF~o!S z=v2czCPyCEaz(}1T_%~&SQb8Ko0HIgAoP%=(!~pf&370&&B_;e3I{RD;O>&s?%#HWMvWqIaTpt8P2k#JCWHBM@G*_R1@X;TC{S02E9(}_6 zd~W-^WTWk2rpa8vi+}L3J>z(xpQD@~zo?qAZ{{}}8yWW*ETM0#{(lKQm9||X>QzhK zG5seUc4wLk4o5!I{r#auW~Sz^-t!ZezIeI3!{z*=?iAfic{{h580t2PU0=Gi^Jbb4 zcT~!skp8~pTOkjgmrm4bymy~VQ|@1D|4-+q3z%1ieq?g*@T>^c5M912x-5*_b650r ub6gB0?HX9NS4ulICu49Q@9 zJJUNu#8IGa^FEJ|N7{_?E=LwLY0OCGbL`NV7$c(G#NqZ~k@>_94X&z>3eToAb8yM= zFbeX!DXC58XnOQ`(GLf~$BK3xNvNdK)mYeOq$#aACe^_XE>G}Jn#s{ zux|Oot?Ii*q^7v&m&v^K^CrD#2>h#f$K{QUN9&Uttjqc;R!%Oy`|+b(8$G7ODB(=`GlO>ejWNB!1 zgL9vXeT7^S_x#m{$28)&Ca-4utI&7isrBB9H=k^TQdS>$ZDD-+$(>W5Cs>x3um698 z*`Y%5q*I0K8$VT51Q*nYZW^fP1>g%_-+E%(1Al>FRa6G|M)h=bng!<=MQt84Ngt1 zeHnII=ziU`33claD9turX_j)0bG3xh>cq{e-St;qeiz$+>zU6kUd8XXyAE3x@JDRg z@{V6A^Rcj2W&YO*uL?WbcB;=k`BvrSbk8Zev1`wIw(zbrQs_Rmf63WNsv8A+X7JtL zXnu3fksAWp1}=xsc$+MnVo)YKK|Ds(vfEe6e@Y9ro@bGNXbk9{Nc;pWNB>-{=s z&$n6dv{F=UuL;|H#SP(2-~E!jKc%HeIF@a6j=0M%v8i5GIH&UHtIG*)^Dk8-nYzrD zz4XYAd8(JxZYCSnuya{97p0E9oo4z?dP9h3^7Q842fF^8p7L3`w=Xh;H*mM@?}q)S zgbw60hwUm*`}5gVakcrJnG^Q(ns0brpQqlD+g~bOFKuZ*XU>ydb9z-DaQt|EMl<== tQ|T9$3jLE3E?(SmeIFAl{2$BukKukfx6Uhj;isT1?CI*~vd$@?2>{t2*7g7Z literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_edit_appearance.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_edit_appearance.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe520dea04bc36223fe80d52be51a5f102a43a3 GIT binary patch literal 815 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfoZ0vi(`lf z@71Yi^L+v(+MjQ8somyD?NbhoNq5VAY9e&>usQa^YX2S}RDh4xl;GM+f( zcFbP6ob^A$4)c31POpkOC2I`aPFwTbQn32y_v7yZ_Fe25`uiDlPxEG!wF=39$-EOg z;ZEM6tjhJ;jq9E*Q;6Vvc(tH^hu(F8#{v6Ug0`QEm^=Nr*MjVTP=lT&>l!{Qd~M@B zGIaxQ-=WkARgU59e7CGGXqB`)=BkkjJCI(H;rhp_f@|SEA(IBaMe8`XaCTO#+yW&PLu_QLyG<(xv{ z4SXS$!pCi=9kf1JB9XrC*9Ptfi}dGoNJp3Td48F&WxmhyQl66g9=jT~C#z}yT)zIG q&m!r~yxSV`P6WP4znh;V{8e0oPq@ZF*nc%Bv3k1txvX<+HFO}IF@F95okWp)S)qH#eRhq%X&{SIkG#MW?qU{;LE+RW(CI*wMds{ z4VkNJG6cRjNwJu{Xbka4eev?QUv>Ps*Oy8KbbrKT|GjqW_nh75@7> zSR}Ysd{h67^(!M!XCKRuHQ>D4D|J#~hbZ^%)*AZ^ap|*)0jIUTJju?eE65F~b=9cq zxL1&2*J`tCt>O*2);axAZ%%rh`8d;oP2`dP_m*>7Q{FKCREg1hx$N-=!8e+>wOe|- zJ~I9jTHnz0(JWrjPvppifZ1wOtbTXy$WYX~$evVxbW`uvxJcs@JMXPN&TgZ4&$D=W zl1b6~dDNCEA=W8}M*z?~~z9GJ)<%fa| zYp%&`l|PE#-xZy%<__;YR4dUZn)H4~{(?%`KPMKM%so86r?%=-*@q4HPQ31&;iP`% zaES9C;{x4VniA~#2OnRU_}-Aubp7mqPP~Z>HO1=vX5J4j#s_EQO}bz%!ZvT^mVghd zB-&P9crwZ7z(lWN&jrU*KZa)tFD)`%deZ#7)JNL_pZIq?ruHkc-)#!HKgaRof~Uu; zjUKKc1Vahl zw#QvY3e9`wp8vjUdG)*c^LxKcc@jRq?*IMU-+$WY*Ux{yURSJptHX!u-x`0YzNy;V z5Z}yU^5~Xv$CU~Hm!zLqDyJ;IP3QH&rPF*2_prw0TCJS2Z_^Z~$nv21aek*mCR?`K z&S1Xl*kV25{P`UbvOem1vy5Ew-K#hy19Saw%SfM#fEb`Z%zwyO#(`Q~c@pELaE4F)Q`Fx-CcV+F@_1*7( zPc3*dznrv@~GMzQDk)E4W)?+QYrl*De03 zc&O>v2Ti^pvgGH#pDS37t$L_!(^`AVaXzc(cm1c~u2vE5$RF2GUaXZU> z?e@I3nQISlJ&vj_Zqon%;)r~*z0rKbs^6tQ{>@WgP|^NqzQE+Q%U+0IyR+r!mdM6{ z3mmt6PKw=VV`KcS_}pOIxu2>>KdgSR=*@jD&RsS_y56o{xqDCN8DaOq9o(k-5PjhPq3w>$eKF>YM^K}O}Tz|T7>*IMmZSr>!{EqdC2 zK*5G_ZNT>j(sx?-n)0U~T<}AtmB1wv!0%w^Nl8n z3??3|9f=PlCoFV{5TC@gpiO7RyX_89?4Df~Y5|wo6xdjouohZf2w^n6$DAZ?lK5z+ i!`Tf7l;bWptYBdfI?>-C_E$m~kDVQ^ggaui;IWW(A2o z|M)8&8oj$=(7|3;QTBaq^X|US-pA;u?olQ6V>`nnO<+G z^jN_XD=x)ftTVxE^R;;a@Nn?}Jb&)qwMkquud^EbK;HFq^>bP0l+XkK>bZZ4 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_boost_plus.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_boost_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..2ee37f89e610927740424874ac3d82590454e443 GIT binary patch literal 987 zcmV<110?*3P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFMM*?KRA>e5m`P|9Q4oe_5;YiH z4hgu%4Hr;R5rT>=7)8_ z6w))mOCa(IOv_CZkd>Vu1X?wpam7l9GY)S@q`y9OZI z2Hsf+Yx8d|G8x^(n*yO$@LaQu&|fDmWVkW)PC&GoytlzdLw=LV>j6&P01U5zE)!FW z&1(ae8g6EG|4hWF*jxwPvS%CxyQ4OSG4?e+sU;dA2+GLF=p+%ZpV78ArIi@uH{l!v zQ>{VKj`z6bQ{smqY#7@>u~;k_eCbV)Uje>=EMqBzl8>pK5A#uP9wxqLH?UCn?m!Xm_c@6y9(l-YT?+NCbkEN$P?!j zHB3*XazNA%rv@Ye1-`QgOfp1+hjDB+IhAcB&=)J4)|J^!b$$vtq-%GG@gCx(0d`+r zYD>Mdb4ci=0qU#<@>w0q1j=Qw3N$l*q1+1te67xBAf{mD2ii#(Ux>Mq}-vIOhm(Xqy{tf*M{gN1!jHACG$EdPpqe8OF zFe0C^ZM9XzcURqW#}?;e_c20xe8QUZQRG}42@P4TJ{nkSA$Oe-xM}fuGy7=3^c#2p z!xP?EMkGqr03*^$?qwDEUvYhq-Is%C6aD4+(-xGuod(vc!zk(pAfMflLX7+edpLk? z1S4~JaYCR2`~@Q4z)CNPYncSn+re3|yq0wvwHiCn*n$5$@DE(QMgPb%s(Szc002ov JPDHLkV1hREmInX; literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_info.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_info.png new file mode 100644 index 0000000000000000000000000000000000000000..0cc1157af642cbd8e983562404284f0dfadca97f GIT binary patch literal 1032 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 Z{TE82uE(|9LEHcU002ovPDHLkV1km|!GZt) literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_boost_profile_badge.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_boost_profile_badge.png new file mode 100644 index 0000000000000000000000000000000000000000..1b432add714d428062421df363f5fd4a186fac4e GIT binary patch literal 494 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZp5{7UAjQ7!twx zcFJBaW=DbJ?_C7#1vYvt5|e`NLTk^Ef4}0nG`^l?I6L_d+t#|qn4)i*=iGlRubj8PWADe<2b)){-=!1adLq@McjJO5jH8DDoX zz56&l_ryG=f(P6cX}L2F$?~jt{fjqu#^GAV?gQd#OzRhZWmz@j0RQc#?;eq_BkzO4 N+SAp~Wt~$(699GCw`>3a literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_boost_profile_badge2.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_boost_profile_badge2.png new file mode 100644 index 0000000000000000000000000000000000000000..77a74d06fa2799c6630f7d190c2858ce70e243de GIT binary patch literal 696 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZv>fz@+5q;usRa z`F860Y~etG^D}>azFJ4-~L5vAsF_2mhB_!M59%-?RCm#5HfvYsdUs z3R9;vw8n{Wb2+gd%<7)*6upYw)$?)sqcuL0VmF=4<7<@tVet9c-kI-j$LGtcZ+yb{ z<+tpLt69zk$Ku!@Pc}#>w(S($$!GtdS>3^gasPrRPpcjYY8=q(nCi+>&zj<#w9stA ztF&?x`GtNi{aJq}{mQHfdo2FyacKwtVe<`P0-{3kKARry?MM|jvFCm5=5k24;9(Qb zm3!@?JbyVdYPyz*o-j9Ezhhmra{1vW&iDUq(d6P0v_H1Q=6SbW_nznb&)$hGc)0QW zu6IEl&mZuz+`ReD>i_CVciE)6B-P@b3=1Ycwn@!9ekQ#0{pSd~V0-U5*LNE2OqbeT zE+XGzRFW0Sb^>{;&IH>Rws@z@~LNZ_%&6 zZ3?pk3xCG!f3+yJ#^yh()Xn_Z-~Y=$Yt_v;Gb=6p~Un=zU_Ibz3LtO4yulV2fkzb|pZ%g6*M;4Pz>UFhls85ieEMrnU z>A=4OXDv#YsudK%_i{ep<9g&1--$%ymrtvn37$NZsD0oEN6)PoA@%YF@82DW|6KFT UKix)i2PoBey85}Sb4q9e02~M+P5=M^ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_boost_plus.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_boost_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9ad819a21cb451cdc6fac0e997dbd37830e995 GIT binary patch literal 1352 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_edit_appearance.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_edit_appearance.png new file mode 100644 index 0000000000000000000000000000000000000000..e7167bae3700dffefc4573a388dad9dc17c383ba GIT binary patch literal 2554 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS^WJyFpRCodHoOg^DMHI(55yb*l zh$Wywu!1dOi>Sd8Ypf{t*fl7zV)?_8sF>IiNo;^!gC@p;vG;D&hzf@&U_r2fVu=OO z^YcCTr+c$+W@mr5`#a9uOFr4%H}Ac9Gr#@K%+CJqx^?T4t{&*>fvz6t>Vd8v=&U`^ z)RBp|w6rWu{e59|=#w0EzB2p>-@yWy-qh6e8OMf8Lpz8LS)LYd3p>G%unjB+F`~|T z7hZ!$;Vn9?g=6OybqbsaufQTGOTHq|1lXZd_7I5=fUDsV)u1124l6>ee2?K+xQ=mZ zaja8ic681#m<};A6QkSUSQr?S6n0C2?#z=wcjqq0Mu1>~SXeGK^Srq?NpUBSnvLC}d{iM~=J<0EzJ zhJ9Z+0yIWdGSd)u7nl#0oL(f~Tw7{5#i|9}4=_A8K*|97y}(^ztMg00`-r&-EC5%= zrBZ6&DUr7YYnJ#0{Z>VyW3M~M?Hp9CGO9?dSX&}*2U=>RWsg|@pdAr=fTn9pjtV*( zg#^*p$|o-wE^SmeZVj42^;ppiV<2~pgN^(igO}mRHbL8SL9o-nlDckD0%^?g$<$D; zIH{3;7|u6^{34}*Gc=BaLcW!hk%Sg|uKbB& zllD}Izcm|vgMQ6WT*@^e_~g)#Z|P-Z(HDL)vbnXrl@U|VaHHTQmiyo;%p<6U(sp%p+kha#~3+DH4Tbvu|(&uO>>`&Fbc-8zcRcMDhaOLTYp`*Y-9s60zQJYnl zIc5#Hq~1Z`+Xp($mjpidLL150QmQRWSEghP4Fyhm%{&|qhW>_0U*-MUNp_!D(z0ZB&Q_BHV5rRuOG^c^3~vlHeUZ-O!E3-^T>a8 znKSL(TnS6UW5nL%VZGk@4gD~011X?jGk6s_Nws?K=JO!&-zJ+uI(Mna@u^&Q6 zE-n-}(wGWw_f$FseJ?8v`oZuC_~d2^{QEyv&=?&-cL(3f^+(E9h>7Fc;MX0tfPLVY z^Iu-D^*7&CxA8R9aN+uVr&Xpuxb4gD{B0vRz2vo z7i8t7*jo7RZuwQBqq197t0QA#D#J%FDCO^Kj1%_XOHId_MxxVT?E5Op`6JjMCO30H zi*ZcbP?-i~YdN3$y~bC+_?iqu(lH~?=VCW4ZA(1;X~ToCeOjM7*WQ-ig6Nm9)e8v? zftSIO{X-expy_(LpT1G{hHphboI!lyj-V^jg zmSdvR!t)lm0w%yr@W~_!_5W&2T}O~ zd~TPcBkOW~xT7;KlUsjhqwq^Z7gAYwbJXjpP*At5PzNQ>=W?9w2I4w57M-KNS)B-j z9sk8#f8glyE(aP0)?H%!+ylR2E2dnxF()i4UQiq&4WCHECgnIP%LD8R;=W4Id5qQ|^qQ*T#OHEW{x9_lfD?*lVNS6|JF4|D}Gq-crv=b|<$5#`W*$ z4k=PG_B~;m5$on6aXQ?V24voIJB^yl^>#%Q#piA(jxM$6H1~vx#&4KC32y{?Nc72h z6yy%T0Z~w>MI}A zNd7>QyaQVIY&;2T@u@}VEYNyrK4{@N0Cof4FH06tHk|d@s~kJ8&`Em5tNooas8l{k$Fzoq>lsZ?_*zkGM$^iCA?Vp^HiPh|96Ln*2EG~?5Nl@F Q=l}o!07*qoM6N<$f?y}ipa1{> literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_pack.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_pack.png new file mode 100644 index 0000000000000000000000000000000000000000..70ec3004cd5a2b0d2dee9a3b1bbcf91f304e5a9a GIT binary patch literal 2412 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_boost_profile_badge2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_boost_profile_badge2.png new file mode 100644 index 0000000000000000000000000000000000000000..58ebf6f49346bc9ec3aec3c5adafa6e5052b9e4e GIT binary patch literal 970 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?oH}Q0F49Q@9 zJL7D&h@-&K%@6paF_C>(ewsTPjhgRK#$Mkn`&ZSiU-sKK)$H1Q)uu$4Pz+zD##P;P9ByV`y1+#>OoSB6_y>V)3#zbx3! zTYurnq;sKKQ?JW~-xK-VeIRAQ>S5J@e%bI^><^1O#X9@O}KHX4$WA*9M{`|aC zYU)g~d9A-DN=}!K5RTBeKD#()UDC(L56TlJhpm{si?y4FMeJ1R+H9>&AB;YjZgAAT zQmYrYuI+?=Rk!7?Yd<$WJkQX5I+k5Zg=}A%MiJ$cnj6MJ1(Hz{Sl;p64@il4S?SMpb6bjj>Bxm>1vrbp7*Z0hv5x(UkD^K&jQ zJ8<#stfkK+W|=O_sfy}#IF(#>xa-Nzb)`$)ebzATw@EgV4K{xAY3cJ-6VjgSy5`y` zVU^^QsTE)JiP3VQlbEcne$T{&7n9Qctkxc9v{d>rpWnUz;mw=E&F9bXo-n?*l=X>q zkJ`$`*|AqTR<1nr#5QTW>ES*6C;Z!tp6u^meEU|0<+3O0Qx!WEg+D|e2>g)$=bfa{ i%pF%6A@Kh$=6Z&ce5z3~7hhchRemove User Unban Tap and hold on user to unban. + Do Not Restrict Boosters + Turn this on to always allow users who boosted your group to send messages and media. + Choose how many boosts a user must give to the group to bypass restrictions on sending messages. Invite via Link Dismiss admin Edit permissions @@ -904,6 +907,8 @@ transferred ownership to %1$s un1 changed the group sticker set un1 removed the group sticker set + un1 changed the group emoji pack + un1 removed the group emoji pack un1 made un2 the discussion group for this channel un1 removed the discussion group un2 un1 linked this group to un2 @@ -998,6 +1003,16 @@ un1 changed channel emoji status to %2$s (for %3$s) un1 changed channel wallpaper un1 removed channel wallpaper + un1 changed group color from %1$s to %2$s + un1 changed group emoji from %1$s to %2$s + un1 changed group color and icon from %1$s to %2$s + un1 changed group profile color and icon from %1$s to %2$s + un1 changed group emoji status from %1$s to %2$s + un1 changed group emoji status to %2$s + un1 changed group emoji status from %1$s to %2$s (for %3$s) + un1 changed group emoji status to %2$s (for %3$s) + un1 changed group wallpaper + un1 removed group wallpaper none New Broadcast List @@ -1050,15 +1065,22 @@ You can choose a sticker set that will be available to all group members when they are chatting in this group. CHOOSE STICKER SET Choose sticker set + Choose emoji pack stickerset You can create your own custom sticker sets using the @stickers bot. + You can create your own custom emoji packs using the @stickers bot. No such sticker set found Try again or choose from the list below Set as Group Sticker Set Remove Group Sticker Set + Set as Group Emoji Pack + Remove Group Emoji Pack No results found for \"%1$s\" My sticker sets My emoji packs + Add emoji pack by link + All members will be able to use these emoji in the group, even if they don\'t have Telegram Premium. + emojiset invisible support @@ -1835,6 +1857,7 @@ %1$s is available. None An error occurred. + None Stickers Settings @@ -2197,6 +2220,7 @@ Change Chat Background Change Your Color Appearance + Appearance & Emoji Chat Background Reset Chat Backgrounds Remove all uploaded chat backgrounds and restore the pre-installed ones. @@ -5555,6 +5579,8 @@ Reset Theme No Theme No Wallpaper + Wallpaper updated + Group emoji pack updated You changed the chat theme to %1$s %1$s changed the chat theme to %2$s %1$s changed the channel theme to %2$s @@ -5761,6 +5787,7 @@ Available reactions I hope you\'re enjoying your day as much as I am. Dino + Monika Quick Reactions Double tap this message for a quck reaction. un1 changed chat reactions \nfrom: %1$s \nto: %2$s @@ -6008,6 +6035,7 @@ This link allows you or **anyone you choose** to activate a %1$s. **Telegram Premium** subscription What\'s included + Send gifts **to your friends!** 🎄 Gift Telegram Premium Let **%1$s** enjoy exclusive features of Telegram with **Telegram Premium**. Telegram Premium @@ -6729,6 +6757,8 @@ Setting new wallpaper... You set a new wallpaper for this chat Channel set a new wallpaper + Group set a new wallpaper + %s set a new wallpaper You set the same wallpaper for the chat %s set a new wallpaper for this chat %s set a new wallpaper for this chat @@ -6871,6 +6901,7 @@ Get Premium back with up to **%1$d%%** off Your Telegram Premium has recently expired. Tap here to extend it. Reply privately... + Comment story... My Story %d Stories %d Story @@ -6924,6 +6955,7 @@ Archive Only you can see archived stories unless you choose to save them to your profile. Only admins can see archived stories unless you choose to post them to channel profile. + Only admins of the group can see archived stories unless they are posted to the group page. %d archived stories %d archived story %d archived stories @@ -7185,6 +7217,10 @@ 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 hours. Privacy settings will apply. Post to Channel Page + Post to Group Page + Keep this story on the group page even after it expires in %d hours. + Keep this story on the group page even after it expires in %d hour. + Keep this story on the group page even after it expires in %d hours. Keep this story on the channel page even after it expires in %d hours. Keep this story on the channel page even after it expires in %d hour. Keep this story on the channel page even after it expires in %d hours. @@ -7374,6 +7410,7 @@ Audio Photo Send reaction as a private message + Send reaction as a message Remove Audio Remove Video Publish story as @@ -7397,8 +7434,15 @@ Boosts Level %d Level + Boost this group to send messages Enable Stories - Boost your channel by gifting your subscribers\nTelegram Premium. + The group has **%d** boost. + The group has **%d** boosts. + What are boosts? + Every **Telegram Premium** subscriber can boost your group **%d** time and help you unlock more features by using this link: + Every **Telegram Premium** subscriber can boost your group **%d** times and help you unlock more features by using this link: + Boost your channel by gifting your subscribers\n**Telegram Premium**. + Boost your group by gifting your members\n**Telegram Premium**. Get boosts > You can review the list of features and terms of use for Telegram Premium **here**. You are participating in this giveaway. @@ -7416,6 +7460,7 @@ Open Gift Link Save Recipients %s just started a giveaway of Telegram Premium subscriptions to its followers. + %s just started a giveaway of Telegram Premium subscriptions to its members. Delete announcement Deleting this message won\'t cancel the giveaway - the winners will still be selected on **%s**.\n\nOnce deleted, the Giveaway Announcement cannot be restored. %d winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes. @@ -7423,6 +7468,16 @@ %d winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes. %d undistributed link codes were forwarded to channel administrators. %d undistributed links codes were forwarded to channel administrators. + %d undistributed link codes were forwarded to group administrators. + %d undistributed links codes were forwarded to group administrators. + %s boosted the group + %2$s boosted the group %1$d times + %s boosted the channel + %2$s boosted the channel %1$d times + You boosted the group + You boosted the group %1$d times + You boosted the channel + You boosted the channel %1$d times %d boost %d boost %d boosts @@ -7442,10 +7497,16 @@ Get Boosts via Gifts Use Link Share this link with your subsсribers to get more boosts. + Share this link with your members to get more boosts. Get more boosts for your channel by gifting Premium to your subscribers. + Get more boosts for your group by gifting Premium to your subscribers. Start Giveaway + Boosts for Groups + Boosts for Channels + Members of your group can **boost** it so that it **levels up** and gets **exclusive features**. + Subscribers of your channel can **boost** it so that it **levels up** and gets **exclusive features**. Select a giveaway you already paid for to set it up. - Add Channel + Add Group or Channel Create Giveaway Show %1$d More Gifted Boosts Show %1$d More Gifted Boosts @@ -7477,6 +7538,7 @@ Giveaway Giveaway results Channel started a giveaway + Group started a giveaway The recipient will be selected when the giveaway ends. Incomplete Giveaway No recipient @@ -7489,11 +7551,17 @@ this channel will receive %d boosts this channel will receive %d boosts this channel will receive %d boosts + this group will receive %d boost + this group will receive %d boosts + this group will receive %d boosts + this group will receive %d boosts + this group will receive %d boosts Date and Time Boosts via Gifts Used Gift Link Gift Link Get more boosts for your channel by gifting Premium to your subscribers. + Get more boosts for your group by gifting Premium to your members. This link was used to activate\na **Telegram Premium** subscription. This link allows you to activate\na **Telegram Premium** subscription. This link allows **%1$s** to activate a **Telegram Premium** subscription. @@ -7501,12 +7569,15 @@ This link hasn\'t been activated yet. All subscribers Only new subscribers + All members + Only new members Select Date and Time Confirm From To Gift You were selected by the channel + You were selected by the group Reason Date Prepaid giveaways @@ -7532,18 +7603,23 @@ This link was used on %s. Quantity of prizes Choose how many Premium subscriptions to give away and boosts to receive. - Channels included in the giveaway - Choose the channels the users need to join to take part in the giveaway. + Groups and channels included + Choose groups and channels the users need to join to take part in the giveaway. Users eligible for the giveaway Choose if you want to limit the giveaway only to those who joined the channel after the giveaway started or to users from specific countries. + Choose if you want to limit the giveaway only to those who joined the group after the giveaway started or to users from specific countries. Date when giveaway ends Choose when %d subscriber of your channel will be randomly selected to receive Telegram Premium. Choose when %d subscribers of your channel will be randomly selected to receive Telegram Premium. Choose when %d subscribers of your channel will be randomly selected to receive Telegram Premium. Choose when %d subscribers of your channel will be randomly selected to receive Telegram Premium. Choose when %d subscribers of your channel will be randomly selected to receive Telegram Premium. + Choose when %d members of your group will be randomly selected to receive Telegram Premium. + Choose when %d members of your group will be randomly selected to receive Telegram Premium. Check your channels’ **Statistics** to see how this giveaway boosted your channel. Check your channels’ **Statistics** to see how gifts boosted your channel. + Check your groups’ **Statistics** to see how this giveaway boosted your group. + Check your groups’ **Statistics** to see how gifts boosted your group. Giveaway created Gift link forwarded to **%1$s**. Gift link forwarded to **Saved Messages**. @@ -7562,6 +7638,8 @@ This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. + This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscription for %4$s for its members. + This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its members. **%2$s** also included **%1$d** **%3$s** in the prizes. Admins of the channel are responsible for delivering these prizes. **%2$s** also included **%1$d** **%3$s** in the prizes. Admins of the channel are responsible for delivering these prizes. On **%2$s**, Telegram will automatically select **%3$s** random user that joined **%4$s**. @@ -7609,6 +7687,8 @@ This giveaway was sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. This giveaway was sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. This giveaway was sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. + This giveaway was sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscription for %4$s for its members. + This giveaway was sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its members. On **%2$s**, Telegram automatically selected **%3$s** random user that joined **%4$s**. On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s**. On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s**. @@ -7622,7 +7702,9 @@ Reduce Quantity Giveaway ended Channel is Private + Group is Private Are you sure you want to add a private channel? Users won\'t be able to join it without an invite link. + Are you sure you want to add a private group? Users won\'t be able to join it without an invite link. You didn\'t win a prize in this giveaway. You won a prize in this giveaway 🏆 View my prize @@ -7642,11 +7724,8 @@ You can’t purchase **%1$d** subscriptions in the app. Only **%2$s** available. You can’t purchase **%1$d** subscriptions in the app. Only **%2$s** available. You can’t purchase **%1$d** subscriptions in the app. Only **%2$s** available. - Select up to %1$d channel - Select up to %1$d channels - Select up to %1$d channels - Select up to %1$d channels - Select up to %1$d channels + Select up to %1$d group or channel + Select up to %1$d groups or channels Select up to %1$d country Select up to %1$d countries Select up to %1$d countries @@ -7669,15 +7748,13 @@ To take part in this giveaway please join channel **%1$s** before **%2$s**. You are not eligible to participate in this giveaway, because you joined this channel on **%1$s**, which is before the contest started. You are not eligible to participate in this giveaway, because you are an admin of participating channel (**%1$s**). + You are not eligible to participate in this giveaway, because you are an admin of participating group (**%1$s**). You are not eligible to participate in this giveaway, because your country is not included in the terms of the giveaway. Only the recipient can see the link. Only giveaway creator can see the link. You can select maximum 10 users. - You can select maximum %1$d channel. - You can select maximum %1$d channels. - You can select maximum %1$d channels. - You can select maximum %1$d channels. - You can select maximum %1$d channels. + You can select up to %1$d group or channel. + You can select up to %1$d groups or channels. You can select maximum %1$d country. You can select maximum %1$d countries. You can select maximum %1$d countries. @@ -7689,6 +7766,9 @@ Wait until the boost is available or get **%1$d** more boosts by gifting a **Telegram Premium** subscription. Wait until the boost is available or get **%1$d** more boosts by gifting a **Telegram Premium** subscription. Boost Again + Boost Group + Boost Channel + **Premium** users can boost your group with this link: Reassign Boost Start Giveaway Are you sure you want to start the giveaway now? @@ -7745,6 +7825,10 @@ All subscribers of the channels: New subscribers of the channel: New subscribers of the channels: + All members of the group: + All members of the groups: + New members of the group: + New members of the groups: with **%1$d** %2$s **%1$d** %2$s @@ -7767,21 +7851,35 @@ Manage Messages Manage Stories Premium subscribers + Premium members Existing Boosts Boosts to level up Your channel is currently boosted by these users. + Your group is currently boosted by these users. Boost Channel + Boost Group + Boost + Giveaway + Features Unlock Features BOOST Enable stories for the channel + Enable stories for the group Enable stories for channel + Additional Features + By gaining **boosts**, your group reaches higher levels and unlocks more features. + By gaining **boosts**, your channel reaches higher levels and unlocks more features. + Boost the group **%1$d** time to remove messaging restrictions. Your boosts will help **%2$s** to unlock new features. + Boost the group **%1$d** times to remove messaging restrictions. Your boosts will help **%2$s** to unlock new features. You are about to use a mini app operated by an independent party **not affiliated with Telegram**. You must agree to the Terms of Use of mini apps to continue. I agree to the **Terms of Use** Saved stories can be viewed by others on the channel’s profile until an admin removes them. You boosted the channel + You boosted the group You boosted %s! Premium needed! Only **Telegram Premium** subscribers can boost channels. Do you want subscribe to **Telegram Premium?** + Only **Telegram Premium** subscribers can boost groups. Do you want subscribe to **Telegram Premium?** Replace You currently boost **%1$s**. Do you want to boost **%2$s** instead? Can’t boost too often! @@ -7808,7 +7906,28 @@ Help upgrade channel This channel reached **Level 1** and can now post stories. This channel reached **Level %1$d** and can now post **%2$s** per day. + Your group needs to reach **Level %d** to change group color to selected.\n\nAsk your **Premium** members to boost your group with this link: + Your group needs to reach **Level %d** to change group profile color to selected.\n\nAsk your **Premium** members to boost your group with this link: + Your group needs to reach **Level %d** to change group link style icon.\n\nAsk your **Premium** members to boost your group with this link: + Your group needs to reach **Level %d** to change group profile icon.\n\nAsk your **Premium** members to boost your group with this link: + Your group needs to reach **Level %d** to set group emoji status.\n\nAsk your **Premium** members to boost your group with this link: + Your group needs to reach **Level %d** to set group emoji pack.\n\nAsk your **Premium** members to boost your group with this link: + Your group needs to reach **Level %d** to change group wallpaper.\n\nAsk your **Premium** members to boost your group with this link: + Your group needs to reach **Level %d** to change group wallpaper to custom photo.\n\nAsk your **Premium** members to boost your group with this link: + Your group needs %s to enable posting stories.\n\nAsk your **Premium** members to boost your group with this link: + Your group needs %1$s to be able post **%2$s** per day.\n\nAsk your Premium members to boost your group with this link: + This group need %s to enable stories. Help make it possible! + This group need %1$s to be able post **%2$s** per day. Help make it possible! + This group need %s more boosts to enable stories. + **%1$s** needs %2$s to unlock new features. + Help upgrade group + This group reached **Level 1** and can now post stories. + This group reached **Level %1$d** and can now post **%2$s** per day. + **%2$s** boosted the group **%1$d** time. + **%2$s** boosted the group **%1$d** times. + Boost **%1$s** to help it unlock new features and get a booster **badge** for your messages. No users currently boost your channel + No users currently boost your group Can’t boost with gifted Premium! Because your **Telegram Premium** subscription was gifted to you, you can’t use it boost channels. Maximum Level Reached @@ -7828,6 +7947,7 @@ Unlock Colors Unlock Profile Colors Unlock Emoji Status + Unlock Group Emoji Pack Unlock Wallpaper Unlock Link Icons Unlock Profile Icons @@ -7925,6 +8045,7 @@ You have changed appearance settings. Apply changes? OPEN Your name color has been updated! + Group appearance has been updated Channel appearance has been updated Your channel color has been updated! Your profile color has been updated! @@ -7969,28 +8090,46 @@ %d Custom Reaction %d Custom Reactions %d Channel Name Colors + %d Group Name Colors %d Styles for Links and Quotes %d Styles for Links and Quotes Custom Logo for Links and Quotes %d Colors for Channel Cover + %d Colors for Group Cover Custom Logo for Channel Cover + Custom Logo for Group Cover %s Emoji Statuses %d Channel Background %d Channel Backgrounds + %d Group Background + %d Group Backgrounds Custom Channel Background + Custom Group Background + Custom Emoji Pack + Real-Time Translations + Voice-to-Text Conversion Level %d Unlocks: Level %1$d Required Reply Logo Choose a color for the name of your channel, the links it sends, and replies to its messages. Profile Logo Choose a color and a logo for the channel\'s profile. + Choose a color and a logo for the group\'s profile. + Group Emoji Pack + Group Emoji + Choose an emoji pack that will be available to all members within the group. Channel Emoji Status + Group Emoji Status Choose a status that will be shown next to the channel\'s name. + Choose a status that will be shown next to the group\'s name. Channel Wallpaper + Group Wallpaper Choose from Gallery Remove Wallpaper Upload your own background image for the channel. + Upload your own background image for the group. Set a wallpaper that will be visible for everyone reading your channel. + Set a wallpaper that will be visible for everyone reading your group. Read More Message reposted to your profile. Message reposted to **%s**. @@ -8029,6 +8168,7 @@ Close Video Message Are you sure you want to stop listening and delete video message? My Notes + All members of the group can use the %s pack. Tap to view your **Saved Messages** organized by type or source. Senders of these messages restricted to link their name when forwarding. Hide Read Time @@ -8095,6 +8235,7 @@ Messages tagged with View Replies restricted + Comments restricted Unlock You need a **Premium** Subscription to reply to **%s**’s stories. Unable to send diff --git a/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java index 3903d7a19..b0a033059 100644 --- a/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java +++ b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java @@ -1,5 +1,7 @@ package org.telegram.messenger; +import static org.telegram.ui.PremiumPreviewFragment.applyNewSpan; + import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -9,15 +11,26 @@ import android.view.ViewGroup; import androidx.core.content.FileProvider; +import org.json.JSONObject; import org.telegram.messenger.web.BuildConfig; +import org.telegram.messenger.web.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TL_smsjobs; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Adapters.DrawerLayoutAdapter; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.UpdateAppAlertDialog; import org.telegram.ui.Components.UpdateLayout; import org.telegram.ui.IUpdateLayout; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.SMSStatsActivity; +import org.telegram.ui.SMSSubscribeSheet; import java.io.File; +import java.util.ArrayList; public class ApplicationLoaderImpl extends ApplicationLoader { @Override @@ -98,4 +111,125 @@ public class ApplicationLoaderImpl extends ApplicationLoader { public IUpdateLayout takeUpdateLayout(Activity activity, ViewGroup sideMenu, ViewGroup sideMenuContainer) { return new UpdateLayout(activity, sideMenu, sideMenuContainer); } + + @Override + public TLRPC.Update parseTLUpdate(int constructor) { + if (constructor == TL_smsjobs.TL_updateSmsJob.constructor) { + return new TL_smsjobs.TL_updateSmsJob(); + } + return super.parseTLUpdate(constructor); + } + + @Override + public void processUpdate(int currentAccount, TLRPC.Update update) { + if (update instanceof TL_smsjobs.TL_updateSmsJob) { + SMSJobController.getInstance(currentAccount).processJobUpdate(((TL_smsjobs.TL_updateSmsJob) update).job_id); + } + } + + @Override + public boolean extendDrawer(ArrayList items) { + if (SMSJobController.getInstance(UserConfig.selectedAccount).isAvailable()) { + CharSequence text = LocaleController.getString(R.string.SmsJobsMenu); + if (MessagesController.getGlobalMainSettings().getBoolean("newppsms", true)) { + text = applyNewSpan(text.toString()); + } + items.add(new DrawerLayoutAdapter.Item(93, text, R.drawable.left_sms).onClick(v -> { + MessagesController.getGlobalMainSettings().edit().putBoolean("newppsms", false).apply(); + SMSJobController controller = (SMSJobController) SMSJobController.getInstance(UserConfig.selectedAccount); + final int state = controller.currentState; + if (state == SMSJobController.STATE_NONE) { + SMSSubscribeSheet.show(LaunchActivity.instance, SMSJobController.getInstance(UserConfig.selectedAccount).isEligible, null, null); + return; + } else if (state == SMSJobController.STATE_NO_SIM) { + controller.checkSelectedSIMCard(); + if (controller.getSelectedSIM() == null) { + new AlertDialog.Builder(LaunchActivity.instance) + .setTitle(LocaleController.getString(R.string.SmsNoSimTitle)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.getString(R.string.SmsNoSimMessage))) + .setPositiveButton(LocaleController.getString(R.string.OK), null) + .show(); + return; + } + } else if (state == SMSJobController.STATE_ASKING_PERMISSION) { + SMSSubscribeSheet.requestSMSPermissions(LaunchActivity.instance, () -> { + controller.checkSelectedSIMCard(); + if (controller.getSelectedSIM() == null) { + controller.setState(SMSJobController.STATE_NO_SIM); + new AlertDialog.Builder(LaunchActivity.instance) + .setTitle(LocaleController.getString(R.string.SmsNoSimTitle)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.getString(R.string.SmsNoSimMessage))) + .setPositiveButton(LocaleController.getString(R.string.OK), null) + .show(); + return; + } + ConnectionsManager.getInstance(UserConfig.selectedAccount).sendRequest(new TL_smsjobs.TL_smsjobs_join(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + BulletinFactory.global().createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + controller.setState(SMSJobController.STATE_JOINED); + controller.loadStatus(true); + SMSSubscribeSheet.showSubscribed(LaunchActivity.instance, null); + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment != null) { + lastFragment.presentFragment(new SMSStatsActivity()); + } + } + })); + }, false); + return; + } + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment != null) { + lastFragment.presentFragment(new SMSStatsActivity()); + } + })); + } + return true; + } + + @Override + public boolean checkRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) { + if (SMSSubscribeSheet.checkSMSPermissions(requestCode, permissions, grantResults)) { + return true; + } + return super.checkRequestPermissionResult(requestCode, permissions, grantResults); + } + + @Override + public boolean onSuggestionFill(String suggestion, String[] output, boolean[] closeable) { + if ("PREMIUM_SMSJOBS".equals(suggestion) && SMSJobController.getInstance(UserConfig.selectedAccount).currentState != SMSJobController.STATE_JOINED) { + output[0] = LocaleController.getString(R.string.SmsJobsPremiumHintTitle); + output[1] = LocaleController.getString(R.string.SmsJobsPremiumHintMessage); + closeable[0] = true; + return true; + } + return super.onSuggestionFill(suggestion, output, closeable); + } + + @Override + public boolean onSuggestionClick(String suggestion) { + if ("PREMIUM_SMSJOBS".equals(suggestion)) { + SMSSubscribeSheet.show(LaunchActivity.instance, SMSJobController.getInstance(UserConfig.selectedAccount).isEligible, null, null); + return true; + } + return false; + } + + @Override + public boolean consumePush(int account, JSONObject json) { + try { + if (json != null && "SMSJOB".equals(json.getString("loc_key"))) { + JSONObject custom = json.getJSONObject("custom"); + String job_id = custom.getString("job_id"); + SMSJobController.getInstance(UserConfig.selectedAccount).processJobUpdate(job_id); + return true; + } + } catch (Exception e) { + FileLog.e(e); + } + return false; + } } diff --git a/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/SMSJobController.java b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/SMSJobController.java new file mode 100644 index 000000000..289b99691 --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/SMSJobController.java @@ -0,0 +1,725 @@ +package org.telegram.messenger; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Notification; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.telephony.CellInfo; +import android.telephony.SmsManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; + +import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.web.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.SerializedData; +import org.telegram.tgnet.TL_smsjobs; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.SMSSubscribeSheet; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +public class SMSJobController implements NotificationCenter.NotificationCenterDelegate { + + private static volatile SMSJobController[] Instance = new SMSJobController[UserConfig.MAX_ACCOUNT_COUNT]; + private static final Object[] lockObjects = new Object[UserConfig.MAX_ACCOUNT_COUNT]; + static { + for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; i++) { + lockObjects[i] = new Object(); + } + } + public static SMSJobController getInstance(int num) { + SMSJobController localInstance = Instance[num]; + if (localInstance == null) { + synchronized (lockObjects[num]) { + localInstance = Instance[num]; + if (localInstance == null) { + Instance[num] = localInstance = new SMSJobController(num); + } + } + } + return localInstance; + } + + public final static int STATE_NONE = 0; + public final static int STATE_ASKING_PERMISSION = 1; + public final static int STATE_NO_SIM = 2; + public final static int STATE_JOINED = 3; + + public final int currentAccount; + + public int currentState; + + public TL_smsjobs.TL_smsjobs_status currentStatus; + private boolean loadingStatus, loadedStatus; + public boolean atStatisticsPage; + + private boolean loadingIsEligible, loadedIsEligible; + public TL_smsjobs.TL_smsjobs_eligibleToJoin isEligible; + + public SIM selectedSimCard; + + public boolean isEligible() { + return isEligible != null || loadingIsEligible; + } + + private SharedPreferences journalPrefs; + + private SMSJobController(int account) { + this.currentAccount = account; + journalPrefs = ApplicationLoader.applicationContext.getSharedPreferences("smsjobs_journal_" + currentAccount, Context.MODE_PRIVATE); + loadCacheStatus(); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.newSuggestionsAvailable); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.newSuggestionsAvailable) { + if (currentState != STATE_NONE) { + checkIsEligible(true); + } + invalidateStatus(); + } + } + + public boolean isAvailable() { + if (currentState != STATE_NONE) { + checkIsEligible(false); + loadStatus(false); + } + return currentState != STATE_NONE && (isEligible != null || currentStatus != null); + } + + public void checkIsEligible(boolean force) { + if (loadedIsEligible && !force || loadingIsEligible) return; + loadingIsEligible = true; + ConnectionsManager.getInstance(currentAccount).sendRequest(new TL_smsjobs.TL_smsjobs_isEligibleToJoin(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + loadingIsEligible = false; + loadedIsEligible = true; + if (res instanceof TL_smsjobs.TL_smsjobs_eligibleToJoin) { + isEligible = (TL_smsjobs.TL_smsjobs_eligibleToJoin) res; + } else if (err != null && "NOT_ELIGIBLE".equals(err.text)) { + isEligible = null; + } else if (err != null && "ALREADY_JOINED".equals(err.text)) { + isEligible = null; + } else if (err != null) { + BulletinFactory.showError(err); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.smsJobStatusUpdate); + })); + } + + public void loadStatus(boolean force) { + if (loadingStatus || loadedStatus && !force) + return; + loadingStatus = true; + ConnectionsManager.getInstance(currentAccount).sendRequest(new TL_smsjobs.TL_smsjobs_getStatus(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + TL_smsjobs.TL_smsjobs_status lastStatus = currentStatus; + TL_smsjobs.TL_smsjobs_eligibleToJoin lastIsEligible = isEligible; + int lastState = currentState, state = currentState; + loadingStatus = false; + loadedStatus = true; + if (res instanceof TL_smsjobs.TL_smsjobs_status) { + state = STATE_JOINED; + currentStatus = (TL_smsjobs.TL_smsjobs_status) res; + saveCacheStatus(); + } else if (err != null && "NOT_JOINED".equals(err.text)) { + if (state == STATE_JOINED) { + state = STATE_NONE; + } + currentStatus = null; + saveCacheStatus(); + } else if (err != null && "NOT_ELIGIBLE".equals(err.text)) { + if (state == STATE_JOINED) { + state = STATE_NONE; + } + currentStatus = null; + isEligible = null; + saveCacheStatus(); + } else { + BulletinFactory.showError(err); + } + if (lastStatus != currentStatus || lastIsEligible != isEligible || lastState != state) { + setState(state); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.smsJobStatusUpdate); + } + })); + } + + public void invalidateStatus() { + loadedStatus = false; + if (atStatisticsPage) { + loadStatus(false); + } + } + + public void init() { + loadStatus(false); + checkSelectedSIMCard(); + } + + public void checkSelectedSIMCard() { + int selectedSimId = MessagesController.getMainSettings(currentAccount).getInt("smsjobs_sim", -1); + try { + ArrayList sims = getSIMs(); + if (sims.isEmpty()) { + selectedSimCard = null; + } else if (selectedSimId == -1) { + selectedSimCard = sims.get(0); + } else { + selectedSimCard = null; + for (int i = 0; i < sims.size(); ++i) { + if (sims.get(i).id == selectedSimId) { + selectedSimCard = sims.get(i); + break; + } + } + } + } catch (Exception e) { + FileLog.e(e); + selectedSimCard = null; + } + if (selectedSimCard != null && selectedSimCard.id != selectedSimId) { + MessagesController.getMainSettings(currentAccount).edit().putInt("smsjobs_sim", selectedSimCard.id).apply(); + } + if (currentState == STATE_NO_SIM && selectedSimCard != null) { + ConnectionsManager.getInstance(currentAccount).sendRequest(new TL_smsjobs.TL_smsjobs_join(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + BulletinFactory.global().createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + SMSJobController.getInstance(currentAccount).setState(SMSJobController.STATE_JOINED); + SMSJobController.getInstance(currentAccount).loadStatus(true); + SMSSubscribeSheet.showSubscribed(LaunchActivity.instance == null ? ApplicationLoader.applicationContext : LaunchActivity.instance, null); + } + })); + } + } + + public SIM getSelectedSIM() { + return selectedSimCard; + } + + public void setSelectedSIM(SIM sim) { + if (sim == null) return; + selectedSimCard = sim; + MessagesController.getMainSettings(currentAccount).edit().putInt("smsjobs_sim", selectedSimCard.id).apply(); + } + + public int simsCount() { + try { + return getSIMs().size(); + } catch (Exception e) { + + } + return 0; + } + + public ArrayList getSIMs() { + return getSIMs(ApplicationLoader.applicationContext); + } + + private void loadCacheStatus() { + currentState = MessagesController.getMainSettings(currentAccount).getInt("smsjobs_state", STATE_NONE); + String string = MessagesController.getMainSettings(currentAccount).getString("smsjobs_status", null); + if (string != null) { + try { + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(string)); + int constructor = serializedData.readInt32(true); + if (constructor == TL_smsjobs.TL_smsjobs_status.constructor) { + currentStatus = new TL_smsjobs.TL_smsjobs_status(); + currentStatus.readParams(serializedData, true); + } + } catch (Exception e) { + FileLog.e(e); + currentStatus = null; + } + } + readJournal(); + } + + public void setState(int state) { + MessagesController.getMainSettings(currentAccount).edit().putInt("smsjobs_state", this.currentState = state).apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.smsJobStatusUpdate); + if (currentState == STATE_JOINED) { + MessagesController.getInstance(currentAccount).removeSuggestion(0, "PREMIUM_SMSJOBS"); + } + } + + public int getState() { + return currentState; + } + + private void saveCacheStatus() { + SharedPreferences.Editor edit = MessagesController.getMainSettings(currentAccount).edit(); + if (currentStatus == null) { + edit.remove("smsjobs_status"); + } else { + SerializedData data = new SerializedData(currentStatus.getObjectSize()); + currentStatus.serializeToStream(data); + edit.putString("smsjobs_status", Utilities.bytesToHex(data.toByteArray())); + } + edit.apply(); + } + + private HashSet completedJobs = new HashSet<>(); + private HashSet loadingJobs = new HashSet<>(); + + public void processJobUpdate(String job_id) { + if (currentState != STATE_JOINED) { + FileLog.d("[smsjob] received update on sms job " + job_id + ", but we did not join!!! currentState=" + currentState); + return; + } + if (completedJobs.contains(job_id) || loadingJobs.contains(job_id)) return; + loadingJobs.add(job_id); + FileLog.d("[smsjob] received update on sms job " + job_id + ", fetching"); + TL_smsjobs.TL_smsjobs_getSmsJob req = new TL_smsjobs.TL_smsjobs_getSmsJob(); + req.job_id = job_id; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TL_smsjobs.TL_smsJob) { + runJob((TL_smsjobs.TL_smsJob) res); + } else { + FileLog.e("[smsjob] failed to fetch sms job by id " + job_id); + loadingJobs.remove(job_id); + } + })); + } + + private void runJob(TL_smsjobs.TL_smsJob job) { + checkSelectedSIMCard(); + final String phone_number = !job.phone_number.startsWith("+") ? "+" + job.phone_number : job.phone_number; + FileLog.d("[smsjob] running sms job " + job.job_id + (BuildVars.DEBUG_PRIVATE_VERSION ? ": " + job.text + " to " + phone_number : "") + ", selected sim: " + (selectedSimCard == null ? "null" : "{id=" + selectedSimCard.id + ", icc=" + selectedSimCard.iccId + ", name=" + selectedSimCard.name + ", slot=" + selectedSimCard.slot + "}")); + boolean[] finished = new boolean[1]; + sendSMS( + ApplicationLoader.applicationContext, + selectedSimCard, + phone_number, + job.text, + (success, reason) /* sent callback */ -> { + FileLog.d("[smsjob] sms job " + job.job_id + " sent callback: success=" + success + ", reason=" + reason); + if (!finished[0] && !success) { + finished[0] = true; + finishJob(job.job_id, phone_number, reason); + } + }, + (success, reason) /* delivered callback */ -> { + FileLog.d("[smsjob] sms job " + job.job_id + " delivered callback: success=" + success + ", reason=" + reason); + if (!finished[0]) { + finished[0] = true; + finishJob(job.job_id, phone_number, success ? null : reason); + } + } + ); + } + + private void finishJob(String job_id, String phone_number, String error) { + FileLog.d("[smsjob] finished sms job " + job_id + ", error=" + error); + TL_smsjobs.TL_smsjobs_finishJob req = new TL_smsjobs.TL_smsjobs_finishJob(); + req.job_id = job_id; + if (error != null) { + req.flags |= 1; + req.error = error; + } + completedJobs.add(job_id); + loadingJobs.remove(job_id); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TLRPC.TL_boolTrue) { + FileLog.d("[smsjob] finished sms job " + job_id + ", received true"); + } else if (res instanceof TLRPC.TL_boolFalse) { + FileLog.d("[smsjob] finished sms job " + job_id + ", received false"); + } else if (err != null) { + FileLog.d("[smsjob] finished sms job " + job_id + ", received error " + err.code + " " + err.text); + } + pushToJournal(job_id, phone_number, error); + invalidateStatus(); + })); + } + + + private static class PendingSMS { + public final int id; + public final Utilities.Callback2 whenSent; + public final Utilities.Callback2 whenDelivered; + public final boolean received[] = new boolean[2]; + public PendingSMS(int id, Utilities.Callback2 whenSent, Utilities.Callback2 whenDelivered) { + this.id = id; + this.whenSent = whenSent; + this.whenDelivered = whenDelivered; + } + } + + private static HashMap pending = new HashMap<>(); + + public static void receivedSMSIntent(Intent intent, final int resultCode) { + if (intent == null) return; + final int id = intent.getIntExtra("tg_sms_id", 0); + final boolean sent = intent.getBooleanExtra("sent", false); + final boolean delivered = intent.getBooleanExtra("delivered", false); + PendingSMS pending = SMSJobController.pending.get(id); + if (pending == null) { + FileLog.d("[smsjob] received sms callback with id " + id + ", "+ (sent ? "sent" : (delivered ? "delivered" : "null")) +": not found"); + return; + } + FileLog.d("[smsjob] received sms callback with id " + id + ", "+ (sent ? "sent" : (delivered ? "delivered" : "null"))); + boolean success = false; + String reason = null; + switch (resultCode) { + case Activity.RESULT_OK: + success = true; + break; + case SmsManager.RESULT_ERROR_NONE: reason = "RESULT_ERROR_NONE"; break; + case SmsManager.RESULT_ERROR_GENERIC_FAILURE: reason = "RESULT_ERROR_GENERIC_FAILURE"; break; + case SmsManager.RESULT_ERROR_RADIO_OFF: reason = "RESULT_ERROR_RADIO_OFF"; break; + case SmsManager.RESULT_ERROR_NULL_PDU: reason = "RESULT_ERROR_NULL_PDU"; break; + case SmsManager.RESULT_ERROR_NO_SERVICE: reason = "RESULT_ERROR_NO_SERVICE"; break; + case SmsManager.RESULT_ERROR_LIMIT_EXCEEDED: reason = "RESULT_ERROR_LIMIT_EXCEEDED"; break; + case SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE: reason = "RESULT_ERROR_FDN_CHECK_FAILURE"; break; + case SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED: reason = "RESULT_ERROR_SHORT_CODE_NOT_ALLOWED"; break; + case SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED: reason = "RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED"; break; + case SmsManager.RESULT_RADIO_NOT_AVAILABLE: reason = "RESULT_RADIO_NOT_AVAILABLE"; break; + case SmsManager.RESULT_NETWORK_REJECT: reason = "RESULT_NETWORK_REJECT"; break; + case SmsManager.RESULT_INVALID_ARGUMENTS: reason = "RESULT_INVALID_ARGUMENTS"; break; + case SmsManager.RESULT_INVALID_STATE: reason = "RESULT_INVALID_STATE"; break; + case SmsManager.RESULT_NO_MEMORY: reason = "RESULT_NO_MEMORY"; break; + case SmsManager.RESULT_INVALID_SMS_FORMAT: reason = "RESULT_INVALID_SMS_FORMAT"; break; + case SmsManager.RESULT_SYSTEM_ERROR: reason = "RESULT_SYSTEM_ERROR"; break; + case SmsManager.RESULT_MODEM_ERROR: reason = "RESULT_MODEM_ERROR"; break; + case SmsManager.RESULT_NETWORK_ERROR: reason = "RESULT_NETWORK_ERROR"; break; + case SmsManager.RESULT_ENCODING_ERROR: reason = "RESULT_ENCODING_ERROR"; break; + case SmsManager.RESULT_INVALID_SMSC_ADDRESS: reason = "RESULT_INVALID_SMSC_ADDRESS"; break; + case SmsManager.RESULT_OPERATION_NOT_ALLOWED: reason = "RESULT_OPERATION_NOT_ALLOWED"; break; + case SmsManager.RESULT_INTERNAL_ERROR: reason = "RESULT_INTERNAL_ERROR"; break; + case SmsManager.RESULT_NO_RESOURCES: reason = "RESULT_NO_RESOURCES"; break; + case SmsManager.RESULT_CANCELLED: reason = "RESULT_CANCELLED"; break; + case SmsManager.RESULT_REQUEST_NOT_SUPPORTED: reason = "RESULT_REQUEST_NOT_SUPPORTED"; break; + case SmsManager.RESULT_NO_BLUETOOTH_SERVICE: reason = "RESULT_NO_BLUETOOTH_SERVICE"; break; + case SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS: reason = "RESULT_INVALID_BLUETOOTH_ADDRESS"; break; + case SmsManager.RESULT_BLUETOOTH_DISCONNECTED: reason = "RESULT_BLUETOOTH_DISCONNECTED"; break; + case SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING: reason = "RESULT_UNEXPECTED_EVENT_STOP_SENDING"; break; + case SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY: reason = "RESULT_SMS_BLOCKED_DURING_EMERGENCY"; break; + case SmsManager.RESULT_SMS_SEND_RETRY_FAILED: reason = "RESULT_SMS_SEND_RETRY_FAILED"; break; + case SmsManager.RESULT_REMOTE_EXCEPTION: reason = "RESULT_REMOTE_EXCEPTION"; break; + case SmsManager.RESULT_NO_DEFAULT_SMS_APP: reason = "RESULT_NO_DEFAULT_SMS_APP"; break; + case SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE: reason = "RESULT_RIL_RADIO_NOT_AVAILABLE"; break; + case SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY: reason = "RESULT_RIL_SMS_SEND_FAIL_RETRY"; break; + case SmsManager.RESULT_RIL_NETWORK_REJECT: reason = "RESULT_RIL_NETWORK_REJECT"; break; + case SmsManager.RESULT_RIL_INVALID_STATE: reason = "RESULT_RIL_INVALID_STATE"; break; + case SmsManager.RESULT_RIL_INVALID_ARGUMENTS: reason = "RESULT_RIL_INVALID_ARGUMENTS"; break; + case SmsManager.RESULT_RIL_NO_MEMORY: reason = "RESULT_RIL_NO_MEMORY"; break; + case SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED: reason = "RESULT_RIL_REQUEST_RATE_LIMITED"; break; + case SmsManager.RESULT_RIL_INVALID_SMS_FORMAT: reason = "RESULT_RIL_INVALID_SMS_FORMAT"; break; + case SmsManager.RESULT_RIL_SYSTEM_ERR: reason = "RESULT_RIL_SYSTEM_ERR"; break; + case SmsManager.RESULT_RIL_ENCODING_ERR: reason = "RESULT_RIL_ENCODING_ERR"; break; + case SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS: reason = "RESULT_RIL_INVALID_SMSC_ADDRESS"; break; + case SmsManager.RESULT_RIL_MODEM_ERR: reason = "RESULT_RIL_MODEM_ERR"; break; + case SmsManager.RESULT_RIL_NETWORK_ERR: reason = "RESULT_RIL_NETWORK_ERR"; break; + case SmsManager.RESULT_RIL_INTERNAL_ERR: reason = "RESULT_RIL_INTERNAL_ERR"; break; + case SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED: reason = "RESULT_RIL_REQUEST_NOT_SUPPORTED"; break; + case SmsManager.RESULT_RIL_INVALID_MODEM_STATE: reason = "RESULT_RIL_INVALID_MODEM_STATE"; break; + case SmsManager.RESULT_RIL_NETWORK_NOT_READY: reason = "RESULT_RIL_NETWORK_NOT_READY"; break; + case SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED: reason = "RESULT_RIL_OPERATION_NOT_ALLOWED"; break; + case SmsManager.RESULT_RIL_NO_RESOURCES: reason = "RESULT_RIL_NO_RESOURCES"; break; + case SmsManager.RESULT_RIL_CANCELLED: reason = "RESULT_RIL_CANCELLED"; break; + case SmsManager.RESULT_RIL_SIM_ABSENT: reason = "RESULT_RIL_SIM_ABSENT"; break; + case SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED: reason = "RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED"; break; + case SmsManager.RESULT_RIL_ACCESS_BARRED: reason = "RESULT_RIL_ACCESS_BARRED"; break; + case SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL: reason = "RESULT_RIL_BLOCKED_DUE_TO_CALL"; break; + case SmsManager.RESULT_RIL_GENERIC_ERROR: reason = "RESULT_RIL_GENERIC_ERROR"; break; + case SmsManager.RESULT_RECEIVE_DISPATCH_FAILURE: reason = "RESULT_RECEIVE_DISPATCH_FAILURE"; break; + case SmsManager.RESULT_RECEIVE_INJECTED_NULL_PDU: reason = "RESULT_RECEIVE_INJECTED_NULL_PDU"; break; + case SmsManager.RESULT_RECEIVE_RUNTIME_EXCEPTION: reason = "RESULT_RECEIVE_RUNTIME_EXCEPTION"; break; + case SmsManager.RESULT_RECEIVE_NULL_MESSAGE_FROM_RIL: reason = "RESULT_RECEIVE_NULL_MESSAGE_FROM_RIL"; break; + case SmsManager.RESULT_RECEIVE_WHILE_ENCRYPTED: reason = "RESULT_RECEIVE_WHILE_ENCRYPTED"; break; + case SmsManager.RESULT_RECEIVE_SQL_EXCEPTION: reason = "RESULT_RECEIVE_SQL_EXCEPTION"; break; + case SmsManager.RESULT_RECEIVE_URI_EXCEPTION: reason = "RESULT_RECEIVE_URI_EXCEPTION"; break; + default: reason = "UNKNOWN_EXCEPTION_" + resultCode; break; + } + if (sent && !pending.received[0]) { + pending.whenSent.run(success, reason); + pending.received[0] = true; + } else if (delivered && !pending.received[1]) { + pending.whenDelivered.run(success, reason); + pending.received[1] = true; + } + if (pending.received[0] && pending.received[1]) { + SMSJobController.pending.remove(id); + } + } + + private static void sendSMS( + Context context, + SIM sim, + String phone, + String text, + final Utilities.Callback2 whenSent, + final Utilities.Callback2 whenDelivered + ) { + SmsManager smsManager; + if (sim != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + smsManager = SmsManager.getSmsManagerForSubscriptionId(sim.id); + } else { + smsManager = SmsManager.getDefault(); + } + final int ID = (int) (Math.random() * 1_000_000); + final Intent sentIntent = new Intent(context, SMSResultService.class); + sentIntent.putExtra("sent", true); + sentIntent.putExtra("tg_sms_id", ID); + final PendingIntent sentPI = PendingIntent.getBroadcast(context, 0, sentIntent, PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); + + final Intent deliveredIntent = new Intent(context, SMSResultService.class); + deliveredIntent.putExtra("delivered", true); + deliveredIntent.putExtra("tg_sms_id", ID); + final PendingIntent deliveredPI = PendingIntent.getBroadcast(context, 0, deliveredIntent, PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); + + pending.put(ID, new PendingSMS(ID, whenSent, whenDelivered)); + + FileLog.d("[smsjob] sending sms with id " + ID); + smsManager.sendTextMessage(phone, null, text, sentPI, deliveredPI); + } + + public static class SIM { + public final int id; + public final int slot; + public final String name; + public final String iccId; + + public final String country; + public final String carrier; + public final String phone_number; + public SIM(int id, int slot, String name, String country) { + this.id = id; + this.slot = slot; + this.name = name; + this.iccId = null; + this.country = country; + this.carrier = null; + this.phone_number = null; + } + + public SIM(int slot, String country) { + this.id = slot; + this.slot = slot; + this.name = "SIM" + (1 + slot); + this.iccId = null; + this.country = country; + this.carrier = null; + this.phone_number = null; + } + + public SIM(int id, int slot, String name, String iccId, String country, String carrier, String phoneNumber) { + this.id = id; + this.slot = slot; + this.name = name; + this.iccId = iccId; + this.country = country; + this.carrier = carrier; + this.phone_number = phoneNumber; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1) + @RequiresPermission(Manifest.permission.READ_PHONE_NUMBERS) + public static SIM from(SubscriptionManager subscriptionManager, SubscriptionInfo info) { + if (info == null) { + return null; + } + String phoneNumber; + if (android.os.Build.VERSION.SDK_INT >= 33) { + phoneNumber = subscriptionManager.getPhoneNumber(info.getSubscriptionId()); + } else { + phoneNumber = info.getNumber(); + } + return new SIM( + info.getSubscriptionId(), + info.getSimSlotIndex(), + info.getDisplayName() == null ? "" : info.getDisplayName().toString(), + info.getIccId(), + info.getCountryIso(), + info.getCarrierName() == null ? null : info.getCarrierName().toString(), + phoneNumber + ); + } + + @NonNull + @Override + public String toString() { + return (country != null ? "[" + country + "] " : "") + name + (carrier != null ? " (" + carrier + ")" : ""); + } + } + + private static ArrayList getSIMs(Context context) { + final ArrayList simInfoList = new ArrayList<>(); + if (android.os.Build.VERSION.SDK_INT >= 30) { + final SubscriptionManager subscriptionManager = SubscriptionManager.from(context); + final List infos = subscriptionManager.getCompleteActiveSubscriptionInfoList(); + if (infos != null) { + for (int i = 0; i < infos.size(); ++i) { + SIM sim = SIM.from(subscriptionManager, infos.get(i)); + if (sim != null) { + simInfoList.add(sim); + } + } + } + } else if (android.os.Build.VERSION.SDK_INT >= 26) { + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + for (int i = 0; i < 4; ++i) { + try { + if (telephonyManager.getSimState(i) == TelephonyManager.SIM_STATE_READY) { + String country = null; + SIM sim = new SIM(i, country); + simInfoList.add(sim); + } + } catch (Exception e) { + FileLog.e(e); + } + } + } + return simInfoList; + } + + public void leave() { + currentStatus = null; + setState(STATE_NONE); + clearJournal(); + ConnectionsManager.getInstance(currentAccount).sendRequest(new TL_smsjobs.TL_smsjobs_leave(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + BulletinFactory.global().createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + SMSJobController.getInstance(currentAccount).loadStatus(true); + SMSJobController.getInstance(currentAccount).checkIsEligible(true); + } + })); + } + + private int updateSettingsReqId; + public void toggleAllowInternational(boolean value) { + if (currentStatus == null) return; + if (updateSettingsReqId != 0) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(updateSettingsReqId, true); + } + if (currentStatus.allow_international == value) return; + TL_smsjobs.TL_smsjobs_updateSettings req = new TL_smsjobs.TL_smsjobs_updateSettings(); + req.allow_international = value; + final int[] reqId = new int[1]; + updateSettingsReqId = reqId[0] = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (reqId[0] != updateSettingsReqId) return; + updateSettingsReqId = 0; + if (currentStatus != null) { + currentStatus.allow_international = value; + } + })); + } + + public ArrayList journal = new ArrayList<>(); + + private void readJournal() { + journal.clear(); + for (Object v : journalPrefs.getAll().values()) { + if (v instanceof String) { + JobEntry entry = JobEntry.fromString((String) v); + if (entry != null) { + journal.add(entry); + } + } + } + Collections.sort(journal, (a, b) -> b.date - a.date); + } + + private void clearJournal() { + journal.clear(); + journalPrefs.edit().clear().apply(); + } + + private void pushToJournal(String job_id, String phone_number, String error) { + JobEntry entry = new JobEntry(); + entry.job_id = job_id; + entry.error = error; + entry.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + entry.country = getCountryFromPhoneNumber(ApplicationLoader.applicationContext, phone_number); + journal.add(0, entry); + journalPrefs.edit().putString(entry.job_id, entry.toString()).apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.smsJobStatusUpdate); + } + + public static String getCountryFromPhoneNumber(Context context, String phone_number) { + if (phone_number == null) return null; + final String phone = PhoneFormat.stripExceptNumbers(phone_number); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(context.getResources().getAssets().open("countries.txt"))); + String line; + while ((line = reader.readLine()) != null) { + String[] args = line.split(";"); + if (phone.startsWith(args[0])) { + return args[1]; + } + } + reader.close(); + } catch (Exception e) { + FileLog.e(e); + } finally { + try { + if (reader != null) { + reader.close(); + } + } catch (Exception e2) { + FileLog.e(e2); + } + } + return ""; + } + + public static class JobEntry { + public String job_id; + public String error; + public String country; + public int date; + + @NonNull + @Override + public String toString() { + return job_id + "," + (error == null ? "" : error) + "," + date + "," + country; + } + + public static JobEntry fromString(String string) { + String[] parts = string.split(","); + if (parts.length != 4) return null; + JobEntry entry = new JobEntry(); + entry.job_id = parts[0]; + entry.error = TextUtils.isEmpty(parts[1]) ? null : parts[1]; + entry.date = Utilities.parseInt(parts[2]); + entry.country = parts[3]; + return entry; + } + } +} diff --git a/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/SMSResultService.java b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/SMSResultService.java new file mode 100644 index 000000000..2fafc1c53 --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/SMSResultService.java @@ -0,0 +1,12 @@ +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class SMSResultService extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + SMSJobController.receivedSMSIntent(intent, getResultCode()); + } +} diff --git a/TMessagesProj_AppStandalone/src/main/java/org/telegram/tgnet/TL_smsjobs.java b/TMessagesProj_AppStandalone/src/main/java/org/telegram/tgnet/TL_smsjobs.java new file mode 100644 index 000000000..fe87a80a2 --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/java/org/telegram/tgnet/TL_smsjobs.java @@ -0,0 +1,238 @@ +package org.telegram.tgnet; + +public class TL_smsjobs { + + public static class TL_smsjobs_eligibleToJoin extends TLObject { + public static final int constructor = 0xdc8b44cf; + + public String terms_of_use; + public int monthly_sent_sms; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + terms_of_use = stream.readString(exception); + monthly_sent_sms = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(terms_of_use); + stream.writeInt32(monthly_sent_sms); + } + } + + public static class TL_smsjobs_status extends TLObject { + public static final int constructor = 0x2aee9191; + + public int flags; + public boolean allow_international; + public int recent_sent; + public int recent_since; + public int recent_remains; + public int total_sent; + public int total_since; + public String last_gift_slug; + public String terms_url; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + allow_international = (flags & 1) != 0; + recent_sent = stream.readInt32(exception); + recent_since = stream.readInt32(exception); + recent_remains = stream.readInt32(exception); + total_sent = stream.readInt32(exception); + total_since = stream.readInt32(exception); + if ((flags & 2) != 0) { + last_gift_slug = stream.readString(exception); + } + terms_url = stream.readString(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = allow_international ? flags | 1 : flags &~ 1; + stream.writeInt32(flags); + stream.writeInt32(recent_sent); + stream.writeInt32(recent_since); + stream.writeInt32(recent_remains); + stream.writeInt32(total_sent); + stream.writeInt32(total_since); + if ((flags & 2) != 0) { + stream.writeString(last_gift_slug); + } + stream.writeString(terms_url); + } + } + + public static class TL_updateSmsJob extends TLRPC.Update { + public static final int constructor = 0xf16269d4; + + public String job_id; + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + job_id = stream.readString(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(job_id); + } + } + + public static class TL_smsJob extends TLObject { + public static final int constructor = 0xe6a1eeb8; + + public String job_id; + public String phone_number; + public String text; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + job_id = stream.readString(exception); + phone_number = stream.readString(exception); + text = stream.readString(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(job_id); + stream.writeString(phone_number); + stream.writeString(text); + } + } + + public static class TL_smsjobs_isEligibleToJoin extends TLObject { + public static final int constructor = 0xedc39d0; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor == TL_smsjobs_eligibleToJoin.constructor) { + TL_smsjobs_eligibleToJoin result = new TL_smsjobs_eligibleToJoin(); + result.readParams(stream, exception); + return result; + } + return null; + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_smsjobs_join extends TLObject { + public static final int constructor = 0xa74ece2d; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TLRPC.Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_smsjobs_leave extends TLObject { + public static final int constructor = 0x9898ad73; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TLRPC.Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_smsjobs_getStatus extends TLObject { + public static final int constructor = 0x10a698e8; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor == TL_smsjobs_status.constructor) { + TL_smsjobs_status result = new TL_smsjobs_status(); + result.readParams(stream, exception); + return result; + } + return null; + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_smsjobs_getSmsJob extends TLObject { + public static final int constructor = 0x778d902f; + + public String job_id; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor == TL_smsJob.constructor) { + TL_smsJob result = new TL_smsJob(); + result.readParams(stream, exception); + return result; + } + return null; + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(job_id); + } + } + + public static class TL_smsjobs_finishJob extends TLObject { + public static final int constructor = 0x4f1ebf24; + + public int flags; + public String job_id; + public String error; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TLRPC.Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(job_id); + if ((flags & 1) != 0) { + stream.writeString(error); + } + } + } + + public static class TL_smsjobs_updateSettings extends TLObject { + public static final int constructor = 0x93fa0bf; + + public int flags; + public boolean allow_international; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TLRPC.Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = allow_international ? flags | 1 : flags &~ 1; + stream.writeInt32(flags); + } + } +} diff --git a/TMessagesProj_AppStandalone/src/main/java/org/telegram/ui/SMSStatsActivity.java b/TMessagesProj_AppStandalone/src/main/java/org/telegram/ui/SMSStatsActivity.java new file mode 100644 index 000000000..ddd590f60 --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/java/org/telegram/ui/SMSStatsActivity.java @@ -0,0 +1,1065 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; +import static org.telegram.messenger.AndroidUtilities.quietSleep; +import static org.telegram.messenger.LocaleController.formatPluralString; +import static org.telegram.messenger.LocaleController.formatString; +import static org.telegram.messenger.LocaleController.getString; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.URLSpan; +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.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.LocationController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.SMSJobController; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.browser.Browser; +import org.telegram.messenger.web.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.TL_smsjobs; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.LanguageCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.BottomSheetWithRecyclerListView; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkSpanDrawable; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.Premium.LimitPreviewView; +import org.telegram.ui.Components.Premium.boosts.GiftInfoBottomSheet; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.Locale; +import java.util.Objects; + +public class SMSStatsActivity extends GradientHeaderActivity implements NotificationCenter.NotificationCenterDelegate { + + private final static int VIEW_TYPE_HEADER = 0; + private final static int VIEW_TYPE_TABLE = 1; + private final static int VIEW_TYPE_SHADOW = 2; + private final static int VIEW_TYPE_BUTTON = 3; + private final static int VIEW_TYPE_SWITCH = 4; + private final static int VIEW_TYPE_HEADERCELL = 5; + private final static int VIEW_TYPE_JOBENTRY = 6; + + private ArrayList oldItems = new ArrayList<>(); + private ArrayList items = new ArrayList<>(); + private boolean allowInternationalSet = false, allowInternational = false; + private boolean askedStatusToLoad = false; + + private final AdapterWithDiffUtils adapter = new AdapterWithDiffUtils() { + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + final int viewType = holder.getItemViewType(); + return viewType == VIEW_TYPE_BUTTON || viewType == VIEW_TYPE_SWITCH; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case VIEW_TYPE_HEADER: + view = getHeader(getContext()); + break; + case VIEW_TYPE_HEADERCELL: + view = new HeaderCell(getContext()); + break; + case VIEW_TYPE_TABLE: + view = table = new TableView(getContext(), currentAccount); + break; + case VIEW_TYPE_BUTTON: + view = new TextCell(getContext()); + break; + case VIEW_TYPE_SWITCH: + view = new TextCell(getContext(), 23, false, true, getResourceProvider()); + break; + case VIEW_TYPE_JOBENTRY: + view = new JobEntryCell(getContext()); + break; + default: + case VIEW_TYPE_SHADOW: + view = new TextInfoPrivacyCell(getContext()); + Drawable shadowDrawable = Theme.getThemedDrawable(getContext(), org.telegram.messenger.R.drawable.greydivider, Theme.getColor(Theme.key_windowBackgroundGrayShadow, resourceProvider)); + Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)); + CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); + combinedDrawable.setFullsize(true); + view.setBackground(combinedDrawable); + break; + } + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + + @Override + public int getItemViewType(int position) { + if (position < 0 || position >= items.size()) + return VIEW_TYPE_SHADOW; + return items.get(position).viewType; + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (position < 0 || position >= items.size()) + return; + SMSStatsActivity.Item item = items.get(position); + final int viewType = holder.getItemViewType(); + final boolean divider = position + 1 < items.size() && items.get(position + 1).viewType == viewType; + if (viewType == VIEW_TYPE_SHADOW) { + TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; + final boolean isLast = position == items.size() - 1; + if (TextUtils.isEmpty(item.text)) { + cell.setFixedSize(isLast ? 350 : 21); + cell.setText(""); + } else { + cell.setFixedSize(0); + cell.setText(item.text); + } + } else if (viewType == VIEW_TYPE_BUTTON) { + TextCell cell = (TextCell) holder.itemView; + if (item.red) { + cell.setColors(Theme.key_text_RedBold, Theme.key_text_RedRegular); + } else { + cell.setColors(Theme.key_windowBackgroundWhiteGrayIcon, Theme.key_windowBackgroundWhiteBlackText); + } + if (item.id == BUTTON_SIM) { + SMSJobController.SIM sim = SMSJobController.getInstance(currentAccount).getSelectedSIM(); + String simCard = sim == null ? "" : sim.name; + if (item.icon == 0) { + cell.setTextAndValue(item.text.toString(), simCard, divider); + } else { + cell.setTextAndValueAndIcon(item.text.toString(), simCard, item.icon, divider); + } + } else if (item.icon == 0) { + cell.setText(item.text, divider); + } else { + cell.setTextAndIcon(item.text, item.icon, divider); + } + } else if (viewType == VIEW_TYPE_SWITCH) { + TextCell cell = (TextCell) holder.itemView; + boolean checked = false; + if (item.id == BUTTON_ALLOW_INTERNATIONAL) { + checked = allowInternational; + } + cell.setTextAndCheck(item.text, checked, divider); + } else if (viewType == VIEW_TYPE_TABLE) { + ((TableView) holder.itemView).update(false); + } else if (viewType == VIEW_TYPE_HEADERCELL) { + ((HeaderCell) holder.itemView).setText(item.text); + } else if (viewType == VIEW_TYPE_JOBENTRY) { + ((JobEntryCell) holder.itemView).set(item.entry); + } + } + + @Override + public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) { + super.onViewAttachedToWindow(holder); + if (holder.getItemViewType() == VIEW_TYPE_TABLE) { + ((TableView) holder.itemView).update(false); + } + } + + @Override + public int getItemCount() { + return items.size(); + } + }; + + private static class Item extends AdapterWithDiffUtils.Item { + + public int id; + public int icon; + public CharSequence text; + public boolean red; + public SMSJobController.JobEntry entry; + + public Item(int viewType) { + super(viewType, false); + } + + public static Item asButton(int id, int icon, CharSequence text) { + Item item = new Item(VIEW_TYPE_BUTTON); + item.id = id; + item.icon = icon; + item.text = text; + return item; + } + + public static Item asSwitch(int id, CharSequence text) { + Item item = new Item(VIEW_TYPE_SWITCH); + item.id = id; + item.text = text; + return item; + } + + public static Item asJobEntry(SMSJobController.JobEntry jobEntry) { + Item item = new Item(VIEW_TYPE_JOBENTRY); + item.entry = jobEntry; + return item; + } + + public static Item asHeader(CharSequence text) { + Item item = new Item(VIEW_TYPE_HEADERCELL); + item.text = text; + return item; + } + + public static Item asShadow(CharSequence text) { + Item item = new Item(VIEW_TYPE_SHADOW); + item.text = text; + return item; + } + + public Item makeRed() { + this.red = true; + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Item item = (Item) o; + return item.id == id && item.viewType == viewType && item.entry == entry && icon == item.icon && red == item.red && Objects.equals(text, item.text); + } + + @Override + public int hashCode() { + return Objects.hash(icon, text, red); + } + } + + public final static int BUTTON_TERMS = 1; + public final static int BUTTON_PREMIUM = 2; + public final static int BUTTON_ALLOW_INTERNATIONAL = 3; + public final static int BUTTON_SIM = 4; + public final static int BUTTON_HISTORY = 5; + public final static int BUTTON_DEACTIVATE = 6; + + private TableView table; + public void updateItems() { + final int state = SMSJobController.getInstance(currentAccount).getState(); + + oldItems.clear(); + oldItems.addAll(items); + items.clear(); + + items.add(new Item(VIEW_TYPE_HEADER)); + items.add(new Item(VIEW_TYPE_TABLE)); + items.add(Item.asShadow(null)); + items.add(Item.asButton(BUTTON_TERMS, R.drawable.menu_intro, LocaleController.getString(R.string.SmsToS))); + items.add(Item.asButton(BUTTON_PREMIUM, R.drawable.menu_premium_main, LocaleController.getString(R.string.SmsPremiumBenefits))); + if (state == SMSJobController.STATE_JOINED && !SMSJobController.getInstance(currentAccount).journal.isEmpty()) { + items.add(Item.asButton(BUTTON_HISTORY, R.drawable.menu_sms_history, LocaleController.getString(R.string.SmsHistory))); + } + if (state == SMSJobController.STATE_JOINED && SMSJobController.getInstance(currentAccount).simsCount() > 1) { + items.add(Item.asButton(BUTTON_SIM, R.drawable.menu_storage_path, LocaleController.getString(R.string.SmsActiveSim))); + } + items.add(Item.asShadow(null)); + items.add(Item.asSwitch(BUTTON_ALLOW_INTERNATIONAL, LocaleController.getString(R.string.SmsAllowInternational))); + items.add(Item.asShadow(LocaleController.getString(R.string.SmsCostsInfo))); + if (state != SMSJobController.STATE_NONE) { + items.add(Item.asButton(BUTTON_DEACTIVATE, 0, LocaleController.getString(R.string.SmsDeactivate)).makeRed()); + } + items.add(Item.asShadow(null)); + + if (adapter != null) { + adapter.setItems(oldItems, items); + } + } + + public SMSStatsActivity() { + super(); + updateItems(); + } + + @Override + public View createView(Context context) { + View rootView = super.createView(context); + updateHeader(); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(350); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + listView.setItemAnimator(itemAnimator); + listView.setOnItemClickListener((view, position) -> { + if (position < 0 || position >= items.size()) return; + Item item = items.get(position); + + if (item.viewType == VIEW_TYPE_HEADER) { + if (SMSJobController.getInstance(currentAccount).getState() == SMSJobController.STATE_ASKING_PERMISSION) { + SMSSubscribeSheet.requestSMSPermissions(getContext(), () -> { + SMSJobController.getInstance(currentAccount).checkSelectedSIMCard(); + if (SMSJobController.getInstance(currentAccount).getSelectedSIM() == null) { + SMSJobController.getInstance(currentAccount).setState(SMSJobController.STATE_NO_SIM); + new AlertDialog.Builder(getContext(), getResourceProvider()) + .setTitle(LocaleController.getString(R.string.SmsNoSimTitle)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.getString(R.string.SmsNoSimMessage))) + .setPositiveButton(LocaleController.getString(R.string.OK), null) + .show(); + return; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(new TL_smsjobs.TL_smsjobs_join(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + BulletinFactory.global().createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + SMSJobController.getInstance(currentAccount).setState(SMSJobController.STATE_JOINED); + SMSJobController.getInstance(currentAccount).loadStatus(true); + SMSSubscribeSheet.showSubscribed(getContext(), getResourceProvider()); + update(true); + } + })); + }, false); + } + } else if (item.id == BUTTON_TERMS) { + TL_smsjobs.TL_smsjobs_status status = SMSJobController.getInstance(currentAccount).currentStatus; + TL_smsjobs.TL_smsjobs_eligibleToJoin isEligible = SMSJobController.getInstance(currentAccount).isEligible; + if (status != null) { + Browser.openUrl(getContext(), status.terms_url); + } else if (isEligible != null) { + Browser.openUrl(getContext(), isEligible.terms_of_use); + } + } else if (item.id == BUTTON_ALLOW_INTERNATIONAL) { + if (SMSJobController.getInstance(currentAccount).currentState != SMSJobController.STATE_JOINED) { + return; + } + SMSJobController.getInstance(currentAccount).toggleAllowInternational(allowInternational = !allowInternational); + ((TextCell) view).setChecked(allowInternational); + } else if (item.id == BUTTON_PREMIUM) { + presentFragment(new PremiumPreviewFragment("sms")); + } else if (item.id == BUTTON_DEACTIVATE) { + AlertDialog d = new AlertDialog.Builder(getContext(), getResourceProvider()) + .setTitle(LocaleController.getString(R.string.SmsDeactivateTitle)) + .setMessage(LocaleController.getString(R.string.SmsDeactivateMessage)) + .setPositiveButton(LocaleController.getString(R.string.VoipGroupLeave), (di, w) -> { + finishFragment(); + if (SMSJobController.getInstance(currentAccount).getState() == SMSJobController.STATE_JOINED) { + AndroidUtilities.runOnUIThread(() -> { + SMSJobController.getInstance(currentAccount).leave(); + }, 120); + } else { + SMSJobController.getInstance(currentAccount).setState(SMSJobController.STATE_NONE); + } + }) + .setNegativeButton(LocaleController.getString(R.string.Back), null) + .setDimAlpha(0.5f) + .create(); + showDialog(d); + ((TextView) d.getButton(DialogInterface.BUTTON_POSITIVE)).setTextColor(getThemedColor(Theme.key_text_RedBold)); + } else if (item.id == BUTTON_SIM) { + try { + ArrayList finalSims = SMSJobController.getInstance(currentAccount).getSIMs(); + SMSJobController.SIM finalSelectedSim = SMSJobController.getInstance(currentAccount).getSelectedSIM(); + if (finalSims == null) return; + + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString(R.string.SmsSelectSim)); + final LinearLayout linearLayout = new LinearLayout(getParentActivity()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + builder.setView(linearLayout); + + for (int a = 0, N = finalSims.size(); a < N; a++) { + final SMSJobController.SIM sim = finalSims.get(a); + if (sim == null) continue; + LanguageCell cell = new LanguageCell(context); + cell.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + cell.setTag(a); + String description = ""; + if (sim.country != null) { + description += LocationController.countryCodeToEmoji(sim.country); + } + if (!TextUtils.isEmpty(description)) { + description += " "; + } + description += sim.name; + NotificationCenter.listenEmojiLoading(cell.textView2); + cell.setValue(AndroidUtilities.replaceTags("**SIM" + (1 + sim.slot) + "**"), Emoji.replaceEmoji(description, cell.textView2.getPaint().getFontMetricsInt(), false)); + cell.setLanguageSelected(finalSelectedSim != null && finalSelectedSim.id == sim.id, false); + cell.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 2)); + linearLayout.addView(cell); + cell.setOnClickListener(v -> { + SMSJobController.getInstance(currentAccount).setSelectedSIM(sim); + ((TextCell) view).setValue(sim.name, !LocaleController.isRTL); + builder.getDismissRunnable().run(); + }); + } + builder.setNegativeButton(LocaleController.getString("Cancel", org.telegram.messenger.R.string.Cancel), null); + showDialog(builder.create()); + } catch (Exception e) { + FileLog.e(e); + } + } else if (item.id == BUTTON_HISTORY) { + showDialog(new SMSHistorySheet(this)); + } + }); + return rootView; + } + + private LimitPreviewView limitPreviewView; + private View aboveTitleView; + + private void updateHeader() { + limitPreviewView = new LimitPreviewView(getContext(), R.drawable.msg_limit_chats, 0, 0, resourceProvider); + limitPreviewView.isStatistic = true; + limitPreviewView.setDarkGradientProvider(this::setDarkGradientLocation); + aboveTitleView = new FrameLayout(getContext()) { + { + addView(limitPreviewView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 8, 60, 8, 33)); + } + }; + + update(false); + } + + private void update(boolean animated) { + final int state = SMSJobController.getInstance(currentAccount).getState(); + + TL_smsjobs.TL_smsjobs_status status = SMSJobController.getInstance(currentAccount).currentStatus; + TL_smsjobs.TL_smsjobs_eligibleToJoin isEligible = SMSJobController.getInstance(currentAccount).isEligible; + if (status == null && !askedStatusToLoad) { + SMSJobController.getInstance(currentAccount).loadStatus(true); + askedStatusToLoad = true; + } + + if (!allowInternational) { + allowInternationalSet = status != null; + allowInternational = status != null && status.allow_international; + } + + final int sentNumber = status == null ? 0 : status.recent_sent; + final int remainingNumber = status == null ? (isEligible == null ? 0 : isEligible.monthly_sent_sms) : status.recent_remains; + + if (limitPreviewView != null) { + limitPreviewView.setStatus(sentNumber, sentNumber + remainingNumber, animated); + } + if (table != null) { + table.update(animated); + } + + if (state == SMSJobController.STATE_NO_SIM) { + SMSJobController.getInstance(currentAccount).checkSelectedSIMCard(); + configureHeader( + getString(R.string.SmsStatusNoSim), + getString(R.string.SmsStatusNoSimSubtitle), + aboveTitleView, + null + ); + } else if (state == SMSJobController.STATE_ASKING_PERMISSION) { + if (getParentActivity() != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ( + getParentActivity().checkSelfPermission(Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED && + getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED && + getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED + )) { + SMSJobController.getInstance(currentAccount).checkSelectedSIMCard(); + if (SMSJobController.getInstance(currentAccount).getSelectedSIM() == null) { + SMSJobController.getInstance(currentAccount).setState(SMSJobController.STATE_NO_SIM); + update(true); + new AlertDialog.Builder(getContext(), getResourceProvider()) + .setTitle(LocaleController.getString(R.string.SmsNoSimTitle)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.getString(R.string.SmsNoSimMessage))) + .setPositiveButton(LocaleController.getString(R.string.OK), null) + .show(); + return; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(new TL_smsjobs.TL_smsjobs_join(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + BulletinFactory.global().createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + SMSJobController.getInstance(currentAccount).setState(SMSJobController.STATE_JOINED); + SMSJobController.getInstance(currentAccount).loadStatus(true); + SMSSubscribeSheet.showSubscribed(getContext(), getResourceProvider()); + update(true); + } + })); + } + + configureHeader( + getString(R.string.SmsStatusNoPermission), + getString(R.string.SmsStatusNoPermissionSubtitle), + aboveTitleView, + null + ); + } else if (status != null && sentNumber >= sentNumber + remainingNumber) { + configureHeader( + formatString(R.string.SmsStatusDone, sentNumber), + AndroidUtilities.replaceTags(getString(R.string.SmsStatusDoneSubtitle)), + aboveTitleView, + null + ); + } else { + if (sentNumber == 0) { + configureHeader( + getString(R.string.SmsStatusFirst), + AndroidUtilities.replaceTags(getString(R.string.SmsStatusFirstSubtitle)), + aboveTitleView, + null + ); + } else { + configureHeader( + formatString(R.string.SmsStatusSending, sentNumber, sentNumber + remainingNumber), + AndroidUtilities.replaceTags(formatPluralString("SmsStatusSendingSubtitle", remainingNumber)), + aboveTitleView, + null + ); + } + } + } + + @Override + public boolean onFragmentCreate() { + getNotificationCenter().addObserver(this, NotificationCenter.smsJobStatusUpdate); + SMSJobController.getInstance(currentAccount).init(); + SMSJobController.getInstance(currentAccount).atStatisticsPage = true; + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + getNotificationCenter().removeObserver(this, NotificationCenter.smsJobStatusUpdate); + SMSJobController.getInstance(currentAccount).atStatisticsPage = false; + super.onFragmentDestroy(); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.smsJobStatusUpdate) { + updateItems(); + update(true); + } + } + + @Override + protected RecyclerView.Adapter createAdapter() { + return adapter; + } + + public class TableView extends LinearLayout { + + public final int currentAccount; + public final AnimatedTextView smsSentTextView; + public final AnimatedTextView smsRemainingTextView; + public final TextView sentSinceTitleView; + public final AnimatedTextView sentSinceDateTextView; + public final AnimatedTextView giftSinceDateTextView; + public final LinkSpanDrawable.LinksTextView lastGiftLinkTextView; + + public TableView(Context context, int currentAccount) { + super(context); + this.currentAccount = currentAccount; + + setOrientation(LinearLayout.VERTICAL); + setPadding(dp(22), 0, dp(22), dp(20)); + + TextView titleView = new TextView(context); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleView.setText(LocaleController.getString(R.string.SmsOverview)); + addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0)); + + LinearLayout hor = new LinearLayout(context); + hor.setOrientation(HORIZONTAL); + addView(hor, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 23, 0, 0)); + LinearLayout left = new LinearLayout(context); + left.setOrientation(VERTICAL); + hor.addView(left, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1, Gravity.FILL)); + LinearLayout right = new LinearLayout(context); + right.setOrientation(VERTICAL); + hor.addView(right, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1, Gravity.FILL)); + + smsSentTextView = new AnimatedTextView(context, false, true, true); + smsSentTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourceProvider)); + smsSentTextView.setTextSize(dp(17)); + smsSentTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + left.addView(smsSentTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 20, 4, 0, 4, 0)); + TextView textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + textView.setText(LocaleController.getString(R.string.SmsTotalSent)); + left.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 4, 0, 4, 0)); + + sentSinceDateTextView = new AnimatedTextView(context, false, true, true); + sentSinceDateTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourceProvider)); + sentSinceDateTextView.setTextSize(dp(17)); + sentSinceDateTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + right.addView(sentSinceDateTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 20, 4, 0, 4, 0)); + sentSinceTitleView = new TextView(context); + sentSinceTitleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + sentSinceTitleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + sentSinceTitleView.setText(LocaleController.getString(R.string.SmsSentSince)); + right.addView(sentSinceTitleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 4, 0, 4, 0)); + + hor = new LinearLayout(context); + hor.setOrientation(HORIZONTAL); + addView(hor, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 23, 0, 0)); + left = new LinearLayout(context); + left.setOrientation(VERTICAL); + hor.addView(left, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1, Gravity.FILL)); + right = new LinearLayout(context); + right.setOrientation(VERTICAL); + hor.addView(right, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1, Gravity.FILL)); + + smsRemainingTextView = new AnimatedTextView(context, false, true, true); + smsRemainingTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourceProvider)); + smsRemainingTextView.setTextSize(dp(17)); + smsRemainingTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + smsRemainingTextView.setText("0"); + left.addView(smsRemainingTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 20, 4, 0, 4, 0)); + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + textView.setText(LocaleController.getString(R.string.SmsRemaining)); + left.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 4, 0, 4, 0)); + + giftSinceDateTextView = new AnimatedTextView(context, false, true, true); + giftSinceDateTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourceProvider)); + giftSinceDateTextView.setTextSize(dp(17)); + giftSinceDateTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + right.addView(giftSinceDateTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 20, 4, 0, 4, 0)); + lastGiftLinkTextView = new LinkSpanDrawable.LinksTextView(context); + lastGiftLinkTextView.setPadding(dp(4), 0, 0, 0); + lastGiftLinkTextView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText, resourceProvider)); + lastGiftLinkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + lastGiftLinkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + lastGiftLinkTextView.setText(LocaleController.getString(R.string.SmsLastGiftLink)); + right.addView(lastGiftLinkTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0)); + + update(false); + } + + public void update(boolean animated) { + TL_smsjobs.TL_smsjobs_status status = SMSJobController.getInstance(currentAccount).currentStatus; + TL_smsjobs.TL_smsjobs_eligibleToJoin isEligible = SMSJobController.getInstance(currentAccount).isEligible; + if (status == null && !askedStatusToLoad) { + SMSJobController.getInstance(currentAccount).loadStatus(true); + askedStatusToLoad = true; + } + if (LocaleController.isRTL) { + animated = false; + } + + final int sentNumber = status == null ? 0 : status.recent_sent; + final int remainingNumber = status == null ? (isEligible == null ? 0 : isEligible.monthly_sent_sms) : status.recent_remains; + + smsSentTextView.setText("" + (status == null ? 0 : status.total_sent), animated); + smsRemainingTextView.setText("" + remainingNumber, animated); + if (status == null) { + sentSinceDateTextView.setText(LocaleController.getString(R.string.None), animated); + } else { + String date = LocaleController.formatDateAudio(status.total_since, false); + if (date.length() > 0) { + date = date.substring(0, 1).toUpperCase() + date.substring(1); + } + sentSinceDateTextView.setText(date, animated); + } + sentSinceTitleView.setText(LocaleController.getString(R.string.SmsStartDate)); + if (status != null && status.last_gift_slug != null) { + String date = LocaleController.formatDateAudio(status.recent_since, false); + if (date.length() > 0) { + date = date.substring(0, 1).toUpperCase() + date.substring(1); + } + giftSinceDateTextView.setText(date, animated); + } else { + giftSinceDateTextView.setText(LocaleController.getString(R.string.None), animated); + } + SpannableString giftLink = new SpannableString(LocaleController.getString(R.string.SmsLastGiftLink)); + if (status != null && status.last_gift_slug != null) { + giftLink.setSpan(new URLSpan("") { + @Override + public void onClick(View widget) { + GiftInfoBottomSheet.show(SMSStatsActivity.this, status.last_gift_slug); + } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + ds.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText, resourceProvider)); + } + }, 0, giftLink.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + lastGiftLinkTextView.setText(giftLink); + } + } + + private static class JobEntryCell extends FrameLayout { + public TextView statusTextView; + public TextView dateTextView; + + public JobEntryCell(Context context) { + super(context); + + statusTextView = new TextView(context); + statusTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + statusTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + statusTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + statusTextView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); + addView(statusTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT, 21, 0, 0, 0)); + + dateTextView = new TextView(context); + dateTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + dateTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + dateTextView.setGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT); + addView(dateTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.RIGHT, 0, 0, 21, 0)); + } + + public void set(SMSJobController.JobEntry entry) { + if (entry.error != null) { + statusTextView.setText("Failed"); + statusTextView.setTextColor(Theme.getColor(Theme.key_text_RedBold)); + } else { + statusTextView.setText("Success"); + statusTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGreenText)); + } + dateTextView.setText(LocaleController.getInstance().formatDate(entry.date)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); + } + } + + + public static class SMSHistorySheet extends BottomSheetWithRecyclerListView implements NotificationCenter.NotificationCenterDelegate { + + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public class HeaderCell extends LinearLayout { + public HeaderCell(Context context) { + super(context); + + setOrientation(LinearLayout.VERTICAL); + + ImageView imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setImageResource(R.drawable.large_sms_code); + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + imageView.setBackground(Theme.createCircleDrawable(dp(80), Theme.getColor(Theme.key_featuredStickers_addButton))); + addView(imageView, LayoutHelper.createLinear(80, 80, Gravity.CENTER_HORIZONTAL, 0, 24, 0, 12)); + + TextView textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + textView.setGravity(Gravity.CENTER); + textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textView.setText(getString(R.string.SmsHistoryTitle)); + addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 50, 0, 50, 6)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setGravity(Gravity.CENTER); + textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + textView.setText(AndroidUtilities.replaceTags(getString(R.string.SmsHistorySubtitle))); + textView.setLineSpacing(dp(2), 1f); + addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 50, 0, 50, 20)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), heightMeasureSpec); + } + } + + public class TableHeader extends FrameLayout { + private final LinearLayout container; + public TableHeader(Context context) { + super(context); + + container = new LinearLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(Math.min(MeasureSpec.getSize(widthMeasureSpec), dp(350)), MeasureSpec.EXACTLY), heightMeasureSpec); + } + }; + addView(container, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 37, Gravity.CENTER_HORIZONTAL, 14, 0, 14, 0)); + + TextView dateCountry = new TextView(context); + dateCountry.setGravity(Gravity.CENTER_VERTICAL); + dateCountry.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + dateCountry.setText(LocaleController.getString(R.string.SmsHistoryDateCountry)); + dateCountry.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + dateCountry.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + dateCountry.setPadding(dp(13), 0, dp(13), 0); + container.addView(dateCountry, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 37, 30, Gravity.FILL)); + + TextView status = new TextView(context); + status.setGravity(Gravity.CENTER_VERTICAL); + status.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + status.setText(LocaleController.getString(R.string.SmsHistoryStatus)); + status.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + status.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + status.setPadding(dp(13), 0, dp(13), 0); + container.addView(status, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 37, 70, Gravity.FILL)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), dp(37)); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + AndroidUtilities.rectTmp.set(container.getX() - dpf2(0.5f), dpf2(0.5f), container.getX() + container.getMeasuredWidth() + dpf2(0.5f), container.getMeasuredHeight() + dp(5)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(5), dp(5), backgroundPaint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(5), dp(5), strokePaint); + canvas.drawLine(container.getX() - dpf2(0.5f), container.getMeasuredHeight() - dpf2(0.5f), container.getX() + container.getMeasuredWidth() + dpf2(0.5f), container.getMeasuredHeight() - dpf2(0.5f), strokePaint); + super.dispatchDraw(canvas); + } + } + + public class TableCell extends FrameLayout { + private final LinearLayout container; + private final TextView dateTextView; + private final TextView countryTextView; + private final TextView statusTextView; + public TableCell(Context context) { + super(context); + + container = new LinearLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(Math.min(MeasureSpec.getSize(widthMeasureSpec), dp(350)), MeasureSpec.EXACTLY), heightMeasureSpec); + } + }; + addView(container, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.CENTER_HORIZONTAL, 14, 0, 14, 0)); + + LinearLayout left = new LinearLayout(context); + left.setOrientation(LinearLayout.VERTICAL); + left.setGravity(Gravity.CENTER_VERTICAL); + + dateTextView = new TextView(context); + dateTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + dateTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + dateTextView.setPadding(dp(13), 0, dp(13), 0); + left.addView(dateTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 2f)); + + countryTextView = new TextView(context); + NotificationCenter.listenEmojiLoading(countryTextView); + countryTextView.setTextColor(Theme.blendOver(Theme.getColor(Theme.key_dialogBackground), Theme.multAlpha(Theme.getColor(Theme.key_dialogTextBlack), .55f))); + countryTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + countryTextView.setPadding(dp(13), 0, dp(13), 0); + left.addView(countryTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + container.addView(left, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50, 30, Gravity.FILL)); + + statusTextView = new TextView(context); + statusTextView.setGravity(Gravity.CENTER_VERTICAL); + statusTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + statusTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + statusTextView.setPadding(dp(13), 0, dp(13), 0); + container.addView(statusTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50, 70, Gravity.FILL)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(50), MeasureSpec.EXACTLY)); + } + + private boolean isLast; + + public void setEntry(SMSJobController.JobEntry entry, boolean last) { + if (entry == null) return; + dateTextView.setText(LocaleController.getInstance().formatterGiveawayCard.format(new Date(entry.date * 1000L)) + ", " + LocaleController.getInstance().formatterDay.format(new Date(entry.date * 1000L))); + if (!TextUtils.isEmpty(entry.country)) { + countryTextView.setText(Emoji.replaceEmoji(LocationController.countryCodeToEmoji(entry.country) + " " + new Locale("", entry.country).getDisplayCountry(), countryTextView.getPaint().getFontMetricsInt(), false)); + } else { + countryTextView.setText(""); + } + if (TextUtils.isEmpty(entry.error)) { + statusTextView.setTextColor(Theme.getColor(Theme.key_avatar_nameInMessageGreen)); + statusTextView.setText(LocaleController.getString(R.string.SmsHistoryStatusSuccess)); + } else { + statusTextView.setTextColor(Theme.getColor(Theme.key_text_RedBold)); + statusTextView.setText(LocaleController.getString(R.string.SmsHistoryStatusFailure)); + } + isLast = last; + invalidate(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (isLast) { + AndroidUtilities.rectTmp.set(container.getX() - dpf2(0.5f), -dp(6), container.getX() + container.getMeasuredWidth() + dpf2(0.5f), container.getMeasuredHeight() - dpf2(0.5f)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(5), dp(5), strokePaint); + } else { + canvas.drawRect(container.getX() - dpf2(0.5f), -dp(1), container.getX() + container.getMeasuredWidth() + dpf2(0.5f), container.getMeasuredHeight() - dpf2(0.5f), strokePaint); + } + super.dispatchDraw(canvas); + } + } + + public SMSHistorySheet(BaseFragment fragment) { + super(fragment, false, false); + + strokePaint.setStrokeWidth(dp(1)); + strokePaint.setStyle(Paint.Style.STROKE); + strokePaint.setColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_divider, resourcesProvider), Color.WHITE, 0.1f)); + backgroundPaint.setColor(Theme.getColor(Theme.key_graySection, resourcesProvider)); + + FrameLayout buttonContainer = new FrameLayout(getContext()); + buttonContainer.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); + ButtonWithCounterView button = new ButtonWithCounterView(getContext(), resourcesProvider); + button.setOnClickListener(v -> { + dismiss(); + }); + button.setText(LocaleController.getString(R.string.Close), false); + buttonContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.CENTER_VERTICAL, 16, 0, 16, 0)); + View buttonShadow = new View(getContext()); + buttonShadow.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + buttonContainer.addView(buttonShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1.5f / AndroidUtilities.density, Gravity.TOP | Gravity.FILL_HORIZONTAL)); + containerView.addView(buttonContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 68, Gravity.BOTTOM)); + + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(350); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + recyclerListView.setItemAnimator(itemAnimator); + } + + @Override + protected CharSequence getTitle() { + return LocaleController.getString(R.string.SmsHistoryTitle); + } + + public static final int VIEW_TYPE_HEADER = 0; + public static final int VIEW_TYPE_TABLE_HEADER = 1; + public static final int VIEW_TYPE_TABLE_CELL = 2; + public static final int VIEW_TYPE_BUTTON_PAD = 3; + + @Override + protected RecyclerListView.SelectionAdapter createAdapter() { + return 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 HeaderCell(getContext()); + } else if (viewType == VIEW_TYPE_TABLE_HEADER) { + view = new TableHeader(getContext()); + } else if (viewType == VIEW_TYPE_BUTTON_PAD) { + view = new View(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(68 + 20), MeasureSpec.EXACTLY)); + } + }; + } else { + view = new TableCell(getContext()); + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + position -= 2; + ArrayList entries = SMSJobController.getInstance(currentAccount).journal; + if (position < 0 || entries == null || position >= entries.size()) { + return; + } + ((TableCell) holder.itemView).setEntry(entries.get(position), position + 1 == entries.size()); + } + + @Override + public int getItemViewType(int position) { + if (position == 0) { + return VIEW_TYPE_HEADER; + } else if (position == 1) { + return VIEW_TYPE_TABLE_HEADER; + } else if (position == getItemCount() - 1) { + return VIEW_TYPE_BUTTON_PAD; + } else { + return VIEW_TYPE_TABLE_CELL; + } + } + + @Override + public int getItemCount() { + return 3 + SMSJobController.getInstance(currentAccount).journal.size(); + } + }; + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.smsJobStatusUpdate) { + if (recyclerListView != null && recyclerListView.getAdapter() != null) { + recyclerListView.getAdapter().notifyDataSetChanged(); + } + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.smsJobStatusUpdate); + } + + @Override + public void dismiss() { + super.dismiss(); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.smsJobStatusUpdate); + } + } + +} diff --git a/TMessagesProj_AppStandalone/src/main/java/org/telegram/ui/SMSSubscribeSheet.java b/TMessagesProj_AppStandalone/src/main/java/org/telegram/ui/SMSSubscribeSheet.java new file mode 100644 index 000000000..0d666e0af --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/java/org/telegram/ui/SMSSubscribeSheet.java @@ -0,0 +1,397 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.LocaleController.formatPluralString; +import static org.telegram.messenger.LocaleController.formatString; +import static org.telegram.messenger.LocaleController.getString; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.net.Uri; +import android.os.Build; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.LongSparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.SMSJobController; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.browser.Browser; +import org.telegram.messenger.web.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.TL_smsjobs; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CheckBoxSquare; +import org.telegram.ui.Components.FireworksOverlay; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkSpanDrawable; +import org.telegram.ui.Components.RLottieImageView; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +public class SMSSubscribeSheet { + + public static BottomSheet show(Context context, TL_smsjobs.TL_smsjobs_eligibleToJoin isEligible, Runnable onHide, Theme.ResourcesProvider resourcesProvider) { + BottomSheet sheet = new BottomSheet(context, false, resourcesProvider); + sheet.fixNavigationBar(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + + ImageView imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setImageResource(R.drawable.large_sms_code); + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + imageView.setBackground(Theme.createCircleDrawable(dp(80), Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider))); + layout.addView(imageView, LayoutHelper.createLinear(80, 80, Gravity.CENTER_HORIZONTAL, 0, 24, 0, 12)); + + TextView textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + textView.setGravity(Gravity.CENTER); + textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textView.setText(getString(R.string.SmsSubscribeTitle)); + layout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 30, 0, 30, 6)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setGravity(Gravity.CENTER); + textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4, resourcesProvider)); + textView.setText(AndroidUtilities.replaceTags(getString(R.string.SmsSubscribeMessage))); + layout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 30, 0, 30, 14)); + + final Runnable openPremium = () -> { + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (fragment != null) { + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + fragment.showAsSheet(new PremiumPreviewFragment("sms"), params); + } + }; + layout.addView(new FeatureCell(context, R.drawable.menu_feature_sms, getString(R.string.SmsSubscribeFeature1Title), formatPluralString("SmsSubscribeFeature1Message", isEligible == null ? 100 : isEligible.monthly_sent_sms), resourcesProvider), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 30, 16, 30, 0)); + layout.addView(new FeatureCell(context, R.drawable.menu_feature_premium, getString(R.string.SmsSubscribeFeature2Title), AndroidUtilities.replaceSingleTag(getString(R.string.SmsSubscribeFeature2Message), openPremium), resourcesProvider), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 30, 16, 30, 0)); + layout.addView(new FeatureCell(context, R.drawable.menu_feature_gift, getString(R.string.SmsSubscribeFeature3Title), getString(R.string.SmsSubscribeFeature3Message), resourcesProvider), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 30, 16, 30, 0)); + + final Runnable openTOS = () -> { + if (isEligible == null) return; + Browser.openUrl(context, isEligible.terms_of_use); + }; + FrameLayout acceptLayout = new FrameLayout(context); + final CheckBoxSquare checkBox = new CheckBoxSquare(context, false); + checkBox.setDuplicateParentStateEnabled(false); + checkBox.setFocusable(false); + checkBox.setFocusableInTouchMode(false); + checkBox.setClickable(false); + acceptLayout.addView(checkBox, LayoutHelper.createFrame(18, 18, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0)); + LinkSpanDrawable.LinksTextView linkTextView = new LinkSpanDrawable.LinksTextView(context, resourcesProvider); + linkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + linkTextView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText, resourcesProvider)); + linkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + linkTextView.setMaxLines(2); + linkTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + linkTextView.setEllipsize(TextUtils.TruncateAt.END); + linkTextView.setText(AndroidUtilities.replaceSingleTag(getString(R.string.SmsSubscribeAccept), openTOS)); + acceptLayout.addView(linkTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 16 : 58, 21, LocaleController.isRTL ? 58 : 16, 21)); + layout.addView(acceptLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 9, 0, 9, 0)); + + ButtonWithCounterView button = new ButtonWithCounterView(context, resourcesProvider); + button.setText(getString(R.string.SmsSubscribeActivate), false); + button.setEnabled(false); + layout.addView(button, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 14, 0, 14, 0)); + acceptLayout.setOnClickListener(v -> { + checkBox.setChecked(!checkBox.isChecked(), true); + button.setEnabled(checkBox.isChecked()); + }); + final float[] shiftDp = new float[] { 4 }; + button.setOnClickListener(v -> { + final int currentAccount = UserConfig.selectedAccount; + if (!button.isEnabled()) { + AndroidUtilities.shakeViewSpring(acceptLayout, shiftDp[0] = -shiftDp[0]); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + return; + } + SMSJobController.getInstance(currentAccount).setState(SMSJobController.STATE_ASKING_PERMISSION); + requestSMSPermissions(context, () -> { + SMSJobController.getInstance(currentAccount).checkSelectedSIMCard(); + if (SMSJobController.getInstance(currentAccount).getSelectedSIM() == null) { + sheet.dismiss(); + SMSJobController.getInstance(currentAccount).setState(SMSJobController.STATE_NO_SIM); + new AlertDialog.Builder(context, resourcesProvider) + .setTitle(LocaleController.getString(R.string.SmsNoSimTitle)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.getString(R.string.SmsNoSimMessage))) + .setPositiveButton(LocaleController.getString(R.string.OK), null) + .show(); + return; + } + button.setLoading(true); + ConnectionsManager.getInstance(currentAccount).sendRequest(new TL_smsjobs.TL_smsjobs_join(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + button.setLoading(false); + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + button.setLoading(false); + BulletinFactory.global().createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + SMSJobController.getInstance(currentAccount).setState(SMSJobController.STATE_JOINED); + sheet.dismiss(); + SMSJobController.getInstance(currentAccount).loadStatus(true); + showSubscribed(context, resourcesProvider); + } + })); + }, false); + }); + + linkTextView = new LinkSpanDrawable.LinksTextView(context, resourcesProvider); + linkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4, resourcesProvider)); + linkTextView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText, resourcesProvider)); + linkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + linkTextView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + linkTextView.setText(AndroidUtilities.replaceSingleTag(getString(R.string.SmsSubscribeActivateText), openTOS)); + linkTextView.setGravity(Gravity.CENTER); + layout.addView(linkTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 30, 17, 30, 14)); + + sheet.setCustomView(layout); + + sheet.show(); + if (onHide != null) { + sheet.setOnHideListener(v -> onHide.run()); + } + return sheet; + } + + private static class FeatureCell extends LinearLayout { + public FeatureCell(Context context, int icon, CharSequence title, CharSequence message, Theme.ResourcesProvider resourcesProvider) { + super(context); + setOrientation(HORIZONTAL); + + ImageView iconView = new ImageView(context); + iconView.setImageResource(icon); + iconView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider), PorterDuff.Mode.SRC_IN)); + addView(iconView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, 0, 4, 17, 0)); + + LinearLayout textLayout = new LinearLayout(context); + textLayout.setOrientation(VERTICAL); + addView(textLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL)); + + TextView titleView = new TextView(context); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + titleView.setText(title); + textLayout.addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 1)); + + LinkSpanDrawable.LinksTextView messageView = new LinkSpanDrawable.LinksTextView(context, resourcesProvider); + messageView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + messageView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4, resourcesProvider)); + messageView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText, resourcesProvider)); + messageView.setText(message); + textLayout.addView(messageView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(Math.min(dp(330), MeasureSpec.getSize(widthMeasureSpec)), MeasureSpec.EXACTLY), heightMeasureSpec); + } + } + + public static BottomSheet showSubscribed(Context context, Theme.ResourcesProvider resourcesProvider) { + final int currentAccount = UserConfig.selectedAccount; + BottomSheet sheet = new BottomSheet(context, false, resourcesProvider); + sheet.fixNavigationBar(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + + RLottieImageView imageView = new RLottieImageView(context); + imageView.setAnimation(R.raw.giveaway_results, 120, 120); + imageView.getAnimatedDrawable().multiplySpeed(1.8f); + imageView.playAnimation(); + layout.addView(imageView, LayoutHelper.createLinear(120, 120, Gravity.CENTER_HORIZONTAL, 0, 24, 0, 12)); + + TextView textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + textView.setGravity(Gravity.CENTER); + textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textView.setText(getString(R.string.SmsPremiumActivated)); + layout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 30, 0, 30, 14)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setGravity(Gravity.CENTER); + textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + final TextView finalTextView2 = textView; + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); + String countryCode = null; + if (user != null) { + countryCode = SMSJobController.getCountryFromPhoneNumber(context, user.phone); + } + String country = null; + if (!TextUtils.isEmpty(countryCode)) { + try { + country = new Locale("", countryCode).getDisplayCountry(); + } catch (Exception e) { + + } + } + if (country != null) { + finalTextView2.setText(AndroidUtilities.replaceTags(formatString(R.string.SmsPremiumActivatedText, country))); + } else { + finalTextView2.setText(AndroidUtilities.replaceTags(getString(R.string.SmsPremiumActivatedTextUnknown))); + } + layout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 30, 0, 30, 16)); + + LinkSpanDrawable.LinksTextView linkTextView = new LinkSpanDrawable.LinksTextView(context, resourcesProvider); + linkTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + linkTextView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText, resourcesProvider)); + linkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + linkTextView.setGravity(Gravity.CENTER); + linkTextView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + linkTextView.setText(AndroidUtilities.replaceSingleTag(getString(R.string.SmsPremiumActivatedText2), () -> { + sheet.dismiss(); + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment != null) { + lastFragment.presentFragment(new SMSStatsActivity()); + } + })); + layout.addView(linkTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 30, 0, 30, 24)); + + ButtonWithCounterView button = new ButtonWithCounterView(context, resourcesProvider); + button.setText(getString(R.string.OK), false); + layout.addView(button, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 14, 0, 14, 0)); + button.setOnClickListener(v -> { + sheet.dismiss(); + }); + + sheet.setCustomView(layout); + + sheet.show(); + + final FireworksOverlay fireworksOverlay = new FireworksOverlay(context); + sheet.getContainer().addView(fireworksOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + fireworksOverlay.postDelayed(() -> { + fireworksOverlay.start(true); + }, 720); + sheet.setOnHideListener(v -> { + fireworksOverlay.animate().alpha(0).start(); + }); + + return sheet; + } + + private static LongSparseArray> permissionsCallbacks; + public static void requestSMSPermissions(Context context, Runnable whenDone, boolean forceOpenSettings) { + if (permissionsCallbacks == null) { + permissionsCallbacks = new LongSparseArray<>(); + } + Activity _activity = AndroidUtilities.findActivity(context); + if (_activity == null) _activity = LaunchActivity.instance; + if (_activity == null || whenDone == null) return; + final Activity activity = _activity; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + final boolean hasSMSPermission = activity.checkSelfPermission(Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED; + final boolean hasPhonePermission = activity.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED && activity.checkSelfPermission(Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED; + if (hasSMSPermission && hasPhonePermission) { + whenDone.run(); + return; + } + if (activity.shouldShowRequestPermissionRationale(Manifest.permission.SEND_SMS) || activity.shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE) || activity.shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_NUMBERS) || forceOpenSettings) { + int messageResId; + if (!hasSMSPermission && !hasPhonePermission) { + messageResId = R.string.SmsPermissionTextSMSPhoneSettings; + } else if (!hasSMSPermission) { + messageResId = R.string.SmsPermissionTextSMSSettings; + } else { + messageResId = R.string.SmsPermissionTextPhoneSettings; + } + new AlertDialog.Builder(activity) + .setMessage(AndroidUtilities.replaceTags(getString(messageResId))) + .setPositiveButton(LocaleController.getString("Settings", R.string.Settings), (dialog, which) -> { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", activity.getPackageName(), null); + intent.setData(uri); + activity.startActivity(intent); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .setOnDismissListener(dialog -> { + + }) + .setTopImage(R.drawable.permissions_sms, Theme.getColor(Theme.key_dialogTopBackground)) + .show(); + } else { + new AlertDialog.Builder(activity) + .setMessage(AndroidUtilities.replaceTags(getString(R.string.SmsPermissionText))) + .setPositiveButton(LocaleController.getString(R.string.Next), (dialog, which) -> { + final int requestCode = (int) (1000 + Math.abs(Math.random() * (Integer.MAX_VALUE - 1000))); + permissionsCallbacks.put(requestCode, success -> { + if (!success) { + requestSMSPermissions(context, whenDone, true); + } else { + whenDone.run(); + } + }); + activity.requestPermissions(new String[] { Manifest.permission.SEND_SMS, Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_PHONE_NUMBERS }, requestCode); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .setOnDismissListener(dialog -> { + + }) + .setTopImage(R.drawable.permissions_sms, Theme.getColor(Theme.key_dialogTopBackground)) + .show(); + } + return; + } + whenDone.run(); + } + + public static boolean checkSMSPermissions(int requestCode, String[] permissions, int[] grantResults) { + if (permissionsCallbacks != null) { + Utilities.Callback callback = permissionsCallbacks.get(requestCode); + if (callback != null) { + permissionsCallbacks.remove(requestCode); + boolean granted = true; + for (int i = 0; i < grantResults.length; ++i) { + if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { + granted = false; + } + } + final boolean finalGranted = granted; + AndroidUtilities.runOnUIThread(() -> callback.run(finalGranted)); + return true; + } + } + return false; + } + +} diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/large_sms_code.png b/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/large_sms_code.png new file mode 100644 index 0000000000000000000000000000000000000000..33b6a24578db0908be09639b744232491d5dc80c GIT binary patch literal 2350 zcmZ`*c{~#i8{dV6naN$UOp>D{%AI3NbIa{To3L4knj?3vq|}loN7`tya#XIl&m#8` zi4GG+j0)xU(;x5q{_%d^KfcfR`#jJ0^ZfZd&n+7(Qy9NAKL7xLVb7y4?6K!xKzaA# z3kI*y9s#diFf|60^d6ksOVHlVSRYGEfYP3Z0)RJt0g%6zJxK2X007f~0Pr3I|JG=r z|8zZR;Q#8sM!vqBy?M|_ShSIS7?7LeTXe`yvOQvaPzfWE=SnuhmbkjY@~B8sK`Kc) zfkGKIppEeQD^7yxR0xdDkTuhw5~G-FhQ3(Rhs4pU@?mPgpViH;y%tt|Q5kcay*ZhG z9xu!9MvQ24uJ82e60$SLi?b#AVhK&BCZv7{hVklwbAkVx(ioD&uCc5O%=dgUy%0hy z*eHhbjNHE_i{lB~uM%+i^7uJti)P^GX4ph1g%OG6aKr`$B)>?gbfj&oN1e6sm_a3! z$wJ=#1}vo?mV>*%wNNeJ3kx2G+|MyPnzi2|({xhmrC`x10g>d4M_`Q;=(zUPt|eg2 zsI^OIZ8RDG0l-@u%ZvSut4w8!cQv z8z%emGMJyZuPzDi?+^B8Rg1=-tyoMx91wo|t3Zt)aJkvXy!2e!lc1lz(-Ga+CknAjLM z3@SH8&>o;$X4NQb_DF3H3E|(6fxP%NH(Y16ZL5QvWt1t7Yt!FXd9Usm?qvTVwp#5c zv&Jrk1=a7F**%TSQ#ZGYr@k6T>a%5_{z&dyW|tVuIBwnzj+6-Gy}+avQH)Rl%vu+ z+sC0|_^@^ehT$CA_B&T*8&f7PLuaGXiOcA>J@{t`A*iK%X%5PMI3ywHI<|3*O^Oe! zvHcN&5lA&B_rnD_WUCbhM^-TkNdOsm{ZO-PTTOTdKtEI#6^3bJyWNEMI z_8L@9xDe0&V6=W`zKNSDaa3Cy`Nw{8hO&HM?#qNHEj+Ctz9vEh&JmlAFipQE+Gc+h ztr2NUka}dx-nfyj%CpJS23If;Ckrhnd;r^dYRkoBr(PX7nqB3TIJ43GMYJ=TmpgG{ zuw5ho@JvvieoaaBp5{dr(34pF(^9!Qu}7Z0PCn5gL83ja{ZFej)5N)Flx~H5(PU&g zS!$-1DL1`mOnq#0u65P-txvYGBArKh6*mquAKh=BbnO2l&3qlJo z=~c%|{`K9g{7INf03k6D;$;EK@^bHJBKY>}K4d+&G9Lk_2|jxM z9YoTtvubt3{FygLz*>{uxX$_Gn@$&dZ}Jv#;R-iCyB)~p?BwWxepQeLmO=X5@MC># ztdSljN^OxOY+#Zbd+9Cfv{vc1_BF`U`JhRzI3o04b1e#wwLwY2XuUSijmU$d^Ojok zHB@t*Aar7_kr!z_(y8l}>rEr8gEu^!08u9HRx7L^uj)9tX~rV-{34hh>Uh{er@QEa zM{*t-zKwM63ksgn(}Rl1@(F>4r{qf9&n3c}|KNg!m3F#%b389J9%JB54QZ!+%9_0T zI~2HzB@%ugjb+2DLq&uJ_7Tj@L`)v+M72DmA&%OkoUUB4287eTzD`R(iMLvfah8;4 zzul&;f|4{Bph>qc`f^l$5X{iqhP8zLK5F_{AEpeZYwT#4wwUq?S3RhS4!!sNjnvX~ zf*mo&A@y{21FOrcr>$@|qg?!3t+1Fyca?3lV3Ne& ztAqyim_rDu6!i_ryY$=nEl6Yfx@Fw=tkTx;;e3tNm7w+Z8f4OJKAd1hNn6RNM&)V8 z(Y=**>SbS6ygUPQ4c#LCem=n_m5zU^hvWqwc)t*s<$)g`cnqkHM=QWlf*n z6$A%h&hUsRT=o}QWv@@Cw4Zz&&YiGT1J9PP;jmZjWbD{=IxcYLiGtAaGdvl^) z!|DC1679tLVM2<~+FNgL#i&0Z*-U<(pLCbGsi$9?ehgFD8%xKl;sQmi-6b{#4LI^P zi@x}xo9(%{LFN|9`jt-=BeN(v4kUfy^rx?{wVfzrP9=V}&j;#>M>u D4;e<@ literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_feature_gift.png b/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_feature_gift.png new file mode 100644 index 0000000000000000000000000000000000000000..77b6e7547e63ef61ce31414750bfbb82feaa3c69 GIT binary patch literal 1188 zcmV;V1Y7%wP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz14oO5oR9Fe!ms^NUQ5eV1F&Ot- z?sAEyG0LrwC`O1}UnG=L5)Uq=TvC#^5f2{RBg!r1h47$>DUsWxJjl3B9=s5d`}O$! z_u1dE_CEW}oW0GI{OdR0+TZ%tx4yIXWvxl2{xPMCsV9@kOe1b3RKR<<1*g*K^lfaO zh#!x0F^q$b@Bj`Fe+Bz@BKZdR31R)haU6Qt47B^eNr;kithd-gw!sx5!4L-4K?&T1 zv(N?R!*GzEKqa(*tDrH`eK-g2U?FI=enJ^5RgaA?3R>d-)Q{M9mVtH)SOK3wdJ6Sw zpii(IazB=K2e4QbmrNv?3DOVf6wZRL625>*lTM0=>x$oQyPn5nB1t!R3(~%*Ecmy3 zz1cro3&b4sW8PqO%ae-)Tl{1)RiI}jC$49x!`GBt2Mv6>wY#hnyV31W)Fw#@oOY7l zr9B7QgI4eim`>5q?a?zc7iz(Df`(p>29_D-yJ zYw0!p+VQ@LLf>G-tWR1S}m#{Q+7r?c(AEjI}`8Ye2^llTHE;;i5Sl zTSwc@NBTi~Km{nT=8%qB?mSE9MlU3jsm|+k9K`g5DKHXBVG!&GSJhl}b%q6+^r>G8 zY`ESt6o@S1g8TiFu$Lqoiq$Py1a2&sA6oK`}UcyQJbhBR!6U`jwn(+Xk+XHdqD?zX-w9{`iRNFgKwY@pT5eCNt>@egf*bEbVKS%=PYOq)w~1^ADJmi$I+Zo>suCwK;Gq6z-*G`|7(@$h(6z_W<}0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz1IY~r8R9Fe^msyC8VHC%G_Kxdz2(R^ld<86Iw;n3pe!$#)~)GaPU5m}W=agcp*UkiXzG zN0T&3@yOdxqhW|gL%kbaJleQFF}?6JbGh7cYy|X}LGT#-1@FMu@RhUjZCpi<8;ql% zNqeX@Aq%b{O8W}+wO-HC2+bMT(XOcW4iVfe?7D%0XI0}ZpGRflGY-~q1~oJ@C`2V3mEIuuRWmoxmX|ZJZRX7(>7L^5~OC6 zYfu@M5q}PsgyXSeggN*C3j1P38G_X6#TUNAHY&l6f_tIx7|w=T#gl$Sz?jHkKSIc)G@B<|R*XuPu* ztx4F@NWXrWW9x9<8(WWY7Gpy_jei^NDYjYb?zDw^=E7KO;#=ag;5`W(oEfAGL;S02lH%Kxb0(F}WS{D4JLAfDzF|v%cfvT6FV@dr$kv(5E z(P=g*K3@T?( zO&L@VK|Rwy@1#qmaJ4#wpgn9UO#C2}a~glYBNQO@09bp3O}VJa002ovPDHLkV1h)7H6#E4 literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_feature_sms.png b/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_feature_sms.png new file mode 100644 index 0000000000000000000000000000000000000000..139dc1f5b0669753ec2accadcc6157a7f528f72d GIT binary patch literal 1459 zcmV;k1x)&hP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz29Z5t%R9Fe+mtBZeRTRhX9Vac* z(lN|2n!>b?u_6h?vdqz! zX)tcI<%%OMz@W3}bDeQ9`b?Mtk|8((2ca82gq_7=@eq1+!oXAEP4K}Aw70`ZWrz-s z`qR)ZLWA2`U7vL%Y|X+7convp{{qwBq4n)Qh5euz8Gvap9nOXpSZcOr)#U~nkHJEB z3`_GZ0+0mWf%asW>2@tmu4bbN#(OU9SKv>W?Y>-1(iB(;0StmfIso~n=60?Tpznjw z3ob`#bV5^ZSAwS(+3M zNu%AIJ(Zq;*f^L0siQ{zy!@=6-04uZknw4jeg?^1b=L7_(_52;NSFif;M4i^E&PJL z0qWouY<;WO(6L}^!TyTA4^DzjpuT;epS+gAS+qmpoI6gV)67MoCgB)JuCajo-;La* zo8+Lq0=nQ_*a$A+F@Q1K9q0~NWp;qpu6-VK!abRB+VDww>iN*3J=GGvPbSjdXZBk1 zPSE~uh)@SHt+In@T!w(REL^Gtd_r461ztB3%Qs*J|0*jx}1I;u;D!mu*boeH~8h8VA zC`uNBKhTY|<=+O9Ya>*e|00tF6bZv-*q}3QLOmhd^ zO1s^H$+dPE-wwDP_Q2N=3jHsIhcG^)|2p(lQKXRUFIS`a57&`6gyHXct_56aO}t0Z z*I@%~tpiDSq~cGXjUe_!jjK`5z;5gRti^Ymb~WD`(Y8bKOCa%|Ul_;M8v0xTM7wx5 ztW^-LZD0FG187ZM5Bizwe!U;o!9>^!T04?`umw`PKlV2u(QJmrTOvDL3ulDR#0N1Q zBf2}M1fTC?RsG~?9i9WJja8lSEdq%ix+yF~LmQo*Uh;gZ`oC;2-bdl6{2Eh3;aqJ2 zJ!yErrV_@$pzdM_uO2E#`!aCxbrg++SLJ0chGqq@bw2jM##Evk z1e!scoTLkU$Muv^Y3dzRVWe%?g-F%{|6RS1PoUz$9dXz~Tx_nz9NNPgTp z_SMeL&!EN?px5LxV`W1%$fw@IlWNR|x%c&>2>?XDJ_lyx-8)x@-fzCKsK3n_(H8mK`HylW;#svl#6)XqcZBq9g9|?au=o(x7H6=Rez|6`J zj-Aj7(Z2%kFhWg#eUUlUy2Xo6NhIrEflhNR)?U!vrk5+q0Q&zae*+ytdPwRTK}!Gt N002ovPDHLkV1oG5mZbmy literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_intro.png b/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/menu_intro.png new file mode 100644 index 0000000000000000000000000000000000000000..1fed265343e2433b3e5ceaf5fce1d2f70a758c6e GIT binary patch literal 603 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/permissions_sms.png b/TMessagesProj_AppStandalone/src/main/res/drawable-hdpi/permissions_sms.png new file mode 100644 index 0000000000000000000000000000000000000000..544ca2fc91240e9cce193e30ebcd56b0d2e95cf4 GIT binary patch literal 2537 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/large_sms_code.png b/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/large_sms_code.png new file mode 100644 index 0000000000000000000000000000000000000000..4a593b2ddce9954c1ba14ffceb440045bf1e7cca GIT binary patch literal 1560 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 KT-G@yGywn~wL|j& literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_feature_sms.png b/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_feature_sms.png new file mode 100644 index 0000000000000000000000000000000000000000..0f00290405e52331ae1e8df32d51708e35a58c23 GIT binary patch literal 848 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfoYegi(`lf z@7$^J8GV5=$8B%%oIdog+emlIr10PqqTYc{J3pywZ@qS6)}g4Kx1XNk6`vBO-Kk_!g;pu_uq@Jy?6hA@wwu8-{%~kJ-z+MzIew- z=8(flKN#a5Y<*t2`Nf~sgJy@=N*8=T$gxCW?jMy3S(BBox|hak7RhGMclmvR%XGoi zxaQ>_WYrc3U2_m#)5>bV>7Sr|r1j?NhZa52DcRmdT&0{lI44Oblqp>D*dV@4QQ+p@ ziHmsnN<|Bs~XQg4@hD!2M6^(WU)Z_U+Or$3&pG+ zntwT%HDgQNnrky3Fqz(eCVWA0;+Yrii~kE=Wz$vo&Eg@~yzQmQoyMH4Uj7H2d?!q4 zUvr6n^Q(K2Oj2)TWY{{T@|xA&Hv?s_AGQ{KIZ-uj>5HWwm`W~8y1-NISbzU%0naLj z_ZnfVCw5kUU@SR0%zX;)?FS(?asAKK?};K{}fZG6j7O7 z+>?3fifLomx`WIYB_&yk*L6MP*}_~e;?`u*y6bl7=6&rd&t2pfJKRgU!&GZlD!gQY ze96VXP5%!$q#E#vi@LskU(NZ?LBZ>83tK+V%eFsX-p00i_>zopr00FmaYybcN literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_intro.png b/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_intro.png new file mode 100644 index 0000000000000000000000000000000000000000..6072f66ee6020e5fa510abc08f86abbf932a5bb5 GIT binary patch literal 522 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfti;pBF~o!S z?bOwN%z*-J<&1}Y6}(yZIO_8CD|j^B{Jz3@3s>C2$hbxG7F>`J5n@qvWZ-OjI=d|0 z`pwP)k6nG9|IW>s`7{08+Vst9l21B+UA^j-$~M8S?SJGe=k4EK^G~sryMTY6!zzz; z1zlxVO+)s^>4Uaq~={dnJ}S!>@Mm%Nd6CS~eJ$s611`fHERyI=9gID7-+MOy`S z+0zr1wm)#-na^_a%&W%GHx5zX1$*CLz0oI`qcGECV)m@6(7BHuahUzEXTH1sftaV$ z^7IA94|IOrIDW~$c5C0g`m??37Wi4Y#%mmW@#63GJ@L{Te5bEj)RHh?^r8Fv{VE+d z*uKeD&TD_Z-=uQm}gr{an^LB{Ts5mEzQM literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_premium_main.png b/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_premium_main.png new file mode 100644 index 0000000000000000000000000000000000000000..0f578be0d3cc2dd108b56a07cb416475ebd9e525 GIT binary patch literal 728 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfyv3!#WBQ# zck9%H-Xet}$IFAR2#9XZjK?)SRJkKdhJ@#Vqe>iysMz3(;tJo|5|(f^xGTRwLm zO%lGfds#eR(}VC^_grKT&wi-9BUfOHirF$z1D*8A?H`@Ro?rTQ{i>l(gZ_p`PDiJC z|LxfOeMlfZs)019w{Db%%E|&WV!uOoov+ruBn`SNv?Vp|2yTk0T z5`TArY?OAZG25%HlJ7sZXI2=?QSsM|+kiKa}p*8ejvh&uk96+ zw|@J}@S1h~)sNLzqAtF>a&d|`Pd@wGmz^#fIWP1z-;1x_^E}Ar;4eOt!zFu;HJAyW z-yGM(_Th8WhMcQ<7ra+8WG}mDcJ2G8maqE)*37y7arJ_Eax3yp^bYJ=-LZAEU1QF< zfHg7k9^21Z{j61-)uepEZx-v#a0wn>=`C}zF7-53EsF`htbB=mGq2Ix*UuMxwn%zX z(z8mf*T?p*VBlI-r@2Yt3V-ITKDE^F?NR^jtHM1z{xRP&NNf^nSfUC_Ri3VXF6*2U Fng9}eKiU8Q literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_sms_history.png b/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_sms_history.png new file mode 100644 index 0000000000000000000000000000000000000000..7023594a59a6669e439d74cb1a0e9a586e42db0a GIT binary patch literal 768 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# z_v}<(kB~r#w!OY;!ASy6TB0*ua$PuYxhS-((D+Yi(l82Wt@kvlB?gR^UU0ZYllQ;i!r zoEHRq_RP?H?-I>b{XkA*-oaf(^S2-0!19H!{-A=+Cmu=Zn!5&!mp2$@EEYIu@TXy} zV{o5`zwn+W{tGteyKZoI9sbIvhE=Zh?A%U~!;q1*7e=@Zmis^a=$yyKzxPsj3OSjx5_uu%_Luk zeNn4;er5Sd?tqvHUGF2MFW=GIv-)pN7h~2%z2(P*?8ZA5|E|l|#Fdr1-VxMGmY=NTtlJ_hx7~&W|KmKT~k;Cpf zJ^tjqhq=wOvy@Ek{Ejzxe!%C3?#gp se=qlUw!Wm$bC7$-S@*hgzv_?Y-&Id^n38iu1eE$bUHx3vIVCg!0GgaYO8@`> literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_storage_path.png b/TMessagesProj_AppStandalone/src/main/res/drawable-mdpi/menu_storage_path.png new file mode 100644 index 0000000000000000000000000000000000000000..21d5bf31be45bc7076d9667f34ff0cecb175a90c GIT binary patch literal 529 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgftlHDXF~o!S z?bMB4%#H$W?-y~-2-{$=wss4z=G(2JN6xu#^jkYuNv!OamSIA=veFNxHj$=`rLK#f zn?FDID7Q?XyQuZSfpX*BpU=O!mv&gy^XRl=-_CE!5zN(HAiq5Gm(+>Y<(an{Y%AI# zzjY+serxvL?}fxirjL?q4jbM%p#EdcxhHHgf##2Lf7wl(JNa1wr~HOwVO7RmRy+?k zxJ*;wn029@(`Ro{q~R~d7*;lG1HQE|HDk~n(lZg~_AIY@w378s_1=~rp4>h84_FQ7U*DPE z`ng2B;L?8iuze06`oAT=e||(it)}0e@naHu!CZGk{`>tR!ONxMYoEG*+20^ne_^+~ ziJN5cW+&dIVO0^u;uBtPKb0G?vFpTvD{B<5YtIQ6vzys5ZRXx)wL6Dcl6=ba&fZ^e zmOXumYpc0Ir`gHcitxY|@wHb(X1QPa%Xm`!$u{OSGmZPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHzez+vRA>e5m}`htRTRhXbw;Ip z1(i)T!=x74kU^1T`XTL2h(gm#DL;hzAqxtEK9metP!RMI1}c06)zAkGNx@($Fv~}! z5!u5joG6`U(tO}6$MN?2?>YOp@4086d+#*edxBZ;KWp!`)>-?%A7`I^P9`%X)g6KC zU^Ji0m(ub*;7)K07zN6aV+4N+ zJ_76LOjkKK4>%U$ji42r0)r*WrJRieCRXf5lGlTk;57KJM7h;QeK9^|`AIkz90ZjT zwKcaal5xQ#83A6c6ziCF)V4N=@`W46fUPk}D{T^oF}@xQi*slw|IogPVfUL<(S>i zSq}v021&94=Xkd@>Q{hwott)1J|Bz*Z##BdJV4=EU3qEEeMP^VxfXSZVTntED_3f2CT+ph-*oGhs|!EcT?9uL}dZ-EyQ)>cp~Zy>RtGCM1G&xcJ%E)T(kjb^oOJFQaMHx z_r0+bxEc6l6OQ_r1ZrRg(7r8sK{4n%Os)U&4QdtW3v3&L82zG=Xm-@mg2BV4m)#oR zlh2gP+(^XZlwX&@BPX%z#q<-28@B-~`qQSE*&w#V*fpc;fVN02O)I-7Yz7@* zB)AgX2lBRP>aHwh_F8QR^qcT^5VsWEo6=I&vw0aE=rM#TbYb`~E$m9*u~Fm|7p^^) zk)~}o$UCelC}pBE)KogKN4&x%gW+fDFUy#6dC8I&&u|7*VHULK{s^@1r%^f~)kFuh zsTc`oKs6lNN#+6Rw8;qw&3DO*U|t7gAmD41wlHmZX^~!tG{bFM$%I%=i$EIWEF|Xp zh!@O&6R4L|NYyf(Vd-r0<=qNl1 zOaSA6-t5}L^-&|}DBeR3*#<@OIsgGZ)SrM0!Cs(a#SWk!Q2LEBBts(*8G(NQf8wmH T$USm(00000NkvXXu0mjfbx7PX literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/large_sms_code.png b/TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/large_sms_code.png new file mode 100644 index 0000000000000000000000000000000000000000..a2c9dbc27e0126dbfb30f1e3d57caf007f43174a GIT binary patch literal 3467 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 Z{sYvl@-+YCRU!ZY002ovPDHLkV1gS~rab@v literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_intro.png b/TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_intro.png new file mode 100644 index 0000000000000000000000000000000000000000..4a42fdb6ead7e243450e3e70e6446dd5296deff8 GIT binary patch literal 910 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 Dn<1k@ literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_storage_path.png b/TMessagesProj_AppStandalone/src/main/res/drawable-xhdpi/menu_storage_path.png new file mode 100644 index 0000000000000000000000000000000000000000..4bc039d3e29ae2641a1106e7cb9cdb85baad19af GIT binary patch literal 938 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 O04+6rRHX{~#s2^if%Rno literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_feature_gift.png b/TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_feature_gift.png new file mode 100644 index 0000000000000000000000000000000000000000..1633928296e279b00f7bdf3ac15839d27cebbac5 GIT binary patch literal 2236 zcmV;t2t)UYP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS@CP_p=RCodHnpuogMHGf-aKR0g zL5-*=kf10K0%F`{Q4$Rj2@+8rlqeV@j0*zB2Q^0HgBmsPgvJ-dxJ!^AE+FnE3K|p? z35uwIBp{$DQIzrfp}VaD%4ooaE1~I$ND{`gYx_y0@XBgE}hEnhG?w#@O1n zw6q)n?=mnFoC1ylJHUGI33#osv2hF6vWYQ{$9NPt3-kg_y$Ig~Bhp5X%}B5m$VU`yLO3z4|BC7p(Bn}N2V~3O_l^q;oj%}wkd_{b^PP#D zsP9M{xud^}_T*5Y$ZiIIIQnUuQ$xNp;S=o%;I}~3+u^SR8v}Be{SckPd`P)*@u!GKJ6$#tM`r`d6ksYsRJCaeB)VOJCh`!iL7>HEB0~2ZkE7X%j4Po;FylM{ zErA!DCu|((o(+79zklGTDYoXf_kg9*cFfHBL~PdfF{%?FbKQ^Li8L0E&lYhlg$7y4ZI6N^gV(^Yo;Vc zihbHJ*ts~m77PJ8i#Y&#L6=bQ^*NqA*=B z)c$CEl!JC4d!8I7Q>fp3xp)giadb+z3=H-ewL{)#148qLTiLMX#HP`qkpRX&&nddVoWL z=C_?dbIf<(cTf&>#z^z(FpshJeA@eki2}U#KE?&8v- zNTWIylH?*cQQFGA=qYXIAU($I0xP-CjAxzg&Y#wz<9U1KM_I^J-(O#L&Ln4s-`9>bQce+Z5z-#=IvtZa=O%zI`g! zui7PxUnyyFw;Dy;H{xu%HBlh$p1!1eiAh--)1ii!dDj+5i#JPIY&@shL38~OKcJqP z?aQsG2DU(3Jwx>I@Y;;UU7}5~P78cA2Kk9TK^yUWxfRvG7HBgA+YQ^;HVP)><^}{R zl8^KdspMUBr5RMYs|E!sdWx|R(VK)NNZq37SG*S4+=5lg2KHJ$Gy$zKx;a<Zjr%OQ(*C+jhfey25BCraiq({1TN!!@jx3GFDmPa^ivjW9Mz*t8B{T<^z+0*ww zr^WdT$+1mUprUn9$Y~|{1gy2uEkFyxxVc~#IzxFB7cJ)CRg9`uAPS>{`}={OeupK@ zaC?@;QA|}S5XI@w*jjh^_Cks)L_M(Wo@J3j>!478t>%-U#(Wl}Elz&yi}H;uu9+8z zq{ac=LFH1WXGGN~kljJsLix^#U7hw@ApTz3unu>#b=n(fj|F;*sx{8nz(;4`$M^Qd zr`u{?)_0JOI&5-!mHhxXoym7T*b8*zG7!uJdbC?AdmUsQ#q~2S5Q%RkpiiBkbVSl0 z{@p^{Lp$doeui)ETw8x2-71>!H1|D<<4?Pq|tB2}l%|6&mt zHzT_-C-2F16PS_fSM5?WcMugAWU65MMx0HzmI`EJvHff+Vn&Gz!oG9rZ0zf?YjdzU z7UdLIpe;q(`&YMyRd-#j&|R`Qy0YMFpS+UZX1X+jr^`t$qn_Hi*tJk~$>!+FVhgmO zNPGY1yYm>RtKrvtHy86f0_|dgwK*1v;~w)bqrD#Va;$XRpwHxHb6pO$JF?a^n~ZT6 z#yHdP%IWII90IhAIKenjZptx8I(~>Gf*ggyLJ+GP>8SREErc|hEzF{*(BdZPhMa>t zqny;KY-U_>Qsu>+Gy&K*t+48jl*5Fi$*20;;J6!(rvaTSpPF=#8qr%z94~^$xO288 zjVV=uT&EOElV5kBBhp$X9mH*>C~fsHspVWdV(X|tM+Mqh1^xwN@Dw6gfVv0(0000< KMNUMnLSTY-xF?(d literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_feature_premium.png b/TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_feature_premium.png new file mode 100644 index 0000000000000000000000000000000000000000..4abc668c6ab4d1cbfd66b58097fba967ed267274 GIT binary patch literal 2572 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_intro.png b/TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/menu_intro.png new file mode 100644 index 0000000000000000000000000000000000000000..9a72445a2768a6bcddecc23bc03ed103677ce5d6 GIT binary patch literal 1025 zcmV+c1pfPpP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS;Ye_^wRCodHoWE`qF%ZV@2n2~g zEd>Qgh!XJ(k&rlAD$=BYx8MnQ0qUft2@(wi2`L>tqNSjTlxs-}f?)G~(Vn?j_KweI z@7a4Z(&%<=?|A07Yx^d9&S<2f1eAahPy)pg7^m>8X_^h#xdXimy`9455;lI}+9T-k zcs%~Mgq@2^qX7ZRCM>*wK8HSq-h`GUr*P&o^gZ+)V4d~m9N=t2e?V&y`nsJR5IWg} z?$$!Z;U|6PlOHU>L##D?0Lxp!*2`>o2)8DoLv9g3yD02t`rYv77%@Hea6Qn*_pM8{)D;xOD3D<4CloTD_@}W z8A{*hW#896s2r9ypr`W|ar`0Z;sP7dcPo|?oHGmXiZo1^KHRXb=4w@|*uL}IKV$TY z1c7)^WhC$m`G^CT@2(h)X$g>NxUL5ZNVxL~NC0$IsE?|~ z(#h4~G4y(rfyFNRjppBwTk-Ed$t5`;ze&%}{T(eD#L`kvVCD8~?c-7_3A z;mu&b$t4G%AU=BcU5YV*epx7V#O)kmjAkG7r4<5i%ouqxYt6fpP`s!;c&oRVm zieL0q0SSl{kOC422-W%o34oF>^XyM^u@35*i*>+ht27sr84agJj!9Z`v99MsbFnTu zZJp*~0g#5$B*z>y6gC%eC?Mf>Dj)?U5D==fU%PpCU0OIbv1L)QaTBVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?pGibPRCodHn|X*;RUF41HMcZN zTZBwZEtg7L{xL8aNl8UW|0rzF)M%rEc3OxQgeWRZ$yBt(7DA}BEEH$-k0_$Z!YtQv z3n?wd7Bihb-|1aB?>Fb%x%a(yXXeekAAGsz{LXKGcRBam^V+qmP^AKu3REi4d=;o_ zKG*r4>+0&xf-?XprY%)fRh#l9+F*~Ov9m-KN@hP6NshOf z(_d~K!t-5%n)>y!8jPk~0*M3EWcky~NqT2-Hf2ZN&~@!C+5$kiHI=?)Ibmpz~4 z=9q-lof1k+V;=cAA^EcAlW0$H&?LN#euq$E8UvDXNj7?hbV|){UuuIf_GU08^R~ik${)9}FpC=}naRM?+@w}f zoNJZoPfn`e;^j!D#w4hx(U7EpOBP7SrJAJrEn1F@hPzqi+8?J48of_Ec7~_5)8gbw zYN02wiD?7H#zc>ug=y`y7sps_tc{^xfJ?jR=;_reiQIaFAKip${|*|y z=fOP12&(&7tE`NZ6gl4K$@|z@6`H9r-<5U=H+ zLvC7zsR1tiL#LBBeg=GBI^Tfb*{e{-Omfn6VF9qTI+zxcms#mt|8tI~2Nla~fLwIH zU6aer9^%)Tkbd22)(Z>r$aBLQkxjMft+Ogjq@wI-oak z1-ls>0U>%gWG@XL;{(C^fRjD&N2ReBl*Q1gU~Rxr#MVuGHCP1R0a`=e3hZJ#tRQKc zuhYF-Fqnh`*w9XqeZWUw!aO!xPG~Y-41=0Cya3W9jCi9Ydo@63Sl9R{l8s{LF7Pk# z(c3Uf;>Q~e#zz6){vKa2aXj5?o&p2CjtXF6OE=>Mz(=~IA1c6XdKDaX26uq3KpN6C z;axBRxbK1KgYalz^LF5){V*qaRI+E`So?V5rUVN38*n$!dQ4`7{Z+t{cF+#Z%xMzC z1n{PfD%by-W9n~UNqqWb@U_y!aghE=KG`PY5x`UvRMdTzM&6Qc)YbCF94+unp1Cr>3a z$y$%)Y7Z|FtC#|fF&+-lUu$^H(ftgkip8aBx6>qTPFwqizotnXCvZY+HNd4E3DmqI z1)V{7)-`S4hKt$~ht1Q#O<V*^e)yBxKk{7~f5T^r-V|5dK!$(ekM|d6_25Ct; z(oOU?1mtvyS}J%x(@h~3~3Jq;>D3{#(gX}&!apw@{!pQr@mk2Uh5FK zK43983PQAnf#BXijRDDoNVesp!TTS)dpt_9XS&UypgvCZ8OJ^$^pbi5(89hpB|QKR zfDq|1{s?GvQv@=a21wSO2GGqT`MMwU0v*Biz!ziDUrQ1d4d?TKkMxTk@eMdUeO2h2 z$dMx?9U$E}lJC$N`-)>O+a^Kim)Z~)sb_2*ywSx*CL2Ju($GePGhGjFkQWa7fn5or z)QaP6phE*A1u|qSXVbTu$xt5YgXWn9x++c$$Nj+vz;{~foBoSH+i)`>Z0mj}AM#~M zF)af{6(@EskuV546|#JFtrFwAwbDIpJShe8+-eK-=fGftC2zu|ky!R4P!Z fK&1k$wF3VEdMV-Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS@A4x<(RCodHn`wwvRT#$|O~*3J z%q^l^Lt6|p3Qg1e5L%QdRE*F{v=2o}U<5HAOh^hewKB*EKeUsDLM}y%LZp=`+GY;! zZJN8{HvRrHci!$ip7-AS-h1vlW6T5px%Zs&JpX5T?>%=pciOaRmDUQhRv^a;ROHB= zh`O$>?hF)rfwKd2WP1c02=IGFMa6OUn?=f6Ac}E5S&jfB!IfYD=nYh)Vxr<~1{=Xz zumY^4XuH^+{z6gugQ?&X<0MV0;|#cGxR; z@ddo%j}pbFqp-Y!(}`eDL}Z^bHo6>9$q$gfVxl-FmLnGZaur}ku}J7&33RVhc9Gw} zKO3hgZg2ChGeI28ak_4}$C=KU*Hg(EL`0|j1I1D7o@-8odA1>(&IB&egsH1oixI^G zicRD*y$6c3YTy!`QWtu6=z&mi0mbK%Y7Z_NC}1B0jyb%nqEGiLEmjmCP@Gnj&zQ`C zL(&!OwCuEh2Hi6|C; z&&pvs^s3^t6U7Y_zm;(%Cj*1-ch*=Y+BGGUm0$q>B%r(BrC>-2rioPHtN~V(XKD9G z7*tsn+M9qLBy$nCF9XLxqwHm8m``W$bp*=8N>xdIuwH8!Xpb+6q(o)-?{N6cqeyyS zwxYL{$pp(`)|&R>WY+1m@X-_e~ zJABNKjT9q2%j`DB$q&C+5Ah24E?1H4G@`ttpCwVa&J;(@De-Cf)xc-&MN(c$&Peo` zg0kx}c&Xp?ld%!YD3IIf2Dh%7R%#-nLwk|2*b-@w^B}S0U8F50-$jurp=|FF7DgJB zVKC1k!M)HFNDBxBXy{B!HX2K@-S1w3iTfvdgnE4w^PU zJ+r9}^8~eGzR&3;F$6Jb|z8}#>CSD%mA*B92&#b z)hgeQ-EnYtqqop@Qqml;@%Eq#mp(An2T-$t>qeIDdeNiG^T7K}=P7yP;ko50nl5^p&(J<=!rxBo2DOW9@q-v(<`#_-gAOO+M|KS?2sB32>;FSoYQA4*E`6JECt8m(KyvW7vOuAQTlV#ba!{w-Jz z-X)H8G5VQ?!*j|hL=-^d>w*17QETr#fc{mxJ%|&%46i1cC2;EDP-^gL zQgXBiv$z83&`v5k74(JZLa>a&l=IVBD|c@CVpVF?1zqmDUQhR-m;4Su5}_Dbt$2MyTepRaYR2bCJ^)czpQEw%ogUt$x3lx<)7JZym@8%Lx)X_gX?#qG) zz7rOx^Gm6?2*)>i2sBA7e!ad#oo8y_UF+M%HzQX)NM5#j)$5PB=ij_bvChp^JJw*B zz$3xzd)i^?i&LwvzG5rNTc23W_jC1;In2gWy;AMkfBbA|neq66-VAov6Zw;Rngus# z&R?hGvUG>-1I-BUnQE2sEoG0|7OY54$kUza`84j)pQJl{(j9Jw>IeHn8qXGJsa)MU zsc5HX@Da@&d)aTv%GkSqXW7FNFZ<0c^inXp1ykFBstMC1*<|k=*uQ*g>s)6)`v{h( zeG7MlL@25##hcH#(rO^5xvB4IjEWqCy)5h5Mb2VQC;V9)9-;09}r^ZS=_WOT^Lr%qt zJLXA^%YJjGt~Td@u`=$CZEB!UMiOV$sS&=5GM7z3$~}6ux!3u zx?uVX>k_APOUykwWu9Dg-r#U9aZWyy?>P~xooiZ_Oq=vTl*Q8Nl<5L_*%Mt8r(Q04 zazb0yM_?cGg9$!fCv~1Xo%=oITqW1RXou-CbNNhDbN2s#+Lg8V1G|HFy@!xmX_Nle zlSL(U9^G%JUvay0FY4Wwh2|U0YgDqVBRt%n|4Gb9s5yS+j^Xt?H|jk39;K;id=a|s zX!Q5bkGdd-1BJ^!U3`3G&DW}!_3@A9|CI2WV3Ts)XsPI03qIA1#fyKswy%2{vXEtK z%;SZ;l8$oAdK8pT9Bw$CqkV$olfeVS+gwIXHarz)T-Pd8y3G}{^~;G`fBfq&)qg+b zq&%l&7ss}{}pn);yfqPEAavwvzIm_B9=Uvr~woy^x)T#6oDt0sOr6rPY{ zA8$8*?~3XP>-&~%m3Evr{TK(t=xt3s3jEA+o7ZBu87{rRgC+H!}EeG&GW@aJ2kvEJ?8Q%bwSUb_G^4%skf|@iOPB5 z`zwD>)PqE}Nh@-cO!==n`#obzRc(|E5Ieaif8RQ9owFKePT0QWl39 literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/permissions_sms.png b/TMessagesProj_AppStandalone/src/main/res/drawable-xxhdpi/permissions_sms.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0221ad33c28ba3645bd856e0ef111b48dacce8 GIT binary patch literal 5587 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 IujUZ*KdkFVWB>pF literal 0 HcmV?d00001 diff --git a/TMessagesProj_AppStandalone/src/main/res/drawable/left_sms.xml b/TMessagesProj_AppStandalone/src/main/res/drawable/left_sms.xml new file mode 100644 index 000000000..82eca4b1c --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/res/drawable/left_sms.xml @@ -0,0 +1,37 @@ + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj_AppStandalone/src/main/res/values/strings.xml b/TMessagesProj_AppStandalone/src/main/res/values/strings.xml new file mode 100644 index 000000000..8fbbb5ba7 --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/res/values/strings.xml @@ -0,0 +1,69 @@ + + + SMS Statistics + + Premium Subscription **for free** + Help Telegram send SMS codes and get a free premium subscription. + + Premium for Free + You are one of **0.01%** users eligible to take part in Telegram\'s **Premium for SMS** initiative! + Help Send Login SMS + Let Telegram use your phone to send %d login SMS per month. + Get Telegram Premium + Receive 1-month **Premium subscription** each month. + Share Premium with Friends + Send gift links granting Telegram subscriptions to your friends. + + I accept the **Terms of Service for P2PLP** + Activate + Sending SMS can result in charges. Please read **Terms of Service for Peer-to-Peer Login Program.** + + Premium for SMS activated! + Telegram will now try to use your device to automatically send SMS codes in your country (**%s**). + Telegram will now try to use your device to automatically send SMS codes in your country. + Check **SMS Statistics** in the left-side menu to see how many SMS have been sent or change settings for this Program. + To join the **Premium for SMS** program, please allow Telegram to send out SMS from your device + To join the **Premium for SMS** program, please allow Telegram to send out SMS from your device.\n\nTap Settings -> Permissions, and turn **SMS** on. + To join the **Premium for SMS** program, please allow Telegram to read phone SIM card info.\n\nTap Settings -> Permissions, and turn **Phone** permission on. + To join the **Premium for SMS** program, please allow Telegram to send out SMS and read phone SIM card info.\n\nTap Settings -> Permissions, and turn **SMS** and **Phone** permissions on. + + %1$d of %2$d SMS Sent + Only **%d** SMS left to send to received your **Telegram Premium** gift link. + + Premium for SMS + Help Telegram send SMS login codes and get **Telegram Premium** gift links. + Insert a SIM card + To join this program, please insert a SIM card into the device to start sending SMS. + Access Required + To join this program, please allow Telegram to send SMS in your phone\'s Settings. + All %d SMS Sent! + Telegram Premium gift-code is sent for you to activate. + + No SIM card + Insert a SIM card into the device and come back to **SMS Statistics**. + + Total SMS Sent + SMS Remaining + Sent Since + Start Date + Last Gift Link Receipt + + Overview + Terms of Service + Benefits of Premium + SMS History + Active SIM + Select SIM card + Also send SMS outside my country + Please refer to your mobile plan for any SMS costs that you may incur + Deactivate Premium for SMS + Deactivate Premium for SMS + Are you sure you want to leave the program? + + Sent SMS History + Here you can see all the SMS automatically sent from your device. + Date and Country + Status + Sent + Failed + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 7f4dade33..9fd925235 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,8 +13,8 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sat Mar 12 05:53:50 MSK 2016 -APP_VERSION_CODE=4365 -APP_VERSION_NAME=10.6.4 +APP_VERSION_CODE=4404 +APP_VERSION_NAME=10.8.1 APP_PACKAGE=org.telegram.messenger RELEASE_KEY_PASSWORD=android RELEASE_KEY_ALIAS=androidkey