From 135e3cc7668457f149b4f5493c2c6e7ac4e70387 Mon Sep 17 00:00:00 2001 From: xaxtix Date: Fri, 3 Feb 2023 23:11:36 +0400 Subject: [PATCH] update to 9.4.0 --- TMessagesProj/build.gradle | 1 + .../config/debug/AndroidManifest.xml | 1 - .../config/debug/AndroidManifest_SDK23.xml | 1 - .../config/release/AndroidManifest.xml | 1 - .../config/release/AndroidManifest_SDK23.xml | 1 - .../release/AndroidManifest_standalone.xml | 1 - TMessagesProj/jni/tgnet/ApiScheme.cpp | 8 +- TMessagesProj/jni/tgnet/ApiScheme.h | 4 +- .../jni/tgnet/ConnectionsManager.cpp | 6 +- TMessagesProj/src/main/AndroidManifest.xml | 4 +- TMessagesProj/src/main/assets/arctic.attheme | 22 +- .../src/main/assets/bluebubbles.attheme | 22 +- .../src/main/assets/darkblue.attheme | 22 +- TMessagesProj/src/main/assets/day.attheme | 22 +- TMessagesProj/src/main/assets/night.attheme | 22 +- .../widget/DefaultItemAnimator.java | 21 + .../telegram/messenger/AndroidUtilities.java | 136 +- .../telegram/messenger/ApplicationLoader.java | 1 + .../telegram/messenger/AuthTokensHelper.java | 119 + .../org/telegram/messenger/BackupAgent.java | 35 + .../telegram/messenger/BillingController.java | 31 +- .../org/telegram/messenger/BuildVars.java | 6 +- .../org/telegram/messenger/ChatObject.java | 217 +- .../messenger/ContactsController.java | 2 +- .../messenger/DatabaseMigrationHelper.java | 6 + .../telegram/messenger/DocumentObject.java | 5 +- .../java/org/telegram/messenger/Emoji.java | 28 +- .../java/org/telegram/messenger/Fetcher.java | 132 + .../telegram/messenger/FileLoadOperation.java | 12 +- .../org/telegram/messenger/FileLoader.java | 96 +- .../telegram/messenger/FilePathDatabase.java | 1 + .../messenger/FileUploadOperation.java | 12 +- .../org/telegram/messenger/ImageLoader.java | 153 +- .../org/telegram/messenger/ImageLocation.java | 23 +- .../org/telegram/messenger/ImageReceiver.java | 112 +- .../telegram/messenger/LocaleController.java | 2 +- .../telegram/messenger/MediaController.java | 1 + .../messenger/MediaDataController.java | 191 +- .../messenger/MessageCustomParamsHelper.java | 32 +- .../org/telegram/messenger/MessageObject.java | 131 +- .../messenger/MessagesController.java | 428 ++- .../telegram/messenger/MessagesStorage.java | 231 +- .../messenger/NotificationCenter.java | 9 +- .../messenger/NotificationsController.java | 12 +- .../messenger/ProxyRotationController.java | 128 + .../messenger/PushListenerController.java | 4 +- .../SaveToGallerySettingsHelper.java | 252 ++ .../messenger/SendMessagesHelper.java | 96 +- .../org/telegram/messenger/SharedConfig.java | 164 +- .../telegram/messenger/StatsController.java | 32 +- .../telegram/messenger/TopicsController.java | 42 +- .../messenger/TranslateController.java | 980 +++++++ .../org/telegram/messenger/UserConfig.java | 60 +- .../org/telegram/messenger/UserObject.java | 22 + .../org/telegram/messenger/Utilities.java | 38 + .../telegram/messenger/VideoEditedInfo.java | 2 + .../telegram/messenger/browser/Browser.java | 21 +- .../messenger/utils/BitmapsCache.java | 26 +- .../messenger/utils/PhotoUtilities.java | 8 +- .../video/MediaCodecVideoConvertor.java | 6 +- .../messenger/video/TextureRenderer.java | 56 +- .../main/java/org/telegram/tgnet/TLRPC.java | 1028 ++++++- .../ui/ActionBar/ActionBarMenuItem.java | 8 - .../ui/ActionBar/ActionBarMenuSubItem.java | 19 +- .../ui/ActionBar/ActionBarPopupWindow.java | 4 + .../telegram/ui/ActionBar/AlertDialog.java | 10 +- .../telegram/ui/ActionBar/BottomSheet.java | 29 +- .../telegram/ui/ActionBar/SimpleTextView.java | 21 +- .../java/org/telegram/ui/ActionBar/Theme.java | 37 + .../telegram/ui/Adapters/DialogsAdapter.java | 117 +- .../ui/Adapters/DialogsSearchAdapter.java | 82 +- .../java/org/telegram/ui/ArticleViewer.java | 53 +- .../java/org/telegram/ui/BubbleActivity.java | 4 +- .../ui/CacheChatsExceptionsFragment.java | 7 +- .../org/telegram/ui/CacheControlActivity.java | 149 +- .../org/telegram/ui/CachedMediaLayout.java | 6 +- .../org/telegram/ui/CalendarActivity.java | 32 +- .../org/telegram/ui/Cells/AboutLinkCell.java | 8 +- .../org/telegram/ui/Cells/BotHelpCell.java | 85 +- .../org/telegram/ui/Cells/ChatActionCell.java | 74 +- .../telegram/ui/Cells/ChatMessageCell.java | 318 +- .../org/telegram/ui/Cells/CheckBoxCell.java | 19 +- .../org/telegram/ui/Cells/DialogCell.java | 44 +- .../telegram/ui/Cells/DialogsHintCell.java | 104 + .../ui/Cells/DialogsRequestedEmptyCell.java | 177 ++ .../telegram/ui/Cells/DrawerActionCell.java | 7 +- .../telegram/ui/Cells/DrawerProfileCell.java | 13 +- .../org/telegram/ui/Cells/DrawerUserCell.java | 11 +- .../telegram/ui/Cells/ProfileSearchCell.java | 80 +- .../ui/Cells/RequestPeerRequirementsCell.java | 297 ++ .../ui/Cells/SharedPhotoVideoCell2.java | 3 + .../telegram/ui/Cells/StickerSetNameCell.java | 14 +- .../java/org/telegram/ui/Cells/TextCell.java | 103 +- .../org/telegram/ui/Cells/TextCheckCell.java | 32 +- .../org/telegram/ui/Cells/TextCheckCell2.java | 69 +- .../telegram/ui/Cells/TextSettingsCell.java | 38 +- .../ui/Cells/ThemePreviewMessagesCell.java | 3 + .../telegram/ui/ChannelCreateActivity.java | 112 +- .../java/org/telegram/ui/ChatActivity.java | 752 ++++- .../org/telegram/ui/ChatEditActivity.java | 30 +- .../telegram/ui/ChatRightsEditActivity.java | 464 ++- .../org/telegram/ui/ChatUsersActivity.java | 457 ++- .../ui/ChatsWidgetConfigActivity.java | 2 +- .../telegram/ui/Components/AlertsCreator.java | 101 +- .../ui/Components/AnimatedEmojiDrawable.java | 70 +- .../ui/Components/AnimatedFileDrawable.java | 5 +- .../telegram/ui/Components/AnimatedFloat.java | 8 + .../ui/Components/AnimatedTextView.java | 228 +- .../ui/Components/AttachBotIntroTopView.java | 4 +- .../ui/Components/AttachableDrawable.java | 8 + .../ui/Components/AudioPlayerAlert.java | 3 +- .../Components/AvatarConstructorFragment.java | 1395 +++++++++ .../AvatarConstructorPreviewCell.java | 217 ++ .../ui/Components/BackupImageView.java | 9 +- .../ui/Components/BotKeyboardView.java | 23 +- .../ui/Components/BotWebViewSheet.java | 64 +- .../org/telegram/ui/Components/Bulletin.java | 10 + .../ui/Components/BulletinFactory.java | 26 + .../telegram/ui/Components/CacheChart.java | 301 +- .../telegram/ui/Components/CanvasButton.java | 5 + .../ui/Components/ChatActivityEnterView.java | 301 +- .../ui/Components/ChatAttachAlert.java | 153 +- .../ChatAttachAlertDocumentLayout.java | 2 +- .../ChatAttachAlertPhotoLayout.java | 283 +- .../ChatAttachRestrictedLayout.java | 154 + .../ui/Components/ChatAvatarContainer.java | 2 +- .../org/telegram/ui/Components/CheckBox2.java | 37 +- .../telegram/ui/Components/CheckBoxBase.java | 2 +- .../Components/CircularProgressDrawable.java | 2 +- .../telegram/ui/Components/ColorPicker.java | 9 +- .../DrawingInBackgroundThreadDrawable.java | 4 +- .../ui/Components/EmojiPacksAlert.java | 309 +- .../ui/Components/EmojiTabsStrip.java | 62 +- .../org/telegram/ui/Components/EmojiView.java | 1602 ++++++---- .../ui/Components/ForwardingPreviewView.java | 2 +- .../ui/Components/FragmentContextView.java | 4 +- .../ui/Components/GestureDetector2.java | 4 +- .../telegram/ui/Components/GradientTools.java | 106 + .../telegram/ui/Components/ImageUpdater.java | 38 +- .../ui/Components/LinkSpanDrawable.java | 4 +- .../ui/Components/LoadingDrawable.java | 5 +- .../Components/MotionBackgroundDrawable.java | 23 +- .../OverlayActionBarLayoutDialog.java | 39 + .../ui/Components/PagerSlidingTabStrip.java | 95 +- .../Paint/Views/LPhotoPaintView.java | 7 +- .../telegram/ui/Components/PasscodeView.java | 21 +- .../Premium/DoubledLimitsBottomSheet.java | 4 +- .../Premium/GiftPremiumBottomSheet.java | 13 +- .../ui/Components/Premium/HelloParticles.java | 221 ++ .../Components/Premium/LimitPreviewView.java | 4 +- .../Premium/PremiumFeatureBottomSheet.java | 7 +- .../Components/Premium/PremiumGradient.java | 15 +- .../Premium/PremiumPreviewBottomSheet.java | 4 +- .../Components/Premium/PremiumTierCell.java | 24 +- .../Premium/VideoScreenPreview.java | 36 +- .../ui/Components/ProfileGalleryView.java | 55 +- .../ui/Components/RLottieDrawable.java | 95 +- .../ui/Components/RLottieImageView.java | 93 +- .../ui/Components/ReactedHeaderView.java | 3 +- .../ui/Components/ReactedUsersListView.java | 2 +- .../ui/Components/ReactionTabHolderView.java | 2 +- .../ChatSelectionReactionMenuOverlay.java | 380 +++ .../Reactions/CustomEmojiReactionsWindow.java | 24 +- .../Reactions/ReactionsEffectOverlay.java | 2 +- .../Reactions/ReactionsLayoutInBubble.java | 2 +- .../Components/ReactionsContainerLayout.java | 51 +- .../ui/Components/RecyclerListView.java | 4 +- .../ui/Components/ScrollSlidingTabStrip.java | 24 +- .../Components/SearchDownloadsContainer.java | 11 +- .../ui/Components/SearchStateDrawable.java | 339 +++ .../ui/Components/SearchViewPager.java | 13 +- .../telegram/ui/Components/SeekBarView.java | 2 +- .../ui/Components/SharedMediaLayout.java | 5 +- .../ui/Components/SimpleThemeDescription.java | 4 + .../Components/StickerCategoriesListView.java | 956 ++++++ .../ui/Components/StickerMasksAlert.java | 2 +- .../Components/StickerSetBulletinLayout.java | 7 + .../telegram/ui/Components/StickersAlert.java | 2 +- .../ui/Components/StorageDiagramView.java | 8 +- .../ui/Components/SuggestEmojiView.java | 306 +- .../ui/Components/TranslateAlert.java | 1803 ------------ .../ui/Components/TranslateAlert2.java | 2603 ++++++----------- .../ui/Components/TranslateButton.java | 262 ++ .../Components/VectorAvatarThumbDrawable.java | 239 ++ .../ui/Components/ViewPagerFixed.java | 2 + .../ui/Components/spoilers/SpoilerEffect.java | 63 +- .../org/telegram/ui/ContactAddActivity.java | 16 +- .../org/telegram/ui/ContactsActivity.java | 13 +- .../ui/ContactsWidgetConfigActivity.java | 2 +- .../org/telegram/ui/ContentPreviewViewer.java | 299 +- .../telegram/ui/CountrySelectActivity.java | 22 +- .../org/telegram/ui/DataSettingsActivity.java | 240 +- .../org/telegram/ui/DataUsage2Activity.java | 1108 +++++++ .../org/telegram/ui/DataUsageActivity.java | 8 +- .../ui/DialogOrContactPickerActivity.java | 7 +- .../java/org/telegram/ui/DialogsActivity.java | 668 ++++- .../telegram/ui/ExternalActionActivity.java | 4 +- .../telegram/ui/FeedWidgetConfigActivity.java | 3 +- .../org/telegram/ui/FilteredSearchView.java | 2 +- .../org/telegram/ui/GroupCallActivity.java | 23 +- .../org/telegram/ui/GroupCreateActivity.java | 5 +- .../telegram/ui/GroupCreateFinalActivity.java | 44 +- .../org/telegram/ui/KeepMediaPopupView.java | 7 +- .../telegram/ui/LanguageSelectActivity.java | 315 +- .../java/org/telegram/ui/LaunchActivity.java | 136 +- .../java/org/telegram/ui/LoginActivity.java | 286 +- .../telegram/ui/NewContactBottomSheet.java | 26 +- .../NotificationsCustomSettingsActivity.java | 7 +- .../java/org/telegram/ui/PhotoViewer.java | 64 +- .../org/telegram/ui/PinchToZoomHelper.java | 4 +- .../telegram/ui/PremiumPreviewFragment.java | 215 +- .../telegram/ui/PrivacyControlActivity.java | 8 +- .../telegram/ui/PrivacySettingsActivity.java | 62 +- .../java/org/telegram/ui/ProfileActivity.java | 159 +- .../org/telegram/ui/ProxyListActivity.java | 168 +- .../ui/RestrictedLanguagesSelectActivity.java | 386 ++- .../ui/SaveToGallerySettingsActivity.java | 663 +++++ .../ui/SelectAnimatedEmojiDialog.java | 1115 ++++--- .../org/telegram/ui/StickersActivity.java | 2 +- .../ui/TextMessageEnterTransition.java | 2 +- .../java/org/telegram/ui/ThemeActivity.java | 18 +- .../java/org/telegram/ui/TopicsFragment.java | 3 + .../telegram/ui/WallpapersListActivity.java | 5 +- .../webrtc/DefaultVideoEncoderFactory.java | 3 + .../webrtc/HardwareVideoEncoderFactory.java | 11 +- .../main/java/org/webrtc/MediaCodecUtils.java | 7 +- .../res/drawable-hdpi/msg_channel_create.png | Bin 0 -> 970 bytes .../drawable-hdpi/msg_download_settings.png | Bin 0 -> 635 bytes .../drawable-hdpi/msg_emoji_activities.png | Bin 932 -> 1136 bytes .../res/drawable-hdpi/msg_emoji_angry.png | Bin 0 -> 870 bytes .../main/res/drawable-hdpi/msg_emoji_back.png | Bin 0 -> 380 bytes .../main/res/drawable-hdpi/msg_emoji_bath.png | Bin 0 -> 884 bytes .../main/res/drawable-hdpi/msg_emoji_busy.png | Bin 0 -> 682 bytes .../res/drawable-hdpi/msg_emoji_dislike.png | Bin 0 -> 789 bytes .../main/res/drawable-hdpi/msg_emoji_food.png | Bin 922 -> 794 bytes .../res/drawable-hdpi/msg_emoji_happy.png | Bin 0 -> 884 bytes .../main/res/drawable-hdpi/msg_emoji_hi.png | Bin 0 -> 1097 bytes .../main/res/drawable-hdpi/msg_emoji_home.png | Bin 0 -> 915 bytes .../main/res/drawable-hdpi/msg_emoji_like.png | Bin 0 -> 813 bytes .../main/res/drawable-hdpi/msg_emoji_love.png | Bin 0 -> 811 bytes .../res/drawable-hdpi/msg_emoji_neutral.png | Bin 0 -> 809 bytes .../main/res/drawable-hdpi/msg_emoji_omg.png | Bin 0 -> 909 bytes .../res/drawable-hdpi/msg_emoji_party.png | Bin 0 -> 1288 bytes .../res/drawable-hdpi/msg_emoji_person.png | Bin 0 -> 974 bytes .../main/res/drawable-hdpi/msg_emoji_sad.png | Bin 0 -> 858 bytes .../res/drawable-hdpi/msg_emoji_sleep.png | Bin 0 -> 680 bytes .../res/drawable-hdpi/msg_emoji_stickers.png | Bin 0 -> 951 bytes .../res/drawable-hdpi/msg_emoji_study.png | Bin 0 -> 1035 bytes .../res/drawable-hdpi/msg_emoji_tongue.png | Bin 0 -> 1035 bytes .../res/drawable-hdpi/msg_emoji_vacation.png | Bin 0 -> 1127 bytes .../main/res/drawable-hdpi/msg_emoji_what.png | Bin 0 -> 1237 bytes .../main/res/drawable-hdpi/msg_emoji_work.png | Bin 0 -> 576 bytes .../drawable-hdpi/msg_filled_autodelete.png | Bin 0 -> 958 bytes .../res/drawable-hdpi/msg_filled_blocked.png | Bin 0 -> 563 bytes .../drawable-hdpi/msg_filled_data_calls.png | Bin 0 -> 604 bytes .../drawable-hdpi/msg_filled_data_files.png | Bin 0 -> 503 bytes .../msg_filled_data_messages.png | Bin 0 -> 767 bytes .../drawable-hdpi/msg_filled_data_music.png | Bin 0 -> 635 bytes .../drawable-hdpi/msg_filled_data_photos.png | Bin 0 -> 556 bytes .../msg_filled_data_received.png | Bin 0 -> 465 bytes .../drawable-hdpi/msg_filled_data_sent.png | Bin 0 -> 501 bytes .../drawable-hdpi/msg_filled_data_videos.png | Bin 0 -> 506 bytes .../drawable-hdpi/msg_filled_data_voice.png | Bin 0 -> 639 bytes .../drawable-hdpi/msg_filled_datausage.png | Bin 0 -> 389 bytes .../res/drawable-hdpi/msg_filled_devices.png | Bin 0 -> 348 bytes .../res/drawable-hdpi/msg_filled_email.png | Bin 0 -> 544 bytes .../drawable-hdpi/msg_filled_passcode_off.png | Bin 0 -> 665 bytes .../drawable-hdpi/msg_filled_passcode_on.png | Bin 0 -> 641 bytes .../drawable-hdpi/msg_filled_permissions.png | Bin 0 -> 648 bytes .../res/drawable-hdpi/msg_filled_plus.png | Bin 0 -> 359 bytes .../res/drawable-hdpi/msg_filled_sdcard.png | Bin 0 -> 525 bytes .../drawable-hdpi/msg_filled_storageusage.png | Bin 0 -> 830 bytes .../res/drawable-hdpi/msg_mini_download.png | Bin 0 -> 412 bytes .../main/res/drawable-hdpi/msg_mini_lock3.png | Bin 0 -> 404 bytes .../res/drawable-hdpi/msg_mini_upload.png | Bin 0 -> 464 bytes .../drawable-hdpi/msg_premium_translate.png | Bin 0 -> 868 bytes .../res/drawable-hdpi/msg_smile_status.png | Bin 0 -> 967 bytes .../res/drawable-mdpi/msg_channel_create.png | Bin 0 -> 703 bytes .../drawable-mdpi/msg_download_settings.png | Bin 0 -> 508 bytes .../drawable-mdpi/msg_emoji_activities.png | Bin 597 -> 754 bytes .../res/drawable-mdpi/msg_emoji_angry.png | Bin 0 -> 618 bytes .../main/res/drawable-mdpi/msg_emoji_back.png | Bin 0 -> 271 bytes .../main/res/drawable-mdpi/msg_emoji_bath.png | Bin 0 -> 641 bytes .../main/res/drawable-mdpi/msg_emoji_busy.png | Bin 0 -> 479 bytes .../res/drawable-mdpi/msg_emoji_dislike.png | Bin 0 -> 561 bytes .../main/res/drawable-mdpi/msg_emoji_food.png | Bin 633 -> 543 bytes .../res/drawable-mdpi/msg_emoji_happy.png | Bin 0 -> 614 bytes .../main/res/drawable-mdpi/msg_emoji_hi.png | Bin 0 -> 683 bytes .../main/res/drawable-mdpi/msg_emoji_home.png | Bin 0 -> 627 bytes .../main/res/drawable-mdpi/msg_emoji_like.png | Bin 0 -> 566 bytes .../main/res/drawable-mdpi/msg_emoji_love.png | Bin 0 -> 568 bytes .../res/drawable-mdpi/msg_emoji_neutral.png | Bin 0 -> 567 bytes .../main/res/drawable-mdpi/msg_emoji_omg.png | Bin 0 -> 642 bytes .../res/drawable-mdpi/msg_emoji_party.png | Bin 0 -> 804 bytes .../res/drawable-mdpi/msg_emoji_person.png | Bin 0 -> 662 bytes .../main/res/drawable-mdpi/msg_emoji_sad.png | Bin 0 -> 596 bytes .../res/drawable-mdpi/msg_emoji_sleep.png | Bin 0 -> 515 bytes .../res/drawable-mdpi/msg_emoji_stickers.png | Bin 0 -> 619 bytes .../res/drawable-mdpi/msg_emoji_study.png | Bin 0 -> 670 bytes .../res/drawable-mdpi/msg_emoji_tongue.png | Bin 0 -> 676 bytes .../res/drawable-mdpi/msg_emoji_vacation.png | Bin 0 -> 720 bytes .../main/res/drawable-mdpi/msg_emoji_what.png | Bin 0 -> 747 bytes .../main/res/drawable-mdpi/msg_emoji_work.png | Bin 0 -> 485 bytes .../drawable-mdpi/msg_filled_autodelete.png | Bin 0 -> 655 bytes .../res/drawable-mdpi/msg_filled_blocked.png | Bin 0 -> 402 bytes .../drawable-mdpi/msg_filled_data_calls.png | Bin 0 -> 434 bytes .../drawable-mdpi/msg_filled_data_files.png | Bin 0 -> 355 bytes .../msg_filled_data_messages.png | Bin 0 -> 545 bytes .../drawable-mdpi/msg_filled_data_music.png | Bin 0 -> 444 bytes .../drawable-mdpi/msg_filled_data_photos.png | Bin 0 -> 420 bytes .../msg_filled_data_received.png | Bin 0 -> 380 bytes .../drawable-mdpi/msg_filled_data_sent.png | Bin 0 -> 389 bytes .../drawable-mdpi/msg_filled_data_videos.png | Bin 0 -> 395 bytes .../drawable-mdpi/msg_filled_data_voice.png | Bin 0 -> 461 bytes .../drawable-mdpi/msg_filled_datausage.png | Bin 0 -> 309 bytes .../res/drawable-mdpi/msg_filled_devices.png | Bin 0 -> 312 bytes .../res/drawable-mdpi/msg_filled_email.png | Bin 0 -> 418 bytes .../drawable-mdpi/msg_filled_passcode_off.png | Bin 0 -> 489 bytes .../drawable-mdpi/msg_filled_passcode_on.png | Bin 0 -> 516 bytes .../drawable-mdpi/msg_filled_permissions.png | Bin 0 -> 490 bytes .../res/drawable-mdpi/msg_filled_plus.png | Bin 0 -> 325 bytes .../res/drawable-mdpi/msg_filled_sdcard.png | Bin 0 -> 401 bytes .../drawable-mdpi/msg_filled_storageusage.png | Bin 0 -> 560 bytes .../res/drawable-mdpi/msg_mini_download.png | Bin 0 -> 338 bytes .../main/res/drawable-mdpi/msg_mini_lock3.png | Bin 0 -> 327 bytes .../res/drawable-mdpi/msg_mini_upload.png | Bin 0 -> 376 bytes .../drawable-mdpi/msg_premium_translate.png | Bin 0 -> 583 bytes .../res/drawable-mdpi/msg_smile_status.png | Bin 0 -> 617 bytes .../res/drawable-xhdpi/msg_channel_create.png | Bin 0 -> 1284 bytes .../drawable-xhdpi/msg_download_settings.png | Bin 0 -> 941 bytes .../drawable-xhdpi/msg_emoji_activities.png | Bin 1413 -> 1663 bytes .../res/drawable-xhdpi/msg_emoji_angry.png | Bin 0 -> 1397 bytes .../res/drawable-xhdpi/msg_emoji_back.png | Bin 0 -> 430 bytes .../res/drawable-xhdpi/msg_emoji_bath.png | Bin 0 -> 1221 bytes .../res/drawable-xhdpi/msg_emoji_busy.png | Bin 0 -> 1114 bytes .../res/drawable-xhdpi/msg_emoji_dislike.png | Bin 0 -> 1079 bytes .../res/drawable-xhdpi/msg_emoji_food.png | Bin 1292 -> 1035 bytes .../res/drawable-xhdpi/msg_emoji_happy.png | Bin 0 -> 1387 bytes .../main/res/drawable-xhdpi/msg_emoji_hi.png | Bin 0 -> 1531 bytes .../res/drawable-xhdpi/msg_emoji_home.png | Bin 0 -> 1190 bytes .../res/drawable-xhdpi/msg_emoji_like.png | Bin 0 -> 1107 bytes .../res/drawable-xhdpi/msg_emoji_love.png | Bin 0 -> 1124 bytes .../res/drawable-xhdpi/msg_emoji_neutral.png | Bin 0 -> 1237 bytes .../main/res/drawable-xhdpi/msg_emoji_omg.png | Bin 0 -> 1439 bytes .../res/drawable-xhdpi/msg_emoji_party.png | Bin 0 -> 1735 bytes .../res/drawable-xhdpi/msg_emoji_person.png | Bin 0 -> 1478 bytes .../main/res/drawable-xhdpi/msg_emoji_sad.png | Bin 0 -> 1339 bytes .../res/drawable-xhdpi/msg_emoji_sleep.png | Bin 0 -> 886 bytes .../res/drawable-xhdpi/msg_emoji_stickers.png | Bin 0 -> 1273 bytes .../res/drawable-xhdpi/msg_emoji_study.png | Bin 0 -> 1360 bytes .../res/drawable-xhdpi/msg_emoji_tongue.png | Bin 0 -> 1512 bytes .../res/drawable-xhdpi/msg_emoji_vacation.png | Bin 0 -> 1542 bytes .../res/drawable-xhdpi/msg_emoji_what.png | Bin 0 -> 1766 bytes .../res/drawable-xhdpi/msg_emoji_work.png | Bin 0 -> 799 bytes .../drawable-xhdpi/msg_filled_autodelete.png | Bin 0 -> 1246 bytes .../res/drawable-xhdpi/msg_filled_blocked.png | Bin 0 -> 825 bytes .../drawable-xhdpi/msg_filled_data_calls.png | Bin 0 -> 762 bytes .../drawable-xhdpi/msg_filled_data_files.png | Bin 0 -> 604 bytes .../msg_filled_data_messages.png | Bin 0 -> 1003 bytes .../drawable-xhdpi/msg_filled_data_music.png | Bin 0 -> 892 bytes .../drawable-xhdpi/msg_filled_data_photos.png | Bin 0 -> 810 bytes .../msg_filled_data_received.png | Bin 0 -> 560 bytes .../drawable-xhdpi/msg_filled_data_sent.png | Bin 0 -> 626 bytes .../drawable-xhdpi/msg_filled_data_videos.png | Bin 0 -> 616 bytes .../drawable-xhdpi/msg_filled_data_voice.png | Bin 0 -> 882 bytes .../drawable-xhdpi/msg_filled_datausage.png | Bin 0 -> 524 bytes .../res/drawable-xhdpi/msg_filled_devices.png | Bin 0 -> 503 bytes .../res/drawable-xhdpi/msg_filled_email.png | Bin 0 -> 830 bytes .../msg_filled_passcode_off.png | Bin 0 -> 859 bytes .../drawable-xhdpi/msg_filled_passcode_on.png | Bin 0 -> 832 bytes .../drawable-xhdpi/msg_filled_permissions.png | Bin 0 -> 829 bytes .../res/drawable-xhdpi/msg_filled_plus.png | Bin 0 -> 441 bytes .../res/drawable-xhdpi/msg_filled_sdcard.png | Bin 0 -> 654 bytes .../msg_filled_storageusage.png | Bin 0 -> 1056 bytes .../res/drawable-xhdpi/msg_mini_download.png | Bin 0 -> 519 bytes .../res/drawable-xhdpi/msg_mini_lock3.png | Bin 0 -> 494 bytes .../res/drawable-xhdpi/msg_mini_upload.png | Bin 0 -> 570 bytes .../drawable-xhdpi/msg_premium_translate.png | Bin 0 -> 1129 bytes .../res/drawable-xhdpi/msg_smile_status.png | Bin 0 -> 1474 bytes .../drawable-xxhdpi/msg_channel_create.png | Bin 0 -> 1811 bytes .../drawable-xxhdpi/msg_download_settings.png | Bin 0 -> 1009 bytes .../drawable-xxhdpi/msg_emoji_activities.png | Bin 2001 -> 2495 bytes .../res/drawable-xxhdpi/msg_emoji_angry.png | Bin 0 -> 1972 bytes .../res/drawable-xxhdpi/msg_emoji_back.png | Bin 0 -> 570 bytes .../res/drawable-xxhdpi/msg_emoji_bath.png | Bin 0 -> 1693 bytes .../res/drawable-xxhdpi/msg_emoji_busy.png | Bin 0 -> 1396 bytes .../res/drawable-xxhdpi/msg_emoji_dislike.png | Bin 0 -> 1528 bytes .../res/drawable-xxhdpi/msg_emoji_food.png | Bin 1896 -> 1294 bytes .../res/drawable-xxhdpi/msg_emoji_happy.png | Bin 0 -> 1950 bytes .../main/res/drawable-xxhdpi/msg_emoji_hi.png | Bin 0 -> 2282 bytes .../res/drawable-xxhdpi/msg_emoji_home.png | Bin 0 -> 1689 bytes .../res/drawable-xxhdpi/msg_emoji_like.png | Bin 0 -> 1528 bytes .../res/drawable-xxhdpi/msg_emoji_love.png | Bin 0 -> 1613 bytes .../res/drawable-xxhdpi/msg_emoji_neutral.png | Bin 0 -> 1629 bytes .../res/drawable-xxhdpi/msg_emoji_omg.png | Bin 0 -> 2020 bytes .../res/drawable-xxhdpi/msg_emoji_party.png | Bin 0 -> 2696 bytes .../res/drawable-xxhdpi/msg_emoji_person.png | Bin 0 -> 1975 bytes .../res/drawable-xxhdpi/msg_emoji_sad.png | Bin 0 -> 1871 bytes .../res/drawable-xxhdpi/msg_emoji_sleep.png | Bin 0 -> 1255 bytes .../drawable-xxhdpi/msg_emoji_stickers.png | Bin 0 -> 1678 bytes .../res/drawable-xxhdpi/msg_emoji_study.png | Bin 0 -> 2056 bytes .../res/drawable-xxhdpi/msg_emoji_tongue.png | Bin 0 -> 2217 bytes .../drawable-xxhdpi/msg_emoji_vacation.png | Bin 0 -> 2370 bytes .../res/drawable-xxhdpi/msg_emoji_what.png | Bin 0 -> 2660 bytes .../res/drawable-xxhdpi/msg_emoji_work.png | Bin 0 -> 976 bytes .../drawable-xxhdpi/msg_filled_autodelete.png | Bin 0 -> 1875 bytes .../drawable-xxhdpi/msg_filled_blocked.png | Bin 0 -> 1103 bytes .../drawable-xxhdpi/msg_filled_data_calls.png | Bin 0 -> 1073 bytes .../drawable-xxhdpi/msg_filled_data_files.png | Bin 0 -> 798 bytes .../msg_filled_data_messages.png | Bin 0 -> 1543 bytes .../drawable-xxhdpi/msg_filled_data_music.png | Bin 0 -> 1317 bytes .../msg_filled_data_photos.png | Bin 0 -> 1097 bytes .../msg_filled_data_received.png | Bin 0 -> 747 bytes .../drawable-xxhdpi/msg_filled_data_sent.png | Bin 0 -> 860 bytes .../msg_filled_data_videos.png | Bin 0 -> 803 bytes .../drawable-xxhdpi/msg_filled_data_voice.png | Bin 0 -> 1279 bytes .../drawable-xxhdpi/msg_filled_datausage.png | Bin 0 -> 579 bytes .../drawable-xxhdpi/msg_filled_devices.png | Bin 0 -> 575 bytes .../res/drawable-xxhdpi/msg_filled_email.png | Bin 0 -> 1042 bytes .../msg_filled_passcode_off.png | Bin 0 -> 1153 bytes .../msg_filled_passcode_on.png | Bin 0 -> 1166 bytes .../msg_filled_permissions.png | Bin 0 -> 1215 bytes .../res/drawable-xxhdpi/msg_filled_plus.png | Bin 0 -> 578 bytes .../res/drawable-xxhdpi/msg_filled_sdcard.png | Bin 0 -> 942 bytes .../msg_filled_storageusage.png | Bin 0 -> 1586 bytes .../res/drawable-xxhdpi/msg_mini_download.png | Bin 0 -> 609 bytes .../res/drawable-xxhdpi/msg_mini_lock3.png | Bin 0 -> 644 bytes .../res/drawable-xxhdpi/msg_mini_upload.png | Bin 0 -> 766 bytes .../drawable-xxhdpi/msg_premium_translate.png | Bin 0 -> 1712 bytes .../res/drawable-xxhdpi/msg_smile_status.png | Bin 0 -> 2077 bytes .../src/main/res/raw/msg_translate.json | 1 + TMessagesProj/src/main/res/values/strings.xml | 213 +- gradle.properties | 4 +- 433 files changed, 22076 insertions(+), 6899 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AuthTokensHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/BackupAgent.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Fetcher.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ProxyRotationController.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/SaveToGallerySettingsHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsRequestedEmptyCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/RequestPeerRequirementsCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/AttachableDrawable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorPreviewCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/SearchStateDrawable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateButton.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/SaveToGallerySettingsActivity.java create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_channel_create.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_download_settings.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_angry.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_back.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_bath.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_busy.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_dislike.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_happy.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_hi.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_home.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_like.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_love.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_neutral.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_omg.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_party.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_person.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sad.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sleep.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_stickers.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_study.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_tongue.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_vacation.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_what.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_work.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_blocked.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_calls.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_files.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_messages.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_music.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_photos.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_received.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_sent.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_videos.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_voice.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_datausage.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_devices.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_email.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_off.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_on.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_permissions.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_sdcard.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_filled_storageusage.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_mini_download.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_mini_lock3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_mini_upload.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_premium_translate.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_smile_status.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_channel_create.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_download_settings.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_angry.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_back.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_bath.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_busy.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_dislike.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_happy.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_hi.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_home.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_like.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_love.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_neutral.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_omg.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_party.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_person.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sad.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sleep.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_stickers.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_study.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_tongue.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_vacation.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_what.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_work.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_blocked.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_calls.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_files.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_messages.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_music.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_photos.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_received.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_sent.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_videos.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_voice.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_datausage.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_devices.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_email.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_off.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_on.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_permissions.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_sdcard.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_filled_storageusage.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_mini_download.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_mini_lock3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_mini_upload.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_premium_translate.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_smile_status.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_channel_create.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_download_settings.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_angry.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_back.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_bath.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_busy.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_dislike.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_happy.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_hi.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_home.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_like.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_love.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_neutral.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_omg.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_party.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_person.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_sad.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_sleep.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_stickers.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_study.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_tongue.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_vacation.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_what.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_work.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_blocked.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_calls.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_files.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_messages.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_music.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_photos.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_received.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_sent.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_videos.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_voice.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_datausage.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_devices.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_email.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_off.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_on.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_permissions.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_sdcard.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_storageusage.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_download.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_lock3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_upload.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_premium_translate.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_smile_status.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_channel_create.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_download_settings.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_angry.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_back.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_bath.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_busy.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_dislike.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_happy.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_hi.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_home.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_like.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_love.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_neutral.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_omg.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_party.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_person.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sad.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sleep.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_stickers.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_study.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_tongue.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_vacation.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_what.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_work.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_blocked.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_calls.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_files.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_messages.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_music.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_photos.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_received.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_sent.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_videos.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_voice.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_datausage.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_devices.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_email.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_off.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_on.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_permissions.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_sdcard.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_storageusage.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_download.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_lock3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_upload.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_premium_translate.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_smile_status.png create mode 100644 TMessagesProj/src/main/res/raw/msg_translate.json diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index f7d331b8b..ee5a84d37 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -36,6 +36,7 @@ dependencies { implementation 'com.google.android.gms:play-services-wearable:18.0.0' implementation 'com.google.android.gms:play-services-location:21.0.1' implementation 'com.google.android.gms:play-services-wallet:19.1.0' + implementation 'com.google.android.gms:play-services-safetynet:18.0.1' implementation 'com.googlecode.mp4parser:isoparser:1.0.6' implementation 'com.stripe:stripe-android:2.0.2' implementation 'com.google.mlkit:language-id:16.1.1' diff --git a/TMessagesProj/config/debug/AndroidManifest.xml b/TMessagesProj/config/debug/AndroidManifest.xml index 92a95c778..b7f49c6f5 100644 --- a/TMessagesProj/config/debug/AndroidManifest.xml +++ b/TMessagesProj/config/debug/AndroidManifest.xml @@ -18,7 +18,6 @@ readInt32(&error); + if ((flags & 2) != 0) { + otherwise_relogin_days = stream->readInt32(&error); + } if ((flags & 1) != 0) { tmp_sessions = stream->readInt32(&error); } + if ((flags & 4) != 0) { + future_auth_token = std::unique_ptr(stream->readByteArray(&error)); + } user = std::unique_ptr(User::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error)); } diff --git a/TMessagesProj/jni/tgnet/ApiScheme.h b/TMessagesProj/jni/tgnet/ApiScheme.h index 8f8a046e2..77a8da911 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.h +++ b/TMessagesProj/jni/tgnet/ApiScheme.h @@ -705,10 +705,12 @@ public: class TL_auth_authorization : public auth_Authorization { public: - static const uint32_t constructor = 0x33fb7bb8; + static const uint32_t constructor = 0x2ea2c0d4; int32_t flags; int32_t tmp_sessions; + int32_t otherwise_relogin_days; + std::unique_ptr future_auth_token; std::unique_ptr user; void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error); diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp index a1a911edd..4e884a118 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -891,10 +891,12 @@ void ConnectionsManager::onConnectionDataReceived(Connection *connection, Native if (object != nullptr) { if (datacenter->isHandshaking(connection->isMediaConnection)) { + if (LOGS_ENABLED) DEBUG_E("process handshake"); datacenter->processHandshakeResponse(connection->isMediaConnection, object, messageId); } else { - processServerResponse(object, messageId, 0, 0, connection, 0, 0); - connection->addProcessedMessageId(messageId); + if (LOGS_ENABLED) DEBUG_E("connection(%p) received incorrect unencrypted message type", connection); + connection->reconnect(); + return; } lastProtocolUsefullData = true; connection->setHasUsefullData(); diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index d350aa887..cd6a7009f 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -84,7 +84,9 @@ = 19) { + oldViewAnim.setUpdateListener(animation1 -> onChangeAnimationUpdate(changeInfo.oldHolder)); + } oldViewAnim .setInterpolator(getChangeInterpolator()) .setListener(new AnimatorListenerAdapter() { @@ -493,6 +509,9 @@ public class DefaultItemAnimator extends SimpleItemAnimator { if (animateByScale(newView) > 0) { newViewAnimation.scaleX(1f).scaleY(1f); } + if (Build.VERSION.SDK_INT >= 19) { + newViewAnimation.setUpdateListener(animation1 -> onChangeAnimationUpdate(changeInfo.newHolder)); + } newViewAnimation .setListener(new AnimatorListenerAdapter() { @Override @@ -512,6 +531,8 @@ public class DefaultItemAnimator extends SimpleItemAnimator { dispatchChangeFinished(changeInfo.newHolder, false); mChangeAnimations.remove(changeInfo.newHolder); dispatchFinishedWhenDone(); + + afterAnimateChangeImpl(changeInfo.oldHolder, changeInfo.newHolder); } }).start(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index 7ab496f9d..639bd502a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -541,6 +541,27 @@ public class AndroidUtilities { recycleBitmaps(Collections.singletonList(image)); } + public static boolean findClickableView(ViewGroup container, float x, float y) { + for (int i = 0; i < container.getChildCount(); i++) { + View child = container.getChildAt(i); + if (child.getVisibility() != View.VISIBLE) { + continue; + } + if (child.isClickable()) { + return true; + } else if (child instanceof ViewGroup && findClickableView((ViewGroup) child, x - child.getX(), y - child.getY())) { + return true; + } + } + return false; + } + + public static void removeFromParent(View child) { + if (child.getParent() != null) { + ((ViewGroup) child.getParent()).removeView(child); + } + } + private static class LinkSpec { String url; int start; @@ -2193,12 +2214,20 @@ public class AndroidUtilities { if (!hasCallPermissions) { return null; } + String order; + Bundle selectionArgs; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + order = "date DESC"; + } else { + order = "date DESC LIMIT 5"; + } try (Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query( CallLog.Calls.CONTENT_URI, new String[]{CallLog.Calls.NUMBER, CallLog.Calls.DATE}, CallLog.Calls.TYPE + " IN (" + CallLog.Calls.MISSED_TYPE + "," + CallLog.Calls.INCOMING_TYPE + "," + CallLog.Calls.REJECTED_TYPE + ")", null, - "date DESC LIMIT 5")) { + order + )) { while (cursor.moveToNext()) { String number = cursor.getString(0); long date = cursor.getLong(1); @@ -2926,7 +2955,9 @@ public class AndroidUtilities { } public static String formatFileSize(long size, boolean removeZero) { - if (size < 1024) { + if (size == 0) { + return String.format("%d KB", 0); + } else if (size < 1024) { return String.format("%d B", size); } else if (size < 1024 * 1024) { float value = size / 1024.0f; @@ -2935,7 +2966,7 @@ public class AndroidUtilities { } else { return String.format("%.1f KB", value); } - } else if (size < 1024 * 1024 * 1024) { + } else if (size < 1000 * 1024 * 1024) { float value = size / 1024.0f / 1024.0f; if (removeZero && (value - (int) value) * 10 == 0) { return String.format("%d MB", (int) value); @@ -3633,7 +3664,7 @@ public class AndroidUtilities { lineView.setBackgroundColor(Theme.getColor(Theme.key_divider)); linearLayout.addView(lineView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1)); } - for (int a = 0; a < 5; a++) { + for (int a = 0; a < 6; a++) { String text = null; String detail = null; if (a == 0) { @@ -3651,6 +3682,9 @@ public class AndroidUtilities { } else if (a == 4) { text = password; detail = LocaleController.getString("UseProxyPassword", R.string.UseProxyPassword); + } else if (a == 5) { + text = LocaleController.getString(R.string.Checking); + detail = LocaleController.getString(R.string.ProxyStatus); } if (TextUtils.isEmpty(text)) { continue; @@ -3660,8 +3694,22 @@ public class AndroidUtilities { cell.getTextView().setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); cell.getValueTextView().setTextColor(Theme.getColor(Theme.key_dialogTextGray3)); linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - if (a == 2) { - break; + + if (a == 5) { + try { + ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(address, Integer.parseInt(port), user, password, secret, time -> AndroidUtilities.runOnUIThread(() -> { + if (time == -1) { + cell.getTextView().setText(LocaleController.getString(R.string.Unavailable)); + cell.getTextView().setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + } else { + cell.getTextView().setText(LocaleController.getString(R.string.Available) + ", " + LocaleController.formatString(R.string.Ping, time)); + cell.getTextView().setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGreenText)); + } + })); + } catch (NumberFormatException ignored) { + cell.getTextView().setText(LocaleController.getString(R.string.Unavailable)); + cell.getTextView().setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + } } } @@ -4664,18 +4712,36 @@ public class AndroidUtilities { return spannableStringBuilder; } + public static CharSequence replaceMultipleCharSequence(String what, CharSequence from, CharSequence obj) { + SpannableStringBuilder spannableStringBuilder; + if (from instanceof SpannableStringBuilder) { + spannableStringBuilder = (SpannableStringBuilder) from; + } else { + spannableStringBuilder = new SpannableStringBuilder(from); + } + int index = TextUtils.indexOf(from, what); + while (index >= 0) { + spannableStringBuilder.replace(index, index + what.length(), obj); + index = TextUtils.indexOf(spannableStringBuilder, what); + } + return spannableStringBuilder; + } + public static Bitmap makeBlurBitmap(View view) { + return makeBlurBitmap(view, 6f, 7); + } + public static Bitmap makeBlurBitmap(View view, float downscale, int maxRadius) { if (view == null) { return null; } - int w = (int) (view.getWidth() / 6.0f); - int h = (int) (view.getHeight() / 6.0f); + int w = (int) (view.getWidth() / downscale); + int h = (int) (view.getHeight() / downscale); Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); - canvas.scale(1.0f / 6.0f, 1.0f / 6.0f); + canvas.scale(1.0f / downscale, 1.0f / downscale); canvas.drawColor(Theme.getColor(Theme.key_windowBackgroundWhite)); view.draw(canvas); - Utilities.stackBlurBitmap(bitmap, Math.max(7, Math.max(w, h) / 180)); + Utilities.stackBlurBitmap(bitmap, Math.max(maxRadius, Math.max(w, h) / 180)); return bitmap; } @@ -4808,4 +4874,54 @@ public class AndroidUtilities { return output; } + + public static boolean isRTL(CharSequence text) { + if (text == null || text.length() <= 0) { + return false; + } + char c; + for (int i = 0; i < text.length(); ++i) { + c = text.charAt(i); + if (c >= 0x590 && c <= 0x6ff) { + return true; + } + } + return false; + } + + private static Pattern uriParse; + private static Pattern getURIParsePattern() { + if (uriParse == null) { + uriParse = Pattern.compile("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"); // RFC 3986 B + } + return uriParse; + } + + public static String getHostAuthority(String uri) { + if (uri == null) { + return null; + } + // CVE-2017-13274 + Matcher matcher = getURIParsePattern().matcher(uri); + if (matcher.matches()) { + String authority = matcher.group(4); + if (authority != null) { + authority = authority.toLowerCase(); + } + return authority; + } + return null; + } + + public static String getHostAuthority(Uri uri) { + if (uri == null) { + return null; + } + return getHostAuthority(uri.toString()); + } + + public static boolean intersect1d(int x1, int x2, int y1, int y2) { + return Math.max(x1, x2) >= Math.min(y1, y2) && Math.max(y1, y2) >= Math.min(x1, x2); + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index d449fc068..194ff0ca7 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -278,6 +278,7 @@ public class ApplicationLoader extends Application { AndroidUtilities.runOnUIThread(ApplicationLoader::startPushService); LauncherIconController.tryFixLauncherIconIfNeeded(); + ProxyRotationController.init(); } public static void startPushService() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AuthTokensHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/AuthTokensHelper.java new file mode 100644 index 000000000..045670cba --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AuthTokensHelper.java @@ -0,0 +1,119 @@ +package org.telegram.messenger; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.google.android.exoplayer2.util.Log; + +import org.telegram.tgnet.SerializedData; +import org.telegram.tgnet.TLRPC; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class AuthTokensHelper { + + public static ArrayList getSavedLogOutTokens() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); + int count = preferences.getInt("count", 0); + + if (count == 0) { + return null; + } + + ArrayList tokens = new ArrayList<>(); + for (int i = 0; i < count; i++) { + String value = preferences.getString("log_out_token_" + i, ""); + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + TLRPC.TL_auth_loggedOut token = TLRPC.TL_auth_loggedOut.TLdeserialize(serializedData, serializedData.readInt32(true), true); + if (token != null) { + tokens.add(token); + } + } + + return tokens; + } + + public static void saveLogOutTokens(ArrayList tokens) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); + ArrayList activeTokens = new ArrayList<>(); + preferences.edit().clear().apply(); + int date = (int) (System.currentTimeMillis() / 1000L); + for (int i = 0; i < Math.min(20, tokens.size()); i++) { + activeTokens.add(tokens.get(i)); + } + if (activeTokens.size() > 0) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("count", activeTokens.size()); + for (int i = 0; i < activeTokens.size(); i++) { + SerializedData data = new SerializedData(activeTokens.get(i).getObjectSize()); + activeTokens.get(i).serializeToStream(data); + editor.putString("log_out_token_" + i, Utilities.bytesToHex(data.toByteArray())); + } + editor.apply(); + // BackupAgent.requestBackup(ApplicationLoader.applicationContext); + } + } + + public static ArrayList getSavedLogInTokens() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens_login", Context.MODE_PRIVATE); + int count = preferences.getInt("count", 0); + + if (count == 0) { + return null; + } + + ArrayList tokens = new ArrayList<>(); + for (int i = 0; i < count; i++) { + String value = preferences.getString("log_in_token_" + i, ""); + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + TLRPC.auth_Authorization token = TLRPC.auth_Authorization.TLdeserialize(serializedData, serializedData.readInt32(true), true); + if (token instanceof TLRPC.TL_auth_authorization) { + tokens.add((TLRPC.TL_auth_authorization) token); + } + } + + return tokens; + } + + public static void saveLogInToken(TLRPC.TL_auth_authorization token) { + if (BuildVars.DEBUG_VERSION) { + FileLog.d("saveLogInToken " + new String(token.future_auth_token, StandardCharsets.UTF_8)); + } + ArrayList tokens = getSavedLogInTokens(); + if (tokens == null) { + tokens = new ArrayList<>(); + } + tokens.add(0, token); + saveLogInTokens(tokens); + } + + private static void saveLogInTokens(ArrayList tokens) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens_login", Context.MODE_PRIVATE); + ArrayList activeTokens = new ArrayList<>(); + preferences.edit().clear().apply(); + for (int i = 0; i < Math.min(20, tokens.size()); i++) { + activeTokens.add(tokens.get(i)); + } + if (activeTokens.size() > 0) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("count", activeTokens.size()); + for (int i = 0; i < activeTokens.size(); i++) { + SerializedData data = new SerializedData(activeTokens.get(i).getObjectSize()); + activeTokens.get(i).serializeToStream(data); + editor.putString("log_in_token_" + i, Utilities.bytesToHex(data.toByteArray())); + } + editor.apply(); + BackupAgent.requestBackup(ApplicationLoader.applicationContext); + } + } + + public static void addLogOutToken(TLRPC.TL_auth_loggedOut response) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); + int count = preferences.getInt("count", 0); + SerializedData data = new SerializedData(response.getObjectSize()); + response.serializeToStream(data); + preferences.edit().putString("log_out_token_" + count, Utilities.bytesToHex(data.toByteArray())).putInt("count", count + 1).apply(); + BackupAgent.requestBackup(ApplicationLoader.applicationContext); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BackupAgent.java b/TMessagesProj/src/main/java/org/telegram/messenger/BackupAgent.java new file mode 100644 index 000000000..78ff6ee83 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BackupAgent.java @@ -0,0 +1,35 @@ +package org.telegram.messenger; + +import android.app.backup.BackupAgentHelper; +import android.app.backup.BackupDataInput; +import android.app.backup.BackupDataOutput; +import android.app.backup.BackupManager; +import android.app.backup.FullBackupDataOutput; +import android.app.backup.RestoreObserver; +import android.app.backup.SharedPreferencesBackupHelper; +import android.content.Context; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import org.telegram.tgnet.TLRPC; + +import java.io.IOException; +import java.util.ArrayList; + +public class BackupAgent extends BackupAgentHelper { + + private static BackupManager backupManager; + + @Override + public void onCreate() { + SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, "saved_tokens", "saved_tokens_login"); + addHelper("prefs", helper); + } + + public static void requestBackup(Context context) { + if (backupManager == null) { + backupManager = new BackupManager(context); + } + backupManager.dataChanged(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java b/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java index 23ed977fa..1a568b401 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java @@ -54,6 +54,8 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien private Map> resultListeners = new HashMap<>(); private List requestingTokens = new ArrayList<>(); + private String lastPremiumTransaction; + private String lastPremiumToken; private Map currencyExpMap = new HashMap<>(); @@ -73,6 +75,14 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien .build(); } + public String getLastPremiumTransaction() { + return lastPremiumTransaction; + } + + public String getLastPremiumToken() { + return lastPremiumToken; + } + public String formatCurrency(long amount, String currency) { return formatCurrency(amount, currency, getCurrencyExp(currency)); } @@ -156,10 +166,10 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien } public void launchBillingFlow(Activity activity, AccountInstance accountInstance, TLRPC.InputStorePaymentPurpose paymentPurpose, List productDetails) { - launchBillingFlow(activity, accountInstance, paymentPurpose, productDetails, false); + launchBillingFlow(activity, accountInstance, paymentPurpose, productDetails, null, false); } - public void launchBillingFlow(Activity activity, AccountInstance accountInstance, TLRPC.InputStorePaymentPurpose paymentPurpose, List productDetails, boolean checkedConsume) { + public void launchBillingFlow(Activity activity, AccountInstance accountInstance, TLRPC.InputStorePaymentPurpose paymentPurpose, List productDetails, BillingFlowParams.SubscriptionUpdateParams subscriptionUpdateParams, boolean checkedConsume) { if (!isReady() || activity == null) { return; } @@ -167,7 +177,7 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien if (paymentPurpose instanceof TLRPC.TL_inputStorePaymentGiftPremium && !checkedConsume) { queryPurchases(BillingClient.ProductType.INAPP, (billingResult, list) -> { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { - Runnable callback = () -> launchBillingFlow(activity, accountInstance, paymentPurpose, productDetails, true); + Runnable callback = () -> launchBillingFlow(activity, accountInstance, paymentPurpose, productDetails, subscriptionUpdateParams, true); AtomicInteger productsToBeConsumed = new AtomicInteger(0); List productsConsumed = new ArrayList<>(); @@ -205,9 +215,12 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien return; } - boolean ok = billingClient.launchBillingFlow(activity, BillingFlowParams.newBuilder() - .setProductDetailsParamsList(productDetails) - .build()).getResponseCode() == BillingClient.BillingResponseCode.OK; + BillingFlowParams.Builder flowParams = BillingFlowParams.newBuilder() + .setProductDetailsParamsList(productDetails); + if (subscriptionUpdateParams != null) { + flowParams.setSubscriptionUpdateParams(subscriptionUpdateParams); + } + boolean ok = billingClient.launchBillingFlow(activity, flowParams.build()).getResponseCode() == BillingClient.BillingResponseCode.OK; if (ok) { for (BillingFlowParams.ProductDetailsParams params : productDetails) { @@ -240,7 +253,13 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien if (list == null) { return; } + lastPremiumTransaction = null; for (Purchase purchase : list) { + if (purchase.getProducts().contains(PREMIUM_PRODUCT_ID)) { + lastPremiumTransaction = purchase.getOrderId(); + lastPremiumToken = purchase.getPurchaseToken(); + } + if (!requestingTokens.contains(purchase.getPurchaseToken())) { for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; i++) { AccountInstance acc = AccountInstance.getInstance(i); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 194a65e38..63052129f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -24,11 +24,13 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 3026; - public static String BUILD_VERSION_STRING = "9.3.3"; + public static int BUILD_VERSION = 3098; + public static String BUILD_VERSION_STRING = "9.4.0"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; + // SafetyNet key for Google Identity SDK, set it to empty to disable + public static String SAFETYNET_KEY = "AIzaSyDqt8P-7F7CPCseMkOiVRgb1LY8RN1bvH8"; public static String SMS_HASH = isStandaloneApp() ? "w0lkcmTZkKh" : (DEBUG_VERSION ? "O2P2z+/jBpJ" : "oLeq9AcOZkT"); public static String PLAYSTORE_APP_URL = "https://play.google.com/store/apps/details?id=org.telegram.messenger"; public static String GOOGLE_AUTH_CLIENT_ID = "760348033671-81kmi3pi84p11ub8hp9a1funsv0rn2p9.apps.googleusercontent.com"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index bd471c81a..65ab143c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -38,6 +38,7 @@ public class ChatObject { public static final int CHAT_TYPE_CHANNEL = 2; public static final int CHAT_TYPE_USER = 3; public static final int CHAT_TYPE_MEGAGROUP = 4; + public static final int CHAT_TYPE_FORUM = 5; public static final int ACTION_PIN = 0; public static final int ACTION_CHANGE_INFO = 1; @@ -46,6 +47,7 @@ public class ChatObject { public static final int ACTION_ADD_ADMINS = 4; public static final int ACTION_POST = 5; public static final int ACTION_SEND = 6; + public static final int ACTION_SEND_TEXT = 22; public static final int ACTION_SEND_MEDIA = 7; public static final int ACTION_SEND_STICKERS = 8; public static final int ACTION_EMBED_LINKS = 9; @@ -56,6 +58,15 @@ public class ChatObject { public static final int ACTION_MANAGE_CALLS = 14; public static final int ACTION_MANAGE_TOPICS = 15; + public static final int ACTION_SEND_PHOTO = 16; + public static final int ACTION_SEND_VIDEO = 17; + public static final int ACTION_SEND_MUSIC = 18; + public static final int ACTION_SEND_DOCUMENTS = 19; + public static final int ACTION_SEND_VOICE = 20; + public static final int ACTION_SEND_ROUND = 21; + public static final int ACTION_SEND_PLAIN = 22; + public static final int ACTION_SEND_GIFS = 23; + public final static int VIDEO_FRAME_NO_FRAME = 0; public final static int VIDEO_FRAME_REQUESTING = 1; public final static int VIDEO_FRAME_HAS_FRAME = 2; @@ -85,6 +96,61 @@ public class ChatObject { return false; } + public static boolean canSendAnyMedia(TLRPC.Chat currentChat) { + return canSendPhoto(currentChat) || canSendVideo(currentChat) || canSendRoundVideo(currentChat)|| canSendVoice(currentChat) || canSendDocument(currentChat) || canSendMusic(currentChat) || canSendStickers(currentChat); + } + + public static String getAllowedSendString(TLRPC.Chat chat) { + StringBuilder stringBuilder = new StringBuilder(); + if (ChatObject.canSendPhoto(chat)) { + stringBuilder.append(LocaleController.getString("SendMediaPermissionPhotos", R.string.SendMediaPermissionPhotos)); + } + if (ChatObject.canSendVideo(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionVideos", R.string.SendMediaPermissionVideos)); + } + if (ChatObject.canSendStickers(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs)); + } + if (ChatObject.canSendMusic(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionMusic", R.string.SendMediaPermissionMusic)); + } + if (ChatObject.canSendDocument(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionFiles", R.string.SendMediaPermissionFiles)); + } + if (ChatObject.canSendVoice(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionVoice", R.string.SendMediaPermissionVoice)); + } + if (ChatObject.canSendRoundVideo(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionRound", R.string.SendMediaPermissionRound)); + } + if (ChatObject.canSendEmbed(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaEmbededLinks", R.string.SendMediaEmbededLinks)); + } + + return stringBuilder.toString(); + } + public static class Call { public final static int RECORD_TYPE_AUDIO = 0, RECORD_TYPE_VIDEO_PORTAIT = 1, @@ -1412,6 +1478,13 @@ public class ChatObject { case ACTION_SEND_POLLS: case ACTION_VIEW: case ACTION_MANAGE_TOPICS: + case ACTION_SEND_PHOTO: + case ACTION_SEND_VIDEO: + case ACTION_SEND_MUSIC: + case ACTION_SEND_DOCUMENTS: + case ACTION_SEND_VOICE: + case ACTION_SEND_ROUND: + case ACTION_SEND_PLAIN: return true; } return false; @@ -1459,14 +1532,31 @@ public class ChatObject { return rights.view_messages; case ACTION_MANAGE_TOPICS: return rights.manage_topics; + case ACTION_SEND_PHOTO: + return rights.send_photos; + case ACTION_SEND_VIDEO: + return rights.send_videos; + case ACTION_SEND_MUSIC: + return rights.send_audios; + case ACTION_SEND_DOCUMENTS: + return rights.send_docs; + case ACTION_SEND_VOICE: + return rights.send_voices; + case ACTION_SEND_ROUND: + return rights.send_roundvideos; + case ACTION_SEND_PLAIN: + return rights.send_plain; } return false; } public static boolean isActionBannedByDefault(TLRPC.Chat chat, int action) { - if (getBannedRight(chat.banned_rights, action)) { + if (chat == null) { return false; } + if (getBannedRight(chat.banned_rights, action) && getBannedRight(chat.default_banned_rights, action)) { + return true; + } return getBannedRight(chat.default_banned_rights, action); } @@ -1628,8 +1718,31 @@ public class ChatObject { return canUserDoAction(chat, ACTION_EMBED_LINKS); } - public static boolean canSendMedia(TLRPC.Chat chat) { - return canUserDoAction(chat, ACTION_SEND_MEDIA); + // public static boolean canSendMedia(TLRPC.Chat chat) { +// return canUserDoAction(chat, ACTION_SEND_MEDIA); +// } + public static boolean canSendPhoto(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_PHOTO); + } + + public static boolean canSendVideo(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_VIDEO); + } + + public static boolean canSendMusic(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_MUSIC); + } + + public static boolean canSendDocument(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_DOCUMENTS); + } + + public static boolean canSendVoice(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_VOICE); + } + + public static boolean canSendRoundVideo(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_ROUND); } public static boolean canSendPolls(TLRPC.Chat chat) { @@ -1640,6 +1753,10 @@ public class ChatObject { return canUserDoAction(chat, ACTION_SEND); } + public static boolean canSendPlain(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_PLAIN); + } + public static boolean canPost(TLRPC.Chat chat) { return canUserDoAction(chat, ACTION_POST); } @@ -1760,6 +1877,13 @@ public class ChatObject { currentBannedRights += bannedRights.change_info ? 1 : 0; currentBannedRights += bannedRights.pin_messages ? 1 : 0; currentBannedRights += bannedRights.manage_topics ? 1 : 0; + currentBannedRights += bannedRights.send_photos ? 1 : 0; + currentBannedRights += bannedRights.send_videos ? 1 : 0; + currentBannedRights += bannedRights.send_roundvideos ? 1 : 0; + currentBannedRights += bannedRights.send_voices ? 1 : 0; + currentBannedRights += bannedRights.send_audios ? 1 : 0; + currentBannedRights += bannedRights.send_docs ? 1 : 0; + currentBannedRights += bannedRights.send_plain ? 1 : 0; currentBannedRights += bannedRights.until_date; return currentBannedRights; } @@ -1819,6 +1943,93 @@ public class ChatObject { return !TextUtils.isEmpty(getPublicUsername(chat)); } + public static String getRestrictedErrorText(TLRPC.Chat chat, int action) { + if (action == ACTION_SEND_GIFS) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachGifRestricted", R.string.GlobalAttachGifRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachGifRestrictedForever", R.string.AttachGifRestrictedForever); + } else { + return LocaleController.formatString("AttachGifRestricted", R.string.AttachGifRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_STICKERS) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachStickersRestricted", R.string.GlobalAttachStickersRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachStickersRestrictedForever", R.string.AttachStickersRestrictedForever); + } else { + return LocaleController.formatString("AttachStickersRestricted", R.string.AttachStickersRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_PHOTO) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachPhotoRestricted", R.string.GlobalAttachPhotoRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachPhotoRestrictedForever", R.string.AttachPhotoRestrictedForever); + } else { + return LocaleController.formatString("AttachPhotoRestricted", R.string.AttachPhotoRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_VIDEO) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachVideoRestricted", R.string.GlobalAttachVideoRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachVideoRestrictedForever", R.string.AttachVideoRestrictedForever); + } else { + return LocaleController.formatString("AttachVideoRestricted", R.string.AttachVideoRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_DOCUMENTS) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachDocumentsRestricted", R.string.GlobalAttachDocumentsRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachDocumentsRestrictedForever", R.string.AttachDocumentsRestrictedForever); + } else { + return LocaleController.formatString("AttachDocumentsRestricted", R.string.AttachDocumentsRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_MEDIA) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachMediaRestricted", R.string.GlobalAttachMediaRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachMediaRestrictedForever", R.string.AttachMediaRestrictedForever); + } else { + return LocaleController.formatString("AttachMediaRestricted", R.string.AttachMediaRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_MUSIC) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachAudioRestricted", R.string.GlobalAttachAudioRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachAudioRestrictedForever", R.string.AttachAudioRestrictedForever); + } else { + return LocaleController.formatString("AttachAudioRestricted", R.string.AttachAudioRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_PLAIN) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachPlainRestricted", R.string.GlobalAttachPlainRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachPlainRestrictedForever", R.string.AttachPlainRestrictedForever); + } else { + return LocaleController.formatString("AttachPlainRestricted", R.string.AttachPlainRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_ROUND) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachRoundRestricted", R.string.GlobalAttachRoundRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachRoundRestrictedForever", R.string.AttachRoundRestrictedForever); + } else { + return LocaleController.formatString("AttachRoundRestricted", R.string.AttachRoundRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_VOICE) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachVoiceRestricted", R.string.GlobalAttachVoiceRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachVoiceRestrictedForever", R.string.AttachVoiceRestrictedForever); + } else { + return LocaleController.formatString("AttachVoiceRestricted", R.string.AttachVoiceRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } + + return ""; + } + + public static class VideoParticipant { public TLRPC.TL_groupCallParticipant participant; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java index 3a2020d4f..fd23f5421 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -762,7 +762,7 @@ public class ContactsController extends BaseController { String lookup_key = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); String phone = null; - if (contactsMap.get(lookup_key) != null || TextUtils.isEmpty(name)) { + if ((contactsMap != null && contactsMap.get(lookup_key) != null) || TextUtils.isEmpty(name)) { continue; } pCur = cr.query( diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java index 1ecc488f4..db5c54af3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java @@ -1218,6 +1218,12 @@ public class DatabaseMigrationHelper { version = 111; } + if (version == 111) { + database.executeFast("CREATE TABLE emoji_groups(type INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 112").stepThis().dispose(); + version = 112; + } + return version; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DocumentObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/DocumentObject.java index cc2f161b1..b63fe2810 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DocumentObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DocumentObject.java @@ -116,7 +116,10 @@ public class DocumentObject { int w = 512, h = 512; for (int a = 0, N = document.attributes.size(); a < N; a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); - if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { + if ( + attribute instanceof TLRPC.TL_documentAttributeImageSize || + attribute instanceof TLRPC.TL_documentAttributeVideo + ) { w = attribute.w; h = attribute.h; break; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java index d036520ee..58fb9d41f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java @@ -64,6 +64,15 @@ public class Emoji { public static float emojiDrawingYOffset; public static boolean emojiDrawingUseAlpha = true; + private static String[] DEFAULT_RECENT = new String[]{ + "\uD83D\uDE02", "\uD83D\uDE18", "\u2764", "\uD83D\uDE0D", "\uD83D\uDE0A", "\uD83D\uDE01", + "\uD83D\uDC4D", "\u263A", "\uD83D\uDE14", "\uD83D\uDE04", "\uD83D\uDE2D", "\uD83D\uDC8B", + "\uD83D\uDE12", "\uD83D\uDE33", "\uD83D\uDE1C", "\uD83D\uDE48", "\uD83D\uDE09", "\uD83D\uDE03", + "\uD83D\uDE22", "\uD83D\uDE1D", "\uD83D\uDE31", "\uD83D\uDE21", "\uD83D\uDE0F", "\uD83D\uDE1E", + "\uD83D\uDE05", "\uD83D\uDE1A", "\uD83D\uDE4A", "\uD83D\uDE0C", "\uD83D\uDE00", "\uD83D\uDE0B", + "\uD83D\uDE06", "\uD83D\uDC4C", "\uD83D\uDE10", "\uD83D\uDE15" + }; + private final static int MAX_RECENT_EMOJI_COUNT = 48; static { @@ -663,6 +672,14 @@ public class Emoji { emojiUseHistory.put(code, ++count); } + public static void removeRecentEmoji(String code) { + emojiUseHistory.remove(code); + recentEmoji.remove(code); + if (emojiUseHistory.isEmpty() || recentEmoji.isEmpty()) { + addRecentEmoji(DEFAULT_RECENT[0]); + } + } + public static void sortEmoji() { recentEmoji.clear(); for (HashMap.Entry entry : emojiUseHistory.entrySet()) { @@ -756,15 +773,8 @@ public class Emoji { } if (emojiUseHistory.isEmpty()) { if (!preferences.getBoolean("filled_default", false)) { - String[] newRecent = new String[]{ - "\uD83D\uDE02", "\uD83D\uDE18", "\u2764", "\uD83D\uDE0D", "\uD83D\uDE0A", "\uD83D\uDE01", - "\uD83D\uDC4D", "\u263A", "\uD83D\uDE14", "\uD83D\uDE04", "\uD83D\uDE2D", "\uD83D\uDC8B", - "\uD83D\uDE12", "\uD83D\uDE33", "\uD83D\uDE1C", "\uD83D\uDE48", "\uD83D\uDE09", "\uD83D\uDE03", - "\uD83D\uDE22", "\uD83D\uDE1D", "\uD83D\uDE31", "\uD83D\uDE21", "\uD83D\uDE0F", "\uD83D\uDE1E", - "\uD83D\uDE05", "\uD83D\uDE1A", "\uD83D\uDE4A", "\uD83D\uDE0C", "\uD83D\uDE00", "\uD83D\uDE0B", - "\uD83D\uDE06", "\uD83D\uDC4C", "\uD83D\uDE10", "\uD83D\uDE15"}; - for (int i = 0; i < newRecent.length; i++) { - emojiUseHistory.put(newRecent[i], newRecent.length - i); + for (int i = 0; i < DEFAULT_RECENT.length; i++) { + emojiUseHistory.put(DEFAULT_RECENT[i], DEFAULT_RECENT.length - i); } preferences.edit().putBoolean("filled_default", true).commit(); saveRecentEmoji(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Fetcher.java b/TMessagesProj/src/main/java/org/telegram/messenger/Fetcher.java new file mode 100644 index 000000000..44aa1f90a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Fetcher.java @@ -0,0 +1,132 @@ +package org.telegram.messenger; + +import android.util.Pair; + +import java.util.ArrayList; +import java.util.HashMap; + +public abstract class Fetcher { + + protected void getRemote(int currentAccount, Args arguments, long hash, Utilities.Callback3 onResult) { + // Implement this function + } + + // Not specifying getLocal and setLocal would mean that data is cached only in RAM + protected void getLocal(int currentAccount, Args arguments, Utilities.Callback2 onResult) { + // Implement this function + onResult.run(0L, null); + } + + protected void setLocal(int currentAccount, Args arguments, R data, long hash) { + // Implement this function + } + + private long requestRemotelyTimeout = 4 * 60 * 1000; + + private HashMap, R> cachedResults; + private HashMap, ArrayList>> loadingCallbacks; + private HashMap, Long> lastRequestedRemotely; + + public void fetch(int currentAccount, Args arguments, Utilities.Callback onResult) { + final Pair key = new Pair<>(currentAccount, arguments); + + if (isLoading(key)) { + saveCallback(key, onResult); + return; + } + + R cached = getCachedResult(key); + if (cached != null && !shouldRequest(key)) { + if (onResult != null) { + onResult.run(cached); + } + return; + } + + saveCallback(key, onResult); + getLocal(currentAccount, arguments, (hash, data) -> { + if (shouldRequest(key)) { + saveLastRequested(key); + getRemote(currentAccount, arguments, hash, (notModified, remoteData, newHash) -> { + if (notModified) { + cacheResult(key, data); + callCallbacks(key, data); + } else { + if (remoteData != null) { + setLocal(currentAccount, arguments, remoteData, newHash); + cacheResult(key, remoteData); + } + callCallbacks(key, remoteData); + } + }); + } else { + cacheResult(key, data); + callCallbacks(key, data); + } + }); + } + + private R getCachedResult(Pair key) { + if (cachedResults == null) { + return null; + } + return cachedResults.get(key); + } + + private void cacheResult(Pair key, R result) { + if (cachedResults == null) { + cachedResults = new HashMap<>(); + } + cachedResults.put(key, result); + } + + private void saveLastRequested(Pair key) { + if (lastRequestedRemotely == null) { + lastRequestedRemotely = new HashMap<>(); + } + lastRequestedRemotely.put(key, System.currentTimeMillis()); + } + + private boolean shouldRequest(Pair key) { + Long lastRequested = lastRequestedRemotely != null ? lastRequestedRemotely.get(key) : null; + return lastRequested == null || System.currentTimeMillis() - lastRequested >= requestRemotelyTimeout; + } + + private boolean isLoading(Pair key) { + return loadingCallbacks != null && loadingCallbacks.get(key) != null; + } + + private void saveCallback(Pair key, Utilities.Callback callback) { + if (callback == null) { + return; + } + if (loadingCallbacks == null) { + loadingCallbacks = new HashMap<>(); + } + ArrayList> callbacks = loadingCallbacks.get(key); + if (callbacks == null) { + loadingCallbacks.put(key, callbacks = new ArrayList<>()); + } + callbacks.add(callback); + } + + private void callCallbacks(Pair key, R result) { + if (loadingCallbacks == null) { + return; + } + + final ArrayList> callbacks = loadingCallbacks.get(key); + if (callbacks == null) { + return; + } + + AndroidUtilities.runOnUIThread(() -> { + for (Utilities.Callback callback: callbacks) { + callback.run(result); + } + callbacks.clear(); + }); + + loadingCallbacks.remove(key); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index d96cc3339..9da5b22f6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -1412,7 +1412,11 @@ public class FileLoadOperation { } else if (currentType == ConnectionsManager.FileTypePhoto) { StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_PHOTOS, 1); } else if (currentType == ConnectionsManager.FileTypeFile) { - StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); + if (ext != null && (ext.toLowerCase().endsWith("mp3") || ext.toLowerCase().endsWith("m4a"))) { + StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_MUSIC, 1); + } else { + StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); + } } } delegate.didFinishLoadingFile(FileLoadOperation.this, cacheFileFinal); @@ -2148,7 +2152,11 @@ public class FileLoadOperation { } else if (currentType == ConnectionsManager.FileTypePhoto) { StatsController.getInstance(currentAccount).incrementReceivedBytesCount(response.networkType, StatsController.TYPE_PHOTOS, response.getObjectSize() + 4); } else if (currentType == ConnectionsManager.FileTypeFile) { - StatsController.getInstance(currentAccount).incrementReceivedBytesCount(response.networkType, StatsController.TYPE_FILES, response.getObjectSize() + 4); + if (ext != null && (ext.toLowerCase().endsWith("mp3") || ext.toLowerCase().endsWith("m4a"))) { + StatsController.getInstance(currentAccount).incrementReceivedBytesCount(response.networkType, StatsController.TYPE_MUSIC, response.getObjectSize() + 4); + } else { + StatsController.getInstance(currentAccount).incrementReceivedBytesCount(response.networkType, StatsController.TYPE_FILES, response.getObjectSize() + 4); + } } } processRequestResult(requestInfo, error); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 9abfea23a..c9febf7b8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -45,7 +45,7 @@ public class FileLoader extends BaseController { String str = (String) parentObject; if (str.startsWith("sent_")) { if (sentPattern == null) { - sentPattern = Pattern.compile("sent_.*_([0-9]+)_([0-9]+)_([0-9]+)"); + sentPattern = Pattern.compile("sent_.*_([0-9]+)_([0-9]+)_([0-9]+)_([0-9]+)"); } try { Matcher matcher = sentPattern.matcher(str); @@ -54,6 +54,7 @@ public class FileLoader extends BaseController { fileMeta.messageId = Integer.parseInt(matcher.group(1)); fileMeta.dialogId = Long.parseLong(matcher.group(2)); fileMeta.messageType = Integer.parseInt(matcher.group(3)); + fileMeta.messageSize = Long.parseLong(matcher.group(4)); return fileMeta; } } catch (Exception e) { @@ -66,11 +67,25 @@ public class FileLoader extends BaseController { fileMeta.messageId = messageObject.getId(); fileMeta.dialogId = messageObject.getDialogId(); fileMeta.messageType = messageObject.type; + fileMeta.messageSize = messageObject.getSize(); return fileMeta; } return null; } + public static TLRPC.VideoSize getVectorMarkupVideoSize(TLRPC.Photo photo) { + if (photo == null || photo.video_sizes == null) { + return null; + } + for (int i = 0; i < photo.video_sizes.size(); i++) { + TLRPC.VideoSize videoSize = photo.video_sizes.get(i); + if (videoSize instanceof TLRPC.TL_videoSizeEmojiMarkup || videoSize instanceof TLRPC.TL_videoSizeStickerMarkup) { + return videoSize; + } + } + return null; + } + private int getPriorityValue(int priorityType) { if (priorityType == PRIORITY_STREAM) { return Integer.MAX_VALUE; @@ -732,7 +747,6 @@ public class FileLoader extends BaseController { storeDir = getDirectory(type); boolean saveCustomPath = false; - if ((type == MEDIA_DIR_IMAGE || type == MEDIA_DIR_VIDEO) && canSaveToPublicStorage(parentObject)) { File newDir; if (type == MEDIA_DIR_IMAGE) { @@ -856,16 +870,27 @@ public class FileLoader extends BaseController { } private boolean canSaveToPublicStorage(Object parentObject) { - if (SharedConfig.saveToGalleryFlags == 0 || BuildVars.NO_SCOPED_STORAGE) { + if (BuildVars.NO_SCOPED_STORAGE) { return false; } - if (parentObject instanceof MessageObject) { - MessageObject messageObject = (MessageObject) parentObject; + FilePathDatabase.FileMeta metadata = getFileMetadataFromParent(currentAccount, parentObject); + MessageObject messageObject = null; + if (metadata != null) { int flag; - long dialogId = messageObject.getDialogId(); - if (messageObject.isRoundVideo() || messageObject.isVoice() || messageObject.isAnyKindOfSticker() || getMessagesController().isChatNoForwards(getMessagesController().getChat(-dialogId)) || messageObject.messageOwner.noforwards || DialogObject.isEncryptedDialog(dialogId)) { + long dialogId = metadata.dialogId; + if (getMessagesController().isChatNoForwards(getMessagesController().getChat(-dialogId)) || DialogObject.isEncryptedDialog(dialogId)) { return false; } + if (parentObject instanceof MessageObject) { + messageObject = (MessageObject) parentObject; + if (messageObject.isRoundVideo() || messageObject.isVoice() || messageObject.isAnyKindOfSticker() || messageObject.messageOwner.noforwards) { + return false; + } + } else { + if (metadata.messageType == MessageObject.TYPE_ROUND_VIDEO || metadata.messageType == MessageObject.TYPE_STICKER || metadata.messageType == MessageObject.TYPE_VOICE) { + return false; + } + } if (dialogId >= 0) { flag = SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; } else { @@ -876,7 +901,7 @@ public class FileLoader extends BaseController { } } - if ((SharedConfig.saveToGalleryFlags & flag) != 0) { + if (SaveToGallerySettingsHelper.needSave(flag, metadata, messageObject, currentAccount)) { return true; } } @@ -1182,13 +1207,64 @@ public class FileLoader extends BaseController { } if (byMinSide) { int currentSide = Math.min(obj.h, obj.w); - if (closestObject == null || side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || obj instanceof TLRPC.TL_photoCachedSize || side > lastSide && lastSide < currentSide) { + if ( + closestObject == null || + side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || + obj instanceof TLRPC.TL_photoCachedSize || side > lastSide && lastSide < currentSide + ) { closestObject = obj; lastSide = currentSide; } } else { int currentSide = Math.max(obj.w, obj.h); - if (closestObject == null || side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || obj instanceof TLRPC.TL_photoCachedSize || currentSide <= side && lastSide < currentSide) { + if ( + closestObject == null || + side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || + obj instanceof TLRPC.TL_photoCachedSize || + currentSide <= side && lastSide < currentSide + ) { + closestObject = obj; + lastSide = currentSide; + } + } + } + return closestObject; + } + + public static TLRPC.VideoSize getClosestVideoSizeWithSize(ArrayList sizes, int side) { + return getClosestVideoSizeWithSize(sizes, side, false); + } + + public static TLRPC.VideoSize getClosestVideoSizeWithSize(ArrayList sizes, int side, boolean byMinSide) { + return getClosestVideoSizeWithSize(sizes, side, byMinSide, false); + } + + public static TLRPC.VideoSize getClosestVideoSizeWithSize(ArrayList sizes, int side, boolean byMinSide, boolean ignoreStripped) { + if (sizes == null || sizes.isEmpty()) { + return null; + } + int lastSide = 0; + TLRPC.VideoSize closestObject = null; + for (int a = 0; a < sizes.size(); a++) { + TLRPC.VideoSize obj = sizes.get(a); + if (obj == null || obj instanceof TLRPC.TL_videoSizeEmojiMarkup || obj instanceof TLRPC.TL_videoSizeStickerMarkup) { + continue; + } + if (byMinSide) { + int currentSide = Math.min(obj.h, obj.w); + if (closestObject == null || + side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || + side > lastSide && lastSide < currentSide) { + closestObject = obj; + lastSide = currentSide; + } + } else { + int currentSide = Math.max(obj.w, obj.h); + if ( + closestObject == null || + side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || + currentSide <= side && lastSide < currentSide + ) { closestObject = obj; lastSide = currentSide; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java b/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java index ad1e909f5..929c237d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java @@ -445,5 +445,6 @@ public class FilePathDatabase { public long dialogId; public int messageId; public int messageType; + public long messageSize; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java index f208907fe..f1574ff36 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java @@ -535,7 +535,11 @@ public class FileUploadOperation { } else if (currentType == ConnectionsManager.FileTypePhoto) { StatsController.getInstance(currentAccount).incrementSentBytesCount(networkType, StatsController.TYPE_PHOTOS, requestSize); } else if (currentType == ConnectionsManager.FileTypeFile) { - StatsController.getInstance(currentAccount).incrementSentBytesCount(networkType, StatsController.TYPE_FILES, requestSize); + if (uploadingFilePath != null && (uploadingFilePath.toLowerCase().endsWith("mp3") || uploadingFilePath.toLowerCase().endsWith("m4a"))) { + StatsController.getInstance(currentAccount).incrementSentBytesCount(networkType, StatsController.TYPE_MUSIC, requestSize); + } else { + StatsController.getInstance(currentAccount).incrementSentBytesCount(networkType, StatsController.TYPE_FILES, requestSize); + } } if (currentRequestIv != null) { freeRequestIvs.add(currentRequestIv); @@ -590,7 +594,11 @@ public class FileUploadOperation { } else if (currentType == ConnectionsManager.FileTypePhoto) { StatsController.getInstance(currentAccount).incrementSentItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_PHOTOS, 1); } else if (currentType == ConnectionsManager.FileTypeFile) { - StatsController.getInstance(currentAccount).incrementSentItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); + if (uploadingFilePath != null && (uploadingFilePath.toLowerCase().endsWith("mp3") || uploadingFilePath.toLowerCase().endsWith("m4a"))) { + StatsController.getInstance(currentAccount).incrementSentItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_MUSIC, 1); + } else { + StatsController.getInstance(currentAccount).incrementSentItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); + } } } else if (currentUploadRequetsCount < maxRequestsCount) { if (estimatedSize == 0 && !uploadFirstPartLater && !nextPartFirst) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index d6d522523..1e8af90fb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -74,6 +74,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; import java.util.zip.GZIPInputStream; @@ -86,6 +87,7 @@ import java.util.zip.GZIPInputStream; * b - need blur image * g - autoplay * lastframe - return lastframe for Lottie animation + * lastreactframe - return lastframe for Lottie animation + some scale ReactionLastFrame magic * firstframe - return firstframe for Lottie animation */ public class ImageLoader { @@ -870,6 +872,7 @@ public class ImageLoader { boolean precache = false; boolean limitFps = false; boolean lastFrameBitmap = false; + boolean lastFrameReactionScaleBitmap = false; boolean firstFrameBitmap = false; int autoRepeat = 1; int[] colors = null; @@ -896,6 +899,10 @@ public class ImageLoader { if (cacheImage.filter.contains("lastframe")) { lastFrameBitmap = true; } + if (cacheImage.filter.contains("lastreactframe")) { + lastFrameBitmap = true; + lastFrameReactionScaleBitmap = true; + } if (cacheImage.filter.contains("firstframe")) { firstFrameBitmap = true; } @@ -964,13 +971,17 @@ public class ImageLoader { precache = false; } BitmapsCache.CacheOptions cacheOptions = null; - if (precache) { + if (precache || lastFrameBitmap || firstFrameBitmap) { cacheOptions = new BitmapsCache.CacheOptions(); - if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { - cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; - } - if (cacheImage.filter != null && cacheImage.filter.contains("flbk")) { - cacheOptions.fallback = true; + if (!lastFrameBitmap && !firstFrameBitmap) { + if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { + cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; + } + if (cacheImage.filter != null && cacheImage.filter.contains("flbk")) { + cacheOptions.fallback = true; + } + } else { + cacheOptions.firstFrame = true; } } if (compressed) { @@ -980,7 +991,7 @@ public class ImageLoader { } } if (lastFrameBitmap || firstFrameBitmap) { - loadLastFrame(lottieDrawable, h, w, lastFrameBitmap); + loadLastFrame(lottieDrawable, h, w, lastFrameBitmap, lastFrameReactionScaleBitmap); } else { lottieDrawable.setAutoRepeat(autoRepeat); onPostExecute(lottieDrawable); @@ -995,6 +1006,8 @@ public class ImageLoader { } boolean limitFps = false; boolean precache = false; + boolean fistFrame = false; + boolean notCreateStream = false; if (cacheImage.filter != null) { String[] args = cacheImage.filter.split("_"); if (args.length >= 2) { @@ -1008,20 +1021,28 @@ public class ImageLoader { if ("pcache".equals(args[i])) { precache = true; } + if ("firstframe".equals(args[i])) { + fistFrame = true; + } + if ("nostream".equals(args[i])) { + notCreateStream = true; + } + } + if (fistFrame) { + notCreateStream = true; + } + } + BitmapsCache.CacheOptions cacheOptions = null; + if (precache && !fistFrame) { + cacheOptions = new BitmapsCache.CacheOptions(); + if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { + cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; } } if ((isAnimatedAvatar(cacheImage.filter) || AUTOPLAY_FILTER.equals(cacheImage.filter)) && !(cacheImage.imageLocation.document instanceof TLRPC.TL_documentEncrypted) && !precache) { TLRPC.Document document = cacheImage.imageLocation.document instanceof TLRPC.Document ? cacheImage.imageLocation.document : null; long size = document != null ? cacheImage.size : cacheImage.imageLocation.currentSize; - BitmapsCache.CacheOptions cacheOptions = null; - if (precache) { - cacheOptions = new BitmapsCache.CacheOptions(); - if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { - cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; - } - } - boolean notCreateStream = cacheImage.filter != null && cacheImage.filter.contains("nostream"); - fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, false, notCreateStream ? 0 : size, notCreateStream ? null : document, document == null && !notCreateStream ? cacheImage.imageLocation : null, cacheImage.parentObject, seekTo, cacheImage.currentAccount, false, cacheOptions); + fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, fistFrame, notCreateStream ? 0 : size, notCreateStream ? null : document, document == null && !notCreateStream ? cacheImage.imageLocation : null, cacheImage.parentObject, seekTo, cacheImage.currentAccount, false, cacheOptions); fileDrawable.setIsWebmSticker(MessageObject.isWebM(document) || MessageObject.isVideoSticker(document) || isAnimatedAvatar(cacheImage.filter)); } else { @@ -1036,21 +1057,25 @@ public class ImageLoader { h = (int) (h_filter * AndroidUtilities.density); } } - BitmapsCache.CacheOptions cacheOptions = null; - if (precache) { - cacheOptions = new BitmapsCache.CacheOptions(); - if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { - cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; - } - } - boolean createDecoder = cacheImage.filter != null && ("d".equals(cacheImage.filter) || cacheImage.filter.contains("_d")); - boolean notCreateStream = cacheImage.filter != null && cacheImage.filter.contains("nostream"); + boolean createDecoder = fistFrame || (cacheImage.filter != null && ("d".equals(cacheImage.filter) || cacheImage.filter.contains("_d"))); fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, createDecoder, 0, notCreateStream ? null : cacheImage.imageLocation.document, null, null, seekTo, cacheImage.currentAccount, false, w, h, cacheOptions); fileDrawable.setIsWebmSticker(MessageObject.isWebM(cacheImage.imageLocation.document) || MessageObject.isVideoSticker(cacheImage.imageLocation.document) || isAnimatedAvatar(cacheImage.filter)); } - fileDrawable.setLimitFps(limitFps); - Thread.interrupted(); - onPostExecute(fileDrawable); + if (fistFrame) { + Bitmap bitmap = fileDrawable.getFrameAtTime(0, false); + + fileDrawable.recycle(); + Thread.interrupted(); + if (bitmap == null) { + onPostExecute(null); + } else { + onPostExecute(new BitmapDrawable(bitmap)); + } + } else { + fileDrawable.setLimitFps(limitFps); + Thread.interrupted(); + onPostExecute(fileDrawable); + } } else { Long mediaId = null; boolean mediaIsVideo = false; @@ -1548,10 +1573,10 @@ public class ImageLoader { } } - private void loadLastFrame(RLottieDrawable lottieDrawable, int w, int h, boolean lastFrame) { + private void loadLastFrame(RLottieDrawable lottieDrawable, int w, int h, boolean lastFrame, boolean reaction) { Bitmap bitmap; Canvas canvas; - if (lastFrame) { + if (lastFrame && reaction) { bitmap = Bitmap.createBitmap((int) (w * ImageReceiver.ReactionLastFrame.LAST_FRAME_SCALE), (int) (h * ImageReceiver.ReactionLastFrame.LAST_FRAME_SCALE), Bitmap.Config.ARGB_8888); canvas = new Canvas(bitmap); canvas.scale(2f, 2f, w * ImageReceiver.ReactionLastFrame.LAST_FRAME_SCALE / 2f, h * ImageReceiver.ReactionLastFrame.LAST_FRAME_SCALE / 2f); @@ -1560,32 +1585,29 @@ public class ImageLoader { canvas = new Canvas(bitmap); } + lottieDrawable.prepareForGenerateCache(); + Bitmap currentBitmap = Bitmap.createBitmap(lottieDrawable.getIntrinsicWidth(), lottieDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + lottieDrawable.setGeneratingFrame(lastFrame ? lottieDrawable.getFramesCount() - 1 : 0); + lottieDrawable.getNextFrame(currentBitmap); + lottieDrawable.releaseForGenerateCache(); + canvas.save(); + if (!(lastFrame && reaction)) { + canvas.scale(currentBitmap.getWidth() / w, currentBitmap.getHeight() / h, w / 2f, h / 2f); + } + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setFilterBitmap(true); + BitmapDrawable bitmapDrawable = null; + if (lastFrame && reaction) { + canvas.drawBitmap(currentBitmap, (bitmap.getWidth() - currentBitmap.getWidth()) / 2f, (bitmap.getHeight() - currentBitmap.getHeight()) / 2f, paint); + bitmapDrawable = new ImageReceiver.ReactionLastFrame(bitmap); + } else { + canvas.drawBitmap(currentBitmap, 0, 0, paint); + bitmapDrawable = new BitmapDrawable(bitmap); + } - AndroidUtilities.runOnUIThread(() -> { - lottieDrawable.setOnFrameReadyRunnable(() -> { - lottieDrawable.setOnFrameReadyRunnable(null); - BitmapDrawable bitmapDrawable = null; - if (lottieDrawable.getBackgroundBitmap() != null || lottieDrawable.getRenderingBitmap() != null) { - Bitmap currentBitmap = lottieDrawable.getBackgroundBitmap() != null ? lottieDrawable.getBackgroundBitmap() : lottieDrawable.getRenderingBitmap(); - canvas.save(); - if (!lastFrame) { - canvas.scale(currentBitmap.getWidth() / w, currentBitmap.getHeight() / h, w / 2f, h / 2f); - } - Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - paint.setFilterBitmap(true); - if (lastFrame) { - canvas.drawBitmap(currentBitmap, (bitmap.getWidth() - currentBitmap.getWidth()) / 2f, (bitmap.getHeight() - currentBitmap.getHeight()) / 2f, paint); - bitmapDrawable = new ImageReceiver.ReactionLastFrame(bitmap); - } else { - canvas.drawBitmap(currentBitmap, 0, 0, paint); - bitmapDrawable = new BitmapDrawable(bitmap); - } - } - onPostExecute(bitmapDrawable); - lottieDrawable.recycle(); - }); - lottieDrawable.setCurrentFrame(lastFrame ? lottieDrawable.getFramesCount() - 1 : 0, true, true); - }); + lottieDrawable.recycle(); + currentBitmap.recycle(); + onPostExecute(bitmapDrawable); } private void onPostExecute(final Drawable drawable) { @@ -1736,7 +1758,7 @@ public class ImageLoader { public void addImageReceiver(ImageReceiver imageReceiver, String key, String filter, int type, int guid) { int index = imageReceiverArray.indexOf(imageReceiver); - if (index >= 0) { + if (index >= 0 && Objects.equals(imageReceiverArray.get(index).getImageKey(), key)) { imageReceiverGuidsArray.set(index, guid); return; } @@ -2040,11 +2062,14 @@ public class ImageLoader { public void fileDidLoaded(final String location, final File finalFile, Object parentObject, final int type) { fileProgresses.remove(location); AndroidUtilities.runOnUIThread(() -> { - if (SharedConfig.saveToGalleryFlags != 0 && finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { - if (parentObject instanceof MessageObject) { - MessageObject messageObject = (MessageObject) parentObject; - - long dialogId = messageObject.getDialogId(); + if (finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { + FilePathDatabase.FileMeta meta = FileLoader.getFileMetadataFromParent(currentAccount, parentObject); + if (meta != null) { + MessageObject messageObject = null; + if (parentObject instanceof MessageObject) { + messageObject = (MessageObject) parentObject; + } + long dialogId = meta.dialogId; int flag; if (dialogId >= 0) { flag = SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; @@ -2055,7 +2080,7 @@ public class ImageLoader { flag = SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP; } } - if ((SharedConfig.saveToGalleryFlags & flag) != 0) { + if (SaveToGallerySettingsHelper.needSave(flag, meta, messageObject, currentAccount)) { AndroidUtilities.addMediaToGallery(finalFile.toString()); } } @@ -2656,6 +2681,7 @@ public class ImageLoader { final boolean shouldGenerateQualityThumb = imageReceiver.isShouldGenerateQualityThumb(); final int currentAccount = imageReceiver.getCurrentAccount(); final boolean currentKeyQuality = type == ImageReceiver.TYPE_IMAGE && imageReceiver.isCurrentKeyQuality(); + final Runnable loadOperationRunnable = () -> { boolean added = false; if (thumb != 2) { @@ -3320,6 +3346,9 @@ public class ImageLoader { } private boolean useLottieMemCache(ImageLocation imageLocation, String key) { + if (key.endsWith("_firstframe") || key.endsWith("_lastframe")) { + return false; + } return imageLocation != null && (MessageObject.isAnimatedStickerDocument(imageLocation.document, true) || imageLocation.imageType == FileLoader.IMAGE_TYPE_LOTTIE || MessageObject.isVideoSticker(imageLocation.document)) || isAnimatedAvatar(key); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java index 47a415bcd..287a6d5bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java @@ -118,7 +118,8 @@ public class ImageLocation { public static final int TYPE_BIG = 0; public static final int TYPE_SMALL = 1; public static final int TYPE_STRIPPED = 2; - public static final int TYPE_VIDEO_THUMB = 3; + public static final int TYPE_VIDEO_SMALL = 3; + public static final int TYPE_VIDEO_BIG = 4; public static ImageLocation getForUserOrChat(TLObject object, int type) { if (object instanceof TLRPC.User) { @@ -133,19 +134,25 @@ public class ImageLocation { if (user == null || user.access_hash == 0 || user.photo == null) { return null; } - if (type == TYPE_VIDEO_THUMB) { + if (type == TYPE_VIDEO_BIG || type == TYPE_VIDEO_SMALL) { int currentAccount = UserConfig.selectedAccount; if (MessagesController.getInstance(currentAccount).isPremiumUser(user) && user.photo.has_video) { final TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(user.id); if (userFull != null && userFull.profile_photo != null && userFull.profile_photo.video_sizes != null && !userFull.profile_photo.video_sizes.isEmpty()) { - TLRPC.VideoSize videoSize = userFull.profile_photo.video_sizes.get(0); - for (int i = 0; i < userFull.profile_photo.video_sizes.size(); i++) { - if ("p".equals(userFull.profile_photo.video_sizes.get(i).type)) { - videoSize = userFull.profile_photo.video_sizes.get(i); - break; + if (type == TYPE_VIDEO_BIG) { + TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(userFull.profile_photo.video_sizes, 1000); + return ImageLocation.getForPhoto(videoSize, userFull.profile_photo); + } else { + TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(userFull.profile_photo.video_sizes, 100); + for (int i = 0; i < userFull.profile_photo.video_sizes.size(); i++) { + if ("p".equals(userFull.profile_photo.video_sizes.get(i).type)) { + videoSize = userFull.profile_photo.video_sizes.get(i); + break; + } } + return ImageLocation.getForPhoto(videoSize, userFull.profile_photo); } - return ImageLocation.getForPhoto(videoSize, userFull.profile_photo); + } } return null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index 0ef7415bc..dbc57d4cd 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -33,12 +33,14 @@ import androidx.annotation.Keep; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AnimatedFileDrawable; +import org.telegram.ui.Components.AttachableDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ClipRoundedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LoadingStickerDrawable; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RecyclableDrawable; +import org.telegram.ui.Components.VectorAvatarThumbDrawable; import java.util.ArrayList; @@ -370,10 +372,10 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg setForUserOrChat(object, avatarDrawable, null); } public void setForUserOrChat(TLObject object, Drawable avatarDrawable, Object parentObject) { - setForUserOrChat(object, avatarDrawable, null, false); + setForUserOrChat(object, avatarDrawable, parentObject, false, 0); } - public void setForUserOrChat(TLObject object, Drawable avatarDrawable, Object parentObject, boolean animationEnabled) { + public void setForUserOrChat(TLObject object, Drawable avatarDrawable, Object parentObject, boolean animationEnabled, int vectorType) { if (parentObject == null) { parentObject = object; } @@ -381,29 +383,46 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg BitmapDrawable strippedBitmap = null; boolean hasStripped = false; ImageLocation videoLocation = null; + TLRPC.VideoSize vectorImageMarkup = null; + boolean isPremium = false; if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; + isPremium = user.premium; if (user.photo != null) { strippedBitmap = user.photo.strippedBitmap; hasStripped = user.photo.stripped_thumb != null; - if (animationEnabled && MessagesController.getInstance(currentAccount).isPremiumUser(user) && user.photo.has_video && !SharedConfig.getLiteMode().enabled()) { + if (vectorType == VectorAvatarThumbDrawable.TYPE_STATIC) { + final TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(user.id); + if (userFull != null) { + TLRPC.Photo photo = user.photo.personal ? userFull.personal_photo : userFull.profile_photo; + if (photo != null) { + vectorImageMarkup = FileLoader.getVectorMarkupVideoSize(photo); + } + } + } + if (vectorImageMarkup == null && animationEnabled && MessagesController.getInstance(currentAccount).isPremiumUser(user) && user.photo.has_video && !SharedConfig.getLiteMode().enabled()) { final TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(user.id); if (userFull == null) { MessagesController.getInstance(currentAccount).loadFullUser(user, currentGuid, false); } else { - TLRPC.Photo photo = userFull.profile_photo; + TLRPC.Photo photo = user.photo.personal ? userFull.personal_photo : userFull.profile_photo; if (photo != null) { - ArrayList videoSizes = photo.video_sizes; - if (videoSizes != null && !videoSizes.isEmpty()) { - TLRPC.VideoSize videoSize = videoSizes.get(0); - for (int i = 0; i < videoSizes.size(); i++) { - TLRPC.VideoSize videoSize1 = videoSizes.get(i); - if ("p".equals(videoSize1.type)) { - videoSize = videoSize1; - break; + vectorImageMarkup = FileLoader.getVectorMarkupVideoSize(photo); + if (vectorImageMarkup == null) { + ArrayList videoSizes = photo.video_sizes; + if (videoSizes != null && !videoSizes.isEmpty()) { + TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(videoSizes, 100); + for (int i = 0; i < videoSizes.size(); i++) { + TLRPC.VideoSize videoSize1 = videoSizes.get(i); + if ("p".equals(videoSize1.type)) { + videoSize = videoSize1; + } + if (videoSize1 instanceof TLRPC.TL_videoSizeEmojiMarkup || videoSize1 instanceof TLRPC.TL_videoSizeStickerMarkup) { + vectorImageMarkup = videoSize1; + } } + videoLocation = ImageLocation.getForPhoto(videoSize, photo); } - videoLocation = ImageLocation.getForPhoto(videoSize, photo); } } } @@ -416,18 +435,23 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg hasStripped = chat.photo.stripped_thumb != null; } } - ImageLocation location = ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_SMALL); - String filter = "50_50"; - if (videoLocation != null) { - setImage(videoLocation, "avatar", location, filter, null, null, strippedBitmap, 0, null, parentObject, 0); - animatedFileDrawableRepeatMaxCount = 3; + if (vectorImageMarkup != null && vectorType != 0) { + VectorAvatarThumbDrawable drawable = new VectorAvatarThumbDrawable(vectorImageMarkup, isPremium, vectorType); + setImageBitmap(drawable); } else { - if (strippedBitmap != null) { - setImage(location, filter, strippedBitmap, null, parentObject, 0); - } else if (hasStripped) { - setImage(location, filter, ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_STRIPPED), "50_50_b", avatarDrawable, parentObject, 0); + ImageLocation location = ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_SMALL); + String filter = "50_50"; + if (videoLocation != null) { + setImage(videoLocation, "avatar", location, filter, null, null, strippedBitmap, 0, null, parentObject, 0); + animatedFileDrawableRepeatMaxCount = 3; } else { - setImage(location, filter, avatarDrawable, null, parentObject, 0); + if (strippedBitmap != null) { + setImage(location, filter, strippedBitmap, null, parentObject, 0); + } else if (hasStripped) { + setImage(location, filter, ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_STRIPPED), "50_50_b", avatarDrawable, parentObject, 0); + } else { + setImage(location, filter, avatarDrawable, null, parentObject, 0); + } } } @@ -501,7 +525,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg currentParentObject = null; currentCacheType = 0; roundPaint.setShader(null); - staticThumbDrawable = thumb; + setStaticDrawable(thumb); currentAlpha = 1.0f; previousAlpha = 1f; currentSize = 0; @@ -653,7 +677,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg currentExt = ext; currentSize = size; currentCacheType = cacheType; - staticThumbDrawable = thumb; + setStaticDrawable(thumb); imageShader = null; composeShader = null; thumbShader = null; @@ -820,7 +844,8 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } thumbShader = null; roundPaint.setShader(null); - staticThumbDrawable = bitmap; + setStaticDrawable(bitmap); + updateDrawableRadius(bitmap); currentMediaLocation = null; currentMediaFilter = null; @@ -870,6 +895,26 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } } + private void setStaticDrawable(Drawable bitmap) { + if (bitmap == staticThumbDrawable) { + return; + } + AttachableDrawable oldDrawable = null; + if (staticThumbDrawable instanceof AttachableDrawable) { + if (staticThumbDrawable.equals(bitmap)) { + return; + } + oldDrawable = (AttachableDrawable) staticThumbDrawable; + } + staticThumbDrawable = bitmap; + if (attachedToWindow && staticThumbDrawable instanceof AttachableDrawable) { + ((AttachableDrawable) staticThumbDrawable).onAttachedToWindow(this); + } + if (attachedToWindow && oldDrawable != null) { + oldDrawable.onDetachedFromWindow(this); + } + } + private void setDrawableShader(Drawable drawable, BitmapShader shader) { if (drawable == currentThumbDrawable || drawable == staticThumbDrawable) { thumbShader = shader; @@ -965,9 +1010,12 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.stopAllHeavyOperations); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.startAllHeavyOperations); } + if (staticThumbDrawable instanceof AttachableDrawable) { + ((AttachableDrawable) staticThumbDrawable).onDetachedFromWindow(this); + } if (staticThumbDrawable != null) { - staticThumbDrawable = null; + setStaticDrawable(null); thumbShader = null; roundPaint.setShader(null); } @@ -1055,6 +1103,9 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg if (NotificationCenter.getGlobalInstance().isAnimationInProgress()) { didReceivedNotification(NotificationCenter.stopAllHeavyOperations, currentAccount, 512); } + if (staticThumbDrawable instanceof AttachableDrawable) { + ((AttachableDrawable) staticThumbDrawable).onAttachedToWindow(this); + } return false; } @@ -1888,6 +1939,9 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg checkAlphaAnimation(animationNotReady && crossfadeWithThumb, backgroundThreadDrawHolder); result = true; } else if (staticThumbDrawable != null) { + if (staticThumbDrawable instanceof VectorAvatarThumbDrawable) { + ((VectorAvatarThumbDrawable) staticThumbDrawable).setParent(this); + } drawDrawable(canvas, staticThumbDrawable, (int) (overrideAlpha * 255), null, thumbOrientation, backgroundThreadDrawHolder); checkAlphaAnimation(animationNotReady, backgroundThreadDrawHolder); result = true; @@ -2134,7 +2188,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } public boolean hasNotThumb() { - return currentImageDrawable != null || currentMediaDrawable != null; + return currentImageDrawable != null || currentMediaDrawable != null || staticThumbDrawable instanceof VectorAvatarThumbDrawable; } public boolean hasStaticThumb() { @@ -2872,7 +2926,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg currentThumbDrawable = null; thumbShader = null; roundPaint.setShader(null); - staticThumbDrawable = thumb; + setStaticDrawable(thumb); crossfadeWithThumb = true; currentAlpha = 0f; updateDrawableRadius(staticThumbDrawable); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index 75decfcfa..2c444dc42 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -442,7 +442,7 @@ public class LocaleController { public LocaleInfo getBuiltinLanguageByPlural(String plural) { Collection values = languagesDict.values(); for (LocaleInfo l : values) - if (l.pathToFile != null && l.pathToFile.equals("remote") && l.pluralLangCode != null && l.pluralLangCode.equals(plural)) + if (l.pathToFile != null && l.pathToFile.equals("remote") && !"en_raw".equals(l.shortName) && l.pluralLangCode != null && l.pluralLangCode.equals(plural)) return l; return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index cacf807c9..c6bee0115 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -352,6 +352,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, public boolean isChatPreviewSpoilerRevealed; public boolean isAttachSpoilerRevealed; + public TLRPC.VideoSize emojiMarkup; public PhotoEntry(int bucketId, int imageId, long dateTaken, String path, int orientation, boolean isVideo, int width, int height, long size) { this.bucketId = bucketId; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 4c8c27238..5b060af5a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -44,6 +44,8 @@ import androidx.core.content.pm.ShortcutInfoCompat; import androidx.core.content.pm.ShortcutManagerCompat; import androidx.core.graphics.drawable.IconCompat; +import com.android.billingclient.api.ProductDetails; + import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteDatabase; import org.telegram.SQLite.SQLiteException; @@ -71,6 +73,7 @@ import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PremiumPreviewFragment; import java.io.File; import java.util.ArrayList; @@ -177,6 +180,8 @@ public class MediaDataController extends BaseController { loadStickersByEmojiOrName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME, false, true); loadEmojiThemes(); loadRecentAndTopReactions(false); + loadAvatarConstructor(false); + loadAvatarConstructor(true); ringtoneDataStore = new RingtoneDataStore(currentAccount); } @@ -386,6 +391,70 @@ public class MediaDataController extends BaseController { return premiumPromo; } + public Integer getPremiumHintAnnualDiscount(boolean checkTransaction) { + if (checkTransaction && (!BillingController.getInstance().isReady() || BillingController.getInstance().getLastPremiumTransaction() == null) || premiumPromo == null) { + return null; + } + + boolean found = false; + int discount = 0; + double currentPrice = 0; + for (TLRPC.TL_premiumSubscriptionOption option : premiumPromo.period_options) { + if (checkTransaction ? option.current && Objects.equals(option.transaction.replaceAll(PremiumPreviewFragment.TRANSACTION_PATTERN, "$1"), BillingController.getInstance().getLastPremiumTransaction()) : option.months == 1) { + found = true; + + if (!BuildVars.useInvoiceBilling() && BillingController.PREMIUM_PRODUCT_DETAILS != null) { + ProductDetails.SubscriptionOfferDetails offerDetails = null; + for (ProductDetails.SubscriptionOfferDetails details : BillingController.PREMIUM_PRODUCT_DETAILS.getSubscriptionOfferDetails()) { + String period = details.getPricingPhases().getPricingPhaseList().get(0).getBillingPeriod(); + if (option.months == 12 ? period.equals("P1Y") : period.equals(String.format(Locale.ROOT, "P%dM", option.months))) { + offerDetails = details; + break; + } + } + + if (offerDetails == null) { + currentPrice = (double) option.amount / option.months; + } else { + currentPrice = (double) offerDetails.getPricingPhases().getPricingPhaseList().get(0).getPriceAmountMicros() / option.months; + } + } else { + currentPrice = (double) option.amount / option.months; + } + } + } + for (TLRPC.TL_premiumSubscriptionOption option : premiumPromo.period_options) { + if (found && option.months == 12) { + double amount; + if (!BuildVars.useInvoiceBilling() && BillingController.PREMIUM_PRODUCT_DETAILS != null) { + ProductDetails.SubscriptionOfferDetails offerDetails = null; + for (ProductDetails.SubscriptionOfferDetails details : BillingController.PREMIUM_PRODUCT_DETAILS.getSubscriptionOfferDetails()) { + String period = details.getPricingPhases().getPricingPhaseList().get(0).getBillingPeriod(); + if (option.months == 12 ? period.equals("P1Y") : period.equals(String.format(Locale.ROOT, "P%dM", option.months))) { + offerDetails = details; + break; + } + } + + if (offerDetails == null) { + amount = (double) option.amount / option.months; + } else { + amount = (double) offerDetails.getPricingPhases().getPricingPhaseList().get(0).getPriceAmountMicros() / option.months; + } + } else { + amount = (double) option.amount / option.months; + } + + discount = (int) ((1.0 - amount / currentPrice) * 100); + } + } + if (!found || discount <= 0) { + return null; + } + + return discount; + } + public TLRPC.TL_attachMenuBots getAttachMenuBots() { return attachMenuBots; } @@ -1109,7 +1178,7 @@ public class MediaDataController extends BaseController { } return cacheSet; } - if (inputStickerSet instanceof TLRPC.TL_inputStickerSetID && hash != null) { + if (inputStickerSet instanceof TLRPC.TL_inputStickerSetID) { getMessagesStorage().getStorageQueue().postRunnable(() -> { TLRPC.TL_messages_stickerSet cachedSet = getCachedStickerSetInternal(inputStickerSet.id, hash); AndroidUtilities.runOnUIThread(() -> { @@ -1191,7 +1260,7 @@ public class MediaDataController extends BaseController { if (data != null) { set = TLRPC.TL_messages_stickerSet.TLdeserialize(data, data.readInt32(false), false); int cachedHash = cursor.intValue(1); - if (hash != null && hash != cachedHash) { + if (hash != null && hash != 0 && hash != cachedHash) { return null; } } @@ -3715,12 +3784,14 @@ public class MediaDataController extends BaseController { boolean isAnimated = false; boolean isVideo = false; boolean isVoice = false; + boolean isRound = false; boolean isMusic = false; boolean isSticker = false; for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + isRound = attribute.round_message; isVoice = attribute.round_message; isVideo = !attribute.round_message; } else if (attribute instanceof TLRPC.TL_documentAttributeAnimated) { @@ -3732,7 +3803,7 @@ public class MediaDataController extends BaseController { isSticker = true; } } - if (isVoice) { + if (isVoice || isRound) { return MEDIA_AUDIO; } else if (isVideo && !isAnimated && !isSticker) { return MEDIA_PHOTOVIDEO; @@ -3801,12 +3872,29 @@ public class MediaDataController extends BaseController { } getFileLoader().checkMediaExistance(objects); - AndroidUtilities.runOnUIThread(() -> { - int totalCount = res.count; - getMessagesController().putUsers(res.users, fromCache != 0); - getMessagesController().putChats(res.chats, fromCache != 0); - getNotificationCenter().postNotificationName(NotificationCenter.mediaDidLoad, dialogId, totalCount, objects, classGuid, type, topReached, min_id != 0, requestIndex); - }); + Runnable notify = () -> { + AndroidUtilities.runOnUIThread(() -> { + int totalCount = res.count; + getMessagesController().putUsers(res.users, fromCache != 0); + getMessagesController().putChats(res.chats, fromCache != 0); + getNotificationCenter().postNotificationName(NotificationCenter.mediaDidLoad, dialogId, totalCount, objects, classGuid, type, topReached, min_id != 0, requestIndex); + }); + }; + + if (getMessagesController().getTranslateController().isFeatureAvailable()) { + getMessagesStorage().getStorageQueue().postRunnable(() -> { + for (int i = 0; i < objects.size(); ++i) { + MessageObject messageObject = objects.get(i); + TLRPC.Message message = getMessagesStorage().getMessageWithCustomParamsOnlyInternal(messageObject.getId(), messageObject.getDialogId()); + messageObject.messageOwner.translatedToLanguage = message.translatedToLanguage; + messageObject.messageOwner.translatedText = message.translatedText; + messageObject.updateTranslation(); + } + notify.run(); + }); + } else { + notify.run(); + } }); } } @@ -7071,14 +7159,14 @@ public class MediaDataController extends BaseController { } public void getEmojiSuggestions(String[] langCodes, String keyword, boolean fullMatch, KeywordResultCallback callback, boolean allowAnimated) { - getEmojiSuggestions(langCodes, keyword, fullMatch, callback, null, allowAnimated, false, null); + getEmojiSuggestions(langCodes, keyword, fullMatch, callback, null, allowAnimated, false, false, null); } public void getEmojiSuggestions(String[] langCodes, String keyword, boolean fullMatch, KeywordResultCallback callback, final CountDownLatch sync, boolean allowAnimated) { - getEmojiSuggestions(langCodes, keyword, fullMatch, callback, sync, allowAnimated, false, null); + getEmojiSuggestions(langCodes, keyword, fullMatch, callback, sync, allowAnimated, false, false, null); } - public void getEmojiSuggestions(String[] langCodes, String keyword, boolean fullMatch, KeywordResultCallback callback, final CountDownLatch sync, boolean allowAnimated, boolean allowTopicIcons, Integer maxAnimatedPerEmoji) { + public void getEmojiSuggestions(String[] langCodes, String keyword, boolean fullMatch, KeywordResultCallback callback, final CountDownLatch sync, boolean allowAnimated, boolean allowTopicIcons, boolean includeSingleEmoji, Integer maxAnimatedPerEmoji) { if (callback == null) { return; } @@ -7116,6 +7204,29 @@ public class MediaDataController extends BaseController { return; } + if (includeSingleEmoji) { + final int[] emojiOnly = new int[1]; + ArrayList ranges = Emoji.parseEmojis(keyword, emojiOnly); + if (emojiOnly[0] > 0) { + for (int i = 0; i < ranges.size(); ++i) { + String code = ranges.get(i).code.toString(); + boolean foundDuplicate = false; + for (int j = 0; j < result.size(); ++j) { + if (TextUtils.equals(result.get(j).emoji, code)) { + foundDuplicate = true; + break; + } + } + if (!foundDuplicate) { + KeywordResult keywordResult = new KeywordResult(); + keywordResult.emoji = code; + keywordResult.keyword = ""; + result.add(keywordResult); + } + } + } + } + String key = keyword.toLowerCase(); for (int a = 0; a < 2; a++) { if (a == 1) { @@ -7734,4 +7845,60 @@ public class MediaDataController extends BaseController { } return objects; } + + public TLRPC.TL_emojiList profileAvatarConstructorDefault; + public TLRPC.TL_emojiList groupAvatarConstructorDefault; + + private void loadAvatarConstructor(boolean profile) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("avatar_constructor" + currentAccount, Context.MODE_PRIVATE); + String value; + long lastCheckTime; + if (profile) { + value = preferences.getString("profile", null); + lastCheckTime = preferences.getLong("profile_last_check", 0); + } else { + value = preferences.getString("group", null); + lastCheckTime = preferences.getLong("group_last_check", 0); + } + + + TLRPC.TL_emojiList emojiList = null; + if (value != null) { + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + try { + emojiList = (TLRPC.TL_emojiList) TLRPC.TL_emojiList.TLdeserialize(serializedData, serializedData.readInt32(true), true); + if (profile) { + profileAvatarConstructorDefault = emojiList; + } else { + groupAvatarConstructorDefault = emojiList; + } + } catch (Throwable e) { + FileLog.e(e); + } + } + + if (emojiList == null || (System.currentTimeMillis() - lastCheckTime) > 24 * 60 * 60 * 1000 || BuildVars.DEBUG_PRIVATE_VERSION) { + TLRPC.TL_account_getDefaultProfilePhotoEmojis req = new TLRPC.TL_account_getDefaultProfilePhotoEmojis(); + if (emojiList != null) { + req.hash = emojiList.hash; + } + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_emojiList) { + SerializedData data = new SerializedData(response.getObjectSize()); + response.serializeToStream(data); + SharedPreferences.Editor editor = preferences.edit(); + if (profile) { + profileAvatarConstructorDefault = (TLRPC.TL_emojiList) response; + editor.putString("profile", Utilities.bytesToHex(data.toByteArray())); + editor.putLong("profile_last_check", System.currentTimeMillis()); + } else { + groupAvatarConstructorDefault = (TLRPC.TL_emojiList) response; + editor.putString("group", Utilities.bytesToHex(data.toByteArray())); + editor.putLong("group_last_check", System.currentTimeMillis()); + } + editor.apply(); + } + })); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageCustomParamsHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageCustomParamsHelper.java index 44f57a0fb..8077a925f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageCustomParamsHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageCustomParamsHelper.java @@ -14,7 +14,10 @@ public class MessageCustomParamsHelper { !message.voiceTranscriptionRated && !message.voiceTranscriptionForce && message.voiceTranscriptionId == 0 && - !message.premiumEffectWasPlayed; + !message.premiumEffectWasPlayed && + message.originalLanguage == null && + message.translatedToLanguage == null && + message.translatedText == null; } public static void copyParams(TLRPC.Message fromMessage, TLRPC.Message toMessage) { @@ -25,6 +28,9 @@ public class MessageCustomParamsHelper { toMessage.voiceTranscriptionRated = fromMessage.voiceTranscriptionRated; toMessage.voiceTranscriptionId = fromMessage.voiceTranscriptionId; toMessage.premiumEffectWasPlayed = fromMessage.premiumEffectWasPlayed; + toMessage.originalLanguage = fromMessage.originalLanguage; + toMessage.translatedToLanguage = fromMessage.translatedToLanguage; + toMessage.translatedText = fromMessage.translatedText; } @@ -69,6 +75,10 @@ public class MessageCustomParamsHelper { this.message = message; flags += message.voiceTranscription != null ? 1 : 0; flags += message.voiceTranscriptionForce ? 2 : 0; + + flags += message.originalLanguage != null ? 4 : 0; + flags += message.translatedToLanguage != null ? 8 : 0; + flags += message.translatedText != null ? 16 : 0; } @Override @@ -85,6 +95,16 @@ public class MessageCustomParamsHelper { stream.writeInt64(message.voiceTranscriptionId); stream.writeBool(message.premiumEffectWasPlayed); + + if ((flags & 4) != 0) { + stream.writeString(message.originalLanguage); + } + if ((flags & 8) != 0) { + stream.writeString(message.translatedToLanguage); + } + if ((flags & 16) != 0) { + message.translatedText.serializeToStream(stream); + } } @Override @@ -100,6 +120,16 @@ public class MessageCustomParamsHelper { message.voiceTranscriptionId = stream.readInt64(exception); message.premiumEffectWasPlayed = stream.readBool(exception); + + if ((flags & 4) != 0) { + message.originalLanguage = stream.readString(exception); + } + if ((flags & 8) != 0) { + message.translatedToLanguage = stream.readString(exception); + } + if ((flags & 16) != 0) { + message.translatedText = TLRPC.TL_textWithEntities.TLdeserialize(stream, stream.readInt32(exception), exception); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index c3cbaf844..f9197e24a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -56,6 +56,7 @@ import org.telegram.ui.Components.URLSpanNoUnderlineBold; import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.Components.spoilers.SpoilerEffect; +import org.w3c.dom.Text; import java.io.BufferedReader; import java.io.File; @@ -114,6 +115,7 @@ public class MessageObject { public Long emojiAnimatedStickerId; public boolean isTopicMainMessage; public boolean settingAvatar; + public TLRPC.VideoSize emojiMarkup; private boolean emojiAnimatedStickerLoading; public String emojiAnimatedStickerColor; public CharSequence messageText; @@ -222,7 +224,6 @@ public class MessageObject { public int textHeight; public boolean hasRtl; public float textXOffset; - public int linesCount; public SendAnimationData sendAnimationData; @@ -1170,6 +1171,7 @@ public class MessageObject { updateMessageText(users, chats, sUsers, sChats); setType(); + updateTranslation(false); measureInlineBotButtons(); Calendar rightNow = new GregorianCalendar(); @@ -1191,7 +1193,7 @@ public class MessageObject { } int[] emojiOnly = allowsBigEmoji() ? new int[1] : null; messageText = Emoji.replaceEmoji(messageText, paint.getFontMetricsInt(), AndroidUtilities.dp(20), false, emojiOnly); - messageText = replaceAnimatedEmoji(messageText, messageOwner.entities, paint.getFontMetricsInt()); + messageText = replaceAnimatedEmoji(messageText, paint.getFontMetricsInt()); if (emojiOnly != null && emojiOnly[0] > 1) { replaceEmojiToLottieFrame(messageText, emojiOnly); } @@ -2415,7 +2417,7 @@ public class MessageObject { int[] emojiOnly = allowsBigEmoji() ? new int[1] : null; messageText = Emoji.replaceEmoji(messageText, paint.getFontMetricsInt(), AndroidUtilities.dp(20), false, emojiOnly); - messageText = replaceAnimatedEmoji(messageText, messageOwner.entities, paint.getFontMetricsInt()); + messageText = replaceAnimatedEmoji(messageText, paint.getFontMetricsInt()); if (emojiOnly != null && emojiOnly[0] > 1) { replaceEmojiToLottieFrame(messageText, emojiOnly); } @@ -2511,7 +2513,38 @@ public class MessageObject { return name; } + public boolean updateTranslation() { + return updateTranslation(true); + } + + public boolean translated = false; + public boolean updateTranslation(boolean force) { + boolean replyUpdated = replyMessageObject != null && replyMessageObject.updateTranslation(force); + if ( + TranslateController.isTranslatable(this) && + MessagesController.getInstance(currentAccount).getTranslateController().isTranslatingDialog(getDialogId()) && + messageOwner != null && + messageOwner.translatedText != null && + TextUtils.equals(MessagesController.getInstance(currentAccount).getTranslateController().getDialogTranslateTo(getDialogId()), messageOwner.translatedToLanguage) + ) { + if (translated) { + return replyUpdated || false; + } + translated = true; + applyNewText(messageOwner.translatedText.text); + generateCaption(); + return replyUpdated || true; + } else if (messageOwner != null && (force || translated)) { + translated = false; + applyNewText(messageOwner.message); + generateCaption(); + return replyUpdated || true; + } + return replyUpdated || false; + } + public void applyNewText() { + translated = false; applyNewText(messageOwner.message); } @@ -2524,6 +2557,7 @@ public class MessageObject { fromUser = MessagesController.getInstance(currentAccount).getUser(messageOwner.from_id.user_id); } messageText = text; + ArrayList entities = translated && messageOwner.translatedText != null ? messageOwner.translatedText.entities : messageOwner.entities; TextPaint paint; if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGame) { paint = Theme.chat_msgGameTextPaint; @@ -2532,7 +2566,7 @@ public class MessageObject { } int[] emojiOnly = allowsBigEmoji() ? new int[1] : null; messageText = Emoji.replaceEmoji(messageText, paint.getFontMetricsInt(), AndroidUtilities.dp(20), false, emojiOnly); - messageText = replaceAnimatedEmoji(messageText, messageOwner.entities, paint.getFontMetricsInt()); + messageText = replaceAnimatedEmoji(messageText, entities, paint.getFontMetricsInt()); if (emojiOnly != null && emojiOnly[0] > 1) { replaceEmojiToLottieFrame(messageText, emojiOnly); } @@ -2668,7 +2702,7 @@ public class MessageObject { } mess = Emoji.replaceEmoji(mess, Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); if (replyMessageObject != null && replyMessageObject.messageOwner != null) { - mess = replaceAnimatedEmoji(mess, replyMessageObject.messageOwner.entities, Theme.chat_msgTextPaint.getFontMetricsInt()); + mess = replyMessageObject.replaceAnimatedEmoji(mess, Theme.chat_msgTextPaint.getFontMetricsInt()); } MediaDataController.addTextStyleRuns(replyMessageObject, (Spannable) mess); if (ellipsize) { @@ -3375,6 +3409,41 @@ public class MessageObject { } } else if (messageOwner.action instanceof TLRPC.TL_messageActionAttachMenuBotAllowed) { messageText = LocaleController.getString(R.string.ActionAttachMenuBotAllowed); + } else if (messageOwner.action instanceof TLRPC.TL_messageActionRequestedPeer) { + TLRPC.Peer peer = ((TLRPC.TL_messageActionRequestedPeer) messageOwner.action).peer; + TLObject peerObject = null; + if (peer instanceof TLRPC.TL_peerUser) { + peerObject = MessagesController.getInstance(currentAccount).getUser(peer.user_id); + if (peerObject == null) { + peerObject = getUser(users, sUsers, peer.user_id); + } + } else if (peer instanceof TLRPC.TL_peerChat) { + peerObject = MessagesController.getInstance(currentAccount).getChat(peer.chat_id); + if (peerObject == null) { + peerObject = getChat(chats, sChats, peer.chat_id); + } + } else if (peer instanceof TLRPC.TL_peerChannel) { + peerObject = MessagesController.getInstance(currentAccount).getChat(peer.channel_id); + if (peerObject == null) { + peerObject = getChat(chats, sChats, peer.channel_id); + } + } + TLRPC.User bot = MessagesController.getInstance(currentAccount).getUser(getDialogId()); + if (bot == null) { + bot = getUser(users, sUsers, getDialogId()); + } + if (peerObject == null) { + if (peer instanceof TLRPC.TL_peerUser) { + messageText = LocaleController.getString(R.string.ActionRequestedPeerUser); + } else if (peer instanceof TLRPC.TL_peerChat) { + messageText = LocaleController.getString(R.string.ActionRequestedPeerChat); + } else { + messageText = LocaleController.getString(R.string.ActionRequestedPeerChannel); + } + } else { + messageText = replaceWithLink(LocaleController.getString(R.string.ActionRequestedPeer), "un1", peerObject); + } + messageText = replaceWithLink(messageText, "un2", bot); } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL) { TLRPC.TL_messageActionSetMessagesTTL action = (TLRPC.TL_messageActionSetMessagesTTL) messageOwner.action; TLRPC.Chat chat = messageOwner.peer_id != null && messageOwner.peer_id.channel_id != 0 ? getChat(chats, sChats, messageOwner.peer_id.channel_id) : null; @@ -3824,7 +3893,7 @@ public class MessageObject { } else { type = TYPE_ANIMATED_STICKER; } - } else if (!isDice() && emojiOnlyCount >= 1 && !hasUnwrappedEmoji) { + } else if (isMediaEmpty() && !isDice() && emojiOnlyCount >= 1 && !hasUnwrappedEmoji) { type = TYPE_EMOJIS; } else if (isMediaEmpty()) { type = TYPE_TEXT; @@ -3951,7 +4020,7 @@ public class MessageObject { } int[] emojiOnly = allowsBigEmoji() ? new int[1] : null; messageText = Emoji.replaceEmoji(messageText, paint.getFontMetricsInt(), AndroidUtilities.dp(20), false, emojiOnly); - messageText = replaceAnimatedEmoji(messageText, messageOwner.entities, paint.getFontMetricsInt()); + messageText = replaceAnimatedEmoji(messageText, paint.getFontMetricsInt()); if (emojiOnly != null && emojiOnly[0] > 1) { replaceEmojiToLottieFrame(messageText, emojiOnly); } @@ -4546,22 +4615,30 @@ public class MessageObject { ); } + private boolean captionTranslated; + public void generateCaption() { - if (caption != null || isRoundVideo()) { + if (caption != null && translated == captionTranslated || isRoundVideo()) { return; } + String text = messageOwner.message; + ArrayList entities = messageOwner.entities; if (hasExtendedMedia()) { - messageOwner.message = messageOwner.media.description; + text = messageOwner.message = messageOwner.media.description; } - if (!isMediaEmpty() && !(getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGame) && !TextUtils.isEmpty(messageOwner.message)) { - caption = Emoji.replaceEmoji(messageOwner.message, Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); - caption = replaceAnimatedEmoji(caption, messageOwner.entities, Theme.chat_msgTextPaint.getFontMetricsInt()); + if (captionTranslated = translated) { + text = messageOwner.translatedText.text; + entities = messageOwner.translatedText.entities; + } + if (!isMediaEmpty() && !(getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGame) && !TextUtils.isEmpty(text)) { + caption = Emoji.replaceEmoji(text, Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + caption = replaceAnimatedEmoji(caption, Theme.chat_msgTextPaint.getFontMetricsInt()); boolean hasEntities; if (messageOwner.send_state != MESSAGE_SEND_STATE_SENT) { hasEntities = false; } else { - hasEntities = !messageOwner.entities.isEmpty(); + hasEntities = !entities.isEmpty(); } boolean useManualParse = !hasEntities && ( @@ -4819,7 +4896,17 @@ public class MessageObject { entities.add(entityItalic); return addEntitiesToText(text, entities, isOutOwner(), true, photoViewer, useManualParse); } else { - return addEntitiesToText(text, messageOwner.entities, isOutOwner(), true, photoViewer, useManualParse); + ArrayList entities; + if (translated) { + if (messageOwner.translatedText == null) { + entities = null; + } else { + entities = messageOwner.translatedText.entities; + } + } else { + entities = messageOwner.entities; + } + return addEntitiesToText(text, entities, isOutOwner(), true, photoViewer, useManualParse); } } @@ -4847,6 +4934,11 @@ public class MessageObject { } } + public Spannable replaceAnimatedEmoji(CharSequence text, Paint.FontMetricsInt fontMetricsInt) { + ArrayList entities = translated && messageOwner.translatedText != null ? messageOwner.translatedText.entities : messageOwner.entities; + return replaceAnimatedEmoji(text, entities, fontMetricsInt, false); + } + public static Spannable replaceAnimatedEmoji(CharSequence text, ArrayList entities, Paint.FontMetricsInt fontMetricsInt) { return replaceAnimatedEmoji(text, entities, fontMetricsInt, false); } @@ -4866,8 +4958,7 @@ public class MessageObject { if (span != null) { int start = spannable.getSpanStart(span); int end = spannable.getSpanEnd(span); - - if (entity.offset == start && entity.length == (end - start)) { + if (AndroidUtilities.intersect1d(entity.offset, entity.offset + entity.length, start, end)) { spannable.removeSpan(span); emojiSpans[j] = null; } @@ -4903,7 +4994,7 @@ public class MessageObject { Spannable spannable = (Spannable) text; URLSpan[] spans = spannable.getSpans(0, text.length(), URLSpan.class); boolean hasUrls = spans != null && spans.length > 0; - if (entities.isEmpty()) { + if (entities == null || entities.isEmpty()) { return hasUrls; } @@ -5224,11 +5315,13 @@ public class MessageObject { textLayoutBlocks = new ArrayList<>(); textWidth = 0; + ArrayList entities = translated && messageOwner.translatedText != null ? messageOwner.translatedText.entities : messageOwner.entities; + boolean hasEntities; if (messageOwner.send_state != MESSAGE_SEND_STATE_SENT) { hasEntities = false; } else { - hasEntities = !messageOwner.entities.isEmpty(); + hasEntities = !entities.isEmpty(); } boolean useManualParse = !hasEntities && ( @@ -5305,7 +5398,7 @@ public class MessageObject { } textHeight = textLayout.getHeight(); - linesCount = textLayout.getLineCount(); + int linesCount = textLayout.getLineCount(); int linesPreBlock = totalAnimatedEmojiCount >= 50 ? LINES_PER_BLOCK_WITH_EMOJI : LINES_PER_BLOCK; int blocksCount; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 5606cce5f..3c04a5a1c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -26,6 +26,7 @@ import android.os.SystemClock; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Base64; +import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; @@ -401,6 +402,8 @@ public class MessagesController extends BaseController implements NotificationCe private LongSparseArray emojiStatusUntilValues = new LongSparseArray<>(); private TopicsController topicsController; private CacheByChatsController cacheByChatsController; + private TranslateController translateController; + public boolean uploadMarkupVideo; public void getNextReactionMention(long dialogId, int topicId, int count, Consumer callback) { final MessagesStorage messagesStorage = getMessagesStorage(); @@ -590,6 +593,10 @@ public class MessagesController extends BaseController implements NotificationCe return topicsController; } + public TranslateController getTranslateController() { + return translateController; + } + public boolean isForum(long dialogId) { TLRPC.Chat chatLocal = getChat(-dialogId); return chatLocal != null && chatLocal.forum; @@ -1008,6 +1015,10 @@ public class MessagesController extends BaseController implements NotificationCe return localInstance; } + public SharedPreferences getMainSettings() { + return mainPreferences; + } + public static SharedPreferences getNotificationsSettings(int account) { return getInstance(account).notificationsPreferences; } @@ -1152,6 +1163,7 @@ public class MessagesController extends BaseController implements NotificationCe telegramAntispamUserId = mainPreferences.getLong("telegramAntispamUserId", -1); telegramAntispamGroupSizeMin = mainPreferences.getInt("telegramAntispamGroupSizeMin", 100); hiddenMembersGroupSizeMin = mainPreferences.getInt("hiddenMembersGroupSizeMin", 100); + uploadMarkupVideo = mainPreferences.getBoolean("uploadMarkupVideo", true); BuildVars.GOOGLE_AUTH_CLIENT_ID = mainPreferences.getString("googleAuthClientId", BuildVars.GOOGLE_AUTH_CLIENT_ID); Set currencySet = mainPreferences.getStringSet("directPaymentsCurrency", null); @@ -1290,6 +1302,7 @@ public class MessagesController extends BaseController implements NotificationCe topicsController = new TopicsController(num); cacheByChatsController = new CacheByChatsController(num); + translateController = new TranslateController(this); } @@ -1598,6 +1611,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(key); } else { currentDialog.pinned = newDialog.pinned; currentDialog.pinnedNum = newDialog.pinnedNum; @@ -1645,6 +1659,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(key); } } else { // if (newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { @@ -1682,6 +1697,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(key); } } } @@ -1802,13 +1818,29 @@ public class MessagesController extends BaseController implements NotificationCe lockFiltersInternal(); } + public void updateEmojiStatus(TLRPC.EmojiStatus newStatus) { + TLRPC.TL_account_updateEmojiStatus req = new TLRPC.TL_account_updateEmojiStatus(); + req.emoji_status = newStatus; + TLRPC.User user = getUserConfig().getCurrentUser(); + if (user != null) { + user.emoji_status = req.emoji_status; + getNotificationCenter().postNotificationName(NotificationCenter.userEmojiStatusUpdated, user); + getMessagesController().updateEmojiStatusUntilUpdate(user.id, user.emoji_status); + } + getConnectionsManager().sendRequest(req, (res, err) -> { + if (!(res instanceof TLRPC.TL_boolTrue)) { + // TODO: reject + } + }); + } + public void removeFilter(DialogFilter filter) { dialogFilters.remove(filter); dialogFiltersById.remove(filter.id); getNotificationCenter().postNotificationName(NotificationCenter.dialogFiltersUpdated); } - private void loadAppConfig() { + public void loadAppConfig() { if (loadingAppConfig) { return; } @@ -1824,6 +1856,16 @@ public class MessagesController extends BaseController implements NotificationCe for (int a = 0, N = object.value.size(); a < N; a++) { TLRPC.TL_jsonObjectValue value = object.value.get(a); switch (value.key) { + case "upload_markup_video": { + if (value.value instanceof TLRPC.TL_jsonBool) { + if (uploadMarkupVideo != ((TLRPC.TL_jsonBool) value.value).value) { + uploadMarkupVideo = ((TLRPC.TL_jsonBool) value.value).value; + editor.putBoolean("uploadMarkupVideo", uploadMarkupVideo); + changed = true; + } + } + break; + } case "login_google_oauth_client_id": { if (value.value instanceof TLRPC.TL_jsonString) { String str = ((TLRPC.TL_jsonString) value.value).value; @@ -3450,6 +3492,7 @@ public class MessagesController extends BaseController implements NotificationCe getLocationController().cleanup(); getMediaDataController().cleanup(); getColorPalette().cleanup(); + getTranslateController().cleanup(); showFiltersTooltip = false; @@ -4433,6 +4476,7 @@ public class MessagesController extends BaseController implements NotificationCe res.full_chat.inviterId = old.inviterId; } fullChats.put(chatId, res.full_chat); + getTranslateController().updateDialogFull(-chatId); applyDialogNotificationsSettings(-chatId, 0, res.full_chat.notify_settings); for (int a = 0; a < res.full_chat.bot_info.size(); a++) { @@ -4530,6 +4574,7 @@ public class MessagesController extends BaseController implements NotificationCe } } fullUsers.put(user.id, userFull); + getTranslateController().updateDialogFull(user.id); loadingFullUsers.remove(user.id); loadedFullUsers.put(user.id, System.currentTimeMillis()); String names = user.first_name + user.last_name + UserObject.getPublicUsername(user); @@ -5269,7 +5314,7 @@ public class MessagesController extends BaseController implements NotificationCe if (photo == null) { TLRPC.TL_photos_updateProfilePhoto req = new TLRPC.TL_photos_updateProfilePhoto(); req.id = new TLRPC.TL_inputPhotoEmpty(); - getUserConfig().getCurrentUser().photo = new TLRPC.TL_userProfilePhotoEmpty(); + // getUserConfig().getCurrentUser().photo = new TLRPC.TL_userProfilePhotoEmpty(); TLRPC.User user = getUser(getUserConfig().getClientUserId()); if (user == null) { user = getUserConfig().getCurrentUser(); @@ -5277,39 +5322,49 @@ public class MessagesController extends BaseController implements NotificationCe if (user == null) { return; } - user.photo = getUserConfig().getCurrentUser().photo; + getMessagesStorage().clearUserPhoto(user.id, user.photo.photo_id); + // user.photo = getUserConfig().getCurrentUser().photo; getNotificationCenter().postNotificationName(NotificationCenter.mainUserInfoChanged); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_ALL); + getConnectionsManager().sendRequest(req, (response, error) -> { if (error == null) { - TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; - TLRPC.User user1 = getUser(getUserConfig().getClientUserId()); - if (user1 == null) { - user1 = getUserConfig().getCurrentUser(); - putUser(user1, false); - } else { - getUserConfig().setCurrentUser(user1); - } - if (user1 == null) { - return; - } - getMessagesStorage().clearUserPhotos(user1.id); - ArrayList users = new ArrayList<>(); - users.add(user1); - getMessagesStorage().putUsersAndChats(users, null, false, true); - if (photos_photo.photo instanceof TLRPC.TL_photo) { - user1.photo = new TLRPC.TL_userProfilePhoto(); - user1.photo.has_video = !photos_photo.photo.video_sizes.isEmpty(); - user1.photo.photo_id = photos_photo.photo.id; - user1.photo.photo_small = FileLoader.getClosestPhotoSizeWithSize(photos_photo.photo.sizes, 150).location; - user1.photo.photo_big = FileLoader.getClosestPhotoSizeWithSize(photos_photo.photo.sizes, 800).location; - user1.photo.dc_id = photos_photo.photo.dc_id; - } else { - user1.photo = new TLRPC.TL_userProfilePhotoEmpty(); - } AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; + TLRPC.User user1 = getUser(getUserConfig().getClientUserId()); + if (user1 == null) { + user1 = getUserConfig().getCurrentUser(); + putUser(user1, false); + } else { + getUserConfig().setCurrentUser(user1); + } + if (user1 == null) { + return; + } + ArrayList users = new ArrayList<>(); + users.add(user1); + getMessagesStorage().putUsersAndChats(users, null, false, true); + if (photos_photo.photo instanceof TLRPC.TL_photo) { + user1.photo = new TLRPC.TL_userProfilePhoto(); + user1.photo.has_video = !photos_photo.photo.video_sizes.isEmpty(); + user1.photo.photo_id = photos_photo.photo.id; + user1.photo.photo_small = FileLoader.getClosestPhotoSizeWithSize(photos_photo.photo.sizes, 150).location; + user1.photo.photo_big = FileLoader.getClosestPhotoSizeWithSize(photos_photo.photo.sizes, 800).location; + user1.photo.dc_id = photos_photo.photo.dc_id; + } else { + user1.photo = new TLRPC.TL_userProfilePhotoEmpty(); + } + + TLRPC.UserFull userFull = getUserFull(getUserConfig().getClientUserId()); + userFull.profile_photo = photos_photo.photo; + getMessagesStorage().updateUserInfo(userFull, false); + + getUserConfig().getCurrentUser().photo = user1.photo; + putUser(user1, false); + getNotificationCenter().postNotificationName(NotificationCenter.mainUserInfoChanged); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_ALL); + getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_AVATAR); getUserConfig().saveConfig(true); }); } @@ -6336,6 +6391,7 @@ public class MessagesController extends BaseController implements NotificationCe public void putChatFull(TLRPC.ChatFull chatFull) { fullChats.put(chatFull.id, chatFull); + getTranslateController().updateDialogFull(-chatFull.id); } public void processChatInfo(long chatId, TLRPC.ChatFull info, ArrayList usersArr, boolean fromCache, boolean force, boolean byChannelUsers, ArrayList pinnedMessages, HashMap pinnedMessagesMap, int totalPinnedCount, boolean pinnedEndReached) { @@ -6349,6 +6405,7 @@ public class MessagesController extends BaseController implements NotificationCe if (info != null) { if (fullChats.get(chatId) == null) { fullChats.put(chatId, info); + getTranslateController().updateDialogFull(-chatId); } putUsers(usersArr, fromCache); if (info.stickerset != null) { @@ -6391,6 +6448,7 @@ public class MessagesController extends BaseController implements NotificationCe if (info != null) { if (fullUsers.get(user.id) == null) { fullUsers.put(user.id, info); + getTranslateController().updateDialogFull(user.id); int index = blockePeers.indexOfKey(user.id); if (info.blocked) { @@ -6964,6 +7022,7 @@ public class MessagesController extends BaseController implements NotificationCe if (promoDialog.last_message_date == 0) { promoDialog.last_message_date = messageObject.messageOwner.date; } + getTranslateController().checkDialogMessages(did); } sortDialogs(null); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload, true); @@ -7062,113 +7121,114 @@ public class MessagesController extends BaseController implements NotificationCe newStrings.put(key, newPrintingStrings); newTypes.put(key, newPrintingStringsTypes); + int type = 0; + CharSequence text = null; if (key > 0 || isEncryptedChat || arr.size() == 1) { PrintingUser pu = arr.get(0); TLRPC.User user = getUser(pu.userId); if (user == null) { continue; } + final boolean isGroup = key < 0 && !isEncryptedChat; if (pu.action instanceof TLRPC.TL_sendMessageRecordAudioAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsRecordingAudio", R.string.IsRecordingAudio, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsRecordingAudio", R.string.IsRecordingAudio, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("RecordingAudio", R.string.RecordingAudio)); + text = LocaleController.getString("RecordingAudio", R.string.RecordingAudio); } - newPrintingStringsTypes.put(threadId, 1); + type = 1; } else if (pu.action instanceof TLRPC.TL_sendMessageRecordRoundAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsRecordingRound", R.string.IsRecordingRound, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsRecordingRound", R.string.IsRecordingRound, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("RecordingRound", R.string.RecordingRound)); + text = LocaleController.getString("RecordingRound", R.string.RecordingRound); } - newPrintingStringsTypes.put(threadId, 4); + type = 4; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadRoundAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingVideo", R.string.IsSendingVideo, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingVideo", R.string.IsSendingVideo, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingVideoStatus", R.string.SendingVideoStatus)); + text = LocaleController.getString("SendingVideoStatus", R.string.SendingVideoStatus); } - newPrintingStringsTypes.put(threadId, 4); + type = 4; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadAudioAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingAudio", R.string.IsSendingAudio, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingAudio", R.string.IsSendingAudio, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingAudio", R.string.SendingAudio)); + text = LocaleController.getString("SendingAudio", R.string.SendingAudio); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadVideoAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingVideo", R.string.IsSendingVideo, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingVideo", R.string.IsSendingVideo, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingVideoStatus", R.string.SendingVideoStatus)); + text = LocaleController.getString("SendingVideoStatus", R.string.SendingVideoStatus); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageRecordVideoAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsRecordingVideo", R.string.IsRecordingVideo, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsRecordingVideo", R.string.IsRecordingVideo, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("RecordingVideoStatus", R.string.RecordingVideoStatus)); + text = LocaleController.getString("RecordingVideoStatus", R.string.RecordingVideoStatus); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadDocumentAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingFile", R.string.IsSendingFile, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingFile", R.string.IsSendingFile, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingFile", R.string.SendingFile)); + text = LocaleController.getString("SendingFile", R.string.SendingFile); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadPhotoAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingPhoto", R.string.IsSendingPhoto, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingPhoto", R.string.IsSendingPhoto, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingPhoto", R.string.SendingPhoto)); + text = LocaleController.getString("SendingPhoto", R.string.SendingPhoto); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageGamePlayAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingGame", R.string.IsSendingGame, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingGame", R.string.IsSendingGame, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingGame", R.string.SendingGame)); + text = LocaleController.getString("SendingGame", R.string.SendingGame); } - newPrintingStringsTypes.put(threadId, 3); + type = 3; } else if (pu.action instanceof TLRPC.TL_sendMessageGeoLocationAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSelectingLocation", R.string.IsSelectingLocation, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSelectingLocation", R.string.IsSelectingLocation, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SelectingLocation", R.string.SelectingLocation)); + text = LocaleController.getString("SelectingLocation", R.string.SelectingLocation); } - newPrintingStringsTypes.put(threadId, 0); + type = 0; } else if (pu.action instanceof TLRPC.TL_sendMessageChooseContactAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSelectingContact", R.string.IsSelectingContact, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSelectingContact", R.string.IsSelectingContact, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SelectingContact", R.string.SelectingContact)); + text = LocaleController.getString("SelectingContact", R.string.SelectingContact); } - newPrintingStringsTypes.put(threadId, 0); + type = 0; } else if (pu.action instanceof TLRPC.TL_sendMessageEmojiInteractionSeen) { - String emoji = ((TLRPC.TL_sendMessageEmojiInteractionSeen) pu.action).emoticon; - String printingString; - if (key < 0 && !isEncryptedChat) { - printingString = LocaleController.formatString("IsEnjoyngAnimations", R.string.IsEnjoyngAnimations, getUserNameForTyping(user), emoji); + final String emoji = ((TLRPC.TL_sendMessageEmojiInteractionSeen) pu.action).emoticon; + if (isGroup) { + text = LocaleController.formatString("IsEnjoyngAnimations", R.string.IsEnjoyngAnimations, getUserNameForTyping(user), emoji); } else { - printingString = LocaleController.formatString("EnjoyngAnimations", R.string.EnjoyngAnimations, emoji); + text = LocaleController.formatString("EnjoyngAnimations", R.string.EnjoyngAnimations, emoji); } - newPrintingStrings.put(threadId, printingString); - newPrintingStringsTypes.put(threadId, 5); + type = 5; } else if (pu.action instanceof TLRPC.TL_sendMessageChooseStickerAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsChoosingSticker", R.string.IsChoosingSticker, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsChoosingSticker", R.string.IsChoosingSticker, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("ChoosingSticker", R.string.ChoosingSticker)); + text = LocaleController.getString("ChoosingSticker", R.string.ChoosingSticker); } - newPrintingStringsTypes.put(threadId, 5); + type = 5; } else { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsTypingGroup", R.string.IsTypingGroup, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsTypingGroup", R.string.IsTypingGroup, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("Typing", R.string.Typing)); + text = LocaleController.getString("Typing", R.string.Typing); } - newPrintingStringsTypes.put(threadId, 0); + type = 0; } } else { int count = 0; @@ -7188,22 +7248,30 @@ public class MessagesController extends BaseController implements NotificationCe } if (label.length() != 0) { if (count == 1) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsTypingGroup", R.string.IsTypingGroup, label.toString())); + text = LocaleController.formatString("IsTypingGroup", R.string.IsTypingGroup, label.toString()); } else { if (arr.size() > 2) { String plural = LocaleController.getPluralString("AndMoreTypingGroup", arr.size() - 2); try { - newPrintingStrings.put(threadId, String.format(plural, label.toString(), arr.size() - 2)); + text = String.format(plural, label.toString(), arr.size() - 2); } catch (Exception e) { - newPrintingStrings.put(threadId, "LOC_ERR: AndMoreTypingGroup"); + text = "LOC_ERR: AndMoreTypingGroup"; } } else { - newPrintingStrings.put(threadId, LocaleController.formatString("AreTypingGroup", R.string.AreTypingGroup, label.toString())); + text = LocaleController.formatString("AreTypingGroup", R.string.AreTypingGroup, label.toString()); } } - newPrintingStringsTypes.put(threadId, 0); + type = 0; } } + if (text != null && ApplicationLoader.applicationContext != null) { + if (Theme.dialogs_messageNamePaint == null) { + Theme.createDialogsResources(ApplicationLoader.applicationContext); + } + text = Emoji.replaceEmoji(text, Theme.dialogs_messageNamePaint.getFontMetricsInt(), false); + newPrintingStrings.put(threadId, text); + newPrintingStringsTypes.put(threadId, type); + } } } @@ -8085,7 +8153,7 @@ public class MessagesController extends BaseController implements NotificationCe getConnectionsManager().sendRequest(req, (response, error) -> { if (error == null) { TLRPC.messages_Dialogs dialogsRes = (TLRPC.messages_Dialogs) response; - processLoadedDialogs(dialogsRes, null, folderId, 0, count, 0, false, false, false); + processLoadedDialogs(dialogsRes, null, null, folderId, 0, count, 0, false, false, false); if (onEmptyCallback != null && dialogsRes.dialogs.isEmpty()) { AndroidUtilities.runOnUIThread(onEmptyCallback); } @@ -8258,7 +8326,7 @@ public class MessagesController extends BaseController implements NotificationCe dialogs.messages.addAll(res.messages); dialogs.users.addAll(res.users); dialogs.chats.addAll(res.chats); - processLoadedDialogs(dialogs, null, dialog.folder_id, 0, 1, DIALOGS_LOAD_TYPE_UNKNOWN, false, false, false); + processLoadedDialogs(dialogs, null, null, dialog.folder_id, 0, 1, DIALOGS_LOAD_TYPE_UNKNOWN, false, false, false); } } if (newTaskId != 0) { @@ -8544,6 +8612,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(key); } allDialogs.clear(); @@ -8764,7 +8833,7 @@ public class MessagesController extends BaseController implements NotificationCe } } - processLoadedDialogs(dialogsRes, null, 0, offsetId, 0, 0, false, true, false); + processLoadedDialogs(dialogsRes, null, null, 0, offsetId, 0, 0, false, true, false); } catch (Exception e) { FileLog.e(e); AndroidUtilities.runOnUIThread(() -> migratingDialogs = false); @@ -8780,7 +8849,7 @@ public class MessagesController extends BaseController implements NotificationCe private int DIALOGS_LOAD_TYPE_CHANNEL = 2; private int DIALOGS_LOAD_TYPE_UNKNOWN = 3; - public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayList encChats, int folderId, int offset, int count, int loadType, boolean resetEnd, boolean migrate, boolean fromCache) { + public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayList encChats, ArrayList fullUsers, int folderId, int offset, int count, int loadType, boolean resetEnd, boolean migrate, boolean fromCache) { Utilities.stageQueue.postRunnable(() -> { if (!firstGettingTask) { getNewDeleteTask(null, null); @@ -8794,6 +8863,13 @@ public class MessagesController extends BaseController implements NotificationCe if (loadType == DIALOGS_LOAD_TYPE_CACHE && dialogsRes.dialogs.size() == 0) { AndroidUtilities.runOnUIThread(() -> { putUsers(dialogsRes.users, true); + if (fullUsers != null) { + for (int i = 0; i < fullUsers.size(); i++) { + long did = fullUsers.get(i).id; + this.fullUsers.put(did, fullUsers.get(i)); + getTranslateController().updateDialogFull(did); + } + } loadingDialogs.put(folderId, false); if (resetEnd) { dialogsEndReached.put(folderId, false); @@ -9040,6 +9116,13 @@ public class MessagesController extends BaseController implements NotificationCe } putUsers(dialogsRes.users, loadType == DIALOGS_LOAD_TYPE_CACHE); putChats(dialogsRes.chats, loadType == DIALOGS_LOAD_TYPE_CACHE); + if (fullUsers != null) { + for (int i = 0; i < fullUsers.size(); i++) { + long did = fullUsers.get(i).id; + this.fullUsers.put(did, fullUsers.get(i)); + getTranslateController().updateDialogFull(did); + } + } if (encChats != null) { for (int a = 0; a < encChats.size(); a++) { @@ -9090,6 +9173,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(key); } else { if (loadType != DIALOGS_LOAD_TYPE_CACHE) { currentDialog.notify_settings = value.notify_settings; @@ -9141,6 +9225,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(key); } } else { // if (newMsg == null && oldMs.getId() > 0 || newMsg != null && newMsg.messageOwner.date > oldMsg.messageOwner.date) @@ -9178,6 +9263,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(key); } } } @@ -9635,6 +9721,7 @@ public class MessagesController extends BaseController implements NotificationCe FileLog.d("processDialogsUpdate new message not null"); } } + getTranslateController().checkDialogMessages(key); } else { if (BuildVars.LOGS_ENABLED) { FileLog.d("processDialogsUpdate dialog not null"); @@ -9694,6 +9781,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(key); } if (fromCache && newMsgs == null) { checkLastDialogMessage(value, null, 0); @@ -9740,6 +9828,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(key); } } } @@ -10268,7 +10357,7 @@ public class MessagesController extends BaseController implements NotificationCe if (type == ChatObject.CHAT_TYPE_CHAT && !forImport) { TLRPC.TL_messages_createChat req = new TLRPC.TL_messages_createChat(); req.title = title; - if (ttlPeriod > 0) { + if (ttlPeriod >= 0) { req.ttl_period = ttlPeriod; req.flags |= 1; } @@ -10299,16 +10388,17 @@ public class MessagesController extends BaseController implements NotificationCe } }); }, ConnectionsManager.RequestFlagFailOnServerErrors); - } else if (forImport || type == ChatObject.CHAT_TYPE_CHANNEL || type == ChatObject.CHAT_TYPE_MEGAGROUP) { + } else if (forImport || type == ChatObject.CHAT_TYPE_CHANNEL || type == ChatObject.CHAT_TYPE_MEGAGROUP || type == ChatObject.CHAT_TYPE_FORUM) { TLRPC.TL_channels_createChannel req = new TLRPC.TL_channels_createChannel(); req.title = title; req.about = about != null ? about : ""; req.for_import = forImport; - if (forImport || type == ChatObject.CHAT_TYPE_MEGAGROUP) { + if (forImport || type == ChatObject.CHAT_TYPE_MEGAGROUP || type == ChatObject.CHAT_TYPE_FORUM) { req.megagroup = true; } else { req.broadcast = true; } + req.forum = type == ChatObject.CHAT_TYPE_FORUM; if (location != null) { req.geo_point = new TLRPC.TL_inputGeoPoint(); req.geo_point.lat = location.getLatitude(); @@ -10962,12 +11052,12 @@ public class MessagesController extends BaseController implements NotificationCe }, ConnectionsManager.RequestFlagInvokeAfter); } - public void changeChatAvatar(long chatId, TLRPC.TL_inputChatPhoto oldPhoto, TLRPC.InputFile inputPhoto, TLRPC.InputFile inputVideo, double videoStartTimestamp, String videoPath, TLRPC.FileLocation smallSize, TLRPC.FileLocation bigSize, Runnable callback) { + public void changeChatAvatar(long chatId, TLRPC.TL_inputChatPhoto oldPhoto, TLRPC.InputFile inputPhoto, TLRPC.InputFile inputVideo, TLRPC.VideoSize emojiMarkup, double videoStartTimestamp, String videoPath, TLRPC.FileLocation smallSize, TLRPC.FileLocation bigSize, Runnable callback) { TLObject request; TLRPC.InputChatPhoto inputChatPhoto; if (oldPhoto != null) { inputChatPhoto = oldPhoto; - } else if (inputPhoto != null || inputVideo != null) { + } else if (inputPhoto != null || inputVideo != null || emojiMarkup != null) { TLRPC.TL_inputChatUploadedPhoto uploadedPhoto = new TLRPC.TL_inputChatUploadedPhoto(); if (inputPhoto != null) { uploadedPhoto.file = inputPhoto; @@ -10979,6 +11069,10 @@ public class MessagesController extends BaseController implements NotificationCe uploadedPhoto.video_start_ts = videoStartTimestamp; uploadedPhoto.flags |= 4; } + if (emojiMarkup != null) { + uploadedPhoto.video_emoji_markup = emojiMarkup; + uploadedPhoto.flags |= 8; + } inputChatPhoto = uploadedPhoto; } else { inputChatPhoto = new TLRPC.TL_inputChatPhotoEmpty(); @@ -11039,6 +11133,7 @@ public class MessagesController extends BaseController implements NotificationCe File src = new File(videoPath); src.renameTo(destFile); } + getMessagesStorage().addDialogPhoto(-chatId, photo); } } processUpdates(updates, false); @@ -11047,6 +11142,7 @@ public class MessagesController extends BaseController implements NotificationCe callback.run(); } getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_AVATAR); + getNotificationCenter().postNotificationName(NotificationCenter.reloadDialogPhotos); }); }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -11076,13 +11172,8 @@ public class MessagesController extends BaseController implements NotificationCe getConnectionsManager().cleanup(false); AndroidUtilities.runOnUIThread(() -> { if (response instanceof TLRPC.TL_auth_loggedOut) { - TLRPC.TL_auth_loggedOut res = (TLRPC.TL_auth_loggedOut) response; if (((TLRPC.TL_auth_loggedOut) response).future_auth_token != null) { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); - int count = preferences.getInt("count", 0); - SerializedData data = new SerializedData(response.getObjectSize()); - res.serializeToStream(data); - preferences.edit().putString("log_out_token_" + count, Utilities.bytesToHex(data.toByteArray())).putInt("count", count + 1).apply(); + AuthTokensHelper.addLogOutToken((TLRPC.TL_auth_loggedOut) response); } } }); @@ -11125,44 +11216,6 @@ public class MessagesController extends BaseController implements NotificationCe getContactsController().deleteUnknownAppAccounts(); } - public static ArrayList getSavedLogOutTokens() { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); - int count = preferences.getInt("count", 0); - if (count == 0) { - return null; - } - - ArrayList tokens = new ArrayList<>(); - for (int i = 0; i < count; i++) { - String value = preferences.getString("log_out_token_" + i, ""); - SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); - TLRPC.TL_auth_loggedOut token = TLRPC.TL_auth_loggedOut.TLdeserialize(serializedData, serializedData.readInt32(true), true); - if (token != null) { - tokens.add(token); - } - } - return tokens; - } - - public static void saveLogOutTokens(ArrayList tokens) { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); - ArrayList activeTokens = new ArrayList<>(); - preferences.edit().clear().apply(); - int date = (int) (System.currentTimeMillis() / 1000L); - for (int i = 0; i < Math.min(20, tokens.size()); i++) { - activeTokens.add(tokens.get(i)); - } - if (activeTokens.size() > 0) { - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("count", activeTokens.size()); - for (int i = 0; i < activeTokens.size(); i++) { - SerializedData data = new SerializedData(activeTokens.get(i).getObjectSize()); - activeTokens.get(i).serializeToStream(data); - editor.putString("log_out_token_" + i, Utilities.bytesToHex(data.toByteArray())); - } - editor.apply(); - } - } private boolean gettingAppChangelog; @@ -11478,7 +11531,7 @@ public class MessagesController extends BaseController implements NotificationCe dialogs.messages.addAll(res.messages); dialogs.users.addAll(res.users); dialogs.chats.addAll(res.chats); - processLoadedDialogs(dialogs, null, dialog.folder_id, 0, 1, DIALOGS_LOAD_TYPE_CHANNEL, false, false, false); + processLoadedDialogs(dialogs, null, null, dialog.folder_id, 0, 1, DIALOGS_LOAD_TYPE_CHANNEL, false, false, false); } } if (newTaskId != 0) { @@ -12458,6 +12511,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + getTranslateController().checkDialogMessages(dialog.id); } changed = true; @@ -14314,6 +14368,7 @@ public class MessagesController extends BaseController implements NotificationCe boolean isDialogCreated = createdDialogIds.contains(message.dialog_id); MessageObject obj = new MessageObject(currentAccount, message, usersDict, chatsDict, isDialogCreated, isDialogCreated); + getTranslateController().invalidateTranslation(obj); LongSparseArray> array; if (editingMessages == null) { @@ -15047,7 +15102,7 @@ public class MessagesController extends BaseController implements NotificationCe } else if (baseUpdate instanceof TLRPC.TL_updateChannelPinnedTopics) { TLRPC.TL_updateChannelPinnedTopics update = (TLRPC.TL_updateChannelPinnedTopics) baseUpdate; - if ((update.flags & 1) > 0) { + if ((update.flags & 1) != 0) { getTopicsController().applyPinnedOrder(update.channel_id, update.order); } else { getTopicsController().reloadTopics(update.channel_id, false); @@ -16283,6 +16338,7 @@ public class MessagesController extends BaseController implements NotificationCe } } dialogMessage.put(dialogId, arrayList); + getTranslateController().checkDialogMessages(dialogId); changed = true; if (filterDialogsChanged) { @@ -16325,6 +16381,7 @@ public class MessagesController extends BaseController implements NotificationCe } } dialogMessage.put(dialogId, arrayList); + getTranslateController().checkDialogMessages(dialogId); if (lastMessage.messageOwner.peer_id.channel_id == 0) { dialogMessagesByIds.put(lastMessage.getId(), lastMessage); if (lastMessage.messageOwner.random_id != 0) { @@ -16344,6 +16401,10 @@ public class MessagesController extends BaseController implements NotificationCe return changed; } + public TLRPC.Dialog getDialog(long did) { + return dialogs_dict.get(did); + } + public void addDialogAction(long did, boolean clean) { TLRPC.Dialog dialog = dialogs_dict.get(did); if (dialog == null) { @@ -16412,7 +16473,11 @@ public class MessagesController extends BaseController implements NotificationCe if (sortingDialogFilter == null) { continue; } - Collections.sort(allDialogs, dialogDateComparator); + try { + Collections.sort(allDialogs, dialogDateComparator); + } catch (Exception e) { + FileLog.e(e); + } ArrayList dialogsByFilter = sortingDialogFilter.dialogs; for (int a = 0, N = allDialogs.size(); a < N; a++) { @@ -16973,6 +17038,73 @@ public class MessagesController extends BaseController implements NotificationCe }); } + public boolean matchesAdminRights(TLRPC.Chat chat, TLRPC.User user, TLRPC.TL_chatAdminRights rights) { + if (rights == null) { + return true; + } + TLRPC.TL_chatAdminRights userRights = getChatAdminRightsCached(chat, user); + return ( + (!rights.change_info || userRights != null && userRights.change_info) && + (!rights.post_messages || userRights != null && userRights.post_messages) && + (!rights.edit_messages || userRights != null && userRights.edit_messages) && + (!rights.delete_messages || userRights != null && userRights.delete_messages) && + (!rights.ban_users || userRights != null && userRights.ban_users) && + (!rights.invite_users || userRights != null && userRights.invite_users) && + (!rights.pin_messages || userRights != null && userRights.pin_messages) && + (!rights.add_admins || userRights != null && userRights.add_admins) && + (!rights.anonymous || userRights != null && userRights.anonymous) && + (!rights.manage_call || userRights != null && userRights.manage_call) && + (!rights.other || userRights != null && userRights.other) && + (!rights.manage_topics || userRights != null && userRights.manage_topics) + ); + } + + public TLRPC.TL_chatAdminRights getChatAdminRightsCached(TLRPC.Chat chat, TLRPC.User user) { + if (chat == null || user == null) { + return null; + } + if (UserObject.isUserSelf(user)) { + return chat.admin_rights; + } + final TLRPC.ChatFull chatFull = getChatFull(chat.id); + if (chatFull == null || chatFull.participants == null || chatFull.participants.participants == null) { + return null; + } + final ArrayList participants = chatFull.participants.participants; + + for (int i = 0; i < participants.size(); ++i) { + TLRPC.ChatParticipant participant = participants.get(i); + if (participant != null && participant.user_id == user.id) { + if (participant instanceof TLRPC.TL_chatChannelParticipant && ((TLRPC.TL_chatChannelParticipant) participant).channelParticipant != null) { + return ((TLRPC.TL_chatChannelParticipant) participant).channelParticipant.admin_rights; + } + return null; + } + } + return null; + } + + public boolean isInChatCached(TLRPC.Chat chat, TLRPC.User user) { + if (chat == null || user == null) { + return false; + } + if (UserObject.isUserSelf(user)) { + return !ChatObject.isNotInChat(chat); + } + final TLRPC.ChatFull chatFull = getChatFull(chat.id); + if (chatFull == null || chatFull.participants == null || chatFull.participants.participants == null) { + return false; + } + final ArrayList participants = chatFull.participants.participants; + for (int i = 0; i < participants.size(); ++i) { + TLRPC.ChatParticipant participant = participants.get(i); + if (participant != null && participant.user_id == user.id) { + return true; + } + } + return false; + } + public void checkIsInChat(boolean tryCacheFirst, TLRPC.Chat chat, TLRPC.User user, IsInChatCheckedCallback callback) { if (chat == null || user == null) { if (callback != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index c6a523a91..e19fd6d6f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -15,6 +15,7 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; +import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.util.SparseIntArray; @@ -34,6 +35,7 @@ import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.DialogsSearchAdapter; +import org.telegram.ui.DialogsActivity; import org.telegram.ui.EditWidgetActivity; import java.io.File; @@ -93,7 +95,7 @@ public class MessagesStorage extends BaseController { } } - private final static int LAST_DB_VERSION = 111; + private final static int LAST_DB_VERSION = 112; private boolean databaseMigrationInProgress; public boolean showClearDatabaseAlert; private LongSparseIntArray dialogIsForum = new LongSparseIntArray(); @@ -447,6 +449,8 @@ public class MessagesStorage extends BaseController { database.executeFast("CREATE TABLE reaction_mentions_topics(message_id INTEGER, state INTEGER, dialog_id INTEGER, topic_id INTEGER, PRIMARY KEY(message_id, dialog_id, topic_id))").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS reaction_mentions_topics_did ON reaction_mentions_topics(dialog_id, topic_id);").stepThis().dispose(); + database.executeFast("CREATE TABLE emoji_groups(type INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose(); + //version database.executeFast("PRAGMA user_version = " + LAST_DB_VERSION).stepThis().dispose(); } else { @@ -502,9 +506,9 @@ public class MessagesStorage extends BaseController { } } catch (Exception e) { FileLog.e(e); - if (BuildVars.DEBUG_PRIVATE_VERSION) { - throw new RuntimeException(e); - } +// if (BuildVars.DEBUG_PRIVATE_VERSION) { +// throw new RuntimeException(e); +// } if (openTries < 3 && e.getMessage() != null && e.getMessage().contains("malformed")) { if (openTries == 2) { cleanupInternal(true); @@ -3917,68 +3921,82 @@ public class MessagesStorage extends BaseController { return; } storageQueue.postRunnable(() -> { - SQLitePreparedStatement state = null; - try { - database.executeFast("DELETE FROM user_photos WHERE uid = " + did).stepThis().dispose(); - state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)"); - for (int a = 0, N = photos.photos.size(); a < N; a++) { - TLRPC.Photo photo = photos.photos.get(a); - if (photo instanceof TLRPC.TL_photoEmpty) { - continue; - } - if (photo.file_reference == null) { - photo.file_reference = new byte[0]; - } - state.requery(); - int size = photo.getObjectSize(); - if (messages != null) { - size += messages.get(a).getObjectSize(); - } - NativeByteBuffer data = new NativeByteBuffer(size); - photo.serializeToStream(data); - if (messages != null) { - messages.get(a).serializeToStream(data); - } - state.bindLong(1, did); - state.bindLong(2, photo.id); - state.bindByteBuffer(3, data); - state.step(); - data.reuse(); - } - state.dispose(); - state = null; - } catch (Exception e) { - FileLog.e(e); - } finally { - if (state != null) { - state.dispose(); - } - } + putDialogPhotosInternal(did, photos, messages); }); } - public void addDialogPhoto(long did, TLRPC.Photo photo) { - storageQueue.postRunnable(() -> { - SQLitePreparedStatement state = null; - try { - state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)"); - + private void putDialogPhotosInternal(long did, TLRPC.photos_Photos photos, ArrayList messages) { + SQLitePreparedStatement state = null; + try { + database.executeFast("DELETE FROM user_photos WHERE uid = " + did).stepThis().dispose(); + state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)"); + for (int a = 0, N = photos.photos.size(); a < N; a++) { + TLRPC.Photo photo = photos.photos.get(a); + if (photo instanceof TLRPC.TL_photoEmpty || photo == null) { + continue; + } + if (photo.file_reference == null) { + photo.file_reference = new byte[0]; + } state.requery(); int size = photo.getObjectSize(); + if (messages != null && messages.get(a) != null) { + size += messages.get(a).getObjectSize(); + } NativeByteBuffer data = new NativeByteBuffer(size); photo.serializeToStream(data); + if (messages != null && messages.get(a) != null) { + messages.get(a).serializeToStream(data); + } state.bindLong(1, did); state.bindLong(2, photo.id); state.bindByteBuffer(3, data); state.step(); data.reuse(); + } + state.dispose(); + state = null; + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { state.dispose(); - state = null; + } + } + } + + public void addDialogPhoto(long did, TLRPC.Photo photoToAdd) { + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d ORDER BY rowid ASC", did)); + + TLRPC.photos_Photos res = new TLRPC.TL_photos_photos(); + ArrayList messages = new ArrayList<>(); + + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Photo photo = TLRPC.Photo.TLdeserialize(data, data.readInt32(false), false); + if (data.remaining() > 0) { + messages.add(TLRPC.Message.TLdeserialize(data, data.readInt32(false), false)); + } else { + messages.add(null); + } + data.reuse(); + res.photos.add(photo); + messages.add(null); + } + } + cursor.dispose(); + cursor = null; + res.photos.add(0, photoToAdd); + putDialogPhotosInternal(did, res, messages); } catch (Exception e) { FileLog.e(e); } finally { - if (state != null) { - state.dispose(); + if (cursor != null) { + cursor.dispose(); } } }); @@ -4260,7 +4278,7 @@ public class MessagesStorage extends BaseController { SQLitePreparedStatement state = null; try { database.beginTransaction(); - TLRPC.Message message = getMessageWithCustomParamsOnly(msgId, dialogId); + TLRPC.Message message = getMessageWithCustomParamsOnlyInternal(msgId, dialogId); message.voiceTranscriptionOpen = saveFromMessage.voiceTranscriptionOpen; message.voiceTranscriptionRated = saveFromMessage.voiceTranscriptionRated; message.voiceTranscriptionFinal = saveFromMessage.voiceTranscriptionFinal; @@ -4308,7 +4326,7 @@ public class MessagesStorage extends BaseController { SQLitePreparedStatement state = null; try { database.beginTransaction(); - TLRPC.Message message = getMessageWithCustomParamsOnly(messageId, dialogId); + TLRPC.Message message = getMessageWithCustomParamsOnlyInternal(messageId, dialogId); message.voiceTranscriptionFinal = isFinal; message.voiceTranscriptionId = transcriptionId; message.voiceTranscription = text; @@ -4348,7 +4366,7 @@ public class MessagesStorage extends BaseController { SQLitePreparedStatement state = null; try { database.beginTransaction(); - TLRPC.Message message = getMessageWithCustomParamsOnly(messageId, dialogId); + TLRPC.Message message = getMessageWithCustomParamsOnlyInternal(messageId, dialogId); message.voiceTranscriptionOpen = saveFromMessage.voiceTranscriptionOpen; message.voiceTranscriptionRated = saveFromMessage.voiceTranscriptionRated; message.voiceTranscriptionFinal = saveFromMessage.voiceTranscriptionFinal; @@ -4397,7 +4415,7 @@ public class MessagesStorage extends BaseController { SQLitePreparedStatement state = null; try { database.beginTransaction(); - TLRPC.Message message = getMessageWithCustomParamsOnly(saveFromMessage.id, dialogId); + TLRPC.Message message = getMessageWithCustomParamsOnlyInternal(saveFromMessage.id, dialogId); MessageCustomParamsHelper.copyParams(saveFromMessage, message); for (int i = 0; i < 2; i++) { @@ -4436,7 +4454,7 @@ public class MessagesStorage extends BaseController { }); } - private TLRPC.Message getMessageWithCustomParamsOnly(int messageId, long dialogId) { + public TLRPC.Message getMessageWithCustomParamsOnlyInternal(int messageId, long dialogId) { TLRPC.Message message = new TLRPC.TL_message(); SQLiteCursor cursor = null; try { @@ -5838,6 +5856,29 @@ public class MessagesStorage extends BaseController { }); } + public ArrayList loadUserInfos(HashSet uids) { + ArrayList arrayList = new ArrayList<>(); + try { + String ids = TextUtils.join(",", uids); + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM user_settings WHERE uid IN(" + ids + ")"); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.UserFull info = TLRPC.UserFull.TLdeserialize(data, data.readInt32(false), false); + info.pinned_msg_id = cursor.intValue(1); + arrayList.add(info); + data.reuse(); + + } + } + cursor.dispose(); + cursor = null; + } catch (Exception e) { + FileLog.e(e); + } + return arrayList; + } + public void loadUserInfo(TLRPC.User user, boolean force, int classGuid, int fromMessageId) { if (user == null) { return; @@ -10705,7 +10746,7 @@ public class MessagesStorage extends BaseController { state_download.bindInteger(2, type); state_download.bindInteger(3, message.date); state_download.bindByteBuffer(4, data); - state_download.bindString(5, "sent_" + (message.peer_id != null ? message.peer_id.channel_id : 0) + "_" + message.id + "_" + DialogObject.getPeerDialogId(message.peer_id) + "_" + messageObject.type); + state_download.bindString(5, "sent_" + (message.peer_id != null ? message.peer_id.channel_id : 0) + "_" + message.id + "_" + DialogObject.getPeerDialogId(message.peer_id) + "_" + messageObject.type + "_" + messageObject.getSize()); state_download.step(); data.reuse(); } @@ -13715,6 +13756,7 @@ public class MessagesStorage extends BaseController { SQLiteCursor cursor = null; try { ArrayList usersToLoad = new ArrayList<>(); + HashSet dialogUsers = new HashSet<>(); usersToLoad.add(getUserConfig().getClientUserId()); ArrayList chatsToLoad = new ArrayList<>(); ArrayList encryptedToLoad = new ArrayList<>(); @@ -13856,6 +13898,7 @@ public class MessagesStorage extends BaseController { if (!usersToLoad.contains(dialogId)) { usersToLoad.add(dialogId); } + dialogUsers.add(dialogId); } else if (DialogObject.isChatDialog(dialogId)) { if (!chatsToLoad.contains(-dialogId)) { chatsToLoad.add(-dialogId); @@ -13998,14 +14041,18 @@ public class MessagesStorage extends BaseController { if (!usersToLoad.isEmpty()) { getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users); } - getMessagesController().processLoadedDialogs(dialogs, encryptedChats, folderId, offset, count, 1, false, false, true); + ArrayList fullUsers = null; + if (!dialogUsers.isEmpty()) { + fullUsers = loadUserInfos(dialogUsers); + } + getMessagesController().processLoadedDialogs(dialogs, encryptedChats, fullUsers, folderId, offset, count, 1, false, false, true); } catch (Exception e) { dialogs.dialogs.clear(); dialogs.users.clear(); dialogs.chats.clear(); encryptedChats.clear(); FileLog.e(e); - getMessagesController().processLoadedDialogs(dialogs, encryptedChats, folderId, 0, 100, 1, true, false, true); + getMessagesController().processLoadedDialogs(dialogs, encryptedChats, null, folderId, 0, 100, 1, true, false, true); checkMalformed(e); } finally { if (cursor != null) { @@ -14040,6 +14087,41 @@ public class MessagesStorage extends BaseController { } } + public void updateDialogData(TLRPC.Dialog dialog) { + if (dialog == null) { + return; + } + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + SQLitePreparedStatement state = null; + try { + cursor = database.queryFinalized("SELECT data FROM dialogs WHERE did = " + dialog.id); + if (!cursor.next()) { + return; + } + + state = database.executeFast("UPDATE dialogs SET data = ? WHERE did = ?"); + NativeByteBuffer data = new NativeByteBuffer(dialog.getObjectSize()); + dialog.serializeToStream(data); + state.bindByteBuffer(1, data); + state.bindLong(2, dialog.id); + state.step(); + state.dispose(); + state = null; + data.reuse(); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + if (state != null) { + state.dispose(); + } + } + }); + } + private void putDialogsInternal(TLRPC.messages_Dialogs dialogs, int check) { SQLitePreparedStatement state_messages = null; SQLitePreparedStatement state_dialogs = null; @@ -14777,7 +14859,7 @@ public class MessagesStorage extends BaseController { } - public void localSearch(int dialogsType, String query, ArrayList resultArray, ArrayList resultArrayNames, ArrayList encUsers, int folderId) { + public void localSearch(int dialogsType, String query, ArrayList resultArray, ArrayList resultArrayNames, ArrayList encUsers, ArrayList onlyDialogIds, int folderId) { long selfUserId = UserConfig.getInstance(currentAccount).getClientUserId(); SQLiteCursor cursor = null; try { @@ -14816,23 +14898,30 @@ public class MessagesStorage extends BaseController { dialogSearchResult.date = cursor.intValue(1); dialogsResult.put(id, dialogSearchResult); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER && (onlyDialogIds == null || !onlyDialogIds.contains(id))) { + continue; + } + if (!DialogObject.isEncryptedDialog(id)) { if (DialogObject.isUserDialog(id)) { - if (dialogsType == 4 && id == selfUserId) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_USERS_ONLY && id == selfUserId) { continue; } - if (dialogsType != 2 && !usersToLoad.contains(id)) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY || dialogsType == DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY) { + continue; + } + if (dialogsType != DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO && !usersToLoad.contains(id)) { usersToLoad.add(id); } } else { - if (dialogsType == 4) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_USERS_ONLY) { continue; } if (!chatsToLoad.contains(-id)) { chatsToLoad.add(-id); } } - } else if (dialogsType == 0 || dialogsType == 3) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT || dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD) { int encryptedChatId = DialogObject.getEncryptedChatId(id); if (!encryptedToLoad.contains(encryptedChatId)) { encryptedToLoad.add(encryptedChatId); @@ -14892,6 +14981,9 @@ public class MessagesStorage extends BaseController { if (data != null) { TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); data.reuse(); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER && (onlyDialogIds == null || !onlyDialogIds.contains(user.id))) { + continue; + } DialogsSearchAdapter.DialogSearchResult dialogSearchResult = dialogsResult.get(user.id); if (user.status != null) { user.status.expires = cursor.intValue(1); @@ -14926,6 +15018,15 @@ public class MessagesStorage extends BaseController { if (data != null) { TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); data.reuse(); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER && (onlyDialogIds == null || !onlyDialogIds.contains(-chat.id))) { + continue; + } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY && ChatObject.isChannelAndNotMegaGroup(chat)) { + continue; + } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY && !ChatObject.isChannelAndNotMegaGroup(chat)) { + continue; + } if (!(chat == null || chat.deactivated || ChatObject.isChannel(chat) && ChatObject.isNotInChat(chat))) { long dialog_id = -chat.id; DialogsSearchAdapter.DialogSearchResult dialogSearchResult = dialogsResult.get(dialog_id); @@ -14942,7 +15043,7 @@ public class MessagesStorage extends BaseController { cursor = null; } - if (!encryptedToLoad.isEmpty()) { + if (!encryptedToLoad.isEmpty() && dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { cursor = getDatabase().queryFinalized(String.format(Locale.US, "SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer, q.seq_in, q.seq_out, q.use_count, q.exchange_id, q.key_date, q.fprint, q.fauthkey, q.khash, q.in_seq_no, q.admin_id, q.mtproto_seq FROM enc_chats as q INNER JOIN users as u ON q.user = u.uid WHERE q.uid IN(%s)", TextUtils.join(",", encryptedToLoad))); while (cursor.next()) { String name = cursor.stringValue(1); @@ -15046,7 +15147,7 @@ public class MessagesStorage extends BaseController { resultArrayNames.add(dialogSearchResult.name); } - if (dialogsType != 2) { + if (dialogsType != DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO && dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER && dialogsType != DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY && dialogsType != DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY) { cursor = getDatabase().queryFinalized("SELECT u.data, u.status, u.name, u.uid FROM users as u INNER JOIN contacts as c ON u.uid = c.uid"); while (cursor.next()) { long uid = cursor.longValue(3); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 944693535..b577bcd46 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -72,6 +72,7 @@ public class NotificationCenter { public static final int updateMessageMedia = totalEvents++; public static final int replaceMessagesObjects = totalEvents++; public static final int didSetPasscode = totalEvents++; + public static final int passcodeDismissed = totalEvents++; public static final int twoStepPasswordChanged = totalEvents++; public static final int didSetOrRemoveTwoStepPassword = totalEvents++; public static final int didRemoveTwoStepPassword = totalEvents++; @@ -136,6 +137,11 @@ public class NotificationCenter { public static final int recentEmojiStatusesUpdate = totalEvents++; public static final int updateSearchSettings = totalEvents++; + public static final int messageTranslated = totalEvents++; + public static final int messageTranslating = totalEvents++; + public static final int dialogIsTranslatable = totalEvents++; + public static final int dialogTranslate = totalEvents++; + public static final int didGenerateFingerprintKeyPair = totalEvents++; public static final int walletPendingTransactionsChanged = totalEvents++; @@ -231,6 +237,7 @@ public class NotificationCenter { public static final int didSetNewWallpapper = totalEvents++; public static final int proxySettingsChanged = totalEvents++; public static final int proxyCheckDone = totalEvents++; + public static final int proxyChangedByRotation = totalEvents++; public static final int liveLocationsChanged = totalEvents++; public static final int newLocationAvailable = totalEvents++; public static final int liveLocationsCacheChanged = totalEvents++; @@ -735,7 +742,7 @@ public class NotificationCenter { @Override public boolean remove(@Nullable Object o) { - if (set.remove(0)) { + if (set.remove(o)) { return super.remove(o); } return false; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index 20fa6ebcc..26999fb35 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -4084,6 +4084,7 @@ public class NotificationsController extends BaseController { long selfUserId = getUserConfig().getClientUserId(); boolean waitingForPasscode = AndroidUtilities.needShowPasscode() || SharedConfig.isWaitingForPasscodeEnter; + boolean passcode = SharedConfig.passcodeHash.length() > 0; int maxCount = 7; LongSparseArray personCache = new LongSparseArray<>(); @@ -4148,6 +4149,7 @@ public class NotificationsController extends BaseController { } else { chat = getMessagesController().getChat(-dialogId); if (chat == null) { + canReply = false; if (lastMessageObject.isFcmMessage()) { isSupergroup = lastMessageObject.isSupergroup(); name = lastMessageObject.localName; @@ -4172,7 +4174,9 @@ public class NotificationsController extends BaseController { name = topic.title + " in " + name; } } - + if (canReply) { + canReply = ChatObject.canSendPlain(chat); + } } } } else { @@ -4207,6 +4211,9 @@ public class NotificationsController extends BaseController { photoPath = null; canReply = false; } + if (passcode) { + canReply = false; + } if (photoPath != null) { avatalFile = getFileLoader().getPathToAttach(photoPath, true); @@ -4521,6 +4528,7 @@ public class NotificationsController extends BaseController { } else { intent.putExtra("chatId", -dialogId); } + FileLog.d("show extra notifications chatId " + dialogId + " topicId " + topicId); if (topicId != 0) { intent.putExtra("topicId", topicId); } @@ -4596,7 +4604,7 @@ public class NotificationsController extends BaseController { if (wearReplyAction != null) { builder.addAction(wearReplyAction); } - if (!waitingForPasscode) { + if (!passcode) { builder.addAction(readAction); } if (sortedDialogs.size() == 1 && !TextUtils.isEmpty(summary)) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ProxyRotationController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ProxyRotationController.java new file mode 100644 index 000000000..9b5fb7713 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ProxyRotationController.java @@ -0,0 +1,128 @@ +package org.telegram.messenger; + +import android.content.SharedPreferences; +import android.os.SystemClock; + +import org.telegram.tgnet.ConnectionsManager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class ProxyRotationController implements NotificationCenter.NotificationCenterDelegate { + private final static ProxyRotationController INSTANCE = new ProxyRotationController(); + + public final static int DEFAULT_TIMEOUT_INDEX = 1; + public final static List ROTATION_TIMEOUTS = Arrays.asList( + 5, 10, 15, 30, 60 + ); + + private boolean isCurrentlyChecking; + private Runnable checkProxyAndSwitchRunnable = () -> { + isCurrentlyChecking = true; + + int currentAccount = UserConfig.selectedAccount; + boolean startedCheck = false; + for (int i = 0; i < SharedConfig.proxyList.size(); i++) { + SharedConfig.ProxyInfo proxyInfo = SharedConfig.proxyList.get(i); + if (proxyInfo.checking || SystemClock.elapsedRealtime() - proxyInfo.availableCheckTime < 2 * 60 * 1000) { + continue; + } + startedCheck = true; + proxyInfo.checking = true; + proxyInfo.proxyCheckPingId = ConnectionsManager.getInstance(currentAccount).checkProxy(proxyInfo.address, proxyInfo.port, proxyInfo.username, proxyInfo.password, proxyInfo.secret, time -> AndroidUtilities.runOnUIThread(() -> { + proxyInfo.availableCheckTime = SystemClock.elapsedRealtime(); + proxyInfo.checking = false; + if (time == -1) { + proxyInfo.available = false; + proxyInfo.ping = 0; + } else { + proxyInfo.ping = time; + proxyInfo.available = true; + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, proxyInfo); + })); + } + + if (!startedCheck) { + isCurrentlyChecking = false; + switchToAvailable(); + } + }; + + public static void init() { + INSTANCE.initInternal(); + } + + @SuppressWarnings("ComparatorCombinators") + private void switchToAvailable() { + isCurrentlyChecking = false; + + if (!SharedConfig.proxyRotationEnabled) { + return; + } + + List sortedList = new ArrayList<>(SharedConfig.proxyList); + Collections.sort(sortedList, (o1, o2) -> Long.compare(o1.ping, o2.ping)); + for (SharedConfig.ProxyInfo info : sortedList) { + if (info == SharedConfig.currentProxy || info.checking || !info.available) { + continue; + } + + SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); + editor.putString("proxy_ip", info.address); + editor.putString("proxy_pass", info.password); + editor.putString("proxy_user", info.username); + editor.putInt("proxy_port", info.port); + editor.putString("proxy_secret", info.secret); + editor.putBoolean("proxy_enabled", true); + + if (!info.secret.isEmpty()) { + editor.putBoolean("proxy_enabled_calls", false); + } + editor.apply(); + + SharedConfig.currentProxy = info; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyChangedByRotation); + ConnectionsManager.setProxySettings(true, SharedConfig.currentProxy.address, SharedConfig.currentProxy.port, SharedConfig.currentProxy.username, SharedConfig.currentProxy.password, SharedConfig.currentProxy.secret); + break; + } + } + + private void initInternal() { + for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; i++) { + NotificationCenter.getInstance(i).addObserver(this, NotificationCenter.didUpdateConnectionState); + } + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxyCheckDone); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxySettingsChanged); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.proxyCheckDone) { + if (!SharedConfig.isProxyEnabled() || !SharedConfig.proxyRotationEnabled || SharedConfig.proxyList.size() <= 1 || !isCurrentlyChecking) { + return; + } + + switchToAvailable(); + } else if (id == NotificationCenter.proxySettingsChanged) { + AndroidUtilities.cancelRunOnUIThread(checkProxyAndSwitchRunnable); + } else if (id == NotificationCenter.didUpdateConnectionState && account == UserConfig.selectedAccount) { + if (!SharedConfig.isProxyEnabled() && !SharedConfig.proxyRotationEnabled || SharedConfig.proxyList.size() <= 1) { + return; + } + + int state = ConnectionsManager.getInstance(account).getConnectionState(); + + if (state == ConnectionsManager.ConnectionStateConnectingToProxy) { + if (!isCurrentlyChecking) { + AndroidUtilities.runOnUIThread(checkProxyAndSwitchRunnable, ROTATION_TIMEOUTS.get(SharedConfig.proxyRotationTimeout) * 1000L); + } + } else { + AndroidUtilities.cancelRunOnUIThread(checkProxyAndSwitchRunnable); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java b/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java index 486cfcb6e..130f1d177 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java @@ -3,6 +3,7 @@ package org.telegram.messenger; import android.os.SystemClock; import android.text.TextUtils; import android.util.Base64; +import android.util.Log; import android.util.SparseBooleanArray; import androidx.annotation.IntDef; @@ -286,8 +287,9 @@ public class PushListenerController { chat_id = 0; } if (custom.has("topic_id")) { - topicId =custom.getInt("topic_id"); + topicId = custom.getInt("topic_id"); } + FileLog.d( "recived push notification chatId " + chat_id + " custom topicId " + topicId); if (custom.has("encryption_id")) { dialogId = DialogObject.makeEncryptedDialogId(custom.getInt("encryption_id")); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SaveToGallerySettingsHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SaveToGallerySettingsHelper.java new file mode 100644 index 000000000..9a5c10105 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SaveToGallerySettingsHelper.java @@ -0,0 +1,252 @@ +package org.telegram.messenger; + +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS; +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP; +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.util.LongSparseArray; + +public class SaveToGallerySettingsHelper { + + //shared settings + public static SharedSettings user; + public static SharedSettings groups; + public static SharedSettings channels; + + public static String USERS_PREF_NAME = "users_save_gallery_exceptions"; + public static String CHANNELS_PREF_NAME = "channels_save_gallery_exceptions"; + public static String GROUPS_PREF_NAME = "groups_save_gallery_exceptions"; + + public static final long DEFAULT_VIDEO_LIMIT = 100 * 1024 * 1024;//100 MB + public static final long MAX_VIDEO_LIMIT = 4L * 1000 * 1024 * 1024;//100 MB + + public static void load(SharedPreferences preferences) { + boolean saveToGalleryLegacy = preferences.getBoolean("save_gallery", false); + int saveToGalleryFlags; + if (saveToGalleryLegacy && BuildVars.NO_SCOPED_STORAGE) { + saveToGalleryFlags = SAVE_TO_GALLERY_FLAG_PEER + SAVE_TO_GALLERY_FLAG_CHANNELS + SAVE_TO_GALLERY_FLAG_GROUP; + } else { + saveToGalleryFlags = preferences.getInt("save_gallery_flags", -1); + } + //migration + if (saveToGalleryFlags != -1) { + preferences.edit().remove("save_gallery").remove("save_gallery_flags").apply(); + user = new SharedSettings(); + user.savePhoto = user.saveVideo = (saveToGalleryFlags & SAVE_TO_GALLERY_FLAG_PEER) != 0; + user.limitVideo = DEFAULT_VIDEO_LIMIT; + user.save("user", preferences); + + groups = new SharedSettings(); + groups.savePhoto = user.saveVideo = (saveToGalleryFlags & SAVE_TO_GALLERY_FLAG_GROUP) != 0; + groups.limitVideo = DEFAULT_VIDEO_LIMIT; + groups.save("groups", preferences); + + channels = new SharedSettings(); + channels.savePhoto = channels.saveVideo = (saveToGalleryFlags & SAVE_TO_GALLERY_FLAG_CHANNELS) != 0; + channels.limitVideo = DEFAULT_VIDEO_LIMIT; + channels.save("channels", preferences); + + } else { + user = SharedSettings.read("user", preferences); + groups = SharedSettings.read("groups", preferences); + channels = SharedSettings.read("channels", preferences); + } + user.type = SAVE_TO_GALLERY_FLAG_PEER; + groups.type = SAVE_TO_GALLERY_FLAG_GROUP; + channels.type = SAVE_TO_GALLERY_FLAG_CHANNELS; + } + + public static boolean needSave(int flag, FilePathDatabase.FileMeta metaData, MessageObject messageObject, int currentAccount) { + SharedSettings settings; + if (flag == SharedConfig.SAVE_TO_GALLERY_FLAG_PEER) { + settings = user; + } else if (flag == SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS) { + settings = channels; + } else if (flag == SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP) { + settings = groups; + } else { + return false; + } + return settings.needSave(metaData, messageObject, currentAccount); + } + + public static LongSparseArray loadExceptions(SharedPreferences sharedPreferences) { + LongSparseArray exceptions = new LongSparseArray<>(); + int count = sharedPreferences.getInt("count", 0); + for (int i = 0; i < count; i++) { + DialogException dialogException = new DialogException(); + dialogException.dialogId = sharedPreferences.getLong(i + "_dialog_id", 0); + dialogException.savePhoto = sharedPreferences.getBoolean(i + "_photo", false); + dialogException.saveVideo = sharedPreferences.getBoolean(i + "_video", false); + dialogException.limitVideo = sharedPreferences.getLong(i + "_limitVideo", DEFAULT_VIDEO_LIMIT); + if (dialogException.dialogId != 0) { + exceptions.put(dialogException.dialogId, dialogException); + } + } + return exceptions; + } + + public static void saveExceptions(SharedPreferences sharedPreferences, LongSparseArray exceptions) { + sharedPreferences.edit().clear().apply(); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putInt("count", exceptions.size()); + for (int i = 0; i < exceptions.size(); i++) { + DialogException dialogException = exceptions.valueAt(i); + editor.putLong(i + "_dialog_id", dialogException.dialogId); + editor.putBoolean(i + "_photo", dialogException.savePhoto); + editor.putBoolean(i + "_video", dialogException.saveVideo); + editor.putLong(i + "_limitVideo", dialogException.limitVideo); + } + editor.apply(); + } + + public static Settings getSettings(int type) { + if (type == SAVE_TO_GALLERY_FLAG_PEER) { + return user; + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + return groups; + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + return channels; + } + return null; + } + + public static void saveSettings(int type) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (type == SAVE_TO_GALLERY_FLAG_PEER) { + user.save("user", preferences); + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + groups.save("group", preferences); + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + channels.save("channels", preferences); + } + } + + public static abstract class Settings { + public boolean savePhoto; + public boolean saveVideo; + public long limitVideo = 100 * 1024 * 1024; ///100 MB + + public boolean enabled() { + return savePhoto || saveVideo; + } + + public abstract CharSequence createDescription(int currentAccount); + + public void toggle() { + if (enabled()) { + saveVideo = false; + savePhoto = false; + } else { + savePhoto = true; + saveVideo = true; + } + } + } + + public static class SharedSettings extends Settings { + private int type; + + private void save(String prefix, SharedPreferences sharedPreferences) { + sharedPreferences.edit() + .putBoolean(prefix + "_save_gallery_photo", savePhoto) + .putBoolean(prefix + "_save_gallery_video", saveVideo) + .putLong(prefix + "_save_gallery_limitVideo", limitVideo) + .apply(); + + } + + private static SharedSettings read(String prefix, SharedPreferences preferences) { + SharedSettings settings = new SharedSettings(); + settings.savePhoto = preferences.getBoolean(prefix + "_save_gallery_photo", false); + settings.saveVideo = preferences.getBoolean(prefix + "_save_gallery_video", false); + settings.limitVideo = preferences.getLong(prefix + "_save_gallery_limitVideo", DEFAULT_VIDEO_LIMIT); + return settings; + } + + private boolean needSave(FilePathDatabase.FileMeta meta, MessageObject messageObject, int currentAccount) { + LongSparseArray exceptions = UserConfig.getInstance(currentAccount).getSaveGalleryExceptions(type); + DialogException exception = exceptions.get(meta.dialogId); + if (messageObject != null && messageObject.isOutOwner()) { + return false; + } + boolean isVideo = (messageObject != null && messageObject.isVideo()) || meta.messageType == MessageObject.TYPE_VIDEO; + long size = messageObject != null ? messageObject.getSize() : meta.messageSize; + boolean needSaveVideo = saveVideo; + boolean needSavePhoto = savePhoto; + long saveVideoLimit = limitVideo; + if (exception != null) { + needSaveVideo = exception.saveVideo; + needSavePhoto = exception.savePhoto; + saveVideoLimit = exception.limitVideo; + } + if (isVideo) { + if (needSaveVideo && (saveVideoLimit == -1 || size < saveVideoLimit)) { + return true; + } + } else { + if (needSavePhoto) { + return true; + } + } + return false; + } + + public CharSequence createDescription(int currentAccount) { + StringBuilder builder = new StringBuilder(); + if (enabled()) { + if (savePhoto) { + builder.append(LocaleController.getString("SaveToGalleryPhotos", R.string.SaveToGalleryPhotos)); + } + if (saveVideo) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("SaveToGalleryVideos", R.string.SaveToGalleryVideos)); + if (limitVideo > 0 && limitVideo < 4L * 1000 * 1024 * 1024) { + builder.append(" (").append(AndroidUtilities.formatFileSize(limitVideo, true)).append(")"); + } + } + } else { + builder.append(LocaleController.getString("SaveToGalleryOff", R.string.SaveToGalleryOff)); + } + LongSparseArray exceptions = UserConfig.getInstance(currentAccount).getSaveGalleryExceptions(type); + if (exceptions.size() != 0) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.formatPluralString("Exception", exceptions.size(), exceptions.size())); + } + return builder; + } + } + + public static class DialogException extends Settings { + public long dialogId; + + public CharSequence createDescription(int currentAccount) { + StringBuilder builder = new StringBuilder(); + if (enabled()) { + if (savePhoto) { + builder.append(LocaleController.getString("SaveToGalleryPhotos", R.string.SaveToGalleryPhotos)); + } + if (saveVideo) { + if (builder.length() != 0) { + builder.append(", "); + } + + if (limitVideo > 0 && limitVideo < 4L * 1000 * 1024 * 1024) { + builder.append(LocaleController.formatString("SaveToGalleryVideosUpTo", R.string.SaveToGalleryVideosUpTo, AndroidUtilities.formatFileSize(limitVideo, true))); + } else { + builder.append(LocaleController.formatString("SaveToGalleryVideos", R.string.SaveToGalleryVideos)); + } + } + } else { + builder.append(LocaleController.getString("SaveToGalleryOff", R.string.SaveToGalleryOff)); + } + return builder; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 21ce755ec..0bc11624e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -519,6 +519,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe public boolean forceImage; public boolean updateStickersOrder; public boolean hasMediaSpoilers; + public TLRPC.VideoSize emojiMarkup; } @SuppressLint("MissingPermission") @@ -1454,7 +1455,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe HashMap params = null; if (DialogObject.isEncryptedDialog(did) && messageObject.messageOwner.peer_id != null && (messageObject.messageOwner.media.photo instanceof TLRPC.TL_photo || messageObject.messageOwner.media.document instanceof TLRPC.TL_document)) { params = new HashMap<>(); - params.put("parentObject", "sent_" + messageObject.messageOwner.peer_id.channel_id + "_" + messageObject.getId() + "_" + messageObject.getDialogId() + "_" + messageObject.type); + params.put("parentObject", "sent_" + messageObject.messageOwner.peer_id.channel_id + "_" + messageObject.getId() + "_" + messageObject.getDialogId() + "_" + messageObject.type + "_" + messageObject.getSize()); } if (messageObject.messageOwner.media.photo instanceof TLRPC.TL_photo) { sendMessage((TLRPC.TL_photo) messageObject.messageOwner.media.photo, null, did, messageObject.replyMessageObject, null, messageObject.messageOwner.message, messageObject.messageOwner.entities, null, params, true, 0, messageObject.messageOwner.media.ttl_seconds, messageObject, false); @@ -1674,10 +1675,14 @@ public class SendMessagesHelper extends BaseController implements NotificationCe final TLRPC.Peer peer_id = getMessagesController().getPeer(peer); boolean isSignature = false; boolean canSendStickers = true; - boolean canSendMedia = true; + boolean canSendPhoto = true; + boolean canSendVideo = true; + boolean canSendDocument = true; + boolean canSendMusic = true; boolean canSendPolls = true; boolean canSendPreview = true; boolean canSendVoiceMessages = true; + boolean canSendVoiceRound = true; String rank = null; long linkedToGroup = 0; TLRPC.Chat chat; @@ -1690,7 +1695,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe TLRPC.UserFull userFull = getMessagesController().getUserFull(peer); if (userFull != null) { - canSendVoiceMessages = !userFull.voice_messages_forbidden; + canSendVoiceRound = canSendVoiceMessages = !userFull.voice_messages_forbidden; } } else { chat = getMessagesController().getChat(-peer); @@ -1709,9 +1714,14 @@ public class SendMessagesHelper extends BaseController implements NotificationCe rank = getMessagesController().getAdminRank(chat.id, myId); } canSendStickers = ChatObject.canSendStickers(chat); - canSendMedia = ChatObject.canSendMedia(chat); + canSendPhoto = ChatObject.canSendPhoto(chat); + canSendVideo = ChatObject.canSendVideo(chat); + canSendDocument = ChatObject.canSendDocument(chat); canSendPreview = ChatObject.canSendEmbed(chat); canSendPolls = ChatObject.canSendPolls(chat); + canSendVoiceRound = ChatObject.canSendRoundVideo(chat); + canSendVoiceMessages = ChatObject.canSendVoice(chat); + canSendMusic = ChatObject.canSendMusic(chat); } LongSparseArray groupsMap = new LongSparseArray<>(); @@ -1739,9 +1749,19 @@ public class SendMessagesHelper extends BaseController implements NotificationCe sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_STICKERS) ? 4 : 1; } continue; - } else if (!canSendMedia && (msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) && !mediaIsSticker) { + } else if (!canSendPhoto && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && !msgObj.isVideo() && !mediaIsSticker) { if (sendResult == 0) { - sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_MEDIA) ? 5 : 2; + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_PHOTO) ? 10 : 12; + } + continue; + } else if (!canSendMusic && msgObj.isMusic()) { + if (sendResult == 0) { + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_MUSIC) ? 19 : 20; + } + continue; + } else if (!canSendVideo && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && msgObj.isVideo() && !mediaIsSticker) { + if (sendResult == 0) { + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_VIDEO) ? 9 : 11; } continue; } else if (!canSendPolls && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { @@ -1750,13 +1770,30 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } continue; } else if (!canSendVoiceMessages && MessageObject.isVoiceMessage(msgObj.messageOwner)) { - if (sendResult == 0) { - sendResult = 7; + if (chat != null) { + if (sendResult == 0) { + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_VOICE) ? 13 : 14; + } + } else { + if (sendResult == 0) { + sendResult = 7; + } } continue; - } else if (!canSendVoiceMessages && MessageObject.isRoundVideoMessage(msgObj.messageOwner)) { + } else if (!canSendVoiceRound && MessageObject.isRoundVideoMessage(msgObj.messageOwner)) { + if (chat != null) { + if (sendResult == 0) { + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_ROUND) ? 15 : 16; + } + } else { + if (sendResult == 0) { + sendResult = 8; + } + } + continue; + } else if (!canSendDocument && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaDocument && !mediaIsSticker) { if (sendResult == 0) { - sendResult = 8; + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_DOCUMENTS) ? 17 : 18; } continue; } @@ -2220,6 +2257,38 @@ public class SendMessagesHelper extends BaseController implements NotificationCe return sendResult; } + public static int canSendMessageToChat(TLRPC.Chat chat, MessageObject msgObj) { + boolean canSendStickers = ChatObject.canSendStickers(chat); + boolean canSendPhoto = ChatObject.canSendPhoto(chat); + boolean canSendVideo = ChatObject.canSendVideo(chat); + boolean canSendDocument = ChatObject.canSendDocument(chat); + boolean canSendPreview = ChatObject.canSendEmbed(chat); + boolean canSendPolls = ChatObject.canSendPolls(chat); + boolean canSendVoiceRound = ChatObject.canSendRoundVideo(chat); + boolean canSendVoiceMessages = ChatObject.canSendVoice(chat); + boolean canSendMusic = ChatObject.canSendMusic(chat); + + boolean mediaIsSticker = (msgObj.isSticker() || msgObj.isAnimatedSticker() || msgObj.isGif() || msgObj.isGame()); + if (!canSendStickers && mediaIsSticker) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_STICKERS) ? 4 : 1; + } else if (!canSendPhoto && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && !msgObj.isVideo() && !mediaIsSticker) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_PHOTO) ? 10 : 12; + } else if (!canSendMusic && msgObj.isMusic()) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_MUSIC) ? 19 : 20; + } else if (!canSendVideo && msgObj.isVideo() && !mediaIsSticker) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_VIDEO) ? 9 : 11; + } else if (!canSendPolls && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_POLLS) ? 6 : 3; + } else if (!canSendVoiceMessages && MessageObject.isVoiceMessage(msgObj.messageOwner)) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_VOICE) ? 13 : 14; + } else if (!canSendVoiceRound && MessageObject.isRoundVideoMessage(msgObj.messageOwner)) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_ROUND) ? 15 : 16; + } else if (!canSendDocument && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaDocument && !mediaIsSticker) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_DOCUMENTS) ? 17 : 18; + } + return 0; + } + private void writePreviousMessageData(TLRPC.Message message, SerializedData data) { if (message.media == null) { TLRPC.TL_messageMediaEmpty media = new TLRPC.TL_messageMediaEmpty(); @@ -5822,7 +5891,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } if (sentMessage.media instanceof TLRPC.TL_messageMediaPhoto && sentMessage.media.photo != null && newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) { if (sentMessage.media.ttl_seconds == 0 && !newMsgObj.scheduled) { - getMessagesStorage().putSentFile(originalPath, sentMessage.media.photo, 0, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + MessageObject.TYPE_PHOTO); + getMessagesStorage().putSentFile(originalPath, sentMessage.media.photo, 0, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + MessageObject.TYPE_PHOTO + "_" + newMsgObj.getSize()); } if (newMsg.media.photo.sizes.size() == 1 && newMsg.media.photo.sizes.get(0).location instanceof TLRPC.TL_fileLocationUnavailable) { @@ -5883,14 +5952,14 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if ((isVideo || MessageObject.isGifMessage(sentMessage)) && MessageObject.isGifDocument(sentMessage.media.document) == MessageObject.isGifDocument(newMsg.media.document)) { if (!newMsgObj.scheduled) { MessageObject messageObject = new MessageObject(currentAccount, sentMessage, false, false); - getMessagesStorage().putSentFile(originalPath, sentMessage.media.document, 2, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + messageObject.type); + getMessagesStorage().putSentFile(originalPath, sentMessage.media.document, 2, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + messageObject.type + "_" + messageObject.getSize()); } if (isVideo) { sentMessage.attachPath = newMsg.attachPath; } } else if (!MessageObject.isVoiceMessage(sentMessage) && !MessageObject.isRoundVideoMessage(sentMessage) && !newMsgObj.scheduled) { MessageObject messageObject = new MessageObject(currentAccount, sentMessage, false, false); - getMessagesStorage().putSentFile(originalPath, sentMessage.media.document, 1, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + messageObject.type); + getMessagesStorage().putSentFile(originalPath, sentMessage.media.document, 1, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + messageObject.type + "_" + messageObject.getSize()); } } @@ -7144,6 +7213,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe TLRPC.TL_forumTopic topic = accountInstance.getMessagesController().getTopicsController().findTopic(-dialogId, topicId); if (topic != null && topic.topicStartMessage != null) { replyToMsg = new MessageObject(accountInstance.getCurrentAccount(), topic.topicStartMessage, false, false); + replyToMsg.isTopicMainMessage = true; } } for (int a = 0; a < count; a++) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index 2384918ee..782480a6b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -41,9 +41,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Locale; public class SharedConfig { + /** + * V2: Ping and check time serialized + */ + private final static int PROXY_SCHEMA_V2 = 2; + private final static int PROXY_CURRENT_SCHEMA_VERSION = PROXY_SCHEMA_V2; + public final static int PASSCODE_TYPE_PIN = 0, PASSCODE_TYPE_PASSWORD = 1; @@ -125,7 +132,7 @@ public class SharedConfig { private static final Object sync = new Object(); private static final Object localIdSync = new Object(); - public static int saveToGalleryFlags; +// public static int saveToGalleryFlags; public static int mapPreviewType = 2; public static boolean chatBubbles = Build.VERSION.SDK_INT >= 30; public static boolean autoplayGifs = true; @@ -142,7 +149,7 @@ public class SharedConfig { public static boolean streamMkv = false; public static boolean saveStreamMedia = true; public static boolean smoothKeyboard = true; - public static boolean pauseMusicOnRecord = true; + public static boolean pauseMusicOnRecord = false; public static boolean chatBlur = true; public static boolean noiseSupression; public static boolean noStatusBar = true; @@ -161,6 +168,8 @@ public class SharedConfig { public static boolean fontSizeIsDefault; public static int bubbleRadius = 17; public static int ivFontSize = 16; + public static boolean proxyRotationEnabled; + public static int proxyRotationTimeout; public static int messageSeenHintCount; public static int emojiInteractionsHintCount; public static int dayNightThemeSwitchHintCount; @@ -184,6 +193,8 @@ public class SharedConfig { public static int fastScrollHintCount = 3; public static boolean dontAskManageStorage; + public static boolean translateChats = true; + public static boolean isFloatingDebugActive; public static LiteMode liteMode; @@ -205,23 +216,23 @@ public class SharedConfig { public boolean available; public long availableCheckTime; - public ProxyInfo(String a, int p, String u, String pw, String s) { - address = a; - port = p; - username = u; - password = pw; - secret = s; - if (address == null) { - address = ""; + public ProxyInfo(String address, int port, String username, String password, String secret) { + this.address = address; + this.port = port; + this.username = username; + this.password = password; + this.secret = secret; + if (this.address == null) { + this.address = ""; } - if (password == null) { - password = ""; + if (this.password == null) { + this.password = ""; } - if (username == null) { - username = ""; + if (this.username == null) { + this.username = ""; } - if (secret == null) { - secret = ""; + if (this.secret == null) { + this.secret = ""; } } @@ -279,6 +290,8 @@ public class SharedConfig { editor.putBoolean("forwardingOptionsHintShown", forwardingOptionsHintShown); editor.putInt("lockRecordAudioVideoHint", lockRecordAudioVideoHint); editor.putString("storageCacheDir", !TextUtils.isEmpty(storageCacheDir) ? storageCacheDir : ""); + editor.putBoolean("proxyRotationEnabled", proxyRotationEnabled); + editor.putInt("proxyRotationTimeout", proxyRotationTimeout); if (pendingAppUpdate != null) { try { @@ -302,6 +315,7 @@ public class SharedConfig { editor.putBoolean("hasEmailLogin", hasEmailLogin); editor.putBoolean("useLNavigation", useLNavigation); editor.putBoolean("floatingDebugActive", isFloatingDebugActive); + editor.putBoolean("record_via_sco", recordViaSco); editor.apply(); } catch (Exception e) { FileLog.e(e); @@ -345,6 +359,8 @@ public class SharedConfig { passportConfigJson = preferences.getString("passportConfigJson", ""); passportConfigHash = preferences.getInt("passportConfigHash", 0); storageCacheDir = preferences.getString("storageCacheDir", null); + proxyRotationEnabled = preferences.getBoolean("proxyRotationEnabled", false); + proxyRotationTimeout = preferences.getInt("proxyRotationTimeout", ProxyRotationController.DEFAULT_TIMEOUT_INDEX); String authKeyString = preferences.getString("pushAuthKey", null); if (!TextUtils.isEmpty(authKeyString)) { pushAuthKey = Base64.decode(authKeyString, Base64.DEFAULT); @@ -399,13 +415,7 @@ public class SharedConfig { } preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); - boolean saveToGalleryLegacy = preferences.getBoolean("save_gallery", false); - if (saveToGalleryLegacy && BuildVars.NO_SCOPED_STORAGE) { - saveToGalleryFlags = SAVE_TO_GALLERY_FLAG_PEER + SAVE_TO_GALLERY_FLAG_CHANNELS + SAVE_TO_GALLERY_FLAG_GROUP; - preferences.edit().remove("save_gallery").putInt("save_gallery_flags", saveToGalleryFlags).apply(); - } else { - saveToGalleryFlags = preferences.getInt("save_gallery_flags", 0); - } + SaveToGallerySettingsHelper.load(preferences); autoplayGifs = preferences.getBoolean("autoplay_gif", true); autoplayVideo = preferences.getBoolean("autoplay_video", true); mapPreviewType = preferences.getInt("mapPreviewType", 2); @@ -1036,17 +1046,17 @@ public class SharedConfig { } public static void toggleSaveToGalleryFlag(int flag) { - if ((saveToGalleryFlags & flag) != 0) { - saveToGalleryFlags &= ~flag; - } else { - saveToGalleryFlags |= flag; - } - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - preferences.edit().putInt("save_gallery_flags", saveToGalleryFlags).apply(); - ImageLoader.getInstance().checkMediaPaths(); - ImageLoader.getInstance().getCacheOutQueue().postRunnable(() -> { - checkSaveToGalleryFiles(); - }); +// if ((saveToGalleryFlags & flag) != 0) { +// saveToGalleryFlags &= ~flag; +// } else { +// saveToGalleryFlags |= flag; +// } +// SharedPreferences preferences = MessagesController.getGlobalMainSettings(); +// preferences.edit().putInt("save_gallery_flags", saveToGalleryFlags).apply(); +// ImageLoader.getInstance().checkMediaPaths(); +// ImageLoader.getInstance().getCacheOutQueue().postRunnable(() -> { +// checkSaveToGalleryFiles(); +// }); } public static void toggleAutoplayGifs() { @@ -1256,17 +1266,46 @@ public class SharedConfig { byte[] bytes = Base64.decode(list, Base64.DEFAULT); SerializedData data = new SerializedData(bytes); int count = data.readInt32(false); - for (int a = 0; a < count; a++) { - ProxyInfo info = new ProxyInfo( - data.readString(false), - data.readInt32(false), - data.readString(false), - data.readString(false), - data.readString(false)); - proxyList.add(info); - if (currentProxy == null && !TextUtils.isEmpty(proxyAddress)) { - if (proxyAddress.equals(info.address) && proxyPort == info.port && proxyUsername.equals(info.username) && proxyPassword.equals(info.password)) { - currentProxy = info; + if (count == -1) { // V2 or newer + int version = data.readByte(false); + + if (version == PROXY_SCHEMA_V2) { + count = data.readInt32(false); + + for (int i = 0; i < count; i++) { + ProxyInfo info = new ProxyInfo( + data.readString(false), + data.readInt32(false), + data.readString(false), + data.readString(false), + data.readString(false)); + + info.ping = data.readInt64(false); + info.availableCheckTime = data.readInt64(false); + + proxyList.add(info); + if (currentProxy == null && !TextUtils.isEmpty(proxyAddress)) { + if (proxyAddress.equals(info.address) && proxyPort == info.port && proxyUsername.equals(info.username) && proxyPassword.equals(info.password)) { + currentProxy = info; + } + } + } + } else { + FileLog.e("Unknown proxy schema version: " + version); + } + } else { + for (int a = 0; a < count; a++) { + ProxyInfo info = new ProxyInfo( + data.readString(false), + data.readInt32(false), + data.readString(false), + data.readString(false), + data.readString(false)); + proxyList.add(info); + if (currentProxy == null && !TextUtils.isEmpty(proxyAddress)) { + if (proxyAddress.equals(info.address) && proxyPort == info.port && proxyUsername.equals(info.username) && proxyPassword.equals(info.password)) { + currentProxy = info; + } } } } @@ -1279,16 +1318,33 @@ public class SharedConfig { } public static void saveProxyList() { + List infoToSerialize = new ArrayList<>(proxyList); + Collections.sort(infoToSerialize, (o1, o2) -> { + long bias1 = SharedConfig.currentProxy == o1 ? -200000 : 0; + if (!o1.available) { + bias1 += 100000; + } + long bias2 = SharedConfig.currentProxy == o2 ? -200000 : 0; + if (!o2.available) { + bias2 += 100000; + } + return Long.compare(o1.ping + bias1, o2.ping + bias2); + }); SerializedData serializedData = new SerializedData(); - int count = proxyList.size(); + serializedData.writeInt32(-1); + serializedData.writeByte(PROXY_CURRENT_SCHEMA_VERSION); + int count = infoToSerialize.size(); serializedData.writeInt32(count); for (int a = 0; a < count; a++) { - ProxyInfo info = proxyList.get(a); + ProxyInfo info = infoToSerialize.get(a); serializedData.writeString(info.address != null ? info.address : ""); serializedData.writeInt32(info.port); serializedData.writeString(info.username != null ? info.username : ""); serializedData.writeString(info.password != null ? info.password : ""); serializedData.writeString(info.secret != null ? info.secret : ""); + + serializedData.writeInt64(info.ping); + serializedData.writeInt64(info.availableCheckTime); } SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); preferences.edit().putString("proxy_list", Base64.encodeToString(serializedData.toByteArray(), Base64.NO_WRAP)).commit(); @@ -1309,6 +1365,10 @@ public class SharedConfig { return proxyInfo; } + public static boolean isProxyEnabled() { + return MessagesController.getGlobalMainSettings().getBoolean("proxy_enabled", false) && currentProxy != null; + } + public static void deleteProxy(ProxyInfo proxyInfo) { if (currentProxy == proxyInfo) { currentProxy = null; @@ -1340,7 +1400,7 @@ public class SharedConfig { File videoPath = new File(telegramPath, "Telegram Video"); videoPath.mkdir(); - if (saveToGalleryFlags != 0 || !BuildVars.NO_SCOPED_STORAGE) { + if (!BuildVars.NO_SCOPED_STORAGE) { if (imagePath.isDirectory()) { new File(imagePath, ".nomedia").delete(); } @@ -1484,6 +1544,14 @@ public class SharedConfig { public static void setLastCheckedBackgroundActivity(long l) { prefs.edit().putLong("last_checked", l).apply(); } + + public static int getDismissedCount() { + return prefs.getInt("dismissed_count", 0); + } + + public static void increaseDismissedCount() { + prefs.edit().putInt("dismissed_count", getDismissedCount() + 1).apply(); + } } private static Boolean animationsEnabled; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/StatsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/StatsController.java index 6b681510e..8e33394cb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/StatsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/StatsController.java @@ -27,7 +27,9 @@ public class StatsController extends BaseController { public static final int TYPE_PHOTOS = 4; public static final int TYPE_FILES = 5; public static final int TYPE_TOTAL = 6; - private static final int TYPES_COUNT = 7; + public static final int TYPE_MUSIC = 7; + private static final int OLD_TYPES_COUNT = 7; + private static final int TYPES_COUNT = 8; private byte[] buffer = new byte[8]; @@ -87,7 +89,7 @@ public class StatsController extends BaseController { try { statsFile.seek(0); for (int a = 0; a < 3; a++) { - for (int b = 0; b < TYPES_COUNT; b++) { + for (int b = 0; b < OLD_TYPES_COUNT; b++) { statsFile.write(longToBytes(sentBytes[a][b]), 0, 8); statsFile.write(longToBytes(receivedBytes[a][b]), 0, 8); statsFile.write(intToBytes(sentItems[a][b]), 0, 4); @@ -96,6 +98,14 @@ public class StatsController extends BaseController { statsFile.write(intToBytes(callsTotalTime[a]), 0, 4); statsFile.write(longToBytes(resetStatsDate[a]), 0, 8); } + for (int b = OLD_TYPES_COUNT; b < TYPES_COUNT; ++b) { + for (int a = 0; a < 3; ++a) { + statsFile.write(longToBytes(sentBytes[a][b]), 0, 8); + statsFile.write(longToBytes(receivedBytes[a][b]), 0, 8); + statsFile.write(intToBytes(sentItems[a][b]), 0, 4); + statsFile.write(intToBytes(receivedItems[a][b]), 0, 4); + } + } statsFile.getFD().sync(); } catch (Exception ignore) { @@ -132,7 +142,7 @@ public class StatsController extends BaseController { if (statsFile.length() > 0) { boolean save = false; for (int a = 0; a < 3; a++) { - for (int b = 0; b < TYPES_COUNT; b++) { + for (int b = 0; b < OLD_TYPES_COUNT; b++) { statsFile.readFully(buffer, 0, 8); sentBytes[a][b] = bytesToLong(buffer); statsFile.readFully(buffer, 0, 8); @@ -151,6 +161,18 @@ public class StatsController extends BaseController { resetStatsDate[a] = System.currentTimeMillis(); } } + for (int b = OLD_TYPES_COUNT; b < TYPES_COUNT; ++b) { + for (int a = 0; a < 3; ++a) { + statsFile.readFully(buffer, 0, 8); + sentBytes[a][b] = bytesToLong(buffer); + statsFile.readFully(buffer, 0, 8); + receivedBytes[a][b] = bytesToLong(buffer); + statsFile.readFully(buffer, 0, 4); + sentItems[a][b] = bytesToInt(buffer); + statsFile.readFully(buffer, 0, 4); + receivedItems[a][b] = bytesToInt(buffer); + } + } if (save) { saveStats(); } @@ -222,14 +244,14 @@ public class StatsController extends BaseController { public long getSentBytesCount(int networkType, int dataType) { if (dataType == TYPE_MESSAGES) { - return sentBytes[networkType][TYPE_TOTAL] - sentBytes[networkType][TYPE_FILES] - sentBytes[networkType][TYPE_AUDIOS] - sentBytes[networkType][TYPE_VIDEOS] - sentBytes[networkType][TYPE_PHOTOS]; + return sentBytes[networkType][TYPE_TOTAL] - sentBytes[networkType][TYPE_FILES] - sentBytes[networkType][TYPE_AUDIOS] - sentBytes[networkType][TYPE_VIDEOS] - sentBytes[networkType][TYPE_PHOTOS] - sentBytes[networkType][TYPE_MUSIC]; } return sentBytes[networkType][dataType]; } public long getReceivedBytesCount(int networkType, int dataType) { if (dataType == TYPE_MESSAGES) { - return receivedBytes[networkType][TYPE_TOTAL] - receivedBytes[networkType][TYPE_FILES] - receivedBytes[networkType][TYPE_AUDIOS] - receivedBytes[networkType][TYPE_VIDEOS] - receivedBytes[networkType][TYPE_PHOTOS]; + return receivedBytes[networkType][TYPE_TOTAL] - receivedBytes[networkType][TYPE_FILES] - receivedBytes[networkType][TYPE_AUDIOS] - receivedBytes[networkType][TYPE_VIDEOS] - receivedBytes[networkType][TYPE_PHOTOS] - receivedBytes[networkType][TYPE_MUSIC]; } return receivedBytes[networkType][dataType]; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java index 92841bb4a..54a957356 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java @@ -204,10 +204,8 @@ public class TopicsController extends BaseController { } } - - if (topicsToReload != null && loadType != LOAD_TYPE_LOAD_UNKNOWN) { - reloadTopics(chatId, topicsToReload); + reloadTopics(chatId, topicsToReload, null); } else if (((loadType == LOAD_TYPE_PRELOAD && !fromCache) || loadType == LOAD_TYPE_LOAD_NEXT) && topics.size() >= totalCount && totalCount >= 0) { endIsReached.put(chatId, 1); getUserConfig().getPreferences().edit().putBoolean("topics_end_reached_" + chatId, true).apply(); @@ -244,7 +242,6 @@ public class TopicsController extends BaseController { ArrayList topics = topicsByChatId.get(chatId); if (topics != null) { if (openedTopicsBuChatId.get(chatId, 0) > 0) { -// Comparator.comparingInt(o -> o.topMessage == null ? Integer.MAX_VALUE : -(o.pinned ? Integer.MAX_VALUE - o.pinnedOrder : o.topMessage.date)) Collections.sort(topics, (a, b) -> { if (a.hidden != b.hidden) { return a.hidden ? -1 : 1; @@ -351,7 +348,7 @@ public class TopicsController extends BaseController { sortTopics(chatId); } if (topicsToReload != null) { - reloadTopics(chatId, topicsToReload); + reloadTopics(chatId, topicsToReload, null); } }); } @@ -359,7 +356,7 @@ public class TopicsController extends BaseController { }); } - private void reloadTopics(long chatId, ArrayList topicsToReload) { + public void reloadTopics(long chatId, ArrayList topicsToReload, Runnable callback) { TLRPC.TL_channels_getForumTopicsByID req = new TLRPC.TL_channels_getForumTopicsByID(); for (int i = 0; i < topicsToReload.size(); i++) { req.topics.add(topicsToReload.get(i).id); @@ -379,6 +376,9 @@ public class TopicsController extends BaseController { processTopics(chatId, topics.topics, messagesMap, false, LOAD_TYPE_LOAD_UNKNOWN, -1); getMessagesStorage().putMessages(topics.messages, false, true, false, 0, false, 0); getMessagesStorage().saveTopics(-chatId, topicsByChatId.get(chatId), true, true); + if (callback != null) { + callback.run(); + } }); } })); @@ -820,7 +820,7 @@ public class TopicsController extends BaseController { for (int i = 0; i < topicsToReload.size(); i++) { long dialogId = topicsToReload.keyAt(i); ArrayList topics = topicsToReload.valueAt(i); - reloadTopics(-dialogId, topics); + reloadTopics(-dialogId, topics, null); } } @@ -872,14 +872,9 @@ public class TopicsController extends BaseController { endIsReached.delete(chatId); clearLoadingOffset(chatId); - TLRPC.Chat chat = getMessagesController().getChat(chatId); if (chat != null && chat.forum) { - if (fromCache) { - preloadTopics(chatId); - } else { - loadTopics(chatId, false, LOAD_TYPE_PRELOAD); - } + loadTopics(chatId, fromCache, LOAD_TYPE_PRELOAD); } sortTopics(chatId); }); @@ -979,6 +974,27 @@ public class TopicsController extends BaseController { } } + public void loadTopic(long chatId, int topicId, Runnable runnable) { + getMessagesStorage().loadTopics(-chatId, topics -> { + AndroidUtilities.runOnUIThread(() -> { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("loaded from cache " + chatId + " topics_count=" + (topics == null ? 0 : topics.size())); + } + + processTopics(chatId, topics, null, true, LOAD_TYPE_PRELOAD, -1); + sortTopics(chatId); + if (findTopic(chatId, topicId) != null) { + runnable.run(); + } else { + ArrayList topicToReload = new ArrayList<>(); + TLRPC.TL_forumTopic topic = new TLRPC.TL_forumTopic(); + topic.id = topicId; + reloadTopics(chatId, topicToReload, runnable); + } + }); + }); + } + private class TopicsLoadOffset { int lastMessageId; int lastMessageDate; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java new file mode 100644 index 000000000..a9e721ede --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java @@ -0,0 +1,980 @@ +package org.telegram.messenger; + +import android.content.Context; +import android.content.res.Resources; +import android.icu.text.Collator; +import android.text.TextUtils; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; + +import androidx.annotation.Nullable; + +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.TranslateAlert2; +import org.telegram.ui.RestrictedLanguagesSelectActivity; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; + +public class TranslateController extends BaseController { + + public static final String UNKNOWN_LANGUAGE = "und"; + + private static final int REQUIRED_TOTAL_MESSAGES_CHECKED = 8; + private static final float REQUIRED_PERCENTAGE_MESSAGES_TRANSLATABLE = .60F; + private static final float REQUIRED_MIN_PERCENTAGE_MESSAGES_UNKNOWN = .65F; + + private static final int MAX_SYMBOLS_PER_REQUEST = 25000; + private static final int MAX_MESSAGES_PER_REQUEST = 20; + private static final int GROUPING_TRANSLATIONS_TIMEOUT = 200; + + private final Set translatingDialogs = new HashSet<>(); + private final Set translatableDialogs = new HashSet<>(); + private final HashMap translatableDialogMessages = new HashMap<>(); + private final HashMap translateDialogLanguage = new HashMap<>(); + private final HashMap detectedDialogLanguage = new HashMap<>(); + private final HashMap> keptReplyMessageObjects = new HashMap<>(); + private final Set hideTranslateDialogs = new HashSet<>(); + + class TranslatableDecision { + Set certainlyTranslatable = new HashSet<>(); + Set unknown = new HashSet<>(); + Set certainlyNotTranslatable = new HashSet<>(); + } + + private MessagesController messagesController; + + public TranslateController(MessagesController messagesController) { + super(messagesController.currentAccount); + this.messagesController = messagesController; + + AndroidUtilities.runOnUIThread(this::loadTranslatingDialogsCached, 150); + } + + public boolean isFeatureAvailable() { + return UserConfig.getInstance(currentAccount).isPremium() && isChatTranslateEnabled(); + } + + public boolean isChatTranslateEnabled() { + return MessagesController.getMainSettings(currentAccount).getBoolean("translate_chat_button", true); + } + + public boolean isContextTranslateEnabled() { + return MessagesController.getMainSettings(currentAccount).getBoolean("translate_button", MessagesController.getGlobalMainSettings().getBoolean("translate_button", false)); + } + + public void setContextTranslateEnabled(boolean enable) { + MessagesController.getMainSettings(currentAccount).edit().putBoolean("translate_button", enable).apply(); + } + + public static boolean isTranslatable(MessageObject messageObject) { + return ( + messageObject != null && messageObject.messageOwner != null && + !messageObject.isOutOwner() && + ( + messageObject.type == MessageObject.TYPE_TEXT || + messageObject.type == MessageObject.TYPE_VIDEO || + messageObject.type == MessageObject.TYPE_PHOTO || + messageObject.type == MessageObject.TYPE_VOICE || + messageObject.type == MessageObject.TYPE_FILE || + messageObject.type == MessageObject.TYPE_MUSIC + ) && !TextUtils.isEmpty(messageObject.messageOwner.message) + ); + } + + public boolean isDialogTranslatable(long dialogId) { + return ( + isFeatureAvailable() && + !DialogObject.isEncryptedDialog(dialogId) && + getUserConfig().getClientUserId() != dialogId && + /* DialogObject.isChatDialog(dialogId) &&*/ + translatableDialogs.contains(dialogId) + ); + } + + public boolean isTranslateDialogHidden(long dialogId) { + if (hideTranslateDialogs.contains(dialogId)) { + return true; + } + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + return chatFull.translations_disabled; + } + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + return userFull.translations_disabled; + } + return false; + } + + public boolean isTranslatingDialog(long dialogId) { + return isFeatureAvailable() && translatingDialogs.contains(dialogId); + } + + public void toggleTranslatingDialog(long dialogId) { + toggleTranslatingDialog(dialogId, !isTranslatingDialog(dialogId)); + } + + public boolean toggleTranslatingDialog(long dialogId, boolean value) { + boolean currentValue = isTranslatingDialog(dialogId), notified = false; + if (value && !currentValue) { + translatingDialogs.add(dialogId); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, true); + notified = true; + } else if (!value && currentValue) { + translatingDialogs.remove((Long) dialogId); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, false); + cancelTranslations(dialogId); + notified = true; + } + saveTranslatingDialogsCache(); + return notified; + } + + private int hash(MessageObject messageObject) { + if (messageObject == null) { + return 0; + } + return Objects.hash(messageObject.getDialogId(), messageObject.getId()); + } + + private String currentLanguage() { + String lang = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; + if (lang != null) { + lang = lang.split("_")[0]; + } + return lang; + } + + public String getDialogTranslateTo(long dialogId) { + String lang = translateDialogLanguage.get(dialogId); + if (lang == null) { + lang = TranslateAlert2.getToLanguage(); + if (lang == null || lang.equals(getDialogDetectedLanguage(dialogId))) { + lang = currentLanguage(); + } + } + if ("nb".equals(lang)) { + lang = "no"; + } + return lang; + } + + public void setDialogTranslateTo(long dialogId, String language) { + if (TextUtils.equals(getDialogTranslateTo(dialogId), language)) { + return; + } + + boolean wasTranslating = isTranslatingDialog(dialogId); + + if (wasTranslating) { + AndroidUtilities.runOnUIThread(() -> { + synchronized (TranslateController.this) { + translateDialogLanguage.put(dialogId, language); + translatingDialogs.add(dialogId); + saveTranslatingDialogsCache(); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, true); + }, 150); + } else { + synchronized (TranslateController.this) { + translateDialogLanguage.put(dialogId, language); + } + } + + cancelTranslations(dialogId); + synchronized (this) { + translatingDialogs.remove(dialogId); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, false); + + TranslateAlert2.setToLanguage(language); + } + + public void updateDialogFull(long dialogId) { + if (!isFeatureAvailable() || !isDialogTranslatable(dialogId)) { + return; + } + + final boolean wasHidden = hideTranslateDialogs.contains(dialogId); + + boolean hidden = false; + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + hidden = chatFull.translations_disabled; + } else { + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + hidden = userFull.translations_disabled; + } + } + + synchronized (this) { + if (hidden) { + hideTranslateDialogs.add(dialogId); + } else { + hideTranslateDialogs.remove(dialogId); + } + } + + if (wasHidden != hidden) { + saveTranslatingDialogsCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, isTranslatingDialog(dialogId)); + } + } + + public void setHideTranslateDialog(long dialogId, boolean hide) { + setHideTranslateDialog(dialogId, hide, false); + } + + public void setHideTranslateDialog(long dialogId, boolean hide, boolean doNotNotify) { + TLRPC.TL_messages_togglePeerTranslations req = new TLRPC.TL_messages_togglePeerTranslations(); + req.peer = getMessagesController().getInputPeer(dialogId); + req.disabled = hide; + getConnectionsManager().sendRequest(req, null); + + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + chatFull.translations_disabled = hide; + getMessagesStorage().updateChatInfo(chatFull, true); + } + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + userFull.translations_disabled = hide; + getMessagesStorage().updateUserInfo(userFull, true); + } + + synchronized (this) { + if (hide) { + hideTranslateDialogs.add(dialogId); + } else { + hideTranslateDialogs.remove(dialogId); + } + } + saveTranslatingDialogsCache(); + + if (!doNotNotify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, isTranslatingDialog(dialogId)); + } + } + + private static List languagesOrder = Arrays.asList( + "en", "ar", "zh", "fr", "de", "it", "ja", "ko", "pt", "ru", "es", "uk" + ); + + private static List allLanguages = Arrays.asList( + "af", "sq", "am", "ar", "hy", "az", "eu", "be", "bn", "bs", "bg", "ca", "ceb", "zh", "co", "hr", "cs", "da", "nl", "en", "eo", "et", "fi", "fr", "fy", "gl", "ka", "de", "el", "gu", "ht", "ha", "haw", "he", "iw", "hi", "hmn", "hu", "is", "ig", "id", "ga", "it", "ja", "jv", "kn", "kk", "km", "rw", "ko", "ku", "ky", "lo", "la", "lv", "lt", "lb", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mn", "my", "ne", "no", "ny", "or", "ps", "fa", "pl", "pt", "pa", "ro", "ru", "sm", "gd", "sr", "st", "sn", "sd", "si", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", "tt", "te", "th", "tr", "tk", "uk", "ur", "ug", "uz", "vi", "cy", "xh", "yi", "yo", "zu" + ); + + public static class Language { + public String code; + public String displayName; + } + + public static ArrayList getLanguages() { + ArrayList result = new ArrayList<>(); + for (int i = 0; i < allLanguages.size(); ++i) { + Language language = new Language(); + language.code = allLanguages.get(i); + language.displayName = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(language.code)); + if (language.displayName == null) { + continue; + } + result.add(language); + } + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + Collator collator = Collator.getInstance(Locale.getDefault()); + Collections.sort(result, (lng1, lng2) -> collator.compare(lng1.displayName, lng2.displayName)); + } else { + Collections.sort(result, Comparator.comparing(lng -> lng.displayName)); + } + return result; + } + + private static LinkedHashSet suggestedLanguageCodes = null; + public static void invalidateSuggestedLanguageCodes() { + suggestedLanguageCodes = null; + } + public static void analyzeSuggestedLanguageCodes() { + LinkedHashSet langs = new LinkedHashSet<>(); + try { + langs.add(LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode); + } catch (Exception e1) { + FileLog.e(e1); + } + try { + langs.add(Resources.getSystem().getConfiguration().locale.getLanguage()); + } catch (Exception e2) { + FileLog.e(e2); + } + try { + langs.addAll(RestrictedLanguagesSelectActivity.getRestrictedLanguages()); + } catch (Exception e3) { + FileLog.e(e3); + } + try { + InputMethodManager imm = (InputMethodManager) ApplicationLoader.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE); + List ims = imm.getEnabledInputMethodList(); + for (InputMethodInfo method : ims) { + List submethods = imm.getEnabledInputMethodSubtypeList(method, true); + for (InputMethodSubtype submethod : submethods) { + if ("keyboard".equals(submethod.getMode())) { + String currentLocale = submethod.getLocale(); + if (currentLocale != null && currentLocale.contains("_")) { + currentLocale = currentLocale.split("_")[0]; + } + if (TranslateAlert2.languageName(currentLocale) != null) { + langs.add(currentLocale); + } + } + } + } + } catch (Exception e4) { + FileLog.e(e4); + } + suggestedLanguageCodes = langs; + } + + public static ArrayList getSuggestedLanguages(String except) { + ArrayList result = new ArrayList<>(); + if (suggestedLanguageCodes == null) { + analyzeSuggestedLanguageCodes(); + if (suggestedLanguageCodes == null) { + return result; + } + } + Iterator i = suggestedLanguageCodes.iterator(); + while (i.hasNext()) { + final String code = i.next(); + if (TextUtils.equals(code, except) || "no".equals(except) && "nb".equals(code) || "nb".equals(except) && "no".equals(code)) { + continue; + } + Language language = new Language(); + language.code = code; + language.displayName = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(language.code)); + if (language.displayName == null) { + continue; + } + result.add(language); + } + return result; + } + + public static ArrayList getLocales() { + HashMap languages = LocaleController.getInstance().languagesDict; + ArrayList locales = new ArrayList<>(languages.values()); + for (int i = 0; i < locales.size(); ++i) { + LocaleController.LocaleInfo locale = locales.get(i); + if (locale == null || locale.shortName != null && locale.shortName.endsWith("_raw") || !"remote".equals(locale.pathToFile)) { + locales.remove(i); + i--; + } + } + + final LocaleController.LocaleInfo currentLocale = LocaleController.getInstance().getCurrentLocaleInfo(); + Comparator comparator = (o, o2) -> { + if (o == currentLocale) { + return -1; + } else if (o2 == currentLocale) { + return 1; + } + final int index1 = languagesOrder.indexOf(o.pluralLangCode); + final int index2 = languagesOrder.indexOf(o2.pluralLangCode); + if (index1 >= 0 && index2 >= 0) { + return index1 - index2; + } else if (index1 >= 0) { + return -1; + } else if (index2 >= 0) { + return 1; + } + if (o.serverIndex == o2.serverIndex) { + return o.name.compareTo(o2.name); + } + if (o.serverIndex > o2.serverIndex) { + return 1; + } else if (o.serverIndex < o2.serverIndex) { + return -1; + } + return 0; + }; + Collections.sort(locales, comparator); + + return locales; + } + + public void checkRestrictedLanguagesUpdate() { + synchronized (this) { + translatableDialogMessages.clear(); + + ArrayList toNotify = new ArrayList<>(); + HashSet languages = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); + for (long dialogId : translatableDialogs) { + String language = detectedDialogLanguage.get(dialogId); + if (language != null && languages.contains(language)) { + cancelTranslations(dialogId); + translatingDialogs.remove(dialogId); + toNotify.add(dialogId); + } + } + translatableDialogs.clear(); + saveTranslatingDialogsCache(); + + for (long dialogId : toNotify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, false); + } + } + } + + @Nullable + public String getDialogDetectedLanguage(long dialogId) { + return detectedDialogLanguage.get(dialogId); + } + + public void checkTranslation(MessageObject messageObject, boolean onScreen) { + checkTranslation(messageObject, onScreen, false); + } + + private void checkTranslation(MessageObject messageObject, boolean onScreen, boolean keepReply) { + if (!isFeatureAvailable()) { + return; + } + if (messageObject == null || messageObject.messageOwner == null) { + return; + } + + long dialogId = messageObject.getDialogId(); + + if (!keepReply && messageObject.replyMessageObject != null) { + checkTranslation(messageObject.replyMessageObject, onScreen, true); + } + + if (!isTranslatable(messageObject)) { + return; + } + + if (!isTranslatingDialog(dialogId)) { + checkLanguage(messageObject); + return; + } + + final String language = getDialogTranslateTo(dialogId); + MessageObject potentialReplyMessageObject; + if (!keepReply && (messageObject.messageOwner.translatedText == null || !language.equals(messageObject.messageOwner.translatedToLanguage)) && (potentialReplyMessageObject = findReplyMessageObject(dialogId, messageObject.getId())) != null) { + messageObject.messageOwner.translatedToLanguage = potentialReplyMessageObject.messageOwner.translatedToLanguage; + messageObject.messageOwner.translatedText = potentialReplyMessageObject.messageOwner.translatedText; + messageObject = potentialReplyMessageObject; + } + + if (onScreen && isTranslatingDialog(dialogId)) { + final MessageObject finalMessageObject = messageObject; + if (finalMessageObject.messageOwner.translatedText == null || !language.equals(finalMessageObject.messageOwner.translatedToLanguage)) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageTranslating, finalMessageObject); + pushToTranslate(finalMessageObject, language, (text, lang) -> { + finalMessageObject.messageOwner.translatedToLanguage = lang; + finalMessageObject.messageOwner.translatedText = text; + if (keepReply) { + keepReplyMessage(finalMessageObject); + } + + getMessagesStorage().updateMessageCustomParams(dialogId, finalMessageObject.messageOwner); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageTranslated, finalMessageObject); + + ArrayList dialogMessages = messagesController.dialogMessage.get(dialogId); + if (dialogMessages != null) { + for (int i = 0; i < dialogMessages.size(); ++i) { + MessageObject dialogMessage = dialogMessages.get(i); + if (dialogMessage != null && dialogMessage.getId() == finalMessageObject.getId()) { + dialogMessage.messageOwner.translatedToLanguage = lang; + dialogMessage.messageOwner.translatedText = text; + if (dialogMessage.updateTranslation()) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, 0); + } + break; + } + } + } + }); + } else if (keepReply) { + keepReplyMessage(messageObject); + } + } + } + + public void invalidateTranslation(MessageObject messageObject) { + if (!isFeatureAvailable()) { + return; + } + if (messageObject == null || messageObject.messageOwner == null) { + return; + } + final long dialogId = messageObject.getDialogId(); + messageObject.messageOwner.translatedToLanguage = null; + messageObject.messageOwner.translatedText = null; + getMessagesStorage().updateMessageCustomParams(dialogId, messageObject.messageOwner); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageTranslated, messageObject, isTranslatingDialog(dialogId)); + }); + } + + public void checkDialogMessages(long dialogId) { + if (!isFeatureAvailable()) { + return; + } + getMessagesStorage().getStorageQueue().postRunnable(() -> { + final ArrayList dialogMessages = messagesController.dialogMessage.get(dialogId); + if (dialogMessages == null) { + return; + } + ArrayList customProps = new ArrayList<>(); + for (int i = 0; i < dialogMessages.size(); ++i) { + MessageObject dialogMessage = dialogMessages.get(i); + if (dialogMessage == null || dialogMessage.messageOwner == null) { + customProps.add(null); + continue; + } + customProps.add(getMessagesStorage().getMessageWithCustomParamsOnlyInternal(dialogMessage.getId(), dialogMessage.getDialogId())); + } + AndroidUtilities.runOnUIThread(() -> { + boolean updated = false; + for (int i = 0; i < Math.min(customProps.size(), dialogMessages.size()); ++i) { + MessageObject dialogMessage = dialogMessages.get(i); + TLRPC.Message props = customProps.get(i); + if (dialogMessage == null || dialogMessage.messageOwner == null || props == null) { + continue; + } + dialogMessage.messageOwner.translatedText = props.translatedText; + dialogMessage.messageOwner.translatedToLanguage = props.translatedToLanguage; + if (dialogMessage.updateTranslation(false)) { + updated = true; + } + } + if (updated) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, 0); + } + }); + }); + } + + + public void cleanup() { + cancelAllTranslations(); + resetTranslatingDialogsCache(); + + translatingDialogs.clear(); + translatableDialogs.clear(); + translatableDialogMessages.clear(); + translateDialogLanguage.clear(); + detectedDialogLanguage.clear(); + keptReplyMessageObjects.clear(); + hideTranslateDialogs.clear(); + loadingTranslations.clear(); + } + + private ArrayList pendingLanguageChecks = new ArrayList<>(); + private void checkLanguage(MessageObject messageObject) { + if (!LanguageDetector.hasSupport()) { + return; + } + if (!isTranslatable(messageObject) || messageObject.messageOwner == null || TextUtils.isEmpty(messageObject.messageOwner.message)) { + return; + } + if (messageObject.messageOwner.originalLanguage != null) { + checkDialogTranslatable(messageObject); + return; + } + + final long dialogId = messageObject.getDialogId(); + final int hash = hash(messageObject); + if (isDialogTranslatable(dialogId)) { + return; + } + if (pendingLanguageChecks.contains(hash)) { + return; + } + + pendingLanguageChecks.add(hash); + + LanguageDetector.detectLanguage(messageObject.messageOwner.message, lng -> AndroidUtilities.runOnUIThread(() -> { + String detectedLanguage = lng; + if (detectedLanguage == null) { + detectedLanguage = UNKNOWN_LANGUAGE; + } + messageObject.messageOwner.originalLanguage = detectedLanguage; + getMessagesStorage().updateMessageCustomParams(dialogId, messageObject.messageOwner); + pendingLanguageChecks.remove((Integer) hash); + checkDialogTranslatable(messageObject); + }), err -> AndroidUtilities.runOnUIThread(() -> { + messageObject.messageOwner.originalLanguage = UNKNOWN_LANGUAGE; + getMessagesStorage().updateMessageCustomParams(dialogId, messageObject.messageOwner); + pendingLanguageChecks.remove((Integer) hash); + })); + } + + private void checkDialogTranslatable(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return; + } + + final long dialogId = messageObject.getDialogId(); + TranslatableDecision translatableMessages = translatableDialogMessages.get(dialogId); + if (translatableMessages == null) { + translatableDialogMessages.put(dialogId, translatableMessages = new TranslatableDecision()); + } + + final boolean isUnknown = isTranslatable(messageObject) && ( + messageObject.messageOwner.originalLanguage == null || + UNKNOWN_LANGUAGE.equals(messageObject.messageOwner.originalLanguage) + ); + final boolean translatable = ( + isTranslatable(messageObject) && + messageObject.messageOwner.originalLanguage != null && + !UNKNOWN_LANGUAGE.equals(messageObject.messageOwner.originalLanguage) && + !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(messageObject.messageOwner.originalLanguage) && + !TextUtils.equals(getDialogTranslateTo(dialogId), messageObject.messageOwner.originalLanguage) + ); + + if (isUnknown) { + translatableMessages.unknown.add(messageObject.getId()); + } else { + (translatable ? translatableMessages.certainlyTranslatable : translatableMessages.certainlyNotTranslatable).add(messageObject.getId()); + } + + if (!isUnknown) { + detectedDialogLanguage.put(dialogId, messageObject.messageOwner.originalLanguage); + } + + final int translatableCount = translatableMessages.certainlyTranslatable.size(); + final int unknownCount = translatableMessages.unknown.size(); + final int notTranslatableCount = translatableMessages.certainlyNotTranslatable.size(); + final int totalCount = translatableCount + unknownCount + notTranslatableCount; + if ( + totalCount >= REQUIRED_TOTAL_MESSAGES_CHECKED && + (translatableCount / (float) (translatableCount + notTranslatableCount)) >= REQUIRED_PERCENTAGE_MESSAGES_TRANSLATABLE && + (unknownCount / (float) totalCount) < REQUIRED_MIN_PERCENTAGE_MESSAGES_UNKNOWN + ) { + translatableDialogs.add(dialogId); + translatableDialogMessages.remove((Long) dialogId); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogIsTranslatable, dialogId); + }, 450); + } + } + + private final Set loadingTranslations = new HashSet<>(); + private final HashMap> pendingTranslations = new HashMap<>(); + + private static class PendingTranslation { + Runnable runnable; + ArrayList messageIds = new ArrayList<>(); + ArrayList messageTexts = new ArrayList<>(); + ArrayList> callbacks = new ArrayList<>(); + String language; + + int symbolsCount; + + int reqId = -1; + } + + private void pushToTranslate( + MessageObject message, + String language, + Utilities.Callback2 callback + ) { + if (message == null || callback == null) { + return; + } + + long dialogId = message.getDialogId(); + + PendingTranslation pendingTranslation; + synchronized (this) { + ArrayList dialogPendingTranslations = pendingTranslations.get(dialogId); + if (dialogPendingTranslations == null) { + pendingTranslations.put(dialogId, dialogPendingTranslations = new ArrayList<>()); + } + + if (dialogPendingTranslations.isEmpty()) { + dialogPendingTranslations.add(pendingTranslation = new PendingTranslation()); + } else { + pendingTranslation = dialogPendingTranslations.get(dialogPendingTranslations.size() - 1); + } + + if (pendingTranslation.messageIds.contains(message.getId())) { + return; + } + + int messageSymbolsCount = 0; + if (message.messageOwner != null && message.messageOwner.message != null) { + messageSymbolsCount = message.messageOwner.message.length(); + } else if (message.caption != null) { + messageSymbolsCount = message.caption.length(); + } else if (message.messageText != null) { + messageSymbolsCount = message.messageText.length(); + } + + if (pendingTranslation.symbolsCount + messageSymbolsCount >= MAX_SYMBOLS_PER_REQUEST || + pendingTranslation.messageIds.size() + 1 >= MAX_MESSAGES_PER_REQUEST) { + dialogPendingTranslations.add(pendingTranslation = new PendingTranslation()); + } + + if (pendingTranslation.runnable != null) { + AndroidUtilities.cancelRunOnUIThread(pendingTranslation.runnable); + } + loadingTranslations.add(message.getId()); + pendingTranslation.messageIds.add(message.getId()); + TLRPC.TL_textWithEntities source = null; + if (message.messageOwner != null) { + source = new TLRPC.TL_textWithEntities(); + source.text = message.messageOwner.message; + source.entities = message.messageOwner.entities; + } + pendingTranslation.messageTexts.add(source); + pendingTranslation.callbacks.add(callback); + pendingTranslation.language = language; + pendingTranslation.symbolsCount += messageSymbolsCount; + final PendingTranslation pendingTranslation1 = pendingTranslation; + pendingTranslation.runnable = () -> { + synchronized (TranslateController.this) { + ArrayList dialogPendingTranslations1 = pendingTranslations.get(dialogId); + if (dialogPendingTranslations1 != null) { + dialogPendingTranslations1.remove(pendingTranslation1); + if (dialogPendingTranslations1.isEmpty()) { + pendingTranslations.remove(dialogId); + } + } + } + + TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); + req.flags |= 1; + req.peer = getMessagesController().getInputPeer(dialogId); + req.id = pendingTranslation1.messageIds; + req.to_lang = pendingTranslation1.language; + + final int reqId = getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + final ArrayList ids; + final ArrayList> callbacks; + final ArrayList texts; + synchronized (TranslateController.this) { + ids = pendingTranslation1.messageIds; + callbacks = pendingTranslation1.callbacks; + texts = pendingTranslation1.messageTexts; + } + if (res instanceof TLRPC.TL_messages_translateResult) { + ArrayList translated = ((TLRPC.TL_messages_translateResult) res).result; + final int count = Math.min(callbacks.size(), translated.size()); + for (int i = 0; i < count; ++i) { + callbacks.get(i).run(TranslateAlert2.preprocess(texts.get(i), translated.get(i)), pendingTranslation1.language); + } + } else if (err != null && "TO_LANG_INVALID".equals(err.text)) { + toggleTranslatingDialog(dialogId, false); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR, LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2)); + } else { + for (int i = 0; i < callbacks.size(); ++i) { + callbacks.get(i).run(null, pendingTranslation1.language); + } + } + synchronized (TranslateController.this) { + for (int i = 0; i < ids.size(); ++i) { + loadingTranslations.remove(ids.get(i)); + } + } + })); + synchronized (TranslateController.this) { + pendingTranslation1.reqId = reqId; + } + }; + AndroidUtilities.runOnUIThread(pendingTranslation.runnable, GROUPING_TRANSLATIONS_TIMEOUT); + } + } + + public boolean isTranslating(MessageObject messageObject) { + synchronized (this) { + return messageObject != null && isTranslatingDialog(messageObject.getDialogId()) && loadingTranslations.contains(messageObject.getId()); + } + } + + public boolean isTranslating(MessageObject messageObject, MessageObject.GroupedMessages group) { + if (messageObject == null) { + return false; + } + if (!isTranslatingDialog(messageObject.getDialogId())) { + return false; + } + synchronized (this) { + if (loadingTranslations.contains(messageObject.getId())) { + return true; + } + if (group != null) { + for (MessageObject message : group.messages) { + if (loadingTranslations.contains(message.getId())) { + return true; + } + } + } + } + return false; + } + + public void cancelAllTranslations() { + synchronized (this) { + for (ArrayList translations : pendingTranslations.values()) { + if (translations != null) { + for (PendingTranslation pendingTranslation : translations) { + AndroidUtilities.cancelRunOnUIThread(pendingTranslation.runnable); + if (pendingTranslation.reqId != -1) { + getConnectionsManager().cancelRequest(pendingTranslation.reqId, true); + for (Integer messageId : pendingTranslation.messageIds) { + loadingTranslations.remove(messageId); + } + } + } + } + } + } + } + + public void cancelTranslations(long dialogId) { + synchronized (this) { + ArrayList translations = pendingTranslations.get(dialogId); + if (translations != null) { + for (PendingTranslation pendingTranslation : translations) { + AndroidUtilities.cancelRunOnUIThread(pendingTranslation.runnable); + if (pendingTranslation.reqId != -1) { + getConnectionsManager().cancelRequest(pendingTranslation.reqId, true); + for (Integer messageId : pendingTranslation.messageIds) { + loadingTranslations.remove(messageId); + } + } + } + pendingTranslations.remove((Long) dialogId); + } + } + } + + private void keepReplyMessage(MessageObject messageObject) { + if (messageObject == null) { + return; + } + HashMap map = keptReplyMessageObjects.get(messageObject.getDialogId()); + if (map == null) { + keptReplyMessageObjects.put(messageObject.getDialogId(), map = new HashMap<>()); + } + map.put(messageObject.getId(), messageObject); + } + + public MessageObject findReplyMessageObject(long dialogId, int messageId) { + HashMap map = keptReplyMessageObjects.get(dialogId); + if (map == null) { + return null; + } + return map.get(messageId); + } + + private void clearAllKeptReplyMessages(long dialogId) { + keptReplyMessageObjects.remove(dialogId); + } + + + private void loadTranslatingDialogsCached() { + if (!isFeatureAvailable()) { + return; + } + + String translatingDialogsCache = messagesController.getMainSettings().getString("translating_dialog_languages2", null); + if (translatingDialogsCache == null) { + return; + } + String[] dialogs = translatingDialogsCache.split(";"); + + HashSet restricted = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); + for (int i = 0; i < dialogs.length; ++i) { + String[] keyval = dialogs[i].split("="); + if (keyval.length < 2) { + continue; + } + long did = Long.parseLong(keyval[0]); + String[] langs = keyval[1].split(">"); + if (langs.length != 2) { + continue; + } + String from = langs[0], to = langs[1]; + if ("null".equals(from)) from = null; + if ("null".equals(to)) to = null; + if (from != null) { + detectedDialogLanguage.put(did, from); + if (!restricted.contains(from)) { + translatingDialogs.add(did); + translatableDialogs.add(did); + } + if (to != null) { + translateDialogLanguage.put(did, to); + } + } + } + + Set hidden = messagesController.getMainSettings().getStringSet("hidden_translation_at", null); + if (hidden != null) { + Iterator i = hidden.iterator(); + while (i.hasNext()) { + try { + hideTranslateDialogs.add(Long.parseLong(i.next())); + } catch (Exception e) { + FileLog.e(e); + } + } + } + } + + private void saveTranslatingDialogsCache() { + StringBuilder langset = new StringBuilder(); + Iterator i = translatingDialogs.iterator(); + boolean first = true; + while (i.hasNext()) { + try { + long did = i.next(); + if (!first) { + langset.append(";"); + } + if (first) { + first = false; + } + String lang = detectedDialogLanguage.get(did); + if (lang == null) { + lang = "null"; + } + String tolang = getDialogTranslateTo(did); + if (tolang == null) { + tolang = "null"; + } + langset.append(did).append("=").append(lang).append(">").append(tolang); + } catch (Exception e) {} + } + + Set hidden = new HashSet<>(); + i = hideTranslateDialogs.iterator(); + while (i.hasNext()) { + try { + hidden.add("" + i.next()); + } catch (Exception e) { + FileLog.e(e); + } + } + MessagesController.getMainSettings(currentAccount).edit().putString("translating_dialog_languages2", langset.toString()).putStringSet("hidden_translation_at", hidden).apply(); + } + + private void resetTranslatingDialogsCache() { + MessagesController.getMainSettings(currentAccount).edit().remove("translating_dialog_languages2").remove("hidden_translation_at").apply(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index 253bdd2b1..ed023fc61 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -12,6 +12,9 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.SystemClock; import android.util.Base64; +import android.util.LongSparseArray; +import android.util.SparseArray; +import android.util.SparseLongArray; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLRPC; @@ -78,6 +81,10 @@ public class UserConfig extends BaseController { public volatile byte[] savedPasswordHash; public volatile byte[] savedSaltedPassword; public volatile long savedPasswordTime; + LongSparseArray userSaveGalleryExceptions; + LongSparseArray chanelSaveGalleryExceptions; + LongSparseArray groupsSaveGalleryExceptions; + private static volatile UserConfig[] Instance = new UserConfig[UserConfig.MAX_ACCOUNT_COUNT]; public static UserConfig getInstance(int num) { @@ -415,6 +422,48 @@ public class UserConfig extends BaseController { } } + public LongSparseArray getSaveGalleryExceptions(int type) { + if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_PEER) { + if (userSaveGalleryExceptions == null) { + userSaveGalleryExceptions = SaveToGallerySettingsHelper.loadExceptions(ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.USERS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE)); + } + return userSaveGalleryExceptions; + } else if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP) { + if (groupsSaveGalleryExceptions == null) { + groupsSaveGalleryExceptions = SaveToGallerySettingsHelper.loadExceptions(ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.GROUPS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE)); + } + return groupsSaveGalleryExceptions; + } else if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS) { + if (chanelSaveGalleryExceptions == null) { + chanelSaveGalleryExceptions = SaveToGallerySettingsHelper.loadExceptions(ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.CHANNELS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE)); + } + return chanelSaveGalleryExceptions; + } + return null; + } + + public void updateSaveGalleryExceptions(int type, LongSparseArray exceptions) { + if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_PEER) { + userSaveGalleryExceptions = exceptions; + SaveToGallerySettingsHelper.saveExceptions( + ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.USERS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE), + userSaveGalleryExceptions + ); + } else if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP) { + groupsSaveGalleryExceptions = exceptions; + SaveToGallerySettingsHelper.saveExceptions( + ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.GROUPS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE), + groupsSaveGalleryExceptions + ); + } else if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS) { + chanelSaveGalleryExceptions = exceptions; + SaveToGallerySettingsHelper.saveExceptions( + ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.CHANNELS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE), + chanelSaveGalleryExceptions + ); + } + } + public void clearConfig() { getPreferences().edit().clear().apply(); @@ -516,16 +565,7 @@ public class UserConfig extends BaseController { } public Long getEmojiStatus() { - if (currentUser == null) { - return null; - } - if (currentUser.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - return ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).document_id; - } - if (currentUser.emoji_status instanceof TLRPC.TL_emojiStatus) { - return ((TLRPC.TL_emojiStatus) currentUser.emoji_status).document_id; - } - return null; + return UserObject.getEmojiStatusDocumentId(currentUser); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java index af7af8a8f..b7bfa661f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java @@ -111,4 +111,26 @@ public class UserObject { public static boolean hasFallbackPhoto(TLRPC.UserFull userInfo) { return userInfo != null && userInfo.fallback_photo != null && !(userInfo.fallback_photo instanceof TLRPC.TL_photoEmpty); } + + public static Long getEmojiStatusDocumentId(TLRPC.User user) { + if (user == null) { + return null; + } + return getEmojiStatusDocumentId(user.emoji_status); + } + + public static Long getEmojiStatusDocumentId(TLRPC.EmojiStatus emojiStatus) { + if (emojiStatus == null) { + return null; + } + if (emojiStatus instanceof TLRPC.TL_emojiStatus) + return ((TLRPC.TL_emojiStatus) emojiStatus).document_id; + if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil) { + TLRPC.TL_emojiStatusUntil untilStatus = (TLRPC.TL_emojiStatusUntil) emojiStatus; + if (untilStatus.until > (int) (System.currentTimeMillis() / 1000)) { + return untilStatus.document_id; + } + } + return null; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 8b140259f..5e3dfb73d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -510,10 +510,18 @@ public class Utilities { public void run(T arg); } + public static interface CallbackReturn { + public ReturnType run(Arg arg); + } + public static interface Callback2 { public void run(T arg, T2 arg2); } + public static interface Callback3 { + public void run(T arg, T2 arg2, T3 arg3); + } + public static Value getOrDefault(HashMap map, Key key, Value defaultValue) { Value v = map.get(key); if (v == null) { @@ -521,4 +529,34 @@ public class Utilities { } return v; } + + public static void doCallbacks(Utilities.Callback ...actions) { + doCallbacks(0, actions); + } + private static void doCallbacks(int i, Utilities.Callback ...actions) { + if (actions != null && actions.length > i) { + actions[i].run(() -> doCallbacks(i + 1, actions)); + } + } + + public static void raceCallbacks(Runnable onFinish, Utilities.Callback ...actions) { + if (actions == null || actions.length == 0) { + if (onFinish != null) { + onFinish.run(); + } + return; + } + final int[] finished = new int[] { 0 }; + Runnable checkFinish = () -> { + finished[0]++; + if (finished[0] == actions.length) { + if (onFinish != null) { + onFinish.run(); + } + } + }; + for (int i = 0; i < actions.length; ++i) { + actions[i].run(checkFinish); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index aef8d17c4..d219b56c0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -103,6 +103,7 @@ public class VideoEditedInfo { public int textAlign; public int viewWidth; public int viewHeight; + public float roundRadius; public float scale; public float textViewWidth; @@ -122,6 +123,7 @@ public class VideoEditedInfo { public View view; public Canvas canvas; public AnimatedFileDrawable animatedFileDrawable; + public Canvas roundRadiusCanvas; public MediaEntity() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java index c53c09743..570c29f6a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java @@ -26,6 +26,7 @@ import org.telegram.messenger.BuildVars; import org.telegram.messenger.CustomTabsCopyReceiver; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.ShareBroadcastReceiver; @@ -248,7 +249,7 @@ public class Browser { boolean internalUri = isInternalUri(uri, forceBrowser); if (tryTelegraph) { try { - String host = uri.getHost().toLowerCase(); + String host = AndroidUtilities.getHostAuthority(uri); if (isTelegraphUrl(host, true) || uri.toString().toLowerCase().contains("telegram.org/faq") || uri.toString().toLowerCase().contains("telegram.org/privacy")) { final AlertDialog[] progressDialog = new AlertDialog[] { new AlertDialog(context, AlertDialog.ALERT_TYPE_SPINNER) @@ -307,7 +308,7 @@ public class Browser { FileLog.e(e); } } - String host = uri.getHost() != null ? uri.getHost().toLowerCase() : ""; + String host = AndroidUtilities.getHostAuthority(uri.toString().toLowerCase()); if (AccountInstance.getInstance(currentAccount).getMessagesController().autologinDomains.contains(host)) { String token = "autologin_token=" + URLEncoder.encode(AccountInstance.getInstance(UserConfig.selectedAccount).getMessagesController().autologinToken, "UTF-8"); String url = uri.toString(); @@ -375,6 +376,13 @@ public class Browser { } if (forceBrowser[0] || allActivities == null || allActivities.isEmpty()) { + if (MessagesController.getInstance(currentAccount).authDomains.contains(host)) { + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + ApplicationLoader.applicationContext.startActivity(intent); + return; + } + Intent share = new Intent(ApplicationLoader.applicationContext, ShareBroadcastReceiver.class); share.setAction(Intent.ACTION_SEND); @@ -441,9 +449,16 @@ public class Browser { } public static boolean isInternalUri(Uri uri, boolean all, boolean[] forceBrowser) { - String host = uri.getHost(); + String host = AndroidUtilities.getHostAuthority(uri); host = host != null ? host.toLowerCase() : ""; + if (MessagesController.getInstance(UserConfig.selectedAccount).authDomains.contains(host)) { + if (forceBrowser != null) { + forceBrowser[0] = true; + } + return false; + } + Matcher prefixMatcher = LaunchActivity.PREFIX_T_ME_PATTERN.matcher(host); if (prefixMatcher.find()) { uri = Uri.parse("https://t.me/" + prefixMatcher.group(1) + (TextUtils.isEmpty(uri.getPath()) ? "" : "/" + uri.getPath()) + (TextUtils.isEmpty(uri.getQuery()) ? "" : "?" + uri.getQuery())); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java b/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java index cb6a39eb5..2b2c7f295 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java @@ -42,7 +42,6 @@ public class BitmapsCache { ArrayList frameOffsets = new ArrayList<>(); - final boolean useSharedBuffers; static ConcurrentHashMap sharedBuffers = new ConcurrentHashMap(); static volatile boolean cleanupScheduled; @@ -111,6 +110,9 @@ public class BitmapsCache { fileExist = false; file.delete(); } else { + if (cachedFile != randomAccessFile) { + closeCachedFile(); + } cachedFile = randomAccessFile; } } @@ -179,6 +181,9 @@ public class BitmapsCache { if (count > 0) { fillFrames(randomAccessFile, count); randomAccessFile.seek(0); + if (cachedFile != randomAccessFile) { + closeCachedFile(); + } cachedFile = randomAccessFile; fileExist = true; return; @@ -345,6 +350,7 @@ public class BitmapsCache { this.frameOffsets.clear(); this.frameOffsets.addAll(frameOffsets); + closeCachedFile(); cachedFile = new RandomAccessFile(file, "r"); cacheCreated = true; fileExist = true; @@ -460,6 +466,9 @@ public class BitmapsCache { bufferTmp = getBuffer(selectedFrame); randomAccessFile.readFully(bufferTmp, 0, selectedFrame.frameSize); if (!recycled) { + if (cachedFile != randomAccessFile) { + closeCachedFile(); + } cachedFile = randomAccessFile; } else { cachedFile = null; @@ -495,6 +504,16 @@ public class BitmapsCache { return FRAME_RESULT_NO_FRAME; } + private void closeCachedFile() { + if (cachedFile != null) { + try { + cachedFile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + private byte[] getBuffer(FrameOffset selectedFrame) { boolean useSharedBuffers = this.useSharedBuffers && Thread.currentThread().getName().startsWith(DispatchQueuePoolBackground.THREAD_PREFIX); byte[] bufferTmp; @@ -539,6 +558,10 @@ public class BitmapsCache { return frameOffsets.size(); } + public boolean isCreated() { + return cacheCreated && fileExist; + } + private class FrameOffset { final int index; int frameSize; @@ -642,6 +665,7 @@ public class BitmapsCache { public static class CacheOptions { public int compressQuality = 100; public boolean fallback = false; + public boolean firstFrame; } private static class CacheGeneratorSharedTools { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/utils/PhotoUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/utils/PhotoUtilities.java index 52fbac616..ee534ca26 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/utils/PhotoUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/utils/PhotoUtilities.java @@ -47,10 +47,10 @@ public class PhotoUtilities { INavigationLayout layout = baseFragment.getParentLayout(); int currentAccount = baseFragment.getCurrentAccount(); - ImageUpdater imageUpdater = new ImageUpdater(true); + ImageUpdater imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); imageUpdater.parentFragment = baseFragment; imageUpdater.processEntry(entry); - imageUpdater.setDelegate((photo, video, videoStartTimestamp, videoPath, bigSize, smallSize, isVideo) -> AndroidUtilities.runOnUIThread(() -> { + imageUpdater.setDelegate((photo, video, videoStartTimestamp, videoPath, bigSize, smallSize, isVideo, emojiMarkup) -> AndroidUtilities.runOnUIThread(() -> { TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); if (photo != null) { req.file = photo; @@ -62,6 +62,10 @@ public class PhotoUtilities { req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.video_emoji_markup = emojiMarkup; + req.flags |= 16; + } ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (response instanceof TLRPC.TL_photos_photo) { TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java index fea4f5c05..61bb3813b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java @@ -354,7 +354,9 @@ public class MediaCodecVideoConvertor { } avatarStartTime = 0; //this encoder work with bitrate better, prevent case when result video max 2MB - encoderName = "OMX.google.h264.encoder"; + if (originalBitrate >= 15_000_000) { + encoderName = "OMX.google.h264.encoder"; + } } else if (bitrate <= 0) { bitrate = 921600; } @@ -822,7 +824,7 @@ public class MediaCodecVideoConvertor { long timeLeft = System.currentTimeMillis() - time; if (BuildVars.LOGS_ENABLED) { - FileLog.d("compression completed time=" + timeLeft + " needCompress=" + needCompress + " w=" + resultWidth + " h=" + resultHeight + " bitrate=" + bitrate); + FileLog.d("compression completed time=" + timeLeft + " needCompress=" + needCompress + " w=" + resultWidth + " h=" + resultHeight + " bitrate=" + bitrate + " file size=" + cacheFile.length()); } return error; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java index 57edfb8c9..c1b4a6560 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java @@ -14,6 +14,10 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.graphics.Typeface; import android.opengl.GLES11Ext; @@ -52,6 +56,7 @@ import org.telegram.ui.Components.FilterShaders; import org.telegram.ui.Components.Paint.Views.EditTextOutline; import org.telegram.ui.Components.Paint.Views.PaintTextOptionsView; import org.telegram.ui.Components.RLottieDrawable; +import org.telegram.ui.Components.Rect; import java.io.File; import java.io.RandomAccessFile; @@ -143,6 +148,8 @@ public class TextureRenderer { private boolean isPhoto; private boolean firstFrame = true; + Path path; + Paint xRefPaint; public TextureRenderer(MediaController.SavedFilterState savedFilterState, String image, String paint, ArrayList entities, MediaController.CropState cropState, int w, int h, int originalWidth, int originalHeight, int rotation, float fps, boolean photo) { isPhoto = photo; @@ -404,6 +411,7 @@ public class TextureRenderer { VideoEditedInfo.MediaEntity entity = mediaEntities.get(a); if (entity.ptr != 0) { RLottieDrawable.getFrame(entity.ptr, (int) entity.currentFrame, stickerBitmap, 512, 512, stickerBitmap.getRowBytes(), true); + applyRoundRadius(entity, stickerBitmap); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); entity.currentFrame += entity.framesPerDraw; @@ -420,15 +428,21 @@ public class TextureRenderer { currentFrame--; } Bitmap frameBitmap = entity.animatedFileDrawable.getBackgroundBitmap(); - if (stickerCanvas == null && stickerBitmap != null) { - stickerCanvas = new Canvas(stickerBitmap); - } - if (stickerBitmap != null && frameBitmap != null) { - stickerBitmap.eraseColor(Color.TRANSPARENT); - stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); - drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); + if (frameBitmap != null) { + if (stickerCanvas == null && stickerBitmap != null) { + stickerCanvas = new Canvas(stickerBitmap); + if (stickerBitmap.getHeight() != frameBitmap.getHeight() || stickerBitmap.getWidth() != frameBitmap.getWidth()) { + stickerCanvas.scale(stickerBitmap.getWidth() / (float) frameBitmap.getWidth(), stickerBitmap.getHeight() / (float) frameBitmap.getHeight()); + } + } + if (stickerBitmap != null) { + stickerBitmap.eraseColor(Color.TRANSPARENT); + stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); + applyRoundRadius(entity, stickerBitmap); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); + drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); + } } } else if (entity.view != null && entity.canvas != null && entity.bitmap != null) { entity.bitmap.eraseColor(Color.TRANSPARENT); @@ -438,6 +452,7 @@ public class TextureRenderer { EditTextEffects editTextEffects = (EditTextEffects) entity.view; editTextEffects.incrementFrames(currentFrame - lastFrame); entity.view.draw(entity.canvas); + applyRoundRadius(entity, entity.bitmap); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, entity.bitmap, 0); drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); @@ -453,6 +468,29 @@ public class TextureRenderer { GLES20.glFinish(); } + private void applyRoundRadius(VideoEditedInfo.MediaEntity entity, Bitmap stickerBitmap) { + if (stickerBitmap == null || entity == null || entity.roundRadius == 0) { + return; + } + if (entity.roundRadiusCanvas == null) { + entity.roundRadiusCanvas = new Canvas(stickerBitmap); + } + if (path == null) { + path = new Path(); + } + if (xRefPaint == null) { + xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + xRefPaint.setColor(0xff000000); + xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + float rad = Math.min(stickerBitmap.getWidth(), stickerBitmap.getHeight()) * entity.roundRadius; + path.rewind(); + RectF rect = new RectF(0, 0, stickerBitmap.getWidth(), stickerBitmap.getHeight()); + path.addRoundRect(rect, rad, rad, Path.Direction.CCW); + path.toggleInverseFillType(); + entity.roundRadiusCanvas.drawPath(path, xRefPaint); + } + private void drawTexture(boolean bind, int texture) { drawTexture(bind, texture, -10000, -10000, -10000, -10000, 0, false); } diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index d405d420b..b5577333a 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -69,7 +69,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 = 151; + public static final int LAYER = 152; public static class TL_stats_megagroupStats extends TLObject { public static int constructor = 0xef7ff916; @@ -395,11 +395,11 @@ public class TLRPC { public static int constructor = 0xe1bb0d61; public String email; - public TL_auth_sentCode sent_code; + public auth_SentCode sent_code; public void readParams(AbstractSerializedData stream, boolean exception) { email = stream.readString(exception); - sent_code = TL_auth_sentCode.TLdeserialize(stream, stream.readInt32(exception), exception); + sent_code = auth_SentCode.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -426,6 +426,13 @@ public class TLRPC { public boolean invite_users; public boolean pin_messages; public boolean manage_topics; + public boolean send_photos; + public boolean send_videos; + public boolean send_roundvideos; + public boolean send_audios; + public boolean send_voices; + public boolean send_docs; + public boolean send_plain; public int until_date; public static TL_chatBannedRights TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -456,11 +463,36 @@ public class TLRPC { invite_users = (flags & 32768) != 0; pin_messages = (flags & 131072) != 0; manage_topics = (flags & 262144) != 0; + send_photos = (flags & 524288) != 0; + send_videos = (flags & 1048576) != 0; + send_roundvideos = (flags & 2097152) != 0; + send_audios = (flags & 4194304) != 0; + send_voices = (flags & 8388608) != 0; + send_docs = (flags & 16777216) != 0; + send_plain = (flags & 33554432) != 0; + if (send_media) { + send_photos = true; + send_videos = true; + send_roundvideos = true; + send_audios = true; + send_voices = true; + send_docs = true; + } until_date = stream.readInt32(exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + if (send_photos && send_videos && send_roundvideos && send_audios && send_voices && send_docs) { + send_media = true; + } else { + send_media = false; + } + if (send_plain && send_media) { + send_messages = true; + } else { + send_messages = false; + } flags = view_messages ? (flags | 1) : (flags &~ 1); flags = send_messages ? (flags | 2) : (flags &~ 2); flags = send_media ? (flags | 4) : (flags &~ 4); @@ -474,6 +506,13 @@ public class TLRPC { flags = invite_users ? (flags | 32768) : (flags &~ 32768); flags = pin_messages ? (flags | 131072) : (flags &~ 131072); flags = manage_topics ? (flags | 262144) : (flags &~ 262144); + flags = send_photos ? (flags | 524288) : (flags &~ 524288); + flags = send_videos ? (flags | 1048576) : (flags &~ 1048576); + flags = send_roundvideos ? (flags | 2097152) : (flags &~ 2097152); + flags = send_audios ? (flags | 4194304) : (flags &~ 4194304); + flags = send_voices ? (flags | 8388608) : (flags &~ 8388608); + flags = send_docs ? (flags | 16777216) : (flags &~ 16777216); + flags = send_plain ? (flags | 33554432) : (flags &~ 33554432); stream.writeInt32(flags); stream.writeInt32(until_date); } @@ -1265,9 +1304,12 @@ public class TLRPC { } public static class TL_premiumSubscriptionOption extends TLObject { - public static int constructor = 0xb6f11ebe; + public static int constructor = 0x5f2d1df2; public int flags; + public boolean current; + public String transaction; + public boolean can_purchase_upgrade; public int months; public String currency; public long amount; @@ -1275,18 +1317,62 @@ public class TLRPC { public String store_product; public static TL_premiumSubscriptionOption TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_premiumSubscriptionOption.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_premiumSubscriptionOption", constructor)); - } else { - return null; - } + TL_premiumSubscriptionOption result = null; + switch (constructor) { + case 0x5f2d1df2: + result = new TL_premiumSubscriptionOption(); + break; + case 0xb6f11ebe: + result = new TL_premiumSubscriptionOption_layer151(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_premiumSubscriptionOption", constructor)); + } + if (result != null) { + result.readParams(stream, exception); } - TL_premiumSubscriptionOption result = new TL_premiumSubscriptionOption(); - result.readParams(stream, exception); return result; } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + current = (flags & 2) != 0; + if ((flags & 8) != 0) { + transaction = stream.readString(exception); + } + can_purchase_upgrade = (flags & 4) != 0; + months = stream.readInt32(exception); + currency = stream.readString(exception); + amount = stream.readInt64(exception); + bot_url = stream.readString(exception); + if ((flags & 1) != 0) { + store_product = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = current ? (flags | 2) : (flags &~ 2); + flags = can_purchase_upgrade ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + if ((flags & 8) != 0) { + stream.writeString(transaction); + } + stream.writeInt32(months); + stream.writeString(currency); + stream.writeInt64(amount); + stream.writeString(bot_url); + if ((flags & 1) != 0) { + stream.writeString(store_product); + } + } + } + + public static class TL_premiumSubscriptionOption_layer151 extends TL_premiumSubscriptionOption { + public static int constructor = 0xb6f11ebe; + + public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); months = stream.readInt32(exception); @@ -2689,7 +2775,10 @@ public class TLRPC { case 0x44747e9a: result = new TL_auth_authorizationSignUpRequired(); break; - case 0x33fb7bb8: + case 0x33fb7bb8://TODO old constructor need remove + result = new TL_auth_authorization(); + break; + case 0x2ea2c0d4: result = new TL_auth_authorization(); break; } @@ -2726,12 +2815,13 @@ public class TLRPC { } public static class TL_auth_authorization extends auth_Authorization { - public static int constructor = 0x33fb7bb8; + public static int constructor = 0x2ea2c0d4; public int flags; public boolean setup_password_required; public int otherwise_relogin_days; public int tmp_sessions; + public byte[] future_auth_token; public User user; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -2743,6 +2833,9 @@ public class TLRPC { if ((flags & 1) != 0) { tmp_sessions = stream.readInt32(exception); } + if ((flags & 4) != 0) { + future_auth_token = stream.readByteArray(exception); + } user = User.TLdeserialize(stream, stream.readInt32(exception), exception); } @@ -2756,6 +2849,9 @@ public class TLRPC { if ((flags & 1) != 0) { stream.writeInt32(tmp_sessions); } + if ((flags & 4) != 0) { + stream.writeByteArray(future_auth_token); + } user.serializeToStream(stream); } } @@ -6706,6 +6802,10 @@ public class TLRPC { public boolean google_signin_allowed; public String email_pattern; public int next_phone_login_date; + public byte[] nonce; + public String receipt; + public int push_timeout; + public boolean verifiedFirebase; //custom public static auth_SentCodeType TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { auth_SentCodeType result = null; @@ -6734,6 +6834,9 @@ public class TLRPC { case 0xd9565c39: result = new TL_auth_sentCodeTypeFragmentSms(); break; + case 0xe57b1432: + result = new TL_auth_sentCodeTypeFirebaseSms(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in auth_SentCodeType", constructor)); @@ -6877,6 +6980,40 @@ public class TLRPC { } } + public static class TL_auth_sentCodeTypeFirebaseSms extends auth_SentCodeType { + public static int constructor = 0xe57b1432; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + nonce = stream.readByteArray(exception); + } + if ((flags & 2) != 0) { + receipt = stream.readString(exception); + } + if ((flags & 2) != 0) { + push_timeout = stream.readInt32(exception); + } + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeByteArray(nonce); + } + if ((flags & 2) != 0) { + stream.writeString(receipt); + } + if ((flags & 2) != 0) { + stream.writeInt32(push_timeout); + } + stream.writeInt32(length); + } + } + public static abstract class messages_StickerSetInstallResult extends TLObject { public ArrayList sets = new ArrayList<>(); @@ -8605,27 +8742,50 @@ public class TLRPC { } } - public static class TL_auth_sentCode extends TLObject { - public static int constructor = 0x5e002502; + public static abstract class auth_SentCode extends TLObject { public int flags; public auth_SentCodeType type; public String phone_code_hash; public auth_CodeType next_type; public int timeout; + public auth_Authorization authorization; - public static TL_auth_sentCode TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_auth_sentCode.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_auth_sentCode", constructor)); - } else { - return null; - } + public static auth_SentCode TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + auth_SentCode result = null; + switch (constructor) { + case 0x2390fe44: + result = new TL_auth_sentCodeSuccess(); + break; + case 0x5e002502: + result = new TL_auth_sentCode(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in auth_SentCode", constructor)); + } + if (result != null) { + result.readParams(stream, exception); } - TL_auth_sentCode result = new TL_auth_sentCode(); - result.readParams(stream, exception); return result; } + } + + public static class TL_auth_sentCodeSuccess extends auth_SentCode { + public static int constructor = 0x2390fe44; + + public void readParams(AbstractSerializedData stream, boolean exception) { + authorization = auth_Authorization.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + authorization.serializeToStream(stream); + } + } + + public static class TL_auth_sentCode extends auth_SentCode { + public static int constructor = 0x5e002502; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -12090,6 +12250,7 @@ public class TLRPC { public boolean can_delete_channel; public boolean antispam; public boolean participants_hidden; + public boolean translations_disabled; public ChatReactions available_reactions; public long inviterId; //custom @@ -14565,6 +14726,7 @@ public class TLRPC { can_delete_channel = (flags2 & 1) != 0; antispam = (flags2 & 2) != 0; participants_hidden = (flags2 & 4) != 0; + translations_disabled = (flags2 & 8) != 0; id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -14702,6 +14864,7 @@ public class TLRPC { 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); stream.writeInt32(flags2); stream.writeInt64(id); stream.writeString(about); @@ -17674,14 +17837,17 @@ public class TLRPC { } public static class TL_codeSettings extends TLObject { - public static int constructor = 0x8a6469c2; + public static int constructor = 0xad253d78; public int flags; public boolean allow_flashcall; public boolean current_number; public boolean allow_app_hash; public boolean allow_missed_call; + public boolean allow_firebase; public ArrayList logout_tokens = new ArrayList<>(); + public String token; + public boolean app_sandbox; public static TL_codeSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_codeSettings.constructor != constructor) { @@ -17702,6 +17868,7 @@ public class TLRPC { current_number = (flags & 2) != 0; allow_app_hash = (flags & 16) != 0; allow_missed_call = (flags & 32) != 0; + allow_firebase = (flags & 128) != 0; if ((flags & 64) != 0) { int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -17712,9 +17879,17 @@ public class TLRPC { } int count = stream.readInt32(exception); for (int a = 0; a < count; a++) { - logout_tokens.add(stream.readByteArray(exception)); + byte[] object = stream.readByteArray(exception); + if (object == null) { + return; + } + logout_tokens.add(object); } } + if ((flags & 256) != 0) { + token = stream.readString(exception); + } + app_sandbox = (flags & 256) != 0; } public void serializeToStream(AbstractSerializedData stream) { @@ -17723,6 +17898,8 @@ public class TLRPC { flags = current_number ? (flags | 2) : (flags &~ 2); flags = allow_app_hash ? (flags | 16) : (flags &~ 16); flags = allow_missed_call ? (flags | 32) : (flags &~ 32); + flags = allow_firebase ? (flags | 128) : (flags &~ 128); + flags = app_sandbox ? (flags | 256) : (flags &~ 256); stream.writeInt32(flags); if ((flags & 64) != 0) { stream.writeInt32(0x1cb5c415); @@ -17732,6 +17909,9 @@ public class TLRPC { stream.writeByteArray(logout_tokens.get(a)); } } + if ((flags & 256) != 0) { + stream.writeString(token); + } } } @@ -18652,6 +18832,9 @@ public class TLRPC { case 0x13767230: result = new TL_keyboardButtonWebView(); break; + case 0xd0b468c: + result = new TL_keyboardButtonRequestPeer(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in KeyboardButton", constructor)); @@ -18911,6 +19094,73 @@ public class TLRPC { } } + public static class TL_videoSizeEmojiMarkup extends VideoSize { + public static int constructor = 0xf85c413c; + + public long emoji_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + emoji_id = stream.readInt64(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++) { + background_colors.add(stream.readInt32(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(emoji_id); + stream.writeInt32(0x1cb5c415); + int count = background_colors.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(background_colors.get(a)); + } + } + } + + public static class TL_videoSizeStickerMarkup extends VideoSize { + public static int constructor = 0xda082fe; + + public InputStickerSet stickerset; + public long sticker_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + stickerset = InputStickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + sticker_id = stream.readInt64(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++) { + background_colors.add(stream.readInt32(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stickerset.serializeToStream(stream); + stream.writeInt64(sticker_id); + stream.writeInt32(0x1cb5c415); + int count = background_colors.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(background_colors.get(a)); + } + } + } + public static abstract class VideoSize extends TLObject { public int flags; @@ -18920,6 +19170,7 @@ public class TLRPC { public int h; public int size; public double video_start_ts; + public ArrayList background_colors = new ArrayList<>(); public static VideoSize TLdeserialize(long photo_id, long document_id, AbstractSerializedData stream, int constructor, boolean exception) { VideoSize result = null; @@ -18933,6 +19184,12 @@ public class TLRPC { case 0xde33b094: result = new TL_videoSize(); break; + case 0xda082fe: + result = new TL_videoSizeStickerMarkup(); + break; + case 0xf85c413c: + result = new TL_videoSizeEmojiMarkup(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in VideoSize", constructor)); @@ -24148,6 +24405,9 @@ public class TLRPC { case 0xaba0f5c6: result = new TL_messageActionGiftPremium(); break; + case 0xfe77345d: + result = new TL_messageActionRequestedPeer(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in MessageAction", constructor)); @@ -40582,6 +40842,123 @@ public class TLRPC { } } + public static abstract class messages_EmojiGroups extends TLObject { + + public static messages_EmojiGroups TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_EmojiGroups result = null; + switch (constructor) { + case 0x6fb4ad87: + result = new TL_messages_emojiGroupsNotModified(); + break; + case 0x881fb94b: + result = new TL_messages_emojiGroups(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_EmojiGroups", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_emojiGroupsNotModified extends messages_EmojiGroups { + public static int constructor = 0x6fb4ad87; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_emojiGroups extends messages_EmojiGroups { + public static int constructor = 0x881fb94b; + + public int hash; + public ArrayList groups = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt32(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++) { + TL_emojiGroup object = TL_emojiGroup.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + groups.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + stream.writeInt32(0x1cb5c415); + int count = groups.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + groups.get(a).serializeToStream(stream); + } + } + } + + public static class TL_emojiGroup extends TLObject { + public static int constructor = 0x7a9abda9; + + public String title; + public long icon_emoji_id; + public ArrayList emoticons = new ArrayList<>(); + + public static TL_emojiGroup TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_emojiGroup.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_emojiGroup", constructor)); + } else { + return null; + } + } + TL_emojiGroup result = new TL_emojiGroup(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + icon_emoji_id = stream.readInt64(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++) { + emoticons.add(stream.readString(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + stream.writeInt64(icon_emoji_id); + stream.writeInt32(0x1cb5c415); + int count = emoticons.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(emoticons.get(a)); + } + } + } + public static class TL_emojiKeyword extends EmojiKeyword { public static int constructor = 0xd5b3b9f9; @@ -44466,49 +44843,50 @@ public class TLRPC { } } - public static abstract class messages_TranslatedText extends TLObject { + public static class TL_messages_translateResult extends TLObject { + public static int constructor = 0x33db32f8; - public static messages_TranslatedText TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - messages_TranslatedText result = null; - switch (constructor) { - case 0x67ca4737: - result = new TL_messages_translateNoResult(); - break; - case 0xa214f7d0: - result = new TL_messages_translateResultText(); - break; - } - if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in messages_TranslatedText", constructor)); - } - if (result != null) { - result.readParams(stream, exception); + public ArrayList result = new ArrayList<>(); + + public static TL_messages_translateResult TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_translateResult.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_translateResult", constructor)); + } else { + return null; + } } + TL_messages_translateResult result = new TL_messages_translateResult(); + result.readParams(stream, exception); return result; } - } - - public static class TL_messages_translateNoResult extends messages_TranslatedText { - public static int constructor = 0x67ca4737; - - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - } - } - - public static class TL_messages_translateResultText extends messages_TranslatedText { - public static int constructor = 0xa214f7d0; - - public String text; public void readParams(AbstractSerializedData stream, boolean exception) { - text = stream.readString(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++) { + TL_textWithEntities object = TL_textWithEntities.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + result.add(object); + } } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeString(text); + stream.writeInt32(0x1cb5c415); + int count = result.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + result.get(a).serializeToStream(stream); + } } } @@ -46110,6 +46488,56 @@ public class TLRPC { } } + public static class TL_textWithEntities extends TLObject { + public static int constructor = 0x751f3146; + + public String text; + public ArrayList entities = new ArrayList<>(); + + public static TL_textWithEntities TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_textWithEntities.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_textWithEntities", constructor)); + } else { + return null; + } + } + TL_textWithEntities result = new TL_textWithEntities(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(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++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + } + public static class TL_account_webAuthorizations extends TLObject { public static int constructor = 0xed56c9fc; @@ -46346,6 +46774,7 @@ public class TLRPC { public boolean has_scheduled; public boolean video_calls_available; public boolean voice_messages_forbidden; + public boolean translations_disabled; public User user; public String about; public TL_contacts_link_layer101 link; @@ -46422,6 +46851,7 @@ public class TLRPC { has_scheduled = (flags & 4096) != 0; video_calls_available = (flags & 8192) != 0; voice_messages_forbidden = (flags & 1048576) != 0; + translations_disabled = (flags & 8388608) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -46490,6 +46920,7 @@ public class TLRPC { flags = has_scheduled ? (flags | 4096) : (flags &~ 4096); flags = video_calls_available ? (flags | 8192) : (flags &~ 8192); flags = voice_messages_forbidden ? (flags | 1048576) : (flags &~ 1048576); + flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -48014,7 +48445,7 @@ public class TLRPC { case 0x1ca48f57: result = new TL_inputChatPhotoEmpty(); break; - case 0xc642724e: + case 0xbdcdaec0: result = new TL_inputChatUploadedPhoto(); break; } @@ -48053,12 +48484,13 @@ public class TLRPC { } public static class TL_inputChatUploadedPhoto extends InputChatPhoto { - public static int constructor = 0xc642724e; + public static int constructor = 0xbdcdaec0; public int flags; public InputFile file; public InputFile video; public double video_start_ts; + public VideoSize video_emoji_markup; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -48071,6 +48503,9 @@ public class TLRPC { if ((flags & 4) != 0) { video_start_ts = stream.readDouble(exception); } + if ((flags & 8) != 0) { + video_emoji_markup = VideoSize.TLdeserialize(0, 0, stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -48085,6 +48520,9 @@ public class TLRPC { if ((flags & 4) != 0) { stream.writeDouble(video_start_ts); } + if ((flags & 8) != 0) { + video_emoji_markup.serializeToStream(stream); + } } } @@ -49991,6 +50429,87 @@ public class TLRPC { } } + public static class TL_messages_getEmojiGroups extends TLObject { + public static int constructor = 0x7488ce5b; + + public int hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_EmojiGroups.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_messages_getEmojiProfilePhotoGroups extends TLObject { + public static int constructor = 0x21a548f3; + + public int hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_EmojiGroups.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_messages_getEmojiStatusGroups extends TLObject { + public static int constructor = 0x2ecd56cd; + + public int hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_EmojiGroups.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_messages_searchCustomEmoji extends TLObject { + public static int constructor = 0x2c11c0d7; + + public String emoticon; + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return EmojiList.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(emoticon); + stream.writeInt64(hash); + } + } + + public static class TL_messages_togglePeerTranslations extends TLObject { + public static int constructor = 0xe47cb579; + + public int flags; + public boolean disabled; + public InputPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = disabled ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + peer.serializeToStream(stream); + } + } + public static class TL_auth_sendCode extends TLObject { public static int constructor = 0xa677244f; @@ -50206,6 +50725,33 @@ public class TLRPC { } } + public static class TL_auth_requestFirebaseSms extends TLObject { + public static int constructor = 0x89464b50; + + public int flags; + public String phone_number; + public String phone_code_hash; + public String safety_net_token; + public String ios_push_secret; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(phone_number); + stream.writeString(phone_code_hash); + if ((flags & 1) != 0) { + stream.writeString(safety_net_token); + } + if ((flags & 2) != 0) { + stream.writeString(ios_push_secret); + } + } + } + public static class TL_account_registerDevice extends TLObject { public static int constructor = 0xec86017a; @@ -51892,13 +52438,14 @@ public class TLRPC { } public static class TL_photos_uploadProfilePhoto extends TLObject { - public static int constructor = 0x89f30f69; + public static int constructor = 0x93c9a51; public int flags; public boolean fallback; public InputFile file; public InputFile video; public double video_start_ts; + public VideoSize video_emoji_markup; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return TL_photos_photo.TLdeserialize(stream, constructor, exception); @@ -51917,6 +52464,9 @@ public class TLRPC { if ((flags & 4) != 0) { stream.writeDouble(video_start_ts); } + if ((flags & 16) != 0) { + video_emoji_markup.serializeToStream(stream); + } } } @@ -55009,17 +55559,16 @@ public class TLRPC { } public static class TL_messages_translateText extends TLObject { - public static int constructor = 0x24ce6dee; + public static int constructor = 0x63183030; public int flags; public InputPeer peer; - public int msg_id; - public String text; - public String from_lang; + public ArrayList id = new ArrayList<>(); + public ArrayList text = new ArrayList<>(); public String to_lang; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return messages_TranslatedText.TLdeserialize(stream, constructor, exception); + return TL_messages_translateResult.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -55029,13 +55578,20 @@ public class TLRPC { peer.serializeToStream(stream); } if ((flags & 1) != 0) { - stream.writeInt32(msg_id); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } } if ((flags & 2) != 0) { - stream.writeString(text); - } - if ((flags & 4) != 0) { - stream.writeString(from_lang); + stream.writeInt32(0x1cb5c415); + final int count = text.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + text.get(a).serializeToStream(stream); + } } stream.writeString(to_lang); } @@ -56396,16 +56952,18 @@ public class TLRPC { } public static class TL_channels_createChannel extends TLObject { - public static int constructor = 0x3d5fb10f; + public static int constructor = 0x91006707; public int flags; public boolean broadcast; public boolean megagroup; public boolean for_import; + public boolean forum; public String title; public String about; public InputGeoPoint geo_point; public String address; + public int ttl_period; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -56416,6 +56974,7 @@ public class TLRPC { flags = broadcast ? (flags | 1) : (flags &~ 1); flags = megagroup ? (flags | 2) : (flags &~ 2); flags = for_import ? (flags | 8) : (flags &~ 8); + flags = forum ? (flags | 32) : (flags &~ 32); stream.writeInt32(flags); stream.writeString(title); stream.writeString(about); @@ -56425,6 +56984,9 @@ public class TLRPC { if ((flags & 4) != 0) { stream.writeString(address); } + if ((flags & 16) != 0) { + stream.writeInt32(ttl_period); + } } } @@ -57876,7 +58438,7 @@ public class TLRPC { case 0xa6751e66: result = new TL_inputStorePaymentPremiumSubscription(); break; - case 0x44618a7d: + case 0x616f7fe8: result = new TL_inputStorePaymentGiftPremium(); break; } @@ -57895,15 +58457,18 @@ public class TLRPC { public int flags; public boolean restore; + public boolean upgrade; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); restore = (flags & 1) != 0; + upgrade = (flags & 2) != 0; } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = restore ? (flags | 1) : (flags &~ 1); + flags = upgrade ? (flags | 2) : (flags &~ 2); stream.writeInt32(flags); } } @@ -59068,6 +59633,9 @@ public class TLRPC { public boolean voiceTranscriptionForce; //custom public long voiceTranscriptionId; //custom public boolean premiumEffectWasPlayed; //custom + public String originalLanguage; //custom + public String translatedToLanguage; //custom + public TL_textWithEntities translatedText; // custom public static Message TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { Message result = null; @@ -59175,7 +59743,11 @@ public class TLRPC { if (result != null) { result.readParams(stream, exception); if (result.from_id == null) { - result.from_id = result.peer_id; + if (result.id < 0 && result.random_id == 0) { + result.from_id = new TL_peerUser(); + } else { + result.from_id = result.peer_id; + } } } return result; @@ -63336,6 +63908,170 @@ public class TLRPC { } } + public static class RequestPeerType extends TLObject { + + public int flags; + + public Boolean creator; + public TL_chatAdminRights user_admin_rights; + public TL_chatAdminRights bot_admin_rights; + public Boolean has_username; + public Boolean forum; + public Boolean bot_participant; + + public static RequestPeerType TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + RequestPeerType result = null; + switch (constructor) { + case TL_requestPeerTypeUser.constructor: + result = new TL_requestPeerTypeUser(); + break; + case TL_requestPeerTypeChat.constructor: + result = new TL_requestPeerTypeChat(); + break; + case TL_requestPeerTypeBroadcast.constructor: + result = new TL_requestPeerTypeBroadcast(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in RequestPeerType", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_requestPeerTypeUser extends RequestPeerType { + public static final int constructor = 0x5f3b8a00; + + public Boolean bot; + public Boolean premium; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + bot = stream.readBool(exception); + } + if ((flags & 2) != 0) { + premium = stream.readBool(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = bot != null ? (flags | 1) : (flags &~ 1); + flags = premium != null ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + if (bot != null) { + stream.writeBool(bot); + } + if (premium != null) { + stream.writeBool(premium); + } + } + } + + public static class TL_requestPeerTypeChat extends RequestPeerType { + public static final int constructor = 0xc9f06e1b; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + bot_participant = (flags & 32) != 0; + creator = (flags & 1) != 0; + if ((flags & 8) != 0) { + has_username = stream.readBool(exception); + } + if ((flags & 16) != 0) { + forum = stream.readBool(exception); + } + if ((flags & 2) != 0) { + user_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + bot_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator != null && creator ? (flags | 1) : (flags &~ 1); + flags = user_admin_rights != null ? (flags | 2) : (flags &~ 2); + flags = bot_admin_rights != null ? (flags | 4) : (flags &~ 4); + flags = has_username != null ? (flags | 8) : (flags &~ 8); + flags = forum != null ? (flags | 16) : (flags &~ 16); + flags = bot_participant != null && bot_participant ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + if (has_username != null) { + stream.writeBool(has_username); + } + if (forum != null) { + stream.writeBool(forum); + } + if (user_admin_rights != null) { + user_admin_rights.serializeToStream(stream); + } + if (bot_admin_rights != null) { + bot_admin_rights.serializeToStream(stream); + } + } + } + + public static class TL_requestPeerTypeBroadcast extends RequestPeerType { + public static final int constructor = 0x339bef6c; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + if ((flags & 8) != 0) { + has_username = stream.readBool(exception); + } + if ((flags & 2) != 0) { + user_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + bot_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator != null && creator ? (flags | 1) : (flags &~ 1); + flags = user_admin_rights != null ? (flags | 2) : (flags &~ 2); + flags = bot_admin_rights != null ? (flags | 4) : (flags &~ 4); + flags = has_username != null ? (flags | 8) : (flags &~ 8); + stream.writeInt32(flags); + if (has_username != null) { + stream.writeBool(has_username); + } + if (user_admin_rights != null) { + user_admin_rights.serializeToStream(stream); + } + if (bot_admin_rights != null) { + bot_admin_rights.serializeToStream(stream); + } + } + } + + public static class TL_keyboardButtonRequestPeer extends KeyboardButton { + public static int constructor = 0xd0b468c; + + public RequestPeerType peer_type; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + button_id = stream.readInt32(exception); + peer_type = RequestPeerType.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeInt32(button_id); + peer_type.serializeToStream(stream); + } + } + public static class TL_messages_getAttachMenuBots extends TLObject { public static int constructor = 0x16fcc2cb; @@ -65447,6 +66183,28 @@ public class TLRPC { stream.writeInt32(period); } } + + public static class TL_messages_sendBotRequestedPeer extends TLObject { + public static int constructor = 0xfe38d01b; + + public InputPeer peer; + public int msg_id; + public int button_id; + public InputPeer requested_peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(msg_id); + stream.writeInt32(button_id); + requested_peer.serializeToStream(stream); + } + } + public static class TL_contacts_exportContactToken extends TLObject { public static int constructor = 0xf8654027; @@ -65500,8 +66258,26 @@ public class TLRPC { } } + public static class TL_messageActionRequestedPeer extends MessageAction { + public static int constructor = 0xfe77345d; + + public int button_id; + public TLRPC.Peer peer; + + public void readParams(AbstractSerializedData stream, boolean exception) { + button_id = stream.readInt32(exception); + peer = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(button_id); + peer.serializeToStream(stream); + } + } + public static class TL_photos_uploadContactProfilePhoto extends TLObject { - public static int constructor = 0xb91a83bf; + public static int constructor = 0xe14c4a71; public int flags; public boolean suggest; @@ -65510,6 +66286,7 @@ public class TLRPC { public InputFile file; public InputFile video; public double video_start_ts; + public VideoSize video_emoji_markup; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return TL_photos_photo.TLdeserialize(stream, constructor, exception); @@ -65530,6 +66307,103 @@ public class TLRPC { if ((flags & 4) != 0) { stream.writeDouble(video_start_ts); } + if ((flags & 32) != 0) { + video_emoji_markup.serializeToStream(stream); + } + } + } + + public static abstract class EmojiList extends TLObject { + + public static EmojiList TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + EmojiList result = null; + switch (constructor) { + case 0x7a1e11d1: + result = new TL_emojiList(); + break; + case 0x481eadfa: + result = new TL_emojiListNotModified(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in EmojiList", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_emojiList extends EmojiList { + public static int constructor = 0x7a1e11d1; + + public long hash; + public ArrayList document_id = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt64(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++) { + document_id.add(stream.readInt64(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + stream.writeInt32(0x1cb5c415); + int count = document_id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(document_id.get(a)); + } + } + } + + public static class TL_emojiListNotModified extends EmojiList { + public static int constructor = 0x481eadfa; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_account_getDefaultProfilePhotoEmojis extends TLObject { + public static int constructor = 0xe2750328; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return EmojiList.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + + public static class TL_account_getDefaultGroupPhotoEmojis extends TLObject { + public static int constructor = 0x915860ae; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return EmojiList.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); } } 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 518a31c57..b4ff4b9db 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -391,14 +391,6 @@ public class ActionBarMenuItem extends FrameLayout { popupWindow.dismiss(); } }); - - if (popupLayout.getSwipeBack() != null) { - popupLayout.getSwipeBack().setOnClickListener(view -> { - if (popupWindow != null) { - popupWindow.dismiss(); - } - }); - } } public void removeAllSubItems() { 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 043acef1b..03f13920b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java @@ -43,14 +43,18 @@ public class ActionBarMenuSubItem extends FrameLayout { } public ActionBarMenuSubItem(Context context, boolean needCheck, boolean top, boolean bottom) { - this(context, needCheck, top, bottom, null); + this(context, needCheck ? 1 : 0, top, bottom, null); } public ActionBarMenuSubItem(Context context, boolean top, boolean bottom, Theme.ResourcesProvider resourcesProvider) { - this(context, false, top, bottom, resourcesProvider); + this(context, 0, top, bottom, resourcesProvider); } public ActionBarMenuSubItem(Context context, boolean needCheck, boolean top, boolean bottom, Theme.ResourcesProvider resourcesProvider) { + this(context, needCheck ? 1 : 0, top, bottom, resourcesProvider); + } + + public ActionBarMenuSubItem(Context context, int needCheck, boolean top, boolean bottom, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; @@ -78,12 +82,17 @@ public class ActionBarMenuSubItem extends FrameLayout { textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL)); - if (needCheck) { + if (needCheck > 0) { checkView = new CheckBox2(context, 26, resourcesProvider); checkView.setDrawUnchecked(false); checkView.setColor(null, null, Theme.key_radioBackgroundChecked); checkView.setDrawBackgroundAsArc(-1); - addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT))); + if (needCheck == 1) { + addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT))); + } else { + addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT))); + textView.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(34) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(34), 0); + } } } @@ -206,7 +215,7 @@ public class ActionBarMenuSubItem extends FrameLayout { subtextView.setSingleLine(true); subtextView.setGravity(Gravity.LEFT); subtextView.setEllipsize(TextUtils.TruncateAt.END); - subtextView.setTextColor(0xff7C8286); + subtextView.setTextColor(getThemedColor(Theme.key_groupcreate_sectionText)); subtextView.setVisibility(GONE); subtextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); subtextView.setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(43), 0, LocaleController.isRTL ? AndroidUtilities.dp(43) : 0, 0); 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 04ec758a2..5d6066159 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java @@ -668,6 +668,10 @@ public class ActionBarPopupWindow extends PopupWindow { } private void init() { + View contentView = getContentView(); + if (contentView instanceof ActionBarPopupWindowLayout && ((ActionBarPopupWindowLayout) contentView).getSwipeBack() != null) { + ((ActionBarPopupWindowLayout) contentView).getSwipeBack().setOnClickListener(e -> dismiss()); + } if (superListenerField != null) { try { mSuperScrollListener = (ViewTreeObserver.OnScrollChangedListener) superListenerField.get(this); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java index 28b057374..d274dfbc4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -94,7 +94,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati private BitmapDrawable[] shadow = new BitmapDrawable[2]; private boolean[] shadowVisibility = new boolean[2]; private AnimatorSet[] shadowAnimation = new AnimatorSet[2]; - private int customViewOffset = 20; + private int customViewOffset = 12; private String dialogButtonColorKey = Theme.key_dialogButton; @@ -277,7 +277,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati if (progressStyle != ALERT_TYPE_SPINNER || blurredBackground) { shadowDrawable = context.getResources().getDrawable(R.drawable.popup_fixed_alert3).mutate(); backgroundColor = getThemedColor(Theme.key_dialogBackground); - blurOpacity = progressStyle == ALERT_TYPE_SPINNER ? 0.55f : (AndroidUtilities.computePerceivedBrightness(backgroundColor) < 0.721f ? 0.80f : 0.92f); + blurOpacity = progressStyle == ALERT_TYPE_SPINNER ? 0.55f : (AndroidUtilities.computePerceivedBrightness(backgroundColor) < 0.721f ? 0.80f : 0.97f); shadowDrawable.setColorFilter(new PorterDuffColorFilter(backgroundColor, PorterDuff.Mode.MULTIPLY)); shadowDrawable.getPadding(backgroundPaddings); } @@ -380,7 +380,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati availableHeight -= topImageView.getMeasuredHeight(); } if (topView != null) { - int w = width - AndroidUtilities.dp(16); + int w = width; int h; if (aspectRatio == 0) { float scale = w / 936.0f; @@ -781,10 +781,6 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati } if (!TextUtils.isEmpty(message)) { messageTextView.setText(message); - if (customView != null) { - ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) messageTextView.getLayoutParams(); - params.topMargin = AndroidUtilities.dp(16); - } messageTextView.setVisibility(View.VISIBLE); } else { messageTextView.setVisibility(View.GONE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java index f8c8507b1..dfb167c2b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -76,6 +76,7 @@ public class BottomSheet extends Dialog { public boolean drawNavigationBar; public boolean drawDoubleNavigationBar; public boolean scrollNavBar; + protected boolean waitingKeyboard; protected boolean useSmoothKeyboard; @@ -167,13 +168,14 @@ public class BottomSheet extends Dialog { private OnDismissListener onHideListener; protected Theme.ResourcesProvider resourcesProvider; protected boolean isPortrait; + public boolean pauseAllHeavyOperations = true; public void setDisableScroll(boolean b) { disableScroll = b; } private ValueAnimator keyboardContentAnimator; - protected boolean smoothKeyboardAnimationEnabled; + public boolean smoothKeyboardAnimationEnabled; private boolean openNoDelay; private float hideSystemVerticalInsetsProgress; @@ -564,11 +566,18 @@ public class BottomSheet extends Dialog { child.layout(childLeft, childTop, childLeft + width, childTop + height); } } - if (layoutCount == 0 && startAnimationRunnable != null) { + if (layoutCount == 0 && startAnimationRunnable != null && !waitingKeyboard) { AndroidUtilities.cancelRunOnUIThread(startAnimationRunnable); startAnimationRunnable.run(); startAnimationRunnable = null; } + if (waitingKeyboard && keyboardVisible) { + if (startAnimationRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(startAnimationRunnable); + startAnimationRunnable.run(); + } + waitingKeyboard = false; + } keyboardChanged = false; } @@ -1206,6 +1215,10 @@ public class BottomSheet extends Dialog { if (Build.VERSION.SDK_INT >= 18) { layoutCount = 2; containerView.setTranslationY((Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight * (1f - hideSystemVerticalInsetsProgress) : 0) + containerView.getMeasuredHeight() + (scrollNavBar ? getBottomInset() : 0)); + long delay = openNoDelay ? 0 : 150; + if (waitingKeyboard) { + delay = 500; + } AndroidUtilities.runOnUIThread(startAnimationRunnable = new Runnable() { @Override public void run() { @@ -1215,7 +1228,7 @@ public class BottomSheet extends Dialog { startAnimationRunnable = null; startOpenAnimation(); } - }, openNoDelay ? 0 : 150); + }, delay); } else { startOpenAnimation(); } @@ -1345,7 +1358,7 @@ public class BottomSheet extends Dialog { navigationBarAnimation ); currentSheetAnimation.setDuration(400); - currentSheetAnimation.setStartDelay(20); + currentSheetAnimation.setStartDelay(waitingKeyboard ? 0 : 20); currentSheetAnimation.setInterpolator(openInterpolator); currentSheetAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -1366,7 +1379,9 @@ public class BottomSheet extends Dialog { getWindow().setAttributes(params); } } - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); + if (pauseAllHeavyOperations) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); + } } @Override @@ -1377,7 +1392,9 @@ public class BottomSheet extends Dialog { } } }); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + if (pauseAllHeavyOperations) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + } currentSheetAnimation.start(); } } 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 52b57bb6e..2e7555f69 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -95,6 +95,7 @@ public class SimpleTextView extends View implements Drawable.Callback { private boolean rightDrawableOutside; private boolean ellipsizeByGradient, ellipsizeByGradientLeft; + private Boolean forceEllipsizeByGradientLeft; private int ellipsizeByGradientWidthDp = 16; private int paddingRight; @@ -192,15 +193,24 @@ public class SimpleTextView extends View implements Drawable.Callback { } public void setEllipsizeByGradient(boolean value) { + setEllipsizeByGradient(value, null); + } + + public void setEllipsizeByGradient(int value) { + setEllipsizeByGradient(value, null); + } + + public void setEllipsizeByGradient(boolean value, Boolean forceLeft) { if (scrollNonFitText == value) { return; } ellipsizeByGradient = value; + this.forceEllipsizeByGradientLeft = forceLeft; updateFadePaints(); } - public void setEllipsizeByGradient(int value) { - setEllipsizeByGradient(true); + public void setEllipsizeByGradient(int value, Boolean forceLeft) { + setEllipsizeByGradient(true, forceLeft); ellipsizeByGradientWidthDp = value; updateFadePaints(); } @@ -219,7 +229,12 @@ public class SimpleTextView extends View implements Drawable.Callback { fadePaintBack.setShader(new LinearGradient(0, 0, AndroidUtilities.dp(6), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); fadePaintBack.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } - boolean ellipsizeLeft = getAlignment() == Layout.Alignment.ALIGN_NORMAL && LocaleController.isRTL || getAlignment() == Layout.Alignment.ALIGN_OPPOSITE && !LocaleController.isRTL; + boolean ellipsizeLeft; + if (forceEllipsizeByGradientLeft != null) { + ellipsizeLeft = forceEllipsizeByGradientLeft; + } else { + ellipsizeLeft = getAlignment() == Layout.Alignment.ALIGN_NORMAL && LocaleController.isRTL || getAlignment() == Layout.Alignment.ALIGN_OPPOSITE && !LocaleController.isRTL; + } if ((fadeEllpsizePaint == null || fadeEllpsizePaintWidth != AndroidUtilities.dp(ellipsizeByGradientWidthDp) || ellipsizeByGradientLeft != ellipsizeLeft) && ellipsizeByGradient) { if (fadeEllpsizePaint == null) { fadeEllpsizePaint = new Paint(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java index d47e462d5..6c1ad0973 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -9,6 +9,7 @@ package org.telegram.ui.ActionBar; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -143,6 +144,11 @@ public class Theme { public static final int MSG_OUT_COLOR_BLACK = 0xff212121; public static final int MSG_OUT_COLOR_WHITE = 0xffffffff; + public static final int default_shadow_color = ColorUtils.setAlphaComponent(Color.BLACK, 27); + + public static void applyDefaultShadow(Paint paint) { + paint.setShadowLayer(dpf2(1), 0, dpf2(0.33f), default_shadow_color); + } public static class BackgroundDrawableSettings { @@ -4007,6 +4013,17 @@ public class Theme { public final static String key_statisticChartLine_cyan = "statisticChartLine_cyan"; public final static String key_statisticChartLineEmpty = "statisticChartLineEmpty"; + public final static String key_color_lightblue = "color_lightblue"; + public final static String key_color_blue = "color_blue"; + public final static String key_color_green = "color_green"; + public final static String key_color_lightgreen = "color_lightgreen"; + public final static String key_color_red = "color_red"; + public final static String key_color_orange = "color_orange"; + public final static String key_color_yellow = "color_yellow"; + public final static String key_color_purple = "color_purple"; + public final static String key_color_cyan = "color_cyan"; + public final static String[] keys_colors = { key_color_lightblue, key_color_blue, key_color_green, key_color_lightgreen, key_color_red, key_color_orange, key_color_yellow, key_color_purple, key_color_cyan }; + public static final String key_chat_outReactionButtonBackground = "chat_outReactionButtonBackground"; public static final String key_chat_inReactionButtonBackground = "chat_inReactionButtonBackground"; public static final String key_chat_outReactionButtonText = "chat_outReactionButtonText"; @@ -4848,6 +4865,16 @@ public class Theme { defaultColors.put(key_statisticChartLineEmpty, 0xFFEEEEEE); defaultColors.put(key_actionBarTipBackground, 0xFF446F94); + defaultColors.put(key_color_blue, 0xff327FE5); + defaultColors.put(key_color_green, 0xff61C752); + defaultColors.put(key_color_red, 0xffE05356); + defaultColors.put(key_color_yellow, 0xffEBA52D); + defaultColors.put(key_color_lightblue, 0xff58A8ED); + defaultColors.put(key_color_lightgreen, 0xff8FCF39); + defaultColors.put(key_color_orange, 0xffF28C39); + defaultColors.put(key_color_purple, 0xff9F79E8); + defaultColors.put(key_color_cyan, 0xff40D0CA); + defaultColors.put(key_voipgroup_checkMenu, 0xff6BB6F9); defaultColors.put(key_voipgroup_muteButton, 0xff77E55C); defaultColors.put(key_voipgroup_muteButton2, 0xff7DDCAA); @@ -5101,9 +5128,19 @@ public class Theme { fallbackKeys.put(key_avatar_background2Blue, key_avatar_backgroundBlue); fallbackKeys.put(key_avatar_background2Pink, key_avatar_backgroundPink); + fallbackKeys.put(key_statisticChartLine_orange, key_color_orange); + fallbackKeys.put(key_statisticChartLine_blue, key_color_blue); + fallbackKeys.put(key_statisticChartLine_red, key_color_red); + fallbackKeys.put(key_statisticChartLine_lightblue, key_color_lightblue); + fallbackKeys.put(key_statisticChartLine_golden, key_color_yellow); + fallbackKeys.put(key_statisticChartLine_purple, key_color_purple); + fallbackKeys.put(key_statisticChartLine_indigo, key_color_purple); + fallbackKeys.put(key_statisticChartLine_cyan, key_color_cyan); + themeAccentExclusionKeys.addAll(Arrays.asList(keys_avatar_background)); themeAccentExclusionKeys.addAll(Arrays.asList(keys_avatar_background2)); themeAccentExclusionKeys.addAll(Arrays.asList(keys_avatar_nameInMessage)); + themeAccentExclusionKeys.addAll(Arrays.asList(keys_colors)); themeAccentExclusionKeys.add(key_chat_attachFileBackground); themeAccentExclusionKeys.add(key_chat_attachGalleryBackground); themeAccentExclusionKeys.add(key_chat_attachFileText); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java index 620e73e6a..a75dfc9a5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -39,6 +39,7 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -48,8 +49,10 @@ import org.telegram.ui.Cells.ArchiveHintCell; import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.DialogMeUrlCell; import org.telegram.ui.Cells.DialogsEmptyCell; +import org.telegram.ui.Cells.DialogsRequestedEmptyCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ProfileSearchCell; +import org.telegram.ui.Cells.RequestPeerRequirementsCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; @@ -83,7 +86,9 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements VIEW_TYPE_NEW_CHAT_HINT = 11, VIEW_TYPE_TEXT = 12, VIEW_TYPE_CONTACTS_FLICKER = 13, - VIEW_TYPE_HEADER_2 = 14; + VIEW_TYPE_HEADER_2 = 14, + VIEW_TYPE_REQUIREMENTS = 15, + VIEW_TYPE_REQUIRED_EMPTY = 16; private Context mContext; private ArchiveHintCell archiveHintCell; @@ -119,7 +124,10 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements private boolean isTransitionSupport; private boolean fromDiffUtils; - public DialogsAdapter(DialogsActivity fragment, Context context, int type, int folder, boolean onlySelect, ArrayList selected, int account) { + private TLRPC.RequestPeerType requestPeerType; + public boolean isEmpty; + + public DialogsAdapter(DialogsActivity fragment, Context context, int type, int folder, boolean onlySelect, ArrayList selected, int account, TLRPC.RequestPeerType requestPeerType) { mContext = context; parentFragment = fragment; dialogsType = type; @@ -136,6 +144,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements if (folder == 0) { this.preloader = new DialogsPreloader(); } + this.requestPeerType = requestPeerType; } public void setRecyclerListView(RecyclerListView recyclerListView) { @@ -156,9 +165,9 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } if (showArchiveHint) { position -= 2; - } else if (dialogsType == 11 || dialogsType == 13) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY) { position -= 2; - } else if (dialogsType == 12) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS) { position -= 1; } return position; @@ -368,7 +377,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } public void updateHasHints() { - hasHints = folderId == 0 && dialogsType == 0 && !isOnlySelect && !MessagesController.getInstance(currentAccount).hintDialogs.isEmpty(); + hasHints = folderId == 0 && dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT && !isOnlySelect && !MessagesController.getInstance(currentAccount).hintDialogs.isEmpty(); } public void updateList(RecyclerListView recyclerListView, boolean hasHiddenArchive, float tabsTranslation) { @@ -451,7 +460,8 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements int viewType = holder.getItemViewType(); return viewType != VIEW_TYPE_FLICKER && viewType != VIEW_TYPE_EMPTY && viewType != VIEW_TYPE_DIVIDER && viewType != VIEW_TYPE_SHADOW && viewType != VIEW_TYPE_HEADER && viewType != VIEW_TYPE_ARCHIVE && - viewType != VIEW_TYPE_LAST_EMPTY && viewType != VIEW_TYPE_NEW_CHAT_HINT && viewType != VIEW_TYPE_CONTACTS_FLICKER; + viewType != VIEW_TYPE_LAST_EMPTY && viewType != VIEW_TYPE_NEW_CHAT_HINT && viewType != VIEW_TYPE_CONTACTS_FLICKER && + viewType != VIEW_TYPE_REQUIREMENTS && viewType != VIEW_TYPE_REQUIRED_EMPTY; } @Override @@ -459,7 +469,8 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements View view; switch (viewType) { case VIEW_TYPE_DIALOG: - if (dialogsType == 2) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO || + dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { view = new ProfileSearchCell(mContext); } else { DialogCell dialogCell = new DialogCell(parentFragment, mContext, true, false, currentAccount, null); @@ -469,6 +480,12 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements dialogCell.setIsTransitionSupport(isTransitionSupport); view = dialogCell; } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } + break; + case VIEW_TYPE_REQUIREMENTS: + view = new RequestPeerRequirementsCell(mContext); break; case VIEW_TYPE_FLICKER: case VIEW_TYPE_CONTACTS_FLICKER: @@ -524,6 +541,14 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements case VIEW_TYPE_EMPTY: view = new DialogsEmptyCell(mContext); break; + case VIEW_TYPE_REQUIRED_EMPTY: + view = new DialogsRequestedEmptyCell(mContext) { + @Override + protected void onButtonClick() { + onCreateGroupForThisClick(); + } + }; + break; case VIEW_TYPE_USER: view = new UserCell(mContext, 8, 0, false); break; @@ -611,12 +636,19 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements case VIEW_TYPE_TEXT: default: { view = new TextCell(mContext); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } } } view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, viewType == 5 ? RecyclerView.LayoutParams.MATCH_PARENT : RecyclerView.LayoutParams.WRAP_CONTENT)); return new RecyclerListView.Holder(view); } + public void onCreateGroupForThisClick() { + + } + public int lastDialogsEmptyType = -1; public int dialogsEmptyType() { @@ -637,10 +669,11 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements case VIEW_TYPE_DIALOG: { TLRPC.Dialog dialog = (TLRPC.Dialog) getItem(i); TLRPC.Dialog nextDialog = (TLRPC.Dialog) getItem(i + 1); - if (dialogsType == 2) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO || dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; long oldDialogId = cell.getDialogId(); + TLObject object = null; TLRPC.Chat chat = null; CharSequence title = null; CharSequence subtitle; @@ -657,6 +690,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } if (chat != null) { + object = chat; title = chat.title; if (ChatObject.isChannel(chat) && !chat.megagroup) { if (chat.participants_count != 0) { @@ -683,15 +717,27 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } } else { subtitle = ""; + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialog.id); + if (user != null) { + object = user; + title = UserObject.getUserName(user); + if (!UserObject.isReplyUser(user)) { + if (user.bot) { + subtitle = LocaleController.getString("Bot", R.string.Bot); + } else { + subtitle = LocaleController.formatUserStatus(currentAccount, user); + } + } + } } cell.useSeparator = nextDialog != null; - cell.setData(chat, null, title, subtitle, isRecent, false); + cell.setData(object, null, title, subtitle, isRecent, false); cell.setChecked(selectedDialogs.contains(cell.getDialogId()), oldDialogId == cell.getDialogId()); } else { DialogCell cell = (DialogCell) holder.itemView; cell.useSeparator = nextDialog != null; cell.fullSeparator = dialog.pinned && nextDialog != null && !nextDialog.pinned; - if (dialogsType == 0) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT) { if (AndroidUtilities.isTablet()) { cell.setDialogSelected(dialog.id == openedDialogId); } @@ -734,6 +780,10 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } break; } + case VIEW_TYPE_REQUIRED_EMPTY: { + ((DialogsRequestedEmptyCell) holder.itemView).set(requestPeerType); + break; + } case VIEW_TYPE_ME_URL: { DialogMeUrlCell cell = (DialogMeUrlCell) holder.itemView; cell.setRecentMeUrl((TLRPC.RecentMeUrl) getItem(i)); @@ -747,7 +797,11 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } case VIEW_TYPE_HEADER: { HeaderCell cell = (HeaderCell) holder.itemView; - if (dialogsType == 11 || dialogsType == 12 || dialogsType == 13) { + if ( + dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || + dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS || + dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY + ) { if (i == 0) { cell.setText(LocaleController.getString("ImportHeader", R.string.ImportHeader)); } else { @@ -792,11 +846,24 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements case VIEW_TYPE_TEXT: { TextCell cell = (TextCell) holder.itemView; cell.setColors(Theme.key_windowBackgroundWhiteBlueText4, Theme.key_windowBackgroundWhiteBlueText4); - cell.setTextAndIcon(LocaleController.getString("CreateGroupForImport", R.string.CreateGroupForImport), R.drawable.msg_groups_create, dialogsCount != 0); + if (requestPeerType != null) { + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + cell.setTextAndIcon(LocaleController.getString("CreateChannelForThis", R.string.CreateChannelForThis), R.drawable.msg_channel_create, true); + } else { + cell.setTextAndIcon(LocaleController.getString("CreateGroupForThis", R.string.CreateGroupForThis), R.drawable.msg_groups_create, true); + } + } else { + cell.setTextAndIcon(LocaleController.getString("CreateGroupForImport", R.string.CreateGroupForImport), R.drawable.msg_groups_create, dialogsCount != 0); + } cell.setIsInDialogs(); cell.setOffsetFromImage(75); break; } + case VIEW_TYPE_REQUIREMENTS: { + RequestPeerRequirementsCell cell = (RequestPeerRequirementsCell) holder.itemView; + cell.set(requestPeerType); + break; + } } if (i >= dialogsCount + 1) { holder.itemView.setAlpha(1f); @@ -1098,6 +1165,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements MessagesController messagesController = MessagesController.getInstance(currentAccount); ArrayList array = parentFragment.getDialogsArray(currentAccount, dialogsType, folderId, dialogsListFrozen); dialogsCount = array.size(); + isEmpty = false; if (!hasHints && dialogsType == 0 && folderId == 0 && messagesController.isDialogsEndReached(folderId) && !forceUpdatingContacts) { if (messagesController.getAllFoldersDialogsCount() <= 10 && ContactsController.getInstance(currentAccount).doneLoadingContacts && !ContactsController.getInstance(currentAccount).contacts.isEmpty()) { @@ -1121,6 +1189,10 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } } + if (requestPeerType != null) { + itemInternals.add(new ItemInternal(VIEW_TYPE_REQUIREMENTS)); + } + boolean stopUpdate = false; if (collapsedView || isTransitionSupport) { for (int k = 0; k < array.size(); k++) { @@ -1134,13 +1206,15 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } if (dialogsCount == 0 && forceUpdatingContacts) { - itemInternals.add(new ItemInternal(VIEW_TYPE_EMPTY)); + isEmpty = true; + itemInternals.add(new ItemInternal(requestPeerType == null ? VIEW_TYPE_EMPTY : VIEW_TYPE_REQUIRED_EMPTY)); itemInternals.add(new ItemInternal(VIEW_TYPE_SHADOW)); itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER)); itemInternals.add(new ItemInternal(VIEW_TYPE_CONTACTS_FLICKER)); } else if (onlineContacts != null) { if (dialogsCount == 0) { - itemInternals.add(new ItemInternal(VIEW_TYPE_EMPTY)); + isEmpty = true; + itemInternals.add(new ItemInternal(requestPeerType == null ? VIEW_TYPE_EMPTY : VIEW_TYPE_REQUIRED_EMPTY)); itemInternals.add(new ItemInternal(VIEW_TYPE_SHADOW)); itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER)); } else { @@ -1165,16 +1239,20 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } else if (showArchiveHint) { itemInternals.add(new ItemInternal(VIEW_TYPE_ARCHIVE)); itemInternals.add(new ItemInternal(VIEW_TYPE_SHADOW)); - } else if (dialogsType == 11 || dialogsType == 13) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY) { itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER)); itemInternals.add(new ItemInternal(VIEW_TYPE_TEXT)); - } else if (dialogsType == 12) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS) { itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER)); } + if ((requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast || requestPeerType instanceof TLRPC.TL_requestPeerTypeChat) && dialogsCount > 0) { + itemInternals.add(new ItemInternal(VIEW_TYPE_TEXT)); + } + if (!stopUpdate) { for (int k = 0; k < array.size(); k++) { - if (dialogsType == 2 && array.get(k) instanceof DialogsActivity.DialogsHeader) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO && array.get(k) instanceof DialogsActivity.DialogsHeader) { itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER_2, array.get(k))); } else { itemInternals.add(new ItemInternal(VIEW_TYPE_DIALOG, array.get(k))); @@ -1185,9 +1263,10 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements if (!forceShowEmptyCell && dialogsType != 7 && dialogsType != 8 && !MessagesController.getInstance(currentAccount).isDialogsEndReached(folderId)) { itemInternals.add(new ItemInternal(VIEW_TYPE_FLICKER)); } else if (dialogsCount == 0) { - itemInternals.add(new ItemInternal(VIEW_TYPE_EMPTY)); + isEmpty = true; + itemInternals.add(new ItemInternal(requestPeerType == null ? VIEW_TYPE_EMPTY : VIEW_TYPE_REQUIRED_EMPTY)); } else { - if (folderId == 0 && dialogsCount > 10 && dialogsType == 0) { + if (folderId == 0 && dialogsCount > 10 && dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT) { itemInternals.add(new ItemInternal(VIEW_TYPE_NEW_CHAT_HINT)); } itemInternals.add(new ItemInternal(VIEW_TYPE_LAST_EMPTY)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java index b825710f3..aa96322e9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -53,6 +53,7 @@ import org.telegram.ui.Cells.TopicSearchCell; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.ForegroundColorSpanThemable; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.DialogsActivity; import org.telegram.ui.FilteredSearchView; import java.util.ArrayList; @@ -109,6 +110,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { private long lastShowMoreUpdate; public View showMoreHeader; private Runnable cancelShowMoreAnimation; + private ArrayList filterDialogIds; private int currentAccount = UserConfig.selectedAccount; @@ -124,6 +126,10 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { private int folderId; private ArrayList allContacts; + public void setFilterDialogIds(ArrayList filterDialogIds) { + this.filterDialogIds = filterDialogIds; + } + public boolean isSearching() { return waitingResponseCount > 0; } @@ -312,6 +318,10 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { return; } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + return; + } + final long dialogId = delegate.getSearchForumDialogId(); final TLRPC.TL_messages_search req = new TLRPC.TL_messages_search(); @@ -432,6 +442,15 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { searchAdapterHelper.mergeResults(searchResult, filtered2RecentSearchObjects); } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + waitingResponseCount--; + if (delegate != null) { + delegate.searchStateChanged(waitingResponseCount > 0, true); + delegate.runResultsEnterAnimation(); + } + return; + } + final TLRPC.TL_messages_searchGlobal req = new TLRPC.TL_messages_searchGlobal(); req.limit = 20; req.q = query; @@ -547,7 +566,14 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { } private boolean resentSearchAvailable() { - return dialogsType != 2 && dialogsType != 4 && dialogsType != 5 && dialogsType != 6 && dialogsType != 11; + return ( + dialogsType != DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO && + dialogsType != DialogsActivity.DIALOGS_TYPE_USERS_ONLY && + dialogsType != DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY && + dialogsType != DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY && + dialogsType != DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS && + dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER + ); } public boolean isSearchWas() { @@ -559,6 +585,9 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { } public void loadRecentSearch() { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + return; + } loadRecentSearch(currentAccount, dialogsType, (arrayList, hashMap) -> { DialogsSearchAdapter.this.setRecentSearch(arrayList, hashMap); }); @@ -581,7 +610,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { boolean add = false; if (DialogObject.isEncryptedDialog(did)) { - if (dialogsType == 0 || dialogsType == 3) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT || dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD) { int encryptedChatId = DialogObject.getEncryptedChatId(did); if (!encryptedToLoad.contains(encryptedChatId)) { encryptedToLoad.add(encryptedChatId); @@ -792,7 +821,8 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { ArrayList resultArrayNames = new ArrayList<>(); ArrayList encUsers = new ArrayList<>(); ArrayList contacts = new ArrayList<>(); - MessagesStorage.getInstance(currentAccount).localSearch(dialogsType, q, resultArray, resultArrayNames, encUsers, -1); + + MessagesStorage.getInstance(currentAccount).localSearch(dialogsType, q, resultArray, resultArrayNames, encUsers, filterDialogIds, -1); // if (allContacts == null) { // allContacts = new ArrayList<>(); // for (ContactsController.Contact contact : ContactsController.getInstance(currentAccount).phoneBookContacts) { @@ -947,7 +977,21 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { searchResultNames.clear(); searchResultHashtags.clear(); searchAdapterHelper.mergeResults(null, null); - searchAdapterHelper.queryServerSearch(null, true, true, dialogsType != 11, dialogsType != 11, dialogsType == 2 || dialogsType == 11, 0, dialogsType == 0, 0, 0, delegate != null ? delegate.getSearchForumDialogId() : 0); + if (dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + searchAdapterHelper.queryServerSearch( + null, + true, + true, + dialogsType != DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS, + dialogsType != DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS, + dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO || dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS, + 0, + dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT, + 0, + 0, + delegate != null ? delegate.getSearchForumDialogId() : 0 + ); + } searchWas = false; lastSearchId = 0; waitingResponseCount = 0; @@ -956,9 +1000,11 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { if (delegate != null) { delegate.searchStateChanged(false, true); } - searchTopics(null); - searchMessagesInternal(null, 0); - searchForumMessagesInternal(null, 0); + if (dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + searchTopics(null); + searchMessagesInternal(null, 0); + searchForumMessagesInternal(null, 0); + } notifyDataSetChanged(); localTipDates.clear(); localTipArchive = false; @@ -1000,17 +1046,33 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { Utilities.searchQueue.postRunnable(searchRunnable = () -> { searchRunnable = null; searchDialogsInternal(query, searchId); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + waitingResponseCount -= 2; + return; + } AndroidUtilities.runOnUIThread(searchRunnable2 = () -> { searchRunnable2 = null; if (searchId != lastSearchId) { return; } - if (needMessagesSearch != 2) { - searchAdapterHelper.queryServerSearch(query, true, dialogsType != 4, true, dialogsType != 4 && dialogsType != 11, dialogsType == 2 || dialogsType == 1, 0, dialogsType == 0, 0, searchId, delegate != null ? delegate.getSearchForumDialogId() : 0); + if (needMessagesSearch != 2 && dialogsType != DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY && dialogsType != DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY) { + searchAdapterHelper.queryServerSearch( + query, + true, + dialogsType != DialogsActivity.DIALOGS_TYPE_USERS_ONLY, + true, + dialogsType != DialogsActivity.DIALOGS_TYPE_USERS_ONLY && dialogsType != DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS, + dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO || dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_SHARE, + 0, + dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT, + 0, + searchId, + delegate != null ? delegate.getSearchForumDialogId() : 0 + ); } else { waitingResponseCount -= 2; } - if (needMessagesSearch == 0) { + if (needMessagesSearch == 0 || dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { waitingResponseCount--; } else { searchTopics(text); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index 5cab8a19d..4a5a3e145 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -167,7 +167,7 @@ import org.telegram.ui.Components.TextPaintMarkSpan; import org.telegram.ui.Components.TextPaintSpan; import org.telegram.ui.Components.TextPaintUrlSpan; import org.telegram.ui.Components.TextPaintWebpageUrlSpan; -import org.telegram.ui.Components.TranslateAlert; +import org.telegram.ui.Components.TranslateAlert2; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.WebPlayerView; @@ -1211,7 +1211,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } BottomSheet.Builder builder = new BottomSheet.Builder(parentActivity); - builder.setTitle(urlFinal); + String formattedUrl = urlFinal; + try { + formattedUrl = URLDecoder.decode(urlFinal.replaceAll("\\+", "%2b"), "UTF-8"); + } catch (Exception e) { + FileLog.e(e); + } + builder.setTitle(formattedUrl); + builder.setTitleMultipleLines(true); builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { if (parentActivity == null) { return; @@ -2648,22 +2655,24 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg pressedEnd = end; } } - if (pressedLink != null) { - links.removeLink(pressedLink); - } - pressedLink = new LinkSpanDrawable(selectedLink, null, x, y); - pressedLink.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); - links.addLink(pressedLink, pressedLinkOwnerLayout); - try { - LinkPath path = pressedLink.obtainNewPath(); - path.setCurrentLayout(layout, pressedStart, 0); - TextPaint textPaint = selectedLink.getTextPaint(); - int shift = textPaint != null ? textPaint.baselineShift : 0; - path.setBaselineShift(shift != 0 ? shift + AndroidUtilities.dp(shift > 0 ? 5 : -2) : 0); - layout.getSelectionPath(pressedStart, pressedEnd, path); - parentView.invalidate(); - } catch (Exception e) { - FileLog.e(e); + if (pressedLink == null || pressedLink.getSpan() != selectedLink) { + if (pressedLink != null) { + links.removeLink(pressedLink); + } + pressedLink = new LinkSpanDrawable(selectedLink, null, x, y); + pressedLink.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); + links.addLink(pressedLink, pressedLinkOwnerLayout); + try { + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(layout, pressedStart, 0); + TextPaint textPaint = selectedLink.getTextPaint(); + int shift = textPaint != null ? textPaint.baselineShift : 0; + path.setBaselineShift(shift != 0 ? shift + AndroidUtilities.dp(shift > 0 ? 5 : -2) : 0); + layout.getSelectionPath(pressedStart, pressedEnd, path); + parentView.invalidate(); + } catch (Exception e) { + FileLog.e(e); + } } } } @@ -3671,10 +3680,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg boolean isLightNavigation = navigationBrightness >= 0.721f; if (isLightNavigation && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { uiFlags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; - navigationBarPaint.setColor(navigationColor); - } else if (!isLightNavigation) { - navigationBarPaint.setColor(navigationColor); } + navigationBarPaint.setColor(navigationColor); windowLayoutParams.systemUiVisibility = uiFlags; if (Build.VERSION.SDK_INT >= 21) { @@ -3688,9 +3695,9 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg textSelectionHelper = new TextSelectionHelper.ArticleTextSelectionHelper(); textSelectionHelper.setParentView(listView[0]); - if (MessagesController.getGlobalMainSettings().getBoolean("translate_button", false)) { + if (MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled()) { textSelectionHelper.setOnTranslate((text, fromLang, toLang, onAlertDismiss) -> { - TranslateAlert.showAlert(parentActivity, parentFragment, currentAccount, fromLang, toLang, text, false, null, onAlertDismiss); + TranslateAlert2.showAlert(parentActivity, parentFragment, currentAccount, fromLang, toLang, text, null, false, null, onAlertDismiss); }); } textSelectionHelper.layoutManager = layoutManager[0]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/BubbleActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/BubbleActivity.java index e40e16255..ba1487ce6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/BubbleActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/BubbleActivity.java @@ -122,7 +122,7 @@ public class BubbleActivity extends BasePermissionsActivity implements INavigati passcodeView.onShow(true, false); SharedConfig.isWaitingForPasscodeEnter = true; drawerLayoutContainer.setAllowOpenDrawer(false, false); - passcodeView.setDelegate(() -> { + passcodeView.setDelegate(view -> { SharedConfig.isWaitingForPasscodeEnter = false; if (passcodeSaveIntent != null) { handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true, passcodeSaveIntentAccount, passcodeSaveIntentState); @@ -130,6 +130,8 @@ public class BubbleActivity extends BasePermissionsActivity implements INavigati } drawerLayoutContainer.setAllowOpenDrawer(true, false); actionBarLayout.showLastFragment(); + + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.passcodeDismissed, view); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheChatsExceptionsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheChatsExceptionsFragment.java index 2290b737f..feb379255 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheChatsExceptionsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheChatsExceptionsFragment.java @@ -81,11 +81,11 @@ public class CacheChatsExceptionsFragment extends BaseFragment { args.putBoolean("onlySelect", true); args.putBoolean("checkCanWrite", false); if (currentType == CacheControlActivity.KEEP_MEDIA_TYPE_GROUP) { - args.putInt("dialogsType", 6); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY); } else if (currentType == CacheControlActivity.KEEP_MEDIA_TYPE_CHANNEL) { - args.putInt("dialogsType", 5); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); } else { - args.putInt("dialogsType", 4); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_USERS_ONLY); } args.putBoolean("allowGlobalSearch", false); DialogsActivity activity = new DialogsActivity(args); @@ -123,6 +123,7 @@ public class CacheChatsExceptionsFragment extends BaseFragment { int finalP = p; showPopupFor(newException); } + return true; }); presentFragment(activity); } else if (items.get(position).viewType == VIEW_TYPE_CHAT) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index a5cc6db47..29dc17039 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -170,7 +170,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe private CacheChartHeader cacheChartHeader; private ClearCacheButtonInternal clearCacheButton; - private volatile boolean canceled = false; + public static volatile boolean canceled = false; private View bottomSheetView; private BottomSheet bottomSheet; @@ -208,9 +208,105 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe } } + private static long lastTotalSizeCalculatedTime; + private static Long lastTotalSizeCalculated; + private static Long lastDeviceTotalSize, lastDeviceTotalFreeSize; + + public static void calculateTotalSize(Utilities.Callback onDone) { + if (onDone == null) { + return; + } + if (lastTotalSizeCalculated != null) { + onDone.run(lastTotalSizeCalculated); + if (System.currentTimeMillis() - lastTotalSizeCalculatedTime < 5000) { + return; + } + } + Utilities.globalQueue.postRunnable(() -> { + canceled = false; + long cacheSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), 5); + long cacheTempSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), 4); + long photoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE), 0); + photoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE_PUBLIC), 0); + long videoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO), 0); + videoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO_PUBLIC), 0); + long documentsSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_DOCUMENT), 1); + documentsSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_FILES), 1); + long musicSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_DOCUMENT), 2); + musicSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_FILES), 2); + long stickersCacheSize = getDirectorySize(new File(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), "acache"), 0); + stickersCacheSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), 3); + long audioSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_AUDIO), 0); + final long totalSize = lastTotalSizeCalculated = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + lastTotalSizeCalculatedTime = System.currentTimeMillis(); + if (!canceled) { + AndroidUtilities.runOnUIThread(() -> { + onDone.run(totalSize); + }); + } + }); + } + + public static void getDeviceTotalSize(Utilities.Callback2 onDone) { + if (lastDeviceTotalSize != null && lastDeviceTotalFreeSize != null) { + if (onDone != null) { + onDone.run(lastDeviceTotalSize, lastDeviceTotalFreeSize); + } + return; + } + File path; + if (Build.VERSION.SDK_INT >= 19) { + ArrayList storageDirs = AndroidUtilities.getRootDirs(); + String dir = (path = storageDirs.get(0)).getAbsolutePath(); + if (!TextUtils.isEmpty(SharedConfig.storageCacheDir)) { + for (int a = 0, N = storageDirs.size(); a < N; a++) { + File file = storageDirs.get(a); + if (file.getAbsolutePath().startsWith(SharedConfig.storageCacheDir)) { + path = file; + break; + } + } + } + } else { + path = new File(SharedConfig.storageCacheDir); + } + try { + StatFs stat = new StatFs(path.getPath()); + long blockSize; + long blockSizeExternal; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + blockSize = stat.getBlockSizeLong(); + } else { + blockSize = stat.getBlockSize(); + } + long availableBlocks; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + availableBlocks = stat.getAvailableBlocksLong(); + } else { + availableBlocks = stat.getAvailableBlocks(); + } + long blocksTotal; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + blocksTotal = stat.getBlockCountLong(); + } else { + blocksTotal = stat.getBlockCount(); + } + + lastDeviceTotalSize = blocksTotal * blockSize; + lastDeviceTotalFreeSize = availableBlocks * blockSize; + if (onDone != null) { + onDone.run(lastDeviceTotalSize, lastDeviceTotalFreeSize); + } + return; + } catch (Exception e) { + FileLog.e(e); + } + } + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); + canceled = false; getNotificationCenter().addObserver(this, NotificationCenter.didClearDatabase); databaseSize = MessagesStorage.getInstance(currentAccount).getDatabaseSize(); loadingDialogs = true; @@ -256,7 +352,11 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe } stickersCacheSize += cacheEmojiSize; audioSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_AUDIO), 0); - totalSize = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + if (canceled) { + return; + } + totalSize = lastTotalSizeCalculated = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + lastTotalSizeCalculatedTime = System.currentTimeMillis(); File path; if (Build.VERSION.SDK_INT >= 19) { @@ -302,14 +402,13 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe FileLog.e(e); } - long minDuration = System.currentTimeMillis() - fragmentCreateTime > 45 ? 600 : 0; AndroidUtilities.runOnUIThread(() -> { resumeDelayedFragmentAnimation(); calculating = false; updateRows(true); updateChart(); - }, Math.max(1, minDuration - (System.currentTimeMillis() - fragmentCreateTime))); + }); loadDialogEntities(); }); @@ -339,11 +438,11 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe if (System.currentTimeMillis() - fragmentCreateTime < 80) { cacheChart.loadingFloat.set(0, true); } - cacheChart.setSegments(totalSize, segments); + cacheChart.setSegments(totalSize, true, segments); } else if (calculating) { - cacheChart.setSegments(-1); + cacheChart.setSegments(-1, true); } else { - cacheChart.setSegments(0); + cacheChart.setSegments(0, true); } } if (clearCacheButton != null && !calculating) { @@ -530,14 +629,14 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe } private String formatPercent(float k, boolean minimize) { - float p = Math.round(k * 100f); - if (minimize && p < 0.1f) { + if (minimize && k < 0.001f) { return String.format("<%.1f%%", 0.1f); } - if (p % 1 == 0) { - return ((int) p) + "%"; + final float p = Math.round(k * 100f); + if (minimize && p <= 0) { + return String.format("<%d%%", 1); } - return String.format("%.1f%%", p); + return String.format("%d%%", (int) p); } private CharSequence getCheckBoxTitle(CharSequence header, int percent) { @@ -545,7 +644,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe } private CharSequence getCheckBoxTitle(CharSequence header, int percent, boolean addArrow) { - String percentString = percent <= 0 ? String.format("<%.1f%%", 0.1f) : String.format("%d%%", percent); + String percentString = percent <= 0 ? String.format("<%.1f%%", 1f) : String.format("%d%%", percent); SpannableString percentStr = new SpannableString(percentString); percentStr.setSpan(new RelativeSizeSpan(.834f), 0, percentStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); percentStr.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, percentStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -700,7 +799,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe canceled = true; } - private long getDirectorySize(File dir, int documentsMusicType) { + private static long getDirectorySize(File dir, int documentsMusicType) { if (dir == null || canceled) { return 0; } @@ -841,7 +940,8 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe } } final boolean imagesClearedFinal = imagesCleared; - totalSize = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + totalSize = lastTotalSizeCalculated = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + lastTotalSizeCalculatedTime = System.currentTimeMillis(); Arrays.fill(selected, true); File path = Environment.getDataDirectory(); @@ -888,8 +988,10 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe } getMediaDataController().ringtoneDataStore.checkRingtoneSoundsLoaded(); - cacheRemovedTooltip.setInfoText(LocaleController.formatString("CacheWasCleared", R.string.CacheWasCleared, AndroidUtilities.formatFileSize(finalClearedSize))); - cacheRemovedTooltip.showWithAction(0, UndoView.ACTION_CACHE_WAS_CLEARED, null, null); + AndroidUtilities.runOnUIThread(() -> { + cacheRemovedTooltip.setInfoText(LocaleController.formatString("CacheWasCleared", R.string.CacheWasCleared, AndroidUtilities.formatFileSize(finalClearedSize))); + cacheRemovedTooltip.showWithAction(0, UndoView.ACTION_CACHE_WAS_CLEARED, null, null); + }, 150); MediaDataController.getInstance(currentAccount).chekAllMedia(true); loadDialogEntities(); @@ -1436,7 +1538,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe LocaleController.getString("StorageCleared", R.string.StorageCleared) ); if (hasCache) { - if (percent < 0.1f) { + if (percent < 0.01f) { subtitle[1].setText(LocaleController.formatString("StorageUsageTelegramLess", R.string.StorageUsageTelegramLess, formatPercent(percent))); } else { subtitle[1].setText(LocaleController.formatString("StorageUsageTelegram", R.string.StorageUsageTelegram, formatPercent(percent))); @@ -1640,7 +1742,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe @Override protected void dispatchDraw(Canvas canvas) { final int margin = AndroidUtilities.dp(8); - int x = (getMeasuredWidth() - margin - valueTextView.getCurrentWidth() + textView.getCurrentWidth()) / 2; + int x = (getMeasuredWidth() - margin - (int) valueTextView.getCurrentWidth() + (int) textView.getCurrentWidth()) / 2; if (LocaleController.isRTL) { super.dispatchDraw(canvas); @@ -2140,14 +2242,11 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe } String value = CacheByChatsController.getKeepMediaString(cacheByChatsController.getKeepMedia(keepMediaType)); if (itemInners.get(position).keepMediaType == KEEP_MEDIA_TYPE_USER) { - textCell2.setTextAndValue(LocaleController.getString("PrivateChats", R.string.PrivateChats), value, true, true); - textCell2.setColorfulIcon(getThemedColor(Theme.key_statisticChartLine_lightblue), R.drawable.msg_filled_menu_users); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("PrivateChats", R.string.PrivateChats), value, true, R.drawable.msg_filled_menu_users, getThemedColor(Theme.key_statisticChartLine_lightblue), true); } else if (itemInners.get(position).keepMediaType == KEEP_MEDIA_TYPE_GROUP) { - textCell2.setTextAndValue(LocaleController.getString("GroupChats", R.string.GroupChats), value, true, true); - textCell2.setColorfulIcon(getThemedColor(Theme.key_statisticChartLine_green), R.drawable.msg_filled_menu_groups); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("GroupChats", R.string.GroupChats), value, true, R.drawable.msg_filled_menu_groups, getThemedColor(Theme.key_statisticChartLine_green), true); } else if (itemInners.get(position).keepMediaType == KEEP_MEDIA_TYPE_CHANNEL) { - textCell2.setTextAndValue(LocaleController.getString("CacheChannels", R.string.CacheChannels), value, true, false); - textCell2.setColorfulIcon(getThemedColor(Theme.key_statisticChartLine_golden), R.drawable.msg_filled_menu_channels); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("CacheChannels", R.string.CacheChannels), value, true, R.drawable.msg_filled_menu_channels, getThemedColor(Theme.key_statisticChartLine_golden), true); } textCell2.setSubtitle(subtitle); break; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CachedMediaLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/CachedMediaLayout.java index 77ed5dc2d..0038362bb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CachedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CachedMediaLayout.java @@ -100,7 +100,7 @@ public class CachedMediaLayout extends FrameLayout implements NestedSizeNotifier int CacheTabChats; allPages[PAGE_TYPE_CHATS] = new Page(LocaleController.getString("Chats", R.string.Chats), PAGE_TYPE_CHATS, new DialogsAdapter()); - allPages[PAGE_TYPE_MEDIA] = new Page(LocaleController.getString("Media", R.string.Media), PAGE_TYPE_MEDIA, new MediaAdapter()); + allPages[PAGE_TYPE_MEDIA] = new Page(LocaleController.getString("MediaTab", R.string.MediaTab), PAGE_TYPE_MEDIA, new MediaAdapter()); allPages[PAGE_TYPE_DOCUMENTS] = new Page(LocaleController.getString("Files", R.string.Files), PAGE_TYPE_DOCUMENTS, new DocumentsAdapter()); allPages[PAGE_TYPE_MUSIC] = new Page(LocaleController.getString("Music", R.string.Music), PAGE_TYPE_MUSIC, new MusicAdapter()); // allPages[PAGE_TYPE_VOICE] = new Page(LocaleController.getString("Voice", R.string.Voice), PAGE_TYPE_VOICE, new VoiceAdapter()); @@ -750,7 +750,7 @@ public class CachedMediaLayout extends FrameLayout implements NestedSizeNotifier holder.itemView.setTag(file); long date = file.file.lastModified(); - cell.setTextAndValueAndTypeAndThumb(file.messageType == MessageObject.TYPE_ROUND_VIDEO ? LocaleController.getString("AttachRound", R.string.AttachRound) : file.file.getName(), LocaleController.formatDateAudio(date, true), Utilities.getExtension(file.file.getName()), null, 0, divider); + cell.setTextAndValueAndTypeAndThumb(file.messageType == MessageObject.TYPE_ROUND_VIDEO ? LocaleController.getString("AttachRound", R.string.AttachRound) : file.file.getName(), LocaleController.formatDateAudio(date / 1000, true), Utilities.getExtension(file.file.getName()), null, 0, divider); if (!animated) { cell.setPhoto(file.file.getPath()); } @@ -992,7 +992,7 @@ public class CachedMediaLayout extends FrameLayout implements NestedSizeNotifier super(context); checkBox = new CheckBox2(context, 21); checkBox.setDrawBackgroundAsArc(14); - checkBox.setColor(Theme.key_radioBackground, Theme.key_radioBackground, Theme.key_checkboxCheck); + checkBox.setColor(Theme.key_checkbox, Theme.key_radioBackground, Theme.key_checkboxCheck); addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.LEFT | Gravity.CENTER_VERTICAL, 18, 0, 0, 0)); View checkBoxClickableView = new View(getContext()); checkBoxClickableView.setOnClickListener(v -> { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java index ba5b0a974..83197df28 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java @@ -9,6 +9,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; @@ -59,6 +60,7 @@ import org.telegram.ui.Components.HintView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SharedMediaLayout; +import org.telegram.ui.Components.spoilers.SpoilerEffect; import java.time.YearMonth; import java.util.ArrayList; @@ -122,6 +124,9 @@ public class CalendarActivity extends BaseFragment { private int calendarType; + private Path path = new Path(); + private SpoilerEffect mediaSpoilerEffect = new SpoilerEffect(); + public CalendarActivity(Bundle args, int photosVideosTypeFilter, int selectedDate) { super(args); this.photosVideosTypeFilter = photosVideosTypeFilter; @@ -923,6 +928,7 @@ public class CalendarActivity extends BaseFragment { PeriodDay periodDay = messagesByDays.get(key); MessageObject messageObject = periodDay.messageObject; if (messageObject != null) { + boolean hasMediaSpoilers = messageObject.hasMediaSpoilers(); if (messageObject.isVideo()) { TLRPC.Document document = messageObject.getDocument(); TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 50); @@ -932,9 +938,9 @@ public class CalendarActivity extends BaseFragment { } if (thumb != null) { if (messageObject.strippedThumb != null) { - receiver.setImage(ImageLocation.getForDocument(qualityThumb, document), "44_44", messageObject.strippedThumb, null, messageObject, 0); + receiver.setImage(ImageLocation.getForDocument(qualityThumb, document), hasMediaSpoilers ? "5_5_b" : "44_44", messageObject.strippedThumb, null, messageObject, 0); } else { - receiver.setImage(ImageLocation.getForDocument(qualityThumb, document), "44_44", ImageLocation.getForDocument(thumb, document), "b", (String) null, messageObject, 0); + receiver.setImage(ImageLocation.getForDocument(qualityThumb, document), hasMediaSpoilers ? "5_5_b" : "44_44", ImageLocation.getForDocument(thumb, document), "b", (String) null, messageObject, 0); } } } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageObject.messageOwner.media.photo != null && !messageObject.photoThumbs.isEmpty()) { @@ -945,9 +951,9 @@ public class CalendarActivity extends BaseFragment { currentPhotoObjectThumb = null; } if (messageObject.strippedThumb != null) { - receiver.setImage(ImageLocation.getForObject(currentPhotoObject, messageObject.photoThumbsObject), "44_44", null, null, messageObject.strippedThumb, currentPhotoObject != null ? currentPhotoObject.size : 0, null, messageObject, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); + receiver.setImage(ImageLocation.getForObject(currentPhotoObject, messageObject.photoThumbsObject), hasMediaSpoilers ? "5_5_b" : "44_44", null, null, messageObject.strippedThumb, currentPhotoObject != null ? currentPhotoObject.size : 0, null, messageObject, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); } else { - receiver.setImage(ImageLocation.getForObject(currentPhotoObject, messageObject.photoThumbsObject), "44_44", ImageLocation.getForObject(currentPhotoObjectThumb, messageObject.photoThumbsObject), "b", currentPhotoObject != null ? currentPhotoObject.size : 0, null, messageObject, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); + receiver.setImage(ImageLocation.getForObject(currentPhotoObject, messageObject.photoThumbsObject), hasMediaSpoilers ? "5_5_b" : "44_44", ImageLocation.getForObject(currentPhotoObjectThumb, messageObject.photoThumbsObject), "b", currentPhotoObject != null ? currentPhotoObject.size : 0, null, messageObject, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); } } else { if (messageObject.strippedThumb != null) { @@ -1060,6 +1066,24 @@ public class CalendarActivity extends BaseFragment { imagesByDays.get(i).setImageCoords(cx - (AndroidUtilities.dp(44) - pad) / 2f, cy - (AndroidUtilities.dp(44) - pad) / 2f, AndroidUtilities.dp(44) - pad, AndroidUtilities.dp(44) - pad); imagesByDays.get(i).draw(canvas); + if (messagesByDays.get(i) != null && messagesByDays.get(i).messageObject != null && messagesByDays.get(i).messageObject.hasMediaSpoilers()) { + float rad = (AndroidUtilities.dp(44) - pad) / 2f; + path.rewind(); + path.addCircle(cx, cy, rad, Path.Direction.CW); + + canvas.save(); + canvas.clipPath(path); + + int sColor = Color.WHITE; + mediaSpoilerEffect.setColor(ColorUtils.setAlphaComponent(sColor, (int) (Color.alpha(sColor) * 0.325f * day.enterAlpha))); + mediaSpoilerEffect.setBounds((int) (cx - rad), (int) (cy - rad), (int) (cx + rad), (int) (cy + rad)); + mediaSpoilerEffect.draw(canvas); + + invalidate(); + + canvas.restore(); + } + blackoutPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (day.enterAlpha * 80))); canvas.drawCircle(cx, cy, (AndroidUtilities.dp(44) - pad) / 2f, blackoutPaint); day.wasDrawn = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java index 131cecae5..4ab62d6a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java @@ -502,9 +502,11 @@ public class AboutLinkCell extends FrameLayout { @Override public void end(boolean replacing) { - if (thisLoading != null) { - links.removeLoading(thisLoading, true); - } + AndroidUtilities.runOnUIThread(() -> { + if (thisLoading != null) { + links.removeLoading(thisLoading, true); + } + }, replacing ? 0 : 350); } } : null; if (pressedLink instanceof URLSpanNoUnderline) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java index 7e540d98c..361e96baf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java @@ -12,6 +12,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.text.Layout; import android.text.Spannable; import android.text.SpannableStringBuilder; @@ -24,6 +25,8 @@ import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; +import androidx.annotation.NonNull; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; @@ -40,6 +43,7 @@ import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanNoUnderline; @@ -58,8 +62,8 @@ public class BotHelpCell extends View { private int textY; public boolean wasDraw; - private ClickableSpan pressedLink; - private LinkPath urlPath = new LinkPath(); + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); private BotHelpCellDelegate delegate; private Theme.ResourcesProvider resourcesProvider; @@ -84,6 +88,9 @@ public class BotHelpCell extends View { imageReceiver.setInvalidateAll(true); imageReceiver.setCrossfadeWithOldImage(true); imageReceiver.setCrossfadeDuration(300); + + selectorDrawable = Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), selectorDrawableRadius = SharedConfig.bubbleRadius, SharedConfig.bubbleRadius); + selectorDrawable.setCallback(this); } public void setDelegate(BotHelpCellDelegate botHelpCellDelegate) { @@ -94,6 +101,7 @@ public class BotHelpCell extends View { if (pressedLink != null) { pressedLink = null; } + links.clear(); invalidate(); } @@ -195,6 +203,13 @@ public class BotHelpCell extends View { } } + public CharSequence getText() { + if (textLayout == null) { + return null; + } + return textLayout.getText(); + } + @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); @@ -217,15 +232,18 @@ public class BotHelpCell extends View { ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { resetPressedLink(); - pressedLink = link[0]; + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x2, y2); result = true; try { - int start = buffer.getSpanStart(pressedLink); - urlPath.setCurrentLayout(textLayout, start, 0); - textLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), urlPath); + int start = buffer.getSpanStart(link[0]); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(textLayout, start, 0); + textLayout.getSelectionPath(start, buffer.getSpanEnd(link[0]), path); } catch (Exception e) { FileLog.e(e); } + links.addLink(pressedLink); + invalidate(); } else { resetPressedLink(); } @@ -238,21 +256,20 @@ public class BotHelpCell extends View { } } else if (pressedLink != null) { try { - if (pressedLink instanceof URLSpanNoUnderline) { - String url = ((URLSpanNoUnderline) pressedLink).getURL(); + ClickableSpan span = pressedLink.getSpan(); + if (span instanceof URLSpanNoUnderline) { + String url = ((URLSpanNoUnderline) span).getURL(); if (url.startsWith("@") || url.startsWith("#") || url.startsWith("/")) { if (delegate != null) { delegate.didPressUrl(url); } } - } else { - if (pressedLink instanceof URLSpan) { - if (delegate != null) { - delegate.didPressUrl(((URLSpan) pressedLink).getURL()); - } - } else { - pressedLink.onClick(this); + } else if (span instanceof URLSpan) { + if (delegate != null) { + delegate.didPressUrl(((URLSpan) span).getURL()); } + } else if (span != null) { + span.onClick(this); } } catch (Exception e) { FileLog.e(e); @@ -264,6 +281,23 @@ public class BotHelpCell extends View { resetPressedLink(); } } + if (selectorDrawable != null) { + if (!result && y > 0 && event.getAction() == MotionEvent.ACTION_DOWN && isClickable()) { + selectorDrawable.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + selectorDrawable.setHotspot(event.getX(), event.getY()); + } + invalidate(); + result = true; + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + selectorDrawable.setState(new int[]{}); + invalidate(); + if (!result && event.getAction() == MotionEvent.ACTION_UP) { + performClick(); + } + result = true; + } + } return result || super.onTouchEvent(event); } @@ -272,6 +306,9 @@ public class BotHelpCell extends View { setMeasuredDimension(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), height + AndroidUtilities.dp(8)); } + private Drawable selectorDrawable; + private int selectorDrawableRadius; + @Override protected void onDraw(Canvas canvas) { int x = (getWidth() - width) / 2; @@ -294,6 +331,15 @@ public class BotHelpCell extends View { drawable.setBounds(x, 0, width + x, height); drawable.draw(canvas); + if (selectorDrawable != null) { + if (selectorDrawableRadius != SharedConfig.bubbleRadius) { + selectorDrawableRadius = SharedConfig.bubbleRadius; + Theme.setMaskDrawableRad(selectorDrawable, selectorDrawableRadius, selectorDrawableRadius); + } + selectorDrawable.setBounds(x + AndroidUtilities.dp(2), AndroidUtilities.dp(2), width + x - AndroidUtilities.dp(2), height - AndroidUtilities.dp(2)); + selectorDrawable.draw(canvas); + } + imageReceiver.setImageCoords(x + imagePadding, imagePadding, width - imagePadding * 2, photoHeight - imagePadding); imageReceiver.draw(canvas); @@ -301,8 +347,8 @@ public class BotHelpCell extends View { Theme.chat_msgTextPaint.linkColor = getThemedColor(Theme.key_chat_messageLinkIn); canvas.save(); canvas.translate(textX = AndroidUtilities.dp(isPhotoVisible ? 14 : 11) + x, textY = AndroidUtilities.dp(11) + y); - if (pressedLink != null) { - canvas.drawPath(urlPath, Theme.chat_urlPaint); + if (links.draw(canvas)) { + invalidate(); } if (textLayout != null) { textLayout.draw(canvas); @@ -349,4 +395,9 @@ public class BotHelpCell extends View { Drawable drawable = resourcesProvider != null ? resourcesProvider.getDrawable(drawableKey) : null; return drawable != null ? drawable : Theme.getThemeDrawable(drawableKey); } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == selectorDrawable || super.verifyDrawable(who); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java index abe0d94b8..cf0ddb654 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -14,6 +14,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; import android.text.Layout; @@ -125,6 +126,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } private boolean canDrawInParent; + private View invalidateWithParent; + + public void setInvalidateWithParent(View viewToInvalidate) { + invalidateWithParent = viewToInvalidate; + } public interface ChatActionCellDelegate { default void didClickImage(ChatActionCell cell) { @@ -397,37 +403,37 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD hasReplyMessage = messageObject.replyMessageObject != null; DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); previousWidth = 0; + imageReceiver.setAutoRepeatCount(0); if (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO) { imageReceiver.setRoundRadius((int) (stickerSize / 2f)); imageReceiver.setAllowStartLottieAnimation(true); imageReceiver.setDelegate(null); TLRPC.TL_messageActionSuggestProfilePhoto action = (TLRPC.TL_messageActionSuggestProfilePhoto) messageObject.messageOwner.action; + TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(action.photo.video_sizes, 1000); ImageLocation videoLocation; if (action.photo.video_sizes != null && !action.photo.video_sizes.isEmpty()) { - videoLocation = ImageLocation.getForPhoto(action.photo.video_sizes.get(0), action.photo); + videoLocation = ImageLocation.getForPhoto(videoSize, action.photo); } else { videoLocation = null; } TLRPC.Photo photo = messageObject.messageOwner.action.photo; - TLRPC.VideoSize videoSize = null; TLRPC.PhotoSize strippedPhotoSize = null; - for (int a = 0, N = messageObject.photoThumbs.size(); a < N; a++) { - TLRPC.PhotoSize photoSize = messageObject.photoThumbs.get(a); - if (photoSize instanceof TLRPC.TL_photoStrippedSize) { - strippedPhotoSize = photoSize; - break; + if (messageObject.strippedThumb == null) { + for (int a = 0, N = messageObject.photoThumbs.size(); a < N; a++) { + TLRPC.PhotoSize photoSize = messageObject.photoThumbs.get(a); + if (photoSize instanceof TLRPC.TL_photoStrippedSize) { + strippedPhotoSize = photoSize; + break; + } } } TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 1000); if (photoSize != null) { - if (!photo.video_sizes.isEmpty()) { - videoSize = photo.video_sizes.get(0); - } if (videoSize != null) { - imageReceiver.setImage(videoLocation, ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForPhoto(photoSize, photo), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", null, 0, null, messageObject, 0); + imageReceiver.setImage(videoLocation, ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForPhoto(photoSize, photo), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", messageObject.strippedThumb, 0, null, messageObject, 0); } else { - imageReceiver.setImage(ImageLocation.getForPhoto(photoSize, photo), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", null, 0, null, messageObject, 0); + imageReceiver.setImage(ImageLocation.getForPhoto(photoSize, photo), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", messageObject.strippedThumb, 0, null, messageObject, 0); } } @@ -527,17 +533,20 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD imageReceiver.setAllowStartLottieAnimation(true); imageReceiver.setDelegate(null); imageReceiver.setRoundRadius(AndroidUtilities.roundMessageSize / 2); + imageReceiver.setAutoRepeatCount(1); long id = messageObject.getDialogId(); avatarDrawable.setInfo(id, null, null); if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { imageReceiver.setImage(null, null, avatarDrawable, null, messageObject, 0); } else { TLRPC.PhotoSize strippedPhotoSize = null; - for (int a = 0, N = messageObject.photoThumbs.size(); a < N; a++) { - TLRPC.PhotoSize photoSize = messageObject.photoThumbs.get(a); - if (photoSize instanceof TLRPC.TL_photoStrippedSize) { - strippedPhotoSize = photoSize; - break; + if (messageObject.strippedThumb == null) { + for (int a = 0, N = messageObject.photoThumbs.size(); a < N; a++) { + TLRPC.PhotoSize photoSize = messageObject.photoThumbs.get(a); + if (photoSize instanceof TLRPC.TL_photoStrippedSize) { + strippedPhotoSize = photoSize; + break; + } } } TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 640); @@ -545,7 +554,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD TLRPC.Photo photo = messageObject.messageOwner.action.photo; TLRPC.VideoSize videoSize = null; if (!photo.video_sizes.isEmpty() && SharedConfig.autoplayGifs) { - videoSize = photo.video_sizes.get(0); + videoSize = FileLoader.getClosestVideoSizeWithSize(photo.video_sizes, 1000); if (!messageObject.mediaExists && !DownloadController.getInstance(currentAccount).canDownloadMedia(DownloadController.AUTODOWNLOAD_TYPE_VIDEO, videoSize.size)) { currentVideoLocation = ImageLocation.getForPhoto(videoSize, photo); String fileName = FileLoader.getAttachFileName(videoSize); @@ -554,9 +563,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } } if (videoSize != null) { - imageReceiver.setImage(ImageLocation.getForPhoto(videoSize, photo), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", avatarDrawable, 0, null, messageObject, 1); + imageReceiver.setImage(ImageLocation.getForPhoto(videoSize, photo), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", messageObject.strippedThumb, 0, null, messageObject, 1); } else { - imageReceiver.setImage(ImageLocation.getForObject(photoSize, messageObject.photoThumbsObject), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", avatarDrawable, 0, null, messageObject, 1); + imageReceiver.setImage(ImageLocation.getForObject(photoSize, messageObject.photoThumbsObject), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", messageObject.strippedThumb, 0, null, messageObject, 1); } } else { imageReceiver.setImageBitmap(avatarDrawable); @@ -844,6 +853,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } else { paint = (TextPaint) getThemedPaint(Theme.key_paint_chatActionText); } + paint.linkColor = paint.getColor(); textLayout = new StaticLayout(text, paint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); spoilersPool.addAll(spoilers); @@ -1511,4 +1521,28 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD private boolean isButtonLayout(MessageObject messageObject) { return messageObject != null && (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM || messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO); } + + @Override + public void invalidate() { + super.invalidate(); + if (invalidateWithParent != null) { + invalidateWithParent.invalidate(); + } + } + + @Override + public void invalidate(Rect dirty) { + super.invalidate(dirty); + if (invalidateWithParent != null) { + invalidateWithParent.invalidate(); + } + } + + @Override + public void invalidate(int l, int t, int r, int b) { + super.invalidate(l, t, r, b); + if (invalidateWithParent != null) { + invalidateWithParent.invalidate(); + } + } } 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 8f745cc92..882cd01be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -53,6 +53,7 @@ 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.Property; import android.util.SparseArray; import android.util.StateSet; @@ -155,6 +156,7 @@ import org.telegram.ui.Components.URLSpanBotCommand; import org.telegram.ui.Components.URLSpanBrowser; import org.telegram.ui.Components.URLSpanMono; import org.telegram.ui.Components.URLSpanNoUnderline; +import org.telegram.ui.Components.VectorAvatarThumbDrawable; import org.telegram.ui.Components.VideoForwardDrawable; import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.PhotoViewer; @@ -242,7 +244,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentPhoto = null; } avatarDrawable.setInfo(currentUser); - avatarImage.setForUserOrChat(currentUser, avatarDrawable, null, true); + avatarImage.setForUserOrChat(currentUser, avatarDrawable, null, true, VectorAvatarThumbDrawable.TYPE_SMALL); } else if (currentChat != null) { if (currentChat.photo != null) { currentPhoto = currentChat.photo.photo_small; @@ -1052,6 +1054,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private float replyTouchX, replyTouchY; private TLRPC.PhotoSize currentReplyPhoto; + private AnimatedFloat translationLoadingFloat; + private LinkPath translationLoadingPath; + private LoadingDrawable translationLoadingDrawable; + private ArrayList translationLoadingDrawableText; + private StaticLayout translationLoadingDrawableLayout; + private boolean drawTopic; private MessageTopicButton topicButton; @@ -1156,6 +1164,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private int lastViewsCount; private int lastRepliesCount; private float selectedBackgroundProgress; + private boolean lastTranslated; private float viewTop; private int backgroundHeight; @@ -3043,7 +3052,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate forwardBotPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - if (currentViaBotUser.bot_inline_placeholder == null) { + if (currentViaBotUser != null && currentViaBotUser.bot_inline_placeholder == null) { delegate.didPressViaBotNotInline(this, currentViaBotUser != null ? currentViaBotUser.id : 0); } else { delegate.didPressViaBot(this, currentViaBotUser != null ? currentViaBotUser.username : currentMessageObject.messageOwner.via_bot_name); @@ -3432,6 +3441,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate this.blurredViewTopOffset = blurredViewTopOffset; this.blurredViewBottomOffset = blurredViewBottomOffset; + if (!botButtons.isEmpty() && viewTop != visibleTop) { + invalidate(); + } viewTop = visibleTop; if (parent != parentHeight || parentOffset != this.parentViewTopOffset) { @@ -4081,7 +4093,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentMessageObject == messageObject && (isUserDataChanged() || photoNotSet) || lastPostAuthor != messageObject.messageOwner.post_author || wasPinned != isPinned || - newReply != lastReplyMessage; + newReply != lastReplyMessage || + messageObject.translated != lastTranslated; boolean groupChanged = groupedMessages != currentMessagesGroup; boolean pollChanged = false; @@ -4190,6 +4203,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.setCrossfadeDuration(ImageReceiver.DEFAULT_CROSSFADE_DURATION); photoImage.setCrossfadeByScale(0); photoImage.setGradientBitmap(null); + lastTranslated = messageObject.translated; lastSendState = messageObject.messageOwner.send_state; lastDeleteDate = messageObject.messageOwner.destroyTime; lastViewsCount = messageObject.messageOwner.views; @@ -4534,11 +4548,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate hasGamePreview = MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame && MessageObject.getMedia(messageObject.messageOwner).game instanceof TLRPC.TL_game; hasInvoicePreview = MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice; hasLinkPreview = !messageObject.isRestrictedMessage && MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage && MessageObject.getMedia(messageObject.messageOwner).webpage instanceof TLRPC.TL_webPage; + TLRPC.WebPage webpage = hasLinkPreview ? MessageObject.getMedia(messageObject.messageOwner).webpage : null; drawInstantView = hasLinkPreview && MessageObject.getMedia(messageObject.messageOwner).webpage.cached_page != null; String siteName = hasLinkPreview ? MessageObject.getMedia(messageObject.messageOwner).webpage.site_name : null; hasEmbed = hasLinkPreview && !TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).webpage.embed_url) && !messageObject.isGif() && !"instangram".equalsIgnoreCase(siteName); boolean slideshow = false; - String webpageType = hasLinkPreview ? MessageObject.getMedia(messageObject.messageOwner).webpage.type : null; + String webpageType = webpage != null ? webpage.type : null; TLRPC.Document androidThemeDocument = null; TLRPC.ThemeSettings androidThemeSettings = null; if (!drawInstantView) { @@ -4557,7 +4572,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if ("telegram_megagroup".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 2; - } else if ("telegram_message".equals(webpageType)) { + } else if ("telegram_message".equals(webpageType) || "photo".equals(webpageType) && webpage != null && webpage.url != null && Browser.isInternalUri(Uri.parse(webpage.url), null)) { drawInstantView = true; drawInstantViewType = 3; } else if ("telegram_theme".equals(webpageType)) { @@ -4868,6 +4883,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } boolean titleIsRTL = false; + if (!titleIsRTL && author != null) { + titleIsRTL = AndroidUtilities.isRTL(author); + } + if (!titleIsRTL && messageObject.linkDescription != null) { + titleIsRTL = AndroidUtilities.isRTL(messageObject.linkDescription); + } if (title != null) { try { titleX = Integer.MAX_VALUE; @@ -4915,9 +4936,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } catch (Exception e) { FileLog.e(e); } - if (titleIsRTL && isSmallImage) { - linkPreviewMaxWidth -= AndroidUtilities.dp(48); - } + } + if (titleIsRTL && isSmallImage) { + linkPreviewMaxWidth -= AndroidUtilities.dp(48); } boolean authorIsRTL = false; @@ -5649,7 +5670,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } - if (user != null) { + if (user != null || !TextUtils.isEmpty(messageObject.vCardData)) { drawInstantView = true; drawInstantViewType = 5; } @@ -7483,7 +7504,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int buttonWidth = (widthForButtons - AndroidUtilities.dp(5) * (buttonsCount - 1) - AndroidUtilities.dp(2)) / buttonsCount; for (int b = 0; b < row.buttons.size(); b++) { BotButton botButton = new BotButton(); - botButton.button = row.buttons.get(b); + TLRPC.TL_keyboardButtonRequestPeer button = new TLRPC.TL_keyboardButtonRequestPeer(); + button.button_id = 0; + button.text = "Request peer"; + button.peer_type = new TLRPC.TL_requestPeerTypeChat(); + ((TLRPC.TL_requestPeerTypeChat) button.peer_type).forum = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights = new TLRPC.TL_chatAdminRights(); +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.change_info = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.delete_messages = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.pin_messages = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.anonymous = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.post_messages = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).premium = false; +// botButton.button = button; + botButton.button = row.buttons.get(b); String key = Utilities.bytesToHex(botButton.button.data); String position = a + "" + b; BotButton oldButton; @@ -7671,6 +7705,17 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate statusDrawableAnimator.removeAllListeners(); statusDrawableAnimator.cancel(); } + if (translationLoadingFloat != null) { + translationLoadingFloat.set(0, true); + } + if (translationLoadingPath != null) { + translationLoadingPath.reset(); + translationLoadingPath = null; + } + if (translationLoadingDrawable != null) { + translationLoadingDrawable.reset(); + translationLoadingDrawable = null; + } transitionParams.lastStatusDrawableParams = -1; statusDrawableAnimationInProgress = false; @@ -8149,7 +8194,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (seekBarWaveform != null) { seekBarWaveform.setWaveform(waveform); } - useTranscribeButton = currentMessageObject != null && (!currentMessageObject.isOutOwner() || currentMessageObject.isSent()) && (UserConfig.getInstance(currentAccount).isPremium() || !MessagesController.getInstance(currentAccount).didPressTranscribeButtonEnough() && (currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionForce || currentMessageObject.getDuration() >= 60) && !MessagesController.getInstance(currentAccount).premiumLocked) && (currentMessageObject.isVoice() && useSeekBarWaveform || currentMessageObject.isRoundVideo()) && currentMessageObject.messageOwner != null && !(MessageObject.getMedia(currentMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage); + useTranscribeButton = ( + currentMessageObject != null && + (!currentMessageObject.isOutOwner() || currentMessageObject.isSent()) && + ( + UserConfig.getInstance(currentAccount).isPremium() || + !MessagesController.getInstance(currentAccount).didPressTranscribeButtonEnough() && ( + currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionForce || + currentMessageObject.getDuration() >= 60 + ) && !MessagesController.getInstance(currentAccount).premiumLocked + ) && ( + currentMessageObject.isVoice() && useSeekBarWaveform || + currentMessageObject.isRoundVideo() + ) && currentMessageObject.messageOwner != null && !(MessageObject.getMedia(currentMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage) + ); updateSeekBarWaveformWidth(null); } @@ -9346,11 +9404,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ); } } - drawMessageText(canvas, transitionParams.animateOutTextBlocks, false, (1.0f - transitionParams.animateChangeProgress), false); - drawMessageText(canvas, currentMessageObject.textLayoutBlocks, true, transitionParams.animateChangeProgress, false); + drawMessageText(canvas, transitionParams.animateOutTextBlocks, transitionParams.animateOutTextXOffset, false, (1.0f - transitionParams.animateChangeProgress), false); + drawMessageText(canvas, currentMessageObject.textLayoutBlocks, currentMessageObject.textXOffset, true, transitionParams.animateChangeProgress, false); canvas.restore(); } else { - drawMessageText(canvas, currentMessageObject.textLayoutBlocks, true, 1.0f, false); + drawMessageText(canvas, currentMessageObject.textLayoutBlocks, currentMessageObject.textXOffset, true, 1.0f, false); } } @@ -9369,7 +9427,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.drawCircle(photoImage.getCenterX(), photoImage.getCenterY(), photoImage.getImageWidth() / 2f, drillHolePaint); } if (isRoundVideo && ( - MediaController.getInstance().isPlayingMessage(currentMessageObject) && MediaController.getInstance().isVideoDrawingReady() && canvas.isHardwareAccelerated() && (currentMessageObject == null || !currentMessageObject.isVoiceTranscriptionOpen() || pipFloat >= 1) + MediaController.getInstance().isPlayingMessage(currentMessageObject) && + MediaController.getInstance().isVideoDrawingReady() && + canvas.isHardwareAccelerated() && + (currentMessageObject == null || !currentMessageObject.isVoiceTranscriptionOpen() || pipFloat >= 1) )) { imageDrawn = true; drawTime = true; @@ -9807,8 +9868,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { linkX = backgroundDrawableLeft + AndroidUtilities.dp(currentMessageObject.isOutOwner() ? 11 : 17); } - int startY = totalHeight - AndroidUtilities.dp(drawPinnedTop ? 9 : 10) - linkPreviewHeight - AndroidUtilities.dp(8); - int linkPreviewY = startY; + float startY = totalHeight - AndroidUtilities.dp(drawPinnedTop ? 9 : 10) - linkPreviewHeight - AndroidUtilities.dp(8); + float linkPreviewY = startY; Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewLine : Theme.key_chat_inPreviewLine)); AndroidUtilities.rectTmp.set(linkX, linkPreviewY - AndroidUtilities.dp(3), linkX + AndroidUtilities.dp(3), linkPreviewY + linkPreviewHeight); @@ -9850,7 +9911,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (linkPreviewY != startY) { linkPreviewY += AndroidUtilities.dp(2); } - descriptionY = linkPreviewY - AndroidUtilities.dp(3); + descriptionY = (int) linkPreviewY - AndroidUtilities.dp(3); canvas.save(); canvas.translate(linkX + AndroidUtilities.dp(10) + descriptionX, descriptionY); descriptionLayout.draw(canvas); @@ -10154,6 +10215,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate startY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(8); linkX = unmovedTextX + AndroidUtilities.dp(1); } + startY += (int) transitionParams.deltaBottom; int linkPreviewY = startY; int smallImageStartY = 0; @@ -10502,10 +10564,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } instantButtonRect.set(linkX, instantY, linkX + instantWidth, instantY + AndroidUtilities.dp(36)); - if (instantButtonLoading != null) { - instantButtonLoading.setBounds(instantButtonRect); - instantButtonLoading.setRadiiDp(6); - } if (instantButtonPressed && instantButtonPressProgress != 1f) { instantButtonPressProgress += (float) Math.min(40, 1000f / AndroidUtilities.screenRefreshRate) / 100f; instantButtonPressProgress = Utilities.clamp(instantButtonPressProgress, 1f, 0); @@ -10522,6 +10580,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate selectorDrawable[0].draw(canvas); } if (instantButtonLoading != null && !instantButtonLoading.isDisappeared()) { + instantButtonLoading.setBounds(instantButtonRect); + instantButtonLoading.setRadiiDp(6); instantButtonLoading.draw(canvas); invalidate(); } @@ -10546,7 +10606,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return currentMessagesGroup == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0; } - private void drawBotButtons(Canvas canvas, ArrayList botButtons, float alpha) { + private void drawBotButtons(Canvas canvas, ArrayList botButtons, int alpha) { int addX; if (currentMessageObject.isOutOwner()) { addX = getMeasuredWidth() - widthForButtons - AndroidUtilities.dp(10); @@ -10563,8 +10623,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } rect.set(0, top, getMeasuredWidth(), top + height); - if (alpha != 1f) { - canvas.saveLayerAlpha(rect, (int) (255 * alpha), Canvas.ALL_SAVE_FLAG); + if (alpha != 0xFF) { + canvas.saveLayerAlpha(rect, alpha, Canvas.ALL_SAVE_FLAG); } else { canvas.save(); } @@ -10612,14 +10672,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Theme.multAlpha(Theme.getColor(Theme.key_chat_serviceBackgroundSelector, resourcesProvider), 3f), Theme.multAlpha(Theme.getColor(Theme.key_chat_serviceBackgroundSelector, resourcesProvider), 10f) ); - button.loadingDrawable.setAlpha((int) (0xFF * alpha)); + button.loadingDrawable.setAlpha(0xFF); button.loadingDrawable.draw(canvas); invalidateOutbounds(); } if (button.selectorDrawable != null) { button.selectorDrawable.setBounds(button.x + addX, (int) y, button.x + addX + button.width, (int) y + button.height); - button.selectorDrawable.setAlpha((int) (0xFF * alpha)); + button.selectorDrawable.setAlpha(0xFF); button.selectorDrawable.draw(canvas); } @@ -10642,7 +10702,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int x = button.x + button.width - AndroidUtilities.dp(3) - drawable.getIntrinsicWidth() + addX; setDrawableBounds(drawable, x, y + AndroidUtilities.dp(3)); drawable.draw(canvas); - } else if (button.button instanceof TLRPC.TL_keyboardButtonSwitchInline) { + } else if (button.button instanceof TLRPC.TL_keyboardButtonSwitchInline || button.button instanceof TLRPC.TL_keyboardButtonRequestPeer) { Drawable drawable = getThemedDrawable(Theme.key_drawable_botInline); int x = button.x + button.width - AndroidUtilities.dp(3) - drawable.getIntrinsicWidth() + addX; setDrawableBounds(drawable, x, y + AndroidUtilities.dp(3)); @@ -10662,8 +10722,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return !currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0f || blurredPhotoImage.getBitmap() == null; } - @SuppressLint("Range") public void drawMessageText(Canvas canvas, ArrayList textLayoutBlocks, boolean origin, float alpha, boolean drawOnlyText) { + drawMessageText(canvas, textLayoutBlocks, currentMessageObject == null ? 0 : currentMessageObject.textXOffset, origin, alpha, drawOnlyText); + } + + @SuppressLint("Range") + public void drawMessageText(Canvas canvas, ArrayList textLayoutBlocks, float rtlOffset, boolean origin, float alpha, boolean drawOnlyText) { if (textLayoutBlocks == null || textLayoutBlocks.isEmpty() || alpha == 0) { return; } @@ -10685,6 +10749,62 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (transitionParams.animateText) { textY = transitionParams.animateFromTextY * (1f - transitionParams.animateChangeProgress) + this.textY * transitionParams.animateChangeProgress; } + + boolean translating = MessagesController.getInstance(currentAccount).getTranslateController().isTranslating(getMessageObject()); + if ((textLayoutBlocks == transitionParams.animateOutTextBlocks) == (currentMessageObject != null && currentMessageObject.translated)) { + if (translationLoadingFloat == null) { + translationLoadingFloat = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + } + float translationLoading = translationLoadingFloat.set(translating ? 1 : 0); + if (translationLoading > 0) { + if (translationLoadingDrawable == null) { + translationLoadingDrawable = new LoadingDrawable(); + translationLoadingDrawable.setAppearByGradient(true); + if (translationLoadingPath == null) { + translationLoadingPath = new LinkPath(true); + } + translationLoadingDrawable.usePath(translationLoadingPath); + translationLoadingDrawable.setRadiiDp(5); + + translationLoadingDrawable.reset(); + } + + if (translationLoadingDrawableText != textLayoutBlocks) { + translationLoadingDrawableText = textLayoutBlocks; + translationLoadingPath.reset(); + for (int i = 0; i < textLayoutBlocks.size(); ++i) { + MessageObject.TextLayoutBlock block = textLayoutBlocks.get(i); + if (block != null && block.textLayout != null) { + translationLoadingPath.setCurrentLayout(block.textLayout, 0, block.isRtl() ? rtlOffset : 0, block.textYOffset); + block.textLayout.getSelectionPath(0, block.textLayout.getText().length(), translationLoadingPath); + } + } + translationLoadingDrawable.updateBounds(); + } + + if (translating && (translationLoadingDrawable.isDisappearing() || translationLoadingDrawable.isDisappeared())) { + translationLoadingDrawable.reset(); + translationLoadingDrawable.resetDisappear(); + } else if (!translating && !translationLoadingDrawable.isDisappearing() && !translationLoadingDrawable.isDisappeared()) { + translationLoadingDrawable.disappear(); + } + + int color = getThemedColor(currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.key_chat_messageLinkOut : Theme.key_chat_messageLinkIn); + translationLoadingDrawable.setColors( + Theme.multAlpha(color, .05f), + Theme.multAlpha(color, .15f), + Theme.multAlpha(color, .1f), + Theme.multAlpha(color, .3f) + ); + canvas.save(); + canvas.translate(textX, textY + transitionYOffsetForDrawables); + translationLoadingDrawable.setAlpha((int) (0xFF * alpha * translationLoading)); + translationLoadingDrawable.draw(canvas); + canvas.restore(); + invalidate(); + } + } + if (firstVisibleBlockNum >= 0) { int restore = Integer.MIN_VALUE; int oldAlpha = 0; @@ -10725,7 +10845,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } MessageObject.TextLayoutBlock block = textLayoutBlocks.get(a); canvas.save(); - canvas.translate(textX - (block.isRtl() ? (int) Math.ceil(currentMessageObject.textXOffset) : 0), textY + block.textYOffset + transitionYOffsetForDrawables); + canvas.translate(textX - (block.isRtl() ? rtlOffset : 0), textY + block.textYOffset + transitionYOffsetForDrawables); if (a == linkBlockNum) { if (!drawOnlyText && links.draw(canvas)) { invalidate(); @@ -11022,10 +11142,26 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject); } - canStreamVideo = (currentMessageObject.isSent() || currentMessageObject.isForwarded()) && (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && autoDownload) && currentMessageObject.canStreamVideo() && !currentMessageObject.needDrawBluredPreview(); - if (SharedConfig.streamMedia && (int) currentMessageObject.getDialogId() != 0 && !currentMessageObject.isSecretMedia() && - (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || - canStreamVideo && currentPosition != null && ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0 || (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) == 0))) { + canStreamVideo = ( + (currentMessageObject.isSent() || currentMessageObject.isForwarded()) && + (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || + documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || + documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && autoDownload + ) && + currentMessageObject.canStreamVideo() && + !currentMessageObject.needDrawBluredPreview() + ); + if ( + SharedConfig.streamMedia && + (int) currentMessageObject.getDialogId() != 0 && + !currentMessageObject.isSecretMedia() && ( + documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || + canStreamVideo && currentPosition != null && ( + (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0 || + (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) == 0 + ) + ) + ) { hasMiniProgress = fileExists ? 1 : 2; fileExists = true; } @@ -11146,7 +11282,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); float setProgress = 0; if (!FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { - if (!currentMessageObject.loadingCancelled && (documentAttachType == 0 && autoDownload || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && MessageObject.isGifDocument(documentAttach, currentMessageObject.hasValidGroupId()) && autoDownload)) { + if ( + !currentMessageObject.loadingCancelled && autoDownload && ( + documentAttachType == 0 || + documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && MessageObject.isGifDocument(documentAttach, currentMessageObject.hasValidGroupId()) + ) + ) { buttonState = 1; } else { buttonState = 0; @@ -12663,6 +12804,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } stringFinalText = TextUtils.ellipsize(sb, Theme.chat_replyTextPaint, maxWidth, TextUtils.TruncateAt.END); + replyTextOffset = 0; replyTextLayout = new StaticLayout(stringFinalText, Theme.chat_replyTextPaint, maxWidth + AndroidUtilities.dp(10), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (replyTextLayout.getLineCount() > 0) { replyTextWidth += (int) Math.ceil(replyTextLayout.getLineWidth(0)) + AndroidUtilities.dp(8); @@ -12738,10 +12880,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private Object getAuthorStatus() { if (currentUser != null) { - if (currentUser.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - return ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).document_id; - } else if (currentUser.emoji_status instanceof TLRPC.TL_emojiStatus) { - return ((TLRPC.TL_emojiStatus) currentUser.emoji_status).document_id; + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(currentUser); + if (emojiStatusId != null) { + return emojiStatusId; } else if (currentUser.premium) { return ContextCompat.getDrawable(ApplicationLoader.applicationContext, R.drawable.msg_premium_liststar).mutate(); } @@ -13689,10 +13830,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (!transitionParams.transitionBotButtons.isEmpty() && transitionParams.animateBotButtonsChanged) { - drawBotButtons(canvas, transitionParams.transitionBotButtons, 1f - transitionParams.animateChangeProgress); + float t = transitionParams.animateChangeProgress; + t = MathUtils.clamp(1f - (float) Math.pow(t, 2f), 0f, 1f); + drawBotButtons(canvas, transitionParams.transitionBotButtons, (int) (0xFF * t)); } if (!botButtons.isEmpty()) { - drawBotButtons(canvas, botButtons, transitionParams.animateBotButtonsChanged ? transitionParams.animateChangeProgress : 1f); + drawBotButtons(canvas, botButtons, transitionParams.animateBotButtonsChanged ? (int) (0xFF * transitionParams.animateChangeProgress) : 0xFF); } drawSideButton(canvas); } @@ -14230,13 +14373,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { ax = backgroundDrawableLeft + transitionParams.deltaLeft + backgroundDrawableRight + AndroidUtilities.dp(22) + nameWidth - adminLayout.getLineWidth(0); } - } else if (!mediaBackground && currentMessageObject.isOutOwner()) { ax = backgroundDrawableLeft + backgroundDrawableRight - AndroidUtilities.dp(17) - adminLayout.getLineWidth(0); } else { ax = backgroundDrawableLeft + backgroundDrawableRight - AndroidUtilities.dp(11) - adminLayout.getLineWidth(0); } } + ax += transitionParams.deltaRight; canvas.translate(ax, nameY + AndroidUtilities.dp(0.5f)); if (transitionParams.animateSign) { Theme.chat_adminPaint.setAlpha((int) (Color.alpha(color) * transitionParams.animateChangeProgress)); @@ -14687,12 +14830,36 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate replyNameLayout.draw(canvas); canvas.restore(); } + int spoilersColor; + if (currentMessageObject != null && currentMessageObject.isOut() && !ChatObject.isChannelAndNotMegaGroup(currentMessageObject.getChatId(), currentAccount)) { + spoilersColor = getThemedColor(Theme.key_chat_outTimeText); + } else { + spoilersColor = Theme.chat_replyTextPaint.getColor(); + } + if (transitionParams.animateReplyTextLayout != null && transitionParams.animateChangeProgress < 1) { + canvas.save(); + canvas.clipRect(replySelectorRect); + + canvas.save(); + canvas.translate(forwardNameX + replyTextOffset - transitionParams.animateReplyTextOffset, replyStartY + Theme.chat_replyNamePaint.getTextSize() + AndroidUtilities.dp(5)); + int wasAlpha2 = Theme.chat_replyTextPaint.getAlpha(); + Theme.chat_replyTextPaint.setAlpha((int) (wasAlpha2 * (1f - transitionParams.animateChangeProgress))); + SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -AndroidUtilities.dp(2), spoilersPatchedReplyTextLayout, transitionParams.animateReplyTextLayout, replySpoilers, canvas, false); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, transitionParams.animateReplyTextLayout, transitionParams.animateOutAnimateEmojiReply, 0, replySpoilers, 0, 0, 0, alpha, Theme.chat_animatedEmojiTextColorFilter); + Theme.chat_replyTextPaint.setAlpha(wasAlpha2); + canvas.restore(); + } if (replyTextLayout != null) { canvas.save(); canvas.translate(forwardNameX, replyStartY + Theme.chat_replyNamePaint.getTextSize() + AndroidUtilities.dp(5)); - int spoilersColor = currentMessageObject.isOut() && !ChatObject.isChannelAndNotMegaGroup(currentMessageObject.getChatId(), currentAccount) ? getThemedColor(Theme.key_chat_outTimeText) : replyTextLayout.getPaint().getColor(); + int wasAlpha2 = Theme.chat_replyTextPaint.getAlpha(); + Theme.chat_replyTextPaint.setAlpha((int) (wasAlpha2 * (transitionParams.animateReplyTextLayout != null ? transitionParams.animateChangeProgress : 1))); SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -AndroidUtilities.dp(2), spoilersPatchedReplyTextLayout, replyTextLayout, replySpoilers, canvas, false); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, replyTextLayout, animatedEmojiReplyStack, 0, replySpoilers, 0, 0, 0, alpha, Theme.chat_animatedEmojiTextColorFilter); + Theme.chat_replyTextPaint.setAlpha(wasAlpha2); + canvas.restore(); + } + if (transitionParams.animateReplyTextLayout != null && transitionParams.animateChangeProgress < 1) { canvas.restore(); } @@ -15180,6 +15347,49 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } canvas.translate(captionX, captionY); + boolean translating = MessagesController.getInstance(currentAccount).getTranslateController().isTranslating(getMessageObject(), getCurrentMessagesGroup()); + if (true) { + if (translationLoadingFloat == null) { + translationLoadingFloat = new AnimatedFloat(((View) getParent()), 350, CubicBezierInterpolator.EASE_OUT_QUINT); + } + float translationLoading = translationLoadingFloat.set(translating ? 1 : 0); + if (translationLoading > 0) { + if (translationLoadingDrawable == null) { + translationLoadingDrawable = new LoadingDrawable(); + translationLoadingDrawable.setAppearByGradient(true); + if (translationLoadingPath == null) { + translationLoadingPath = new LinkPath(true); + } + translationLoadingDrawable.usePath(translationLoadingPath); + translationLoadingDrawable.setRadiiDp(5); + } + + if (translationLoadingDrawableLayout != captionLayout) { + translationLoadingDrawableLayout = captionLayout; + translationLoadingPath.setCurrentLayout(captionLayout, 0, 0); + captionLayout.getSelectionPath(0, captionLayout.getText().length(), translationLoadingPath); + translationLoadingDrawable.updateBounds(); + } + + if (translating && translationLoadingDrawable.isDisappearing() || translationLoadingDrawable.isDisappeared()) { + translationLoadingDrawable.reset(); + translationLoadingDrawable.resetDisappear(); + } else if (!translating && !translationLoadingDrawable.isDisappearing() && !translationLoadingDrawable.isDisappeared()) { + translationLoadingDrawable.disappear(); + } + + int color = getThemedColor(currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.key_chat_messageLinkOut : Theme.key_chat_messageLinkIn); + translationLoadingDrawable.setColors( + Theme.multAlpha(color, .05f), + Theme.multAlpha(color, .15f), + Theme.multAlpha(color, .1f), + Theme.multAlpha(color, .3f) + ); + translationLoadingDrawable.setAlpha((int) (0xFF * alpha * translationLoading)); + translationLoadingDrawable.draw(canvas); + invalidate(); + } + } if (links.draw(canvas)) { invalidate(); @@ -18557,8 +18767,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private ArrayList animateOutTextBlocks; private ArrayList lastDrawingTextBlocks; + private float animateOutTextXOffset; private AnimatedEmojiSpan.EmojiGroupedSpans animateOutAnimateEmoji; + private StaticLayout animateReplyTextLayout; + private AnimatedEmojiSpan.EmojiGroupedSpans animateOutAnimateEmojiReply; + private boolean animateEditedEnter; private StaticLayout animateEditedLayout; private StaticLayout animateTimeLayout; @@ -18611,6 +18825,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public float lastDrawingTextX; public float animateFromTextY; + public float lastTextXOffset; public int lastTopOffset; public boolean animateForwardedLayout; @@ -18624,6 +18839,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int animateForwardNameWidth; int lastForwardNameWidth; boolean animateBotButtonsChanged; + public StaticLayout lastDrawnReplyTextLayout; + + public int lastReplyTextXOffset; + public float animateReplyTextOffset; public void recordDrawingState() { wasDraw = true; @@ -18697,6 +18916,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate lastForwardNameWidth = forwardedNameWidth; lastBackgroundLeft = getCurrentBackgroundLeft(); lastBackgroundRight = currentBackgroundDrawable.getBounds().right; + lastTextXOffset = currentMessageObject.textXOffset; + + lastDrawnReplyTextLayout = replyTextLayout; + lastReplyTextXOffset = replyTextOffset; reactionsLayoutInBubble.recordDrawingState(); if (replyNameLayout != null) { @@ -18743,6 +18966,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!sameText) { animateMessageText = true; animateOutTextBlocks = lastDrawingTextBlocks; + animateOutTextXOffset = lastTextXOffset; animateOutAnimateEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animateOutAnimateEmoji, lastDrawingTextBlocks, true); animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animatedEmojiStack, currentMessageObject.textLayoutBlocks); changed = true; @@ -18750,6 +18974,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animatedEmojiStack, currentMessageObject.textLayoutBlocks); } } + if (replyTextLayout != lastDrawnReplyTextLayout) { + animateReplyTextLayout = lastDrawnReplyTextLayout; + animateReplyTextOffset = lastReplyTextXOffset; + animateOutAnimateEmojiReply = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, false, animateOutAnimateEmojiReply, true, lastDrawnReplyTextLayout); + changed = true; + } if (edited && !lastDrawingEdited && timeLayout != null) { String editedStr = LocaleController.getString("EditedMessage", R.string.EditedMessage); CharSequence text = timeLayout.getText(); @@ -18831,7 +19061,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate for (int i = 0; i < botButtons.size(); i++) { BotButton button1 = botButtons.get(i); BotButton button2 = lastDrawBotButtons.get(i); - if (button1.x != button2.x || button1.width != button2.width) { + if (button1.x != button2.x || button1.width != button2.width || button1.title != button2.title) { animateBotButtonsChanged = true; break; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java index 757e14bd0..c771bc688 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java @@ -257,11 +257,14 @@ public class CheckBoxCell extends FrameLayout { } public void setText(CharSequence text, String value, boolean checked, boolean divider) { + setText(text, value, checked, divider, false); + } + public void setText(CharSequence text, String value, boolean checked, boolean divider, boolean animated) { textView.setText(text); if (checkBoxRound != null) { - checkBoxRound.setChecked(checked, false); + checkBoxRound.setChecked(checked, animated); } else { - checkBoxSquare.setChecked(checked, false); + checkBoxSquare.setChecked(checked, animated); } valueTextView.setText(value); needDivider = divider; @@ -359,6 +362,10 @@ public class CheckBoxCell extends FrameLayout { } } + public CheckBox2 getCheckBoxRound() { + return checkBoxRound; + } + public void setSquareCheckBoxColor(String uncheckedColor, String checkedColor, String checkColor) { if (checkBoxSquare != null) { checkBoxSquare.setColors(uncheckedColor, checkedColor, checkColor); @@ -385,4 +392,12 @@ public class CheckBoxCell extends FrameLayout { Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null; return color != null ? color : Theme.getColor(key); } + + public void setIcon(int icon) { + checkBoxRound.setIcon(icon); + } + + public boolean hasIcon() { + return checkBoxRound.hasIcon(); + } } 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 d6a968ce9..33a9c48ae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -99,6 +99,7 @@ import org.telegram.ui.Components.TimerDrawable; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.URLSpanNoUnderlineBold; +import org.telegram.ui.Components.VectorAvatarThumbDrawable; import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.DialogsActivity; import org.telegram.ui.RightSlidingDialogContainer; @@ -932,6 +933,9 @@ public class DialogCell extends BaseCell { } } + if (message != null) { + message.updateTranslation(); + } CharSequence msgText = message != null ? message.messageText : null; if (msgText instanceof Spannable) { Spannable sp = new SpannableStringBuilder(msgText); @@ -1100,12 +1104,10 @@ public class DialogCell extends BaseCell { } drawPremium = MessagesController.getInstance(currentAccount).isPremiumUser(user) && UserConfig.getInstance(currentAccount).clientUserId != user.id && user.id != 0; if (drawPremium) { - if (user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { nameLayoutEllipsizeByGradient = true; - emojiStatus.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, false); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus) { - nameLayoutEllipsizeByGradient = true; - emojiStatus.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, false); + emojiStatus.set(emojiStatusId, false); } else { nameLayoutEllipsizeByGradient = true; emojiStatus.set(PremiumGradient.getInstance().premiumStarDrawableMini, false); @@ -1227,7 +1229,7 @@ public class DialogCell extends BaseCell { } } } else { - if (dialogsType == 3 && UserObject.isUserSelf(user)) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD && UserObject.isUserSelf(user)) { messageString = LocaleController.getString("SavedMessagesInfo", R.string.SavedMessagesInfo); showChecks = false; drawTime = false; @@ -1269,7 +1271,7 @@ public class DialogCell extends BaseCell { } if (lastMessageIsReaction) { - } else if (dialogsType == 2) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO) { if (chat != null) { if (ChatObject.isChannel(chat) && !chat.megagroup) { if (chat.participants_count != 0) { @@ -1300,7 +1302,7 @@ public class DialogCell extends BaseCell { drawCount2 = false; showChecks = false; drawTime = false; - } else if (dialogsType == 3 && UserObject.isUserSelf(user)) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD && UserObject.isUserSelf(user)) { messageString = LocaleController.getString("SavedMessagesInfo", R.string.SavedMessagesInfo); showChecks = false; drawTime = false; @@ -1599,7 +1601,7 @@ public class DialogCell extends BaseCell { promoDialog = false; MessagesController messagesController = MessagesController.getInstance(currentAccount); - if (dialogsType == 0 && messagesController.isPromoDialog(currentDialogId, true)) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT && messagesController.isPromoDialog(currentDialogId, true)) { drawPinBackground = true; promoDialog = true; if (messagesController.promoDialogType == MessagesController.PROMO_TYPE_PROXY) { @@ -1645,7 +1647,7 @@ public class DialogCell extends BaseCell { if (useMeForMyMessages) { nameString = LocaleController.getString("FromYou", R.string.FromYou); } else { - if (dialogsType == 3) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD) { drawPinBackground = true; } nameString = LocaleController.getString("SavedMessages", R.string.SavedMessages); @@ -2587,7 +2589,7 @@ public class DialogCell extends BaseCell { mentionCount = forumTopic.unread_mentions_count; reactionMentionCount = forumTopic.unread_reactions_count; } - if (dialogsType == 2) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO) { drawPin = false; } @@ -2599,12 +2601,10 @@ public class DialogCell extends BaseCell { } if (user != null && (mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0) { user = MessagesController.getInstance(currentAccount).getUser(user.id); - if (user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { nameLayoutEllipsizeByGradient = true; - emojiStatus.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, animated); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus) { - nameLayoutEllipsizeByGradient = true; - emojiStatus.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, animated); + emojiStatus.set(emojiStatusId, animated); } else { nameLayoutEllipsizeByGradient = true; emojiStatus.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); @@ -2774,7 +2774,7 @@ public class DialogCell extends BaseCell { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); avatarImage.setImage(null, null, avatarDrawable, null, user, 0); } else { - avatarImage.setForUserOrChat(user, avatarDrawable, null, true); + avatarImage.setForUserOrChat(user, avatarDrawable, null, true, VectorAvatarThumbDrawable.TYPE_SMALL); } } else if (chat != null) { avatarDrawable.setInfo(chat); @@ -3721,6 +3721,9 @@ public class DialogCell extends BaseCell { timerPaint.setShader(null); if (avatarImage.getBitmap() != null && !avatarImage.getBitmap().isRecycled()) { timerPaint.setColor(PremiumLockIconView.getDominantColor(avatarImage.getBitmap())); + } else if (avatarImage.getDrawable() instanceof VectorAvatarThumbDrawable){ + VectorAvatarThumbDrawable vectorAvatarThumbDrawable = (VectorAvatarThumbDrawable) avatarImage.getDrawable(); + timerPaint.setColor(vectorAvatarThumbDrawable.gradientTools.getAverageColor()); } else { timerPaint.setColor(avatarDrawable.getColor2()); } @@ -4572,6 +4575,9 @@ public class DialogCell extends BaseCell { applyName = false; stringBuilder = SpannableStringBuilder.valueOf(mess); } + if (applyThumbs) { + applyThumbs(stringBuilder); + } } else if (captionMessage != null && captionMessage.caption != null) { MessageObject message = captionMessage; CharSequence mess = message.caption.toString(); @@ -4784,6 +4790,10 @@ public class DialogCell extends BaseCell { public boolean update() { TLRPC.Dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(currentDialogId); if (dialog == null) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD && lastDrawnDialogId != currentDialogId) { + lastDrawnDialogId = currentDialogId; + return true; + } return false; } int messageHash = message == null ? 0 : message.getId(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java new file mode 100644 index 000000000..97b6678e8 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java @@ -0,0 +1,104 @@ +package org.telegram.ui.Cells; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.text.TextUtils; +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 androidx.annotation.NonNull; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.LayoutHelper; + +public class DialogsHintCell extends FrameLayout { + private LinearLayout contentView; + private TextView titleView; + private TextView messageView; + private ImageView chevronView; + + public DialogsHintCell(@NonNull Context context) { + super(context); + + setWillNotDraw(false); + setPadding(dp(16), dp(8), dp(16), dp(8)); + + contentView = new LinearLayout(context); + contentView.setOrientation(LinearLayout.VERTICAL); + contentView.setPadding(LocaleController.isRTL ? dp(24) : 0, 0, LocaleController.isRTL ? 0 : dp(24), 0); + addView(contentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + titleView = new TextView(context); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleView.setSingleLine(); + contentView.addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.TOP)); + + messageView = new TextView(context); + messageView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + messageView.setMaxLines(2); + messageView.setEllipsize(TextUtils.TruncateAt.END); + contentView.addView(messageView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.TOP)); + + chevronView = new ImageView(context); + chevronView.setImageResource(R.drawable.arrow_newchat); + chevronView.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText), PorterDuff.Mode.SRC_IN); + addView(chevronView, LayoutHelper.createFrame(16, 16, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL)); + + updateColors(); + } + + public void updateColors() { + titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + messageView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + setBackground(Theme.AdaptiveRipple.filledRect()); + } + + public void setText(CharSequence title, CharSequence subtitle) { + titleView.setText(title); + messageView.setText(subtitle); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1, Theme.dividerPaint); + } + + private int height; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + if (width <= 0) { + width = AndroidUtilities.displaySize.x; + } + contentView.measure( + MeasureSpec.makeMeasureSpec(width - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, MeasureSpec.AT_MOST) + ); + this.height = contentView.getMeasuredHeight() + getPaddingTop() + getPaddingBottom() + 1; + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + } + + public int height() { + if (getVisibility() != View.VISIBLE) { + return 0; + } + if (height <= 0) { + height = dp(72) + 1; + } + return height; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsRequestedEmptyCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsRequestedEmptyCell.java new file mode 100644 index 000000000..9db08bff4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsRequestedEmptyCell.java @@ -0,0 +1,177 @@ +package org.telegram.ui.Cells; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.StickerEmptyView; + +public class DialogsRequestedEmptyCell extends LinearLayout implements NotificationCenter.NotificationCenterDelegate { + + int currentAccount = UserConfig.selectedAccount; + BackupImageView stickerView; + TextView titleView; + TextView subtitleView; + TextView buttonView; + + public DialogsRequestedEmptyCell(Context context) { + super(context); + + setOrientation(VERTICAL); + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + LinearLayout linearLayout = new LinearLayout(context) { + Path path = new Path(); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + { + paint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + paint.setShadowLayer(dp(1.33f), 0, dp(.33f), 0x1e000000); + } + @Override + protected void onDraw(Canvas canvas) { + canvas.drawPath(path, paint); + super.onDraw(canvas); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + path.rewind(); + AndroidUtilities.rectTmp.set(AndroidUtilities.dp(12), AndroidUtilities.dp(6), getMeasuredWidth() - AndroidUtilities.dp(12), getMeasuredHeight() - AndroidUtilities.dp(12)); + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(10), AndroidUtilities.dp(10), Path.Direction.CW); + } + }; + linearLayout.setWillNotDraw(false); + linearLayout.setOrientation(VERTICAL); + linearLayout.setPadding(AndroidUtilities.dp(12 + 20), AndroidUtilities.dp(6 + 10), AndroidUtilities.dp(12 + 20), AndroidUtilities.dp(12 +20)); + + stickerView = new BackupImageView(context); + stickerView.setOnClickListener(e -> { + stickerView.getImageReceiver().startAnimation(); + }); + updateSticker(); + linearLayout.addView(stickerView, LayoutHelper.createLinear(130, 130, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); + + titleView = new TextView(context); + titleView.setGravity(Gravity.CENTER); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + linearLayout.addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 6, 0, 0)); + + subtitleView = new TextView(context); + subtitleView.setGravity(Gravity.CENTER); + subtitleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + subtitleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + linearLayout.addView(subtitleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 7, 0, 0)); + + buttonView = new TextView(context); + buttonView.setGravity(Gravity.CENTER); + buttonView.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 8)); + buttonView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + buttonView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + buttonView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + buttonView.setPadding(AndroidUtilities.dp(14), AndroidUtilities.dp(14), AndroidUtilities.dp(14), AndroidUtilities.dp(14)); + buttonView.setOnClickListener(e -> { + onButtonClick(); + }); + linearLayout.addView(buttonView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 18, 0, 0)); + + addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + set(null); + } + + protected void onButtonClick() { + + } + + public void set(TLRPC.RequestPeerType requestPeerType) { + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + titleView.setText(LocaleController.getString("NoSuchChannels", R.string.NoSuchChannels)); + subtitleView.setText(LocaleController.getString("NoSuchChannelsInfo", R.string.NoSuchChannelsInfo)); + buttonView.setVisibility(View.VISIBLE); + buttonView.setText(LocaleController.getString("CreateChannelForThis", R.string.CreateChannelForThis)); + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeChat) { + titleView.setText(LocaleController.getString("NoSuchGroups", R.string.NoSuchGroups)); + subtitleView.setText(LocaleController.getString("NoSuchGroupsInfo", R.string.NoSuchGroupsInfo)); + buttonView.setVisibility(View.VISIBLE); + buttonView.setText(LocaleController.getString("CreateGroupForThis", R.string.CreateGroupForThis)); + } else { + titleView.setText(LocaleController.getString("NoSuchUsers", R.string.NoSuchUsers)); + subtitleView.setText(LocaleController.getString("NoSuchUsersInfo", R.string.NoSuchUsersInfo)); + buttonView.setVisibility(View.GONE); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.diceStickersDidLoad); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.diceStickersDidLoad); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.diceStickersDidLoad) { + String name = (String) args[0]; + if (AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME.equals(name) && getVisibility() == VISIBLE) { + updateSticker(); + } + } + } + + private void updateSticker() { + final int stickerType = StickerEmptyView.STICKER_TYPE_SEARCH; + + TLRPC.Document document = null; + TLRPC.TL_messages_stickerSet set = MediaDataController.getInstance(currentAccount).getStickerSetByName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME); + if (set == null) { + set = MediaDataController.getInstance(currentAccount).getStickerSetByEmojiOrName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME); + } + if (set != null && stickerType >= 0 && stickerType < set.documents.size() ) { + document = set.documents.get(stickerType); + } + + if (document != null) { + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundGray, 0.2f); + if (svgThumb != null) { + svgThumb.overrideWidthAndHeight(512, 512); + } + + ImageLocation imageLocation = ImageLocation.getForDocument(document); + stickerView.setImage(imageLocation, "130_130", "tgs", svgThumb, set); + stickerView.getImageReceiver().setAutoRepeat(2); + } else { + MediaDataController.getInstance(currentAccount).loadStickersByEmojiOrName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME, false, set == null); + stickerView.getImageReceiver().clearImage(); + } + } + +} 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 b2e8003ef..e6704d144 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java @@ -14,11 +14,8 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.RectF; import android.graphics.drawable.Drawable; -import android.util.TypedValue; import android.view.Gravity; -import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; -import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -49,18 +46,22 @@ public class DrawerActionCell extends FrameLayout { imageView = new ImageView(context); addView(imageView, LayoutHelper.createFrame(24, 24, Gravity.LEFT | Gravity.TOP, 19, 12, 0, 0)); +// addView(imageView, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 19, 12, LocaleController.isRTL ? 19 : 0, 0)); lottieImageView = new RLottieImageView(context); lottieImageView.setAutoRepeat(false); lottieImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_menuItemIcon), PorterDuff.Mode.SRC_IN)); addView(lottieImageView, LayoutHelper.createFrame(28, 28, Gravity.LEFT | Gravity.TOP, 17, 10, 0, 0)); +// addView(lottieImageView, LayoutHelper.createFrame(28, 28, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 17, 10, LocaleController.isRTL ? 17 : 0, 0)); textView = new AnimatedTextView(context, true, true, true); textView.setAnimationProperties(.6f, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); textView.setTextColor(Theme.getColor(Theme.key_chats_menuItemText)); textView.setTextSize(AndroidUtilities.dp(15)); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setIgnoreRTL(true); addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 19 + 24 + 29, 0, 16, 0)); +// addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 16 : 62, 0, LocaleController.isRTL ? 62 : 16, 0)); setWillNotDraw(false); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java index 12e6752ee..f7c14a92a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java @@ -100,7 +100,7 @@ public class DrawerProfileCell extends FrameLayout implements NotificationCenter private float stateX, stateY; StarParticlesView.Drawable starParticlesDrawable; - PremiumGradient.GradientTools gradientTools; + PremiumGradient.PremiumGradientTools gradientTools; public DrawerProfileCell(Context context, DrawerLayoutContainer drawerLayoutContainer) { super(context); @@ -587,7 +587,7 @@ public class DrawerProfileCell extends FrameLayout implements NotificationCenter drawPremiumProgress = Utilities.clamp(drawPremiumProgress, 1f, 0); if (drawPremiumProgress != 0) { if (gradientTools == null) { - gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradientBottomSheet1, Theme.key_premiumGradientBottomSheet2, Theme.key_premiumGradientBottomSheet3, null); + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradientBottomSheet1, Theme.key_premiumGradientBottomSheet2, Theme.key_premiumGradientBottomSheet3, null); gradientTools.x1 = 0; gradientTools.y1 = 1.1f; gradientTools.x2 = 1.5f; @@ -655,14 +655,11 @@ public class DrawerProfileCell extends FrameLayout implements NotificationCenter drawPremium = false;//user.premium; nameTextView.setText(text); - if (user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { animatedStatus.animate().alpha(1).setDuration(200).start(); nameTextView.setDrawablePadding(AndroidUtilities.dp(4)); - status.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, true); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus) { - animatedStatus.animate().alpha(1).setDuration(200).start(); - nameTextView.setDrawablePadding(AndroidUtilities.dp(4)); - status.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, true); + status.set(emojiStatusId, true); } else if (user.premium) { animatedStatus.animate().alpha(1).setDuration(200).start(); nameTextView.setDrawablePadding(AndroidUtilities.dp(4)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java index 1557a7847..120e1c095 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java @@ -10,7 +10,6 @@ package org.telegram.ui.Cells; import android.content.Context; import android.graphics.Canvas; -import android.graphics.Path; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.view.Gravity; @@ -25,6 +24,7 @@ import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; @@ -139,13 +139,10 @@ public class DrawerUserCell extends FrameLayout implements NotificationCenter.No text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); } catch (Exception ignore) {} textView.setText(text); - if (user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { textView.setDrawablePadding(AndroidUtilities.dp(4)); - status.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, true); - textView.setRightDrawableOutside(true); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus) { - textView.setDrawablePadding(AndroidUtilities.dp(4)); - status.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, true); + status.set(emojiStatusId, true); textView.setRightDrawableOutside(true); } else if (MessagesController.getInstance(account).isPremiumUser(user)) { textView.setDrawablePadding(AndroidUtilities.dp(6)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java index 4dc1997c0..13e155852 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java @@ -289,44 +289,42 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No } nameLockTop = AndroidUtilities.dp(22.0f); updateStatus(false, null, false); - } else { - if (chat != null) { - dialog_id = -chat.id; - drawCheck = chat.verified; - if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); - } else { - nameLeft = AndroidUtilities.dp(11); - } - updateStatus(drawCheck, null, false); - } else if (user != null) { - dialog_id = user.id; - if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); - } else { - nameLeft = AndroidUtilities.dp(11); - } - nameLockTop = AndroidUtilities.dp(21); - drawCheck = user.verified; - drawPremium = !user.self && MessagesController.getInstance(currentAccount).isPremiumUser(user); - updateStatus(drawCheck, user, false); - } else if (contact != null) { - if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); - } else { - nameLeft = AndroidUtilities.dp(11); - } - if (actionButton == null) { - actionButton = new CanvasButton(this); - actionButton.setDelegate(() -> { - if (getParent() instanceof RecyclerListView) { - RecyclerListView parent = (RecyclerListView) getParent(); - parent.getOnItemClickListener().onItemClick(this, parent.getChildAdapterPosition(this)); - } else { - callOnClick(); - } - }); - } + } else if (chat != null) { + dialog_id = -chat.id; + drawCheck = chat.verified; + if (!LocaleController.isRTL) { + nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); + } else { + nameLeft = AndroidUtilities.dp(11); + } + updateStatus(drawCheck, null, false); + } else if (user != null) { + dialog_id = user.id; + if (!LocaleController.isRTL) { + nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); + } else { + nameLeft = AndroidUtilities.dp(11); + } + nameLockTop = AndroidUtilities.dp(21); + drawCheck = user.verified; + drawPremium = !savedMessages && MessagesController.getInstance(currentAccount).isPremiumUser(user); + updateStatus(drawCheck, user, false); + } else if (contact != null) { + if (!LocaleController.isRTL) { + nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); + } else { + nameLeft = AndroidUtilities.dp(11); + } + if (actionButton == null) { + actionButton = new CanvasButton(this); + actionButton.setDelegate(() -> { + if (getParent() instanceof RecyclerListView) { + RecyclerListView parent = (RecyclerListView) getParent(); + parent.getOnItemClickListener().onItemClick(this, parent.getChildAdapterPosition(this)); + } else { + callOnClick(); + } + }); } } @@ -548,13 +546,13 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No if (verified) { statusDrawable.set(new CombinedDrawable(Theme.dialogs_verifiedDrawable, Theme.dialogs_verifiedCheckDrawable, 0, 0), animated); statusDrawable.setColor(null); - } else if (user != null && !user.self && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + } else if (user != null && !savedMessages && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { statusDrawable.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, animated); statusDrawable.setColor(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider)); - } else if (user != null && !user.self && user.emoji_status instanceof TLRPC.TL_emojiStatus) { + } else if (user != null && !savedMessages && user.emoji_status instanceof TLRPC.TL_emojiStatus) { statusDrawable.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, animated); statusDrawable.setColor(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider)); - } else if (user != null && !user.self && MessagesController.getInstance(currentAccount).isPremiumUser(user)) { + } else if (user != null && !savedMessages && MessagesController.getInstance(currentAccount).isPremiumUser(user)) { statusDrawable.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); statusDrawable.setColor(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider)); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RequestPeerRequirementsCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RequestPeerRequirementsCell.java new file mode 100644 index 000000000..04cf51d80 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RequestPeerRequirementsCell.java @@ -0,0 +1,297 @@ +package org.telegram.ui.Cells; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.LayoutHelper; + +import java.util.ArrayList; + +public class RequestPeerRequirementsCell extends LinearLayout { + + public RequestPeerRequirementsCell(Context context) { + super(context); + + setOrientation(VERTICAL); + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + } + + private TLRPC.RequestPeerType requestPeerType; + private ArrayList requirements = new ArrayList<>(); + + public void set(TLRPC.RequestPeerType requestPeerType) { + if (this.requestPeerType != requestPeerType) { + this.requestPeerType = requestPeerType; + removeAllViews(); + + requirements.clear(); + + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeUser) { + TLRPC.TL_requestPeerTypeUser type = (TLRPC.TL_requestPeerTypeUser) requestPeerType; + checkRequirement( + type.premium, + R.string.PeerRequirementPremiumTrue, + R.string.PeerRequirementPremiumFalse + ); + } else { + boolean isChannel = requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast; + + if (isChannel) { + checkRequirement(requestPeerType.has_username, R.string.PeerRequirementChannelPublicTrue, R.string.PeerRequirementChannelPublicFalse); + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PeerRequirementChannelBotParticipant)))); + } + if (requestPeerType.creator != null && requestPeerType.creator) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PeerRequirementChannelCreatorTrue)))); + } + } else { + checkRequirement(requestPeerType.has_username, R.string.PeerRequirementGroupPublicTrue, R.string.PeerRequirementGroupPublicFalse); + checkRequirement(requestPeerType.forum, R.string.PeerRequirementForumTrue, R.string.PeerRequirementForumFalse); + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PeerRequirementGroupBotParticipant)))); + } + if (requestPeerType.creator != null && requestPeerType.creator) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PeerRequirementGroupCreatorTrue)))); + } + } + + if (!(requestPeerType.creator != null && requestPeerType.creator)) { + checkAdminRights(requestPeerType.user_admin_rights, isChannel, R.string.PeerRequirementUserRights, R.string.PeerRequirementUserRight); + } +// checkAdminRights(requestPeerType.bot_admin_rights, isChannel, R.string.PeerRequirementBotRights, R.string.PeerRequirementBotRight); + } + + if (!requirements.isEmpty()) { + HeaderCell headerCell = new HeaderCell(getContext(), 20); + headerCell.setText(LocaleController.getString("PeerRequirements", R.string.PeerRequirements)); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + addView(headerCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + addView(emptyView(9, Theme.getColor(Theme.key_windowBackgroundWhite)), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + for (Requirement requirement : requirements) { + addView(new RequirementCell(getContext(), requirement), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + addView(emptyView(12, Theme.getColor(Theme.key_windowBackgroundWhite)), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + addView(emptyView(12, Theme.getThemedDrawable(getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + } + } + + private View emptyView(int heightDp, int color) { + return emptyView(heightDp, new ColorDrawable(color)); + } + + private View emptyView(int heightDp, Drawable background) { + View view = new View(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(heightDp), MeasureSpec.EXACTLY)); + } + }; + view.setBackground(background); + return view; + } + + private void checkRequirement(Boolean value, String positive, String negative) { + if (value != null) { + if (value) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(positive))); + } else { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(negative))); + } + } + } + + private void checkRequirement(Boolean value, int positiveResId, int negativeResId) { + if (value != null) { + if (value) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(positiveResId)))); + } else { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(negativeResId)))); + } + } + } + + public static CharSequence rightsToString(TLRPC.TL_chatAdminRights rights, boolean isChannel) { + ArrayList array = new ArrayList<>(); + if (rights.change_info) { + array.add(Requirement.make( + 1, + isChannel ? + LocaleController.getString("EditAdminChangeChannelInfo", R.string.EditAdminChangeChannelInfo) : + LocaleController.getString("EditAdminChangeGroupInfo", R.string.EditAdminChangeGroupInfo) + )); + } + if (rights.post_messages && isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminPostMessages", R.string.EditAdminPostMessages))); + } + if (rights.edit_messages && isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminEditMessages", R.string.EditAdminEditMessages))); + } + if (rights.delete_messages) { + array.add(Requirement.make(1, isChannel ? LocaleController.getString("EditAdminDeleteMessages", R.string.EditAdminDeleteMessages) : LocaleController.getString("EditAdminGroupDeleteMessages", R.string.EditAdminGroupDeleteMessages))); + } + if (rights.ban_users && !isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminBanUsers", R.string.EditAdminBanUsers))); + } + if (rights.invite_users) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminAddUsers", R.string.EditAdminAddUsers))); + } + if (rights.pin_messages && !isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminPinMessages", R.string.EditAdminPinMessages))); + } + if (rights.add_admins) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminAddAdmins", R.string.EditAdminAddAdmins))); + } + if (rights.anonymous && !isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminSendAnonymously", R.string.EditAdminSendAnonymously))); + } + if (rights.manage_call) { + array.add(Requirement.make(1, LocaleController.getString("StartVoipChatPermission", R.string.StartVoipChatPermission))); + } + if (rights.manage_topics && !isChannel) { + array.add(Requirement.make(1, LocaleController.getString("ManageTopicsPermission", R.string.ManageTopicsPermission))); + } + + if (array.size() == 1) { + return array.get(0).text.toString().toLowerCase(); + } else if (!array.isEmpty()) { + SpannableStringBuilder string = new SpannableStringBuilder(); + for (int i = 0; i < array.size(); ++i) { + if (i > 0) { + string.append(", "); + } + string.append(array.get(i).text.toString().toLowerCase()); + } + return string; + } + return ""; + } + + private void checkAdminRights(TLRPC.TL_chatAdminRights value, boolean isChannel, CharSequence headerText, CharSequence headerSingleText) { + if (value == null) { + return; + } + + ArrayList rights = new ArrayList<>(); + if (value.change_info) { + rights.add(Requirement.make( + 1, + isChannel ? + LocaleController.getString("EditAdminChangeChannelInfo", R.string.EditAdminChangeChannelInfo) : + LocaleController.getString("EditAdminChangeGroupInfo", R.string.EditAdminChangeGroupInfo) + )); + } + if (value.post_messages && isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminPostMessages", R.string.EditAdminPostMessages))); + } + if (value.edit_messages && isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminEditMessages", R.string.EditAdminEditMessages))); + } + if (value.delete_messages) { + rights.add(Requirement.make(1, isChannel ? LocaleController.getString("EditAdminDeleteMessages", R.string.EditAdminDeleteMessages) : LocaleController.getString("EditAdminGroupDeleteMessages", R.string.EditAdminGroupDeleteMessages))); + } + if (value.ban_users && !isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminBanUsers", R.string.EditAdminBanUsers))); + } + if (value.invite_users) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminAddUsers", R.string.EditAdminAddUsers))); + } + if (value.pin_messages && !isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminPinMessages", R.string.EditAdminPinMessages))); + } + if (value.add_admins) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminAddAdmins", R.string.EditAdminAddAdmins))); + } + if (value.anonymous && !isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminSendAnonymously", R.string.EditAdminSendAnonymously))); + } + if (value.manage_call) { + rights.add(Requirement.make(1, LocaleController.getString("StartVoipChatPermission", R.string.StartVoipChatPermission))); + } + if (value.manage_topics && !isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("ManageTopicsPermission", R.string.ManageTopicsPermission))); + } + + if (rights.size() == 1) { + requirements.add(Requirement.make(TextUtils.concat(headerSingleText, " ", rights.get(0).text))); + } else if (!rights.isEmpty()) { + SpannableStringBuilder string = SpannableStringBuilder.valueOf(headerText); + string.append(" "); + for (int i = 0; i < rights.size(); ++i) { + if (i > 0) { + string.append(", "); + } + string.append(rights.get(i).text.toString().toLowerCase()); + } + string.append("."); + requirements.add(Requirement.make(string)); + } + } + + private void checkAdminRights(TLRPC.TL_chatAdminRights value, boolean isChannel, int headerTextResId, int headerSingleTextResId) { + checkAdminRights(value, isChannel, AndroidUtilities.replaceTags(LocaleController.getString(headerTextResId)), AndroidUtilities.replaceTags(LocaleController.getString(headerSingleTextResId))); + } + + class RequirementCell extends LinearLayout { + + private ImageView imageView; + private TextView textView; + + public RequirementCell(Context context, Requirement requirement) { + super(context); + + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + + setOrientation(HORIZONTAL); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setImageResource(requirement.padding <= 0 ? R.drawable.list_check : R.drawable.list_circle); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader), PorterDuff.Mode.MULTIPLY)); + addView(imageView, LayoutHelper.createLinear(20, 20, 0, Gravity.TOP | Gravity.LEFT, 17 + requirement.padding * 16, -1, 0, 0)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); + textView.setSingleLine(false); + textView.setText(requirement.text); + addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1, 6, 4, 24, 4)); + } + } +} + +class Requirement { + public int padding; + public CharSequence text; + + private Requirement(CharSequence text, int padding) { + this.text = text; + this.padding = padding; + } + + public static Requirement make(CharSequence text) { + return new Requirement(text, 0); + } + + public static Requirement make(int pad, CharSequence text) { + return new Requirement(text, pad); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java index 989cc7999..fff78f7d7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java @@ -255,6 +255,9 @@ public class SharedPhotoVideoCell2 extends View { public void setVideoText(String videoText, boolean drawVideoIcon) { this.videoText = videoText; showVideoLayout = videoText != null; + if (showVideoLayout && videoInfoLayot != null && !videoInfoLayot.getText().toString().equals(videoText)) { + videoInfoLayot = null; + } this.drawVideoIcon = drawVideoIcon; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetNameCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetNameCell.java index cdd874190..dc33dbff6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetNameCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetNameCell.java @@ -75,9 +75,9 @@ public class StickerSetNameCell extends FrameLayout { } } if (supportRtl) { - lp = LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, emoji ? 5 : 17, emoji ? 10 : 2, emoji ? 15 : 57, 0); + lp = LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, emoji ? 5 : 17, emoji ? 5 : 2, emoji ? 15 : 57, 0); } else { - lp = LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, emoji ? 5 : 17, emoji ? 10 : 2, emoji ? 15 : 57, 0); + lp = LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, emoji ? 5 : 17, emoji ? 5 : 2, emoji ? 15 : 57, 0); } addView(textView, lp); @@ -97,10 +97,14 @@ public class StickerSetNameCell extends FrameLayout { buttonView = new ImageView(context); buttonView.setScaleType(ImageView.ScaleType.CENTER); buttonView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiPanelStickerSetNameIcon), PorterDuff.Mode.MULTIPLY)); + buttonView.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_CIRCLE_TO_BOUND_EDGE)); if (supportRtl) { - lp = LayoutHelper.createFrameRelatively(24, 24, Gravity.TOP | Gravity.END, 0, 0, 11, 0); + lp = LayoutHelper.createFrameRelatively(24, 24, Gravity.TOP | Gravity.END, 0, 0, isEmoji ? 0 : 11, 0); } else { - lp = LayoutHelper.createFrame(24, 24, Gravity.TOP | Gravity.RIGHT, 0, 0, 11, 0); + lp = LayoutHelper.createFrame(24, 24, Gravity.TOP | Gravity.RIGHT, 0, 0, isEmoji ? 0 : 11, 0); + } + if (isEmoji) { + buttonView.setTranslationY(AndroidUtilities.dp(4)); } addView(buttonView, lp); } @@ -191,7 +195,7 @@ public class StickerSetNameCell extends FrameLayout { if (empty) { super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(1, MeasureSpec.EXACTLY)); } else { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(isEmoji ? 32 : 24), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(isEmoji ? 27 : 24), MeasureSpec.EXACTLY)); } } 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 70771dab0..6eed7d6ce 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java @@ -37,6 +37,7 @@ public class TextCell extends FrameLayout { public final SimpleTextView textView; private final SimpleTextView subtitleView; public final AnimatedTextView valueTextView; + public final SimpleTextView valueSpoilersTextView; public final RLottieImageView imageView; private Switch checkBox; private ImageView valueImageView; @@ -88,14 +89,24 @@ public class TextCell extends FrameLayout { subtitleView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); addView(subtitleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT)); - valueTextView = new AnimatedTextView(context); + valueTextView = new AnimatedTextView(context, false, false, true); valueTextView.setTextColor(Theme.getColor(dialog ? Theme.key_dialogTextBlue2 : Theme.key_windowBackgroundWhiteValueText, resourcesProvider)); valueTextView.setPadding(0, AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18)); valueTextView.setTextSize(AndroidUtilities.dp(16)); valueTextView.setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); valueTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + valueTextView.setTranslationY(AndroidUtilities.dp(-2)); addView(valueTextView); + valueSpoilersTextView = new SimpleTextView(context); + valueSpoilersTextView.setEllipsizeByGradient(18, false); + valueSpoilersTextView.setTextColor(Theme.getColor(dialog ? Theme.key_dialogTextBlue2 : Theme.key_windowBackgroundWhiteValueText, resourcesProvider)); + valueSpoilersTextView.setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + valueSpoilersTextView.setTextSize(16); + valueSpoilersTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + valueSpoilersTextView.setVisibility(GONE); + addView(valueSpoilersTextView); + imageView = new RLottieImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER); imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(dialog ? Theme.key_dialogIcon : Theme.key_windowBackgroundWhiteGrayIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); @@ -143,8 +154,10 @@ public class TextCell extends FrameLayout { } public void setPrioritizeTitleOverValue(boolean prioritizeTitleOverValue) { - this.prioritizeTitleOverValue = prioritizeTitleOverValue; - requestLayout(); + if (this.prioritizeTitleOverValue != prioritizeTitleOverValue) { + this.prioritizeTitleOverValue = prioritizeTitleOverValue; + requestLayout(); + } } @Override @@ -152,14 +165,18 @@ public class TextCell extends FrameLayout { int width = MeasureSpec.getSize(widthMeasureSpec); int height = AndroidUtilities.dp(heightDp); + int valueWidth; if (prioritizeTitleOverValue) { textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); subtitleView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); valueTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(103 + leftPadding) - textView.getTextWidth(), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + valueSpoilersTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(103 + leftPadding) - textView.getTextWidth(), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); } else { valueTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(leftPadding), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding) - valueTextView.width(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - subtitleView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding) - valueTextView.width(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + valueSpoilersTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(leftPadding), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + valueWidth = Math.max(valueTextView.width(), valueSpoilersTextView.getTextWidth()); + textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding) - valueWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + subtitleView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding) - valueWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); } if (imageView.getVisibility() == VISIBLE) { imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); @@ -186,13 +203,14 @@ public class TextCell extends FrameLayout { int height = bottom - top; int width = right - left; - int viewTop = (height - valueTextView.getTextHeight()) / 2; + int viewTop = (height - Math.max(valueSpoilersTextView.getTextHeight(), valueTextView.getTextHeight())) / 2; int viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(leftPadding) : 0; if (prioritizeTitleOverValue && !LocaleController.isRTL) { - viewLeft = width - valueTextView.getMeasuredWidth() - AndroidUtilities.dp(leftPadding); + viewLeft = width - valueTextView.getMeasuredWidth() - AndroidUtilities.dp(leftPadding); } valueTextView.layout(viewLeft, viewTop, viewLeft + valueTextView.getMeasuredWidth(), viewTop + valueTextView.getMeasuredHeight()); - + viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(leftPadding) : width - valueSpoilersTextView.getMeasuredWidth() - AndroidUtilities.dp(leftPadding); + valueSpoilersTextView.layout(viewLeft, viewTop, viewLeft + valueSpoilersTextView.getMeasuredWidth(), viewTop + valueSpoilersTextView.getMeasuredHeight()); if (LocaleController.isRTL) { viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? offsetFromImage : leftPadding); @@ -245,6 +263,7 @@ public class TextCell extends FrameLayout { valueTextView.setText(null, false); imageView.setVisibility(GONE); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); needDivider = divider; setWillNotDraw(!needDivider); @@ -258,12 +277,25 @@ public class TextCell extends FrameLayout { imageView.setImageResource(resId); imageView.setVisibility(VISIBLE); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); needDivider = divider; setWillNotDraw(!needDivider); } + public void setTextAndColorfulIcon(String text, int resId, int color, boolean divider) { + imageLeft = 21; + offsetFromImage = 71; + textView.setText(text); + valueTextView.setText(null, false); + setColorfulIcon(color, resId); + valueTextView.setVisibility(GONE); + valueImageView.setVisibility(GONE); + needDivider = divider; + setWillNotDraw(!needDivider); + } + public void setTextAndIcon(String text, Drawable drawable, boolean divider) { offsetFromImage = 68; imageLeft = 18; @@ -301,6 +333,7 @@ public class TextCell extends FrameLayout { textView.setText(text); valueTextView.setText(value, animated); valueTextView.setVisibility(VISIBLE); + valueSpoilersTextView.setVisibility(GONE); imageView.setVisibility(GONE); valueImageView.setVisibility(GONE); needDivider = divider; @@ -310,6 +343,38 @@ public class TextCell extends FrameLayout { } } + public void setTextAndValueAndColorfulIcon(String text, CharSequence value, boolean animated, int resId, int color, boolean divider) { + imageLeft = 21; + offsetFromImage = 71; + textView.setText(text); + valueTextView.setText(value, animated); + valueTextView.setVisibility(VISIBLE); + valueSpoilersTextView.setVisibility(GONE); + setColorfulIcon(color, resId); + valueImageView.setVisibility(GONE); + needDivider = divider; + setWillNotDraw(!needDivider); + if (checkBox != null) { + checkBox.setVisibility(GONE); + } + } + + public void setTextAndSpoilersValueAndColorfulIcon(String text, CharSequence value, int resId, int color, boolean divider) { + imageLeft = 21; + offsetFromImage = 71; + textView.setText(text); + valueSpoilersTextView.setVisibility(VISIBLE); + valueSpoilersTextView.setText(value); + valueTextView.setVisibility(GONE); + setColorfulIcon(color, resId); + valueImageView.setVisibility(GONE); + needDivider = divider; + setWillNotDraw(!needDivider); + if (checkBox != null) { + checkBox.setVisibility(GONE); + } + } + public void setTextAndValueAndIcon(String text, String value, int resId, boolean divider) { setTextAndValueAndIcon(text, value, false, resId, divider); } @@ -320,6 +385,7 @@ public class TextCell extends FrameLayout { textView.setText(text); valueTextView.setText(value, animated); valueTextView.setVisibility(VISIBLE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); imageView.setVisibility(VISIBLE); imageView.setTranslationX(0); @@ -337,11 +403,11 @@ public class TextCell extends FrameLayout { offsetFromImage = 65; imageView.setVisibility(VISIBLE); imageView.setPadding(AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2)); - imageView.setTranslationX(AndroidUtilities.dp(-3)); + imageView.setTranslationX(AndroidUtilities.dp(LocaleController.isRTL ? 0 : -3)); imageView.setTranslationY(AndroidUtilities.dp(6)); imageView.setImageResource(resId); imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); - imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(8), color)); + imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(9), color)); } public void setTextAndCheck(String text, boolean checked, boolean divider) { @@ -364,6 +430,7 @@ public class TextCell extends FrameLayout { offsetFromImage = 71; textView.setText(text); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); if (checkBox != null) { checkBox.setVisibility(VISIBLE); @@ -381,6 +448,7 @@ public class TextCell extends FrameLayout { offsetFromImage = 71; textView.setText(text); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); if (checkBox != null) { checkBox.setVisibility(VISIBLE); @@ -401,6 +469,7 @@ public class TextCell extends FrameLayout { valueImageView.setVisibility(VISIBLE); valueImageView.setImageDrawable(drawable); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); imageView.setVisibility(GONE); imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); needDivider = divider; @@ -456,6 +525,9 @@ public class TextCell extends FrameLayout { if (valueTextView != null) { valueTextView.animate().alpha(alpha).start(); } + if (valueSpoilersTextView != null) { + valueSpoilersTextView.animate().alpha(alpha).start(); + } if (valueImageView != null) { valueImageView.animate().alpha(alpha).start(); } @@ -469,6 +541,9 @@ public class TextCell extends FrameLayout { if (valueTextView != null) { valueTextView.setAlpha(alpha); } + if (valueSpoilersTextView != null) { + valueSpoilersTextView.setAlpha(alpha); + } if (valueImageView != null) { valueImageView.setAlpha(alpha); } @@ -542,7 +617,12 @@ public class TextCell extends FrameLayout { float alpha = (0.6f + 0.4f * loadingProgress) * drawLoadingProgress; paint.setAlpha((int) (255 * alpha)); int cy = getMeasuredHeight() >> 1; - AndroidUtilities.rectTmp.set(getMeasuredWidth() - AndroidUtilities.dp(11) - AndroidUtilities.dp(loadingSize), cy - AndroidUtilities.dp(3), getMeasuredWidth() - AndroidUtilities.dp(11), cy + AndroidUtilities.dp(3)); + AndroidUtilities.rectTmp.set( + getMeasuredWidth() - AndroidUtilities.dp(21) - AndroidUtilities.dp(loadingSize), + cy - AndroidUtilities.dp(3), + getMeasuredWidth() - AndroidUtilities.dp(21), + cy + AndroidUtilities.dp(3) + ); if (LocaleController.isRTL) { AndroidUtilities.rectTmp.left = getMeasuredWidth() - AndroidUtilities.rectTmp.left; AndroidUtilities.rectTmp.right = getMeasuredWidth() - AndroidUtilities.rectTmp.right; @@ -551,6 +631,7 @@ public class TextCell extends FrameLayout { invalidate(); } valueTextView.setAlpha(1f - drawLoadingProgress); + valueSpoilersTextView.setAlpha(1f - drawLoadingProgress); super.dispatchDraw(canvas); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java index adb8dbba6..fb65cc52a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java @@ -13,7 +13,10 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.text.TextUtils; @@ -24,6 +27,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; @@ -32,6 +36,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.Switch; import java.util.ArrayList; @@ -53,6 +58,7 @@ public class TextCheckCell extends FrameLayout { private boolean drawCheckRipple; private int padding; private Theme.ResourcesProvider resourcesProvider; + ImageView imageView; public static final Property ANIMATION_PROGRESS = new AnimationProperties.FloatProperty("animationProgress") { @Override @@ -123,6 +129,10 @@ public class TextCheckCell extends FrameLayout { checkBox.setEnabled(enabled); } + public void setCheckBoxIcon(int icon) { + checkBox.setIcon(icon); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (isMultiline) { @@ -333,7 +343,11 @@ public class TextCheckCell extends FrameLayout { canvas.drawCircle(cx, cy, animatedRad, animationPaint); } if (needDivider) { - canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(20) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + if (imageView != null) { + canvas.drawLine(LocaleController.isRTL ? 0 : padding, getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? padding : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + } else { + canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(20) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + } } } @@ -369,4 +383,20 @@ public class TextCheckCell extends FrameLayout { super.onDetachedFromWindow(); attached = false; } + + public void setColorfullIcon(int color, int resId) { + if (imageView == null) { + imageView = new RLottieImageView(getContext()); + imageView.setScaleType(ImageView.ScaleType.CENTER); + addView(imageView, LayoutHelper.createFrame(29, 29, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 19, 0, 19, 0)); + padding = AndroidUtilities.dp(65); + ((MarginLayoutParams)textView.getLayoutParams()).leftMargin = LocaleController.isRTL ? 70 : padding; + ((MarginLayoutParams)textView.getLayoutParams()).rightMargin = LocaleController.isRTL ? padding: 70; + } + imageView.setVisibility(VISIBLE); + imageView.setPadding(AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2)); + imageView.setImageResource(resId); + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(9), color)); + } } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java index 8e9b65466..5c0ee74d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java @@ -10,16 +10,24 @@ package org.telegram.ui.Cells; import android.content.Context; import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; +import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; +import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Switch; @@ -31,6 +39,47 @@ public class TextCheckCell2 extends FrameLayout { private boolean needDivider; private boolean isMultiline; + private LinearLayout collapseViewContainer; + private AnimatedTextView animatedTextView; + private View collapsedArrow; + private View checkBoxClickArea; + + public void setCollapseArrow(String text, boolean collapsed, Runnable onCheckClick) { + if (collapseViewContainer == null) { + collapseViewContainer = new LinearLayout(getContext()); + collapseViewContainer.setOrientation(LinearLayout.HORIZONTAL); + animatedTextView = new AnimatedTextView(getContext(), false, true, true); + animatedTextView.setTextSize(AndroidUtilities.dp(14)); + animatedTextView.getDrawable().setAllowCancel(true); + animatedTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + animatedTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + collapseViewContainer.addView(animatedTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT,20)); + + collapsedArrow = new View(getContext()); + Drawable drawable = getContext().getResources().getDrawable(R.drawable.arrow_more).mutate(); + drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), PorterDuff.Mode.MULTIPLY)); + collapsedArrow.setBackground(drawable); + collapseViewContainer.addView(collapsedArrow, LayoutHelper.createLinear(16, 16, Gravity.CENTER_VERTICAL)); + collapseViewContainer.setClipChildren(false); + setClipChildren(false); + addView(collapseViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + + checkBoxClickArea = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawLine(0, AndroidUtilities.dp(14), 2, getMeasuredHeight()- AndroidUtilities.dp(14), Theme.dividerPaint); + } + }; + checkBoxClickArea.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector), 2)); + addView(checkBoxClickArea, LayoutHelper.createFrame(76, LayoutHelper.MATCH_PARENT, LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)); + } + animatedTextView.setText(text); + collapsedArrow.animate().cancel(); + collapsedArrow.animate().rotation(collapsed ? 0 : 180).setDuration(340).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + checkBoxClickArea.setOnClickListener(v -> onCheckClick.run()); + } + public TextCheckCell2(Context context) { this(context, null); } @@ -46,7 +95,7 @@ public class TextCheckCell2 extends FrameLayout { textView.setSingleLine(true); textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); textView.setEllipsize(TextUtils.TruncateAt.END); - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 64 : 21, 0, LocaleController.isRTL ? 21 : 64, 0)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 64 : 21, 0, LocaleController.isRTL ? 21 : 64, 0)); valueTextView = new TextView(context); valueTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); @@ -73,10 +122,26 @@ public class TextCheckCell2 extends FrameLayout { } } + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (collapseViewContainer != null) { + if (LocaleController.isRTL) { + collapseViewContainer.setTranslationX(textView.getLeft() - collapseViewContainer.getMeasuredWidth() - AndroidUtilities.dp(4)); + } else { + collapseViewContainer.setTranslationX(textView.getRight() + AndroidUtilities.dp(4)); + } + } + } + public void setTextAndCheck(String text, boolean checked, boolean divider) { + setTextAndCheck(text, checked, divider, false); + } + + public void setTextAndCheck(String text, boolean checked, boolean divider, boolean animated) { textView.setText(text); isMultiline = false; - checkBox.setChecked(checked, false); + checkBox.setChecked(checked, animated); needDivider = divider; valueTextView.setVisibility(GONE); LayoutParams layoutParams = (LayoutParams) textView.getLayoutParams(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java index 35a1f49da..c18de2afa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java @@ -12,6 +12,7 @@ import android.animation.Animator; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -42,6 +43,7 @@ public class TextSettingsCell extends FrameLayout { private TextView textView; private AnimatedTextView valueTextView; private ImageView imageView; + private boolean imageViewIsColorful; private BackupImageView valueBackupImageView; private ImageView valueImageView; private boolean needDivider; @@ -94,14 +96,14 @@ public class TextSettingsCell extends FrameLayout { imageView = new RLottieImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER); - imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon), PorterDuff.Mode.MULTIPLY)); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); imageView.setVisibility(GONE); addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0)); valueImageView = new ImageView(context); valueImageView.setScaleType(ImageView.ScaleType.CENTER); valueImageView.setVisibility(INVISIBLE); - valueImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon), PorterDuff.Mode.MULTIPLY)); + valueImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); addView(valueImageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, padding, 0, padding, 0)); } @@ -120,7 +122,11 @@ public class TextSettingsCell extends FrameLayout { } if (imageView.getVisibility() == VISIBLE) { - imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST)); + if (imageViewIsColorful) { + imageView.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(28), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(28), MeasureSpec.EXACTLY)); + } else { + imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST)); + } } if (valueBackupImageView != null) { @@ -213,6 +219,7 @@ public class TextSettingsCell extends FrameLayout { public void setIcon(int resId) { MarginLayoutParams params = (MarginLayoutParams) textView.getLayoutParams(); + imageViewIsColorful = false; if (resId == 0) { imageView.setVisibility(GONE); if (LocaleController.isRTL) { @@ -222,6 +229,31 @@ public class TextSettingsCell extends FrameLayout { } } else { imageView.setImageResource(resId); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + imageView.setBackground(null); + imageView.setVisibility(VISIBLE); + if (LocaleController.isRTL) { + params.rightMargin = AndroidUtilities.dp(71); + } else { + params.leftMargin = AndroidUtilities.dp(71); + } + } + } + + public void setColorfulIcon(int resId, int color) { + MarginLayoutParams params = (MarginLayoutParams) textView.getLayoutParams(); + imageViewIsColorful = true; + if (resId == 0) { + imageView.setVisibility(GONE); + if (LocaleController.isRTL) { + params.rightMargin = AndroidUtilities.dp(this.padding); + } else { + params.leftMargin = AndroidUtilities.dp(this.padding); + } + } else { + imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(8), color)); + imageView.setImageResource(resId); + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); imageView.setVisibility(VISIBLE); if (LocaleController.isRTL) { params.rightMargin = AndroidUtilities.dp(71); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java index fad7ab5a9..a226d9540 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java @@ -191,6 +191,9 @@ public class ThemePreviewMessagesCell extends LinearLayout { private GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { + if (MediaDataController.getInstance(currentAccount).getDoubleTapReaction() == null) { + return false; + } boolean added = getMessageObject().selectReaction(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(MediaDataController.getInstance(currentAccount).getDoubleTapReaction()), false, false); setMessageObject(getMessageObject(), null, false, false); requestLayout(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java index 439d9d39e..d451cb099 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java @@ -54,6 +54,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; @@ -110,6 +111,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC private LinearLayout linearLayout2; private HeaderCell headerCell2; private EditTextBoldCursor editText; + private boolean isGroup; private RLottieDrawable cameraDrawable; @@ -141,23 +143,29 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC private int currentStep; private long chatId; private boolean canCreatePublic = true; + private Boolean forcePublic; private TLRPC.InputFile inputPhoto; private TLRPC.InputFile inputVideo; + private TLRPC.VideoSize inputEmojiMarkup; private String inputVideoPath; private double videoTimestamp; private boolean createAfterUpload; private boolean donePressed; private Integer doneRequestId; + private Utilities.Callback2 onFinishListener; private final static int done_button = 1; public ChannelCreateActivity(Bundle args) { super(args); currentStep = args.getInt("step", 0); + if (args.containsKey("forcePublic")) { + forcePublic = args.getBoolean("forcePublic", false); + } if (currentStep == 0) { avatarDrawable = new AvatarDrawable(); - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_CHANNEL, true); TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername(); req.username = "1"; @@ -175,6 +183,10 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC } } + public void setOnFinishListener(Utilities.Callback2 onFinishListener) { + this.onFinishListener = onFinishListener; + } + @Override public boolean onFragmentCreate() { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatDidCreated); @@ -343,7 +355,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC createAfterUpload = true; return; } - doneRequestId = MessagesController.getInstance(currentAccount).createChat(nameTextView.getText().toString(), new ArrayList<>(), descriptionTextView.getText().toString(), ChatObject.CHAT_TYPE_CHANNEL, false, null, null, 0, ChannelCreateActivity.this); + doneRequestId = MessagesController.getInstance(currentAccount).createChat(nameTextView.getText().toString(), new ArrayList<>(), descriptionTextView.getText().toString(), ChatObject.CHAT_TYPE_CHANNEL, false, null, null, -1, ChannelCreateActivity.this); } else if (currentStep == 1) { if (!isPrivate) { if (descriptionTextView.length() == 0) { @@ -362,15 +374,30 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC AndroidUtilities.shakeView(checkTextView); return; } else { - MessagesController.getInstance(currentAccount).updateChannelUserName(ChannelCreateActivity.this, chatId, lastCheckName, null, null); + AndroidUtilities.runOnUIThread(enableDoneLoading, 200); + MessagesController.getInstance(currentAccount).updateChannelUserName(ChannelCreateActivity.this, chatId, lastCheckName, () -> { + updateDoneProgress(false); + if (onFinishListener != null) { + onFinishListener.run(ChannelCreateActivity.this, chatId); + } + }, () -> { + updateDoneProgress(false); + if (onFinishListener != null) { + onFinishListener.run(ChannelCreateActivity.this, chatId); + } + }); } } + } else if (onFinishListener != null) { + onFinishListener.run(ChannelCreateActivity.this, chatId); + } + if (onFinishListener == null) { + Bundle args = new Bundle(); + args.putInt("step", 2); + args.putLong("chatId", chatId); + args.putInt("chatType", ChatObject.CHAT_TYPE_CHANNEL); + presentFragment(new GroupCreateActivity(args), true); } - Bundle args = new Bundle(); - args.putInt("step", 2); - args.putLong("chatId", chatId); - args.putInt("chatType", ChatObject.CHAT_TYPE_CHANNEL); - presentFragment(new GroupCreateActivity(args), true); } } } @@ -545,7 +572,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC @Override protected void onDraw(Canvas canvas) { if (avatarImage != null && avatarImage.getImageReceiver().hasNotThumb()) { - paint.setAlpha((int) (0x55 * avatarImage.getImageReceiver().getCurrentAlpha())); + paint.setAlpha((int) (0x55 * avatarImage.getImageReceiver().getCurrentAlpha() * avatarProgressView.getAlpha())); canvas.drawCircle(getMeasuredWidth() / 2.0f, getMeasuredHeight() / 2.0f, getMeasuredWidth() / 2.0f, paint); } } @@ -559,6 +586,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC inputPhoto = null; inputVideo = null; inputVideoPath = null; + inputEmojiMarkup = null; videoTimestamp = 0; showAvatarProgress(false, true); avatarImage.setImage(null, null, avatarDrawable, null); @@ -599,8 +627,14 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC avatarEditor.setPadding(AndroidUtilities.dp(0), 0, 0, AndroidUtilities.dp(1)); frameLayout.addView(avatarEditor, LayoutHelper.createFrame(64, 64, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 15, 12, LocaleController.isRTL ? 15 : 0, 12)); - avatarProgressView = new RadialProgressView(context); - avatarProgressView.setSize(AndroidUtilities.dp(30)); + avatarProgressView = new RadialProgressView(context) { + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + avatarOverlay.invalidate(); + } + }; + avatarProgressView.setSize(AndroidUtilities.dp(30)); avatarProgressView.setProgressColor(0xffffffff); avatarProgressView.setNoProgress(false); frameLayout.addView(avatarProgressView, LayoutHelper.createFrame(64, 64, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 16, 12, LocaleController.isRTL ? 16 : 0, 12)); @@ -683,14 +717,16 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC linearLayout.setOrientation(LinearLayout.VERTICAL); scrollView.addView(linearLayout, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - actionBar.setTitle(LocaleController.getString("ChannelSettingsTitle", R.string.ChannelSettingsTitle)); + TLRPC.Chat chat = getMessagesController().getChat(chatId); + isGroup = chat != null && (!ChatObject.isChannel(chat) || ChatObject.isMegagroup(chat)); + actionBar.setTitle(isGroup ? LocaleController.getString("GroupSettingsTitle", R.string.GroupSettingsTitle) : LocaleController.getString("ChannelSettingsTitle", R.string.ChannelSettingsTitle)); fragmentView.setTag(Theme.key_windowBackgroundGray); fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); headerCell2 = new HeaderCell(context, 23); headerCell2.setHeight(46); headerCell2.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - headerCell2.setText(LocaleController.getString("ChannelTypeHeader", R.string.ChannelTypeHeader)); + headerCell2.setText(isGroup ? LocaleController.getString("GroupTypeHeader", R.string.GroupTypeHeader) : LocaleController.getString("ChannelTypeHeader", R.string.ChannelTypeHeader)); linearLayout.addView(headerCell2); linearLayout2 = new LinearLayout(context); @@ -700,8 +736,14 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC radioButtonCell1 = new RadioButtonCell(context); radioButtonCell1.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - radioButtonCell1.setTextAndValue(LocaleController.getString("ChannelPublic", R.string.ChannelPublic), LocaleController.getString("ChannelPublicInfo", R.string.ChannelPublicInfo), false, !isPrivate); - linearLayout2.addView(radioButtonCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + if (forcePublic != null && !forcePublic) { + isPrivate = true; + } + if (isGroup) { + radioButtonCell1.setTextAndValue(LocaleController.getString("MegaPublic", R.string.MegaPublic), LocaleController.getString("MegaPublicInfo", R.string.MegaPublicInfo), false, !isPrivate); + } else { + radioButtonCell1.setTextAndValue(LocaleController.getString("ChannelPublic", R.string.ChannelPublic), LocaleController.getString("ChannelPublicInfo", R.string.ChannelPublicInfo), false, !isPrivate); + } radioButtonCell1.setOnClickListener(v -> { if (!canCreatePublic) { showPremiumIncreaseLimitDialog(); @@ -713,11 +755,20 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC isPrivate = false; updatePrivatePublic(); }); + if (forcePublic == null || forcePublic) { + linearLayout2.addView(radioButtonCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } radioButtonCell2 = new RadioButtonCell(context); radioButtonCell2.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - radioButtonCell2.setTextAndValue(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate), LocaleController.getString("ChannelPrivateInfo", R.string.ChannelPrivateInfo), false, isPrivate); - linearLayout2.addView(radioButtonCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + if (forcePublic != null && forcePublic) { + isPrivate = false; + } + if (isGroup) { + radioButtonCell2.setTextAndValue(LocaleController.getString("MegaPrivate", R.string.MegaPrivate), LocaleController.getString("MegaPrivateInfo", R.string.MegaPrivateInfo), false, isPrivate); + } else { + radioButtonCell2.setTextAndValue(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate), LocaleController.getString("ChannelPrivateInfo", R.string.ChannelPrivateInfo), false, isPrivate); + } radioButtonCell2.setOnClickListener(v -> { if (isPrivate) { return; @@ -725,6 +776,9 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC isPrivate = true; updatePrivatePublic(); }); + if (forcePublic == null || !forcePublic) { + linearLayout2.addView(radioButtonCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } sectionCell = new ShadowSectionCell(context); linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); @@ -923,8 +977,13 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC typeInfoCell.setBackgroundDrawable(Theme.getThemedDrawable(typeInfoCell.getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); linkContainer.setVisibility(View.VISIBLE); loadingAdminedCell.setVisibility(View.GONE); - typeInfoCell.setText(isPrivate ? LocaleController.getString("ChannelPrivateLinkHelp", R.string.ChannelPrivateLinkHelp) : LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp)); - headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle)); + if (isGroup) { + typeInfoCell.setText(isPrivate ? LocaleController.getString("MegaPrivateLinkHelp", R.string.MegaPrivateLinkHelp) : LocaleController.getString("MegaUsernameHelp", R.string.MegaUsernameHelp)); + headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle)); + } else { + typeInfoCell.setText(isPrivate ? LocaleController.getString("ChannelPrivateLinkHelp", R.string.ChannelPrivateLinkHelp) : LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp)); + headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle)); + } publicContainer.setVisibility(isPrivate ? View.GONE : View.VISIBLE); privateContainer.setVisibility(isPrivate ? View.VISIBLE : View.GONE); linkContainer.setPadding(0, 0, 0, isPrivate ? 0 : AndroidUtilities.dp(7)); @@ -954,11 +1013,12 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC } @Override - public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { if (photo != null || video != null) { inputPhoto = photo; inputVideo = video; + inputEmojiMarkup = emojiMarkup; inputVideoPath = videoPath; videoTimestamp = videoStartTimestamp; if (createAfterUpload) { @@ -975,6 +1035,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC doneButton.performClick(); } showAvatarProgress(false, true); + avatarEditor.setImageDrawable(null); } else { avatar = smallSize.location; avatarBig = bigSize.location; @@ -1124,10 +1185,15 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC bundle.putInt("step", 1); bundle.putLong("chat_id", chat_id); bundle.putBoolean("canCreatePublic", canCreatePublic); - if (inputPhoto != null || inputVideo != null) { - MessagesController.getInstance(currentAccount).changeChatAvatar(chat_id, null, inputPhoto, inputVideo, videoTimestamp, inputVideoPath, avatar, avatarBig, null); + if (forcePublic != null) { + bundle.putBoolean("forcePublic", forcePublic); } - presentFragment(new ChannelCreateActivity(bundle), true); + if (inputPhoto != null || inputVideo != null || inputEmojiMarkup != null) { + MessagesController.getInstance(currentAccount).changeChatAvatar(chat_id, null, inputPhoto, inputVideo, inputEmojiMarkup, videoTimestamp, inputVideoPath, avatar, avatarBig, null); + } + ChannelCreateActivity activity = new ChannelCreateActivity(bundle); + activity.setOnFinishListener(onFinishListener); + presentFragment(activity, true); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 6258fdeb3..6e6805280 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -124,6 +124,7 @@ import org.telegram.messenger.ChatObject; import org.telegram.messenger.ChatThemeController; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; +import org.telegram.messenger.DownloadController; import org.telegram.messenger.Emoji; import org.telegram.messenger.EmojiData; import org.telegram.messenger.FileLoader; @@ -144,6 +145,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.SecretChatHelper; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.TranslateController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; @@ -258,6 +260,7 @@ import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.ReactedHeaderView; import org.telegram.ui.Components.ReactedUsersListView; import org.telegram.ui.Components.ReactionTabHolderView; +import org.telegram.ui.Components.Reactions.ChatSelectionReactionMenuOverlay; import org.telegram.ui.Components.Reactions.ReactionsEffectOverlay; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.ReactionsContainerLayout; @@ -274,7 +277,8 @@ import org.telegram.ui.Components.TextSelectionHint; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.ThemeEditorView; import org.telegram.ui.Components.TranscribeButton; -import org.telegram.ui.Components.TranslateAlert; +import org.telegram.ui.Components.TranslateAlert2; +import org.telegram.ui.Components.TranslateButton; import org.telegram.ui.Components.TrendingStickersAlert; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanBotCommand; @@ -354,6 +358,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ActionBarMenuItem headerItem; private ActionBarMenuItem editTextItem; private ActionBarMenuItem searchItem; + private ActionBarMenuSubItem translateItem; private ActionBarMenuItem searchIconItem; private ActionBarMenuItem audioCallIconItem; private boolean searchItemVisible; @@ -427,7 +432,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean addToContactsButtonArchive; private TextView reportSpamButton; private TextView restartTopicButton; - private View topViewSeparator1, topViewSeparator2; + private TranslateButton translateButton; + private View topViewSeparator1, topViewSeparator2, topViewSeparator3; private LinkSpanDrawable.LinksTextView emojiStatusSpamHint; private ImageView closeReportSpam; private TextView chatWithAdminTextView; @@ -672,7 +678,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private SparseArray repliesMessagesDict = new SparseArray<>(); private SparseArray> replyMessageOwners = new SparseArray<>(); private HashMap> messagesByDays = new HashMap<>(); - protected ArrayList messages = new ArrayList<>(); + protected ArrayList messages = new ArrayList(); private SparseArray waitingForReplies = new SparseArray<>(); private LongSparseArray> polls = new LongSparseArray<>(); private LongSparseArray groupedMessagesMap = new LongSparseArray<>(); @@ -889,6 +895,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }; + private ChatSelectionReactionMenuOverlay selectionReactionsOverlay; + private boolean isPauseOnThemePreview; private ChatThemeBottomSheet chatThemeBottomSheet; public ThemeDelegate themeDelegate; @@ -1116,6 +1124,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return items; } + public boolean allowSendPhotos() { + if (currentChat != null && !ChatObject.canSendPhoto(currentChat)) { + return false; + } else { + return true; + } + } + private interface ChatActivityDelegate { default void openReplyMessage(int mid) { @@ -1240,6 +1256,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private final static int topic_close = 60; private final static int open_forum = 61; + private final static int translate = 62; + private final static int id_chat_compose_panel = 1000; RecyclerListView.OnItemLongClickListenerExtended onItemLongClickListener = new RecyclerListView.OnItemLongClickListenerExtended() { @@ -1250,7 +1268,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } wasManualScroll = true; boolean result = true; - if (!actionBar.isActionModeShowed() && (reportType < 0 || (view instanceof ChatActionCell && (((ChatActionCell) view).getMessageObject().messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL) || ((ChatActionCell) view).getMessageObject().type == MessageObject.TYPE_SUGGEST_PHOTO))) { + if (!actionBar.isActionModeShowed() && (reportType < 0 || (view instanceof ChatActionCell && (((ChatActionCell) view).getMessageObject().messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL) || ((view instanceof ChatActionCell) && ((ChatActionCell) view).getMessageObject().type == MessageObject.TYPE_SUGGEST_PHOTO)))) { result = createMenu(view, false, true, x, y); } else { boolean outside = false; @@ -1719,6 +1737,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().addObserver(this, NotificationCenter.chatAvailableReactionsUpdated); getNotificationCenter().addObserver(this, NotificationCenter.dialogsUnreadReactionsCounterChanged); getNotificationCenter().addObserver(this, NotificationCenter.groupStickersDidLoad); + getNotificationCenter().addObserver(this, NotificationCenter.dialogTranslate); + getNotificationCenter().addObserver(this, NotificationCenter.dialogIsTranslatable); + getNotificationCenter().addObserver(this, NotificationCenter.messageTranslated); + getNotificationCenter().addObserver(this, NotificationCenter.messageTranslating); super.onFragmentCreate(); @@ -1951,6 +1973,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return i - cur; } + @Override + public void onBeginSlide() { + super.onBeginSlide(); + + if (selectionReactionsOverlay != null && selectionReactionsOverlay.isVisible()) { + selectionReactionsOverlay.setHiddenByScroll(true); + } + } + @Override public void onFragmentDestroy() { super.onFragmentDestroy(); @@ -2050,6 +2081,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().removeObserver(this, NotificationCenter.didLoadSendAsPeers); getNotificationCenter().removeObserver(this, NotificationCenter.dialogsUnreadReactionsCounterChanged); getNotificationCenter().removeObserver(this, NotificationCenter.groupStickersDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.dialogTranslate); + getNotificationCenter().removeObserver(this, NotificationCenter.dialogIsTranslatable); + getNotificationCenter().removeObserver(this, NotificationCenter.messageTranslated); + getNotificationCenter().removeObserver(this, NotificationCenter.messageTranslating); if (currentEncryptedChat != null) { getNotificationCenter().removeObserver(this, NotificationCenter.didVerifyMessagesStickers); } @@ -2378,6 +2413,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getSendMessagesHelper().sendMessage("/settings", dialog_id, null, null, null, false, null, null, null, true, 0, null, false); } else if (id == search) { openSearchWithText(null); + } else if (id == translate) { + getMessagesController().getTranslateController().setHideTranslateDialog(getDialogId(), false, true); + if (!getMessagesController().getTranslateController().toggleTranslatingDialog(getDialogId(), true)) { + updateTopPanel(true); + } } else if (id == call || id == video_call) { if (currentUser != null && getParentActivity() != null) { VoIPHelper.startCall(currentUser, id == video_call, userInfo != null && userInfo.video_calls_available, getParentActivity(), getMessagesController().getUserFull(currentUser.id), getAccountInstance()); @@ -2613,7 +2653,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (audioCallIconItem != null && showAudioCallAsIcon) { audioCallIconItem.setVisibility(View.GONE); } - } else if (chatActivityEnterView.hasText() && TextUtils.isEmpty(chatActivityEnterView.getSlowModeTimer()) && (currentChat == null || ChatObject.canSendMessages(currentChat))) { + } else if (chatActivityEnterView.hasText() && TextUtils.isEmpty(chatActivityEnterView.getSlowModeTimer()) && (currentChat == null || ChatObject.canSendPlain(currentChat))) { if (headerItem != null) { headerItem.setVisibility(View.GONE); } @@ -2725,6 +2765,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchItemVisible = false; } + if (chatMode == 0 && (threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser) && reportType < 0) { + TLRPC.UserFull userFull = null; + if (currentUser != null) { + audioCallIconItem = menu.addItem(call, R.drawable.ic_call, themeDelegate); + audioCallIconItem.setContentDescription(LocaleController.getString("Call", R.string.Call)); + userFull = getMessagesController().getUserFull(currentUser.id); + if (userFull != null && userFull.phone_calls_available) { + showAudioCallAsIcon = !inPreviewMode; + audioCallIconItem.setVisibility(View.VISIBLE); + } else { + showAudioCallAsIcon = false; + audioCallIconItem.setVisibility(View.GONE); + } + if (avatarContainer != null) { + avatarContainer.setTitleExpand(showAudioCallAsIcon); + } + } + } + editTextItem = menu.addItem(0, R.drawable.ic_ab_other, themeDelegate); editTextItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); editTextItem.setTag(null); @@ -2758,19 +2817,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatMode == 0 && (threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser) && reportType < 0) { TLRPC.UserFull userFull = null; if (currentUser != null) { - audioCallIconItem = menu.addItem(call, R.drawable.ic_call, themeDelegate); - audioCallIconItem.setContentDescription(LocaleController.getString("Call", R.string.Call)); userFull = getMessagesController().getUserFull(currentUser.id); - if (userFull != null && userFull.phone_calls_available) { - showAudioCallAsIcon = !inPreviewMode; - audioCallIconItem.setVisibility(View.VISIBLE); - } else { - showAudioCallAsIcon = false; - audioCallIconItem.setVisibility(View.GONE); - } - if (avatarContainer != null) { - avatarContainer.setTitleExpand(showAudioCallAsIcon); - } } headerItem = menu.addItem(0, R.drawable.ic_ab_other, themeDelegate); headerItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); @@ -2868,6 +2915,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (searchItem != null) { headerItem.addSubItem(search, R.drawable.msg_search, LocaleController.getString("Search", R.string.Search), themeDelegate); } + translateItem = headerItem.addSubItem(translate, R.drawable.msg_translate, LocaleController.getString("TranslateMessage", R.string.TranslateMessage), themeDelegate); + updateTranslateItemVisibility(); if (currentChat != null && !currentChat.creator && !ChatObject.hasAdminRights(currentChat)) { headerItem.addSubItem(report, R.drawable.msg_report, LocaleController.getString("ReportChat", R.string.ReportChat), themeDelegate); } @@ -5893,6 +5942,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not invalidated = true; super.invalidate(); contentView.invalidateBlur(); + if (selectionReactionsOverlay != null && selectionReactionsOverlay.isVisible()) { + selectionReactionsOverlay.invalidatePosition(); + } } @Override @@ -6293,6 +6345,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); } NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopSpoilers); + + if (selectionReactionsOverlay != null && selectionReactionsOverlay.isVisible()) { + selectionReactionsOverlay.setHiddenByScroll(true); + } } } @@ -6381,9 +6437,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not textSelectionHelper.onParentScrolled(); emojiAnimationsOverlay.onScrolled(dy); ReactionsEffectOverlay.onScrolled(dy); + + checkTranslation(false); } }); + selectionReactionsOverlay = new ChatSelectionReactionMenuOverlay(this, context); + contentView.addView(selectionReactionsOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + animatingImageView = new ClippingImageView(context); animatingImageView.setVisibility(View.GONE); contentView.addView(animatingImageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -6838,7 +6899,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not emojiStatusSpamHint.setGravity(Gravity.CENTER); emojiStatusSpamHint.setVisibility(View.GONE); emojiStatusSpamHint.setLinkTextColor(getThemedColor(Theme.key_windowBackgroundWhiteLinkText)); - topChatPanelView.addView(emojiStatusSpamHint, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 25, 56, 25, 1)); + topChatPanelView.addView(emojiStatusSpamHint, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 25, 0, 25, 1)); topViewSeparator1 = new View(context); topViewSeparator1.setVisibility(View.GONE); @@ -6849,6 +6910,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not topViewSeparator2.setVisibility(View.GONE); topViewSeparator2.setBackgroundColor(getThemedColor(Theme.key_divider)); topChatPanelView.addView(topViewSeparator2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.LEFT | Gravity.TOP, 10, 50, 10, 1)); + topViewSeparator3 = new View(context); + topViewSeparator3.setVisibility(View.GONE); + topViewSeparator3.setBackgroundColor(getThemedColor(Theme.key_divider)); + topChatPanelView.addView(topViewSeparator3, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 38)); addToContactsButton = new TextView(context); addToContactsButton.setTextColor(getThemedColor(Theme.key_chat_addContact)); @@ -6933,6 +6998,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateTopPanel(true); }); + translateButton = new TranslateButton(context, this, themeDelegate) { + @Override + protected void onButtonClick() { + getMessagesController().getTranslateController().toggleTranslatingDialog(getDialogId()); + updateTopPanel(true); + } + }; + topChatPanelView.addView(translateButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 2)); + closeReportSpam = new ImageView(context); closeReportSpam.setImageResource(R.drawable.miniplayer_close); closeReportSpam.setContentDescription(LocaleController.getString("Close", R.string.Close)); @@ -7149,7 +7223,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public boolean needSend() { + public boolean needSend(int contentType) { return true; } @@ -8844,6 +8918,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } updatePinnedMessageView(true); updateVisibleRows(); + updateSelectedMessageReactions(); }); bottomMessagesActionContainer.addView(replyButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); @@ -9123,15 +9198,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void dimBehindView(View view, boolean enable) { - scrimView = view; + setScrimView(view); dimBehindView(enable ? 0.2f : 0, view != reactionsMentiondownButton && view != mentiondownButton); } private void dimBehindView(View view, float value) { - scrimView = view; + setScrimView(view); dimBehindView(value, view != reactionsMentiondownButton && view != mentiondownButton); } + private void setScrimView(View scrimView) { + if (this.scrimView == scrimView) { + return; + } + if (this.scrimView != null) { + if (this.scrimView instanceof ChatActionCell) { + ((ChatActionCell) this.scrimView).setInvalidateWithParent(null); + } + } + this.scrimView = scrimView; + if (this.scrimView instanceof ChatActionCell) { + ((ChatActionCell) this.scrimView).setInvalidateWithParent(fragmentView); + } + } public void dimBehindView(boolean enable) { dimBehindView(enable ? 0.2f : 0, true); } @@ -9186,7 +9275,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onAnimationEnd(Animator animation) { if (!enable) { - scrimView = null; + setScrimView(null); scrimViewReaction = null; contentView.invalidate(); chatListView.invalidate(); @@ -9194,7 +9283,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); if (scrimView != null && scrimViewAlpha <= 0f) { - scrimView = null; + setScrimView(null); } scrimAnimatorSet.start(); } @@ -9350,7 +9439,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putInt("hasPoll", hasPoll); args.putBoolean("hasInvoice", hasInvoice); args.putInt("messagesCount", forwardingMessages.messages.size()); @@ -9470,6 +9559,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getMediaDataController().searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages); } + private void updateTranslateItemVisibility() { + if (translateItem == null) { + return; + } + translateItem.setVisibility(getMessagesController().getTranslateController().isTranslateDialogHidden(getDialogId()) && getMessagesController().getTranslateController().isDialogTranslatable(getDialogId()) ? View.VISIBLE : View.GONE); + } + private Animator infoTopViewAnimator; private void updateInfoTopView(boolean animated) { @@ -9848,7 +9944,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!invalidateChatListViewTopPadding || chatListView == null || (fixedKeyboardHeight > 0 && searchExpandProgress == 0)) { return; } - float topPanelViewH = Math.max(0, AndroidUtilities.dp(48) + topChatPanelViewOffset); + float topPanelViewH = Math.max(0, (topChatPanelView.getLayoutParams().height - AndroidUtilities.dp(2)) + topChatPanelViewOffset); float pinnedViewH = 0; if (pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { pinnedViewH = Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); @@ -9967,7 +10063,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - float translation = contentPanTranslation + contentPaddingTop + Math.max(0, AndroidUtilities.dp(48) + topChatPanelViewOffset); + int topPanelHeight = (topChatPanelView == null || topChatPanelView.getLayoutParams() == null ? AndroidUtilities.dp(50) : topChatPanelView.getLayoutParams().height) - AndroidUtilities.dp(2); + float translation = contentPanTranslation + contentPaddingTop + Math.max(0, topPanelHeight + topChatPanelViewOffset); if (pinnedMessageView != null) { translation += pinnedMessageEnterOffset; pinnedMessageView.setTranslationY(translation); @@ -10173,6 +10270,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void onAnimationEnd(Animator animation) { if (loading) { pagedownButtonArrow.setVisibility(View.GONE); + if (!startedLoading[0]) { + pagedownButtonLoadingDrawable.reset(); + pagedownButtonLoading.setVisibility(View.VISIBLE); + } } else { pagedownButtonLoading.setVisibility(View.GONE); } @@ -10260,9 +10361,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not break; } } + if (selectionReactionsOverlay != null && selectionReactionsOverlay.isVisible()) { + selectionReactionsOverlay.setHiddenByScroll(true); + } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putInt("messagesCount", canForwardMessagesCount); args.putInt("hasPoll", hasPoll); args.putBoolean("hasInvoice", hasInvoice); @@ -10974,6 +11078,16 @@ 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.canSendVoice(currentChat)) { + if (chatActivityEnterView.isInVideoMode()) { + mediaBanTooltip.setText(ChatObject.getRestrictedErrorText(currentChat, ChatObject.ACTION_SEND_ROUND)); + } else { + mediaBanTooltip.setText(ChatObject.getRestrictedErrorText(currentChat, ChatObject.ACTION_SEND_VOICE)); + } + } else if (ChatObject.isActionBannedByDefault(currentChat, ChatObject.ACTION_SEND_VOICE)) { + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachVoiceRestricted", R.string.GlobalAttachVoiceRestricted)); + } else if (ChatObject.isActionBannedByDefault(currentChat, ChatObject.ACTION_SEND_ROUND)) { + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachRoundRestricted", R.string.GlobalAttachRoundRestricted)); } else if (ChatObject.isActionBannedByDefault(currentChat, ChatObject.ACTION_SEND_MEDIA)) { mediaBanTooltip.setText(LocaleController.getString("GlobalAttachMediaRestricted", R.string.GlobalAttachMediaRestricted)); } else { @@ -12093,7 +12207,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } else if (messageObjectToReply != null) { - forwardingMessages = null; editingMessageObject = null; replyingMessageObject = messageObjectToReply; chatActivityEnterView.setReplyingMessageObject(messageObjectToReply); @@ -13039,7 +13152,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } getMessagesController().addToPollsQueue(dialog_id, pollsToCheck); - if (maxAdapterPosition >= 0 && minAdapterPosition >= 0) { + if (!isInScheduleMode() && maxAdapterPosition >= 0 && minAdapterPosition >= 0) { int from = minAdapterPosition - chatAdapter.messagesStartRow - 10; int to = maxAdapterPosition - chatAdapter.messagesStartRow + 10; if (from < 0) { @@ -13518,7 +13631,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (inCaseLoading != null) { inCaseLoading.run(); - } else { + } else if (forceNextPinnedMessageId == 0) { progressDialog = new AlertDialog(getParentActivity(), AlertDialog.ALERT_TYPE_SPINNER, themeDelegate); progressDialog.setOnShowListener(dialogInterface -> showPinnedProgress(false)); progressDialog.setOnCancelListener(postponedScrollCancelListener); @@ -13716,7 +13829,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } boolean hideKeyboard = false; - if (currentChat != null && !ChatObject.canSendMessages(currentChat) && !currentChat.gigagroup && (!ChatObject.isChannel(currentChat) || currentChat.megagroup)) { + 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)); } else if (AndroidUtilities.isBannedForever(currentChat.banned_rights)) { @@ -14359,6 +14472,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + updateSelectedMessageReactions(); + } + + private void updateSelectedMessageReactions() { + List selected = new ArrayList<>(); + SparseArray objs = selectedMessagesIds[0]; + for (int i = 0; i < objs.size(); i++) { + selected.add(objs.valueAt(i)); + } + objs = selectedMessagesIds[1]; + for (int i = 0; i < objs.size(); i++) { + selected.add(objs.valueAt(i)); + } + selectionReactionsOverlay.setSelectedMessages(selected); } private void processRowSelect(View view, boolean outside, float touchX, float touchY) { @@ -15036,6 +15163,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (wallpaper instanceof MotionBackgroundDrawable) { MotionBackgroundDrawable motion = (MotionBackgroundDrawable) wallpaper; if (((MotionBackgroundDrawable) wallpaper).isIndeterminateAnimation() != rotate) { + if (!rotate) { + motion.generateNextGradient(); + } motion.setIndeterminateAnimation(rotate); motion.setIndeterminateSpeedScale(rotate ? 1.5f : 1f); motion.updateAnimation(true); @@ -15695,6 +15825,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { obj.stableId = lastStableId++; } + getMessagesController().getTranslateController().checkTranslation(obj, false); if (load_type == 1) { messages.add(0, obj); } else { @@ -17194,6 +17325,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); } else if (id == NotificationCenter.didUpdateReactions) { + if (isInScheduleMode()) { + return; + } long did = (Long) args[0]; doOnIdle(() -> { int msgId = (Integer) args[1]; @@ -18080,9 +18214,290 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not avatarContainer.updateSubtitle(); } } + } else if (id == NotificationCenter.dialogTranslate) { + final long dialogId = (long) args[0]; + if (getDialogId() != dialogId) { + return; + } + + updateTopPanel(true); + if (chatListView != null && chatAdapter != null) { + boolean updatedPinned = false; + ArrayList groupChecked = new ArrayList<>(); + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + MessageObject messageObject = cell.getMessageObject(); + boolean update = false; + if (messageObject != null && messageObject.updateTranslation(false)) { + update = true; + + MessageObject pinnedMessageObject = pinnedMessageObjects.get(messageObject.getId()); + if (pinnedMessageObject != null) { + pinnedMessageObject.messageOwner.translatedText = messageObject.messageOwner.translatedText; + pinnedMessageObject.messageOwner.translatedToLanguage = messageObject.messageOwner.translatedToLanguage; + if (pinnedMessageObject.updateTranslation(currentPinnedMessageId == messageObject.getId())) { + updatedPinned = true; + } + } + } + MessageObject.GroupedMessages group = groupedMessagesMap.get(messageObject.getGroupId()); + if (group != null && !groupChecked.contains(group.groupId)) { + for (int j = 0; j < group.messages.size(); ++j) { + MessageObject groupMessageObject = group.messages.get(j); + if (groupMessageObject != null && groupMessageObject.updateTranslation(false)) { + update = true; + } + } + groupChecked.add(group.groupId); + } + if (messageObject != null && messageObject.replyMessageObject != null) { + MessageObject translatedReplyMessageObject = getMessagesController().getTranslateController().findReplyMessageObject(dialogId, messageObject.replyMessageObject.getId()); + if (translatedReplyMessageObject != null) { + messageObject.replyMessageObject.messageOwner.translatedText = translatedReplyMessageObject.messageOwner.translatedText; + messageObject.replyMessageObject.messageOwner.translatedToLanguage = translatedReplyMessageObject.messageOwner.translatedToLanguage; + if (messageObject.replyMessageObject.updateTranslation(true)) { + update = true; + } + } + } + + if (update) { + messageObject.forceUpdate = true; + cell.setMessageObject(messageObject, cell.getCurrentMessagesGroup(), cell.isPinnedBottom(), cell.isPinnedTop()); + if (group != null) { + if (chatListItemAnimator != null) { + chatListItemAnimator.groupWillChanged(group); + } + for (int j = 0; j < group.messages.size(); j++) { + group.messages.get(j).forceUpdate = true; + } + chatAdapter.notifyDataSetChanged(true); + } else { + chatAdapter.updateRowAtPosition(chatListView.getChildAdapterPosition(child)); + } + } else { + cell.invalidate(); + } + } + } + if (!updatedPinned) { + for (MessageObject pinnedMessageObject : pinnedMessageObjects.values()) { + if (pinnedMessageObject != null && pinnedMessageObject.updateTranslation(currentPinnedMessageId == pinnedMessageObject.getId())) { + updatedPinned = true; + } + } + } + if (updatedPinned) { + updatePinnedMessageView(true, 1); + } + } + checkTranslation(true); + updateTranslateItemVisibility(); + } else if (id == NotificationCenter.messageTranslated) { + MessageObject messageObject = (MessageObject) args[0]; + if (getDialogId() != messageObject.getDialogId()) { + return; + } + updateMessageTranslation(messageObject); + if (args.length > 1 && (boolean) args[1]) { + checkTranslation(true); + } + } else if (id == NotificationCenter.messageTranslating) { + MessageObject messageObject = (MessageObject) args[0]; + if (getDialogId() != messageObject.getDialogId()) { + return; + } + if (chatListView == null || chatAdapter == null) { + return; + } + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + child.invalidate(); + } + } + } else if (id == NotificationCenter.dialogIsTranslatable) { + final long dialogId = (long) args[0]; + if (getDialogId() != dialogId) { + return; + } + + updateTopPanel(true); + updateTranslateItemVisibility(); } } + private boolean updateMessageTranslation(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return false; + } + boolean updated = false; + for (MessageObject pinnedMessageObject : pinnedMessageObjects.values()) { + if (pinnedMessageObject != null && pinnedMessageObject.getId() == messageObject.getId()) { + pinnedMessageObject.messageOwner.translatedText = messageObject.messageOwner.translatedText; + pinnedMessageObject.messageOwner.translatedToLanguage = messageObject.messageOwner.translatedToLanguage; + if (pinnedMessageObject.updateTranslation(true)) { + updatePinnedMessageView(true, 1); + updated = true; + } + } + } + if (chatListView == null) { + return updated; + } + ArrayList groupChecked = new ArrayList<>(); + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + MessageObject cellMessageObject = cell.getMessageObject(); + if (cellMessageObject == null) { + continue; + } + boolean update = false; + if (cellMessageObject.getId() == messageObject.getId()) { + cellMessageObject.messageOwner.translatedText = messageObject.messageOwner.translatedText; + cellMessageObject.messageOwner.translatedToLanguage = messageObject.messageOwner.translatedToLanguage; + if (cellMessageObject.updateTranslation(false)) { + update = true; + ArrayList dependentMessages = replyMessageOwners.get(cellMessageObject.getId()); + if (dependentMessages != null) { + updateMessagesReplyTranslation(dependentMessages, messageObject); + } + } + } + MessageObject.GroupedMessages group = groupedMessagesMap.get(messageObject.getGroupId()); + if (group != null && !groupChecked.contains(group.groupId)) { + for (int j = 0; j < group.messages.size(); ++j) { + MessageObject groupMessageObject = group.messages.get(j); + if (groupMessageObject != null && groupMessageObject.updateTranslation(false)) { + update = true; + } + } + groupChecked.add(group.groupId); + } + if (cellMessageObject.replyMessageObject != null && cellMessageObject.replyMessageObject.getId() == messageObject.getId() && cellMessageObject.replyMessageObject.getDialogId() == messageObject.getDialogId()) { + cellMessageObject.replyMessageObject.messageOwner.translatedText = messageObject.messageOwner.translatedText; + cellMessageObject.replyMessageObject.messageOwner.translatedToLanguage = messageObject.messageOwner.translatedToLanguage; + if (cellMessageObject.replyMessageObject.updateTranslation(false)) { + update = true; + } + } + if (update) { + cellMessageObject.forceUpdate = true; + cell.setMessageObject(cellMessageObject, cell.getCurrentMessagesGroup(), cell.isPinnedBottom(), cell.isPinnedTop()); + if (group != null) { + if (chatListItemAnimator != null) { + chatListItemAnimator.groupWillChanged(group); + } + for (int j = 0; j < group.messages.size(); j++) { + group.messages.get(j).forceUpdate = true; + } + chatAdapter.notifyDataSetChanged(true); + } else { + chatAdapter.updateRowAtPosition(chatListView.getChildAdapterPosition(child)); + } + updated = true; + } + } + } + return updated; + } + + + private boolean updateMessagesReplyTranslation(ArrayList messageIds, MessageObject translatedReplyMessageObject) { + boolean updated = false; + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + MessageObject cellMessageObject = cell.getMessageObject(); + boolean update = false; + if (cellMessageObject != null && messageIds.contains(cellMessageObject.getId()) && cellMessageObject.replyMessageObject != null && cellMessageObject.replyMessageObject.getId() == translatedReplyMessageObject.getId()) { + cellMessageObject.replyMessageObject.messageOwner.translatedText = translatedReplyMessageObject.messageOwner.translatedText; + cellMessageObject.replyMessageObject.messageOwner.translatedToLanguage = translatedReplyMessageObject.messageOwner.translatedToLanguage; + if (cellMessageObject.replyMessageObject.updateTranslation(false)) { + update = true; + } + } + if (update) { + cellMessageObject.forceUpdate = true; + cell.setMessageObject(cellMessageObject, cell.getCurrentMessagesGroup(), cell.isPinnedBottom(), cell.isPinnedTop()); + chatAdapter.updateRowAtPosition(chatListView.getChildAdapterPosition(child)); + updated = true; + } + } + } + return updated; + } + + private long lastTranslationCheck; + private void checkTranslation(boolean force) { + if (System.currentTimeMillis() - lastTranslationCheck > 1000) { + force = true; + } + AndroidUtilities.cancelRunOnUIThread(checkTranslationRunnable); + AndroidUtilities.runOnUIThread(checkTranslationRunnable, force ? 0 : 150); + } + private Runnable checkTranslationRunnable = () -> { + lastTranslationCheck = System.currentTimeMillis(); + if (chatListView != null && chatAdapter != null) { + int minId = Integer.MAX_VALUE, maxId = Integer.MIN_VALUE; + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + if (cell.getCurrentMessagesGroup() != null) { + for (int j = 0; j < cell.getCurrentMessagesGroup().messages.size(); ++j) { + final int mid = cell.getCurrentMessagesGroup().messages.get(j).getId(); + minId = Math.min(minId, mid); + maxId = Math.max(maxId, mid); + } + } else if (cell.getMessageObject() != null) { + final int mid = cell.getMessageObject().getId(); + minId = Math.min(minId, mid); + maxId = Math.max(maxId, mid); + } + } + } + + if (minId <= maxId) { + ArrayList groupsChecked = new ArrayList<>(); + for (int i = 0; i < messages.size(); ++i) { + MessageObject messageObject = messages.get(i); + MessageObject.GroupedMessages group = groupedMessagesMap.get(messageObject.getGroupId()); + if (group != null) { + if (!groupsChecked.contains(group.groupId)) { + for (int j = 0; j < group.messages.size(); ++j) { + MessageObject messageObject1 = group.messages.get(j); + if (messageObject1 != null) { + final int mid = messageObject1.getId(); + getMessagesController().getTranslateController().checkTranslation( + messageObject1, mid >= minId - 7 && mid <= maxId + 7 + ); + } + } + groupsChecked.add(group.groupId); + } + } else { + final int mid = messageObject.getId(); + getMessagesController().getTranslateController().checkTranslation( + messageObject, mid >= minId - 7 && mid <= maxId + 7 + ); + } + } + } + } + + if (currentPinnedMessageId > 0 && pinnedMessageObjects != null) { + getMessagesController().getTranslateController().checkTranslation(pinnedMessageObjects.get(currentPinnedMessageId), true); + } + + updateTranslateItemVisibility(); + }; + private void checkSecretMessageForLocation(MessageObject messageObject) { if (messageObject.type != MessageObject.TYPE_GEO || locationAlertShown || SharedConfig.isSecretMapPreviewSet()) { return; @@ -18971,6 +19386,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } obj.stableId = lastStableId++; + getMessagesController().getTranslateController().checkTranslation(obj, false); messages.add(placeToPaste, obj); if (placeToPaste == 0 && !obj.isSponsored()) { needMoveScrollToLastMessage = true; @@ -19957,6 +20373,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not allowWrite.set(allow); }); + builder.setCustomViewOffset(6); builder.setView(cell); } builder.show(); @@ -20897,6 +21314,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } CharSequence pinnedText = null; + pinnedMessageObject.updateTranslation(false); if (pinnedMessageObject.type == MessageObject.TYPE_MUSIC) { pinnedText = String.format("%s - %s", pinnedMessageObject.getMusicAuthor(), pinnedMessageObject.getMusicTitle()); } else if (pinnedMessageObject.type == MessageObject.TYPE_POLL) { @@ -20915,22 +21333,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mess = mess.substring(0, 150); } mess = mess.replace('\n', ' '); - CharSequence message = mess; + pinnedText = mess; + pinnedText = Emoji.replaceEmoji(pinnedText, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); if (pinnedMessageObject != null && pinnedMessageObject.messageOwner != null) { - message = MessageObject.replaceAnimatedEmoji(mess, pinnedMessageObject.messageOwner.entities, messageTextView.getPaint().getFontMetricsInt()); + pinnedText = pinnedMessageObject.replaceAnimatedEmoji(pinnedText, messageTextView.getPaint().getFontMetricsInt()); } - pinnedText = Emoji.replaceEmoji(message, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); } else if (pinnedMessageObject.messageText != null) { String mess = pinnedMessageObject.messageText.toString(); if (mess.length() > 150) { mess = mess.substring(0, 150); } mess = mess.replace('\n', ' '); - CharSequence message = mess; + pinnedText = mess; + pinnedText = Emoji.replaceEmoji(pinnedText, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); if (pinnedMessageObject != null && pinnedMessageObject.messageOwner != null) { - message = MessageObject.replaceAnimatedEmoji(mess, pinnedMessageObject.messageOwner.entities, messageTextView.getPaint().getFontMetricsInt()); + pinnedText = pinnedMessageObject.replaceAnimatedEmoji(pinnedText, messageTextView.getPaint().getFontMetricsInt()); } - pinnedText = Emoji.replaceEmoji(message, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); } if (pinnedText != null) { if (pinnedText instanceof Spannable) { @@ -21285,9 +21703,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private boolean trackWidth = true; + public void setTrackWidth(boolean value) { this.trackWidth = value; } + public boolean getTrackWidth() { return this.trackWidth; } @@ -21335,6 +21755,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean showAddMembersToGroup = preferences.getBoolean("dialog_bar_invite" + did, false); TLRPC.EmojiStatus showEmojiStatusReport = currentUser != null && (showReport || showBlock) && (currentUser.emoji_status instanceof TLRPC.TL_emojiStatus || currentUser.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) ? currentUser.emoji_status : null; boolean showRestartTopic = !isInPreviewMode() && forumTopic != null && forumTopic.closed && !forumTopic.hidden && ChatObject.canManageTopic(currentAccount, currentChat, forumTopic); + boolean showTranslate = getMessagesController().getTranslateController().isDialogTranslatable(getDialogId()) && !getMessagesController().getTranslateController().isTranslateDialogHidden(getDialogId()); if (showRestartTopic) { shownRestartTopic = true; } @@ -21342,13 +21763,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not reportSpamButton.setVisibility(showReport || showBlock || showGeo ? View.VISIBLE : View.GONE); boolean showRestartTopic1 = (showRestartTopic || shownRestartTopic) && !(showReport || showBlock || showGeo); restartTopicButton.setVisibility(showRestartTopic1 ? View.VISIBLE : View.GONE); - closeReportSpam.setVisibility(showRestartTopic1 ? View.GONE : View.VISIBLE); + translateButton.setVisibility(showTranslate ? View.VISIBLE : View.GONE); + if (showTranslate) { + translateButton.updateText(); + } + closeReportSpam.setVisibility(showRestartTopic1 || showTranslate && !(showReport || showBlock || showGeo) ? View.GONE : View.VISIBLE); if (!showRestartTopic) { shownRestartTopic = false; } - if (showRestartTopic) { + if (showRestartTopic || showTranslate) { show = true; } @@ -21382,12 +21807,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not addToContactsButton.setVisibility(View.GONE); chatWithAdminTextView.setText(AndroidUtilities.replaceTags(str)); } else if (showAddMembersToGroup) { - String str = LocaleController.getString("GroupAddMembers", R.string.GroupAddMembers); - if (str != null) { - str = str.toUpperCase(); - } addToContactsButton.setVisibility(View.VISIBLE); - addToContactsButton.setText(str); + addToContactsButton.setText(LocaleController.getString("GroupAddMembers", R.string.GroupAddMembers)); addToContactsButton.setTag(4); addToContactsButton.setTextColor(getThemedColor(Theme.key_chat_addContact)); if (Build.VERSION.SDK_INT >= 21) { @@ -21409,7 +21830,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (reportSpamButton.getVisibility() == View.VISIBLE) { addToContactsButton.setText(LocaleController.getString("AddContactChat", R.string.AddContactChat)); } else { - addToContactsButton.setText(LocaleController.formatString("AddContactFullChat", R.string.AddContactFullChat, UserObject.getFirstName(user)).toUpperCase()); + float baseWidth = addToContactsButton.getPaint().measureText(LocaleController.formatString(R.string.AddContactFullChat, "")); + addToContactsButton.setText(LocaleController.formatString("AddContactFullChat", R.string.AddContactFullChat, TextUtils.ellipsize(UserObject.getFirstName(user), addToContactsButton.getPaint(), getContext().getResources().getDisplayMetrics().widthPixels - baseWidth - AndroidUtilities.dp(64 * 2), TextUtils.TruncateAt.MIDDLE)).toUpperCase()); } } addToContactsButton.setTag(null); @@ -21468,11 +21890,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatWithAdminTextView != null) { chatWithAdminTextView.setVisibility(isChatWithAdmin ? View.VISIBLE : View.GONE); } - if (userBlocked || (addToContactsButton.getVisibility() == View.GONE && reportSpamButton.getVisibility() == View.GONE && (chatWithAdminTextView == null || chatWithAdminTextView.getVisibility() == View.GONE) && restartTopicButton.getVisibility() == View.GONE)) { + if (userBlocked || (addToContactsButton.getVisibility() == View.GONE && reportSpamButton.getVisibility() == View.GONE && (chatWithAdminTextView == null || chatWithAdminTextView.getVisibility() == View.GONE) && restartTopicButton.getVisibility() == View.GONE && translateButton.getVisibility() == View.GONE)) { show = false; } - int topChatPanelHeight; + int topChatPanelHeight = AndroidUtilities.dp(50); if (showEmojiStatusReport != null) { emojiStatusSpamHint.setVisibility(View.VISIBLE); topViewSeparator1.setVisibility(View.VISIBLE); @@ -21513,12 +21935,33 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } emojiStatusSpamHint.setText(text); emojiStatusSpamHint.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x - AndroidUtilities.dp(50), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(99999, View.MeasureSpec.AT_MOST)); - topChatPanelHeight = AndroidUtilities.dp(50 + 16) + emojiStatusSpamHint.getMeasuredHeight(); + topChatPanelHeight += AndroidUtilities.dp(6); + emojiStatusSpamHint.setTranslationY(topChatPanelHeight); + topChatPanelHeight += AndroidUtilities.dp(10) + emojiStatusSpamHint.getMeasuredHeight(); } else { emojiStatusSpamHint.setVisibility(View.GONE); topViewSeparator1.setVisibility(View.GONE); topViewSeparator2.setVisibility(View.GONE); - topChatPanelHeight = AndroidUtilities.dp(50); + } + if (showTranslate) { + if (restartTopicButton.getVisibility() == View.VISIBLE) { +// topChatPanelHeight += AndroidUtilities.dp(48); + topViewSeparator3.setVisibility(View.VISIBLE); + } else if (addToContactsButton.getVisibility() == View.VISIBLE || user != null && !TextUtils.isEmpty(chatWithAdmin)) { + topViewSeparator3.setVisibility(View.VISIBLE); + } else { + topChatPanelHeight -= AndroidUtilities.dp(48); + topViewSeparator3.setVisibility(View.GONE); + } + topChatPanelHeight += AndroidUtilities.dp(36); + } else { + topViewSeparator3.setVisibility(View.GONE); + } + if (topViewSeparator3.getVisibility() == View.VISIBLE || + topViewSeparator2.getVisibility() == View.VISIBLE) { + topViewSeparator1.setVisibility(View.VISIBLE); + } else { + topViewSeparator1.setVisibility(View.GONE); } topChatPanelView.getLayoutParams().height = topChatPanelHeight; @@ -21637,7 +22080,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void checkRaiseSensors() { if (chatActivityEnterView != null && chatActivityEnterView.isStickersExpanded()) { MediaController.getInstance().setAllowStartRecord(false); - } else if (currentChat != null && !ChatObject.canSendMedia(currentChat)) { + } else if (currentChat != null && !ChatObject.canSendVoice(currentChat)) { MediaController.getInstance().setAllowStartRecord(false); } else if (!ApplicationLoader.mainInterfacePaused && (bottomOverlayChat == null || bottomOverlayChat.getVisibility() != View.VISIBLE) && (bottomOverlay == null || bottomOverlay.getVisibility() != View.VISIBLE) && (searchContainer == null || searchContainer.getVisibility() != View.VISIBLE)) { MediaController.getInstance().setAllowStartRecord(true); @@ -21785,6 +22228,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not height += contentPanTranslation; return height - AndroidUtilities.dp(1.5f); } + + @Override + public boolean allowLayoutChanges() { + return false; + } }); checkActionBarMenu(false); @@ -21870,6 +22318,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + public float getPullingDownOffset() { + return pullingDownOffset; + } + public void checkAdjustResize() { if (reportType >= 0) { AndroidUtilities.requestAdjustNothing(getParentActivity(), classGuid); @@ -22657,13 +23109,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } catch (Exception e) { } } - if (messageTextToTranslate == null) { + if (messageTextToTranslate == null && MessageObject.isMediaEmpty(selectedObject.messageOwner)) { messageTextToTranslate = getMessageContent(selectedObject, 0, false); } if (messageTextToTranslate != null && Emoji.fullyConsistsOfEmojis(messageTextToTranslate)) { messageTextToTranslate = null; // message fully consists of emojis, do not translate } } + if (selectedObject.translated) { + messageTextToTranslate = null; + } if (message.isSponsored() && !getMessagesController().premiumLocked) { items.add(LocaleController.getString("HideAd", R.string.HideAd)); @@ -23585,10 +24040,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not popupLayout.addView(rateTranscriptionLayout, rateTranscriptionLayoutParams); } - final boolean translateButtonEnabled = MessagesController.getGlobalMainSettings().getBoolean("translate_button", false); - scrimPopupWindowItems = new ActionBarMenuSubItem[items.size() + (selectedObject.isSponsored() ? 1 : 0)]; + final boolean translateButtonEnabled = MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled(); + scrimPopupWindowItems = new ActionBarMenuSubItem[items.size() + (selectedObject != null && selectedObject.isSponsored() ? 1 : 0)]; for (int a = 0, N = items.size(); a < N; a++) { - if (a == 0 && selectedObject.isSponsored()) { + if (a == 0 && selectedObject != null && selectedObject.isSponsored()) { ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); cell.setTextAndIcon(LocaleController.getString("SponsoredMessageInfo", R.string.SponsoredMessageInfo), R.drawable.msg_info); cell.setItemHeight(56); @@ -23637,9 +24092,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not processSelectedOption(options.get(i)); }); if (option == OPTION_TRANSLATE) { - String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); + String toLangDefault = LocaleController.getInstance().getCurrentLocale().getLanguage(); + String toLang = TranslateAlert2.getToLanguage(); final CharSequence finalMessageText = messageTextToTranslate; - TranslateAlert.OnLinkPress onLinkPress = (link) -> { + Utilities.CallbackReturn onLinkPress = (link) -> { didPressMessageUrl(link, false, selectedObject, v instanceof ChatMessageCell ? (ChatMessageCell) v : null); return true; }; @@ -23652,10 +24108,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not finalMessageText.toString(), (String lang) -> { fromLang[0] = lang; - if (fromLang[0] != null && (!fromLang[0].equals(toLang) || fromLang[0].equals("und")) && ( - translateButtonEnabled && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(fromLang[0]) || - (currentChat != null && (currentChat.has_link || ChatObject.isPublic(currentChat)) || selectedObject.messageOwner.fwd_from != null) && ("uk".equals(fromLang[0]) || "ru".equals(fromLang[0])) - )) { + if (fromLang[0] != null && (!fromLang[0].equals(toLang) || !fromLang[0].equals(toLangDefault) || fromLang[0].equals(TranslateController.UNKNOWN_LANGUAGE)) && ( + translateButtonEnabled && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(fromLang[0]) || + (currentChat != null && (currentChat.has_link || ChatObject.isPublic(currentChat)) || selectedObject.messageOwner.fwd_from != null) && ("uk".equals(fromLang[0]) || "ru".equals(fromLang[0])) + )) { cell.setVisibility(View.VISIBLE); } waitForLangDetection.set(false); @@ -23677,8 +24133,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (selectedObject == null || i >= options.size() || getParentActivity() == null) { return; } - TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageIdToTranslate[0], fromLang[0], toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); - alert.showDim(false); + String toLangValue = fromLang[0] != null && fromLang[0].equals(toLang) ? toLangDefault : toLang; + ArrayList entities = selectedObject != null && selectedObject.messageOwner != null ? selectedObject.messageOwner.entities : null; + TranslateAlert2 alert = TranslateAlert2.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageIdToTranslate[0], fromLang[0], toLangValue, finalMessageText, entities, noforwards, onLinkPress, () -> dimBehindView(false)); + alert.setDimBehind(false); closeMenu(false); }); cell.postDelayed(() -> { @@ -23691,8 +24149,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (selectedObject == null || i >= options.size() || getParentActivity() == null) { return; } - TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageIdToTranslate[0], "und", toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); - alert.showDim(false); + TranslateAlert2 alert = TranslateAlert2.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageIdToTranslate[0], "und", toLang, finalMessageText, null, noforwards, onLinkPress, () -> dimBehindView(false)); + alert.setDimBehind(false); closeMenu(false); }); } else { @@ -24088,7 +24546,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Runnable updateReactionRunnable; - private void selectReaction(MessageObject primaryMessage, ReactionsContainerLayout reactionsLayout, View fromView, float x, float y, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean fromDoubleTap, boolean bigEmoji, boolean addToRecent) { + public void selectReaction(MessageObject primaryMessage, ReactionsContainerLayout reactionsLayout, View fromView, float x, float y, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean fromDoubleTap, boolean bigEmoji, boolean addToRecent) { if (isInScheduleMode()) { return; } @@ -24338,7 +24796,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not String restrictionReason = MessagesController.getRestrictionReason(messageObject.messageOwner.restriction_reason); if (!TextUtils.isEmpty(restrictionReason)) { str.append(restrictionReason); - } else if (messageObject.caption != null){ + } else if (messageObject.caption != null) { str.append(messageObject.caption); } else { str.append(messageObject.messageText); @@ -24445,7 +24903,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not forwardingMessageGroup = selectedObjectGroup; Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putInt("messagesCount", forwardingMessageGroup == null ? 1 : forwardingMessageGroup.messages.size()); args.putInt("hasPoll", forwardingMessage.isPoll() ? (forwardingMessage.isPublicPoll() ? 2 : 1) : 0); args.putBoolean("hasInvoice", forwardingMessage.isInvoice()); @@ -24744,6 +25202,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not checks[1] = !checks[1]; cell1.setChecked(checks[1], true); }); + builder.setCustomViewOffset(6); builder.setView(frameLayout); } } else if (ChatObject.isChannel(currentChat) && currentChat.megagroup || currentChat != null && !ChatObject.isChannel(currentChat)) { @@ -24768,6 +25227,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not checks[0] = !checks[0]; cell1.setChecked(checks[0], true); }); + builder.setCustomViewOffset(9); builder.setView(frameLayout); } } else { @@ -25062,9 +25522,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { + public boolean didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { if (forwardingMessage == null && selectedMessagesIds[0].size() == 0 && selectedMessagesIds[1].size() == 0) { - return; + return false; } ArrayList fmessages = new ArrayList<>(); if (forwardingMessage != null) { @@ -25073,8 +25533,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { fmessages.add(forwardingMessage); } - forwardingMessage = null; - forwardingMessageGroup = null; } else { for (int a = 1; a >= 0; a--) { ArrayList ids = new ArrayList<>(); @@ -25089,6 +25547,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not fmessages.add(messageObject); } } + } + } + for (int j = 0; j < dids.size(); j++) { + TLRPC.Chat chat = getMessagesController().getChat(-dids.get(j).dialogId); + if (chat != null) { + for (int i = 0; i < fmessages.size(); i++) { + int sendError = SendMessagesHelper.canSendMessageToChat(chat, fmessages.get(i)); + if (sendError != 0) { + AlertsCreator.showSendMediaAlert(sendError, fragment, null); + return false; + } + } + } + } + if (forwardingMessage != null) { + forwardingMessage = null; + forwardingMessageGroup = null; + } else { + for (int a = 1; a >= 0; a--) { selectedMessagesCanCopyIds[a].clear(); selectedMessagesCanStarIds[a].clear(); selectedMessagesIds[a].clear(); @@ -25129,7 +25606,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not args.putLong("chat_id", -did); } if (!getMessagesController().checkCanOpenChat(args, fragment)) { - return; + return true; } } args.putBoolean("historyPreloaded", false); @@ -25171,6 +25648,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateVisibleRows(); } } + return true; } public boolean checkRecordLocked(boolean forceCloseOnDiscard) { @@ -25236,7 +25714,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; } - private void clearSelectionMode() { + public void clearSelectionMode() { + clearSelectionMode(false); + } + + public void clearSelectionMode(boolean suppressUpdateMessageObject) { for (int a = 1; a >= 0; a--) { selectedMessagesIds[a].clear(); selectedMessagesCanCopyIds[a].clear(); @@ -25244,7 +25726,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } hideActionMode(); updatePinnedMessageView(true); - updateVisibleRows(); + updateVisibleRows(suppressUpdateMessageObject); + updateSelectedMessageReactions(); } public void onListItemAnimatorTick() { @@ -25294,6 +25777,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateVisibleRows() { + updateVisibleRows(false); + } + + private void updateVisibleRows(boolean suppressUpdateMessageObject) { if (chatListView == null) { return; } @@ -25341,7 +25828,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not cell.setChecked(false, false, true); } - if (!cell.getMessageObject().deleted || cell.linkedChatId != linkedChatId) { + if ((!cell.getMessageObject().deleted || cell.linkedChatId != linkedChatId) && !suppressUpdateMessageObject) { cell.setIsUpdating(true); cell.linkedChatId = chatInfo != null ? chatInfo.linked_chat_id : 0; cell.setMessageObject(cell.getMessageObject(), cell.getCurrentMessagesGroup(), cell.isPinnedBottom(), cell.isPinnedTop()); @@ -25362,7 +25849,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not cell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); } else if (view instanceof ChatActionCell) { ChatActionCell cell = (ChatActionCell) view; - cell.setMessageObject(cell.getMessageObject()); + if (!suppressUpdateMessageObject) { + cell.setMessageObject(cell.getMessageObject()); + } cell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); } } @@ -25495,6 +25984,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return currentEncryptedChat == null && (bottomOverlayChat == null || bottomOverlayChat.getVisibility() != View.VISIBLE) && !isThreadChat(); } + public boolean canSendMessage() { + return currentEncryptedChat == null && (bottomOverlayChat == null || bottomOverlayChat.getVisibility() != View.VISIBLE); + } + public boolean isInScheduleMode() { return chatMode == MODE_SCHEDULED; } @@ -25590,6 +26083,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not afterMessageSend(); } + public void sendAnimatedEmoji(TLRPC.Document emoji, boolean notify, int scheduleDate) { + if (emoji == null) { + return; + } + String message = MessageObject.findAnimatedEmojiEmoticon(emoji, null); + if (message == null) { + return; + } + ArrayList entities = new ArrayList<>(); + TLRPC.TL_messageEntityCustomEmoji entity = new TLRPC.TL_messageEntityCustomEmoji(); + entity.document = emoji; + entity.document_id = emoji.id; + entity.offset = 0; + entity.length = message.length(); + entities.add(entity); + SendMessagesHelper.getInstance(currentAccount).sendMessage(message, dialog_id, replyingMessageObject, getThreadMessage(), null, false, entities, null, null, notify, scheduleDate, null, false); + afterMessageSend(); + } + public void showOpenGameAlert(final TLRPC.TL_game game, final MessageObject messageObject, final String urlStr, boolean ask, final long uid) { TLRPC.User user = getMessagesController().getUser(uid); if (ask) { @@ -25913,7 +26425,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); } - builder.setCustomViewOffset(12); builder.setView(linearLayout); builder.setPositiveButton(LocaleController.getString("Open", R.string.Open), (dialogInterface, i) -> { if (!cells[0].isChecked()) { @@ -26210,8 +26721,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void processExternalUrl(int type, String url, CharacterStyle span, ChatMessageCell cell, boolean forceAlert) { try { - Uri uri = Uri.parse(url); - String host = uri.getHost() != null ? uri.getHost().toLowerCase() : ""; + + String host = AndroidUtilities.getHostAuthority(url); if ((currentEncryptedChat == null || getMessagesController().secretWebpagePreview == 1) && getMessagesController().authDomains.contains(host)) { getSendMessagesHelper().requestUrlAuth(url, this, type == 0 || type == 2); return; @@ -27003,7 +27514,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not !(button instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(button instanceof TLRPC.TL_keyboardButtonCallback) && !(button instanceof TLRPC.TL_keyboardButtonGame) && !(button instanceof TLRPC.TL_keyboardButtonUrl) && !(button instanceof TLRPC.TL_keyboardButtonBuy) && !(button instanceof TLRPC.TL_keyboardButtonUrlAuth) && - !(button instanceof TLRPC.TL_keyboardButtonUserProfile)) { + !(button instanceof TLRPC.TL_keyboardButtonUserProfile) && !(button instanceof TLRPC.TL_keyboardButtonRequestPeer)) { return; } chatActivityEnterView.didPressedBotButton(button, cell.getMessageObject(), cell.getMessageObject(), makeProgressForBotButton(cell, button instanceof TLRPC.TL_keyboardButtonUrl ? button.url : null)); @@ -27405,7 +27916,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void didPressImage(ChatMessageCell cell, float x, float y) { MessageObject message = cell.getMessageObject(); - message.putInDownloadsStore = true; + if (message.isVideo()) { + if (DownloadController.getInstance(currentAccount).canDownloadMedia(message.messageOwner) == 1) { + message.putInDownloadsStore = true; + } + } else { + message.putInDownloadsStore = true; + } if (message.isSendError()) { createMenu(cell, false, false, x, y); return; @@ -27718,7 +28235,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, 640); TLRPC.VideoSize videoSize = null; if (message.messageOwner.action.photo.video_sizes != null && !message.messageOwner.action.photo.video_sizes.isEmpty()) { - videoSize = message.messageOwner.action.photo.video_sizes.get(0); + videoSize = FileLoader.getClosestVideoSizeWithSize(message.messageOwner.action.photo.video_sizes, 1000); } if (cell.getMessageObject().type == MessageObject.TYPE_SUGGEST_PHOTO && !message.isOutOwner()) { if (message.settingAvatar) { @@ -27845,10 +28362,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void didPressBotButton(MessageObject messageObject, TLRPC.KeyboardButton button) { if (getParentActivity() == null || bottomOverlayChat.getVisibility() == View.VISIBLE && - !(button instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(button instanceof TLRPC.TL_keyboardButtonCallback) && - !(button instanceof TLRPC.TL_keyboardButtonGame) && !(button instanceof TLRPC.TL_keyboardButtonUrl) && - !(button instanceof TLRPC.TL_keyboardButtonBuy) && !(button instanceof TLRPC.TL_keyboardButtonUrlAuth) && - !(button instanceof TLRPC.TL_keyboardButtonUserProfile)) { + !(button instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(button instanceof TLRPC.TL_keyboardButtonCallback) && + !(button instanceof TLRPC.TL_keyboardButtonGame) && !(button instanceof TLRPC.TL_keyboardButtonUrl) && + !(button instanceof TLRPC.TL_keyboardButtonBuy) && !(button instanceof TLRPC.TL_keyboardButtonUrlAuth) && + !(button instanceof TLRPC.TL_keyboardButtonUserProfile) && !(button instanceof TLRPC.TL_keyboardButtonRequestPeer)) { return; } chatActivityEnterView.didPressedBotButton(button, messageObject, messageObject); @@ -27896,6 +28413,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not TLRPC.BotInfo mBotInfo = botInfo.size() != 0 ? botInfo.get(currentUser.id) : null; helpView.setText(true, mBotInfo != null ? mBotInfo.description : null, mBotInfo != null ? mBotInfo.description_document != null ? mBotInfo.description_document : mBotInfo.description_photo : null, mBotInfo); } + updateBotHelpCellClick(helpView); } else if (position == loadingDownRow || position == loadingUpRow) { ChatLoadingCell loadingCell = (ChatLoadingCell) holder.itemView; loadingCell.setProgressVisible(loadsCount > 1); @@ -28038,6 +28556,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + message.updateTranslation(false); + if (groupedMessages != null) { + for (int i = 0; i < groupedMessages.messages.size(); ++i) { + groupedMessages.messages.get(i).updateTranslation(false); + } + } messageCell.setMessageObject(message, groupedMessages, pinnedBottom, pinnedTop); messageCell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); messageCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && message.getId() == highlightMessageId); @@ -28348,6 +28872,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + if (message.updateTranslation(false)) { + messageCell.setMessageObject(message, messageCell.getCurrentMessagesGroup(), messageCell.isPinnedBottom(), messageCell.isPinnedTop()); + } else { + MessageObject.GroupedMessages group = messageCell.getCurrentMessagesGroup(); + if (group != null) { + for (int i = 0; i < group.messages.size(); ++i) { + group.messages.get(i).updateTranslation(); + } + } + } boolean selected = false; boolean disableSelection = false; @@ -30477,6 +31011,52 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private void updateBotHelpCellClick(BotHelpCell cell) { + final boolean translateButtonEnabled = MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled(); + if (translateButtonEnabled && LanguageDetector.hasSupport()) { + final CharSequence text = cell.getText(); + LanguageDetector.detectLanguage(text == null ? "" : text.toString(), lang -> { + String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); + if (lang != null && (!lang.equals(toLang) || lang.equals("und")) && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(lang)) { + cell.setOnClickListener(e -> { + + ActionBarPopupWindow.ActionBarPopupWindowLayout layout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext()); + Drawable shadowDrawable2 = ContextCompat.getDrawable(getContext(), R.drawable.popup_fixed_alert).mutate(); + shadowDrawable2.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground), PorterDuff.Mode.MULTIPLY)); + layout.setBackground(shadowDrawable2); + + final Runnable[] dismiss = new Runnable[1]; + ActionBarMenuSubItem translateButton = new ActionBarMenuSubItem(getContext(), true, true); + translateButton.setTextAndIcon(LocaleController.getString("TranslateMessage", R.string.TranslateMessage), R.drawable.msg_translate); + translateButton.setOnClickListener(e2 -> { + TranslateAlert2.showAlert(getContext(), this, currentAccount, lang, toLang, text, null, false, null, null); + if (dismiss[0] != null) { + dismiss[0].run(); + } + }); + layout.addView(translateButton); + + ActionBarPopupWindow window = new ActionBarPopupWindow(layout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + dismiss[0] = () -> window.dismiss(); + window.setPauseNotifications(true); + window.setDismissAnimationDuration(220); + window.setOutsideTouchable(true); + window.setClippingEnabled(true); + window.setAnimationStyle(R.style.PopupContextAnimation); + window.setFocusable(true); + window.showAsDropDown(cell, cell.getWidth() / 2 - AndroidUtilities.dp(90), AndroidUtilities.dp(-16), Gravity.BOTTOM | Gravity.LEFT); + }); + } else { + cell.setClickable(false); + } + }, err -> { + cell.setClickable(false); + }); + } else { + cell.setClickable(false); + } + } + @Override protected boolean allowPresentFragment() { return !inPreviewMode; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index dbbb3f161..c6ee5bc5f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -199,8 +199,9 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image public ChatEditActivity(Bundle args) { super(args); avatarDrawable = new AvatarDrawable(); - imageUpdater = new ImageUpdater(true); chatId = args.getLong("chat_id", 0); + TLRPC.Chat chat = getMessagesController().getChat(chatId); + imageUpdater = new ImageUpdater(true, chat != null && ChatObject.isChannelAndNotMegaGroup(chat) ? ImageUpdater.FOR_TYPE_CHANNEL : ImageUpdater.FOR_TYPE_GROUP, true); } @Override @@ -605,7 +606,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image setAvatarCell.setOnClickListener(v -> { imageUpdater.openMenu(avatar != null, () -> { avatar = null; - MessagesController.getInstance(currentAccount).changeChatAvatar(chatId, null, null, null, 0, null, null, null, null); + MessagesController.getInstance(currentAccount).changeChatAvatar(chatId, null, null, null, null, 0, null, null, null, null); showAvatarProgress(false, true); avatarImage.setImage(null, null, avatarDrawable, currentChat); cameraDrawable.setCurrentFrame(0); @@ -1110,11 +1111,11 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } @Override - public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { avatar = smallSize.location; - if (photo != null || video != null) { - getMessagesController().changeChatAvatar(chatId, null, photo, video, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, null); + if (photo != null || video != null || emojiMarkup != null) { + getMessagesController().changeChatAvatar(chatId, null, photo, video, emojiMarkup, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, null); if (createAfterUpload) { try { if (progressDialog != null && progressDialog.isShowing()) { @@ -1473,24 +1474,13 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } else { int count = 0; if (currentChat.default_banned_rights != null) { - if (!currentChat.default_banned_rights.send_stickers) { - count++; - } - if (!currentChat.default_banned_rights.send_media) { - count++; - } - if (!currentChat.default_banned_rights.embed_links) { - count++; - } - if (!currentChat.default_banned_rights.send_messages) { + if (!currentChat.default_banned_rights.send_plain) { count++; } + count += ChatUsersActivity.getSendMediaSelectedCount(currentChat.default_banned_rights); if (!currentChat.default_banned_rights.pin_messages) { count++; } - if (!currentChat.default_banned_rights.send_polls) { - count++; - } if (!currentChat.default_banned_rights.invite_users) { count++; } @@ -1501,9 +1491,9 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image count++; } } else { - count = forum ? 9 : 8; + count = forum ? 14 : 13; } - blockCell.setTextAndValueAndIcon(LocaleController.getString("ChannelPermissions", R.string.ChannelPermissions), String.format("%d/%d", count, forum ? 9 : 8), animated, R.drawable.msg_permissions, true); + blockCell.setTextAndValueAndIcon(LocaleController.getString("ChannelPermissions", R.string.ChannelPermissions), String.format("%d/%d", count, forum ? 14 : 13), animated, R.drawable.msg_permissions, true); } if (memberRequestsCell != null) { memberRequestsCell.setTextAndValueAndIcon(LocaleController.getString("MemberRequests", R.string.MemberRequests), String.format("%d", info.requests_pending), R.drawable.msg_requests, logCell != null && logCell.getVisibility() == View.VISIBLE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index c4426ad15..9e2f0ddbe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -39,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.ChatObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -55,6 +56,7 @@ import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.DialogRadioCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.PollEditTextCell; @@ -69,12 +71,14 @@ import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CircularProgressDrawable; import org.telegram.ui.Components.CrossfadeDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; import java.util.Calendar; +import java.util.Locale; public class ChatRightsEditActivity extends BaseFragment { @@ -136,6 +140,12 @@ public class ChatRightsEditActivity extends BaseFragment { private int sendMessagesRow; private int sendMediaRow; + private int sendPhotosRow; + private int sendVideosRow; + private int sendMusicRow; + private int sendFilesRow; + private int sendVoiceRow; + private int sendRoundRow; private int sendStickersRow; private int sendPollsRow; private int embedLinksRow; @@ -154,9 +164,11 @@ public class ChatRightsEditActivity extends BaseFragment { public static final int TYPE_ADD_BOT = 2; private boolean closingKeyboardAfterFinish = false; + private boolean sendMediaExpanded; public interface ChatRightsEditActivityDelegate { void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank); + void didChangeOwner(TLRPC.User user); } @@ -261,10 +273,12 @@ public class ChatRightsEditActivity extends BaseFragment { if (defaultBannedRights == null) { defaultBannedRights = new TLRPC.TL_chatBannedRights(); defaultBannedRights.view_messages = defaultBannedRights.send_media = defaultBannedRights.send_messages = - defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = - defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = - defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = - defaultBannedRights.manage_topics = true; + defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = + defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = + defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = + defaultBannedRights.manage_topics = defaultBannedRights.send_plain = defaultBannedRights.send_videos = + defaultBannedRights.send_photos = defaultBannedRights.send_audios = defaultBannedRights.send_docs = + defaultBannedRights.send_voices = defaultBannedRights.send_roundvideos = false; } if (!defaultBannedRights.change_info) { @@ -278,19 +292,21 @@ public class ChatRightsEditActivity extends BaseFragment { if (defaultBannedRights == null) { defaultBannedRights = new TLRPC.TL_chatBannedRights(); defaultBannedRights.view_messages = defaultBannedRights.send_media = defaultBannedRights.send_messages = - defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = - defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = - defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = - defaultBannedRights.manage_topics = false; + defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = + defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = + defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = + defaultBannedRights.manage_topics = defaultBannedRights.send_plain = defaultBannedRights.send_videos = + defaultBannedRights.send_photos = defaultBannedRights.send_audios = defaultBannedRights.send_docs = + defaultBannedRights.send_voices = defaultBannedRights.send_roundvideos = false; } bannedRights = new TLRPC.TL_chatBannedRights(); if (rightsBanned == null) { bannedRights.view_messages = bannedRights.send_media = bannedRights.send_messages = - bannedRights.embed_links = bannedRights.send_stickers = bannedRights.send_gifs = - bannedRights.send_games = bannedRights.send_inline = bannedRights.send_polls = - bannedRights.invite_users = bannedRights.change_info = bannedRights.pin_messages = - bannedRights.manage_topics = false; + bannedRights.embed_links = bannedRights.send_stickers = bannedRights.send_gifs = + bannedRights.send_games = bannedRights.send_inline = bannedRights.send_polls = + bannedRights.invite_users = bannedRights.change_info = bannedRights.pin_messages = + bannedRights.manage_topics = false; } else { bannedRights.view_messages = rightsBanned.view_messages; bannedRights.send_messages = rightsBanned.send_messages; @@ -306,6 +322,13 @@ public class ChatRightsEditActivity extends BaseFragment { bannedRights.pin_messages = rightsBanned.pin_messages; bannedRights.until_date = rightsBanned.until_date; bannedRights.manage_topics = rightsBanned.manage_topics; + bannedRights.send_photos = rightsBanned.send_photos; + bannedRights.send_videos = rightsBanned.send_videos; + bannedRights.send_roundvideos = rightsBanned.send_roundvideos; + bannedRights.send_audios = rightsBanned.send_audios; + bannedRights.send_voices = rightsBanned.send_voices; + bannedRights.send_docs = rightsBanned.send_docs; + bannedRights.send_plain = rightsBanned.send_plain; } if (defaultBannedRights.view_messages) { bannedRights.view_messages = true; @@ -346,6 +369,27 @@ public class ChatRightsEditActivity extends BaseFragment { if (defaultBannedRights.manage_topics) { bannedRights.manage_topics = true; } + if (defaultBannedRights.send_photos) { + bannedRights.send_photos = true; + } + if (defaultBannedRights.send_videos) { + bannedRights.send_videos = true; + } + if (defaultBannedRights.send_audios) { + bannedRights.send_audios = true; + } + if (defaultBannedRights.send_docs) { + bannedRights.send_docs = true; + } + if (defaultBannedRights.send_voices) { + bannedRights.send_voices = true; + } + if (defaultBannedRights.send_roundvideos) { + bannedRights.send_roundvideos = true; + } + if (defaultBannedRights.send_plain) { + bannedRights.send_plain = true; + } currentBannedRights = ChatObject.getBannedRightsString(bannedRights); @@ -354,15 +398,30 @@ public class ChatRightsEditActivity extends BaseFragment { updateRows(false); } - public static TLRPC.TL_chatAdminRights emptyAdminRights(boolean value) { + public static TLRPC.TL_chatAdminRights rightsOR(TLRPC.TL_chatAdminRights a, TLRPC.TL_chatAdminRights b) { TLRPC.TL_chatAdminRights adminRights = new TLRPC.TL_chatAdminRights(); - adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = - adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = - adminRights.pin_messages = adminRights.add_admins = adminRights.manage_call = adminRights.manage_topics = value; + adminRights.change_info = a.change_info || b.change_info; + adminRights.post_messages = a.post_messages || b.post_messages; + adminRights.edit_messages = a.edit_messages || b.edit_messages; + adminRights.delete_messages = a.delete_messages || b.delete_messages; + adminRights.ban_users = a.ban_users || b.ban_users; + adminRights.invite_users = a.invite_users || b.invite_users; + adminRights.pin_messages = a.pin_messages || b.pin_messages; + adminRights.add_admins = a.add_admins || b.add_admins; + adminRights.manage_call = a.manage_call || b.manage_call; + adminRights.manage_topics = a.manage_topics || b.manage_topics; return adminRights; } + public static TLRPC.TL_chatAdminRights emptyAdminRights(boolean value) { + TLRPC.TL_chatAdminRights adminRights = new TLRPC.TL_chatAdminRights(); + adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = + adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = + adminRights.pin_messages = adminRights.add_admins = adminRights.manage_call = adminRights.manage_topics = value; + return adminRights; + } + @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); @@ -400,6 +459,7 @@ public class ChatRightsEditActivity extends BaseFragment { fragmentView = new FrameLayout(context) { private int previousHeight = -1; + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); @@ -445,7 +505,10 @@ public class ChatRightsEditActivity extends BaseFragment { if (currentType == TYPE_ADD_BOT) { listView.setResetSelectorOnChanged(false); } + itemAnimator.setSupportsChangeAnimations(false); itemAnimator.setDelayAnimations(false); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDurations(350); listView.setItemAnimator(itemAnimator); listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -463,13 +526,32 @@ public class ChatRightsEditActivity extends BaseFragment { if (!canEdit && (!currentChat.creator || currentType != TYPE_ADMIN || position != anonymousRow)) { return; } + if (position == sendMediaRow) { +// if (allDefaultMediaBanned()) { +// new AlertDialog.Builder(getParentActivity()) +// .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) +// .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) +// .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) +// .create() +// .show(); +// return; +// } + sendMediaExpanded = !sendMediaExpanded; + updateRows(false); + if (sendMediaExpanded) { + listViewAdapter.notifyItemRangeInserted(sendMediaRow + 1, 9); + } else { + listViewAdapter.notifyItemRangeRemoved(sendMediaRow + 1, 9); + } + return; + } if (position == 0) { Bundle args = new Bundle(); args.putLong("user_id", currentUser.id); presentFragment(new ProfileActivity(args)); } else if (position == removeAdminRow) { if (currentType == TYPE_ADMIN) { - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), currentRank, isChannel, getFragmentForAlert(0), isAddingNew, false, null,null); + MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), currentRank, isChannel, getFragmentForAlert(0), isAddingNew, false, null, null); if (delegate != null) { delegate.didSetRights(0, adminRights, bannedRights, currentRank); } @@ -630,30 +712,78 @@ public class ChatRightsEditActivity extends BaseFragment { } builder.setCustomView(linearLayout); showDialog(builder.create()); + } else if (view instanceof CheckBoxCell) { + CheckBoxCell checkBoxCell = (CheckBoxCell) view; + if (currentType == TYPE_BANNED && bannedRights != null) { + boolean disabled = !checkBoxCell.isChecked(); + boolean value = false; + + if (checkBoxCell.hasIcon()) { + if (currentType != TYPE_ADD_BOT) { + new AlertDialog.Builder(getParentActivity()) + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyDisabled", R.string.UserRestrictionsCantModifyDisabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); + } + return; + } + + if (position == sendPhotosRow) { + value = bannedRights.send_photos = !bannedRights.send_photos; + } else if (position == sendVideosRow) { + value = bannedRights.send_videos = !bannedRights.send_videos; + } else if (position == sendMusicRow) { + value = bannedRights.send_audios = !bannedRights.send_audios; + } else if (position == sendFilesRow) { + value = bannedRights.send_docs = !bannedRights.send_docs; + } else if (position == sendRoundRow) { + value = bannedRights.send_roundvideos = !bannedRights.send_roundvideos; + } else if (position == sendVoiceRow) { + value = bannedRights.send_voices = !bannedRights.send_voices; + } else if (position == sendStickersRow) { + value = bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = !bannedRights.send_stickers; + } else if (position == embedLinksRow) { + if (bannedRights.send_plain || defaultBannedRights.send_plain) { + View senMessagesView = linearLayoutManager.findViewByPosition(sendMessagesRow); + if (senMessagesView != null) { + AndroidUtilities.shakeViewSpring(senMessagesView); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + return; + } + } + value = bannedRights.embed_links = !bannedRights.embed_links; + } else if (position == sendPollsRow) { + value = bannedRights.send_polls = !bannedRights.send_polls; + } + listViewAdapter.notifyItemChanged(sendMediaRow); + checkBoxCell.setChecked(!value, true); + } } else if (view instanceof TextCheckCell2) { TextCheckCell2 checkCell = (TextCheckCell2) view; if (checkCell.hasIcon()) { if (currentType != TYPE_ADD_BOT) { new AlertDialog.Builder(getParentActivity()) - .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) - .setMessage(LocaleController.getString("UserRestrictionsCantModifyDisabled", R.string.UserRestrictionsCantModifyDisabled)) - .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) - .create() - .show(); + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyDisabled", R.string.UserRestrictionsCantModifyDisabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); } return; } if (!checkCell.isEnabled()) { if ((currentType == TYPE_ADD_BOT || currentType == TYPE_ADMIN) && - (position == changeInfoRow && defaultBannedRights != null && !defaultBannedRights.change_info || - position == pinMessagesRow && defaultBannedRights != null && !defaultBannedRights.pin_messages)) { + (position == changeInfoRow && defaultBannedRights != null && !defaultBannedRights.change_info || + position == pinMessagesRow && defaultBannedRights != null && !defaultBannedRights.pin_messages)) { new AlertDialog.Builder(getParentActivity()) - .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) - .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) - .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) - .create() - .show(); + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); } return; } @@ -705,63 +835,18 @@ public class ChatRightsEditActivity extends BaseFragment { } else if (currentType == TYPE_BANNED && bannedRights != null) { boolean disabled = !checkCell.isChecked(); if (position == sendMessagesRow) { - value = bannedRights.send_messages = !bannedRights.send_messages; - } else if (position == sendMediaRow) { - value = bannedRights.send_media = !bannedRights.send_media; - } else if (position == sendStickersRow) { - value = bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = !bannedRights.send_stickers; - } else if (position == embedLinksRow) { - value = bannedRights.embed_links = !bannedRights.embed_links; - } else if (position == sendPollsRow) { - value = bannedRights.send_polls = !bannedRights.send_polls; + value = bannedRights.send_plain = !bannedRights.send_plain; } - if (disabled) { - if (bannedRights.view_messages && !bannedRights.send_messages) { - bannedRights.send_messages = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMessagesRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((bannedRights.view_messages || bannedRights.send_messages) && !bannedRights.send_media) { - bannedRights.send_media = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMediaRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((bannedRights.view_messages || bannedRights.send_messages) && !bannedRights.send_polls) { - bannedRights.send_polls = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendPollsRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((bannedRights.view_messages || bannedRights.send_messages) && !bannedRights.send_stickers) { - bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendStickersRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((bannedRights.view_messages || bannedRights.send_messages) && !bannedRights.embed_links) { - bannedRights.embed_links = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(embedLinksRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - } else { - if ((!bannedRights.send_messages || !bannedRights.embed_links || !bannedRights.send_inline || !bannedRights.send_media || !bannedRights.send_polls) && bannedRights.view_messages) { + if (!disabled) { + if ((!bannedRights.send_plain || !bannedRights.embed_links || !bannedRights.send_inline || !bannedRights.send_photos || !bannedRights.send_videos || !bannedRights.send_audios || !bannedRights.send_docs || !bannedRights.send_voices || !bannedRights.send_roundvideos || !bannedRights.send_polls) && bannedRights.view_messages) { bannedRights.view_messages = false; } - if ((!bannedRights.embed_links || !bannedRights.send_inline || !bannedRights.send_media || !bannedRights.send_polls) && bannedRights.send_messages) { - bannedRights.send_messages = false; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMessagesRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(true); - } - } + } + if (embedLinksRow >= 0) { + listViewAdapter.notifyItemChanged(embedLinksRow); + } + if (sendMediaRow >= 0) { + listViewAdapter.notifyItemChanged(sendMediaRow); } } if (currentType == TYPE_ADD_BOT) { @@ -982,6 +1067,13 @@ public class ChatRightsEditActivity extends BaseFragment { sendMessagesRow = -1; sendMediaRow = -1; + + sendPhotosRow = -1; + sendVideosRow = -1; + sendMusicRow = -1; + sendFilesRow = -1; + sendVoiceRow = -1; + sendRoundRow = -1; sendStickersRow = -1; sendPollsRow = -1; embedLinksRow = -1; @@ -1021,9 +1113,18 @@ public class ChatRightsEditActivity extends BaseFragment { } else if (currentType == TYPE_BANNED) { sendMessagesRow = rowCount++; sendMediaRow = rowCount++; - sendStickersRow = rowCount++; - sendPollsRow = rowCount++; - embedLinksRow = rowCount++; + if (sendMediaExpanded) { + sendPhotosRow = rowCount++; + sendVideosRow = rowCount++; + sendFilesRow = rowCount++; + sendMusicRow = rowCount++; + sendVoiceRow = rowCount++; + sendRoundRow = rowCount++; + sendStickersRow = rowCount++; + sendPollsRow = rowCount++; + embedLinksRow = rowCount++; + } + addUsersRow = rowCount++; pinMessagesRow = rowCount++; changeInfoRow = rowCount++; @@ -1136,10 +1237,10 @@ public class ChatRightsEditActivity extends BaseFragment { MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, adminRights, currentRank, isChannel, this, isAddingNew, false, null, () -> { if (delegate != null) { delegate.didSetRights( - adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || - adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || (isForum && adminRights.manage_topics) || - adminRights.pin_messages || adminRights.add_admins || adminRights.anonymous || adminRights.manage_call || - adminRights.other ? 1 : 0, adminRights, bannedRights, currentRank); + adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || + adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || (isForum && adminRights.manage_topics) || + adminRights.pin_messages || adminRights.add_admins || adminRights.anonymous || adminRights.manage_call || + adminRights.other ? 1 : 0, adminRights, bannedRights, currentRank); finishFragment(); } }, err -> { @@ -1162,17 +1263,17 @@ public class ChatRightsEditActivity extends BaseFragment { } else if (currentType == TYPE_ADD_BOT) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(asAdmin ? - LocaleController.getString("AddBotAdmin", R.string.AddBotAdmin) : - LocaleController.getString("AddBot", R.string.AddBot) + LocaleController.getString("AddBotAdmin", R.string.AddBotAdmin) : + LocaleController.getString("AddBot", R.string.AddBot) ); boolean isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; String chatName = currentChat == null ? "" : currentChat.title; builder.setMessage(AndroidUtilities.replaceTags( - asAdmin ? ( - isChannel ? - LocaleController.formatString("AddBotMessageAdminChannel", R.string.AddBotMessageAdminChannel, chatName) : - LocaleController.formatString("AddBotMessageAdminGroup", R.string.AddBotMessageAdminGroup, chatName) - ) : LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(currentUser), chatName) + asAdmin ? ( + isChannel ? + LocaleController.formatString("AddBotMessageAdminChannel", R.string.AddBotMessageAdminChannel, chatName) : + LocaleController.formatString("AddBotMessageAdminGroup", R.string.AddBotMessageAdminGroup, chatName) + ) : LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(currentUser), chatName) )); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.setPositiveButton(asAdmin ? LocaleController.getString("AddAsAdmin", R.string.AddAsAdmin) : LocaleController.getString("AddBot", R.string.AddBot), (di, i) -> { @@ -1301,6 +1402,8 @@ public class ChatRightsEditActivity extends BaseFragment { private final int VIEW_TYPE_UNTIL_DATE_CELL = 6; private final int VIEW_TYPE_RANK_CELL = 7; private final int VIEW_TYPE_ADD_BOT_CELL = 8; + private final int VIEW_TYPE_EXPANDABLE_SWITCH = 9; + private final int VIEW_TYPE_INNER_CHECK = 10; private Context mContext; private boolean ignoreTextChange; @@ -1335,7 +1438,7 @@ public class ChatRightsEditActivity extends BaseFragment { if (position == rankRow) return 18; if (position == rankInfoRow) return 19; if (position == sendMessagesRow) return 20; - if (position == sendMediaRow) return 21; + if (position == sendPhotosRow) return 21; if (position == sendStickersRow) return 22; if (position == sendPollsRow) return 23; if (position == embedLinksRow) return 24; @@ -1344,6 +1447,12 @@ public class ChatRightsEditActivity extends BaseFragment { if (position == untilDateRow) return 27; if (position == addBotButtonRow) return 28; if (position == manageTopicsRow) return 29; + if (position == sendVideosRow) return 30; + if (position == sendFilesRow) return 31; + if (position == sendMusicRow) return 32; + if (position == sendVoiceRow) return 33; + if (position == sendRoundRow) return 34; + if (position == sendMediaRow) return 35; return 0; } else { return super.getItemId(position); @@ -1421,6 +1530,7 @@ public class ChatRightsEditActivity extends BaseFragment { view = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlueHeader, 21, 15, true); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; + case VIEW_TYPE_EXPANDABLE_SWITCH: case VIEW_TYPE_SWITCH_CELL: view = new TextCheckCell2(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -1482,6 +1592,14 @@ public class ChatRightsEditActivity extends BaseFragment { }); view = cell; break; + case VIEW_TYPE_INNER_CHECK: + CheckBoxCell checkBoxCell = new CheckBoxCell(mContext, 4, 21, getResourceProvider()); + checkBoxCell.getCheckBoxRound().setDrawBackgroundAsArc(14); + checkBoxCell.getCheckBoxRound().setColor(Theme.key_switch2TrackChecked, Theme.key_radioBackground, Theme.key_checkboxCheck); + checkBoxCell.setEnabled(true); + view = checkBoxCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; } return new RecyclerListView.Holder(view); } @@ -1489,6 +1607,39 @@ public class ChatRightsEditActivity extends BaseFragment { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { + case VIEW_TYPE_INNER_CHECK: + CheckBoxCell checkBoxCell = (CheckBoxCell) holder.itemView; + boolean animated = checkBoxCell.getTag() != null && (Integer) checkBoxCell.getTag() == position; + checkBoxCell.setTag(position); + if (position == sendStickersRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs), "", !bannedRights.send_stickers && !defaultBannedRights.send_stickers, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_stickers ? R.drawable.permission_locked : 0); + } else if (position == embedLinksRow) { + checkBoxCell.setText(LocaleController.getString("UserRestrictionsEmbedLinks", R.string.UserRestrictionsEmbedLinks), "", !bannedRights.embed_links && !defaultBannedRights.embed_links && !bannedRights.send_plain && !defaultBannedRights.send_plain, true, animated); + checkBoxCell.setIcon(defaultBannedRights.embed_links ? R.drawable.permission_locked : 0); + } else if (position == sendPollsRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPolls", R.string.SendMediaPolls), "", !bannedRights.send_polls && !defaultBannedRights.send_polls, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_polls ? R.drawable.permission_locked : 0); + } else if (position == sendPhotosRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionPhotos", R.string.SendMediaPermissionPhotos), "", !bannedRights.send_photos && !defaultBannedRights.send_photos, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_photos ? R.drawable.permission_locked : 0); + } else if (position == sendVideosRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionVideos", R.string.SendMediaPermissionVideos), "", !bannedRights.send_videos && !defaultBannedRights.send_videos, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_videos ? R.drawable.permission_locked : 0); + } else if (position == sendMusicRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionMusic", R.string.SendMediaPermissionMusic), "", !bannedRights.send_audios && !defaultBannedRights.send_audios, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_audios ? R.drawable.permission_locked : 0); + } else if (position == sendFilesRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionFiles", R.string.SendMediaPermissionFiles), "", !bannedRights.send_docs && !defaultBannedRights.send_docs, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_docs ? R.drawable.permission_locked : 0); + } else if (position == sendVoiceRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionVoice", R.string.SendMediaPermissionVoice), "", !bannedRights.send_voices && !defaultBannedRights.send_voices, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_voices ? R.drawable.permission_locked : 0); + } else if (position == sendRoundRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionRound", R.string.SendMediaPermissionRound), "", !bannedRights.send_roundvideos && !defaultBannedRights.send_roundvideos, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_roundvideos ? R.drawable.permission_locked : 0); + } + break; case VIEW_TYPE_USER_CELL: UserCell2 userCell2 = (UserCell2) holder.itemView; String status = null; @@ -1545,11 +1696,30 @@ public class ChatRightsEditActivity extends BaseFragment { headerCell.setText(LocaleController.getString("EditAdminRank", R.string.EditAdminRank)); } break; + case VIEW_TYPE_EXPANDABLE_SWITCH: case VIEW_TYPE_SWITCH_CELL: TextCheckCell2 checkCell = (TextCheckCell2) holder.itemView; boolean asAdminValue = currentType != TYPE_ADD_BOT || asAdmin; boolean isCreator = (currentChat != null && currentChat.creator); - if (position == manageRow) { + if (position == sendMediaRow) { + int sentMediaCount = getSendMediaSelectedCount(); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), sentMediaCount > 0, true, true); + checkCell.setCollapseArrow(String.format(Locale.US, "%d/9", sentMediaCount), !sendMediaExpanded, () -> { + if (allDefaultMediaBanned()) { + new AlertDialog.Builder(getParentActivity()) + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); + return; + } + boolean checked = !checkCell.isChecked(); + checkCell.setChecked(checked); + setSendMediaEnabled(checked); + }); + checkCell.setIcon(allDefaultMediaBanned() ? R.drawable.permission_locked : 0); + } else if (position == manageRow) { checkCell.setTextAndCheck(LocaleController.getString("ManageGroup", R.string.ManageGroup), asAdmin, true); checkCell.setIcon(myAdminRights.add_admins || isCreator ? 0 : R.drawable.permission_locked); } else if (position == changeInfoRow) { @@ -1640,28 +1810,17 @@ public class ChatRightsEditActivity extends BaseFragment { checkCell.setIcon(defaultBannedRights.pin_messages ? R.drawable.permission_locked : 0); } } else if (position == sendMessagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSend", R.string.UserRestrictionsSend), !bannedRights.send_messages && !defaultBannedRights.send_messages, true); - checkCell.setIcon(defaultBannedRights.send_messages ? R.drawable.permission_locked : 0); - } else if (position == sendMediaRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), !bannedRights.send_media && !defaultBannedRights.send_media, true); - checkCell.setIcon(defaultBannedRights.send_media ? R.drawable.permission_locked : 0); - } else if (position == sendStickersRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendStickers", R.string.UserRestrictionsSendStickers), !bannedRights.send_stickers && !defaultBannedRights.send_stickers, true); - checkCell.setIcon(defaultBannedRights.send_stickers ? R.drawable.permission_locked : 0); - } else if (position == embedLinksRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsEmbedLinks", R.string.UserRestrictionsEmbedLinks), !bannedRights.embed_links && !defaultBannedRights.embed_links, true); - checkCell.setIcon(defaultBannedRights.embed_links ? R.drawable.permission_locked : 0); - } else if (position == sendPollsRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendPolls", R.string.UserRestrictionsSendPolls), !bannedRights.send_polls && !defaultBannedRights.send_polls, true); - checkCell.setIcon(defaultBannedRights.send_polls ? R.drawable.permission_locked : 0); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSend", R.string.UserRestrictionsSend), !bannedRights.send_plain && !defaultBannedRights.send_plain, true); + checkCell.setIcon(defaultBannedRights.send_plain ? R.drawable.permission_locked : 0); } if (currentType == TYPE_ADD_BOT) { // checkCell.setEnabled((asAdmin || position == manageRow) && !checkCell.hasIcon(), false); } else { - if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { - checkCell.setEnabled(!bannedRights.send_messages && !bannedRights.view_messages && !defaultBannedRights.send_messages && !defaultBannedRights.view_messages); - } else if (position == sendMessagesRow) { +// if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { +// checkCell.setEnabled(!bannedRights.send_messages && !bannedRights.view_messages && !defaultBannedRights.send_messages && !defaultBannedRights.view_messages); +// } else + if (position == sendMessagesRow) { checkCell.setEnabled(!bannedRights.view_messages && !defaultBannedRights.view_messages); } } @@ -1729,7 +1888,11 @@ public class ChatRightsEditActivity extends BaseFragment { @Override public int getItemViewType(int position) { - if (position == 0) { + if (isExpandableSendMediaRow(position)) { + return VIEW_TYPE_INNER_CHECK; + } else if (position == sendMediaRow) { + return VIEW_TYPE_EXPANDABLE_SWITCH; + } else if (position == 0) { return VIEW_TYPE_USER_CELL; } else if (position == 1 || position == rightsShadowRow || position == removeAdminShadowRow || position == untilSectionRow || position == transferOwnerShadowRow) { return VIEW_TYPE_SHADOW_CELL; @@ -1737,8 +1900,7 @@ public class ChatRightsEditActivity extends BaseFragment { return VIEW_TYPE_HEADER_CELL; } else if (position == changeInfoRow || position == postMessagesRow || position == editMesagesRow || position == deleteMessagesRow || position == addAdminsRow || position == banUsersRow || position == addUsersRow || position == pinMessagesRow || - position == sendMessagesRow || position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || - position == sendPollsRow || position == anonymousRow || position == startVoiceChatRow || position == manageRow || position == manageTopicsRow) { + position == sendMessagesRow || position == anonymousRow || position == startVoiceChatRow || position == manageRow || position == manageTopicsRow) { return VIEW_TYPE_SWITCH_CELL; } else if (position == cantEditInfoRow || position == rankInfoRow) { return VIEW_TYPE_INFO_CELL; @@ -1754,7 +1916,69 @@ public class ChatRightsEditActivity extends BaseFragment { } } + private void setSendMediaEnabled(boolean enabled) { + bannedRights.send_media = !enabled; + bannedRights.send_photos = !enabled; + bannedRights.send_videos = !enabled; + bannedRights.send_stickers = !enabled; + bannedRights.send_audios = !enabled; + bannedRights.send_docs = !enabled; + bannedRights.send_voices = !enabled; + bannedRights.send_roundvideos = !enabled; + bannedRights.embed_links = !enabled; + bannedRights.send_polls = !enabled; + AndroidUtilities.updateVisibleRows(listView); + } + + private int getSendMediaSelectedCount() { + int i = 0; + if (!bannedRights.send_photos && !defaultBannedRights.send_photos) { + i++; + } + if (!bannedRights.send_videos && !defaultBannedRights.send_videos) { + i++; + } + if (!bannedRights.send_stickers && !defaultBannedRights.send_stickers) { + i++; + } + if (!bannedRights.send_audios && !defaultBannedRights.send_audios) { + i++; + } + if (!bannedRights.send_docs && !defaultBannedRights.send_docs) { + i++; + } + if (!bannedRights.send_voices && !defaultBannedRights.send_voices) { + i++; + } + if (!bannedRights.send_roundvideos && !defaultBannedRights.send_roundvideos) { + i++; + } + if (!bannedRights.embed_links && !defaultBannedRights.embed_links && !bannedRights.send_plain && !defaultBannedRights.send_plain) { + i++; + } + if (!bannedRights.send_polls && !defaultBannedRights.send_polls) { + i++; + } + return i; + } + + private boolean allDefaultMediaBanned() { + return 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; + } + + private boolean isExpandableSendMediaRow(int position) { + if (position == sendStickersRow || position == embedLinksRow || position == sendPollsRow || + position == sendPhotosRow || position == sendVideosRow || position == sendFilesRow || + position == sendMusicRow || position == sendRoundRow || position == sendVoiceRow) { + return true; + } + return false; + } + private ValueAnimator asAdminAnimator; + private void updateAsAdmin(boolean animated) { if (addBotButton != null) { addBotButton.invalidate(); @@ -1766,7 +1990,7 @@ public class ChatRightsEditActivity extends BaseFragment { if (child instanceof TextCheckCell2) { if (!asAdmin) { if (childPosition == changeInfoRow && !defaultBannedRights.change_info || - childPosition == pinMessagesRow && !defaultBannedRights.pin_messages) { + childPosition == pinMessagesRow && !defaultBannedRights.pin_messages) { ((TextCheckCell2) child).setChecked(true); ((TextCheckCell2) child).setEnabled(false, false); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index c949e900c..1417d83f7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -19,7 +19,6 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; -import android.util.Log; import android.util.SparseIntArray; import android.view.Gravity; import android.view.View; @@ -35,6 +34,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.ChatObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -54,6 +54,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Adapters.SearchAdapterHelper; +import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.LoadingCell; @@ -65,6 +66,7 @@ import org.telegram.ui.Cells.TextCheckCell2; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.GigagroupConvertAlert; import org.telegram.ui.Components.LayoutHelper; @@ -76,10 +78,14 @@ import org.telegram.ui.Components.UndoView; import java.util.ArrayList; import java.util.Collections; +import java.util.Locale; import java.util.concurrent.atomic.AtomicInteger; public class ChatUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + private static final int VIEW_TYPE_INNER_CHECK = 13; + private static final int VIEW_TYPE_EXPANDABLE_SWITCH = 14; + private ListAdapter listViewAdapter; private StickerEmptyView emptyView; private RecyclerListView listView; @@ -113,8 +119,17 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private int permissionsSectionRow; private int sendMessagesRow; private int sendMediaRow; - private int sendStickersRow; + private int sendMediaPhotosRow; + private int sendMediaVideosRow; + private int sendMediaStickerGifsRow; + private int sendMediaMusicRow; + private int sendMediaFilesRow; + private int sendMediaVoiceMessagesRow; + private int sendMediaVideoMessagesRow; + private int sendMediaEmbededLinksRow; private int sendPollsRow; + + private int sendStickersRow; private int embedLinksRow; private int changeInfoRow; private int addUsersRow; @@ -164,6 +179,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private int delayResults; + private boolean sendMediaExpanded; + private ChatUsersActivityDelegate delegate; private boolean needOpenSearch; @@ -229,6 +246,21 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente defaultBannedRights.invite_users = currentChat.default_banned_rights.invite_users; defaultBannedRights.manage_topics = currentChat.default_banned_rights.manage_topics; defaultBannedRights.change_info = currentChat.default_banned_rights.change_info; + defaultBannedRights.send_photos = currentChat.default_banned_rights.send_photos; + defaultBannedRights.send_videos = currentChat.default_banned_rights.send_videos; + defaultBannedRights.send_roundvideos = currentChat.default_banned_rights.send_roundvideos; + defaultBannedRights.send_audios = currentChat.default_banned_rights.send_audios; + defaultBannedRights.send_voices = currentChat.default_banned_rights.send_voices; + defaultBannedRights.send_docs = currentChat.default_banned_rights.send_docs; + defaultBannedRights.send_plain = currentChat.default_banned_rights.send_plain; + if (!defaultBannedRights.send_media && defaultBannedRights.send_docs && defaultBannedRights.send_voices && defaultBannedRights.send_audios && defaultBannedRights.send_roundvideos && defaultBannedRights.send_videos && defaultBannedRights.send_photos) { + defaultBannedRights.send_photos = false; + defaultBannedRights.send_videos = false; + defaultBannedRights.send_roundvideos = false; + defaultBannedRights.send_audios = false; + defaultBannedRights.send_voices = false; + defaultBannedRights.send_docs = false; + } } initialBannedRights = ChatObject.getBannedRightsString(defaultBannedRights); isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; @@ -282,15 +314,31 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente loadingProgressRow = -1; loadingUserCellRow = -1; loadingHeaderRow = -1; + sendMediaPhotosRow = -1; + sendMediaVideosRow = -1; + sendMediaStickerGifsRow = -1; + sendMediaMusicRow = -1; + sendMediaFilesRow = -1; + sendMediaVoiceMessagesRow = -1; + sendMediaVideoMessagesRow = -1; + sendMediaEmbededLinksRow = -1; rowCount = 0; if (type == TYPE_KICKED) { permissionsSectionRow = rowCount++; sendMessagesRow = rowCount++; sendMediaRow = rowCount++; - sendStickersRow = rowCount++; - sendPollsRow = rowCount++; - embedLinksRow = rowCount++; + if (sendMediaExpanded) { + sendMediaPhotosRow = rowCount++; + sendMediaVideosRow = rowCount++; + sendMediaStickerGifsRow = rowCount++; + sendMediaMusicRow = rowCount++; + sendMediaFilesRow = rowCount++; + sendMediaVoiceMessagesRow = rowCount++; + sendMediaVideoMessagesRow = rowCount++; + sendMediaEmbededLinksRow = rowCount++; + sendPollsRow = rowCount++; + } addUsersRow = rowCount++; pinMessagesRow = rowCount++; changeInfoRow = rowCount++; @@ -591,7 +639,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente emptyView.showProgress(true, false); frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - emptyView.addView(progressLayout,0); + emptyView.addView(progressLayout, 0); listView = new RecyclerListView(context) { @Override @@ -601,6 +649,14 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente fragmentView.invalidate(); } } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (permissionsSectionRow >= 0 && participantsDivider2Row >= 0) { + drawSectionBackground(canvas, permissionsSectionRow, Math.max(0, participantsDivider2Row - 1), getThemedColor(Theme.key_windowBackgroundWhite)); + } + super.dispatchDraw(canvas); + } }; listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) { @Override @@ -613,31 +669,6 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente }); DefaultItemAnimator itemAnimator = new DefaultItemAnimator() { - @Override - protected long getAddAnimationDelay(long removeDuration, long moveDuration, long changeDuration) { - return 0; - } - - @Override - protected long getMoveAnimationDelay() { - return 0; - } - - @Override - public long getMoveDuration() { - return 220; - } - - @Override - public long getRemoveDuration() { - return 220; - } - - @Override - public long getAddDuration() { - return 220; - } - int animationIndex = -1; @Override @@ -657,7 +688,24 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } super.runPendingAnimations(); } + + @Override + protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { + super.onMoveAnimationUpdate(holder); + listView.invalidate(); + } + + @Override + protected void onChangeAnimationUpdate(RecyclerView.ViewHolder holder) { + super.onChangeAnimationUpdate(holder); + listView.invalidate(); + } }; + itemAnimator.setDurations(320); + itemAnimator.setMoveDelay(0); + itemAnimator.setAddDelay(0); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); listView.setItemAnimator(itemAnimator); itemAnimator.setSupportsChangeAnimations(false); listView.setAnimateEmptyView(true, RecyclerListView.EMPTY_VIEW_ANIMATION_TYPE_ALPHA); @@ -665,10 +713,42 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - listView.setOnItemClickListener((view, position) -> { + listView.setOnItemClickListener((view, position, x, y) -> { boolean listAdapter = listView.getAdapter() == listViewAdapter; if (listAdapter) { - if (position == addNewRow) { + if (isExpandableSendMediaRow(position)) { + CheckBoxCell checkBoxCell = (CheckBoxCell) view; + if (position == sendMediaPhotosRow) { + defaultBannedRights.send_photos = !defaultBannedRights.send_photos; + } else if (position == sendMediaVideosRow) { + defaultBannedRights.send_videos = !defaultBannedRights.send_videos; + } else if (position == sendMediaStickerGifsRow) { + defaultBannedRights.send_stickers = !defaultBannedRights.send_stickers; + } else if (position == sendMediaMusicRow) { + defaultBannedRights.send_audios = !defaultBannedRights.send_audios; + } else if (position == sendMediaFilesRow) { + defaultBannedRights.send_docs = !defaultBannedRights.send_docs; + } else if (position == sendMediaVoiceMessagesRow) { + defaultBannedRights.send_voices = !defaultBannedRights.send_voices; + } else if (position == sendMediaVideoMessagesRow) { + defaultBannedRights.send_roundvideos = !defaultBannedRights.send_roundvideos; + } else if (position == sendMediaEmbededLinksRow) { + if (defaultBannedRights.send_plain) { + View senMessagesView = layoutManager.findViewByPosition(sendMessagesRow); + if (senMessagesView != null) { + AndroidUtilities.shakeViewSpring(senMessagesView); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + return; + } + } + defaultBannedRights.embed_links = !defaultBannedRights.embed_links; + } else if (position == sendPollsRow) { + defaultBannedRights.send_polls = !defaultBannedRights.send_polls; + } + + checkBoxCell.setChecked(!checkBoxCell.isChecked(), true); + AndroidUtilities.updateVisibleRows(listView); + } else if (position == addNewRow) { if (type == TYPE_BANNED || type == TYPE_KICKED) { Bundle bundle = new Bundle(); bundle.putLong("chat_id", chatId); @@ -676,6 +756,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente bundle.putInt("selectType", type == TYPE_BANNED ? ChatUsersActivity.SELECT_TYPE_BLOCK : ChatUsersActivity.SELECT_TYPE_EXCEPTION); ChatUsersActivity fragment = new ChatUsersActivity(bundle); fragment.setInfo(info); + fragment.setBannedRights(defaultBannedRights); fragment.setDelegate(new ChatUsersActivityDelegate() { @Override @@ -798,10 +879,10 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente description = LocaleController.getString("InviteToGroupErrorMessageMultipleSome", R.string.InviteToGroupErrorMessageMultipleSome); } new AlertDialog.Builder(context) - .setTitle(title) - .setMessage(description) - .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) - .show(); + .setTitle(title) + .setMessage(description) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .show(); }; for (int a = 0; a < count; a++) { final TLRPC.User user = users.get(a); @@ -977,6 +1058,14 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } return; } + if (position == sendMediaRow) { + //defaultBannedRights.send_media = !defaultBannedRights.send_media; + DiffCallback diffCallback = saveState(); + sendMediaExpanded = !sendMediaExpanded; + AndroidUtilities.updateVisibleRows(listView); + updateListAnimated(diffCallback); + return; + } checkCell.setChecked(!checkCell.isChecked()); if (position == changeInfoRow) { defaultBannedRights.change_info = !defaultBannedRights.change_info; @@ -987,11 +1076,19 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } else if (position == pinMessagesRow) { defaultBannedRights.pin_messages = !defaultBannedRights.pin_messages; } else { - boolean disabled = !checkCell.isChecked(); if (position == sendMessagesRow) { - defaultBannedRights.send_messages = !defaultBannedRights.send_messages; + defaultBannedRights.send_plain = !defaultBannedRights.send_plain; + if (sendMediaEmbededLinksRow >= 0) { + listViewAdapter.notifyItemChanged(sendMediaEmbededLinksRow); + } + if (sendMediaRow >= 0) { + listViewAdapter.notifyItemChanged(sendMediaRow); + } } else if (position == sendMediaRow) { - defaultBannedRights.send_media = !defaultBannedRights.send_media; + DiffCallback diffCallback = saveState(); + sendMediaExpanded = !sendMediaExpanded; + AndroidUtilities.updateVisibleRows(listView); + updateListAnimated(diffCallback); } else if (position == sendStickersRow) { defaultBannedRights.send_stickers = defaultBannedRights.send_games = defaultBannedRights.send_gifs = defaultBannedRights.send_inline = !defaultBannedRights.send_stickers; } else if (position == embedLinksRow) { @@ -999,51 +1096,6 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } else if (position == sendPollsRow) { defaultBannedRights.send_polls = !defaultBannedRights.send_polls; } - if (disabled) { - if (defaultBannedRights.view_messages && !defaultBannedRights.send_messages) { - defaultBannedRights.send_messages = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMessagesRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((defaultBannedRights.view_messages || defaultBannedRights.send_messages) && !defaultBannedRights.send_media) { - defaultBannedRights.send_media = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMediaRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((defaultBannedRights.view_messages || defaultBannedRights.send_messages) && !defaultBannedRights.send_polls) { - defaultBannedRights.send_polls = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendPollsRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((defaultBannedRights.view_messages || defaultBannedRights.send_messages) && !defaultBannedRights.send_stickers) { - defaultBannedRights.send_stickers = defaultBannedRights.send_games = defaultBannedRights.send_gifs = defaultBannedRights.send_inline = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendStickersRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((defaultBannedRights.view_messages || defaultBannedRights.send_messages) && !defaultBannedRights.embed_links) { - defaultBannedRights.embed_links = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(embedLinksRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - } else { - if ((!defaultBannedRights.embed_links || !defaultBannedRights.send_inline || !defaultBannedRights.send_media || !defaultBannedRights.send_polls) && defaultBannedRights.send_messages) { - defaultBannedRights.send_messages = false; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMessagesRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(true); - } - } - } } return; } @@ -1070,8 +1122,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (adminRights == null) { adminRights = new TLRPC.TL_chatAdminRights(); adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = - adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = - adminRights.manage_topics = adminRights.pin_messages = adminRights.add_admins = true; + adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = + adminRights.manage_topics = adminRights.pin_messages = adminRights.add_admins = true; if (!isChannel) { adminRights.manage_call = true; } @@ -1084,8 +1136,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (participant instanceof TLRPC.TL_chatParticipantCreator) { adminRights = new TLRPC.TL_chatAdminRights(); adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = - adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = - adminRights.manage_topics = adminRights.pin_messages = adminRights.add_admins = true; + adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = + adminRights.manage_topics = adminRights.pin_messages = adminRights.add_admins = true; if (!isChannel) { adminRights.manage_call = true; } @@ -1164,7 +1216,14 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente bannedRights.view_messages = true; bannedRights.send_stickers = true; bannedRights.send_media = true; + bannedRights.send_photos = true; + bannedRights.send_videos = true; + bannedRights.send_roundvideos = true; + bannedRights.send_audios = true; + bannedRights.send_voices = true; + bannedRights.send_docs = true; bannedRights.embed_links = true; + bannedRights.send_plain = true; bannedRights.send_messages = true; bannedRights.send_games = true; bannedRights.send_inline = true; @@ -1231,6 +1290,12 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente return fragmentView; } + private void setBannedRights(TLRPC.TL_chatBannedRights defaultBannedRights) { + if (defaultBannedRights != null) { + this.defaultBannedRights = defaultBannedRights; + } + } + private void sortAdmins(ArrayList participants) { Collections.sort(participants, (lhs, rhs) -> { int type1 = getChannelAdminParticipantType(lhs); @@ -1356,8 +1421,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente admin.date = (int) (System.currentTimeMillis() / 1000); admin.admin_rights = new TLRPC.TL_chatAdminRights(); admin.admin_rights.change_info = admin.admin_rights.post_messages = admin.admin_rights.edit_messages = - admin.admin_rights.delete_messages = admin.admin_rights.ban_users = admin.admin_rights.invite_users = - admin.admin_rights.manage_topics = admin.admin_rights.pin_messages = admin.admin_rights.add_admins = true; + admin.admin_rights.delete_messages = admin.admin_rights.ban_users = admin.admin_rights.invite_users = + admin.admin_rights.manage_topics = admin.admin_rights.pin_messages = admin.admin_rights.add_admins = true; if (!isChannel) { admin.admin_rights.manage_call = true; } @@ -1808,7 +1873,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente }); presentFragment(fragment); } else { - getMessagesController().setUserAdminRole(chatId, getMessagesController().getUser(peerId), new TLRPC.TL_chatAdminRights(), "", !isChannel, ChatUsersActivity.this, false, false, null,null); + getMessagesController().setUserAdminRole(chatId, getMessagesController().getUser(peerId), new TLRPC.TL_chatAdminRights(), "", !isChannel, ChatUsersActivity.this, false, false, null, null); removeParticipants(peerId); } } else if (type == TYPE_BANNED || type == TYPE_KICKED) { @@ -1985,17 +2050,54 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (rights.view_messages && defaultBannedRights.view_messages != rights.view_messages) { builder.append(LocaleController.getString("UserRestrictionsNoRead", R.string.UserRestrictionsNoRead)); } - if (rights.send_messages && defaultBannedRights.send_messages != rights.send_messages) { + if (rights.send_messages && defaultBannedRights.send_plain != rights.send_plain) { if (builder.length() != 0) { builder.append(", "); } - builder.append(LocaleController.getString("UserRestrictionsNoSend", R.string.UserRestrictionsNoSend)); + builder.append(LocaleController.getString("UserRestrictionsNoSendText", R.string.UserRestrictionsNoSendText)); } if (rights.send_media && defaultBannedRights.send_media != rights.send_media) { if (builder.length() != 0) { builder.append(", "); } builder.append(LocaleController.getString("UserRestrictionsNoSendMedia", R.string.UserRestrictionsNoSendMedia)); + } else { + if (rights.send_photos && defaultBannedRights.send_photos != rights.send_photos) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendPhotos", R.string.UserRestrictionsNoSendPhotos)); + } + if (rights.send_videos && defaultBannedRights.send_videos != rights.send_videos) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendVideos", R.string.UserRestrictionsNoSendVideos)); + } + if (rights.send_audios && defaultBannedRights.send_audios != rights.send_audios) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendMusic", R.string.UserRestrictionsNoSendMusic)); + } + if (rights.send_docs && defaultBannedRights.send_docs != rights.send_docs) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendDocs", R.string.UserRestrictionsNoSendDocs)); + } + if (rights.send_voices && defaultBannedRights.send_voices != rights.send_voices) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendVoice", R.string.UserRestrictionsNoSendVoice)); + } + if (rights.send_roundvideos && defaultBannedRights.send_roundvideos != rights.send_roundvideos) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendRound", R.string.UserRestrictionsNoSendRound)); + } } if (rights.send_stickers && defaultBannedRights.send_stickers != rights.send_stickers) { if (builder.length() != 0) { @@ -2009,7 +2111,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } builder.append(LocaleController.getString("UserRestrictionsNoSendPolls", R.string.UserRestrictionsNoSendPolls)); } - if (rights.embed_links && defaultBannedRights.embed_links != rights.embed_links) { + if (rights.embed_links && !rights.send_plain && defaultBannedRights.embed_links != rights.embed_links) { if (builder.length() != 0) { builder.append(", "); } @@ -2087,7 +2189,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente return 0; } else if (participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_channelParticipant) { return 1; - } else { + } else { return 2; } } @@ -2937,7 +3039,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int viewType = holder.getItemViewType(); - if (viewType == 7) { + if (viewType == 7 || viewType == VIEW_TYPE_EXPANDABLE_SWITCH) { return ChatObject.canBlockUsers(currentChat); } else if (viewType == 0) { ManageChatUserCell cell = (ManageChatUserCell) holder.itemView; @@ -2961,6 +3063,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente return ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_BLOCK_USERS); } } + if (viewType == VIEW_TYPE_INNER_CHECK) { + return true; + } return false; } @@ -3015,6 +3120,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente view = new TextSettingsCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; + case VIEW_TYPE_EXPANDABLE_SWITCH: case 7: view = new TextCheckCell2(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -3048,23 +3154,31 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente view = chooseView; chooseView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); chooseView.setOptions( - selectedSlowmode, - LocaleController.getString("SlowmodeOff", R.string.SlowmodeOff), - LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 10), - LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 30), - LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 1), - LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 5), - LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 15), - LocaleController.formatString("SlowmodeHours", R.string.SlowmodeHours, 1) + selectedSlowmode, + LocaleController.getString("SlowmodeOff", R.string.SlowmodeOff), + LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 10), + LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 30), + LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 1), + LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 5), + LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 15), + LocaleController.formatString("SlowmodeHours", R.string.SlowmodeHours, 1) ); chooseView.setCallback(which -> { if (info == null) { return; } selectedSlowmode = which; -// listViewAdapter.notifyItemChanged(slowmodeInfoRow); + listViewAdapter.notifyItemChanged(slowmodeInfoRow); }); break; + case VIEW_TYPE_INNER_CHECK: + CheckBoxCell checkBoxCell = new CheckBoxCell(mContext, 4, 21, getResourceProvider()); + checkBoxCell.getCheckBoxRound().setDrawBackgroundAsArc(14); + checkBoxCell.getCheckBoxRound().setColor(Theme.key_switch2TrackChecked, Theme.key_radioBackground, Theme.key_checkboxCheck); + checkBoxCell.setEnabled(true); + view = checkBoxCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; } return new RecyclerListView.Holder(view); } @@ -3276,32 +3390,39 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente TextSettingsCell settingsCell = (TextSettingsCell) holder.itemView; settingsCell.setTextAndValue(LocaleController.getString("ChannelBlacklist", R.string.ChannelBlacklist), String.format("%d", info != null ? info.kicked_count : 0), false); break; + case VIEW_TYPE_EXPANDABLE_SWITCH: case 7: TextCheckCell2 checkCell = (TextCheckCell2) holder.itemView; + boolean animated = checkCell.getTag() != null && (Integer) checkCell.getTag() == position; + checkCell.setTag(position); if (position == changeInfoRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsChangeInfo", R.string.UserRestrictionsChangeInfo), !defaultBannedRights.change_info && !ChatObject.isPublic(currentChat), manageTopicsRow != -1); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsChangeInfo", R.string.UserRestrictionsChangeInfo), !defaultBannedRights.change_info && !ChatObject.isPublic(currentChat), manageTopicsRow != -1, animated); } else if (position == addUsersRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsInviteUsers", R.string.UserRestrictionsInviteUsers), !defaultBannedRights.invite_users, true); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsInviteUsers", R.string.UserRestrictionsInviteUsers), !defaultBannedRights.invite_users, true, animated); } else if (position == pinMessagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsPinMessages", R.string.UserRestrictionsPinMessages), !defaultBannedRights.pin_messages && !ChatObject.isPublic(currentChat), true); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsPinMessages", R.string.UserRestrictionsPinMessages), !defaultBannedRights.pin_messages && !ChatObject.isPublic(currentChat), true, animated); } else if (position == sendMessagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSend", R.string.UserRestrictionsSend), !defaultBannedRights.send_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendText", R.string.UserRestrictionsSendText), !defaultBannedRights.send_plain, true, animated); } else if (position == sendMediaRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), !defaultBannedRights.send_media, true); - } else if (position == sendStickersRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendStickers", R.string.UserRestrictionsSendStickers), !defaultBannedRights.send_stickers, true); - } else if (position == embedLinksRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsEmbedLinks", R.string.UserRestrictionsEmbedLinks), !defaultBannedRights.embed_links, true); - } else if (position == sendPollsRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendPolls", R.string.UserRestrictionsSendPolls), !defaultBannedRights.send_polls, true); - } else if (position == manageTopicsRow) { - checkCell.setTextAndCheck(LocaleController.getString("CreateTopicsPermission", R.string.CreateTopicsPermission), !defaultBannedRights.manage_topics, false); - } + int sentMediaCount = getSendMediaSelectedCount(); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), sentMediaCount > 0, true, animated); + checkCell.setCollapseArrow(String.format(Locale.US, "%d/9", sentMediaCount), !sendMediaExpanded, new Runnable() { + @Override + public void run() { + boolean checked = !checkCell.isChecked(); + checkCell.setChecked(checked); + setSendMediaEnabled(checked); - if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { - checkCell.setEnabled(!defaultBannedRights.send_messages && !defaultBannedRights.view_messages); - } else if (position == sendMessagesRow) { - checkCell.setEnabled(!defaultBannedRights.view_messages); + } + }); + } else if (position == sendStickersRow) { + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendStickers", R.string.UserRestrictionsSendStickers), !defaultBannedRights.send_stickers, true, animated); + } else if (position == embedLinksRow) { + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsEmbedLinks", R.string.UserRestrictionsEmbedLinks), !defaultBannedRights.embed_links, true, animated); + } else if (position == sendPollsRow) { + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendPollsShort", R.string.UserRestrictionsSendPollsShort), !defaultBannedRights.send_polls, true); + } else if (position == manageTopicsRow) { + checkCell.setTextAndCheck(LocaleController.getString("CreateTopicsPermission", R.string.CreateTopicsPermission), !defaultBannedRights.manage_topics, false, animated); } if (ChatObject.canBlockUsers(currentChat)) { if (position == addUsersRow && !ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_INVITE) || @@ -3355,6 +3476,32 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente textCell.setTextAndCheck(LocaleController.getString("ChannelHideMembers", R.string.ChannelHideMembers), info != null && info.participants_hidden, false); } break; + case VIEW_TYPE_INNER_CHECK: + CheckBoxCell checkBoxCell = (CheckBoxCell) holder.itemView; + animated = checkBoxCell.getTag() != null && (Integer) checkBoxCell.getTag() == position; + checkBoxCell.setTag(position); + if (position == sendMediaPhotosRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionPhotos", R.string.SendMediaPermissionPhotos), "", !defaultBannedRights.send_photos, true, animated); + } else if (position == sendMediaVideosRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionVideos", R.string.SendMediaPermissionVideos), "", !defaultBannedRights.send_videos, true, animated); + } else if (position == sendMediaStickerGifsRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs), "", !defaultBannedRights.send_stickers, true, animated); + } else if (position == sendMediaMusicRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionMusic", R.string.SendMediaPermissionMusic), "", !defaultBannedRights.send_audios, true, animated); + } else if (position == sendMediaFilesRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionFiles", R.string.SendMediaPermissionFiles), "", !defaultBannedRights.send_docs, true, animated); + } else if (position == sendMediaVoiceMessagesRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionVoice", R.string.SendMediaPermissionVoice), "", !defaultBannedRights.send_voices, true, animated); + } else if (position == sendMediaVideoMessagesRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionRound", R.string.SendMediaPermissionRound), "", !defaultBannedRights.send_roundvideos, true, animated); + } else if (position == sendMediaEmbededLinksRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaEmbededLinks", R.string.SendMediaEmbededLinks), "", !defaultBannedRights.embed_links && !defaultBannedRights.send_plain, false, animated); + }else if (position == sendPollsRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPolls", R.string.SendMediaPolls), "", !defaultBannedRights.send_polls, false, animated); + } + // checkBoxCell.setText(getCheckBoxTitle(item.headerName, percents[item.index < 0 ? 8 : item.index], item.index < 0), AndroidUtilities.formatFileSize(item.size), selected, item.index < 0 ? !collapsed : !item.last); + checkBoxCell.setPad(1); + break; } } @@ -3384,7 +3531,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } else if (position == removedUsersRow) { return 6; } else if (position == changeInfoRow || position == addUsersRow || position == pinMessagesRow || position == sendMessagesRow || - position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow || position == manageTopicsRow) { + position == sendStickersRow || position == embedLinksRow || position == manageTopicsRow) { return 7; } else if (position == membersHeaderRow || position == contactsHeaderRow || position == botHeaderRow || position == loadingHeaderRow) { return 8; @@ -3396,6 +3543,10 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente return 11; } else if (position == antiSpamRow || position == hideMembersRow) { return 12; + } else if (isExpandableSendMediaRow(position)) { + return VIEW_TYPE_INNER_CHECK; + } else if (position == sendMediaRow) { + return VIEW_TYPE_EXPANDABLE_SWITCH; } return 0; } @@ -3412,6 +3563,26 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } } + private void setSendMediaEnabled(boolean enabled) { + defaultBannedRights.send_media = !enabled; + defaultBannedRights.send_photos = !enabled; + defaultBannedRights.send_videos = !enabled; + defaultBannedRights.send_stickers = !enabled; + defaultBannedRights.send_audios = !enabled; + defaultBannedRights.send_docs = !enabled; + defaultBannedRights.send_voices = !enabled; + defaultBannedRights.send_roundvideos = !enabled; + defaultBannedRights.embed_links = !enabled; + defaultBannedRights.send_polls = !enabled; + AndroidUtilities.updateVisibleRows(listView); + } + + private boolean isExpandableSendMediaRow(int position) { + return position == sendMediaPhotosRow || position == sendMediaVideosRow || position == sendMediaStickerGifsRow || + position == sendMediaMusicRow || position == sendMediaFilesRow || position == sendMediaVoiceMessagesRow || + position == sendMediaVideoMessagesRow || position == sendMediaEmbededLinksRow || position == sendPollsRow; + } + public DiffCallback saveState() { DiffCallback diffCallback = new DiffCallback(); diffCallback.oldRowCount = rowCount; @@ -3555,6 +3726,42 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } } + private int getSendMediaSelectedCount() { + return getSendMediaSelectedCount(defaultBannedRights); + } + + public static int getSendMediaSelectedCount(TLRPC.TL_chatBannedRights bannedRights) { + int i = 0; + if (!bannedRights.send_photos) { + i++; + } + if (!bannedRights.send_videos) { + i++; + } + if (!bannedRights.send_stickers) { + i++; + } + if (!bannedRights.send_audios) { + i++; + } + if (!bannedRights.send_docs) { + i++; + } + if (!bannedRights.send_voices) { + i++; + } + if (!bannedRights.send_roundvideos) { + i++; + } + if (!bannedRights.embed_links && !bannedRights.send_plain) { + i++; + } + if (!bannedRights.send_polls) { + i++; + } + return i; + } + @Override public ArrayList getThemeDescriptions() { ArrayList themeDescriptions = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatsWidgetConfigActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatsWidgetConfigActivity.java index 5698a6d74..bc87d74f8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatsWidgetConfigActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatsWidgetConfigActivity.java @@ -23,7 +23,7 @@ public class ChatsWidgetConfigActivity extends ExternalActionActivity { if (creatingAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 10); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_WIDGET); args.putBoolean("allowSwitchAccount", true); EditWidgetActivity fragment = new EditWidgetActivity(EditWidgetActivity.TYPE_CHATS, creatingAppWidgetId); fragment.setDelegate(dialogs -> { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java index 69dd43c58..350de26fd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -171,6 +171,7 @@ public class AlertsCreator { } }) .setNegativeButton(LocaleController.getString("ContactsPermissionAlertNotNow", R.string.ContactsPermissionAlertNotNow), null) + .setOnDismissListener(dialog -> SharedConfig.BackgroundActivityPrefs.increaseDismissedCount()) .create(); } @@ -348,16 +349,69 @@ public class AlertsCreator { request instanceof TLRPC.TL_messages_forwardMessages || request instanceof TLRPC.TL_messages_sendMultiMedia || request instanceof TLRPC.TL_messages_sendScheduledMessages) { - switch (error.text) { - case "PEER_FLOOD": - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 0); - break; - case "USER_BANNED_IN_CHANNEL": - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 5); - break; - case "SCHEDULE_TOO_MUCH": - showSimpleToast(fragment, LocaleController.getString("MessageScheduledLimitReached", R.string.MessageScheduledLimitReached)); - break; + long dialogId = 0; + if (request instanceof TLRPC.TL_messages_sendMessage) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendMessage) request).peer); + } else if (request instanceof TLRPC.TL_messages_sendMedia) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendMedia) request).peer); + } else if (request instanceof TLRPC.TL_messages_sendInlineBotResult) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendInlineBotResult) request).peer); + } else if (request instanceof TLRPC.TL_messages_forwardMessages) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_forwardMessages) request).to_peer); + } else if (request instanceof TLRPC.TL_messages_sendMultiMedia) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendMultiMedia) request).peer); + } else if (request instanceof TLRPC.TL_messages_sendScheduledMessages) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendScheduledMessages) request).peer); + } + if (BuildVars.DEBUG_VERSION && error.text != null && error.text.startsWith("CHAT_SEND_") && error.text.endsWith("FORBIDDEN")) { + String errorText = error.text; + TLRPC.Chat chat = dialogId < 0 ? MessagesController.getInstance(currentAccount).getChat(-dialogId) : null; + switch (error.text) { + case "CHAT_SEND_PLAIN_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_PLAIN); + break; + case "CHAT_SEND_PHOTOS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_PHOTO); + break; + case "CHAT_SEND_VIDEOS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_VIDEO); + break; + case "CHAT_SEND_ROUNDVIDEOS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_ROUND); + break; + case "CHAT_SEND_DOCS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_DOCUMENTS); + break; + case "CHAT_SEND_VOICES_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_VOICE); + break; + case "CHAT_SEND_AUDIOS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_MUSIC); + break; + case "CHAT_SEND_STICKERS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_STICKERS); + break; + case "CHAT_SEND_GIFS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_GIFS); + break; + case "CHAT_SEND_POLL_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_POLLS); + break; + + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR, errorText); + } else { + switch (error.text) { + case "PEER_FLOOD": + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 0); + break; + case "USER_BANNED_IN_CHANNEL": + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 5); + break; + case "SCHEDULE_TOO_MUCH": + showSimpleToast(fragment, LocaleController.getString("MessageScheduledLimitReached", R.string.MessageScheduledLimitReached)); + break; + } } } else if (request instanceof TLRPC.TL_messages_importChatInvite) { if (error.text.startsWith("FLOOD_WAIT")) { @@ -746,7 +800,6 @@ public class AlertsCreator { cells[num].setChecked(!cells[num].isChecked(), true); }); - builder.setCustomViewOffset(12); builder.setView(linearLayout); builder.setPositiveButton(LocaleController.getString("BlockAndDeleteReplies", R.string.BlockAndDeleteReplies), (dialogInterface, i) -> { @@ -823,7 +876,6 @@ public class AlertsCreator { cells[num].setChecked(!cells[num].isChecked(), true); }); } - builder.setCustomViewOffset(12); builder.setView(linearLayout); } else { cells = null; @@ -1381,6 +1433,7 @@ public class AlertsCreator { } } }; + builder.setCustomViewOffset(6); builder.setView(frameLayout); AvatarDrawable avatarDrawable = new AvatarDrawable(); @@ -4119,6 +4172,30 @@ public class AlertsCreator { builder.setMessage(LocaleController.getString("ErrorSendRestrictedPrivacyVoiceMessages", R.string.ErrorSendRestrictedPrivacyVoiceMessages)); } else if (result == 8) { builder.setMessage(LocaleController.getString("ErrorSendRestrictedPrivacyVideoMessages", R.string.ErrorSendRestrictedPrivacyVideoMessages)); + } else if (result == 9) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedPrivacyVideo", R.string.ErrorSendRestrictedVideoAll)); + } else if (result == 10) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedPrivacyPhoto", R.string.ErrorSendRestrictedPhotoAll)); + } else if (result == 11) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedVideo", R.string.ErrorSendRestrictedVideo)); + } else if (result == 12) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedPhoto", R.string.ErrorSendRestrictedPhoto)); + } else if (result == 13) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedVoiceAll", R.string.ErrorSendRestrictedVoiceAll)); + } else if (result == 14) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedVoice", R.string.ErrorSendRestrictedVoice)); + } else if (result == 15) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedRoundAll", R.string.ErrorSendRestrictedRoundAll)); + } else if (result == 16) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedRound", R.string.ErrorSendRestrictedRound)); + } else if (result == 17) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedDocumentsAll", R.string.ErrorSendRestrictedDocumentsAll)); + } else if (result == 18) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedDocuments", R.string.ErrorSendRestrictedDocuments)); + } else if (result == 19) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedMusicAll", R.string.ErrorSendRestrictedMusicAll)); + } else if (result == 20) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedMusic", R.string.ErrorSendRestrictedMusic)); } builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); 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 75729d739..3ca5453b8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java @@ -61,6 +61,9 @@ public class AnimatedEmojiDrawable extends Drawable { public static final int CACHE_TYPE_FORUM_TOPIC = 10; public static final int CACHE_TYPE_FORUM_TOPIC_LARGE = 11; public static final int CACHE_TYPE_RENDERING_VIDEO = 12; + public static final int CACHE_TYPE_ALERT_PREVIEW_STATIC = 13; + public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW = 14; + public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 = 15; public int rawDrawIndex; @@ -163,7 +166,9 @@ public class AnimatedEmojiDrawable extends Drawable { if (emojiDocumentsCache != null) { TLRPC.Document cacheDocument = emojiDocumentsCache.get(id); if (cacheDocument != null) { - onDone.run(cacheDocument); + if (onDone != null) { + onDone.run(cacheDocument); + } return; } } @@ -171,19 +176,18 @@ public class AnimatedEmojiDrawable extends Drawable { if (!checkThread()) { return; } - if (onDone != null) { - if (loadingDocuments == null) { - loadingDocuments = new HashMap<>(); - } - ArrayList callbacks = loadingDocuments.get(id); - if (callbacks != null) { - callbacks.add(onDone); - return; - } - callbacks = new ArrayList<>(1); - callbacks.add(onDone); - loadingDocuments.put(id, callbacks); + if (loadingDocuments == null) { + loadingDocuments = new HashMap<>(); } + ArrayList callbacks = loadingDocuments.get(id); + if (callbacks != null) { + callbacks.add(onDone); + return; + } + callbacks = new ArrayList<>(1); + callbacks.add(onDone); + loadingDocuments.put(id, callbacks); + if (toFetchDocuments == null) { toFetchDocuments = new HashSet<>(); } @@ -312,7 +316,10 @@ public class AnimatedEmojiDrawable extends Drawable { ArrayList loadingCallbacks = loadingDocuments.remove(document.id); if (loadingCallbacks != null) { for (int j = 0; j < loadingCallbacks.size(); ++j) { - loadingCallbacks.get(j).run(document); + ReceivedDocument callback = loadingCallbacks.get(j); + if (callback != null) { + callback.run(document); + } } loadingCallbacks.clear(); } @@ -413,6 +420,8 @@ public class AnimatedEmojiDrawable extends Drawable { sizedp = (int) ((Math.abs(Theme.chat_msgTextPaintEmoji[2].ascent()) + Math.abs(Theme.chat_msgTextPaintEmoji[2].descent())) * 1.15f / AndroidUtilities.density); } else if (this.cacheType == STANDARD_LOTTIE_FRAME) { sizedp = (int) ((Math.abs(Theme.chat_msgTextPaintEmoji[0].ascent()) + Math.abs(Theme.chat_msgTextPaintEmoji[0].descent())) * 1.15f / AndroidUtilities.density); + } else if (cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW || cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2) { + sizedp = 100; } else { sizedp = 34; } @@ -459,15 +468,17 @@ public class AnimatedEmojiDrawable extends Drawable { } imageReceiver.setVideoThumbIsSame(true); boolean onlyStaticPreview = SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW && (cacheType == CACHE_TYPE_KEYBOARD || cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); - + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC) { + onlyStaticPreview = true; + } String filter = sizedp + "_" + sizedp; if (cacheType == CACHE_TYPE_RENDERING_VIDEO) { filter += "_d_nostream"; } - if (cacheType != STANDARD_LOTTIE_FRAME && (cacheType != CACHE_TYPE_MESSAGES_LARGE || SharedConfig.getDevicePerformanceClass() < SharedConfig.PERFORMANCE_CLASS_HIGH) && cacheType != CACHE_TYPE_RENDERING_VIDEO) { + if (cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW && cacheType != STANDARD_LOTTIE_FRAME && (cacheType != CACHE_TYPE_MESSAGES_LARGE || SharedConfig.getDevicePerformanceClass() < SharedConfig.PERFORMANCE_CLASS_HIGH) && cacheType != CACHE_TYPE_RENDERING_VIDEO) { filter += "_pcache"; } - if (cacheType != CACHE_TYPE_MESSAGES && cacheType != CACHE_TYPE_MESSAGES_LARGE) { + if (cacheType != CACHE_TYPE_MESSAGES && cacheType != CACHE_TYPE_MESSAGES_LARGE && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2) { filter += "_compress"; } if (cacheType == STANDARD_LOTTIE_FRAME) { @@ -481,8 +492,7 @@ public class AnimatedEmojiDrawable extends Drawable { if ("video/webm".equals(document.mime_type)) { mediaLocation = ImageLocation.getForDocument(document); mediaFilter = filter + "_" + ImageLoader.AUTOPLAY_FILTER; - SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); - thumbDrawable = svgThumb; + thumbDrawable = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); } else if ("application/x-tgsticker".equals(document.mime_type)) { String probableCacheKey = (cacheType != 0 ? cacheType + "_" : "") + documentId + "@" + filter; if (SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW || (cacheType == CACHE_TYPE_KEYBOARD || !ImageLoader.getInstance().hasLottieMemCache(probableCacheKey))) { @@ -524,13 +534,9 @@ public class AnimatedEmojiDrawable extends Drawable { } - if (cacheType == CACHE_TYPE_EMOJI_STATUS || cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS || cacheType == CACHE_TYPE_FORUM_TOPIC) { - imageReceiver.setAutoRepeatCount(2); - } else if (cacheType == CACHE_TYPE_FORUM_TOPIC_LARGE) { - imageReceiver.setAutoRepeatCount(1); - } + updateAutoRepeat(imageReceiver); - if (cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_LARGE) { + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC || cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_LARGE) { imageReceiver.setLayerNum(7); } if (cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS) { @@ -556,6 +562,14 @@ public class AnimatedEmojiDrawable extends Drawable { invalidate(); } + private void updateAutoRepeat(ImageReceiver imageReceiver) { + if (cacheType == CACHE_TYPE_EMOJI_STATUS || cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS || cacheType == CACHE_TYPE_FORUM_TOPIC) { + imageReceiver.setAutoRepeatCount(2); + } else if (cacheType == CACHE_TYPE_FORUM_TOPIC_LARGE || cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW) { + imageReceiver.setAutoRepeatCount(1); + } + } + void invalidate() { if (views != null) { for (int i = 0; i < views.size(); ++i) { @@ -905,11 +919,7 @@ public class AnimatedEmojiDrawable extends Drawable { AnimatedEmojiDrawable drawable = (AnimatedEmojiDrawable) getDrawable(); ImageReceiver imageReceiver = drawable.getImageReceiver(); if (imageReceiver != null) { - if (drawable.cacheType == CACHE_TYPE_EMOJI_STATUS || drawable.cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS || drawable.cacheType == CACHE_TYPE_FORUM_TOPIC) { - imageReceiver.setAutoRepeatCount(2); - } else if (cacheType == CACHE_TYPE_FORUM_TOPIC_LARGE) { - imageReceiver.setAutoRepeatCount(1); - } + drawable.updateAutoRepeat(imageReceiver); imageReceiver.startAnimation(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java index b0e2614bc..aa32f5854 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -481,7 +481,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, if (!precise) { seekToMs(nativePtr, ms, precise); } - Bitmap backgroundBitmap = Bitmap.createBitmap((int) (metaData[0] * scaleFactor), (int) (metaData[1] * scaleFactor), Bitmap.Config.ARGB_8888); + Bitmap backgroundBitmap = Bitmap.createBitmap(metaData[0], metaData[1], Bitmap.Config.ARGB_8888); int result; if (precise) { result = getFrameAtTime(nativePtr, ms, backgroundBitmap, metaData, backgroundBitmap.getRowBytes()); @@ -1072,6 +1072,9 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, @Override public Bitmap getFirstFrame(Bitmap bitmap) { + if (bitmap == null) { + bitmap = Bitmap.createBitmap(renderingWidth, renderingHeight, Bitmap.Config.ARGB_8888); + } Canvas canvas = new Canvas(bitmap); if (generatingCacheBitmap == null) { generatingCacheBitmap = Bitmap.createBitmap(metaData[0], metaData[1], Bitmap.Config.ARGB_8888); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java index 92b50debd..40f6bfdb3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java @@ -77,6 +77,14 @@ public class AnimatedFloat { this.firstSet = true; } + public AnimatedFloat(Runnable invalidate, long transitionDelay, long transitionDuration, TimeInterpolator transitionInterpolator) { + this.invalidate = invalidate; + this.transitionDelay = transitionDelay; + this.transitionDuration = transitionDuration; + this.transitionInterpolator = transitionInterpolator; + this.firstSet = true; + } + public AnimatedFloat(float initialValue, View parentToInvalidate) { this.parent = parentToInvalidate; this.value = targetValue = initialValue; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java index b3d2f6b60..fe827eaa7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java @@ -6,6 +6,7 @@ import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; @@ -39,18 +40,29 @@ public class AnimatedTextView extends View { private boolean isRTL = false; - private int currentWidth, currentHeight; - private Integer[] currentLayoutOffsets; - private Integer[] currentLayoutToOldIndex; - private StaticLayout[] currentLayout; + private float currentWidth, currentHeight; + private Part[] currentParts; private CharSequence currentText; - private int oldWidth, oldHeight; - private Integer[] oldLayoutOffsets; - private Integer[] oldLayoutToCurrentIndex; - private StaticLayout[] oldLayout; + private float oldWidth, oldHeight; + private Part[] oldParts; private CharSequence oldText; + private class Part { + StaticLayout layout; + float offset; + int toOppositeIndex; + float left, width; + + public Part(StaticLayout layout, float offset, int toOppositeIndex) { + this.layout = layout; + this.offset = offset; + this.toOppositeIndex = toOppositeIndex; + this.left = layout == null || layout.getLineCount() <= 0 ? 0 : layout.getLineLeft(0); + this.width = layout == null || layout.getLineCount() <= 0 ? 0 : layout.getLineWidth(0); + } + } + private float t = 0; private boolean moveDown = true; private ValueAnimator animator; @@ -97,26 +109,35 @@ public class AnimatedTextView extends View { canvas.translate(bounds.left, bounds.top); int fullWidth = bounds.width(); int fullHeight = bounds.height(); - if (currentLayout != null && oldLayout != null && t != 1) { - int width = AndroidUtilities.lerp(oldWidth, currentWidth, t); - int height = AndroidUtilities.lerp(oldHeight, currentHeight, t); + if (currentParts != null && oldParts != null && t != 1) { + float width = AndroidUtilities.lerp(oldWidth, currentWidth, t); + float height = AndroidUtilities.lerp(oldHeight, currentHeight, t); canvas.translate(0, (fullHeight - height) / 2f); - for (int i = 0; i < currentLayout.length; ++i) { - int j = currentLayoutToOldIndex[i]; - float x = currentLayoutOffsets[i], y = 0; + for (int i = 0; i < currentParts.length; ++i) { + Part current = currentParts[i]; + int j = current.toOppositeIndex; + float x = current.offset, y = 0; if (j >= 0) { - float oldX = oldLayoutOffsets[j]; - x = AndroidUtilities.lerp(oldX, x, t); + if (isRTL && !ignoreRTL) { + x = currentWidth - (x + current.width); + } + Part old = oldParts[j]; + float oldX = old.offset; + if (isRTL && !ignoreRTL) { + oldX = oldWidth - (oldX + old.width); + } + x = AndroidUtilities.lerp(oldX - old.left, x - current.left, t); textPaint.setAlpha(alpha); } else { + if (isRTL && !ignoreRTL) { + x = currentWidth - (x + current.width); + } + x -= current.left; y = -textPaint.getTextSize() * moveAmplitude * (1f - t) * (moveDown ? 1f : -1f); textPaint.setAlpha((int) (alpha * t)); } canvas.save(); - int lwidth = j >= 0 ? width : currentWidth; - if (isRTL && !ignoreRTL) { - x = -x + 2 * lwidth - currentLayout[i].getWidth() - fullWidth; - } + float lwidth = j >= 0 ? width : currentWidth; if ((gravity | ~Gravity.LEFT) != ~0) { if ((gravity | ~Gravity.RIGHT) == ~0) { x += fullWidth - lwidth; @@ -127,21 +148,23 @@ public class AnimatedTextView extends View { } } canvas.translate(x, y); - currentLayout[i].draw(canvas); + current.layout.draw(canvas); canvas.restore(); } - for (int i = 0; i < oldLayout.length; ++i) { - int j = oldLayoutToCurrentIndex[i]; + for (int i = 0; i < oldParts.length; ++i) { + Part old = oldParts[i]; + int j = old.toOppositeIndex; if (j >= 0) { continue; } - float x = oldLayoutOffsets[i]; + float x = old.offset; float y = textPaint.getTextSize() * moveAmplitude * t * (moveDown ? 1f : -1f); textPaint.setAlpha((int) (alpha * (1f - t))); canvas.save(); if (isRTL && !ignoreRTL) { - x = -x + 2 * oldWidth - oldLayout[i].getWidth() - fullWidth; + x = oldWidth - (x + old.width); } + x -= old.left; if ((gravity | ~Gravity.LEFT) != ~0) { if ((gravity | ~Gravity.RIGHT) == ~0) { x += fullWidth - oldWidth; @@ -152,19 +175,21 @@ public class AnimatedTextView extends View { } } canvas.translate(x, y); - oldLayout[i].draw(canvas); + old.layout.draw(canvas); canvas.restore(); } } else { canvas.translate(0, (fullHeight - currentHeight) / 2f); - if (currentLayout != null) { - for (int i = 0; i < currentLayout.length; ++i) { - textPaint.setAlpha(alpha); + if (currentParts != null) { + textPaint.setAlpha(alpha); + for (int i = 0; i < currentParts.length; ++i) { canvas.save(); - float x = currentLayoutOffsets[i]; + Part current = currentParts[i]; + float x = current.offset; if (isRTL && !ignoreRTL) { - x = -x + 2 * currentWidth - currentLayout[i].getWidth() - fullWidth; + x = currentWidth - (x + current.width); } + x -= current.left; if ((gravity | ~Gravity.LEFT) != ~0) { if ((gravity | ~Gravity.RIGHT) == ~0) { x += fullWidth - currentWidth; @@ -174,8 +199,9 @@ public class AnimatedTextView extends View { x += fullWidth - currentWidth; } } +// boolean isAppeared = currentLayoutToOldIndex != null && i < currentLayoutToOldIndex.length && currentLayoutToOldIndex[i] < 0; canvas.translate(x, 0); - currentLayout[i].draw(canvas); + current.layout.draw(canvas); canvas.restore(); } } @@ -226,48 +252,45 @@ public class AnimatedTextView extends View { oldText = currentText; currentText = text; - currentLayout = null; - oldLayout = null; - ArrayList currentLayoutOffsets = new ArrayList<>(); - ArrayList currentLayoutToOldIndex = new ArrayList<>(); - ArrayList currentLayoutList = new ArrayList<>(); - ArrayList oldLayoutOffsets = new ArrayList<>(); - ArrayList oldLayoutToCurrentIndex = new ArrayList<>(); - ArrayList oldLayoutList = new ArrayList<>(); +// ArrayList currentLayoutOffsets = new ArrayList<>(); +// ArrayList currentLayoutToOldIndex = new ArrayList<>(); +// ArrayList currentLayoutList = new ArrayList<>(); +// ArrayList oldLayoutOffsets = new ArrayList<>(); +// ArrayList oldLayoutToCurrentIndex = new ArrayList<>(); +// ArrayList oldLayoutList = new ArrayList<>(); + ArrayList currentParts = new ArrayList<>(); + ArrayList oldParts = new ArrayList<>(); currentWidth = currentHeight = 0; oldWidth = oldHeight = 0; + isRTL = AndroidUtilities.isRTL(currentText); // order execution matters RegionCallback onEqualRegion = (part, from, to) -> { - StaticLayout layout = makeLayout(part, bounds.width() - Math.min(currentWidth, oldWidth)); - oldLayoutToCurrentIndex.add(currentLayoutList.size()); - currentLayoutToOldIndex.add(oldLayoutList.size()); - currentLayoutOffsets.add(currentWidth); - currentLayoutList.add(layout); - oldLayoutOffsets.add(oldWidth); - oldLayoutList.add(layout); - float partWidth = layout.getLineWidth(0); + StaticLayout layout = makeLayout(part, bounds.width() - (int) Math.ceil(Math.min(currentWidth, oldWidth))); + final Part currentPart = new Part(layout, currentWidth, oldParts.size()); + final Part oldPart = new Part(layout, oldWidth, oldParts.size()); + currentParts.add(currentPart); + oldParts.add(oldPart); + float partWidth = currentPart.width; currentWidth += partWidth; oldWidth += partWidth; currentHeight = Math.max(currentHeight, layout.getHeight()); oldHeight = Math.max(oldHeight, layout.getHeight()); }; RegionCallback onNewPart = (part, from, to) -> { - StaticLayout layout = makeLayout(part, bounds.width() - currentWidth); - currentLayoutOffsets.add(currentWidth); - currentLayoutList.add(layout); - currentLayoutToOldIndex.add(-1); - currentWidth += layout.getLineWidth(0); + StaticLayout layout = makeLayout(part, bounds.width() - (int) Math.ceil(currentWidth)); + final Part currentPart = new Part(layout, currentWidth, -1); + currentParts.add(currentPart); + currentWidth += currentPart.width; currentHeight = Math.max(currentHeight, layout.getHeight()); }; RegionCallback onOldPart = (part, from, to) -> { - StaticLayout layout = makeLayout(part, bounds.width() - oldWidth); - oldLayoutOffsets.add(oldWidth); - oldLayoutList.add(layout); - oldLayoutToCurrentIndex.add(-1); - oldWidth += layout.getLineWidth(0); + StaticLayout layout = makeLayout(part, bounds.width() - (int) Math.ceil(oldWidth)); + final Part oldPart = new Part(layout, oldWidth, -1); + oldParts.add(oldPart); + oldWidth += oldPart.width; oldHeight = Math.max(oldHeight, layout.getHeight()); }; @@ -276,38 +299,14 @@ public class AnimatedTextView extends View { diff(from, to, onEqualRegion, onNewPart, onOldPart); - if (this.currentLayout == null || this.currentLayout.length != currentLayoutList.size()) { - this.currentLayout = new StaticLayout[currentLayoutList.size()]; + if (this.currentParts == null || this.currentParts.length != currentParts.size()) { + this.currentParts = new Part[currentParts.size()]; } - currentLayoutList.toArray(currentLayout); - if (this.currentLayoutOffsets == null || this.currentLayoutOffsets.length != currentLayoutOffsets.size()) { - this.currentLayoutOffsets = new Integer[currentLayoutOffsets.size()]; + currentParts.toArray(this.currentParts); + if (this.oldParts == null || this.oldParts.length != oldParts.size()) { + this.oldParts = new Part[oldParts.size()]; } - currentLayoutOffsets.toArray(this.currentLayoutOffsets); - if (this.currentLayoutToOldIndex == null || this.currentLayoutToOldIndex.length != currentLayoutToOldIndex.size()) { - this.currentLayoutToOldIndex = new Integer[currentLayoutToOldIndex.size()]; - } - currentLayoutToOldIndex.toArray(this.currentLayoutToOldIndex); - - if (this.oldLayout == null || this.oldLayout.length != oldLayoutList.size()) { - this.oldLayout = new StaticLayout[oldLayoutList.size()]; - } - oldLayoutList.toArray(oldLayout); - if (this.oldLayoutOffsets == null || this.oldLayoutOffsets.length != oldLayoutOffsets.size()) { - this.oldLayoutOffsets = new Integer[oldLayoutOffsets.size()]; - } - oldLayoutOffsets.toArray(this.oldLayoutOffsets); - if (this.oldLayoutToCurrentIndex == null || this.oldLayoutToCurrentIndex.length != oldLayoutToCurrentIndex.size()) { - this.oldLayoutToCurrentIndex = new Integer[oldLayoutToCurrentIndex.size()]; - } - oldLayoutToCurrentIndex.toArray(this.oldLayoutToCurrentIndex); - - if (this.currentLayout.length > 0) { - isRTL = this.currentLayout[0].isRtlCharAt(0); - } else if (this.oldLayout.length > 0) { - isRTL = this.oldLayout[0].isRtlCharAt(0); - } - + oldParts.toArray(this.oldParts); if (animator != null) { animator.cancel(); } @@ -322,9 +321,7 @@ public class AnimatedTextView extends View { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - oldLayout = null; - AnimatedTextDrawable.this.oldLayoutOffsets = null; - AnimatedTextDrawable.this.oldLayoutToCurrentIndex = null; + AnimatedTextDrawable.this.oldParts = null; oldText = null; oldWidth = 0; t = 0; @@ -353,22 +350,13 @@ public class AnimatedTextView extends View { toSetTextMoveDown = false; t = 0; - currentLayout = new StaticLayout[1]; - currentLayout[0] = makeLayout(currentText = text, bounds.width()); - currentWidth = (int) currentLayout[0].getLineWidth(0); - currentHeight = currentLayout[0].getHeight(); - currentLayoutOffsets = new Integer[1]; - currentLayoutOffsets[0] = 0; - currentLayoutToOldIndex = new Integer[1]; - currentLayoutToOldIndex[0] = -1; + currentParts = new Part[1]; + currentParts[0] = new Part(makeLayout(currentText = text, bounds.width()), 0, -1); + currentWidth = currentParts[0].width; + currentHeight = currentParts[0].layout.getHeight(); + isRTL = AndroidUtilities.isRTL(currentText); - if (this.currentLayout.length > 0) { - isRTL = this.currentLayout[0].isRtlCharAt(0); - } - - oldLayout = null; - oldLayoutOffsets = null; - oldLayoutToCurrentIndex = null; + oldParts = null; oldText = null; oldWidth = 0; oldHeight = 0; @@ -381,18 +369,18 @@ public class AnimatedTextView extends View { return currentText; } - public int getWidth() { + public float getWidth() { return Math.max(currentWidth, oldWidth); } - public int getCurrentWidth() { - if (currentLayout != null && oldLayout != null) { + public float getCurrentWidth() { + if (currentParts != null && oldParts != null) { return AndroidUtilities.lerp(oldWidth, currentWidth, t); } return currentWidth; } - public int getHeight() { + public float getHeight() { return currentHeight; } @@ -654,6 +642,11 @@ public class AnimatedTextView extends View { public void setTextColor(int color) { textPaint.setColor(color); + alpha = Color.alpha(color); + } + + public int getTextColor() { + return textPaint.getColor(); } public void setTypeface(Typeface typeface) { @@ -724,6 +717,7 @@ public class AnimatedTextView extends View { private CharSequence toSetText; private boolean toSetMoveDown; + public boolean adaptWidth = true; public AnimatedTextView(Context context) { this(context, false, false, false); @@ -752,8 +746,8 @@ public class AnimatedTextView extends View { setText(drawable.getText(), false); } lastMaxWidth = width; - if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) { - width = getPaddingLeft() + drawable.getWidth() + getPaddingRight(); + if (adaptWidth && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) { + width = getPaddingLeft() + (int) Math.ceil(drawable.getWidth()) + getPaddingRight(); } setMeasuredDimension(width, height); } @@ -780,7 +774,7 @@ public class AnimatedTextView extends View { return drawable.isAnimating(); } - private void setIgnoreRTL(boolean value) { + public void setIgnoreRTL(boolean value) { drawable.ignoreRTL = value; } @@ -800,7 +794,7 @@ public class AnimatedTextView extends View { return; } } - int wasWidth = drawable.getWidth(); + int wasWidth = (int) drawable.getWidth(); drawable.setBounds(getPaddingLeft(), getPaddingTop(), lastMaxWidth - getPaddingRight(), getMeasuredHeight() - getPaddingBottom()); drawable.setText(text, animated, moveDown); if (wasWidth < drawable.getWidth() || !animated && wasWidth != drawable.getWidth()) { @@ -809,7 +803,7 @@ public class AnimatedTextView extends View { } public int width() { - return getPaddingLeft() + drawable.getCurrentWidth() + getPaddingRight(); + return getPaddingLeft() + (int) Math.ceil(drawable.getCurrentWidth()) + getPaddingRight(); } public CharSequence getText() { @@ -829,6 +823,10 @@ public class AnimatedTextView extends View { invalidate(); } + public int getTextColor() { + return drawable.getTextColor(); + } + public void setTypeface(Typeface typeface) { drawable.setTypeface(typeface); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java index 47fb79d14..71f5fd867 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java @@ -82,8 +82,8 @@ public class AttachBotIntroTopView extends View { protected void onDraw(Canvas canvas) { super.onDraw(canvas); - AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight() + AndroidUtilities.dp(6)); - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), backgroundPaint); + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight() + AndroidUtilities.dp(10)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(10), AndroidUtilities.dp(10), backgroundPaint); imageReceiver.setImageCoords(getWidth() / 2f - AndroidUtilities.dp(ICONS_SIDE_PADDING + ICONS_SIZE_DP), getHeight() / 2f - AndroidUtilities.dp(ICONS_SIZE_DP) / 2f, AndroidUtilities.dp(ICONS_SIZE_DP), AndroidUtilities.dp(ICONS_SIZE_DP)); imageReceiver.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachableDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachableDrawable.java new file mode 100644 index 000000000..c98b50cf0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachableDrawable.java @@ -0,0 +1,8 @@ +package org.telegram.ui.Components; + +import org.telegram.messenger.ImageReceiver; + +public interface AttachableDrawable { + void onAttachedToWindow(ImageReceiver parent); + void onDetachedFromWindow(ImageReceiver parent); +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java index ae8ac9a14..351297893 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java @@ -1391,7 +1391,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); final ArrayList fmessages = new ArrayList<>(); fmessages.add(messageObject); @@ -1424,6 +1424,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. fragment1.finishFragment(); } } + return true; }); parentActivity.presentFragment(fragment); dismiss(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java new file mode 100644 index 000000000..5568e12bb --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java @@ -0,0 +1,1395 @@ +package org.telegram.ui.Components; + +import static org.telegram.ui.Components.ImageUpdater.FOR_TYPE_CHANNEL; +import static org.telegram.ui.Components.ImageUpdater.FOR_TYPE_GROUP; +import static org.telegram.ui.Components.ImageUpdater.TYPE_SUGGEST_PHOTO_FOR_USER; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +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.view.ViewGroup; +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.core.view.NestedScrollingParent; +import androidx.core.view.NestedScrollingParentHelper; +import androidx.recyclerview.widget.LinearLayoutManager; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.SelectAnimatedEmojiDialog; + +import java.util.ArrayList; +import java.util.Objects; + +public class AvatarConstructorFragment extends BaseFragment { + + public final static float STICKER_DEFAULT_SCALE = 0.7f; + public final static float STICKER_DEFAULT_ROUND_RADIUS = 0.13f; + PreviewView previewView; + private SelectAnimatedEmojiDialog selectAnimatedEmojiDialog; + + int collapsedHeight; + int expandedHeight; + View colorPickerPreviewView; + boolean colorPickerInAnimatoin; + boolean drawForBlur; + boolean wasChanged; + LinearLayout linearLayout; + + boolean forGroup; + private FrameLayout button; + + float progressToExpand; + boolean expandWithKeyboard; + ValueAnimator expandAnimator; + + protected ActionBar overlayActionBar; + + Delegate delegate; + private BackgroundSelectView backgroundSelectView; + CanvasButton avatarClickableArea; + boolean keyboardVisible; + + ValueAnimator keyboardVisibilityAnimator; + float keyboardVisibleProgress; + Paint actionBarPaint = new Paint(); + private int gradientBackgroundItemWidth; + + public String[] keys_avatar_background = {Theme.key_avatar_backgroundBlue, Theme.key_avatar_backgroundCyan, Theme.key_avatar_backgroundGreen, Theme.key_avatar_backgroundOrange, Theme.key_avatar_backgroundRed, Theme.key_avatar_backgroundPink, Theme.key_avatar_backgroundViolet}; + public String[] keys_avatar_background2 = {Theme.key_avatar_background2Blue, Theme.key_avatar_background2Cyan, Theme.key_avatar_background2Green, Theme.key_avatar_background2Orange, Theme.key_avatar_background2Red, Theme.key_avatar_background2Pink, Theme.key_avatar_background2Violet}; + public boolean finishOnDone = true; + private ActionBarMenuItem setPhotoItem; + private BottomSheet bottomSheet; + final ImageUpdater.AvatarFor avatarFor; + boolean isLandscapeMode; + private TextView chooseEmojiHint; + private TextView chooseBackgroundHint; + ImageUpdater imageUpdater; + + public AvatarConstructorFragment(ImageUpdater imageUpdater, ImageUpdater.AvatarFor avatarFor) { + this.imageUpdater = imageUpdater; + this.avatarFor = avatarFor; + } + + @Override + public View createView(Context context) { + hasOwnBackground = true; + actionBar.setBackgroundDrawable(null); + actionBar.setCastShadows(false); + actionBar.setAddToContainer(false); + actionBar.setOccupyStatusBar(true); + actionBar.setTitleColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_listSelector), false); + actionBar.setBackButtonDrawable(new BackDrawable(false)); + actionBar.setAllowOverlayTitle(false); + actionBar.setTitle(LocaleController.getString("PhotoEditor", R.string.PhotoEditor)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + discardEditor(); + } + } + }); + actionBar.getTitleTextView().setAlpha(0); + + overlayActionBar = new ActionBar(getContext()); + overlayActionBar.setCastShadows(false); + overlayActionBar.setAddToContainer(false); + overlayActionBar.setOccupyStatusBar(true); + overlayActionBar.setClipChildren(false); + int selectorColor = ColorUtils.setAlphaComponent(Color.WHITE, 60); + overlayActionBar.setItemsColor(Color.WHITE, false); + + overlayActionBar.setBackButtonDrawable(new BackDrawable(false)); + overlayActionBar.setAllowOverlayTitle(false); + overlayActionBar.setItemsBackgroundColor(selectorColor, false); + ActionBarMenu menuOverlay = overlayActionBar.createMenu(); + menuOverlay.setClipChildren(false); + setPhotoItem = menuOverlay.addItem(1, avatarFor != null && avatarFor.type == TYPE_SUGGEST_PHOTO_FOR_USER ? + LocaleController.getString("SuggestPhoto", R.string.SuggestPhoto) : + LocaleController.getString("SetPhoto", R.string.SetPhoto) + ); + setPhotoItem.setBackground(Theme.createSelectorDrawable(selectorColor, Theme.RIPPLE_MASK_CIRCLE_TO_BOUND_EDGE)); + overlayActionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + discardEditor(); + } + if (id == 1) { + onDonePressed(); + } + } + }); + + linearLayout = new LinearLayout(getContext()) { + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == previewView) { + return true; + } + return super.drawChild(canvas, child, drawingTime); + } + }; + + ContainerLayout nestedSizeNotifierLayout = new ContainerLayout(context) { + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + measureKeyboardHeight(); + boolean isLandscapeModeLocal = MeasureSpec.getSize(widthMeasureSpec) > (MeasureSpec.getSize(heightMeasureSpec) + keyboardHeight); + if (isLandscapeModeLocal != isLandscapeMode) { + isLandscapeMode = isLandscapeModeLocal; + AndroidUtilities.removeFromParent(previewView); + AndroidUtilities.requestAdjustNothing(getParentActivity(), getClassGuid()); + if (isLandscapeMode) { + setProgressToExpand(0, false); + previewView.setExpanded(false); + addView(previewView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } else { + linearLayout.addView(previewView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + AndroidUtilities.requestAdjustResize(getParentActivity(), getClassGuid()); + } + if (isLandscapeMode) { + int avatarWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.45f); + int contentWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.55f); + ((MarginLayoutParams) linearLayout.getLayoutParams()).bottomMargin = 0; + ((MarginLayoutParams) linearLayout.getLayoutParams()).leftMargin = avatarWidth; + ((MarginLayoutParams) previewView.getLayoutParams()).rightMargin = contentWidth; + ((MarginLayoutParams) button.getLayoutParams()).rightMargin = contentWidth + AndroidUtilities.dp(16); + ((MarginLayoutParams) chooseBackgroundHint.getLayoutParams()).topMargin = 0; + ((MarginLayoutParams) chooseEmojiHint.getLayoutParams()).topMargin = AndroidUtilities.dp(10); + } else { + ((MarginLayoutParams) linearLayout.getLayoutParams()).bottomMargin = AndroidUtilities.dp(64); + ((MarginLayoutParams) linearLayout.getLayoutParams()).leftMargin = 0; + ((MarginLayoutParams) previewView.getLayoutParams()).rightMargin = 0; + ((MarginLayoutParams) button.getLayoutParams()).rightMargin = AndroidUtilities.dp(16); + ((MarginLayoutParams) chooseBackgroundHint.getLayoutParams()).topMargin = AndroidUtilities.dp(10); + ((MarginLayoutParams) chooseEmojiHint.getLayoutParams()).topMargin = AndroidUtilities.dp(18); + } + boolean oldKeyboardVisible = keyboardVisible; + keyboardVisible = keyboardHeight >= AndroidUtilities.dp(20); + + if (oldKeyboardVisible != keyboardVisible) { + int newMargin; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (keyboardVisible) { + newMargin = -selectAnimatedEmojiDialog.getTop() + actionBar.getMeasuredHeight() + AndroidUtilities.dp(8); + } else { + newMargin = 0; + } + linearLayout.setTranslationY(linearLayout.getTranslationY() + ((MarginLayoutParams) linearLayout.getLayoutParams()).topMargin - newMargin); + ((MarginLayoutParams) linearLayout.getLayoutParams()).topMargin = newMargin; + createKeyboardVisibleAnimator(keyboardVisible); + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + collapsedHeight = previewView.getMeasuredHeight(); + expandedHeight = previewView.getMeasuredWidth(); + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == overlayActionBar) { + return true; + } + if (child == actionBar && keyboardVisibleProgress > 0) { + actionBarPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + actionBarPaint.setAlpha((int) (255 * keyboardVisibleProgress)); + canvas.drawRect(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight(), actionBarPaint); + getParentLayout().drawHeaderShadow(canvas, (int) (255 * keyboardVisibleProgress), child.getMeasuredHeight()); + } + return super.drawChild(canvas, child, drawingTime); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + int count = canvas.save(); + super.dispatchDraw(canvas); + if (!isLandscapeMode) { + if (!drawForBlur) { + canvas.save(); + float x = linearLayout.getX() + previewView.getX(); + float y = linearLayout.getY() + previewView.getY(); + int additionalH = expandedHeight - collapsedHeight; + int yKeyboardVisible = AndroidUtilities.statusBarHeight + ((ActionBar.getCurrentActionBarHeight() - collapsedHeight) >> 1); + y = AndroidUtilities.lerp(y, yKeyboardVisible, keyboardVisibleProgress); + canvas.translate(x, y); + previewView.draw(canvas); + AndroidUtilities.rectTmp.set(x, y - additionalH / 2f * progressToExpand, x + previewView.getMeasuredWidth(), y + previewView.getMeasuredHeight() + additionalH / 2f * progressToExpand); + float cx = x + previewView.cx; + float cy = y + previewView.cy; + avatarClickableArea.setRect((int) (cx - previewView.size), (int) (cy - previewView.size), (int) (cx + previewView.size), (int) (cy + previewView.size)); + canvas.restore(); + } + canvas.restoreToCount(count); + + + float alpha = previewView.expandProgress.get() * (1f - (colorPickerPreviewView.getVisibility() == View.VISIBLE ? colorPickerPreviewView.getAlpha() : 0)); + if (alpha != 0) { + overlayActionBar.setVisibility(View.VISIBLE); + count = canvas.save(); + canvas.translate(overlayActionBar.getX(), overlayActionBar.getY()); + + if (alpha != 1) { + canvas.saveLayerAlpha(0, 0, overlayActionBar.getMeasuredWidth(), overlayActionBar.getMeasuredHeight(), (int) (255 * alpha), Canvas.ALL_SAVE_FLAG); + } + overlayActionBar.draw(canvas); + canvas.restoreToCount(count); + } else { + overlayActionBar.setVisibility(View.GONE); + } + } + if (colorPickerInAnimatoin) { + invalidate(); + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (keyboardVisibleProgress == 0 && AndroidUtilities.findClickableView(this, ev.getX(), ev.getY())) { + return false; + } + return onTouchEvent(ev); + } + + boolean maybeScroll; + boolean isScrolling; + float startFromProgressToExpand; + float scrollFromX, scrollFromY; + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (avatarClickableArea.checkTouchEvent(event)) { + return true; + } + + if (!isLandscapeMode) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + selectAnimatedEmojiDialog.getHitRect(AndroidUtilities.rectTmp2); + AndroidUtilities.rectTmp2.offset(0, (int) linearLayout.getY()); + if (keyboardVisibleProgress == 0 && !AndroidUtilities.rectTmp2.contains((int) event.getX(), (int) event.getY())) { + maybeScroll = true; + scrollFromX = event.getX(); + scrollFromY = event.getY(); + } + } else if (event.getAction() == MotionEvent.ACTION_MOVE && (maybeScroll || isScrolling)) { + if (maybeScroll) { + if (Math.abs(scrollFromY - event.getY()) > AndroidUtilities.touchSlop) { + maybeScroll = false; + isScrolling = true; + startFromProgressToExpand = progressToExpand; + scrollFromX = event.getX(); + scrollFromY = event.getY(); + } + } else { + float dy = scrollFromY - event.getY(); + float progressToExpand = startFromProgressToExpand + (-dy / (float) expandedHeight); + progressToExpand = Utilities.clamp(progressToExpand, 1f, 0f); + setProgressToExpand(progressToExpand, true); + } + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (isScrolling) { + setExpanded(progressToExpand > 0.5f, false, false); + } + maybeScroll = false; + isScrolling = false; + } + } + return isScrolling || super.onTouchEvent(event) || maybeScroll; + } + }; + nestedSizeNotifierLayout.setFitsSystemWindows(true); + nestedSizeNotifierLayout.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + + linearLayout.setClipChildren(false); + linearLayout.setClipToPadding(false); + linearLayout.setPadding(0, AndroidUtilities.statusBarHeight, 0, 0); + linearLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout.addView(previewView = new PreviewView(getContext()) { + @Override + public void invalidate() { + super.invalidate(); + nestedSizeNotifierLayout.invalidate(); + } + }); + + chooseBackgroundHint = new TextView(getContext()); + chooseBackgroundHint.setText(LocaleController.getString("ChooseBackground", R.string.ChooseBackground)); + chooseBackgroundHint.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + chooseBackgroundHint.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + chooseBackgroundHint.setGravity(Gravity.CENTER); + linearLayout.addView(chooseBackgroundHint, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 21, 10, 21, 10)); + + FrameLayout backgroundContainer = new FrameLayout(getContext()) { + + private Path path = new Path(); + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void dispatchDraw(Canvas canvas) { + Theme.applyDefaultShadow(paint); + paint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, getResourceProvider())); + paint.setAlpha((int) (255 * getAlpha())); + + AndroidUtilities.rectTmp.set( + 0, 0, getMeasuredWidth(), getMeasuredHeight() + ); + path.rewind(); + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(12), AndroidUtilities.dp(12), Path.Direction.CW); + canvas.drawPath(path, paint); + super.dispatchDraw(canvas); + } + }; + backgroundContainer.addView(backgroundSelectView = new BackgroundSelectView(getContext())); + linearLayout.addView(backgroundContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 0, 12, 0, 12, 0)); + + chooseEmojiHint = new TextView(getContext()); + chooseEmojiHint.setText(LocaleController.getString("ChooseEmojiOrSticker", R.string.ChooseEmojiOrSticker)); + chooseEmojiHint.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + chooseEmojiHint.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + chooseEmojiHint.setGravity(Gravity.CENTER); + linearLayout.addView(chooseEmojiHint, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 21, 18, 21, 10)); + + selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog(this, getContext(), false, null, SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR, null) { + + private boolean firstLayout = true; + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (firstLayout) { + firstLayout = false; + selectAnimatedEmojiDialog.onShow(null); + } + } + + protected void onEmojiSelected(View view, Long documentId, TLRPC.Document document, Integer until) { + long docId = documentId == null ? 0 : documentId; + previewView.documentId = docId; + previewView.document = document; + if (docId == 0) { + previewView.backupImageView.setAnimatedEmojiDrawable(null); + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + previewView.backupImageView.getImageReceiver().setImage(ImageLocation.getForDocument(document), "100_100", null, null, svgThumb, 0, "tgs", document, 0); + } else { + previewView.backupImageView.setAnimatedEmojiDrawable(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW, currentAccount, docId)); + previewView.backupImageView.getImageReceiver().clearImage(); + } + if (previewView.getImageReceiver() != null && previewView.getImageReceiver().getAnimation() != null) { + previewView.getImageReceiver().getAnimation().seekTo(0, true); + } + if (previewView.getImageReceiver() != null && previewView.getImageReceiver().getLottieAnimation() != null) { + previewView.getImageReceiver().getLottieAnimation().setCurrentFrame(0, false, true); + } + wasChanged = true; + } + }; + + selectAnimatedEmojiDialog.setAnimationsEnabled(fragmentBeginToShow); + selectAnimatedEmojiDialog.setClipChildren(false); + linearLayout.addView(selectAnimatedEmojiDialog, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 12, 0, 12, 12)); + + linearLayout.setClipChildren(false); + nestedSizeNotifierLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 0, 0, 0, 64)); + + colorPickerPreviewView = new View(getContext()); + colorPickerPreviewView.setVisibility(View.GONE); + + + button = new FrameLayout(getContext()); + button.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 8)); + + TextView textView = new TextView(getContext()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + if (imageUpdater.setForType == FOR_TYPE_CHANNEL) { + textView.setText(LocaleController.getString("SetChannelPhoto", R.string.SetChannelPhoto)); + } else if (imageUpdater.setForType == FOR_TYPE_GROUP) { + textView.setText(LocaleController.getString("SetGroupPhoto", R.string.SetGroupPhoto)); + } else if (avatarFor != null && avatarFor.type == TYPE_SUGGEST_PHOTO_FOR_USER) { + textView.setText(LocaleController.getString("SuggestPhoto", R.string.SuggestPhoto)); + } else { + textView.setText(LocaleController.getString("SetProfilePhotoAvatarConstructor", R.string.SetProfilePhotoAvatarConstructor)); + } + textView.setGravity(Gravity.CENTER); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + button.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + button.setOnClickListener(v -> onDonePressed()); + + nestedSizeNotifierLayout.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 16, 16, 16, 16)); + nestedSizeNotifierLayout.addView(actionBar); + + nestedSizeNotifierLayout.addView(overlayActionBar); + nestedSizeNotifierLayout.addView(colorPickerPreviewView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + avatarClickableArea = new CanvasButton(nestedSizeNotifierLayout); + avatarClickableArea.setDelegate(() -> { + onPreviewClick(); + }); + fragmentView = nestedSizeNotifierLayout; + return fragmentView; + } + + private void discardEditor() { + if (getParentActivity() == null) { + return; + } + if (wasChanged) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("PhotoEditorDiscardAlert", R.string.PhotoEditorDiscardAlert)); + builder.setTitle(LocaleController.getString("DiscardChanges", R.string.DiscardChanges)); + builder.setPositiveButton(LocaleController.getString("PassportDiscard", R.string.PassportDiscard), (dialogInterface, i) -> finishFragment()); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + AlertDialog dialog = builder.create(); + showDialog(dialog); + dialog.redPositive(); + } else { + finishFragment(); + } + } + + private void createKeyboardVisibleAnimator(boolean keyboardVisible) { + if (isLandscapeMode) { + return; + } + keyboardVisibilityAnimator = ValueAnimator.ofFloat(keyboardVisibleProgress, keyboardVisible ? 1f : 0f); + float offsetY = (expandedHeight - collapsedHeight - AndroidUtilities.statusBarHeight) * progressToExpand; + float translationYFrom, translationYTo; + if (keyboardVisible) { + previewView.setExpanded(false); + translationYFrom = linearLayout.getTranslationY(); + translationYTo = 0; + } else { + translationYFrom = offsetY; + translationYTo = linearLayout.getTranslationY(); + } + if (expandWithKeyboard && !keyboardVisible) { + previewView.setExpanded(true); + } else { + expandWithKeyboard = false; + } + keyboardVisibilityAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + keyboardVisibleProgress = (float) animation.getAnimatedValue(); + float offset = AndroidUtilities.lerp(translationYFrom, translationYTo, keyboardVisibleProgress); + actionBar.getTitleTextView().setAlpha(keyboardVisibleProgress); + if (expandWithKeyboard && !keyboardVisible) { + setProgressToExpand(1f - keyboardVisibleProgress, false); + } + linearLayout.setTranslationY(offset); + button.setTranslationY(offset); + fragmentView.invalidate(); + actionBar.invalidate(); + } + }); + keyboardVisibilityAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setProgressToExpand(expandWithKeyboard ? 1f : 0f, false); + expandWithKeyboard = false; + } + }); + keyboardVisibilityAnimator.setDuration(AdjustPanLayoutHelper.keyboardDuration); + keyboardVisibilityAnimator.setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator); + keyboardVisibilityAnimator.start(); + } + + private void onDonePressed() { + if (previewView.getImageReceiver() == null || !previewView.getImageReceiver().hasImageLoaded()) { + return; + } + if (delegate != null) { + delegate.onDone(previewView.backgroundGradient, previewView.documentId, previewView.document, previewView); + } + if (finishOnDone) { + finishFragment(); + } + } + + + private void setExpanded(boolean expanded, boolean fromClick, boolean withColorPicker) { + if (isLandscapeMode) { + return; + } +// if (this.expanded != expanded) { +// this.expanded = expanded; + cancelExpandAnimator(); + expandAnimator = ValueAnimator.ofFloat(progressToExpand, expanded ? 1f : 0f); + if (fromClick) { + previewView.overrideExpandProgress = progressToExpand; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + } + expandAnimator.addUpdateListener(animation -> { + float progress = (float) animation.getAnimatedValue(); + setProgressToExpand(progress, false); + if (fromClick) { + previewView.overrideExpandProgress = progress; + previewView.invalidate(); + } + }); + expandAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + expandAnimator = null; + setProgressToExpand(expanded ? 1f : 0f, false); + if (fromClick) { + previewView.overrideExpandProgress = -1; + previewView.setExpanded(expanded); + } + + } + }); + if (withColorPicker) { + expandAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + expandAnimator.setDuration(350); + expandAnimator.setStartDelay(150); + } else { + expandAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + expandAnimator.setDuration(250); + } + expandAnimator.start(); + // } + } + + void cancelExpandAnimator() { + if (expandAnimator != null) { + expandAnimator.removeAllListeners(); + expandAnimator.cancel(); + expandAnimator = null; + } + } + + private void setProgressToExpand(float progressToExpand, boolean fromScroll) { + this.progressToExpand = progressToExpand; + + float offsetY = (expandedHeight - collapsedHeight - AndroidUtilities.statusBarHeight) * progressToExpand; + if (keyboardVisibleProgress == 0) { + linearLayout.setTranslationY(offsetY); + button.setTranslationY(offsetY); + } + previewView.setTranslationY(-(expandedHeight - collapsedHeight) / 2f * progressToExpand); + fragmentView.invalidate(); + if (fromScroll) { + previewView.setExpanded(progressToExpand > 0.5f); + } + } + + public void startFrom(AvatarConstructorPreviewCell previewCell) { + BackgroundGradient gradient = previewCell.getBackgroundGradient(); + previewView.setGradient(gradient); + if (previewCell.getAnimatedEmoji() != null) { + long docId = previewCell.getAnimatedEmoji().getDocumentId(); + previewView.documentId = docId; + previewView.backupImageView.setAnimatedEmojiDrawable(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW, currentAccount, docId)); + } + backgroundSelectView.selectGradient(gradient); + selectAnimatedEmojiDialog.setForUser(previewCell.forUser); + } + + public class PreviewView extends FrameLayout { + + public long documentId; + public TLRPC.Document document; + BackupImageView backupImageView; + GradientTools gradientTools = new GradientTools(); + GradientTools outGradientTools = new GradientTools(); + float changeBackgroundProgress = 1f; + BackgroundGradient backgroundGradient; + + AnimatedFloat expandProgress = new AnimatedFloat(this, 200, CubicBezierInterpolator.EASE_OUT); + boolean expanded; + float overrideExpandProgress = -1f; + private float size; + private float cx, cy; + + public PreviewView(Context context) { + super(context); + backupImageView = new BackupImageView(context) { + @Override + public void invalidate() { + super.invalidate(); + PreviewView.this.invalidate(); + } + + @Override + public void invalidate(Rect dirty) { + super.invalidate(dirty); + PreviewView.this.invalidate(); + } + + @Override + public void invalidate(int l, int t, int r, int b) { + super.invalidate(l, t, r, b); + PreviewView.this.invalidate(); + } + }; + backupImageView.getImageReceiver().setAutoRepeatCount(1); + backupImageView.getImageReceiver().setAspectFit(true); + setClipChildren(false); + addView(backupImageView, LayoutHelper.createFrame(70, 70, Gravity.CENTER)); + } + + public void setExpanded(boolean expanded) { + if (this.expanded == expanded) { + return; + } + this.expanded = expanded; + if (expanded) { + if (backupImageView.animatedEmojiDrawable != null && backupImageView.animatedEmojiDrawable.getImageReceiver() != null) { + backupImageView.animatedEmojiDrawable.getImageReceiver().startAnimation(); + } + backupImageView.imageReceiver.startAnimation(); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + invalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (isLandscapeMode) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } else { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(140), MeasureSpec.EXACTLY)); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + cx = getMeasuredWidth() / 2f; + cy = getMeasuredHeight() / 2f; + float radius = isLandscapeMode ? getMeasuredWidth() * 0.3f : AndroidUtilities.dp(50); + expandProgress.set(expanded ? 1f : 0f); + if (overrideExpandProgress >= 0) { + expandProgress.set(overrideExpandProgress, true); + } + size = AndroidUtilities.lerp(radius, getMeasuredWidth() / 2f, expandProgress.get()); + size = AndroidUtilities.lerp(size, AndroidUtilities.dp(21), keyboardVisibleProgress); + cx = AndroidUtilities.lerp(cx, getMeasuredWidth() - AndroidUtilities.dp(12) - AndroidUtilities.dp(21), keyboardVisibleProgress); + + + canvas.save(); + int additionalH = expandedHeight - collapsedHeight; + canvas.clipRect(0, -additionalH / 2f, getMeasuredWidth(), getMeasuredHeight() + additionalH / 2f * progressToExpand); + if (backgroundGradient != null) { + gradientTools.setColors(backgroundGradient.color1, backgroundGradient.color2, backgroundGradient.color3, backgroundGradient.color4); + gradientTools.setBounds(cx - size, cy - size, cx + size, cy + size); + if (changeBackgroundProgress != 1f) { + outGradientTools.setBounds(cx - size, cy - size, cx + size, cy + size); + outGradientTools.paint.setAlpha(255); + drawBackround(canvas, cx, cy, radius, size, outGradientTools.paint); + gradientTools.paint.setAlpha((int) (255 * changeBackgroundProgress)); + drawBackround(canvas, cx, cy, radius, size, gradientTools.paint); + changeBackgroundProgress += 16 / 250f; + if (changeBackgroundProgress > 1f) { + changeBackgroundProgress = 1f; + } + invalidate(); + } else { + gradientTools.paint.setAlpha(255); + drawBackround(canvas, cx, cy, radius, size, gradientTools.paint); + } + } + int imageHeight = isLandscapeMode ? (int) (radius * 2 * STICKER_DEFAULT_SCALE) : AndroidUtilities.dp(70); + int imageHeightExpanded = (int) (getMeasuredWidth() * STICKER_DEFAULT_SCALE); + int imageHeightKeyboardVisible = (int) (AndroidUtilities.dp(42) * STICKER_DEFAULT_SCALE); + float imageSize = AndroidUtilities.lerp(imageHeight, imageHeightExpanded, expandProgress.get()); + imageSize = AndroidUtilities.lerp(imageSize, imageHeightKeyboardVisible, keyboardVisibleProgress); + imageSize /= 2; + if (backupImageView.animatedEmojiDrawable != null) { + if (backupImageView.animatedEmojiDrawable.getImageReceiver() != null) { + backupImageView.animatedEmojiDrawable.getImageReceiver().setRoundRadius((int) (imageSize * 2 * STICKER_DEFAULT_ROUND_RADIUS)); + } + backupImageView.animatedEmojiDrawable.setBounds((int) (cx - imageSize), (int) (cy - imageSize), (int) (cx + imageSize), (int) (cy + imageSize)); + backupImageView.animatedEmojiDrawable.draw(canvas); + + } else { + backupImageView.imageReceiver.setImageCoords(cx - imageSize, cy - imageSize, imageSize * 2, imageSize * 2); + backupImageView.imageReceiver.setRoundRadius((int) (imageSize * 2 * STICKER_DEFAULT_ROUND_RADIUS)); + backupImageView.imageReceiver.draw(canvas); + } + } + + private void drawBackround(Canvas canvas, float cx, float cy, float radius, float size, Paint paint) { + float p = expandProgress.get(); + if (p == 0) { + canvas.drawCircle(cx, cy, size, paint); + } else { + float roundRadius = AndroidUtilities.lerp(radius, 0, p); + AndroidUtilities.rectTmp.set(cx - size, cy - size, cx + size, cy + size); + canvas.drawRoundRect(AndroidUtilities.rectTmp, roundRadius, roundRadius, paint); + } + } + + public void setGradient(BackgroundGradient backgroundGradient) { + if (this.backgroundGradient != null) { + outGradientTools.setColors(this.backgroundGradient.color1, this.backgroundGradient.color2, this.backgroundGradient.color3, this.backgroundGradient.color4); + changeBackgroundProgress = 0f; + wasChanged = true; + } + this.backgroundGradient = backgroundGradient; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + invalidate(); + } + + public long getDuration() { + ImageReceiver imageReceiver = backupImageView.getImageReceiver(); + if (backupImageView.animatedEmojiDrawable != null) { + imageReceiver = backupImageView.animatedEmojiDrawable.getImageReceiver(); + } + if (imageReceiver == null) { + return 5000; + } + if (imageReceiver.getLottieAnimation() != null) { + return imageReceiver.getLottieAnimation().getDuration(); + } + return 5000; + } + + public ImageReceiver getImageReceiver() { + ImageReceiver imageReceiver = backupImageView.getImageReceiver(); + if (backupImageView.animatedEmojiDrawable != null) { + imageReceiver = backupImageView.animatedEmojiDrawable.getImageReceiver(); + } + return imageReceiver; + } + + public boolean hasAnimation() { + return getImageReceiver().getAnimation() != null || getImageReceiver().getLottieAnimation() != null; + } + + @Override + public void invalidate() { + super.invalidate(); + fragmentView.invalidate(); + } + } + + private class BackgroundSelectView extends RecyclerListView { + + ArrayList gradients = new ArrayList<>(); + + int stableIdPointer = 200; + + int selectedItemId = -1; + + Adapter adapter; + BackgroundGradient customSelectedGradient; + + public BackgroundSelectView(Context context) { + super(context); + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); + setLayoutManager(layoutManager); + for (int i = 0; i < keys_avatar_background.length; i++) { + BackgroundGradient backgroundGradient = new BackgroundGradient(); + backgroundGradient.stableId = stableIdPointer++; + backgroundGradient.color1 = Theme.getColor(keys_avatar_background[i]); + backgroundGradient.color2 = Theme.getColor(keys_avatar_background2[i]); + gradients.add(backgroundGradient); + } + setOnItemClickListener((view, position) -> { + if (view instanceof GradientSelectorView && !((GradientSelectorView) view).isCustom) { + selectedItemId = ((GradientSelectorView) view).backgroundGradient.stableId; + previewView.setGradient(((GradientSelectorView) view).backgroundGradient); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } else { + if (selectedItemId != 1 && customSelectedGradient != null) { + selectedItemId = 1; + previewView.setGradient(customSelectedGradient); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } else { + showColorPicker(); + } + } + }); + setAdapter(adapter = new Adapter() { + + private final static int VIEW_TYPE_GRADIENT = 0; + private final static int VIEW_TYPE_ADD_CUSTOM = 1; + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case VIEW_TYPE_ADD_CUSTOM: + case VIEW_TYPE_GRADIENT: + default: + view = new GradientSelectorView(getContext()); + break; + } + return new Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + if (holder.getItemViewType() == VIEW_TYPE_GRADIENT) { + GradientSelectorView gradientSelectorView = (GradientSelectorView) holder.itemView; + gradientSelectorView.setGradient(gradients.get(position)); + gradientSelectorView.setSelectedInternal(selectedItemId == gradients.get(position).stableId, true); + } else { + GradientSelectorView gradientSelectorView = (GradientSelectorView) holder.itemView; + gradientSelectorView.setCustom(true); + gradientSelectorView.setGradient(customSelectedGradient); + gradientSelectorView.setSelectedInternal(selectedItemId == 1, true); + } + } + + @Override + public int getItemCount() { + return gradients.size() + 1; + } + + @Override + public long getItemId(int position) { + if (position >= gradients.size()) { + return 1; + } + return gradients.get(position).stableId; + } + + @Override + public int getItemViewType(int position) { + if (position >= gradients.size()) { + return VIEW_TYPE_ADD_CUSTOM; + } + return VIEW_TYPE_GRADIENT; + } + }); + setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + int availableWidth = MeasureSpec.getSize(widthSpec); + int itemsCount = adapter.getItemCount(); + gradientBackgroundItemWidth = availableWidth / itemsCount; + if (gradientBackgroundItemWidth < AndroidUtilities.dp(36)) { + gradientBackgroundItemWidth = AndroidUtilities.dp(36); + } else if (gradientBackgroundItemWidth > AndroidUtilities.dp(150)) { + gradientBackgroundItemWidth = AndroidUtilities.dp(48); + } + super.onMeasure(widthSpec, heightSpec); + } + + public void selectGradient(BackgroundGradient gradient) { + boolean isDefault = false; + for (int i = 0; i < gradients.size(); i++) { + if (gradients.get(i).equals(gradient)) { + selectedItemId = gradients.get(i).stableId; + isDefault = true; + break; + } + } + if (!isDefault) { + customSelectedGradient = gradient; + selectedItemId = 1; + } + adapter.notifyDataSetChanged(); + } + } + + BackgroundGradient colorPickerGradient; + + private void showColorPicker() { + if (bottomSheet != null) { + return; + } + if (!previewView.expanded) { + setExpanded(true, true, true); + } + + BackgroundGradient prevGradient = null; + if (previewView.backgroundGradient != null) { + prevGradient = previewView.backgroundGradient; + } + boolean[] onDoneButtonPressed = new boolean[]{false}; + BackgroundGradient finalPrevGradient = prevGradient; + AndroidUtilities.requestAdjustNothing(getParentActivity(), getClassGuid()); + bottomSheet = new BottomSheet(getContext(), true) { + @Override + public void dismiss() { + super.dismiss(); + backgroundSelectView.selectGradient(colorPickerGradient); + colorPickerInAnimatoin = true; + fragmentView.invalidate(); + colorPickerPreviewView.animate().setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + colorPickerInAnimatoin = false; + colorPickerPreviewView.setVisibility(View.GONE); + } + }).alpha(0f).setDuration(200).start(); + } + + @Override + public void dismissInternal() { + super.dismissInternal(); + AndroidUtilities.requestAdjustResize(getParentActivity(), getClassGuid()); + bottomSheet = null; + } + }; + bottomSheet.fixNavigationBar(); + bottomSheet.pauseAllHeavyOperations = false; + + drawForBlur = true; + colorPickerPreviewView.setBackground(new BitmapDrawable(getContext().getResources(), AndroidUtilities.makeBlurBitmap(fragmentView, 12f, 10))); + drawForBlur = false; + colorPickerPreviewView.setVisibility(View.VISIBLE); + colorPickerPreviewView.setAlpha(0); + colorPickerInAnimatoin = true; + fragmentView.invalidate(); + colorPickerPreviewView.animate().setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + colorPickerInAnimatoin = false; + } + }).alpha(1f).setDuration(200).start(); + + colorPickerGradient = new BackgroundGradient(); + ColorPicker colorPicker = new ColorPicker(getContext(), false, (color, num, applyNow) -> { + switch (num) { + case 0: + if (colorPickerGradient.color1 != color && (colorPickerGradient.color1 == 0 || color == 0)) { + colorPickerGradient = colorPickerGradient.copy(); + previewView.setGradient(colorPickerGradient); + } + colorPickerGradient.color1 = color; + break; + case 1: + if (colorPickerGradient.color2 != color && (colorPickerGradient.color2 == 0 || color == 0)) { + colorPickerGradient = colorPickerGradient.copy(); + previewView.setGradient(colorPickerGradient); + } + colorPickerGradient.color2 = color; + break; + case 2: + if (colorPickerGradient.color3 != color && (colorPickerGradient.color3 == 0 || color == 0)) { + colorPickerGradient = colorPickerGradient.copy(); + previewView.setGradient(colorPickerGradient); + } + colorPickerGradient.color3 = color; + break; + case 3: + if (colorPickerGradient.color4 != color && (colorPickerGradient.color4 == 0 || color == 0)) { + colorPickerGradient = colorPickerGradient.copy(); + previewView.setGradient(colorPickerGradient); + } + colorPickerGradient.color4 = color; + break; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + previewView.invalidate(); + }) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(300), MeasureSpec.EXACTLY)); + } + }; + + if (previewView.backgroundGradient != null) { + colorPicker.setColor(colorPickerGradient.color4 = previewView.backgroundGradient.color4, 3); + colorPicker.setColor(colorPickerGradient.color3 = previewView.backgroundGradient.color3, 2); + colorPicker.setColor(colorPickerGradient.color2 = previewView.backgroundGradient.color2, 1); + colorPicker.setColor(colorPickerGradient.color1 = previewView.backgroundGradient.color1, 0); + } + + colorPicker.setType(-1, true, 4, colorPickerGradient.colorsCount(), false, 0, false); + + previewView.setGradient(colorPickerGradient); + + LinearLayout colorPickerContainer = new LinearLayout(getContext()); + colorPickerContainer.setOrientation(LinearLayout.VERTICAL); + colorPickerContainer.setPadding(0, AndroidUtilities.dp(8), 0, 0); + colorPickerContainer.addView(colorPicker); + + FrameLayout button = new FrameLayout(getContext()); + button.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 8)); + + TextView textView = new TextView(getContext()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setText(LocaleController.getString("SetColor", R.string.SetColor)); + textView.setGravity(Gravity.CENTER); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + button.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + + colorPickerContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, 0, 16, -8, 16, 16)); + button.setOnClickListener(v -> { + onDoneButtonPressed[0] = true; + backgroundSelectView.selectGradient(colorPickerGradient); + bottomSheet.dismiss(); + }); + bottomSheet.setCustomView(colorPickerContainer); + bottomSheet.smoothKeyboardAnimationEnabled = true; + bottomSheet.setDimBehind(false); + bottomSheet.show(); + isLightStatusBar(); + } + + public static class BackgroundGradient { + + public int stableId; + + int color1; + int color2; + int color3; + int color4; + + public BackgroundGradient copy() { + BackgroundGradient backgroundGradient = new BackgroundGradient(); + backgroundGradient.color1 = color1; + backgroundGradient.color2 = color2; + backgroundGradient.color3 = color3; + backgroundGradient.color4 = color4; + return backgroundGradient; + } + + public int colorsCount() { + if (color4 != 0) { + return 4; + } + if (color3 != 0) { + return 3; + } + if (color2 != 0) { + return 2; + } + return 1; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BackgroundGradient)) return false; + BackgroundGradient that = (BackgroundGradient) o; + return color1 == that.color1 && color2 == that.color2 && color3 == that.color3 && color4 == that.color4; + } + + @Override + public int hashCode() { + return Objects.hash(stableId, color1, color2, color3, color4); + } + + public int getAverageColor() { + int color = color1; + if (color2 != 0) { + color = ColorUtils.blendARGB(color, color2, 0.5f); + } + if (color3 != 0) { + color = ColorUtils.blendARGB(color, color3, 0.5f); + } + if (color4 != 0) { + color = ColorUtils.blendARGB(color, color4, 0.5f); + } + return color; + } + } + + private class GradientSelectorView extends View { + + BackgroundGradient backgroundGradient; + + AnimatedFloat progressToSelect = new AnimatedFloat(400, AndroidUtilities.overshootInterpolator); + boolean selected; + boolean isCustom; + + GradientTools gradientTools = new GradientTools(); + Drawable addIcon; + Paint optionsPaint; + Paint defaultPaint; + + public GradientSelectorView(Context context) { + super(context); + progressToSelect.setParent(this); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(gradientBackgroundItemWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY)); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + progressToSelect.set(selected ? 1f : 0, false); + float cx = getMeasuredWidth() / 2f; + float cy = getMeasuredHeight() / 2f; + + Paint paint; + if (backgroundGradient != null) { + gradientTools.setColors(backgroundGradient.color1, backgroundGradient.color2, backgroundGradient.color3, backgroundGradient.color4); + gradientTools.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + paint = gradientTools.paint; + } else { + if (defaultPaint == null) { + defaultPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + defaultPaint.setColor(Theme.getColor(Theme.key_chat_emojiPanelBackground)); + } + paint = defaultPaint; + } + if (progressToSelect.get() == 0) { + canvas.drawCircle(cx, cy, AndroidUtilities.dp(15), paint); + } else { + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(AndroidUtilities.dp(2)); + canvas.drawCircle(cx, cy, AndroidUtilities.dpf2(13.5f), paint); + paint.setStyle(Paint.Style.FILL); + canvas.drawCircle(cx, cy, AndroidUtilities.dp(10) + AndroidUtilities.dp(5) * (1f - progressToSelect.get()), paint); + } + + if (isCustom) { + if (backgroundGradient == null) { + if (addIcon == null) { + addIcon = ContextCompat.getDrawable(getContext(), R.drawable.msg_filled_plus); + addIcon.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_emojiSearchIcon), PorterDuff.Mode.MULTIPLY)); + } + addIcon.setBounds((int) (cx - addIcon.getIntrinsicWidth() / 2f), (int) (cy - addIcon.getIntrinsicHeight() / 2f), + (int) (cx + addIcon.getIntrinsicWidth() / 2f), (int) (cy + addIcon.getIntrinsicHeight() / 2f)); + addIcon.draw(canvas); + } else { + if (optionsPaint == null) { + optionsPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + optionsPaint.setColor(0xffffffff); + } + optionsPaint.setAlpha(Math.round(255f * Utilities.clamp(progressToSelect.get(), 1f, 0f))); + canvas.drawCircle(cx, cy, AndroidUtilities.dp(1.5f), optionsPaint); + canvas.drawCircle(cx - AndroidUtilities.dp(5) * progressToSelect.get(), cy, AndroidUtilities.dp(1.5f), optionsPaint); + canvas.drawCircle(cx + AndroidUtilities.dp(5) * progressToSelect.get(), cy, AndroidUtilities.dp(1.5f), optionsPaint); + + } + } + } + + void setGradient(BackgroundGradient backgroundGradient) { + this.backgroundGradient = backgroundGradient; + } + + void setSelectedInternal(boolean selected, boolean animated) { + if (this.selected != selected) { + this.selected = selected; + invalidate(); + } + if (!animated) { + progressToSelect.set(selected ? 1f : 0, false); + } + } + + public void setCustom(boolean b) { + isCustom = b; + } + } + + boolean isLightInternal = false; + float progressToLightStatusBar = 0f; + ValueAnimator lightProgressAnimator; + + @Override + public boolean isLightStatusBar() { + boolean isLight; + if (previewView != null && (previewView.expanded || previewView.overrideExpandProgress >= 0 && previewView.backgroundGradient != null)) { + int averageColor = previewView.backgroundGradient.getAverageColor(); + isLight = AndroidUtilities.computePerceivedBrightness(averageColor) > 0.721f; + } else { + isLight = AndroidUtilities.computePerceivedBrightness(Theme.getColor(Theme.key_windowBackgroundGray)) > 0.721f; + } + if (isLightInternal != isLight) { + isLightInternal = isLight; + if (actionBar.getAlpha() == 0) { + setProgressToLightStatusBar(isLight ? 0f : 1f); + } else { + if (lightProgressAnimator != null) { + lightProgressAnimator.removeAllListeners(); + lightProgressAnimator.cancel(); + } + lightProgressAnimator = ValueAnimator.ofFloat(progressToLightStatusBar, isLight ? 0f : 1f); + lightProgressAnimator.addUpdateListener(animation -> { + setProgressToLightStatusBar((Float) animation.getAnimatedValue()); + }); + lightProgressAnimator.setDuration(150).start(); + } + } + if (bottomSheet != null) { + AndroidUtilities.setLightStatusBar(bottomSheet.getWindow(), isLight); + } + return isLight; + } + + private void setProgressToLightStatusBar(float value) { + if (progressToLightStatusBar != value) { + progressToLightStatusBar = value; + int color = ColorUtils.blendARGB(Color.BLACK, Color.WHITE, progressToLightStatusBar); + int selectorColor = ColorUtils.setAlphaComponent(color, 60); + overlayActionBar.setItemsColor(color, false); + setPhotoItem.setBackground(Theme.createSelectorDrawable(selectorColor, Theme.RIPPLE_MASK_CIRCLE_TO_BOUND_EDGE)); + } + } + + public void setDelegate(Delegate delegate) { + this.delegate = delegate; + } + + public void onPreviewClick() { + if (isLandscapeMode) { + return; + } + if (keyboardVisibleProgress > 0) { + if (keyboardVisibilityAnimator != null) { + progressToExpand = 1f; + expandWithKeyboard = true; + } + AndroidUtilities.hideKeyboard(fragmentView); + return; + } + setExpanded(!previewView.expanded, true, false); + } + + private class ContainerLayout extends SizeNotifierFrameLayout implements NestedScrollingParent { + + private NestedScrollingParentHelper nestedScrollingParentHelper; + + public ContainerLayout(Context context) { + super(context); + nestedScrollingParentHelper = new NestedScrollingParentHelper(this); + } + + @Override + public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { + if (keyboardVisibleProgress > 0 || isLandscapeMode) { + return false; + } + return true; + } + + @Override + public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) { + nestedScrollingParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes); + cancelExpandAnimator(); + } + + @Override + public void onStopNestedScroll(View target) { + nestedScrollingParentHelper.onStopNestedScroll(target); + setExpanded(progressToExpand > 0.5f, false, false); + } + + @Override + public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { + if (keyboardVisibleProgress > 0 || isLandscapeMode) { + return; + } + if (dyUnconsumed != 0) { + cancelExpandAnimator(); + float progressToExpand = AvatarConstructorFragment.this.progressToExpand - dyUnconsumed / (float) expandedHeight; + progressToExpand = Utilities.clamp(progressToExpand, 1f, 0f); + setProgressToExpand(progressToExpand, true); + } + } + + @Override + public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { + if (keyboardVisibleProgress > 0 || isLandscapeMode) { + return; + } + if (dy > 0 && AvatarConstructorFragment.this.progressToExpand > 0) { + cancelExpandAnimator(); + float progressToExpand = AvatarConstructorFragment.this.progressToExpand - dy / (float) expandedHeight; + progressToExpand = Utilities.clamp(progressToExpand, 1f, 0f); + setProgressToExpand(progressToExpand, true); + consumed[1] = dy; + } + } + + @Override + public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) { + return false; + } + + @Override + public boolean onNestedPreFling(View target, float velocityX, float velocityY) { + return false; + } + + @Override + public int getNestedScrollAxes() { + return nestedScrollingParentHelper.getNestedScrollAxes(); + } + } + + @Override + public boolean isSwipeBackEnabled(MotionEvent event) { + return false; + } + + @Override + public boolean onBackPressed() { + discardEditor(); + return false; + } + + public interface Delegate { + void onDone(BackgroundGradient backgroundGradient, long documentId, TLRPC.Document document, PreviewView previewView); + } + + @Override + public void onResume() { + super.onResume(); + AndroidUtilities.requestAdjustResize(getParentActivity(), getClassGuid()); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorPreviewCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorPreviewCell.java new file mode 100644 index 000000000..c7ac86256 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorPreviewCell.java @@ -0,0 +1,217 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; + +import java.util.ArrayList; + +public class AvatarConstructorPreviewCell extends FrameLayout { + + private AnimatedEmojiDrawable animatedEmojiDrawable; + BackupImageView currentImage; + BackupImageView nextImage; + + Drawable currentBackgroundDrawable; + Drawable nextBackgroundDrawable; + TextView textView; + + TLRPC.TL_emojiList emojiList; + + public final boolean forUser; + private final int currentAccount = UserConfig.selectedAccount; + + int backgroundIndex = 0; + int emojiIndex = 0; + + float progressToNext = 1f; + + Runnable scheduleSwitchToNextRunnable = new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(scheduleSwitchToNextRunnable, 1000); + if (emojiList == null || emojiList.document_id.isEmpty() || progressToNext != 1f) { + + return; + } + emojiIndex++; + backgroundIndex++; + + if (emojiIndex > emojiList.document_id.size() - 1) { + emojiIndex = 0; + } + if (backgroundIndex > Theme.keys_avatar_background.length - 1) { + backgroundIndex = 0; + } + animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_LARGE, currentAccount, emojiList.document_id.get(emojiIndex)); + nextImage.setAnimatedEmojiDrawable(animatedEmojiDrawable); + + + int color1 = Theme.getColor(Theme.keys_avatar_background[backgroundIndex]); + int color2 = Theme.getColor(Theme.keys_avatar_background2[backgroundIndex]); + + nextBackgroundDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{color1, color2}); + + progressToNext = 0f; + invalidate(); + } + }; + + public AvatarConstructorPreviewCell(Context context, boolean forUser) { + super(context); + this.forUser = forUser; + if (forUser) { + emojiList = MediaDataController.getInstance(currentAccount).profileAvatarConstructorDefault; + } else { + emojiList = MediaDataController.getInstance(currentAccount).groupAvatarConstructorDefault; + } + + if (emojiList == null || emojiList.document_id.isEmpty()) { + ArrayList installedEmojipacks = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); + emojiList = new TLRPC.TL_emojiList(); + if (installedEmojipacks.isEmpty()) { + ArrayList featured = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + for (int i = 0; i < featured.size(); i++) { + TLRPC.StickerSetCovered set = featured.get(i); + if (set.cover != null) { + emojiList.document_id.add(set.cover.id); + } else if (set instanceof TLRPC.TL_stickerSetFullCovered) { + TLRPC.TL_stickerSetFullCovered setFullCovered = ((TLRPC.TL_stickerSetFullCovered) set); + if (!setFullCovered.documents.isEmpty()) { + emojiList.document_id.add(setFullCovered.documents.get(0).id); + } + } + } + } else { + for (int i = 0; i < installedEmojipacks.size(); i++) { + TLRPC.TL_messages_stickerSet set = installedEmojipacks.get(i); + if (!set.documents.isEmpty()) { + int index = Math.abs(Utilities.fastRandom.nextInt() % set.documents.size()); + emojiList.document_id.add(set.documents.get(index).id); + } + } + } + + } + currentImage = new BackupImageView(context); + nextImage = new BackupImageView(context); + addView(currentImage, LayoutHelper.createFrame(50, 50, Gravity.CENTER_HORIZONTAL)); + addView(nextImage, LayoutHelper.createFrame(50, 50, Gravity.CENTER_HORIZONTAL)); + + if (emojiList != null && !emojiList.document_id.isEmpty()) { + animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_LARGE, currentAccount, emojiList.document_id.get(0)); + currentImage.setAnimatedEmojiDrawable(animatedEmojiDrawable); + } + int color1 = Theme.getColor(Theme.keys_avatar_background[backgroundIndex]); + int color2 = Theme.getColor(Theme.keys_avatar_background2[backgroundIndex]); + + currentBackgroundDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{color1, color2}); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + textView.setTextColor(Theme.getColor(Theme.key_avatar_text)); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setGravity(Gravity.CENTER); + textView.setText(LocaleController.getString("UseEmoji", R.string.UseEmoji)); + + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 28, Gravity.BOTTOM, 10, 10, 10, 10)); + + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int availableHeight = textView.getTop(); + int imageHeight = (int) (availableHeight * 0.7f); + int padding = (int) ((availableHeight - imageHeight) * 0.7f); + + currentImage.getLayoutParams().width = currentImage.getLayoutParams().height = imageHeight; + nextImage.getLayoutParams().width = nextImage.getLayoutParams().height = imageHeight; + ((LayoutParams) currentImage.getLayoutParams()).topMargin = padding; + ((LayoutParams) nextImage.getLayoutParams()).topMargin = padding; + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (currentBackgroundDrawable != null) { + currentBackgroundDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + } + if (nextBackgroundDrawable != null) { + nextBackgroundDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + } + if (progressToNext == 1f) { + currentBackgroundDrawable.setAlpha(255); + currentBackgroundDrawable.draw(canvas); + currentImage.setAlpha(1f); + currentImage.setScaleX(1f); + currentImage.setScaleY(1f); + nextImage.setAlpha(0f); + } else { + float progressInternal = CubicBezierInterpolator.DEFAULT.getInterpolation(progressToNext); + + currentBackgroundDrawable.setAlpha(255); + currentBackgroundDrawable.draw(canvas); + nextBackgroundDrawable.setAlpha((int) (255 * progressInternal)); + nextBackgroundDrawable.draw(canvas); + + progressToNext += 16 / 250f; + + currentImage.setAlpha(1f - progressInternal); + currentImage.setScaleX(1f - progressInternal); + currentImage.setScaleY(1f - progressInternal); + currentImage.setPivotY(0); + nextImage.setAlpha(progressInternal); + nextImage.setScaleX(progressInternal); + nextImage.setScaleY(progressInternal); + nextImage.setPivotY(nextImage.getMeasuredHeight()); + if (progressToNext > 1f) { + progressToNext = 1f; + currentBackgroundDrawable = nextBackgroundDrawable; + + BackupImageView tmp = currentImage; + currentImage = nextImage; + nextImage = tmp; + } + invalidate(); + } + super.dispatchDraw(canvas); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + AndroidUtilities.runOnUIThread(scheduleSwitchToNextRunnable, 1000); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + AndroidUtilities.cancelRunOnUIThread(scheduleSwitchToNextRunnable); + } + + public AvatarConstructorFragment.BackgroundGradient getBackgroundGradient() { + AvatarConstructorFragment.BackgroundGradient backgroundGradient = new AvatarConstructorFragment.BackgroundGradient(); + backgroundGradient.color1 = Theme.getColor(Theme.keys_avatar_background[backgroundIndex]); + backgroundGradient.color2 = Theme.getColor(Theme.keys_avatar_background2[backgroundIndex]); + return backgroundGradient; + } + + public AnimatedEmojiDrawable getAnimatedEmoji() { + return animatedEmojiDrawable; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java index fb9176d3f..38f06f499 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java @@ -175,8 +175,12 @@ public class BackupImageView extends View { onNewImageSet(); } - public void setImageMedia(ImageLocation mediaLocation, String mediaFilter, ImageLocation imageLocation, String imageFilter, ImageLocation thumbLocation, String thumbFilter, String ext, int size, int cacheType, Object parentObject) { - imageReceiver.setImage(mediaLocation, mediaFilter, imageLocation, imageFilter, thumbLocation, thumbFilter, null, size, ext, parentObject, cacheType); + public void setImageMedia(VectorAvatarThumbDrawable vectorAvatar, ImageLocation mediaLocation, String mediaFilter, ImageLocation imageLocation, String imageFilter, ImageLocation thumbLocation, String thumbFilter, String ext, int size, int cacheType, Object parentObject) { + if (vectorAvatar != null) { + imageReceiver.setImageBitmap(vectorAvatar); + } else { + imageReceiver.setImage(mediaLocation, mediaFilter, imageLocation, imageFilter, thumbLocation, thumbFilter, null, size, ext, parentObject, cacheType); + } onNewImageSet(); } @@ -316,6 +320,7 @@ public class BackupImageView extends View { if (attached && animatedEmojiDrawable != null) { animatedEmojiDrawable.addView(this); } + invalidate(); } ValueAnimator roundRadiusAnimator; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java index 6a34acdef..b19911ebf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java @@ -120,18 +120,11 @@ public class BotKeyboardView extends LinearLayout { float weight = 1.0f / row.buttons.size(); for (int b = 0; b < row.buttons.size(); b++) { TLRPC.KeyboardButton button = row.buttons.get(b); - TextView textView = new TextView(getContext()); - textView.setTag(button); - textView.setTextColor(getThemedColor(Theme.key_chat_botKeyboardButtonText)); - textView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - textView.setGravity(Gravity.CENTER); + Button textView = new Button(getContext(), button); FrameLayout frame = new FrameLayout(getContext()); frame.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - textView.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); - textView.setText(Emoji.replaceEmoji(button.text, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(16), false)); layout.addView(frame, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, weight, 0, 0, b != row.buttons.size() - 1 ? 10 : 0, 0)); textView.setOnClickListener(v -> delegate.didPressedButton((TLRPC.KeyboardButton) v.getTag())); buttonViews.add(textView); @@ -151,6 +144,20 @@ public class BotKeyboardView extends LinearLayout { } } + private class Button extends TextView { + public Button(Context context, TLRPC.KeyboardButton button) { + super(context); + + setTag(button); + setTextColor(getThemedColor(Theme.key_chat_botKeyboardButtonText)); + setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); + setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + setGravity(Gravity.CENTER); + setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + setText(Emoji.replaceEmoji(button.text, getPaint().getFontMetricsInt(), false)); + } + } + public int getKeyboardHeight() { if (botButtons == null) { return 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java index 778ee314b..b08af4de5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java @@ -7,6 +7,7 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.content.Context; +import android.content.ContextWrapper; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -127,6 +128,8 @@ public class BotWebViewSheet extends Dialog implements NotificationCenter.Notifi private VerticalPositionAutoAnimator mainButtonAutoAnimator, radialProgressAutoAnimator; + private PasscodeView passcodeView; + private Runnable pollRunnable = () -> { if (!dismissed) { TLRPC.TL_messages_prolongWebView prolongWebView = new TLRPC.TL_messages_prolongWebView(); @@ -357,19 +360,21 @@ public class BotWebViewSheet extends Dialog implements NotificationCenter.Notifi protected void onDraw(Canvas canvas) { super.onDraw(canvas); - if (!overrideBackgroundColor) { - backgroundPaint.setColor(getColor(Theme.key_windowBackgroundWhite)); + if (passcodeView.getVisibility() != View.VISIBLE) { + if (!overrideBackgroundColor) { + backgroundPaint.setColor(getColor(Theme.key_windowBackgroundWhite)); + } + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.drawRect(AndroidUtilities.rectTmp, dimPaint); + + actionBarPaint.setColor(ColorUtils.blendARGB(actionBarColor, getColor(Theme.key_windowBackgroundWhite), actionBarTransitionProgress)); + float radius = AndroidUtilities.dp(16) * (AndroidUtilities.isTablet() ? 1f : 1f - actionBarTransitionProgress); + AndroidUtilities.rectTmp.set(swipeContainer.getLeft(), AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress), swipeContainer.getRight(), swipeContainer.getTranslationY() + AndroidUtilities.dp(24) + radius); + canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, actionBarPaint); + + AndroidUtilities.rectTmp.set(swipeContainer.getLeft(), swipeContainer.getTranslationY() + AndroidUtilities.dp(24), swipeContainer.getRight(), getHeight()); + canvas.drawRect(AndroidUtilities.rectTmp, backgroundPaint); } - AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); - canvas.drawRect(AndroidUtilities.rectTmp, dimPaint); - - actionBarPaint.setColor(ColorUtils.blendARGB(actionBarColor, getColor(Theme.key_windowBackgroundWhite), actionBarTransitionProgress)); - float radius = AndroidUtilities.dp(16) * (AndroidUtilities.isTablet() ? 1f : 1f - actionBarTransitionProgress); - AndroidUtilities.rectTmp.set(swipeContainer.getLeft(), AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress), swipeContainer.getRight(), swipeContainer.getTranslationY() + AndroidUtilities.dp(24) + radius); - canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, actionBarPaint); - - AndroidUtilities.rectTmp.set(swipeContainer.getLeft(), swipeContainer.getTranslationY() + AndroidUtilities.dp(24), swipeContainer.getRight(), getHeight()); - canvas.drawRect(AndroidUtilities.rectTmp, backgroundPaint); } @Override @@ -536,9 +541,38 @@ public class BotWebViewSheet extends Dialog implements NotificationCenter.Notifi swipeContainer.setTopActionBarOffsetY(ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight - AndroidUtilities.dp(24)); swipeContainer.setIsKeyboardVisible(obj -> frameLayout.getKeyboardHeight() >= AndroidUtilities.dp(20)); + passcodeView = new PasscodeView(context); + frameLayout.addView(passcodeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + setContentView(frameLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } + @Override + protected void onStart() { + super.onStart(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).addOverlayPasscodeView(passcodeView); + } + } + + @Override + protected void onStop() { + super.onStop(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).removeOverlayPasscodeView(passcodeView); + } + } + public void setParentActivity(Activity parentActivity) { this.parentActivity = parentActivity; } @@ -828,6 +862,12 @@ public class BotWebViewSheet extends Dialog implements NotificationCenter.Notifi @Override public void onBackPressed() { + if (passcodeView.getVisibility() == View.VISIBLE) { + if (getOwnerActivity() != null) { + getOwnerActivity().finish(); + } + return; + } if (webViewContainer.onBackPressed()) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java index df5aae36f..422dbacc4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -41,6 +41,7 @@ import androidx.annotation.CallSuper; import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.core.util.Consumer; import androidx.core.view.ViewCompat; import androidx.dynamicanimation.animation.DynamicAnimation; @@ -209,6 +210,9 @@ public class Bulletin { layout.onAttach(this); containerLayout.addOnLayoutChangeListener(containerLayoutListener = (v, left, top1, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + if (currentDelegate != null && !currentDelegate.allowLayoutChanges()) { + return; + } if (!top) { int newOffset = currentDelegate != null ? currentDelegate.getBottomOffset(tag) : 0; if (lastBottomOffset != newOffset) { @@ -580,6 +584,10 @@ public class Bulletin { default void onHide(Bulletin bulletin) { } + + default boolean allowLayoutChanges() { + return true; + } } //endregion @@ -1264,6 +1272,7 @@ public class Bulletin { } public void setAnimation(TLRPC.Document document, int w, int h, String... layers) { + imageView.setAutoRepeat(true); imageView.setAnimation(document, w, h); for (String layer : layers) { imageView.setLayerColor(layer + ".**", textColor); @@ -1746,6 +1755,7 @@ public class Bulletin { } catch (Exception ignore) {} } + @RequiresApi(api = Build.VERSION_CODES.KITKAT_WATCH) private void applyInsets(WindowInsets insets) { if (container != null) { container.setPadding( 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 b18cd5970..8771b2780 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -154,6 +154,15 @@ public final class BulletinFactory { return create(layout, text.length() < 20 ? Bulletin.DURATION_SHORT : Bulletin.DURATION_LONG); } + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, int maxLines) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + layout.setAnimation(iconRawId, 36, 36); + layout.textView.setText(text); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(maxLines); + return create(layout, text.length() < 20 ? Bulletin.DURATION_SHORT : Bulletin.DURATION_LONG); + } + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, CharSequence subtext) { final Bulletin.TwoLineLottieLayout layout = new Bulletin.TwoLineLottieLayout(getContext(), resourcesProvider); layout.setAnimation(iconRawId, 36, 36); @@ -170,6 +179,7 @@ public final class BulletinFactory { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); layout.setAnimation(iconRawId, 36, 36); layout.textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + layout.textView.setTextDirection(View.TEXT_DIRECTION_LOCALE); layout.textView.setSingleLine(false); layout.textView.setMaxLines(3); layout.textView.setText(text); @@ -291,12 +301,28 @@ public final class BulletinFactory { return createEmojiBulletin(MediaDataController.getInstance(UserConfig.selectedAccount).getEmojiAnimatedSticker(emoji), text, button, onButtonClick); } + public Bulletin createEmojiBulletin(TLRPC.Document document, CharSequence text) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + if (MessageObject.isTextColorEmoji(document)) { + layout.imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_undo_infoColor), PorterDuff.Mode.SRC_IN)); + } + layout.setAnimation(document, 36, 36); + layout.textView.setText(text); + layout.textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(3); + return create(layout, Bulletin.DURATION_LONG); + } + public Bulletin createEmojiBulletin(TLRPC.Document document, CharSequence text, CharSequence button, Runnable onButtonClick) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); if (MessageObject.isTextColorEmoji(document)) { layout.imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_undo_infoColor), PorterDuff.Mode.SRC_IN)); } layout.setAnimation(document, 36, 36); + if (layout.imageView.getImageReceiver() != null) { + layout.imageView.getImageReceiver().setRoundRadius(AndroidUtilities.dp(4)); + } layout.textView.setText(text); layout.textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); layout.textView.setSingleLine(false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java index d1ca26bcd..9b6ed55c3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java @@ -5,7 +5,9 @@ import static org.telegram.messenger.AndroidUtilities.dpf2; import static org.telegram.messenger.AndroidUtilities.lerp; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; @@ -35,11 +37,15 @@ import java.util.Arrays; public class CacheChart extends View { + public static final int TYPE_CACHE = 0; + public static final int TYPE_NETWORK = 1; + + private RectF chartMeasureBounds = new RectF(); private RectF chartBounds = new RectF(); private RectF chartInnerBounds = new RectF(); - private static final int SECTIONS_COUNT = 9; - private static final String[] colorKeys = new String[] { + private static final int DEFAULT_SECTIONS_COUNT = 9; + private static final String[] DEFAULT_COLORS = new String[] { Theme.key_statisticChartLine_lightblue, Theme.key_statisticChartLine_blue, Theme.key_statisticChartLine_green, @@ -51,7 +57,7 @@ public class CacheChart extends View { Theme.key_statisticChartLine_golden }; - private static final int[] particles = new int[] { + private static final int[] DEFAULT_PARTICLES = new int[] { R.raw.cache_photos, R.raw.cache_videos, R.raw.cache_documents, @@ -63,13 +69,19 @@ public class CacheChart extends View { R.raw.cache_other }; + private final int sectionsCount; + private final String[] colorKeys; + private final int type; + private final boolean svgParticles; + private final int[] particles; + private boolean loading = true; public AnimatedFloat loadingFloat = new AnimatedFloat(this, 750, CubicBezierInterpolator.EASE_OUT_QUINT); private boolean complete = false; - private AnimatedFloat completeFloat = new AnimatedFloat(this, 750, CubicBezierInterpolator.EASE_OUT_QUINT); + private AnimatedFloat completeFloat = new AnimatedFloat(this, 650, CubicBezierInterpolator.EASE_OUT_QUINT); - private Sector[] sectors = new Sector[SECTIONS_COUNT]; + private Sector[] sectors; private float[] segmentsTmp = new float[2]; private RectF roundingRect = new RectF(); @@ -79,12 +91,15 @@ public class CacheChart extends View { private Path completePath = new Path(); private Paint completePaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint completePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private LinearGradient completeGradient; - private Matrix completeGradientMatrix; + private LinearGradient completeGradient, completeTextGradient; + private Matrix completeGradientMatrix, completeTextGradientMatrix; private AnimatedTextView.AnimatedTextDrawable topText = new AnimatedTextView.AnimatedTextDrawable(false, true, true); private AnimatedTextView.AnimatedTextDrawable bottomText = new AnimatedTextView.AnimatedTextDrawable(false, true, true); + private AnimatedTextView.AnimatedTextDrawable topCompleteText = new AnimatedTextView.AnimatedTextDrawable(false, true, true); + private AnimatedTextView.AnimatedTextDrawable bottomCompleteText = new AnimatedTextView.AnimatedTextDrawable(false, true, true); + private StarParticlesView.Drawable completeDrawable; private static long particlesStart = -1; @@ -244,6 +259,7 @@ public class CacheChart extends View { float time = (now - particlesStart) / 10000f; if (particle != null) { int sz = particle.getWidth(); + float szs = AndroidUtilities.dpf2(15) / sz; float stepangle = 7f; @@ -272,7 +288,7 @@ public class CacheChart extends View { particleAlpha = Math.max(0, Math.min(1, particleAlpha)); particlePaint.setAlpha((int) (0xFF * particleAlpha)); - float s = (float) (.75f * (.25f * (float) (Math.sin(t * Math.PI) - 1) + 1) * (.8f + (Math.sin(angle) + 1) * .25f)); + float s = szs * (float) (.75f * (.25f * (float) (Math.sin(t * Math.PI) - 1) + 1) * (.8f + (Math.sin(angle) + 1) * .25f)); canvas.save(); canvas.translate(x, y); @@ -336,14 +352,27 @@ public class CacheChart extends View { } public CacheChart(Context context) { + this(context, DEFAULT_SECTIONS_COUNT, DEFAULT_COLORS, TYPE_CACHE, DEFAULT_PARTICLES); + } + + public CacheChart(Context context, int count, String[] colorKeys, int type, int[] particles) { super(context); + this.sectionsCount = count; + this.colorKeys = colorKeys; + this.particles = particles; + this.type = type; + this.svgParticles = type == TYPE_CACHE; + this.sectors = new Sector[this.sectionsCount]; + loadingBackgroundPaint.setStyle(Paint.Style.STROKE); loadingBackgroundPaint.setColor(Theme.getColor(Theme.key_listSelector)); completePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); completeGradient = new LinearGradient(0, 0, 0, AndroidUtilities.dp(200), new int[] { 0x006ED556, 0xFF6ED556, 0xFF41BA71, 0x0041BA71 }, new float[] { 0, .07f, .93f, 1 }, Shader.TileMode.CLAMP); + completeTextGradient = new LinearGradient(0, 0, 0, AndroidUtilities.dp(200), new int[] { 0x006ED556, 0xFF6ED556, 0xFF41BA71, 0x0041BA71 }, new float[] { 0, .07f, .93f, 1 }, Shader.TileMode.CLAMP); completeGradientMatrix = new Matrix(); + completeTextGradientMatrix = new Matrix(); completePaintStroke.setShader(completeGradient); completePaint.setShader(completeGradient); completePaintStroke.setStyle(Paint.Style.STROKE); @@ -361,7 +390,19 @@ public class CacheChart extends View { bottomText.setTextSize(AndroidUtilities.dp(12)); bottomText.setGravity(Gravity.CENTER); - for (int i = 0; i < SECTIONS_COUNT; ++i) { + topCompleteText.setAnimationProperties(.2f, 0, 450, CubicBezierInterpolator.EASE_OUT_QUINT); + topCompleteText.getPaint().setShader(completeTextGradient); + topCompleteText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + topCompleteText.setTextSize(AndroidUtilities.dp(32)); + topCompleteText.setGravity(Gravity.CENTER); + + bottomCompleteText.setAnimationProperties(.6f, 0, 450, CubicBezierInterpolator.EASE_OUT_QUINT); + bottomCompleteText.getPaint().setShader(completeTextGradient); + bottomCompleteText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + bottomCompleteText.setTextSize(AndroidUtilities.dp(12)); + bottomCompleteText.setGravity(Gravity.CENTER); + + for (int i = 0; i < sectors.length; ++i) { Sector sector = sectors[i] = new Sector(); final int color2 = Theme.blendOver(Theme.getColor(colorKeys[i]), 0x03000000); final int color1 = Theme.blendOver(Theme.getColor(colorKeys[i]), 0x30ffffff); @@ -369,7 +410,40 @@ public class CacheChart extends View { sector.gradient = new RadialGradient(0, 0, dp(86), new int[]{ color1, color2 }, new float[] { .3f, 1 }, Shader.TileMode.CLAMP); sector.gradient.setLocalMatrix(sector.gradientMatrix = new Matrix()); sector.paint.setShader(sector.gradient); - sector.particle = SvgHelper.getBitmap(particles[i], AndroidUtilities.dp(16), AndroidUtilities.dp(16), 0xffffffff); + } + } + + private boolean interceptTouch = true; + public void setInterceptTouch(boolean value) { + this.interceptTouch = value; + } + + private boolean isAttached; + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + isAttached = true; + for (int i = 0; i < sectors.length; ++i) { + if (sectors[i].particle == null) { + if (svgParticles) { + sectors[i].particle = SvgHelper.getBitmap(particles[i], AndroidUtilities.dp(16), AndroidUtilities.dp(16), 0xffffffff); + } else { + sectors[i].particle = BitmapFactory.decodeResource(getContext().getResources(), particles[i]); + } + } + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + isAttached = false; + for (int i = 0; i < sectors.length; ++i) { + if (sectors[i].particle != null) { + sectors[i].particle.recycle(); + sectors[i].particle = null; + } } } @@ -399,7 +473,7 @@ public class CacheChart extends View { setSelected(index); if (index >= 0) { onSectionDown(index, index != -1); - if (getParent() != null) { + if (getParent() != null && interceptTouch) { getParent().requestDisallowInterceptTouchEvent(true); } } @@ -459,8 +533,12 @@ public class CacheChart extends View { public static class SegmentSize { int index; - boolean selected; - long size; + public boolean selected; + public long size; + + public static SegmentSize of(long size) { + return of(size, true); + } public static SegmentSize of(long size, boolean selected) { SegmentSize segment = new SegmentSize(); @@ -470,20 +548,35 @@ public class CacheChart extends View { } } - public void setSegments(long totalSize, SegmentSize ...segments) { + public void setSegments(long totalSize, boolean animated, SegmentSize ...segments) { if (segments == null || segments.length == 0) { - loading = true; + loading = false; complete = totalSize == 0; - topText.setText(""); - bottomText.setText(""); + if (!animated) { + loadingFloat.set(loading ? 1 : 0, true); + completeFloat.set(complete ? 1 : 0, true); + } + topCompleteText.setText(topText.getText(), false); + topText.setText("0", animated); + topCompleteText.setText("0", animated); + + bottomCompleteText.setText(bottomText.getText(), false); + bottomText.setText("KB", animated); + bottomCompleteText.setText("KB", animated); for (int i = 0; i < sectors.length; ++i) { sectors[i].textAlpha = 0; + if (!animated) { + sectors[i].textAlphaAnimated.set(0, true); + } } invalidate(); return; } loading = false; + if (!animated) { + loadingFloat.set(0, true); + } SpannableString percent = new SpannableString("%"); // percent.setSpan(new RelativeSizeSpan(0.733f), 0, percent.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -505,12 +598,23 @@ public class CacheChart extends View { } if (segmentsSum <= 0) { - loading = true; + loading = false; complete = totalSize <= 0; - topText.setText(""); - bottomText.setText(""); + if (!animated) { + loadingFloat.set(loading ? 1 : 0, true); + completeFloat.set(complete ? 1 : 0, true); + } + topCompleteText.setText(topText.getText(), false); + topText.setText("0", animated); + topCompleteText.setText("0", animated); + bottomCompleteText.setText(bottomText.getText(), false); + bottomText.setText("KB", animated); + bottomCompleteText.setText("KB", animated); for (int i = 0; i < sectors.length; ++i) { sectors[i].textAlpha = 0; + if (!animated) { + sectors[i].textAlphaAnimated.set(0, true); + } } invalidate(); return; @@ -537,14 +641,16 @@ public class CacheChart extends View { tempFloat[i] = segments[i] == null || !segments[i].selected ? 0 : segments[i].size / (float) segmentsSum; } AndroidUtilities.roundPercents(tempFloat, tempPercents); - Arrays.sort(segments, (a, b) -> Long.compare(a.size, b.size)); - for (int i = 0; i < segments.length - 1; ++i) { - if (segments[i].index == segments.length - 1) { - int from = i, to = 0; - SegmentSize temp = segments[to]; - segments[to] = segments[from]; - segments[from] = temp; - break; + if (type == TYPE_CACHE) { // putting "other" section to being the first one + Arrays.sort(segments, (a, b) -> Long.compare(a.size, b.size)); + for (int i = 0; i < segments.length - 1; ++i) { + if (segments[i].index == segments.length - 1) { + int from = i, to = 0; + SegmentSize temp = segments[to]; + segments[to] = segments[from]; + segments[from] = temp; + break; + } } } @@ -559,8 +665,13 @@ public class CacheChart extends View { sectors[i].textAlpha = progress > .05 && progress < 1 ? 1f : 0f; sectors[i].textScale = progress < .08f || tempPercents[i] >= 100 ? .85f : 1f; sectors[i].particlesAlpha = 1; + if (!animated) { + sectors[i].textAlphaAnimated.set(sectors[i].textAlpha, true); + sectors[i].textScaleAnimated.set(sectors[i].textScale, true); + sectors[i].particlesAlphaAnimated.set(sectors[i].particlesAlpha, true); + } if (sectors[i].textAlpha > 0) { - sectors[i].text.setText(string); + sectors[i].text.setText(string, animated); } if (progress < .02f && progress > 0) { progress = .02f; @@ -573,10 +684,19 @@ public class CacheChart extends View { sectors[i].angleCenter = (angleFrom + angleTo) / 2; sectors[i].angleSize = Math.abs(angleTo - angleFrom) / 2; sectors[i].textAlpha = 0; + if (!animated) { + sectors[i].angleCenterAnimated.set(sectors[i].angleCenter, true); + sectors[i].angleSizeAnimated.set(sectors[i].angleSize, true); + sectors[i].textAlphaAnimated.set(sectors[i].textAlpha, true); + } continue; } sectors[i].angleCenter = (angleFrom + angleTo) / 2; sectors[i].angleSize = Math.abs(angleTo - angleFrom) / 2; + if (!animated) { + sectors[i].angleCenterAnimated.set(sectors[i].angleCenter, true); + sectors[i].angleSizeAnimated.set(sectors[i].angleSize, true); + } prev += progress; k++; } @@ -586,9 +706,17 @@ public class CacheChart extends View { if (top.length() >= 4 && segmentsSum < 1024L * 1024L * 1024L) { top = top.split("\\.")[0]; } - topText.setText(top); - bottomText.setText(fileSize.length > 1 ? fileSize[1] : ""); + topText.setText(top, animated); + bottomText.setText(fileSize.length > 1 ? fileSize[1] : "", animated); + if (completeFloat.get() > 0) { + topCompleteText.setText(topText.getText(), animated); + bottomCompleteText.setText(bottomText.getText(), animated); + } + complete = false; + if (!animated) { + completeFloat.set(complete ? 1 : 0, true); + } invalidate(); } @@ -618,8 +746,12 @@ public class CacheChart extends View { final float loading = loadingFloat.set(this.loading ? 1f : 0f); final float complete = completeFloat.set(this.complete ? 1f : 0f); + chartBounds.set(chartMeasureBounds); + final float minusDp = lerp(0, dpf2(padInsideDp()), complete); + chartBounds.inset(minusDp, minusDp); + chartInnerBounds.set(chartBounds); - final float thickness = lerp(dpf2(38), dpf2(10), loading); + final float thickness = lerp(dpf2(38), dpf2(10), Math.max(loading, complete)); chartInnerBounds.inset(thickness, thickness); final float rounding = lerp(0, dp(60), loading); @@ -647,7 +779,7 @@ public class CacheChart extends View { boolean wouldUpdate = loading > 0 || complete > 0; - for (int i = 0; i < SECTIONS_COUNT; ++i) { + for (int i = 0; i < sectors.length; ++i) { Sector sector = sectors[i]; CircularProgressDrawable.getSegments((loadingTime + i * 80) % 5400, segmentsTmp); @@ -672,30 +804,47 @@ public class CacheChart extends View { sector.draw(canvas, chartBounds, chartInnerBounds, angleCenter, angleSize, rounding, 1f - complete, 1f - loading); } - topText.setAlpha((int) (255 * (1f - loading) * (1f - complete))); - topText.setBounds((int) (chartBounds.centerX()), (int) (chartBounds.centerY() - AndroidUtilities.dp(5)), (int) (chartBounds.centerX()), (int) (chartBounds.centerY() - AndroidUtilities.dp(3))); - topText.draw(canvas); - wouldUpdate = topText.isAnimating() || wouldUpdate; + if (type == TYPE_CACHE) { + float textAlpha = (1f - loading) * (1f - complete); + float topTextX = chartBounds.centerX(); + float topTextY = chartBounds.centerY() - dpf2(5); + wouldUpdate = drawAnimatedText(canvas, topText, topTextX, topTextY, 1f, textAlpha) || wouldUpdate; - bottomText.setAlpha((int) (255 * (1f - loading) * (1f - complete))); - bottomText.setBounds((int) (chartBounds.centerX()), (int) (chartBounds.centerY() + AndroidUtilities.dp(22)), (int) (chartBounds.centerX()), (int) (chartBounds.centerY() + AndroidUtilities.dp(22))); - bottomText.draw(canvas); - wouldUpdate = bottomText.isAnimating() || wouldUpdate; + float bottomTextX = chartBounds.centerX(); + float bottomTextY = chartBounds.centerY() + dpf2(22); + wouldUpdate = drawAnimatedText(canvas, bottomText, bottomTextX, bottomTextY, 1f, textAlpha) || wouldUpdate; + } else if (type == TYPE_NETWORK) { + float textAlpha = 1f - loading; + float topTextX = chartBounds.centerX() - AndroidUtilities.lerp(0, dpf2(4), complete); + float topTextY = chartBounds.centerY() - AndroidUtilities.lerp(dpf2(5), 0, complete); + float topTextScale = AndroidUtilities.lerp(1f, 2.25f, complete); + wouldUpdate = drawAnimatedText(canvas, topCompleteText, topTextX, topTextY, topTextScale, textAlpha * complete) || wouldUpdate; + wouldUpdate = drawAnimatedText(canvas, topText, topTextX, topTextY, topTextScale, textAlpha * (1f - complete)) || wouldUpdate; + + float bottomTextX = chartBounds.centerX() + AndroidUtilities.lerp(0, dpf2(26), complete); + float bottomTextY = chartBounds.centerY() + AndroidUtilities.lerp(dpf2(22), -dpf2(18), complete); + float bottomTextScale = AndroidUtilities.lerp(1f, 1.4f, complete); + wouldUpdate = drawAnimatedText(canvas, bottomCompleteText, bottomTextX, bottomTextY, bottomTextScale, textAlpha * complete) || wouldUpdate; + wouldUpdate = drawAnimatedText(canvas, bottomText, bottomTextX, bottomTextY, bottomTextScale, textAlpha * (1f - complete)) || wouldUpdate; + } if (complete > 0) { + boolean init = false; if (completeDrawable == null) { completeDrawable = new StarParticlesView.Drawable(25); completeDrawable.type = 100; - completeDrawable.roundEffect = false; + completeDrawable.roundEffect = true; completeDrawable.useRotate = true; completeDrawable.useBlur = false; completeDrawable.checkBounds = true; completeDrawable.size1 = 18; completeDrawable.distributionAlgorithm = false; completeDrawable.excludeRadius = AndroidUtilities.dp(80); - completeDrawable.k1 = completeDrawable.k2 = completeDrawable.k3 = 0.7f; + completeDrawable.k1 = completeDrawable.k2 = completeDrawable.k3 = .85f; completeDrawable.init(); - + init = true; + } + if (init || completePathBounds == null || !completePathBounds.equals(chartMeasureBounds)) { float d = Math.min(getMeasuredHeight(), Math.min(getMeasuredWidth(), AndroidUtilities.dp(150))); completeDrawable.rect.set(0, 0, d, d); completeDrawable.rect.offset((getMeasuredWidth() - completeDrawable.rect.width()) / 2, (getMeasuredHeight() - completeDrawable.rect.height()) / 2); @@ -713,36 +862,71 @@ public class CacheChart extends View { completePaintStroke.setAlpha((int) (0xFF * complete)); canvas.drawCircle(chartBounds.centerX(), chartBounds.centerY(), (chartBounds.width() - thickness) / 2, completePaintStroke); - if (completePathBounds == null || completePathBounds.equals(chartBounds)) { + if (completePathBounds == null || !completePathBounds.equals(chartMeasureBounds)) { if (completePathBounds == null) { completePathBounds = new RectF(); } - completePathBounds.set(chartBounds); + completePathBounds.set(chartMeasureBounds); completePath.rewind(); - completePath.moveTo(chartBounds.left + chartBounds.width() * .348f, chartBounds.top + chartBounds.height() * .538f); - completePath.lineTo(chartBounds.left + chartBounds.width() * .447f, chartBounds.top + chartBounds.height() * .636f); - completePath.lineTo(chartBounds.left + chartBounds.width() * .678f, chartBounds.top + chartBounds.height() * .402f); + if (type == TYPE_CACHE) { + completePath.moveTo(chartBounds.width() * .348f, chartBounds.height() * .538f); + completePath.lineTo(chartBounds.width() * .447f, chartBounds.height() * .636f); + completePath.lineTo(chartBounds.width() * .678f, chartBounds.height() * .402f); + } else if (type == TYPE_NETWORK) { + completePath.moveTo(chartBounds.width() * .2929f, chartBounds.height() * .4369f); + completePath.lineTo(chartBounds.width() * .381f, chartBounds.height() * .35f); + completePath.lineTo(chartBounds.width() * .4691f, chartBounds.height() * .4369f); + completePath.moveTo(chartBounds.width() * .381f, chartBounds.height() * .35f); + completePath.lineTo(chartBounds.width() * .381f, chartBounds.height() * .6548f); + + completePath.moveTo(chartBounds.width() * .5214f, chartBounds.height() * .5821f); + completePath.lineTo(chartBounds.width() * .6095f, chartBounds.height() * .669f); + completePath.lineTo(chartBounds.width() * .6976f, chartBounds.height() * .5821f); + completePath.moveTo(chartBounds.width() * .6095f, chartBounds.height() * .669f); + completePath.lineTo(chartBounds.width() * .6095f, chartBounds.height() * .3643f); + } + completePath.offset(chartBounds.left, chartBounds.top); + } + if (type == TYPE_CACHE) { + completePaintStroke.setStrokeWidth(dpf2(10)); + canvas.drawPath(completePath, completePaintStroke); } - completePaintStroke.setStrokeWidth(AndroidUtilities.dp(10)); - canvas.drawPath(completePath, completePaintStroke); } - if (wouldUpdate || true) { + if ((wouldUpdate || true) && isAttached) { invalidate(); } } + private boolean drawAnimatedText(Canvas canvas, AnimatedTextView.AnimatedTextDrawable textDrawable, float x, float y, float scale, float alpha) { + if (alpha <= 0) { + return false; + } + textDrawable.setAlpha((int) (0xFF * alpha)); + textDrawable.setBounds(0, 0, 0, 0); + canvas.save(); + canvas.translate(x, y); + canvas.scale(scale, scale); + textDrawable.draw(canvas); + canvas.restore(); + return textDrawable.isAnimating(); + } + protected int heightDp() { return 200; } + protected int padInsideDp() { + return 0; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int width = MeasureSpec.getSize(widthMeasureSpec); final int height = dp(heightDp()); final int d = dp(172); - chartBounds.set( + chartMeasureBounds.set( (width - d) / 2f, (height - d) / 2f, (width + d) / 2f, @@ -750,8 +934,11 @@ public class CacheChart extends View { ); completeGradientMatrix.reset(); - completeGradientMatrix.setTranslate(chartBounds.left, 0); + completeGradientMatrix.setTranslate(chartMeasureBounds.left, 0); completeGradient.setLocalMatrix(completeGradientMatrix); + completeTextGradientMatrix.reset(); + completeTextGradientMatrix.setTranslate(chartMeasureBounds.left, -chartMeasureBounds.centerY()); + completeTextGradient.setLocalMatrix(completeTextGradientMatrix); if (completeDrawable != null) { completeDrawable.rect.set(0, 0, AndroidUtilities.dp(140), AndroidUtilities.dp(140)); @@ -765,4 +952,10 @@ public class CacheChart extends View { MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) ); } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + requestLayout(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java index 97303f65a..818635b1d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java @@ -260,4 +260,9 @@ public class CanvasButton { } } + + public void setRect(int x, int y, int x1, int y1) { + AndroidUtilities.rectTmp.set(x, y, x1, y1); + setRect(AndroidUtilities.rectTmp); + } } 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 ebd0c99a3..96e8f52d4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -114,6 +114,7 @@ import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; @@ -127,6 +128,7 @@ import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.browser.Browser; import org.telegram.messenger.camera.CameraController; import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; @@ -159,6 +161,9 @@ import java.util.Locale; public class ChatActivityEnterView extends BlurredFrameLayout implements NotificationCenter.NotificationCenterDelegate, SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate, StickersAlert.StickersAlertDelegate { + private final int commonInputType; + private boolean stickersEnabled; + public interface ChatActivityEnterViewDelegate { default void onEditTextScroll() {}; @@ -312,6 +317,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private float searchToOpenProgress; private float chatSearchExpandOffset; + private boolean sendRoundEnabled = true; + private boolean sendVoiceEnabled = true; + private boolean sendPlainEnabled = true; + private boolean emojiButtonRestricted; + + private HashMap animationParamsX = new HashMap<>(); private class SeekBarWaveformView extends View { @@ -1844,6 +1855,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (adjustPanLayoutHelper != null && adjustPanLayoutHelper.animationInProgress()) { return; } + if (emojiButtonRestricted) { + showRestrictedHint(); + return; + } if (hasBotWebView() && botCommandsMenuIsShowing()) { botWebViewMenuContainer.dismiss(v::callOnClick); return; @@ -1885,6 +1900,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific messageEditText = new EditTextCaption(context, resourcesProvider) { + CanvasButton canvasButton; + @Override protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) { super.onScrollChanged(horiz, vert, oldHoriz, oldVert); @@ -1958,6 +1975,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (stickersDragging || stickersExpansionAnim != null) { return false; } + if (!sendPlainEnabled && !isEditingMessage()) { + if (canvasButton == null) { + canvasButton = new CanvasButton(this); + canvasButton.setDelegate(() -> { + showRestrictedHint(); + }); + } + canvasButton.setRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); + return canvasButton.checkTouchEvent(event); + } if (isPopupShowing() && event.getAction() == MotionEvent.ACTION_DOWN) { if (searchingType != 0) { setSearchingTypeInternal(0, false); @@ -2131,6 +2158,22 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific protected Theme.ResourcesProvider getResourcesProvider() { return resourcesProvider; } + + @Override + public boolean requestFocus(int direction, Rect previouslyFocusedRect) { + if (!sendPlainEnabled && !isEditingMessage()) { + return false; + } + return super.requestFocus(direction, previouslyFocusedRect); + } + + @Override + public void setOffsetY(float offset) { + super.setOffsetY(offset); + if (sizeNotifierLayout.getForeground() != null) { + sizeNotifierLayout.invalidateDrawable(sizeNotifierLayout.getForeground()); + } + } }; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { messageEditText.setFallbackLineSpacing(false); @@ -2145,13 +2188,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific messageEditText.setWindowView(parentActivity.getWindow().getDecorView()); TLRPC.EncryptedChat encryptedChat = parentFragment != null ? parentFragment.getCurrentEncryptedChat() : null; messageEditText.setAllowTextEntitiesIntersection(supportsSendingNewEntities()); - updateFieldHint(false); int flags = EditorInfo.IME_FLAG_NO_EXTRACT_UI; if (encryptedChat != null) { flags |= 0x01000000; //EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING; } messageEditText.setImeOptions(flags); - messageEditText.setInputType(messageEditText.getInputType() | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE); + messageEditText.setInputType(commonInputType = (messageEditText.getInputType() | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)); + updateFieldHint(false); messageEditText.setSingleLine(false); messageEditText.setMaxLines(6); messageEditText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); @@ -2166,6 +2209,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific messageEditText.setCursorColor(getThemedColor(Theme.key_chat_messagePanelCursor)); messageEditText.setHandlesColor(getThemedColor(Theme.key_chat_TextSelectionCursor)); frameLayout.addView(messageEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 52, 0, isChat ? 50 : 2, 0)); + ((LayoutParams) messageEditText.getLayoutParams()).bottomMargin = AndroidUtilities.dp(1.5f); messageEditText.setOnKeyListener(new OnKeyListener() { boolean ctrlPressed = false; @@ -2555,6 +2599,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (botReplyMarkup != null) { if (!isPopupShowing() || currentPopupContentType != POPUP_CONTENT_BOT_KEYBOARD) { showPopup(1, POPUP_CONTENT_BOT_KEYBOARD); + } else if (isPopupShowing() && currentPopupContentType == POPUP_CONTENT_BOT_KEYBOARD) { + showPopup(0, POPUP_CONTENT_BOT_KEYBOARD); } } else if (hasBotCommands) { setFieldText("/"); @@ -3107,7 +3153,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (parentFragment != null) { TLRPC.Chat chat = parentFragment.getCurrentChat(); TLRPC.UserFull userFull = parentFragment.getCurrentUserInfo(); - if (chat != null && !ChatObject.canSendMedia(chat) || userFull != null && userFull.voice_messages_forbidden) { + if (chat != null && !(ChatObject.canSendVoice(chat) || (ChatObject.canSendRoundVideo(chat) && hasRecordVideo)) || userFull != null && userFull.voice_messages_forbidden) { delegate.needShowMediaBanHint(); return true; } @@ -3161,8 +3207,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else { if (recordAudioVideoRunnableStarted) { AndroidUtilities.cancelRunOnUIThread(recordAudioVideoRunnable); - delegate.onSwitchRecordMode(!isInVideoMode()); - setRecordVideoButtonVisible(!isInVideoMode(), true); + if (sendVoiceEnabled && sendRoundEnabled) { + delegate.onSwitchRecordMode(!isInVideoMode()); + setRecordVideoButtonVisible(!isInVideoMode(), true); + } else { + delegate.needShowMediaBanHint(); + } performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } else if (!hasRecordVideo || calledRecordRunnable) { @@ -3170,6 +3220,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); delegate.needStartRecordVideo(1, true, 0); + } else if (!sendVoiceEnabled) { + delegate.needShowMediaBanHint(); } else { if (recordingAudioVideo && isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), (notify, scheduleDate) -> MediaController.getInstance().stopRecording(1, notify, scheduleDate), () -> MediaController.getInstance().stopRecording(0, false, 0), resourcesProvider); @@ -3515,6 +3567,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific frameLayout.addView(botWebViewButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); } + private void showRestrictedHint() { + 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(); + } + } + private void openWebViewMenu() { Runnable onRequestWebView = () -> { AndroidUtilities.hideKeyboard(this); @@ -4291,14 +4350,44 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } TLRPC.Chat chat = parentFragment.getCurrentChat(); TLRPC.UserFull userFull = parentFragment.getCurrentUserInfo(); + emojiButtonRestricted = false; + stickersEnabled = true; + sendPlainEnabled = true; + sendRoundEnabled = true; + sendVoiceEnabled = true; if (chat != null) { - audioVideoButtonContainer.setAlpha(ChatObject.canSendMedia(chat) ? 1.0f : 0.5f); - if (emojiView != null) { - emojiView.setStickersBanned(!ChatObject.canSendStickers(chat), chat.id); + audioVideoButtonContainer.setAlpha(ChatObject.canSendVoice(chat) || (ChatObject.canSendRoundVideo(chat) && hasRecordVideo)? 1.0f : 0.5f); + + stickersEnabled = ChatObject.canSendStickers(chat); + sendPlainEnabled = ChatObject.canSendPlain(chat); + sendPlainEnabled = ChatObject.canSendPlain(chat); + emojiButtonRestricted = !stickersEnabled && !sendPlainEnabled; + emojiButton.setAlpha(emojiButtonRestricted ? 0.5f : 1.0f); + if (!emojiButtonRestricted) { + if (emojiView != null) { + emojiView.setStickersBanned(!ChatObject.canSendPlain(chat), !ChatObject.canSendStickers(chat), chat.id); + } } + sendRoundEnabled = ChatObject.canSendRoundVideo(chat); + sendVoiceEnabled = ChatObject.canSendVoice(chat); + } else if (userFull != null) { audioVideoButtonContainer.setAlpha(userFull.voice_messages_forbidden ? 0.5f : 1.0f); } + updateFieldHint(false); + + boolean currentModeVideo = isInVideoMode; + if (!sendRoundEnabled && currentModeVideo) { + currentModeVideo = false; + } + if (!sendVoiceEnabled && !currentModeVideo) { + if (hasRecordVideo) { + currentModeVideo = true; + } else { + currentModeVideo = false; + } + } + setRecordVideoButtonVisible(currentModeVideo, false); } public void onBeginHide() { @@ -4400,8 +4489,15 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.sendingMessagesChanged); } + sendPlainEnabled = true; + if (DialogObject.isChatDialog(dialog_id)) { + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); + sendPlainEnabled = ChatObject.canSendPlain(chat); + } + updateScheduleButton(false); checkRoundVideo(); + checkChannelRights(); updateFieldHint(false); updateSendAsButton(parentFragment != null && parentFragment.getFragmentBeginToShow()); } @@ -4424,6 +4520,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return; } hasRecordVideo = true; + sendRoundEnabled = true; + sendVoiceEnabled = true; boolean isChannel = false; if (DialogObject.isChatDialog(dialog_id)) { TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); @@ -4431,20 +4529,32 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (isChannel && !chat.creator && (chat.admin_rights == null || !chat.admin_rights.post_messages)) { hasRecordVideo = false; } + sendRoundEnabled = ChatObject.canSendRoundVideo(chat); + sendVoiceEnabled = ChatObject.canSendVoice(chat); } if (!SharedConfig.inappCamera) { hasRecordVideo = false; } + boolean currentModeVideo = false; if (hasRecordVideo) { if (SharedConfig.hasCameraCache) { CameraController.getInstance().initCamera(null); } SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - boolean currentModeVideo = preferences.getBoolean(isChannel ? "currentModeVideoChannel" : "currentModeVideo", isChannel); - setRecordVideoButtonVisible(currentModeVideo, false); - } else { - setRecordVideoButtonVisible(false, false); + currentModeVideo = preferences.getBoolean(isChannel ? "currentModeVideoChannel" : "currentModeVideo", isChannel); } + + if (!sendRoundEnabled && currentModeVideo) { + currentModeVideo = false; + } + if (!sendVoiceEnabled && !currentModeVideo) { + if (hasRecordVideo) { + currentModeVideo = true; + } else { + currentModeVideo = false; + } + } + setRecordVideoButtonVisible(currentModeVideo, false); } public boolean isInVideoMode() { @@ -4460,6 +4570,18 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } public void updateFieldHint(boolean animated) { + if (!sendPlainEnabled && !isEditingMessage()) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(" d " + LocaleController.getString("PlainTextRestrictedHint", R.string.PlainTextRestrictedHint)); + spannableStringBuilder.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock3), 1, 2, 0); + messageEditText.setHintText(spannableStringBuilder, animated); + messageEditText.setText(null); + messageEditText.setEnabled(false); + messageEditText.setInputType(EditorInfo.IME_ACTION_NONE); + return; + } else { + messageEditText.setEnabled(true); + messageEditText.setInputType(commonInputType); + } if (replyingMessageObject != null && replyingMessageObject.messageOwner.reply_markup != null && !TextUtils.isEmpty(replyingMessageObject.messageOwner.reply_markup.placeholder)) { messageEditText.setHintText(replyingMessageObject.messageOwner.reply_markup.placeholder, animated); } else if (editingMessageObject != null) { @@ -4551,7 +4673,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordPannelAnimation = new AnimatorSet(); recordPannelAnimation.playTogether( - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1.0f), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1.0f), ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1.0f), ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 0.0f), @@ -4642,7 +4764,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_Y, 0.0f), ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1.0f), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1.0f), ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1.0f) ); @@ -4793,9 +4915,6 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (message == null || parentFragment == null) { return false; } - if (container == null) { - container = parentFragment.getLayoutContainer(); - } final boolean isPremium = UserConfig.getInstance(currentAccount).isPremium(); if (!isPremium && UserConfig.getInstance(currentAccount).getClientUserId() != dialogId && message instanceof Spanned) { AnimatedEmojiSpan[] animatedEmojis = ((Spanned) message).getSpans(0, message.length(), AnimatedEmojiSpan.class); @@ -4806,20 +4925,75 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (emoji == null) { emoji = AnimatedEmojiDrawable.findDocument(currentAccount, animatedEmojis[i].getDocumentId()); } - if (emoji != null && !MessageObject.isFreeEmoji(emoji)) { - BulletinFactory.of(container, parentFragment.getResourceProvider()) - .createEmojiBulletin( - emoji, - AndroidUtilities.replaceTags(LocaleController.getString("UnlockPremiumEmojiHint", R.string.UnlockPremiumEmojiHint)), - LocaleController.getString("PremiumMore", R.string.PremiumMore), - () -> { - if (parentFragment != null) { - new PremiumFeatureBottomSheet(parentFragment, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI, false).show(); - } else if (parentFragment.getContext() instanceof LaunchActivity) { - ((LaunchActivity) parentFragment.getContext()).presentFragment(new PremiumPreviewFragment(null)); - } - } - ).show(); + long documentId = animatedEmojis[i].getDocumentId(); + if (emoji == null) { + ArrayList sets1 = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); + for (TLRPC.TL_messages_stickerSet set : sets1) { + if (set != null && set.documents != null && !set.documents.isEmpty()) { + for (TLRPC.Document document : set.documents) { + if (document.id == documentId) { + emoji = document; + break; + } + } + } + if (emoji != null) { + break; + } + } + } + if (emoji == null) { + ArrayList sets2 = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + for (TLRPC.StickerSetCovered set : sets2) { + if (set != null && set.covers != null && !set.covers.isEmpty()) { + for (TLRPC.Document document : set.covers) { + if (document.id == documentId) { + emoji = document; + break; + } + } + } + if (emoji != null) { + break; + } + ArrayList documents = null; + if (set instanceof TLRPC.TL_stickerSetFullCovered) { + documents = ((TLRPC.TL_stickerSetFullCovered) set).documents; + } else if (set instanceof TLRPC.TL_stickerSetNoCovered && set.set != null) { + TLRPC.TL_inputStickerSetID inputStickerSetID = new TLRPC.TL_inputStickerSetID(); + inputStickerSetID.id = set.set.id; + TLRPC.TL_messages_stickerSet fullSet = MediaDataController.getInstance(currentAccount).getStickerSet(inputStickerSetID, true); + if (fullSet != null && fullSet.documents != null) { + documents = fullSet.documents; + } + } + if (documents != null && !documents.isEmpty()) { + for (TLRPC.Document document : documents) { + if (document.id == documentId) { + emoji = document; + break; + } + } + } + if (emoji != null) { + break; + } + } + } + if (emoji == null || !MessageObject.isFreeEmoji(emoji)) { + BulletinFactory.of(parentFragment) + .createEmojiBulletin( + emoji, + AndroidUtilities.replaceTags(LocaleController.getString("UnlockPremiumEmojiHint", R.string.UnlockPremiumEmojiHint)), + LocaleController.getString("PremiumMore", R.string.PremiumMore), + () -> { + if (parentFragment != null) { + new PremiumFeatureBottomSheet(parentFragment, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI, false).show(); + } else if (parentFragment.getContext() instanceof LaunchActivity) { + ((LaunchActivity) parentFragment.getContext()).presentFragment(new PremiumPreviewFragment(null)); + } + } + ).show(); return true; } } @@ -5564,7 +5738,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific TLRPC.Chat chat = parentFragment.getCurrentChat(); TLRPC.UserFull userFull = parentFragment.getCurrentUserInfo(); if (chat != null) { - alpha = ChatObject.canSendMedia(chat) ? 1.0f : 0.5f; + alpha = (ChatObject.canSendVoice(chat) || ChatObject.canSendRoundVideo(chat)) ? 1.0f : 0.5f; } else if (userFull != null) { alpha = userFull.voice_messages_forbidden ? 0.5f : 1.0f; } @@ -5885,7 +6059,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific runningAnimationAudio.playTogether( ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1), - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0), ObjectAnimator.ofFloat(recordCircle, recordCircleScale, 0.0f), @@ -6096,7 +6270,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific iconsAnimator.playTogether( ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1), - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0) ); @@ -6240,7 +6414,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific iconsAnimator.playTogether( ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1), - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0), ObjectAnimator.ofFloat(audioVideoButtonContainer, View.ALPHA, 1.0f) @@ -6750,7 +6924,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (AndroidUtilities.isTablet()) { if (parentActivity instanceof LaunchActivity) { LaunchActivity launchActivity = (LaunchActivity) parentActivity; - View layout = launchActivity.getLayersActionBarLayout().getView(); + View layout = launchActivity != null && launchActivity.getLayersActionBarLayout() != null ? launchActivity.getLayersActionBarLayout().getView() : null; allowFocus = layout == null || layout.getVisibility() != View.VISIBLE; } else { allowFocus = true; @@ -7239,7 +7413,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 1); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_BOT_SHARE); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { long uid = messageObject.messageOwner.from_id.user_id; @@ -7249,7 +7423,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific TLRPC.User user = accountInstance.getMessagesController().getUser(uid); if (user == null) { fragment1.finishFragment(); - return; + return true; } long did = dids.get(0).dialogId; MediaDataController.getInstance(currentAccount).saveDraft(did, 0, "@" + UserObject.getPublicUsername(user) + " " + button.query, null, null, true); @@ -7262,7 +7436,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific args1.putLong("chat_id", -did); } if (!accountInstance.getMessagesController().checkCanOpenChat(args1, fragment1)) { - return; + return true; } ChatActivity chatActivity = new ChatActivity(args1); if (parentFragment.presentFragment(chatActivity, true)) { @@ -7278,6 +7452,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else { fragment1.finishFragment(); } + return true; }); parentFragment.presentFragment(fragment); } @@ -7288,6 +7463,44 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ProfileActivity fragment = new ProfileActivity(args); parentFragment.presentFragment(fragment); } + } else if (button instanceof TLRPC.TL_keyboardButtonRequestPeer) { + TLRPC.TL_keyboardButtonRequestPeer btn = (TLRPC.TL_keyboardButtonRequestPeer) button; + if (btn.peer_type != null && messageObject != null && messageObject.messageOwner != null) { + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER); + if (messageObject != null && messageObject.messageOwner != null && messageObject.messageOwner.from_id instanceof TLRPC.TL_peerUser) { + args.putLong("requestPeerBotId", messageObject.messageOwner.from_id.user_id); + } + try { + SerializedData buffer = new SerializedData(btn.peer_type.getObjectSize()); + btn.peer_type.serializeToStream(buffer); + args.putByteArray("requestPeerType", buffer.toByteArray()); + buffer.cleanup(); + } catch (Exception e) { + FileLog.e(e); + } + DialogsActivity fragment = new DialogsActivity(args); + fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { + @Override + public boolean didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { + if (dids != null && !dids.isEmpty()) { + TLRPC.TL_messages_sendBotRequestedPeer req = new TLRPC.TL_messages_sendBotRequestedPeer(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(messageObject.messageOwner.peer_id); + req.msg_id = messageObject.getId(); + req.button_id = btn.button_id; + req.requested_peer = MessagesController.getInstance(currentAccount).getInputPeer(dids.get(0).dialogId); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); + } + fragment.finishFragment(); + return true; + } + }); + parentFragment.presentFragment(fragment); + return false; + } else { + FileLog.e("button.peer_type is null"); + } } return true; } @@ -7989,6 +8202,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } ChatActivityEnterViewAnimatedIconView.State nextIcon; if (byOpen && currentPopupContentType == 0) { + if (!sendPlainEnabled) { + return; + } nextIcon = ChatActivityEnterViewAnimatedIconView.State.KEYBOARD; } else { int currentPage; @@ -8009,6 +8225,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } } + if (!sendPlainEnabled && nextIcon == ChatActivityEnterViewAnimatedIconView.State.SMILE) { + nextIcon = ChatActivityEnterViewAnimatedIconView.State.GIF; + } else if (!stickersEnabled && nextIcon != ChatActivityEnterViewAnimatedIconView.State.SMILE) { + nextIcon = ChatActivityEnterViewAnimatedIconView.State.SMILE; + } emojiButton.setState(nextIcon, animated); onEmojiIconChanged(nextIcon); @@ -8802,7 +9023,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return; } paint.setAlpha(Math.round(102 * stickersExpansionProgress)); - canvas.drawRect(0, 0, getWidth(), emojiView.getY() - getHeight() + Theme.chat_composeShadowDrawable.getIntrinsicHeight(), paint); + canvas.drawRect(0, 0, getWidth(), emojiView.getY() - getHeight() + Theme.chat_composeShadowDrawable.getIntrinsicHeight() + messageEditText.getOffsetY(), paint); } @Override 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 47e1f0a83..5d9625b8c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -16,6 +16,7 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; +import android.content.ContextWrapper; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; @@ -98,6 +99,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.BasePermissionsActivity; import org.telegram.ui.ChatActivity; +import org.telegram.ui.LaunchActivity; import org.telegram.ui.PassportActivity; import org.telegram.ui.PaymentFormActivity; import org.telegram.ui.PhotoPickerActivity; @@ -115,6 +117,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public ChatActivity.ThemeDelegate parentThemeDelegate; private final NumberTextView captionLimitView; + public boolean forUser; private int currentLimit; private int codepointCount; @@ -122,6 +125,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private boolean isSoundPicker = false; private ImageUpdater.AvatarFor setAvatarFor; + private PasscodeView passcodeView; + private ChatAttachRestrictedLayout restrictedLayout; + public ImageUpdater parentImageUpdater; + public void setCanOpenPreview(boolean canOpenPreview) { this.canOpenPreview = canOpenPreview; selectedArrowImageView.setVisibility(canOpenPreview && avatarPicker != 2 ? View.VISIBLE : View.GONE); @@ -343,6 +350,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return setAvatarFor; } + public void setImageUpdater(ImageUpdater imageUpdater) { + parentImageUpdater = imageUpdater; + } + public interface ChatAttachViewDelegate { void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument); @@ -512,7 +523,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } - void onInit(boolean mediaEnabled) { + void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { } @@ -678,8 +689,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N protected int currentAccount = UserConfig.selectedAccount; - private boolean mediaEnabled = true; + private boolean documentsEnabled = true; + private boolean photosEnabled = true; + private boolean videosEnabled = true; + private boolean musicEnabled = true; private boolean pollsEnabled = true; + private boolean plainTextEnabled = true; protected int maxSelectedPhotos = -1; protected boolean allowOrder = true; @@ -1093,7 +1108,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private Bulletin.Delegate bulletinDelegate = new Bulletin.Delegate() { @Override public int getBottomOffset(int tag) { - return getHeight() - frameLayout2.getTop(); + return getHeight() - frameLayout2.getTop() + AndroidUtilities.dp(52); } }; private int lastNotifyWidth; @@ -1663,14 +1678,14 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N adjustPanLayoutHelper.setResizableView(this); adjustPanLayoutHelper.onAttach(); commentTextView.setAdjustPanLayoutHelper(adjustPanLayoutHelper); - Bulletin.addDelegate(this, bulletinDelegate); + // Bulletin.addDelegate(this, bulletinDelegate); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); adjustPanLayoutHelper.onDetach(); - Bulletin.removeDelegate(this); + // Bulletin.removeDelegate(this); } }; sizeNotifierFrameLayout.setDelegate(new SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate() { @@ -1955,6 +1970,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (view instanceof AttachButton) { int num = (Integer) view.getTag(); if (num == 1) { + if (!photosEnabled && !videosEnabled) { + showLayout(restrictedLayout = new ChatAttachRestrictedLayout(1, this, getContext(), resourcesProvider)); + } showLayout(photoLayout); } else if (num == 3) { if (Build.VERSION.SDK_INT >= 23 && baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { @@ -1969,7 +1987,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } openDocumentsLayout(true); } else if (num == 5) { - if (Build.VERSION.SDK_INT >= 23) { + if (Build.VERSION.SDK_INT >= 23 && plainTextEnabled) { if (baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { baseFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, BasePermissionsActivity.REQUEST_CODE_ATTACH_CONTACT); return; @@ -1980,17 +1998,27 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (!AndroidUtilities.isMapsInstalled(baseFragment)) { return; } - if (locationLayout == null) { - layouts[5] = locationLayout = new ChatAttachAlertLocationLayout(this, getContext(), resourcesProvider); - locationLayout.setDelegate((location, live, notify, scheduleDate) -> ((ChatActivity) baseFragment).didSelectLocation(location, live, notify, scheduleDate)); + if (!plainTextEnabled) { + restrictedLayout = new ChatAttachRestrictedLayout(6, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } else { + if (locationLayout == null) { + layouts[5] = locationLayout = new ChatAttachAlertLocationLayout(this, getContext(), resourcesProvider); + locationLayout.setDelegate((location, live, notify, scheduleDate) -> ((ChatActivity) baseFragment).didSelectLocation(location, live, notify, scheduleDate)); + } + showLayout(locationLayout); } - showLayout(locationLayout); } else if (num == 9) { - if (pollLayout == null) { - layouts[1] = pollLayout = new ChatAttachAlertPollLayout(this, getContext(), resourcesProvider); - pollLayout.setDelegate((poll, params, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendPoll(poll, params, notify, scheduleDate)); + if (!pollsEnabled) { + restrictedLayout = new ChatAttachRestrictedLayout(9, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } else { + if (pollLayout == null) { + layouts[1] = pollLayout = new ChatAttachAlertPollLayout(this, getContext(), resourcesProvider); + pollLayout.setDelegate((poll, params, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendPoll(poll, params, notify, scheduleDate)); + } + showLayout(pollLayout); } - showLayout(pollLayout); } else { delegate.didPressedButton((Integer) view.getTag(), true, true, 0, false); } @@ -2499,6 +2527,35 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N checkColors(); navBarColorKey = null; } + + passcodeView = new PasscodeView(context); + containerView.addView(passcodeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + @Override + protected void onStart() { + super.onStart(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).addOverlayPasscodeView(passcodeView); + } + } + + @Override + protected void onStop() { + super.onStop(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).removeOverlayPasscodeView(passcodeView); + } } private void showCaptionLimitBulletin(BaseFragment parentFragment) { @@ -2621,7 +2678,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private void showLayout(AttachAlertLayout layout) { long newId = selectedId; - if (layout == photoLayout) { + if (layout == restrictedLayout) { + newId = restrictedLayout.id; + } else if (layout == photoLayout) { newId = 1; } else if (layout == audioLayout) { newId = 3; @@ -2841,6 +2900,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private void openContactsLayout() { + if (!plainTextEnabled) { + restrictedLayout = new ChatAttachRestrictedLayout(5, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } if (contactsLayout == null) { layouts[2] = contactsLayout = new ChatAttachAlertContactsLayout(this, getContext(), resourcesProvider); contactsLayout.setDelegate((user, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendContact(user, notify, scheduleDate)); @@ -2849,6 +2912,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private void openAudioLayout(boolean show) { + if (!musicEnabled) { + if (show) { + restrictedLayout = new ChatAttachRestrictedLayout(3, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } + } if (audioLayout == null) { layouts[3] = audioLayout = new ChatAttachAlertAudioLayout(this, getContext(), resourcesProvider); audioLayout.setDelegate((audios, caption, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendAudio(audios, caption, notify, scheduleDate)); @@ -2864,6 +2933,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private void openDocumentsLayout(boolean show) { + if (!documentsEnabled) { + if (show) { + restrictedLayout = new ChatAttachRestrictedLayout(4, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } + } if (documentLayout == null) { int type = isSoundPicker ? ChatAttachAlertDocumentLayout.TYPE_RINGTONE : ChatAttachAlertDocumentLayout.TYPE_DEFAULT; layouts[4] = documentLayout = new ChatAttachAlertDocumentLayout(this, getContext(), type, resourcesProvider); @@ -3438,8 +3513,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N actionBarAnimation.cancel(); actionBarAnimation = null; } - boolean needsSearchItem = avatarSearch || currentAttachLayout == photoLayout && !menuShowed && baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).allowSendGifs(); - boolean needMoreItem = avatarPicker != 0 || !menuShowed && currentAttachLayout == photoLayout && mediaEnabled; + + boolean needsSearchItem = avatarSearch || currentAttachLayout == photoLayout && !menuShowed && baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).allowSendGifs() && ((ChatActivity) baseFragment).allowSendPhotos(); + boolean needMoreItem = avatarPicker != 0 || !menuShowed && currentAttachLayout == photoLayout && (photosEnabled || videosEnabled); + if (currentAttachLayout == restrictedLayout) { + needsSearchItem = false; + needMoreItem = false; + } if (show) { if (needsSearchItem) { searchItem.setVisibility(View.VISIBLE); @@ -3670,15 +3750,20 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N TLRPC.Chat chat = ((ChatActivity) baseFragment).getCurrentChat(); TLRPC.User user = ((ChatActivity) baseFragment).getCurrentUser(); if (chat != null) { - mediaEnabled = ChatObject.canSendMedia(chat); + // mediaEnabled = ChatObject.canSendMedia(chat); + photosEnabled = ChatObject.canSendPhoto(chat); + videosEnabled = ChatObject.canSendVideo(chat); + musicEnabled = ChatObject.canSendMusic(chat); pollsEnabled = ChatObject.canSendPolls(chat); + plainTextEnabled = ChatObject.canSendPlain(chat); + documentsEnabled = ChatObject.canSendDocument(chat); } else { pollsEnabled = user != null && user.bot; } } else { commentTextView.setVisibility(View.INVISIBLE); } - photoLayout.onInit(mediaEnabled); + photoLayout.onInit(videosEnabled, photosEnabled, documentsEnabled); commentTextView.hidePopup(true); enterCommentEventSent = false; setFocusable(false); @@ -3800,6 +3885,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { typeButtonsAvailable = true; } + if (photoLayout != null) { + photoLayout.updateAvatarPicker(); + } } public TextView getSelectedTextView() { @@ -3956,9 +4044,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N musicButton = buttonsCount++; } } else { - if (mediaEnabled) { - galleryButton = buttonsCount++; - + galleryButton = buttonsCount++; + if (photosEnabled || videosEnabled) { if (baseFragment instanceof ChatActivity && !((ChatActivity) baseFragment).isInScheduleMode() && !((ChatActivity) baseFragment).isSecretChat()) { ChatActivity chatActivity = (ChatActivity) baseFragment; @@ -3973,18 +4060,20 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N buttonsCount += attachMenuBots.size(); attachBotsEndRow = buttonsCount; } - - documentButton = buttonsCount++; } - locationButton = buttonsCount++; + documentButton = buttonsCount++; + + if (plainTextEnabled) { + locationButton = buttonsCount++; + } + if (pollsEnabled) { pollButton = buttonsCount++; - } else { + } else if (plainTextEnabled) { contactButton = buttonsCount++; } - if (mediaEnabled) { - musicButton = buttonsCount++; - } + musicButton = buttonsCount++; + TLRPC.User user = baseFragment instanceof ChatActivity ? ((ChatActivity) baseFragment).getCurrentUser() : null; if (user != null && user.bot) { contactButton = buttonsCount++; @@ -4044,6 +4133,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void onBackPressed() { + if (passcodeView.getVisibility() == View.VISIBLE) { + if (getOwnerActivity() != null) { + getOwnerActivity().finish(); + } + return; + } if (actionBar.isSearchFieldVisible()) { actionBar.closeSearchField(); return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java index 4d1ff0685..de472de14 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java @@ -1800,7 +1800,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa resultArray = new ArrayList<>(); ArrayList resultArrayNames = new ArrayList<>(); ArrayList encUsers = new ArrayList<>(); - accountInstance.getMessagesStorage().localSearch(0, query, resultArray, resultArrayNames, encUsers, -1); + accountInstance.getMessagesStorage().localSearch(0, query, resultArray, resultArrayNames, encUsers, null, -1); } final TLRPC.TL_messages_searchGlobal req = new TLRPC.TL_messages_searchGlobal(); 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 87b3154fe..a248e8320 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -67,6 +67,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; @@ -90,8 +91,10 @@ import org.telegram.ui.Cells.PhotoAttachPhotoCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.PhotoViewer; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -100,6 +103,8 @@ import java.util.Map; public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayout implements NotificationCenter.NotificationCenterDelegate { + private static final int VIEW_TYPE_AVATAR_CONSTRUCTOR = 4; + private RecyclerListView cameraPhotoRecyclerView; private LinearLayoutManager cameraPhotoLayoutManager; private PhotoAttachAdapter cameraAttachAdapter; @@ -164,6 +169,9 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou private boolean checkCameraWhenShown; private boolean mediaEnabled; + private boolean videoEnabled; + private boolean photoEnabled; + private boolean documentsEnabled; private float pinchStartDistance; private float cameraZoom; @@ -210,6 +218,11 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou boolean forceDarkTheme; private int animationIndex = -1; + private boolean showAvatarConstructor; + + public void updateAvatarPicker() { + showAvatarConstructor = parentAlert.avatarPicker != 0; + } private class BasePhotoProvider extends PhotoViewer.EmptyPhotoViewerProvider { @Override @@ -227,6 +240,9 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou if (photoEntry == null) { return -1; } + if (checkSendMediaEnabled(photoEntry)) { + return -1; + } boolean add = true; int num; if ((num = addToSelectedPhotos(photoEntry, -1)) == -1) { @@ -538,6 +554,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.albumsDidLoad); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.cameraInitied); FrameLayout container = alert.getContainer(); + showAvatarConstructor = parentAlert.avatarPicker != 0; cameraDrawable = context.getResources().getDrawable(R.drawable.instant_camera).mutate(); @@ -699,6 +716,173 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou if (selectedAlbumEntry == galleryAlbumEntry) { position--; } + if (showAvatarConstructor) { + if (position == 0) { + if (!(view instanceof AvatarConstructorPreviewCell)) { + return; + } + AvatarConstructorFragment avatarConstructorFragment = new AvatarConstructorFragment(parentAlert.parentImageUpdater, parentAlert.getAvatarFor()); + avatarConstructorFragment.finishOnDone = !(parentAlert.getAvatarFor() != null && parentAlert.getAvatarFor().type == ImageUpdater.TYPE_SUGGEST_PHOTO_FOR_USER); + AvatarConstructorPreviewCell previewCell = (AvatarConstructorPreviewCell) view; + parentAlert.baseFragment.presentFragment(avatarConstructorFragment); + avatarConstructorFragment.startFrom(previewCell); + avatarConstructorFragment.setDelegate((gradient, documentId, document, previewView) -> { + selectedPhotos.clear(); + Bitmap bitmap = Bitmap.createBitmap(800, 800, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + GradientTools gradientTools = new GradientTools(); + gradientTools.setColors(gradient.color1, gradient.color2, gradient.color3, gradient.color4); + gradientTools.setBounds(0, 0, 800, 800); + canvas.drawRect(0, 0, 800, 800, gradientTools.paint); + + File file = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "avatar_background.png"); + try { + file.createNewFile(); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); + byte[] bitmapdata = bos.toByteArray(); + + FileOutputStream fos = new FileOutputStream(file); + fos.write(bitmapdata); + fos.flush(); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + float scale = AvatarConstructorFragment.STICKER_DEFAULT_SCALE; + int imageX, imageY; + imageX = imageY = (int) (800 * (1f - scale) / 2f); + int imageSize = (int) (800 * scale); + + ImageReceiver imageReceiver = previewView.getImageReceiver(); + if (imageReceiver.getAnimation() != null) { + Bitmap firstFrame = imageReceiver.getAnimation().getFirstFrame(null); + ImageReceiver firstFrameReceiver = new ImageReceiver(); + firstFrameReceiver.setImageBitmap(firstFrame); + firstFrameReceiver.setImageCoords(imageX, imageY, imageSize, imageSize); + firstFrameReceiver.setRoundRadius((int) (imageSize * AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS)); + firstFrameReceiver.draw(canvas); + firstFrameReceiver.clearImage(); + firstFrame.recycle(); + } else { + if (imageReceiver.getLottieAnimation() != null) { + imageReceiver.getLottieAnimation().setCurrentFrame(0, false, true); + } + imageReceiver.setImageCoords(imageX, imageY, imageSize, imageSize); + imageReceiver.setRoundRadius((int) (imageSize * AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS)); + imageReceiver.draw(canvas); + } + + File thumb = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "avatar_background.png"); + try { + thumb.createNewFile(); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); + byte[] bitmapdata = bos.toByteArray(); + + FileOutputStream fos = new FileOutputStream(thumb); + fos.write(bitmapdata); + fos.flush(); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + MediaController.PhotoEntry photoEntry; + if (previewView.hasAnimation()) { + photoEntry = new MediaController.PhotoEntry(0, 0, 0, file.getPath(), 0, false, 0, 0, 0); + photoEntry.thumbPath = thumb.getPath(); + + if (previewView.documentId != 0) { + TLRPC.TL_videoSizeEmojiMarkup emojiMarkup = new TLRPC.TL_videoSizeEmojiMarkup(); + emojiMarkup.emoji_id = previewView.documentId; + emojiMarkup.background_colors.add(previewView.backgroundGradient.color1); + if (previewView.backgroundGradient.color2 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color2); + } + if (previewView.backgroundGradient.color3 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color3); + } + if (previewView.backgroundGradient.color4 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color4); + } + photoEntry.emojiMarkup = emojiMarkup; + } else if (previewView.document != null) { + TLRPC.TL_videoSizeStickerMarkup emojiMarkup = new TLRPC.TL_videoSizeStickerMarkup(); + emojiMarkup.sticker_id = previewView.document.id; + emojiMarkup.stickerset = MessageObject.getInputStickerSet(previewView.document); + emojiMarkup.background_colors.add(previewView.backgroundGradient.color1); + if (previewView.backgroundGradient.color2 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color2); + } + if (previewView.backgroundGradient.color3 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color3); + } + if (previewView.backgroundGradient.color4 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color4); + } + photoEntry.emojiMarkup = emojiMarkup; + } + + photoEntry.editedInfo = new VideoEditedInfo(); + photoEntry.editedInfo.originalPath = file.getPath(); + photoEntry.editedInfo.resultWidth = 800; + photoEntry.editedInfo.resultHeight = 800; + photoEntry.editedInfo.originalWidth = 800; + photoEntry.editedInfo.originalHeight = 800; + photoEntry.editedInfo.isPhoto = true; + photoEntry.editedInfo.bitrate = -1; + photoEntry.editedInfo.muted = true; + + photoEntry.editedInfo.start = photoEntry.editedInfo.startTime = 0; + photoEntry.editedInfo.endTime = previewView.getDuration(); + photoEntry.editedInfo.framerate = 30; + + photoEntry.editedInfo.avatarStartTime = 0; + photoEntry.editedInfo.estimatedSize = (int) (photoEntry.editedInfo.endTime / 1000.0f * 115200); + photoEntry.editedInfo.estimatedDuration = photoEntry.editedInfo.endTime; + + VideoEditedInfo.MediaEntity mediaEntity = new VideoEditedInfo.MediaEntity(); + mediaEntity.type = 0; + + if (document == null) { + document = AnimatedEmojiDrawable.findDocument(UserConfig.selectedAccount, documentId); + } + if (document == null) { + return; + } + mediaEntity.viewWidth = (int) (800 * scale); + mediaEntity.viewHeight = (int) (800 * scale); + mediaEntity.width = scale; + mediaEntity.height = scale; + mediaEntity.x = (1f - scale) / 2f; + mediaEntity.y = (1f - scale) / 2f; + mediaEntity.document = document; + mediaEntity.parentObject = null; + mediaEntity.text = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(document, true).getAbsolutePath(); + mediaEntity.roundRadius = AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS; + if (MessageObject.isAnimatedStickerDocument(document, true) || MessageObject.isVideoStickerDocument(document)) { + boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(document, true); + mediaEntity.subType |= isAnimatedSticker ? 1 : 4; + } + + photoEntry.editedInfo.mediaEntities = new ArrayList<>(); + photoEntry.editedInfo.mediaEntities.add(mediaEntity); + } else { + photoEntry = new MediaController.PhotoEntry(0, 0, 0, thumb.getPath(), 0, false, 0, 0, 0); + } + selectedPhotos.put(-1, photoEntry); + selectedPhotosOrder.add(-1); + parentAlert.delegate.didPressedButton(7, true, false, 0, false); + }); + + parentAlert.dismiss(); + } + position--; + } ArrayList arrayList = getAllPhotosArray(); if (position < 0 || position >= arrayList.size()) { return; @@ -742,7 +926,13 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } boolean hasSpoiler = arrayList.get(position) instanceof MediaController.PhotoEntry && ((MediaController.PhotoEntry) arrayList.get(position)).hasSpoiler; - + Object object = arrayList.get(position); + if (object instanceof MediaController.PhotoEntry) { + MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; + if (checkSendMediaEnabled(photoEntry)) { + return; + } + } if (hasSpoiler) { setCurrentSpoilerVisible(position, false); } @@ -947,6 +1137,10 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou if (parentAlert.avatarPicker != 2 && !(parentAlert.baseFragment instanceof ChatActivity) || takingPhoto || parentAlert.baseFragment == null || parentAlert.baseFragment.getParentActivity() == null || cameraView == null) { return false; } + if (!videoEnabled) { + BulletinFactory.of(cameraView, resourcesProvider).createErrorBulletin(LocaleController.getString(R.string.GlobalAttachVideoRestricted)).show(); + return false; + } if (Build.VERSION.SDK_INT >= 23) { if (parentAlert.baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { requestingPermissions = true; @@ -1022,6 +1216,10 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou shutterButton.setState(ShutterButton.State.DEFAULT, true); return; } + if (!photoEnabled) { + BulletinFactory.of(cameraView, resourcesProvider).createErrorBulletin(LocaleController.getString(R.string.GlobalAttachPhotoRestricted)).show(); + return; + } 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); @@ -1196,6 +1394,21 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou }); } + private boolean checkSendMediaEnabled(MediaController.PhotoEntry photoEntry) { + if (!videoEnabled && photoEntry.isVideo) { + BulletinFactory.of(parentAlert.sizeNotifierFrameLayout, resourcesProvider).createErrorBulletin( + LocaleController.getString("GlobalAttachVideoRestricted", R.string.GlobalAttachVideoRestricted) + ).show(); + return true; + } else if (!photoEnabled && !photoEntry.isVideo) { + BulletinFactory.of(parentAlert.sizeNotifierFrameLayout, resourcesProvider).createErrorBulletin( + LocaleController.getString("GlobalAttachPhotoRestricted", R.string.GlobalAttachPhotoRestricted) + ).show(); + return true; + } + return false; + } + private int addToSelectedPhotos(MediaController.PhotoEntry object, int index) { Object key = object.imageId; if (selectedPhotos.containsKey(key)) { @@ -1860,6 +2073,13 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } if (cameraView == null) { cameraView = new CameraView(parentAlert.baseFragment.getParentActivity(), parentAlert.openWithFrontFaceCamera) { + + Bulletin.Delegate bulletinDelegate = new Bulletin.Delegate() { + @Override + public int getBottomOffset(int tag) { + return AndroidUtilities.dp(126) + parentAlert.getBottomInset(); + } + }; @Override protected void dispatchDraw(Canvas canvas) { if (Build.VERSION.SDK_INT >= 21) { @@ -1878,6 +2098,18 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou canvas.restore(); } } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Bulletin.addDelegate(cameraView, bulletinDelegate); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Bulletin.removeDelegate(cameraView); + } }; cameraView.setRecordFile(AndroidUtilities.generateVideoPath(parentAlert.baseFragment instanceof ChatActivity && ((ChatActivity) parentAlert.baseFragment).isSecretChat())); cameraView.setFocusable(true); @@ -2735,6 +2967,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou if (count != 0) { parentAlert.selectedMenuItem.hideSubItem(open_in); } + compressItem.setVisibility(documentsEnabled ? View.VISIBLE : View.GONE); if (count > 1) { parentAlert.selectedMenuItem.showSubItem(preview_gap); parentAlert.selectedMenuItem.showSubItem(preview); @@ -2881,8 +3114,11 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } @Override - void onInit(boolean hasMedia) { - mediaEnabled = hasMedia; + void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { + mediaEnabled = hasVideo || hasPhoto; + videoEnabled = hasVideo; + photoEnabled = hasPhoto; + documentsEnabled = hasDocuments; if (cameraView != null) { cameraView.setAlpha(mediaEnabled ? 1.0f : 0.2f); cameraView.setEnabled(mediaEnabled); @@ -3440,10 +3676,16 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou @Override public void getOutline(View view, Outline outline) { PhotoAttachPhotoCell photoCell = (PhotoAttachPhotoCell) view; + if (photoCell.getTag() == null) { + return; + } int position = (Integer) photoCell.getTag(); if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { position++; } + if (showAvatarConstructor) { + position++; + } if (position == 0) { int rad = AndroidUtilities.dp(8 * parentAlert.cornerRadius); outline.setRoundRect(0, 0, view.getMeasuredWidth() + rad, view.getMeasuredHeight() + rad, rad); @@ -3463,6 +3705,9 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } int index = (Integer) v.getTag(); MediaController.PhotoEntry photoEntry = v.getPhotoEntry(); + if (checkSendMediaEnabled(photoEntry)) { + return; + } boolean added = !selectedPhotos.containsKey(photoEntry.imageId); if (added && parentAlert.maxSelectedPhotos >= 0 && selectedPhotos.size() >= parentAlert.maxSelectedPhotos) { if (parentAlert.allowOrder && parentAlert.baseFragment instanceof ChatActivity) { @@ -3515,6 +3760,9 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { position--; } + if (showAvatarConstructor) { + position--; + } PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) holder.itemView; if (this == adapter) { cell.setItemSize(itemSize); @@ -3526,12 +3774,22 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } MediaController.PhotoEntry photoEntry = getPhotoEntryAtPosition(position); + if (photoEntry == null) { + return; + } cell.setPhotoEntry(photoEntry, needCamera && selectedAlbumEntry == galleryAlbumEntry, position == getItemCount() - 1); if (parentAlert.baseFragment instanceof ChatActivity && parentAlert.allowOrder) { cell.setChecked(selectedPhotosOrder.indexOf(photoEntry.imageId), selectedPhotos.containsKey(photoEntry.imageId), false); } else { cell.setChecked(-1, selectedPhotos.containsKey(photoEntry.imageId), false); } + if (!videoEnabled && photoEntry.isVideo) { + cell.setAlpha(0.3f); + } else if (!photoEnabled && !photoEntry.isVideo) { + cell.setAlpha(0.3f); + } else { + cell.setAlpha(1f); + } cell.getImageView().setTag(position); cell.setTag(position); break; @@ -3598,6 +3856,15 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou default: holder = new RecyclerListView.Holder(new PhotoAttachPermissionCell(mContext, resourcesProvider)); break; + case 4: + AvatarConstructorPreviewCell avatarConstructorPreviewCell = new AvatarConstructorPreviewCell(mContext, parentAlert.forUser) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(itemSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(itemSize, MeasureSpec.EXACTLY)); + } + }; + holder = new RecyclerListView.Holder(avatarConstructorPreviewCell); + break; } return holder; } @@ -3619,6 +3886,9 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { count++; } + if (showAvatarConstructor) { + count++; + } if (noGalleryPermissions && this == adapter) { count++; } @@ -3637,6 +3907,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou if (!mediaEnabled) { return 2; } + int localPosition = position; if (needCamera && position == 0 && selectedAlbumEntry == galleryAlbumEntry) { if (noCameraPermissions) { return 3; @@ -3644,6 +3915,12 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou return 1; } } + if (needCamera) { + localPosition--; + } + if (showAvatarConstructor && localPosition == 0) { + return VIEW_TYPE_AVATAR_CONSTRUCTOR; + } if (this == adapter && position == itemsCount - 1) { return 2; } else if (noGalleryPermissions) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java new file mode 100644 index 000000000..133099d36 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java @@ -0,0 +1,154 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; + +public class ChatAttachRestrictedLayout extends ChatAttachAlert.AttachAlertLayout { + + private final EmptyTextProgressView progressView; + private final RecyclerListView listView; + public final int id; + private final RecyclerView.Adapter adapter; + private int gridExtraSpace; + + public ChatAttachRestrictedLayout(int id, ChatAttachAlert alert, Context context, Theme.ResourcesProvider resourcesProvider) { + super(alert, context, resourcesProvider); + this.id = id; + progressView = new EmptyTextProgressView(context, null, resourcesProvider); + progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); + progressView.setOnTouchListener(null); + progressView.setTextSize(16); + 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(); + if (id == 1) { + progressView.setText(ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_MEDIA)); + } else if (id == 3) { + progressView.setText(ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_MUSIC)); + } else if (id == 4) { + progressView.setText(ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_DOCUMENTS)); + } else { + progressView.setText(ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_PLAIN)); + } + progressView.showTextView(); + + listView = new RecyclerListView(context, resourcesProvider); + listView.setSectionsType(RecyclerListView.SECTIONS_TYPE_DATE); + listView.setVerticalScrollBarEnabled(false); + listView.setLayoutManager(new LinearLayoutManager(context)); + listView.setClipToPadding(false); + listView.setAdapter(adapter = new RecyclerView.Adapter() { + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = new View(getContext()) { + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(gridExtraSpace, MeasureSpec.EXACTLY)); + } + }; + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + + } + + @Override + public int getItemCount() { + return 1; + } + }); + listView.setPadding(0, 0, 0, AndroidUtilities.dp(48)); + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + parentAlert.updateLayout(ChatAttachRestrictedLayout.this, true, dy); + } + }); + addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + + @Override + int getCurrentItemTop() { + if (listView.getChildCount() <= 0) { + return Integer.MAX_VALUE; + } + View child = listView.getChildAt(0); + RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); + int top = child.getTop() - AndroidUtilities.dp(8); + int newOffset = top > 0 && holder != null && holder.getAdapterPosition() == 0 ? top : 0; + if (top >= 0 && holder != null && holder.getAdapterPosition() == 0) { + newOffset = top; + // runShadowAnimation(false); + } else { +// runShadowAnimation(true); + } + progressView.setTranslationY(newOffset + (getMeasuredHeight() - newOffset - AndroidUtilities.dp(50) - progressView.getMeasuredHeight()) / 2); +// frameLayout.setTranslationY(newOffset); + return newOffset + AndroidUtilities.dp(12); + } + + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + parentAlert.getSheetContainer().invalidate(); + } + + @Override + int getFirstOffset() { + return getListTopPadding() + AndroidUtilities.dp(4); + } + + @Override + int getListTopPadding() { + return listView.getPaddingTop(); + } + + @Override + void onPreMeasure(int availableWidth, int availableHeight) { + super.onPreMeasure(availableWidth, availableHeight); + int newSize = Math.max(0, availableHeight - ActionBar.getCurrentActionBarHeight()); + if (gridExtraSpace != newSize) { + gridExtraSpace = newSize; + adapter.notifyDataSetChanged(); + } + int paddingTop; + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + paddingTop = (int) (availableHeight / 3.5f); + } else { + paddingTop = (availableHeight / 5 * 2); + } + paddingTop -= AndroidUtilities.dp(52); + if (paddingTop < 0) { + paddingTop = 0; + } + if (listView.getPaddingTop() != paddingTop) { + listView.setPadding(AndroidUtilities.dp(6), paddingTop, AndroidUtilities.dp(6), AndroidUtilities.dp(48)); + } + } + + +} 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 d545913d4..6b0209555 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -935,7 +935,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } else { avatarDrawable.setScaleSize(1f); if (avatarImageView != null) { - avatarImageView.imageReceiver.setForUserOrChat(user, avatarDrawable, null, true); + avatarImageView.imageReceiver.setForUserOrChat(user, avatarDrawable, null, true, VectorAvatarThumbDrawable.TYPE_STATIC); } } } else if (chat != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java index 6626ca270..29342743d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java @@ -3,16 +3,23 @@ package org.telegram.ui.Components; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.CheckBox; +import androidx.core.content.ContextCompat; + +import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.GenericProvider; import org.telegram.ui.ActionBar.Theme; public class CheckBox2 extends View { private CheckBoxBase checkBoxBase; + Drawable iconDrawable; + int currentIcon; public CheckBox2(Context context, int sz) { this(context, sz, null); @@ -93,7 +100,19 @@ public class CheckBox2 extends View { @Override protected void onDraw(Canvas canvas) { - checkBoxBase.draw(canvas); + if (iconDrawable != null) { + int cx = getMeasuredWidth() >> 1; + int cy = getMeasuredHeight() >> 1; + iconDrawable.setBounds(cx - iconDrawable.getIntrinsicWidth() / 2, cy - iconDrawable.getIntrinsicHeight() / 2, cx + iconDrawable.getIntrinsicWidth() / 2, cy + iconDrawable.getIntrinsicHeight() / 2); + iconDrawable.draw(canvas); + Paint paint = new Paint(); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(AndroidUtilities.dp(1.2f)); + paint.setColor(Theme.getColor(Theme.key_switch2Track)); + canvas.drawCircle(cx, cy, cx - AndroidUtilities.dp(1.5f), paint); + } else { + checkBoxBase.draw(canvas); + } } @Override @@ -103,4 +122,20 @@ public class CheckBox2 extends View { info.setChecked(isChecked()); info.setCheckable(true); } + + public void setIcon(int icon) { + if (icon != currentIcon) { + currentIcon = icon; + if (icon == 0) { + iconDrawable = null; + } else { + iconDrawable = ContextCompat.getDrawable(getContext(), icon).mutate(); + iconDrawable.setColorFilter(Theme.getColor(Theme.key_switch2Track), PorterDuff.Mode.MULTIPLY); + } + } + } + + public boolean hasIcon() { + return iconDrawable != null; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java index 296f5e061..703eb7d1b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java @@ -354,7 +354,7 @@ public class CheckBoxBase { if (backgroundType == 9) { paint.setColor(getThemedColor(background2ColorKey)); - } else if (backgroundType == 11 || backgroundType == 6 || backgroundType == 7 || backgroundType == 10 || !drawUnchecked && backgroundColorKey != null) { + } else if (backgroundType == 11 || backgroundType == 6 || backgroundType == 7 || backgroundType == 10 || !drawUnchecked && backgroundColorKey != null || backgroundType == 14) { paint.setColor(getThemedColor(backgroundColorKey)); } else { paint.setColor(getThemedColor(enabled ? Theme.key_checkbox : Theme.key_checkboxDisabled)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java index dcf35cb2e..5d189da01 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java @@ -41,7 +41,7 @@ public class CircularProgressDrawable extends Drawable { } public static void getSegments(float t, float[] segments) { - segments[0] = 1520 * t / 5400f - 20; + segments[0] = Math.max(0, 1520 * t / 5400f - 20); segments[1] = 1520 * t / 5400f; for (int i = 0; i < 4; ++i) { segments[1] += interpolator.getInterpolation((t - i * 1350) / 667f) * 250; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ColorPicker.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ColorPicker.java index 92e92d53e..e8b8c5a95 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ColorPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ColorPicker.java @@ -95,6 +95,7 @@ public class ColorPicker extends FrameLayout { private boolean colorPressed; private int selectedColor; + private int prevSelectedColor; private float pressedMoveProgress = 1.0f; private long lastUpdateTime; @@ -252,6 +253,7 @@ public class ColorPicker extends FrameLayout { boolean checked = radioButton[b] == radioButton1; radioButton[b].setChecked(checked, true); if (checked) { + prevSelectedColor = selectedColor; selectedColor = b; } } @@ -529,7 +531,11 @@ public class ColorPicker extends FrameLayout { } radioButton[3] = button; } - radioButton[0].callOnClick(); + if (prevSelectedColor >= 0 && prevSelectedColor < selectedColor) { + radioButton[prevSelectedColor].callOnClick(); + } else { + radioButton[colorsCount - 1].callOnClick(); + } for (int a = 0; a < radioButton.length; a++) { if (a < colorsCount) { delegate.setColor(radioButton[a].getColor(), a, a == radioButton.length - 1); @@ -907,6 +913,7 @@ public class ColorPicker extends FrameLayout { public void setType(int resetType, boolean hasChanges, int maxColorsCount, int newColorsCount, boolean myMessages, int angle, boolean animated) { if (resetType != currentResetType) { + prevSelectedColor = 0; selectedColor = 0; for (int i = 0; i < 4; i++) { radioButton[i].setChecked(i == selectedColor, true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java index b6b686484..53d6fe0ad 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java @@ -141,7 +141,7 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not } bitmapCanvas.save(); bitmapCanvas.translate(0, padding); - drawInUiThread(bitmapCanvas, 1f); + drawInUiThread(bitmapCanvas, alpha); bitmapCanvas.restore(); } @@ -154,7 +154,7 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not if (bitmap != null ) { Bitmap drawingBitmap = bitmap; - paint.setAlpha((int) (255 * alpha)); + paint.setAlpha((int) (0xFF * alpha)); canvas.save(); canvas.translate(0, -padding); this.drawBitmap(canvas, drawingBitmap, paint); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java index d572c2db5..2eaeaf810 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java @@ -56,6 +56,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; @@ -69,6 +70,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.Premium.PremiumButtonView; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; +import org.telegram.ui.ContentPreviewViewer; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; @@ -87,12 +89,14 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N private EmojiPacksLoader customEmojiPacks; private RecyclerListView listView; + private Adapter adapter; private View shadowView; private FrameLayout buttonsView; private TextView addButtonView; private TextView removeButtonView; private PremiumButtonView premiumButtonView; private GridLayoutManager gridLayoutManager; + private RecyclerAnimationScrollHelper scrollHelper; private CircularProgressDrawable progressDrawable; private ActionBarPopupWindow popupWindow; @@ -102,6 +106,113 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N private float lastY; private Float fromY; + int highlightStartPosition = -1, highlightEndPosition = -1; + private AnimatedFloat highlightAlpha; + + private ContentPreviewViewer.ContentPreviewViewerDelegate previewDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { + @Override + public boolean can() { + return true; + } + + @Override + public boolean needSend(int contentType) { + return fragment instanceof ChatActivity && ((ChatActivity) fragment).canSendMessage() && (UserConfig.getInstance(UserConfig.selectedAccount).isPremium() || ((ChatActivity) fragment).getCurrentUser() != null && UserObject.isUserSelf(((ChatActivity) fragment).getCurrentUser())); + } + + @Override + public void sendEmoji(TLRPC.Document emoji) { + if (fragment instanceof ChatActivity) { + ((ChatActivity) fragment).sendAnimatedEmoji(emoji, true, 0); + } + onCloseByLink(); + dismiss(); + } + + @Override + public boolean needCopy() { + return UserConfig.getInstance(UserConfig.selectedAccount).isPremium(); + } + + @Override + public void copyEmoji(TLRPC.Document document) { + Spannable spannable = SpannableStringBuilder.valueOf(MessageObject.findAnimatedEmojiEmoticon(document)); + spannable.setSpan(new AnimatedEmojiSpan(document, null), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (AndroidUtilities.addToClipboard(spannable)) { + BulletinFactory.of((FrameLayout) containerView, resourcesProvider).createCopyBulletin(LocaleController.getString("EmojiCopied", R.string.EmojiCopied)).show(); + } + } + + @Override + public Boolean canSetAsStatus(TLRPC.Document document) { + if (!UserConfig.getInstance(UserConfig.selectedAccount).isPremium()) { + return null; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + if (user == null) { + return null; + } + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + return document != null && (emojiStatusId == null || emojiStatusId != document.id); + } + + @Override + public void setAsEmojiStatus(TLRPC.Document document, Integer until) { + TLRPC.EmojiStatus status; + if (document == null) { + status = new TLRPC.TL_emojiStatusEmpty(); + } else if (until != null) { + status = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) status).document_id = document.id; + ((TLRPC.TL_emojiStatusUntil) status).until = until; + } else { + status = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) status).document_id = document.id; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + final TLRPC.EmojiStatus previousEmojiStatus = user == null ? new TLRPC.TL_emojiStatusEmpty() : user.emoji_status; + MessagesController.getInstance(currentAccount).updateEmojiStatus(status); + + Runnable undoAction = () -> MessagesController.getInstance(currentAccount).updateEmojiStatus(previousEmojiStatus); + if (document == null) { + final Bulletin.SimpleLayout layout = new Bulletin.SimpleLayout(getContext(), resourcesProvider); + layout.textView.setText(LocaleController.getString("RemoveStatusInfo", R.string.RemoveStatusInfo)); + layout.imageView.setImageResource(R.drawable.msg_settings_premium); + Bulletin.UndoButton undoButton = new Bulletin.UndoButton(getContext(), true, resourcesProvider); + undoButton.setUndoAction(undoAction); + layout.setButton(undoButton); + Bulletin.make((FrameLayout) containerView, layout, Bulletin.DURATION_SHORT).show(); + } else { + BulletinFactory.of((FrameLayout) containerView, resourcesProvider).createEmojiBulletin(document, LocaleController.getString("SetAsEmojiStatusInfo", R.string.SetAsEmojiStatusInfo), LocaleController.getString("Undo", R.string.Undo), undoAction).show(); + } + } + + @Override + public boolean canSchedule() { + return false; +// return delegate != null && delegate.canSchedule(); + } + + @Override + public boolean isInScheduleMode() { + if (fragment instanceof ChatActivity) { + return ((ChatActivity) fragment).isInScheduleMode(); + } + return false; + } + + @Override + public void openSet(TLRPC.InputStickerSet set, boolean clearsInputField) { + + } + + @Override + public long getDialogId() { + + return 0; + } + }; + @Override protected boolean canDismissWithSwipe() { return false; @@ -116,7 +227,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N } private EmojiPacksAlert(BaseFragment fragment, Context context, Theme.ResourcesProvider resourceProvider, ArrayList stickerSets, TLObject parentObject) { - super(context, false, resourceProvider); + super(context, false, resourceProvider = fragment != null && fragment.getResourceProvider() != null ? fragment.getResourceProvider() : resourceProvider); this.fragment = fragment; fixNavigationBar(); @@ -151,7 +262,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N return; } paint.setColor(getThemedColor(Theme.key_dialogBackground)); - paint.setShadowLayer(dp(2), 0, dp(-0.66f), 0x1e000000); + Theme.applyDefaultShadow(paint); path.reset(); float y = lastY = getListTop(); float pad = 0; @@ -437,6 +548,12 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N }; listView = new RecyclerListView(context) { + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = ContentPreviewViewer.getInstance().onInterceptTouchEvent(event, listView, 0, previewDelegate, resourcesProvider); + return super.onInterceptTouchEvent(event) || result; + } + @Override protected void onMeasure(int widthSpec, int heightSpec) { int width = MeasureSpec.getSize(widthSpec); @@ -460,15 +577,47 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N public boolean drawChild(Canvas canvas, View child, long drawingTime) { return false; } + + private Paint highlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void dispatchDraw(Canvas canvas) { + if (highlightAlpha != null && highlightStartPosition >= 0 && highlightEndPosition >= 0 && adapter != null && isAttachedToWindow()) { + float alpha = highlightAlpha.set(0); + + if (alpha > 0) { + int top = Integer.MAX_VALUE, bottom = Integer.MIN_VALUE; + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + int position = getChildAdapterPosition(child); + + if (position != NO_POSITION && position >= highlightStartPosition && position <= highlightEndPosition) { + top = Math.min(top, child.getTop() + (int) child.getTranslationY()); + bottom = Math.max(bottom, child.getBottom() + (int) child.getTranslationY()); + } + } + + if (top < bottom) { + highlightPaint.setColor(Theme.multAlpha(getThemedColor(Theme.key_chat_linkSelectBackground), alpha)); + canvas.drawRect(0, top, getMeasuredWidth(), bottom, highlightPaint); + } + + invalidate(); + } + } + + super.dispatchDraw(canvas); + } }; + highlightAlpha = new AnimatedFloat(0, listView, 0, 1250, CubicBezierInterpolator.EASE_IN); containerView.setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); containerView.setClipChildren(false); containerView.setClipToPadding(false); containerView.setWillNotDraw(false); + listView.setWillNotDraw(false); listView.setSelectorRadius(AndroidUtilities.dp(6)); listView.setSelectorDrawableColor(Theme.getColor(Theme.key_listSelector, resourceProvider)); listView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), AndroidUtilities.dp(68)); - listView.setAdapter(new Adapter()); listView.setLayoutManager(gridLayoutManager = new GridLayoutManager(context, 8)); listView.addItemDecoration(new RecyclerView.ItemDecoration() { @Override @@ -481,7 +630,9 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N } } }); - listView.setOnItemClickListener((view, position) -> { + final Theme.ResourcesProvider finalResourceProvider = resourceProvider; + RecyclerListView.OnItemClickListener stickersOnItemClickListener; + listView.setOnItemClickListener(stickersOnItemClickListener = (view, position) -> { if (stickerSets == null || stickerSets.size() <= 1) { if (popupWindow != null) { popupWindow.dismiss(); @@ -494,7 +645,6 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N SpannableString text = new SpannableString(MessageObject.findAnimatedEmojiEmoticon(span.document == null ? AnimatedEmojiDrawable.findDocument(currentAccount, span.getDocumentId()) : span.document)); text.setSpan(span, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ((Editable) ((ChatActivity) fragment).getChatActivityEnterView().messageEditText.getText()).append(text); - ((ChatActivity) fragment).showEmojiHint(); onCloseByLink(); dismiss(); } catch (Exception ignore) {} @@ -526,7 +676,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N inputStickerSet.id = stickerSet.set.id; inputStickerSet.access_hash = stickerSet.set.access_hash; inputStickerSets.add(inputStickerSet); - new EmojiPacksAlert(fragment, getContext(), resourceProvider, inputStickerSets) { + new EmojiPacksAlert(fragment, getContext(), finalResourceProvider, inputStickerSets) { @Override protected void onCloseByLink() { EmojiPacksAlert.this.dismiss(); @@ -586,6 +736,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N } return false; }); + listView.setOnTouchListener((v, event) -> ContentPreviewViewer.getInstance().onTouch(event, listView, 0, stickersOnItemClickListener, previewDelegate, resourcesProvider)); gridLayoutManager.setReverseLayout(false); gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override @@ -593,6 +744,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N return listView.getAdapter() != null && listView.getAdapter().getItemViewType(position) != 1 ? gridLayoutManager.getSpanCount() : 1; } }); + scrollHelper = new RecyclerAnimationScrollHelper(listView, gridLayoutManager); containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); @@ -629,16 +781,26 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N premiumButtonView.setIcon(R.raw.unlock_icon); premiumButtonView.buttonLayout.setClickable(true); buttonsView.addView(premiumButtonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 12, 10, 12, 10)); + } - updateButton(); - int currentAccount = fragment == null ? UserConfig.selectedAccount : fragment.getCurrentAccount(); - MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_EMOJIPACKS); + @Override + public void onBackPressed() { + if (ContentPreviewViewer.getInstance().isVisible()) { + ContentPreviewViewer.getInstance().closeWithMenu(); + return; + } + super.onBackPressed(); } protected void onButtonClicked(boolean install) { } + private int highlightIndex = -1; + public void highlight(int setIndex) { + highlightIndex = setIndex; + } + private boolean shown = false; private void updateShowButton(boolean show) { boolean animated = !shown && show; @@ -847,6 +1009,20 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N loaded = loadedNow; if (!loaded) { listView.setAlpha(0); + } else if (highlightIndex >= 0) { + int currentPosition = gridLayoutManager.findFirstVisibleItemPosition(); + int position = adapter.getSetHeaderPosition(highlightIndex); + if (Math.abs(currentPosition - position) > (1 + 16 + 1) * 3) { + scrollHelper.setScrollDirection(currentPosition < position ? RecyclerAnimationScrollHelper.SCROLL_DIRECTION_DOWN : RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP); + scrollHelper.scrollToPosition(position, AndroidUtilities.displaySize.y / 2 - AndroidUtilities.dp(170), false, true); + } else { + listView.smoothScrollToPosition(position); + } + highlightStartPosition = adapter.getSetHeaderPosition(highlightIndex); + highlightEndPosition = adapter.getSetEndPosition(highlightIndex); + highlightAlpha.set(1, true); + listView.invalidate(); + highlightIndex = -1; } if (!loaded) { @@ -867,7 +1043,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N if (canInstallPacks.size() == 1) { addButtonView.setText(LocaleController.formatPluralString("AddManyEmojiCount", canInstallPacks.get(0).documents.size())); } else { - addButtonView.setText(LocaleController.formatPluralString("AddManyEmojiCount", canInstallPacks.size())); + addButtonView.setText(LocaleController.formatPluralString("AddManyEmojiPacksCount", canInstallPacks.size())); } addButtonView.setOnClickListener(ev -> { final int count = canInstallPacks.size(); @@ -940,7 +1116,14 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N @Override public void show() { super.show(); + listView.setAdapter(adapter = new Adapter()); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 4); + + customEmojiPacks.start(); + updateButton(); + int currentAccount = fragment == null ? UserConfig.selectedAccount : fragment.getCurrentAccount(); + MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_EMOJIPACKS); } @Override @@ -969,6 +1152,12 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N private class Adapter extends RecyclerListView.SelectionAdapter { + private final int VIEW_TYPE_PADDING = 0; + private final int VIEW_TYPE_EMOJI = 1; + private final int VIEW_TYPE_HEADER = 2; + private final int VIEW_TYPE_TEXT = 3; + private final int VIEW_TYPE_SEPARATOR = 4; + @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { return holder.getItemViewType() == 1; @@ -978,15 +1167,15 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = null; - if (viewType == 0) { + if (viewType == VIEW_TYPE_PADDING) { view = paddingView; - } else if (viewType == 1) { + } else if (viewType == VIEW_TYPE_EMOJI) { view = new EmojiImageView(getContext()); - } else if (viewType == 2) { + } else if (viewType == VIEW_TYPE_HEADER) { view = new EmojiPackHeader(getContext(), customEmojiPacks.data.length <= 1); - } else if (viewType == 3) { + } else if (viewType == VIEW_TYPE_TEXT) { view = new TextView(getContext()); - } else if (viewType == 4) { + } else if (viewType == VIEW_TYPE_SEPARATOR) { view = new SeparatorView(getContext()); } return new RecyclerListView.Holder(view); @@ -996,14 +1185,14 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { position--; switch (holder.getItemViewType()) { - case 3: + case VIEW_TYPE_TEXT: TextView textView = (TextView) holder.itemView; textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); textView.setTextColor(getThemedColor(Theme.key_chat_emojiPanelTrendingDescription)); textView.setText(AndroidUtilities.replaceTags(LocaleController.getString("PremiumPreviewEmojiPack", R.string.PremiumPreviewEmojiPack))); textView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(30), AndroidUtilities.dp(14)); break; - case 1: + case VIEW_TYPE_EMOJI: if (hasDescription) { position--; } @@ -1028,11 +1217,16 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N inputStickerSet.id = customEmoji.stickerSet.set.id; inputStickerSet.short_name = customEmoji.stickerSet.set.short_name; inputStickerSet.access_hash = customEmoji.stickerSet.set.access_hash; - view.span = new AnimatedEmojiSpan(customEmoji.documentId, null); + TLRPC.Document document = customEmoji.getDocument(); + if (document != null) { + view.span = new AnimatedEmojiSpan(document, null); + } else { + view.span = new AnimatedEmojiSpan(customEmoji.documentId, null); + } } } break; - case 2: + case VIEW_TYPE_HEADER: if (hasDescription && position > 0) { position--; } @@ -1067,19 +1261,19 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N @Override public int getItemViewType(int position) { if (position == 0) { - return 0; + return VIEW_TYPE_PADDING; } position--; if (hasDescription) { if (position == 1) { - return 3; + return VIEW_TYPE_TEXT; } else if (position > 0) { position--; } } for (int i = 0, j = 0; i < customEmojiPacks.data.length; ++i) { if (position == j) { - return 2; + return VIEW_TYPE_HEADER; } int count = customEmojiPacks.data[i].size(); if (customEmojiPacks.data.length > 1) { @@ -1087,11 +1281,47 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N } j += 1 + count; if (position == j) { - return 4; + return VIEW_TYPE_SEPARATOR; } j++; } - return 1; + return VIEW_TYPE_EMOJI; + } + + public int getSetHeaderPosition(int setIndex) { + int position = 1; + if (hasDescription) { + position++; + } + for (int i = 0; i < customEmojiPacks.data.length; ++i) { + if (i == setIndex) { + return position; + } + int count = customEmojiPacks.data[i].size(); + if (customEmojiPacks.data.length > 1) { + count = Math.min(gridLayoutManager.getSpanCount() * 2, count); + } + position += 1 + count + 1; + } + return position; + } + + public int getSetEndPosition(int setIndex) { + int position = 1; + if (hasDescription) { + position++; + } + for (int i = 0; i < customEmojiPacks.data.length; ++i) { + int count = customEmojiPacks.data[i].size(); + if (customEmojiPacks.data.length > 1) { + count = Math.min(gridLayoutManager.getSpanCount() * 2, count); + } + if (i == setIndex) { + return position + count + 1; + } + position += 1 + count + 1; + } + return position; } @Override @@ -1156,7 +1386,9 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N } } } - private class EmojiImageView extends View { + + public static class EmojiImageView extends View { + public ImageReceiver.BackgroundThreadDrawHolder[] backgroundThreadDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; public ImageReceiver imageReceiver; @@ -1166,6 +1398,18 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N public AnimatedEmojiSpan span; + public TLRPC.Document getDocument() { + TLRPC.Document document = null; + if (span != null) { + document = span.document; + if (document == null) { + long documentId = span.getDocumentId(); + document = AnimatedEmojiDrawable.findDocument(UserConfig.selectedAccount, documentId); + } + } + return document; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setPadding(AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2)); @@ -1189,7 +1433,10 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N backAnimator = ValueAnimator.ofFloat(pressedProgress, 0); backAnimator.addUpdateListener(animation -> { pressedProgress = (float) animation.getAnimatedValue(); - containerView.invalidate(); + if (getParent() instanceof View) { + ((View) getParent()).invalidate(); + } +// containerView.invalidate(); }); backAnimator.addListener(new AnimatorListenerAdapter() { @Override @@ -1501,6 +1748,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N public ArrayList stickerSets; public ArrayList[] data; private int currentAccount; + private boolean started = false; public EmojiPacksLoader(int currentAccount, ArrayList inputStickerSets, TLObject parentObject) { this.currentAccount = currentAccount; @@ -1509,10 +1757,17 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N } this.inputStickerSets = inputStickerSets; this.parentObject = parentObject; + } + + public void start() { + if (started) { + return; + } + started = true; init(); } - private void init() { + public void init() { if ((parentObject instanceof TLRPC.Photo || parentObject instanceof TLRPC.Document) && (this.inputStickerSets == null || this.inputStickerSets.isEmpty())) { data = new ArrayList[2]; putStickerSet(0, null); 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 09594922c..dfcd5192e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java @@ -68,10 +68,15 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { }; private int settingsDrawableId = R.drawable.smiles_tab_settings; + private boolean forceTabsShow = !UserConfig.getInstance(UserConfig.selectedAccount).isPremium(); + private boolean showSelected = true; + private AnimatedFloat showSelectedAlpha; + private Theme.ResourcesProvider resourcesProvider; private boolean includeAnimated; public LinearLayout contentView; + public EmojiTabButton toggleEmojiStickersTab; public EmojiTabButton recentTab; private EmojiTabButton settingsTab; private EmojiTabsView emojiTabs; @@ -82,6 +87,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { private float selectT = 0f; private float selectAnimationT = 0f; private int selected = 0; + private int selectedFullIndex = 0; private int wasIndex = 0; public boolean animateAppear = true; @@ -89,7 +95,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { private Runnable onSettingsOpenRunnable; private boolean wasDrawn; private int animatedEmojiCacheType = AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP; - + private int currentType; public boolean updateButtonDrawables = true; @@ -98,6 +104,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { this.includeAnimated = includeAnimated; this.resourcesProvider = resourcesProvider; this.onSettingsOpenRunnable = onSettingsOpen; + this.currentType = type; contentView = new LinearLayout(context) { @@ -200,6 +207,11 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { } } + if (showSelectedAlpha == null) { + showSelectedAlpha = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + } + float alpha = showSelectedAlpha.set(showSelected ? 1 : 0); + int selectFrom = (int) Math.floor(selectT), selectTo = (int) Math.ceil(selectT); getChildBounds(selectFrom, from); getChildBounds(selectTo, to); @@ -211,11 +223,23 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { rect.set(rect.centerX() - hw, rect.centerY() - hh, rect.centerX() + hw, rect.centerY() + hh); float r = AndroidUtilities.dp(AndroidUtilities.lerp(8f, 16f, isEmojiTabs)); paint.setColor(selectorColor()); + if (forceTabsShow) { + paint.setAlpha((int) (paint.getAlpha() * alpha * (1f - isEmojiTabs * .5f))); + } path.rewind(); path.addRoundRect(rect, r, r, Path.Direction.CW); canvas.drawPath(path, paint); + if (forceTabsShow) { + path.rewind(); + getChildBounds(1, rect); + path.addRoundRect(rect, AndroidUtilities.dpf2(16), AndroidUtilities.dpf2(16), Path.Direction.CW); + paint.setColor(selectorColor()); + paint.setAlpha((int) (paint.getAlpha() * .5f)); + canvas.drawPath(path, paint); + } + if (emojiTabs != null) { path.addCircle(emojiTabs.getLeft() + AndroidUtilities.dp(15), (emojiTabs.getTop() + emojiTabs.getBottom()) / 2f, AndroidUtilities.dp(15), Path.Direction.CW); } @@ -254,6 +278,9 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { setHorizontalScrollBarEnabled(false); addView(contentView); + if (type == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR) { + contentView.addView(toggleEmojiStickersTab = new EmojiTabButton(context, R.drawable.msg_emoji_stickers, false, false)); + } if (type == SelectAnimatedEmojiDialog.TYPE_TOPIC_ICON) { recentDrawableId = R.drawable.msg_emoji_smiles; } @@ -278,6 +305,11 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { } } + public void showSelected(boolean show) { + this.showSelected = show; + this.contentView.invalidate(); + } + private boolean recentFirstChange = true; private boolean recentIsShown = true; public void showRecent(boolean show) { @@ -297,6 +329,10 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { recentFirstChange = false; } + protected boolean doIncludeFeatured() { + return true; + } + private boolean isFreeEmojiPack(TLRPC.StickerSet set, ArrayList documents) { if (set == null || documents == null) { return false; @@ -363,6 +399,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { appearAnimation = null; } appearCount = emojiPacks.size(); + final boolean includeFeatured = doIncludeFeatured(); final boolean isPremium = UserConfig.getInstance(UserConfig.selectedAccount).isPremium() || allowEmojisForNonPremium(); for (int i = 0; i < emojipackTabs.size(); ++i) { EmojiTabButton emojipackTab = emojipackTabs.get(i); @@ -370,6 +407,9 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { if (emojipackTab != null && emojipackTab.id != null) { for (int j = 0; j < emojiPacks.size(); ++j) { EmojiView.EmojiPack p = emojiPacks.get(j); + if (!includeFeatured && p.featured) { + continue; + } final int id = Objects.hash(p.set.id, p.featured); if (id == emojipackTab.id) { pack = p; @@ -406,6 +446,9 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { } for (int i = 0; i < emojiPacks.size(); ++i) { EmojiView.EmojiPack pack = emojiPacks.get(i); + if (!includeFeatured && pack.featured) { + continue; + } final int id = Objects.hash(pack.set.id, pack.featured); EmojiTabButton emojipackTab = null; for (int j = 0; j < emojipackTabs.size(); ++j) { @@ -438,7 +481,9 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { drawable.addView(emojipackTab.imageView); } } - if (!isPremium && !free) { + if (currentType == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR) { + emojipackTab.setLock(null); + } else if (!isPremium && !free) { emojipackTab.setLock(true); } else if (!this.isInstalled(pack)) { emojipackTab.setLock(false); @@ -558,9 +603,13 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { public void select(int index, boolean animated) { animated = animated && !first; - if (!recentIsShown) { + if (toggleEmojiStickersTab != null) { + index++; + } + if (!recentIsShown || toggleEmojiStickersTab != null) { index = Math.max(1, index); } + selectedFullIndex = index; final int wasSelected = selected; for (int i = 0, j = 0; i < contentView.getChildCount(); ++i, ++j) { View child = contentView.getChildAt(i); @@ -603,7 +652,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { } if (emojiTabs != null) { - emojiTabs.show(selected == 1, animated); + emojiTabs.show(selected == 1 || forceTabsShow, animated); } View child = contentView.getChildAt(selected); @@ -1001,6 +1050,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { } public int maxWidth() { +// return AndroidUtilities.dp((30 + 2) * (clip() ? Math.min(5.7f, contentView.getChildCount()) : contentView.getChildCount())); return AndroidUtilities.dp((30 + 2) * Math.min(5.7f, contentView.getChildCount())); } @@ -1051,8 +1101,8 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { return super.onTouchEvent(ev); } - private boolean shown = false; - private float showT = 0f; + private boolean shown = forceTabsShow; + private float showT = forceTabsShow ? 1f : 0f; private ValueAnimator showAnimator; public void show(boolean show, boolean animated) { if (show == shown) { 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 cb5efca0f..f25b0179f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -8,6 +8,8 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -38,9 +40,12 @@ import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.text.Editable; +import android.text.Spannable; 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; @@ -102,6 +107,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; @@ -132,6 +138,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -144,6 +151,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private ArrayList allTabs = new ArrayList<>(); private ArrayList currentTabs = new ArrayList<>(); + private boolean ignorePagerScroll; private ViewPager pager; private FrameLayout bottomTabContainer; private FrameLayout bulletinContainer; @@ -290,6 +298,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private EmojiViewDelegate delegate; private long currentChatId; + boolean emojiBanned; + boolean stickersBanned; private TLRPC.StickerSetCovered[] primaryInstallingStickerSets = new TLRPC.StickerSetCovered[10]; private LongSparseArray installingStickerSets = new LongSparseArray<>(); @@ -468,13 +478,117 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } private ContentPreviewViewer.ContentPreviewViewerDelegate contentPreviewViewerDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { + @Override + public boolean can() { + return fragment != null; + } + @Override public void sendSticker(TLRPC.Document sticker, String query, Object parent, boolean notify, int scheduleDate) { delegate.onStickerSelected(null, sticker, query, parent, null, notify, scheduleDate); } @Override - public boolean needSend() { + public void resetTouch() { + if (emojiGridView != null) { + emojiGridView.clearAllTouches(); + } + } + + @Override + public void sendEmoji(TLRPC.Document emoji) { + if (fragment instanceof ChatActivity) { + ((ChatActivity) fragment).sendAnimatedEmoji(emoji, true, 0); + } + } + + @Override + public void setAsEmojiStatus(TLRPC.Document document, Integer until) { + TLRPC.EmojiStatus status; + if (document == null) { + status = new TLRPC.TL_emojiStatusEmpty(); + } else if (until != null) { + status = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) status).document_id = document.id; + ((TLRPC.TL_emojiStatusUntil) status).until = until; + } else { + status = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) status).document_id = document.id; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + final TLRPC.EmojiStatus previousEmojiStatus = user == null ? new TLRPC.TL_emojiStatusEmpty() : user.emoji_status; + MessagesController.getInstance(currentAccount).updateEmojiStatus(status); + + Runnable undoAction = () -> MessagesController.getInstance(currentAccount).updateEmojiStatus(previousEmojiStatus); + if (document == null) { + final Bulletin.SimpleLayout layout = new Bulletin.SimpleLayout(getContext(), resourcesProvider); + layout.textView.setText(LocaleController.getString("RemoveStatusInfo", R.string.RemoveStatusInfo)); + layout.imageView.setImageResource(R.drawable.msg_settings_premium); + layout.imageView.setScaleX(.8f); + layout.imageView.setScaleY(.8f); + layout.imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + Bulletin.UndoButton undoButton = new Bulletin.UndoButton(getContext(), true, resourcesProvider); + undoButton.setUndoAction(undoAction); + layout.setButton(undoButton); + if (fragment != null) { + Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT).show(); + } else { + Bulletin.make(bulletinContainer, layout, Bulletin.DURATION_SHORT).show(); + } + } else { + BulletinFactory factory = fragment != null ? BulletinFactory.of(fragment) : BulletinFactory.of(bulletinContainer, resourcesProvider); + factory.createEmojiBulletin(document, LocaleController.getString("SetAsEmojiStatusInfo", R.string.SetAsEmojiStatusInfo), LocaleController.getString("Undo", R.string.Undo), undoAction).show(); + } + } + + @Override + public void copyEmoji(TLRPC.Document document) { + Spannable spannable = SpannableStringBuilder.valueOf(MessageObject.findAnimatedEmojiEmoticon(document)); + spannable.setSpan(new AnimatedEmojiSpan(document, null), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (AndroidUtilities.addToClipboard(spannable)) { + BulletinFactory factory = fragment != null ? BulletinFactory.of(fragment) : BulletinFactory.of(bulletinContainer, resourcesProvider); + factory.createCopyBulletin(LocaleController.getString("EmojiCopied", R.string.EmojiCopied)).show(); + } + } + + @Override + public boolean needCopy() { + return true; + } + + @Override + public boolean needRemoveFromRecent(TLRPC.Document document) { + return document != null && Emoji.recentEmoji.contains("animated_" + document.id); + } + + @Override + public void removeFromRecent(TLRPC.Document document) { + if (document != null) { + Emoji.removeRecentEmoji("animated_" + document.id); + if (emojiAdapter != null) { + emojiAdapter.notifyDataSetChanged(); + } + } + } + + @Override + public Boolean canSetAsStatus(TLRPC.Document document) { + if (!UserConfig.getInstance(UserConfig.selectedAccount).isPremium()) { + return null; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + if (user == null) { + return null; + } + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + return document != null && (emojiStatusId == null || emojiStatusId != document.id); + } + + @Override + public boolean needSend(int contentType) { + if (contentType == ContentPreviewViewer.CONTENT_TYPE_EMOJI) { + return fragment instanceof ChatActivity && ((ChatActivity) fragment).canSendMessage() && (UserConfig.getInstance(UserConfig.selectedAccount).isPremium() || ((ChatActivity) fragment).getCurrentUser() != null && UserObject.isUserSelf(((ChatActivity) fragment).getCurrentUser())); + } return true; } @@ -557,55 +671,81 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private class SearchField extends FrameLayout { - private View searchBackground; - private ImageView searchIconImageView; - private ImageView clearSearchImageView; - private CloseProgressDrawable2 progressDrawable; + private int type; + private ImageView searchImageView; + private SearchStateDrawable searchStateDrawable; private EditTextBoldCursor searchEditText; private View shadowView; private View backgroundView; + private ImageView clear; + private FrameLayout box; private AnimatorSet shadowAnimator; + private StickerCategoriesListView categoriesListView; + private FrameLayout inputBox; + private View inputBoxGradient; + private StickerCategoriesListView.EmojiCategory recent; + private StickerCategoriesListView.EmojiCategory trending; + + @SuppressLint("ClickableViewAccessibility") public SearchField(Context context, int type) { super(context); + this.type = type; shadowView = new View(context); shadowView.setAlpha(0.0f); shadowView.setTag(1); shadowView.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); - addView(shadowView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, AndroidUtilities.getShadowHeight(), Gravity.BOTTOM | Gravity.LEFT)); + addView(shadowView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, AndroidUtilities.getShadowHeight(), Gravity.BOTTOM | Gravity.LEFT)); backgroundView = new View(context); backgroundView.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelBackground)); - addView(backgroundView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, searchFieldHeight)); + addView(backgroundView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, searchFieldHeight)); - searchBackground = new View(context); - searchBackground.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(18), getThemedColor(Theme.key_chat_emojiSearchBackground))); - addView(searchBackground, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, 14, 14, 14, 0)); + box = new FrameLayout(context); + box.setBackground(Theme.createRoundRectDrawable(dp(18), getThemedColor(Theme.key_chat_emojiSearchBackground))); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + box.setClipToOutline(true); + box.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), (int) dp(18)); + } + }); + } + if (type == 2) { + addView(box, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.FILL, 10, 8, 10, 8)); + } else { + addView(box, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.FILL, 10, 6, 10, 8)); + } - searchIconImageView = new ImageView(context); - searchIconImageView.setScaleType(ImageView.ScaleType.CENTER); - searchIconImageView.setImageResource(R.drawable.smiles_inputsearch); - searchIconImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiSearchIcon), PorterDuff.Mode.MULTIPLY)); - addView(searchIconImageView, LayoutHelper.createFrame(36, 36, Gravity.LEFT | Gravity.TOP, 16, 14, 0, 0)); + inputBox = new FrameLayout(context); + box.addView(inputBox, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.LEFT | Gravity.TOP, 38, 0, 0, 0)); - clearSearchImageView = new ImageView(context); - clearSearchImageView.setScaleType(ImageView.ScaleType.CENTER); - clearSearchImageView.setImageDrawable(progressDrawable = new CloseProgressDrawable2() { - @Override - protected int getCurrentColor() { - return getThemedColor(Theme.key_chat_emojiSearchIcon); + searchImageView = new ImageView(context); + searchStateDrawable = new SearchStateDrawable(); + searchStateDrawable.setIconState(SearchStateDrawable.State.STATE_SEARCH, false); + searchStateDrawable.setColor(getThemedColor(Theme.key_chat_emojiSearchIcon)); + searchImageView.setScaleType(ImageView.ScaleType.CENTER); + searchImageView.setImageDrawable(searchStateDrawable); + searchImageView.setOnClickListener(e -> { + if (searchStateDrawable.getIconState() == SearchStateDrawable.State.STATE_BACK) { + searchEditText.setText(""); + search(null, false); + if (categoriesListView != null) { + categoriesListView.scrollToStart(); + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(true, true); + } + toggleClear(false); + if (searchEditText != null) { + searchEditText.clearAnimation(); + searchEditText.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + showInputBoxGradient(false); } }); - progressDrawable.setSide(AndroidUtilities.dp(7)); - clearSearchImageView.setScaleX(0.1f); - clearSearchImageView.setScaleY(0.1f); - clearSearchImageView.setAlpha(0.0f); - addView(clearSearchImageView, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP, 14, 14, 14, 0)); - clearSearchImageView.setOnClickListener(v -> { - searchEditText.setText(""); - AndroidUtilities.showKeyboard(searchEditText); - }); + box.addView(searchImageView, LayoutHelper.createFrame(36, 36, Gravity.LEFT | Gravity.TOP)); searchEditText = new EditTextBoldCursor(context) { @Override @@ -633,49 +773,207 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific searchEditText.setLines(1); searchEditText.setSingleLine(true); searchEditText.setImeOptions(EditorInfo.IME_ACTION_SEARCH | EditorInfo.IME_FLAG_NO_EXTRACT_UI); - if (type == 0) { - searchEditText.setHint(LocaleController.getString("SearchStickersHint", R.string.SearchStickersHint)); - } else if (type == 1) { - searchEditText.setHint(LocaleController.getString("SearchEmojiHint", R.string.SearchEmojiHint)); - } else if (type == 2) { - searchEditText.setHint(LocaleController.getString("SearchGifsTitle", R.string.SearchGifsTitle)); - } + searchEditText.setHint(LocaleController.getString("Search", R.string.Search)); searchEditText.setCursorColor(getThemedColor(Theme.key_featuredStickers_addedIcon)); - searchEditText.setCursorSize(AndroidUtilities.dp(20)); + searchEditText.setCursorSize(dp(20)); searchEditText.setCursorWidth(1.5f); - addView(searchEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.LEFT | Gravity.TOP, 16 + 38, 12, 16 + 30, 0)); + searchEditText.setTranslationY(dp(-2)); + inputBox.addView(searchEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.LEFT | Gravity.TOP, 0, 0, 28, 0)); searchEditText.addTextChangedListener(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) { - boolean show = searchEditText.length() > 0; - boolean showed = clearSearchImageView.getAlpha() != 0; - if (show != showed) { - clearSearchImageView.animate() - .alpha(show ? 1.0f : 0.0f) - .setDuration(150) - .scaleX(show ? 1.0f : 0.1f) - .scaleY(show ? 1.0f : 0.1f) - .start(); + updateButton(); + final String query = searchEditText.getText().toString(); + search(query, true); + if (categoriesListView != null) { + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(TextUtils.isEmpty(query), true); } - if (type == 0) { - stickersSearchGridAdapter.search(searchEditText.getText().toString()); - } else if (type == 1) { - emojiSearchAdapter.search(searchEditText.getText().toString()); - } else if (type == 2) { - gifSearchAdapter.search(searchEditText.getText().toString()); + toggleClear(!TextUtils.isEmpty(query)); + if (searchEditText != null) { + searchEditText.clearAnimation(); + searchEditText.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); } + showInputBoxGradient(false); } }); + + inputBoxGradient = new View(context); + Drawable gradientDrawable = context.getResources().getDrawable(R.drawable.gradient_right).mutate(); + gradientDrawable.setColorFilter(new PorterDuffColorFilter(Theme.blendOver(getThemedColor(Theme.key_chat_emojiPanelBackground), getThemedColor(Theme.key_chat_emojiSearchBackground)), PorterDuff.Mode.MULTIPLY)); + inputBoxGradient.setBackground(gradientDrawable); + inputBoxGradient.setAlpha(0f); + inputBox.addView(inputBoxGradient, LayoutHelper.createFrame(18, LayoutHelper.MATCH_PARENT, Gravity.LEFT)); + + clear = new ImageView(context); + clear.setScaleType(ImageView.ScaleType.CENTER); + clear.setImageDrawable(new CloseProgressDrawable2(1.25f) { + { setSide(AndroidUtilities.dp(7)); } + @Override + protected int getCurrentColor() { + return Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider); + } + }); + clear.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), Theme.RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(15))); + clear.setAlpha(0f); + clear.setOnClickListener(e -> { + searchEditText.setText(""); + search(null, false); + if (categoriesListView != null) { + categoriesListView.scrollToStart(); + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(true, true); + } + toggleClear(false); + if (searchEditText != null) { + searchEditText.clearAnimation(); + searchEditText.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + showInputBoxGradient(false); + }); + box.addView(clear, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP)); + + if (type != 1 || allowAnimatedEmoji && UserConfig.getInstance(UserConfig.selectedAccount).isPremium()) { + categoriesListView = new StickerCategoriesListView(context, null, StickerCategoriesListView.CategoriesType.DEFAULT, resourcesProvider) { + @Override + public void selectCategory(int categoryIndex) { + super.selectCategory(categoryIndex); + showBottomTab(categoriesListView.getSelectedCategory() == null, true); + if (type == 1 && emojiTabs != null) { + emojiTabs.showSelected(categoriesListView.getSelectedCategory() == null); + } else if (type == 0 && stickersTab != null) { + stickersTab.showSelected(categoriesListView.getSelectedCategory() == null); + } + updateButton(); + } + + @Override + protected boolean isTabIconsAnimationEnabled(boolean loaded) { + return !SharedConfig.getLiteMode().enabled(); + } + }; + categoriesListView.setDontOccupyWidth((int) (searchEditText.getPaint().measureText(searchEditText.getHint() + "")) + dp(16)); + categoriesListView.setBackgroundColor(Theme.blendOver(getThemedColor(Theme.key_chat_emojiPanelBackground), getThemedColor(Theme.key_chat_emojiSearchBackground))); + categoriesListView.setOnScrollIntoOccupiedWidth(scrolled -> { + searchEditText.setTranslationX(-Math.max(0, scrolled)); + showInputBoxGradient(scrolled > 0); + updateButton(); + }); + categoriesListView.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + ignorePagerScroll = true; + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + ignorePagerScroll = false; + } + return false; + } + }); + categoriesListView.setOnCategoryClick(category -> { + if (category == recent) { + showInputBoxGradient(false); + categoriesListView.selectCategory(recent); + gifSearchField.searchEditText.setText(""); + gifLayoutManager.scrollToPositionWithOffset(0, 0); + return; + } else if (category == trending) { + showInputBoxGradient(false); + gifSearchField.searchEditText.setText(""); + gifLayoutManager.scrollToPositionWithOffset(gifAdapter.trendingSectionItem, -dp(4)); + categoriesListView.selectCategory(trending); + final ArrayList gifSearchEmojies = MessagesController.getInstance(currentAccount).gifSearchEmojies; + if (!gifSearchEmojies.isEmpty()) { + gifSearchPreloader.preload(gifSearchEmojies.get(0)); + } + return; + } + if (categoriesListView.getSelectedCategory() == category) { + search(null, false); + categoriesListView.selectCategory(null); + } else { + search(category.emojis, false); + categoriesListView.selectCategory(category); + } + }); + box.addView(categoriesListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, 36, 0, 0, 0)); + } + } + + public boolean isCategorySelected() { + return categoriesListView != null && categoriesListView.getSelectedCategory() != null; + } + + public void search(String text, boolean delay) { + if (type == 0) { + stickersSearchGridAdapter.search(text, delay); + } else if (type == 1) { + emojiSearchAdapter.search(text, delay); + } else if (type == 2) { + gifSearchAdapter.search(text, delay); + } + } + + private boolean inputBoxShown = false; + + private void showInputBoxGradient(boolean show) { + if (show == inputBoxShown || inputBoxGradient == null) { + return; + } + inputBoxShown = show; + inputBoxGradient.clearAnimation(); + inputBoxGradient.animate().alpha(show ? 1 : 0).setDuration(120).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + + public boolean isInProgress() { + return isprogress; + } + + private Runnable delayedToggle; + private void toggleClear(boolean enabled) { + if (enabled) { + if (delayedToggle == null) { + AndroidUtilities.runOnUIThread(delayedToggle = () -> { + AndroidUtilities.updateViewShow(clear, true); + }, 340); + } + } else { + if (delayedToggle != null) { + AndroidUtilities.cancelRunOnUIThread(delayedToggle); + delayedToggle = null; + } + AndroidUtilities.updateViewShow(clear, false); + } + } + + private boolean isprogress; + public void showProgress(boolean progress) { + isprogress = progress; + if (progress) { + searchStateDrawable.setIconState(SearchStateDrawable.State.STATE_PROGRESS); + } else { + updateButton(true); + } + } + + private void updateButton() { + updateButton(false); + } + + private void updateButton(boolean force) { + if (!isInProgress() || searchEditText.length() == 0 && (categoriesListView == null || categoriesListView.getSelectedCategory() == null) || force) { + boolean backButton = searchEditText.length() > 0 || categoriesListView != null && categoriesListView.isCategoriesShown() && (categoriesListView.isScrolledIntoOccupiedWidth() || categoriesListView.getSelectedCategory() != null); + searchStateDrawable.setIconState(backButton ? SearchStateDrawable.State.STATE_BACK : SearchStateDrawable.State.STATE_SEARCH); + isprogress = false; + } } public void hideKeyboard() { @@ -930,65 +1228,48 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } - private boolean premiumBulletin = true; - private class ImageViewEmoji extends ImageView { - public int position; - - public ImageReceiver imageReceiver; - public AnimatedEmojiDrawable drawable; - public boolean ignoring; - private boolean isRecent; - private AnimatedEmojiSpan span; - private EmojiPack pack; - private ImageReceiver.BackgroundThreadDrawHolder[] backgroundThreadDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; - float pressedProgress; - ValueAnimator backAnimator; - - public ImageViewEmoji(Context context) { - super(context); - setScaleType(ImageView.ScaleType.CENTER); - setBackground(Theme.createRadSelectorDrawable(getThemedColor(Theme.key_listSelector), AndroidUtilities.dp(2), AndroidUtilities.dp(2))); + private void sendEmoji(ImageViewEmoji imageViewEmoji, String override) { + if (imageViewEmoji == null) { + return; } - - private void sendEmoji(String override) { - if (getSpan() != null) { + if (imageViewEmoji.getSpan() != null) { // if (pack != null && pack.set != null && (pack.free || UserConfig.getInstance(currentAccount).isPremium())) { // openEmojiPackAlert(pack.set); // return; // } - if (delegate != null) { - long documentId = getSpan().documentId; - TLRPC.Document document = getSpan().document; - String emoticon = null; - if (document == null) { - for (int i = 0; i < emojipacksProcessed.size(); ++i) { - EmojiPack pack = emojipacksProcessed.get(i); - for (int j = 0; pack.documents != null && j < pack.documents.size(); ++j) { - if (pack.documents.get(j).id == documentId) { - document = pack.documents.get(j); - break; - } + if (delegate != null) { + long documentId = imageViewEmoji.getSpan().documentId; + TLRPC.Document document = imageViewEmoji.getSpan().document; + String emoticon = null; + if (document == null) { + for (int i = 0; i < emojipacksProcessed.size(); ++i) { + EmojiPack pack = emojipacksProcessed.get(i); + for (int j = 0; pack.documents != null && j < pack.documents.size(); ++j) { + if (pack.documents.get(j).id == documentId) { + document = pack.documents.get(j); + break; } } } - if (document == null) { - document = AnimatedEmojiDrawable.findDocument(currentAccount, documentId); - } - if (emoticon == null && document != null) { - emoticon = MessageObject.findAnimatedEmojiEmoticon(document); - } - if (!MessageObject.isFreeEmoji(document) && !UserConfig.getInstance(currentAccount).isPremium() && !(delegate != null && delegate.isUserSelf()) && !allowEmojisForNonPremium) { - showBottomTab(false, true); - BulletinFactory factory = fragment != null ? BulletinFactory.of(fragment) : BulletinFactory.of(bulletinContainer, resourcesProvider); - if (premiumBulletin || fragment == null) { - factory.createEmojiBulletin( + } + if (document == null) { + document = AnimatedEmojiDrawable.findDocument(currentAccount, documentId); + } + if (emoticon == null && document != null) { + emoticon = MessageObject.findAnimatedEmojiEmoticon(document); + } + if (!MessageObject.isFreeEmoji(document) && !UserConfig.getInstance(currentAccount).isPremium() && !(delegate != null && delegate.isUserSelf()) && !allowEmojisForNonPremium) { + showBottomTab(false, true); + BulletinFactory factory = fragment != null ? BulletinFactory.of(fragment) : BulletinFactory.of(bulletinContainer, resourcesProvider); + if (premiumBulletin || fragment == null) { + factory.createEmojiBulletin( document, AndroidUtilities.replaceTags(LocaleController.getString("UnlockPremiumEmojiHint", R.string.UnlockPremiumEmojiHint)), LocaleController.getString("PremiumMore", R.string.PremiumMore), EmojiView.this::openPremiumAnimatedEmojiFeature - ).show(); - } else { - factory.createSimpleBulletin( + ).show(); + } else { + factory.createSimpleBulletin( R.raw.saved_messages, AndroidUtilities.replaceTags(LocaleController.getString("UnlockPremiumEmojiHint2", R.string.UnlockPremiumEmojiHint2)), LocaleController.getString("Open", R.string.Open), @@ -1010,39 +1291,59 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } }); } - ).show(); - } - premiumBulletin = !premiumBulletin; - return; + ).show(); } - shownBottomTabAfterClick = SystemClock.elapsedRealtime(); - showBottomTab(true, true); - addEmojiToRecent("animated_" + documentId); - delegate.onCustomEmojiSelected(documentId, document, emoticon, isRecent); + premiumBulletin = !premiumBulletin; + return; } - return; + shownBottomTabAfterClick = SystemClock.elapsedRealtime(); + showBottomTab(true, true); + addEmojiToRecent("animated_" + documentId); + delegate.onCustomEmojiSelected(documentId, document, emoticon, imageViewEmoji.isRecent); } - shownBottomTabAfterClick = SystemClock.elapsedRealtime(); - showBottomTab(true, true); - String code = override != null ? override : (String) getTag(); - SpannableStringBuilder builder = new SpannableStringBuilder(); - builder.append(code); - if (override == null) { - if (!isRecent) { - String color = Emoji.emojiColor.get(code); - if (color != null) { - code = addColorToCode(code, color); - } - } - addEmojiToRecent(code); - if (delegate != null) { - delegate.onEmojiSelected(Emoji.fixEmoji(code)); - } - } else { - if (delegate != null) { - delegate.onEmojiSelected(Emoji.fixEmoji(override)); + return; + } + shownBottomTabAfterClick = SystemClock.elapsedRealtime(); + showBottomTab(true, true); + String code = override != null ? override : (String) imageViewEmoji.getTag(); + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(code); + if (override == null) { + if (!imageViewEmoji.isRecent) { + String color = Emoji.emojiColor.get(code); + if (color != null) { + code = addColorToCode(code, color); } } + addEmojiToRecent(code); + if (delegate != null) { + delegate.onEmojiSelected(Emoji.fixEmoji(code)); + } + } else { + if (delegate != null) { + delegate.onEmojiSelected(Emoji.fixEmoji(override)); + } + } + } + + private boolean premiumBulletin = true; + public static class ImageViewEmoji extends ImageView { + public int position; + + public ImageReceiver imageReceiver; + public AnimatedEmojiDrawable drawable; + public boolean ignoring; + private boolean isRecent; + private AnimatedEmojiSpan span; + private EmojiPack pack; + private ImageReceiver.BackgroundThreadDrawHolder[] backgroundThreadDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + float pressedProgress; + ValueAnimator backAnimator; + + public ImageViewEmoji(Context context) { + super(context); + setScaleType(ImageView.ScaleType.CENTER); + setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector), AndroidUtilities.dp(2), AndroidUtilities.dp(2))); } public void setImageDrawable(Drawable drawable, boolean recent) { @@ -1335,7 +1636,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific int color = getThemedColor(Theme.key_chat_emojiBottomPanelIcon); color = Color.argb(30, Color.red(color), Color.green(color), Color.blue(color)); - searchFieldHeight = AndroidUtilities.dp(64); + searchFieldHeight = AndroidUtilities.dp(50); needEmojiSearch = needSearch; tabIcons = new Drawable[]{ @@ -1405,6 +1706,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific emojiItemAnimator.setChangeDuration(160); emojiItemAnimator.setMoveInterpolator(CubicBezierInterpolator.EASE_OUT); emojiGridView.setItemAnimator(emojiItemAnimator); + emojiGridView.setOnTouchListener((v, event) -> ContentPreviewViewer.getInstance().onTouch(event, emojiGridView, EmojiView.this.getMeasuredHeight(), null, contentPreviewViewerDelegate, resourcesProvider)); emojiGridView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { @Override public boolean onItemClick(View view, int position) { @@ -1547,6 +1849,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific needEmojiSearch && position == 0 || position == emojiAdapter.trendingRow || position == emojiAdapter.trendingHeaderRow || + position == emojiAdapter.recentlyUsedHeaderRow || emojiAdapter.positionToSection.indexOfKey(position) >= 0 || emojiAdapter.positionToUnlock.indexOfKey(position) >= 0 ) { @@ -1626,11 +1929,22 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } + @Override + protected boolean doIncludeFeatured() { + return !(featuredEmojiSets.size() > 0 && featuredEmojiSets.get(0).set != null && MessagesController.getEmojiSettings(currentAccount).getLong("emoji_featured_hidden", 0) != featuredEmojiSets.get(0).set.id && UserConfig.getInstance(UserConfig.selectedAccount).isPremium()); + } + @Override protected boolean onTabClick(int index) { if (emojiSmoothScrolling) { return false; } + if (emojiSearchAdapter != null) { + emojiSearchAdapter.search(null); + } + if (emojiSearchField != null && emojiSearchField.categoriesListView != null) { + emojiSearchField.categoriesListView.selectCategory(null); + } Integer position = null; int offset = 0; if (index == 0) { @@ -1735,7 +2049,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific protected void onLayout(boolean changed, int l, int t, int r, int b) { if (firstGifAttach && gifAdapter.getItemCount() > 1) { ignoreLayout = true; - gifLayoutManager.scrollToPositionWithOffset(1, 0); + gifLayoutManager.scrollToPositionWithOffset(0, 0); gifSearchField.setVisibility(VISIBLE); gifTabs.onPageScrolled(0, 0); firstGifAttach = false; @@ -1765,17 +2079,17 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific return; } - if (position != 0) { + if (position != 0 || !gifAdapter.addSearch) { outRect.left = 0; outRect.bottom = 0; outRect.top = AndroidUtilities.dp(2); - outRect.right = gifLayoutManager.isLastInRow(position - 1) ? 0 : AndroidUtilities.dp(2); + outRect.right = gifLayoutManager.isLastInRow(position - (gifAdapter.addSearch ? 1 : 0)) ? 0 : AndroidUtilities.dp(2); } else { outRect.set(0, 0, 0, 0); } } }); - gifGridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); + gifGridView.setPadding(0, searchFieldHeight, 0, AndroidUtilities.dp(44)); gifGridView.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); ((SimpleItemAnimator) gifGridView.getItemAnimator()).setSupportsChangeAnimations(false); gifGridView.setAdapter(gifAdapter = new GifAdapter(context, true)); @@ -1786,7 +2100,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (delegate == null) { return; } - position--; + if (gifAdapter.addSearch) { + position--; + } if (gifGridView.getAdapter() == gifAdapter) { if (position < 0) { return; @@ -1816,7 +2132,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific gifContainer.addView(gifGridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); gifSearchField = new SearchField(context, 2); - gifSearchField.setVisibility(INVISIBLE); +// gifSearchField.setVisibility(INVISIBLE); gifContainer.addView(gifSearchField, new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, searchFieldHeight + AndroidUtilities.getShadowHeight())); gifTabs = new DraggableScrollSlidingTabStrip(context, resourcesProvider); @@ -1825,7 +2141,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific gifTabs.setIndicatorColor(getThemedColor(Theme.key_chat_emojiPanelStickerPackSelectorLine)); gifTabs.setUnderlineColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); gifTabs.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelBackground)); - gifContainer.addView(gifTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, StickerTabView.SMALL_HEIGHT, Gravity.LEFT | Gravity.TOP)); +// gifContainer.addView(gifTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, StickerTabView.SMALL_HEIGHT, Gravity.LEFT | Gravity.TOP)); updateGifTabs(); gifTabs.setDelegate(page -> { @@ -1907,7 +2223,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific protected void onLayout(boolean changed, int l, int t, int r, int b) { if (firstStickersAttach && stickersGridAdapter.getItemCount() > 0) { ignoreLayout = true; - stickersLayoutManager.scrollToPositionWithOffset(1, 0); + stickersLayoutManager.scrollToPositionWithOffset(0, 0); firstStickersAttach = false; ignoreLayout = false; } @@ -1922,8 +2238,15 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } super.requestLayout(); } - }; + @Override + public void onScrolled(int dx, int dy) { + super.onScrolled(dx, dy); + if (stickersTabContainer != null) { + stickersTab.setUnderlineHeight(stickersGridView.canScrollVertically(-1) ? AndroidUtilities.getShadowHeight() : 0); + } + } + }; stickersGridView.setLayoutManager(stickersLayoutManager = new GridLayoutManager(context, 5) { @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { @@ -1975,7 +2298,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } }); - stickersGridView.setPadding(0, AndroidUtilities.dp(4 + 36), 0, AndroidUtilities.dp(44)); + stickersGridView.setPadding(0, AndroidUtilities.dp(36), 0, AndroidUtilities.dp(44)); stickersGridView.setClipToPadding(false); Tab stickersTabHolder = new Tab(); @@ -2079,7 +2402,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific stickersTab.setDragEnabled(true); stickersTab.setWillNotDraw(false); stickersTab.setType(ScrollSlidingTabStrip.Type.TAB); - stickersTab.setUnderlineHeight(AndroidUtilities.getShadowHeight()); + stickersTab.setUnderlineHeight(stickersGridView.canScrollVertically(-1) ? AndroidUtilities.getShadowHeight() : 0); stickersTab.setIndicatorColor(getThemedColor(Theme.key_chat_emojiPanelStickerPackSelectorLine)); stickersTab.setUnderlineColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); @@ -2124,7 +2447,14 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (page == trendingTabNum) { openTrendingStickers(null); return; - } else if (page == recentTabNum) { + } + + if (stickersSearchField != null && stickersSearchField.isCategorySelected()) { + stickersSearchField.search(null, false); + stickersSearchField.categoriesListView.selectCategory(null); + } + + if (page == recentTabNum) { stickersGridView.stopScroll(); scrollStickersToPosition(stickersGridAdapter.getPositionForPack("recent"), 0); resetTabsY(Type.STICKERS); @@ -2178,6 +2508,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific pager = new ViewPager(context) { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { + if (ignorePagerScroll) { + return false; + } if (getParent() != null) { getParent().requestDisallowInterceptTouchEvent(canScrollHorizontally(-1)); } @@ -2198,12 +2531,12 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific animator.setDuration(150); animator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); animator.start(); - scrollEmojisToPosition(0, 0); + scrollEmojisToPosition(1, 0); if (emojiTabs != null) { emojiTabs.select(0); } } else if (item == 1) { - gifGridView.smoothScrollToPosition(1); + gifGridView.smoothScrollToPosition(0); } else { stickersGridView.smoothScrollToPosition(1); } @@ -2253,15 +2586,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific addView(bulletinContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 100, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, 0)); } - bottomTabContainer = new FrameLayout(context) { - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (getParent() != null) { - getParent().requestDisallowInterceptTouchEvent(true); - } - return super.onInterceptTouchEvent(ev); - } - }; + bottomTabContainer = new FrameLayout(context); + bottomTabContainer.setClickable(true); shadowLine = new View(context); shadowLine.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); @@ -2299,9 +2625,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific typeTabs = new PagerSlidingTabStrip(context, resourcesProvider); typeTabs.setViewPager(pager); typeTabs.setShouldExpand(false); - typeTabs.setIndicatorHeight(0); + typeTabs.setIndicatorHeight(AndroidUtilities.dp(3)); + typeTabs.setIndicatorColor(getThemedColor(Theme.key_chat_emojiPanelIconSelected)); typeTabs.setUnderlineHeight(0); - typeTabs.setTabPaddingLeftRight(AndroidUtilities.dp(10)); + typeTabs.setTabPaddingLeftRight(AndroidUtilities.dp(13)); bottomTabContainer.addView(typeTabs, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 40, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); typeTabs.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override @@ -2372,6 +2699,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific searchButton.setScaleType(ImageView.ScaleType.CENTER); searchButton.setContentDescription(LocaleController.getString("Search", R.string.Search)); searchButton.setFocusable(true); + searchButton.setVisibility(View.GONE); if (Build.VERSION.SDK_INT >= 21) { searchButton.setBackground(Theme.createSelectorDrawable(color, Theme.RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(18))); } @@ -2435,9 +2763,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific addView(pager, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); mediaBanTooltip = new CorrectlyMeasuringTextView(context); - mediaBanTooltip.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(3), getThemedColor(Theme.key_chat_gifSaveHintBackground))); + mediaBanTooltip.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(6), getThemedColor(Theme.key_chat_gifSaveHintBackground))); mediaBanTooltip.setTextColor(getThemedColor(Theme.key_chat_gifSaveHintText)); - mediaBanTooltip.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(7), AndroidUtilities.dp(8), AndroidUtilities.dp(7)); + mediaBanTooltip.setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(7), AndroidUtilities.dp(12), AndroidUtilities.dp(7)); mediaBanTooltip.setGravity(Gravity.CENTER_VERTICAL); mediaBanTooltip.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); mediaBanTooltip.setVisibility(INVISIBLE); @@ -2475,6 +2803,12 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific super(context); } + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = ContentPreviewViewer.getInstance().onInterceptTouchEvent(event, this, 0, contentPreviewViewerDelegate, resourcesProvider); + return super.onInterceptTouchEvent(event) || result; + } + private boolean ignoreLayout; SparseArray> viewsGroupedByLines = new SparseArray<>(); @@ -2511,7 +2845,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific protected void onLayout(boolean changed, int l, int t, int r, int b) { if (needEmojiSearch && firstEmojiAttach) { ignoreLayout = true; - emojiLayoutManager.scrollToPositionWithOffset(1, 0); + emojiLayoutManager.scrollToPositionWithOffset(0, 0); firstEmojiAttach = false; ignoreLayout = false; } @@ -2562,7 +2896,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific Emoji.emojiColor.remove(code); } emojiTouchedView.setImageDrawable(Emoji.getEmojiBigDrawable(code), emojiTouchedView.isRecent); - emojiTouchedView.sendEmoji(null); + sendEmoji(emojiTouchedView, null); try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception ignore) {} @@ -2574,11 +2908,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific .replace("\uD83C\uDFFD", "") .replace("\uD83C\uDFFE", "") .replace("\uD83C\uDFFF", ""); - if (color != null) { - emojiTouchedView.sendEmoji(addColorToCode(code, color)); + sendEmoji(emojiTouchedView, addColorToCode(code, color)); } else { - emojiTouchedView.sendEmoji(code); + sendEmoji(emojiTouchedView, code); } } } @@ -2688,7 +3021,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } } - } } @@ -2786,6 +3118,26 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } } + public void clearAllTouches() { + if (touches != null) { + for (Map.Entry e : touches.entrySet()) { + if (e != null) { + View view = e.getValue().view; + if (view != null) { + TouchDownInfo touch = touches.remove(e.getKey()); + if (touch != null) { + if (touch.view != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && touch.view.getBackground() instanceof RippleDrawable) { + touch.view.getBackground().setState(new int[]{}); + } + if (touch.view != null) { + touch.view.setPressed(false); + } + } + } + } + } + } + } public long animateExpandDuration() { return animateExpandAppearDuration() + animateExpandCrossfadeDuration() + 150; @@ -2980,15 +3332,16 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific (!pickerViewPopup.isShowing() || SystemClock.elapsedRealtime() - touch.time < ViewConfiguration.getLongPressTimeout()) ) { View view = touch.view; + int position = getChildAdapterPosition(touch.view); if (view instanceof ImageViewEmoji) { ImageViewEmoji viewEmoji = (ImageViewEmoji) view; - viewEmoji.sendEmoji(null); + sendEmoji(viewEmoji, null); try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception ignore) {} } else if (view instanceof EmojiPackExpand) { EmojiPackExpand button = (EmojiPackExpand) view; - emojiAdapter.expand(getChildAdapterPosition(button), button); + emojiAdapter.expand(position, button); try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception ignore) {} @@ -3162,7 +3515,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private void updateEmojiTabsPosition(int position) { if (!emojiSmoothScrolling && position != RecyclerView.NO_POSITION) { int tab = 0; - int count = getRecentEmoji().size() + (needEmojiSearch ? 1 : 0); + int count = getRecentEmoji().size() + (needEmojiSearch ? 1 : 0) + (emojiAdapter.trendingHeaderRow >= 0 ? 3 : 0); if (position >= count) { tab = -1; for (int a = 0; a < EmojiData.dataColored.length; a++) { @@ -3771,8 +4124,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific // if (parent.getChildAdapterPosition(view) == emojiAdapter.firstTrendingRow) { // outRect.top = AndroidUtilities.dp(32); // } - } else { - outRect.bottom = AndroidUtilities.dp(6); } } else if (view instanceof BackupImageView) { outRect.bottom = AndroidUtilities.dp(12); @@ -3862,22 +4213,21 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific updateBottomTabContainerPosition(); } private void updateBottomTabContainerPosition() { - if (bottomTabContainer.getTag() == null && (delegate == null || !delegate.isSearchOpened()) && (pager == null || pager.getCurrentItem() != 0)) { - View parent = (View) getParent(); - if (parent != null) { - float y = getY() - parent.getHeight(); - if (getLayoutParams().height > 0) { - y += getLayoutParams().height; - } else { - y += getMeasuredHeight(); - } - if (bottomTabContainer.getTop() - y < 0) { - y = bottomTabContainer.getTop(); - } - bottomTabContainer.setTranslationY(-y); - if (needEmojiSearch) { - bulletinContainer.setTranslationY(-y); - } + View parent = (View) getParent(); + if (parent != null) { + float y = getY() - parent.getHeight(); + if (getLayoutParams().height > 0) { + y += getLayoutParams().height; + } else { + y += getMeasuredHeight(); + } + if (bottomTabContainer.getTop() - y < 0) { + y = 0; + } + bottomTabMainTranslation = -y; + bottomTabContainer.setTranslationY(bottomTabMainTranslation + bottomTabAdditionalTranslation); + if (needEmojiSearch) { + bulletinContainer.setTranslationY(bottomTabMainTranslation + bottomTabAdditionalTranslation); } } } @@ -4014,7 +4364,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } else { if (position == 0) { - layoutManager.scrollToPositionWithOffset(1, 0); + layoutManager.scrollToPositionWithOffset(0, 0); } } } @@ -4075,7 +4425,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, AndroidUtilities.dp(0))); } else { searchAnimation.playTogether( - ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, -AndroidUtilities.dp(36)), + ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, a == 2 ? 0 : -AndroidUtilities.dp(36)), ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, AndroidUtilities.dp(0))); } searchAnimation.setDuration(220); @@ -4086,9 +4436,11 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (animation.equals(searchAnimation)) { gridView.setTranslationY(0); if (gridView == stickersGridView) { - gridView.setPadding(0, AndroidUtilities.dp(4), 0, 0); - } else if (gridView == emojiGridView || gridView == gifGridView) { gridView.setPadding(0, 0, 0, 0); + } else if (gridView == emojiGridView) { + gridView.setPadding(AndroidUtilities.dp(5), 0, AndroidUtilities.dp(5), 0); + } else if (gridView == gifGridView) { + gridView.setPadding(0, searchFieldHeight, 0, 0); } searchAnimation = null; } @@ -4109,8 +4461,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } if (gridView == stickersGridView) { gridView.setPadding(0, AndroidUtilities.dp(4), 0, 0); - } else if (gridView == emojiGridView || gridView == gifGridView) { - gridView.setPadding(0, 0, 0, 0); + } else if (gridView == emojiGridView) { + gridView.setPadding(AndroidUtilities.dp(5), 0, AndroidUtilities.dp(5), 0); + } else if (gridView == gifGridView) { + gridView.setPadding(0, searchFieldHeight, 0, 0); } if (gridView == gifGridView) { if (gifSearchAdapter.showTrendingWhenSearchEmpty = gifAdapter.results.size() > 0) { @@ -4123,6 +4477,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific layoutManager.scrollToPositionWithOffset(0, 0); } } + showBottomTab(false, true); } private void showEmojiShadow(boolean show, boolean animated) { @@ -4256,18 +4611,23 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } currentField.searchEditText.setText(""); + if (currentField.categoriesListView != null) { + currentField.categoriesListView.selectCategory(null); + currentField.categoriesListView.scrollToStart(); + } if (a == currentItem && animated) { searchAnimation = new AnimatorSet(); - if (tabStrip != null && a != 2) { + if (tabStrip != null && a != 1) { searchAnimation.playTogether( - ObjectAnimator.ofFloat(tabStrip, View.TRANSLATION_Y, 0), - ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, AndroidUtilities.dp(36) - searchFieldHeight), - ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, AndroidUtilities.dp(36) - searchFieldHeight)); + ObjectAnimator.ofFloat(tabStrip, View.TRANSLATION_Y, 0), + ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, AndroidUtilities.dp(36)), + ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, AndroidUtilities.dp(36)) + ); } else { searchAnimation.playTogether( - ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, AndroidUtilities.dp(36) - searchFieldHeight), - ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, -searchFieldHeight)); + ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, AndroidUtilities.dp(36) - searchFieldHeight) + ); } searchAnimation.setDuration(200); searchAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); @@ -4276,21 +4636,16 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific public void onAnimationEnd(Animator animation) { if (animation.equals(searchAnimation)) { int firstVisPos = layoutManager.findFirstVisibleItemPosition(); - int top = 0; - if (firstVisPos != RecyclerView.NO_POSITION) { - View firstVisView = layoutManager.findViewByPosition(firstVisPos); - top = (int) (firstVisView.getTop() + gridView.getTranslationY()); - } gridView.setTranslationY(0); if (gridView == stickersGridView) { - gridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); - } else if (gridView == gifGridView) { - gridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); - } else if (gridView == emojiGridView) { gridView.setPadding(0, AndroidUtilities.dp(36), 0, AndroidUtilities.dp(44)); + } else if (gridView == gifGridView) { + gridView.setPadding(0, searchFieldHeight, 0, AndroidUtilities.dp(44)); + } else if (gridView == emojiGridView) { + gridView.setPadding(AndroidUtilities.dp(5), AndroidUtilities.dp(36), AndroidUtilities.dp(5), AndroidUtilities.dp(44)); } if (firstVisPos != RecyclerView.NO_POSITION) { - layoutManager.scrollToPositionWithOffset(firstVisPos, top - gridView.getPaddingTop()); + layoutManager.scrollToPositionWithOffset(firstVisPos, 0); } searchAnimation = null; } @@ -4305,24 +4660,25 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific }); searchAnimation.start(); } else { - currentField.setTranslationY(AndroidUtilities.dp(36) - searchFieldHeight); + if (currentField != gifSearchField) { + currentField.setTranslationY(AndroidUtilities.dp(36) - searchFieldHeight); + } if (tabStrip != null && a != 2) { tabStrip.setTranslationY(0); } if (gridView == stickersGridView) { - gridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); + gridView.setPadding(0, AndroidUtilities.dp(36), 0, AndroidUtilities.dp(44)); } else if (gridView == gifGridView) { gridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); } else if (gridView == emojiGridView) { - gridView.setPadding(0, AndroidUtilities.dp(36), 0, AndroidUtilities.dp(44)); + gridView.setPadding(AndroidUtilities.dp(5), AndroidUtilities.dp(36), AndroidUtilities.dp(5), AndroidUtilities.dp(44)); } - layoutManager.scrollToPositionWithOffset(1, 0); + layoutManager.scrollToPositionWithOffset(0, 0); } } if (!animated) { delegate.onSearchOpenClose(0); } - showBottomTab(true, animated); } private void checkStickersSearchFieldScroll(boolean isLayout) { @@ -4442,33 +4798,45 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } + private ValueAnimator bottomTabContainerAnimator; + private float bottomTabMainTranslation, bottomTabAdditionalTranslation; private long shownBottomTabAfterClick; private void showBottomTab(boolean show, boolean animated) { lastBottomScrollDy = 0; - if (show && bottomTabContainer.getTag() == null || !show && bottomTabContainer.getTag() != null || delegate != null && delegate.isSearchOpened()) { + if (delegate != null && delegate.isSearchOpened()) { + show = false; + } + if (show && bottomTabContainer.getTag() == null || !show && bottomTabContainer.getTag() != null) { return; } - if (bottomTabContainerAnimation != null) { - bottomTabContainerAnimation.cancel(); - bottomTabContainerAnimation = null; + if (bottomTabContainerAnimator != null) { + bottomTabContainerAnimator.cancel(); + bottomTabContainerAnimator = null; } bottomTabContainer.setTag(show ? null : 1); if (animated) { - bottomTabContainerAnimation = new AnimatorSet(); - bottomTabContainerAnimation.playTogether( - ObjectAnimator.ofFloat(bottomTabContainer, View.TRANSLATION_Y, show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)), - ObjectAnimator.ofFloat(bulletinContainer, View.TRANSLATION_Y, needEmojiSearch ? (show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)) : bulletinContainer.getTranslationY()), - ObjectAnimator.ofFloat(shadowLine, View.TRANSLATION_Y, show ? 0 : AndroidUtilities.dp(45)) - ); - bottomTabContainerAnimation.setDuration(200); - bottomTabContainerAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT); - bottomTabContainerAnimation.start(); + bottomTabContainerAnimator = ValueAnimator.ofFloat(bottomTabAdditionalTranslation, show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)); + bottomTabContainerAnimator.addUpdateListener(anm -> { + bottomTabAdditionalTranslation = (float) anm.getAnimatedValue(); + updateBottomTabContainerPosition(); + }); + bottomTabContainerAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (bottomTabContainerAnimator != animation) { + return; + } + bottomTabAdditionalTranslation = (float) bottomTabContainerAnimator.getAnimatedValue(); + updateBottomTabContainerPosition(); + bottomTabContainerAnimator = null; + } + }); + bottomTabContainerAnimator.setDuration(380); + bottomTabContainerAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + bottomTabContainerAnimator.start(); } else { - bottomTabContainer.setTranslationY(show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)); - if (needEmojiSearch) { - bulletinContainer.setTranslationY(show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)); - } - shadowLine.setTranslationY(show ? 0 : AndroidUtilities.dp(45)); + bottomTabAdditionalTranslation = show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50); + updateBottomTabContainerPosition(); } } @@ -4554,6 +4922,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } private void animateSearchField(@Type int type, boolean visible, int tabsMinusDy) { + if (type == Type.GIFS) { + return; + } if (getListViewForType(type).findViewHolderForAdapterPosition(0) == null) { return; } @@ -4710,17 +5081,17 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (gifSearchField == null || gifGridView == null) { return; } - RecyclerView.ViewHolder holder = gifGridView.findViewHolderForAdapterPosition(0); - if (holder != null) { - gifSearchField.setTranslationY(holder.itemView.getTop()); - } else { - gifSearchField.setTranslationY(-searchFieldHeight); - } - gifSearchField.showShadow(false, !isLayout); +// RecyclerView.ViewHolder holder = gifGridView.findViewHolderForAdapterPosition(0); +// if (holder != null) { +// gifSearchField.setTranslationY(holder.itemView.getTop()); +// } else { +// gifSearchField.setTranslationY(-searchFieldHeight); +// } + gifSearchField.showShadow(true, !isLayout); } private void scrollGifsToTop() { - gifLayoutManager.scrollToPositionWithOffset(delegate != null && delegate.isExpanded() ? 0 : 1, 0); + gifLayoutManager.scrollToPositionWithOffset(0, 0); resetTabsY(Type.GIFS); } @@ -4919,13 +5290,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific stickerSets.add(pack); } - if (!premiumStickers.isEmpty()) { - premiumTabNum = stickersTabOffset; - stickersTabOffset++; - StickerTabView stickerTabView = stickersTab.addStickerIconTab(4, PremiumGradient.getInstance().premiumStarMenuDrawable2); - stickerTabView.textView.setText(LocaleController.getString("PremiumStickersShort", R.string.PremiumStickersShort)); - stickerTabView.setContentDescription(LocaleController.getString("PremiumStickers", R.string.PremiumStickers)); - } +// if (!premiumStickers.isEmpty()) { +// premiumTabNum = stickersTabOffset; +// stickersTabOffset++; +// StickerTabView stickerTabView = stickersTab.addStickerIconTab(4, PremiumGradient.getInstance().premiumStarMenuDrawable2); +// stickerTabView.textView.setText(LocaleController.getString("PremiumStickersShort", R.string.PremiumStickersShort)); +// stickerTabView.setContentDescription(LocaleController.getString("PremiumStickers", R.string.PremiumStickers)); +// } if (info != null) { long hiddenStickerSetId = MessagesController.getEmojiSettings(currentAccount).getLong("group_hide_stickers_" + info.id, -1); @@ -4974,9 +5345,21 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } else { TLRPC.TL_messages_stickerSet stickerSet = stickerSets.get(a); - TLRPC.Document document = stickerSet.documents.get(0); + TLRPC.Document document = null; + if (stickerSet.set != null && stickerSet.set.thumb_document_id != 0) { + for (int i = 0; i < stickerSet.documents.size(); ++i) { + TLRPC.Document d = stickerSet.documents.get(i); + if (d != null && stickerSet.set.thumb_document_id == d.id) { + document = d; + break; + } + } + } + if (document == null) { + document = stickerSet.documents.get(0); + } TLObject thumb = FileLoader.getClosestPhotoSizeWithSize(stickerSet.set.thumbs, 90); - if (thumb == null || stickerSet.set.gifs) { + if (thumb == null || stickerSet.set.gifs) { thumb = document; } stickersTab.addStickerTab(thumb, document, stickerSet).setContentDescription(stickerSet.set.title + ", " + LocaleController.getString("AccDescrStickerSet", R.string.AccDescrStickerSet)); @@ -5051,6 +5434,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (wasRecentTabSelected && !hasRecent) { gifTabs.selectTab(gifTrendingTabNum); + if (gifSearchField != null && gifSearchField.categoriesListView != null) { + gifSearchField.categoriesListView.selectCategory(gifSearchField.trending); + } } else if (ViewCompat.isLaidOut(gifTabs)) { if (hasRecent && !hadRecent) { gifTabs.onPageScrolled(lastPosition + 1, 0); @@ -5128,10 +5514,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } searchField.backgroundView.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelBackground)); searchField.shadowView.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); - searchField.clearSearchImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiSearchIcon), PorterDuff.Mode.MULTIPLY)); - searchField.searchIconImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiSearchIcon), PorterDuff.Mode.MULTIPLY)); - Theme.setDrawableColorByKey(searchField.searchBackground.getBackground(), Theme.key_chat_emojiSearchBackground); - searchField.searchBackground.invalidate(); + searchField.searchStateDrawable.setColor(getThemedColor(Theme.key_chat_emojiSearchIcon)); + Theme.setDrawableColorByKey(searchField.box.getBackground(), Theme.key_chat_emojiSearchBackground); + searchField.box.invalidate(); searchField.searchEditText.setHintTextColor(getThemedColor(Theme.key_chat_emojiSearchIcon)); searchField.searchEditText.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); } @@ -5255,31 +5640,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific lastNotifyWidth = right - left; reloadStickersAdapter(); } - View parent = (View) getParent(); - if (parent != null) { - int newHeight = bottom - top; - int newHeight2 = parent.getHeight(); - if (lastNotifyHeight != newHeight || lastNotifyHeight2 != newHeight2) { - if (delegate != null && delegate.isSearchOpened()) { - bottomTabContainer.setTranslationY(AndroidUtilities.dp(49)); - if (needEmojiSearch) { - bulletinContainer.setTranslationY(AndroidUtilities.dp(49)); - } - } else { - if (bottomTabContainer.getTag() == null) { - if (newHeight <= lastNotifyHeight) { - bottomTabContainer.setTranslationY(0); - if (needEmojiSearch) { - bulletinContainer.setTranslationY(0); - } - } - } - } - lastNotifyHeight = newHeight; - lastNotifyHeight2 = newHeight2; - } - } super.onLayout(changed, left, top, right, bottom); + updateBottomTabContainerPosition(); updateStickerTabsPosition(); } @@ -5318,9 +5680,12 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } public void onOpen(boolean forceEmoji) { - if (currentPage != 0 && currentChatId != 0) { + if (currentPage != 0 && stickersBanned) { currentPage = 0; } + if (currentPage == 0 && emojiBanned) { + currentPage = 1; + } if (currentPage == 0 || forceEmoji || currentTabs.size() == 1) { showBackspaceButton(true, false); showStickerSettingsButton(false, false); @@ -5343,7 +5708,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific stickersTab.selectTab(stickersTabOffset); } firstTabUpdate = false; - stickersLayoutManager.scrollToPositionWithOffset(1, 0); + stickersLayoutManager.scrollToPositionWithOffset(0, 0); } } else if (currentPage == 2) { showBackspaceButton(false, false); @@ -5354,7 +5719,11 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (gifTabs != null) { gifTabs.selectTab(0); } + if (gifSearchField != null && gifSearchField.categoriesListView != null) { + gifSearchField.categoriesListView.selectCategory(gifSearchField.recent); + } } + showBottomTab(true, true); } @Override @@ -5488,91 +5857,97 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } - public void setStickersBanned(boolean value, long chatId) { + public void setStickersBanned(boolean emojiBanned, boolean stickersBanned, long chatId) { if (typeTabs == null) { return; } - if (value) { + this.emojiBanned = emojiBanned; + this.stickersBanned = stickersBanned; + if (stickersBanned || emojiBanned) { currentChatId = chatId; } else { currentChatId = 0; } - View view = typeTabs.getTab(2); + View view = typeTabs.getTab(stickersBanned ? 2 : 0); if (view != null) { - view.setAlpha(currentChatId != 0 ? 0.5f : 1.0f); - if (currentChatId != 0 && pager.getCurrentItem() != 0) { - showBackspaceButton(true, true); - showStickerSettingsButton(false, true); - pager.setCurrentItem(0, false); + view.setAlpha(currentChatId != 0 ? 0.15f : 1.0f); + if (stickersBanned) { + if (currentChatId != 0 && pager.getCurrentItem() != 0) { + showBackspaceButton(true, true); + showStickerSettingsButton(false, true); + pager.setCurrentItem(0, false); + } + } else { + if (currentChatId != 0 && pager.getCurrentItem() != 1) { + showBackspaceButton(false, true); + showStickerSettingsButton(false, true); + pager.setCurrentItem(1, false); + } } } } - public void showStickerBanHint(boolean gif) { - if (mediaBanTooltip.getVisibility() == VISIBLE) { - return; - } + private AnimatorSet showStickersBanAnimator; + private Runnable hideStickersBan; + public void showStickerBanHint(boolean show, boolean emoji, boolean gif) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(currentChatId); if (chat == null) { return; } - String text; - if (!ChatObject.hasAdminRights(chat) && chat.default_banned_rights != null && chat.default_banned_rights.send_stickers) { - if (gif) { - mediaBanTooltip.setText(LocaleController.getString("GlobalAttachGifRestricted", R.string.GlobalAttachGifRestricted)); - } else { - mediaBanTooltip.setText(LocaleController.getString("GlobalAttachStickersRestricted", R.string.GlobalAttachStickersRestricted)); - } - } else { - if (chat.banned_rights == null) { - return; - } - if (AndroidUtilities.isBannedForever(chat.banned_rights)) { - if (gif) { - mediaBanTooltip.setText(LocaleController.getString("AttachGifRestrictedForever", R.string.AttachGifRestrictedForever)); + 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 (emoji) { + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachEmojiRestricted", R.string.GlobalAttachEmojiRestricted)); + } else if (gif) { + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachGifRestricted", R.string.GlobalAttachGifRestricted)); } else { - mediaBanTooltip.setText(LocaleController.getString("AttachStickersRestrictedForever", R.string.AttachStickersRestrictedForever)); + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachStickersRestricted", R.string.GlobalAttachStickersRestricted)); } } else { - if (gif) { - mediaBanTooltip.setText(LocaleController.formatString("AttachGifRestricted", R.string.AttachGifRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); - } else { - mediaBanTooltip.setText(LocaleController.formatString("AttachStickersRestricted", R.string.AttachStickersRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + if (chat.banned_rights == null) { + return; } - } - } - mediaBanTooltip.setVisibility(View.VISIBLE); - AnimatorSet AnimatorSet = new AnimatorSet(); - AnimatorSet.playTogether( - ObjectAnimator.ofFloat(mediaBanTooltip, View.ALPHA, 0.0f, 1.0f) - ); - AnimatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - AndroidUtilities.runOnUIThread(() -> { - if (mediaBanTooltip == null) { - return; + if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + if (emoji) { + mediaBanTooltip.setText(LocaleController.getString("AttachPlainRestrictedForever", R.string.AttachPlainRestrictedForever)); + } else if (gif) { + mediaBanTooltip.setText(LocaleController.getString("AttachGifRestrictedForever", R.string.AttachGifRestrictedForever)); + } else { + mediaBanTooltip.setText(LocaleController.getString("AttachStickersRestrictedForever", R.string.AttachStickersRestrictedForever)); } - AnimatorSet AnimatorSet1 = new AnimatorSet(); - AnimatorSet1.playTogether( - ObjectAnimator.ofFloat(mediaBanTooltip, View.ALPHA, 0.0f) - ); - AnimatorSet1.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation1) { - if (mediaBanTooltip != null) { - mediaBanTooltip.setVisibility(View.INVISIBLE); - } - } - }); - AnimatorSet1.setDuration(300); - AnimatorSet1.start(); - }, 5000); + } else { + if (emoji) { + mediaBanTooltip.setText(LocaleController.formatString("AttachPlainRestricted", R.string.AttachPlainRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + } if (gif) { + mediaBanTooltip.setText(LocaleController.formatString("AttachGifRestricted", R.string.AttachGifRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + } else { + mediaBanTooltip.setText(LocaleController.formatString("AttachStickersRestricted", R.string.AttachStickersRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + } + } } - }); - AnimatorSet.setDuration(300); - AnimatorSet.start(); + mediaBanTooltip.setVisibility(View.VISIBLE); + } + + if (showStickersBanAnimator != null) { + showStickersBanAnimator.cancel(); + showStickersBanAnimator = null; + } + + showStickersBanAnimator = new AnimatorSet(); + showStickersBanAnimator.playTogether( + ObjectAnimator.ofFloat(mediaBanTooltip, View.ALPHA, show ? mediaBanTooltip.getAlpha() : 1f, show ? 1f : 0f), + ObjectAnimator.ofFloat(mediaBanTooltip, View.TRANSLATION_Y, show ? AndroidUtilities.dp(12) : mediaBanTooltip.getTranslationY(), show ? 0 : AndroidUtilities.dp(12)) + ); + if (hideStickersBan != null) { + AndroidUtilities.cancelRunOnUIThread(hideStickersBan); + } + if (show) { + AndroidUtilities.runOnUIThread(hideStickersBan = () -> showStickerBanHint(false, emoji, gif), 3500); + } + showStickersBanAnimator.setDuration(320); + showStickersBanAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + showStickersBanAnimator.start(); } private void updateVisibleTrendingSets() { @@ -5709,7 +6084,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific gifTabs.invalidateTabs(); } } else if (id == NotificationCenter.newEmojiSuggestionsAvailable) { - if (emojiGridView != null && needEmojiSearch && (emojiSearchField.progressDrawable.isAnimating() || emojiGridView.getAdapter() == emojiSearchAdapter) && !TextUtils.isEmpty(emojiSearchAdapter.lastSearchEmojiString)) { + if (emojiGridView != null && needEmojiSearch && (emojiSearchField.searchStateDrawable.getIconState() == SearchStateDrawable.State.STATE_PROGRESS || emojiGridView.getAdapter() == emojiSearchAdapter) && !TextUtils.isEmpty(emojiSearchAdapter.lastSearchEmojiString)) { emojiSearchAdapter.search(emojiSearchAdapter.lastSearchEmojiString); } } else if (id == NotificationCenter.currentUserPremiumStatusChanged) { @@ -5744,18 +6119,20 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - TLRPC.StickerSetCovered set = (TLRPC.StickerSetCovered) getTag(); - if (MediaDataController.getInstance(currentAccount).isStickerPackUnread(emoji, set.set.id) && dotPaint != null) { - int x = canvas.getWidth() - AndroidUtilities.dp(8); - int y = AndroidUtilities.dp(14); - canvas.drawCircle(x, y, AndroidUtilities.dp(3), dotPaint); + if (!emoji) { + TLRPC.StickerSetCovered set = (TLRPC.StickerSetCovered) getTag(); + if (MediaDataController.getInstance(currentAccount).isStickerPackUnread(emoji, set.set.id) && dotPaint != null) { + int x = canvas.getWidth() - AndroidUtilities.dp(8); + int y = AndroidUtilities.dp(14); + canvas.drawCircle(x, y, AndroidUtilities.dp(3), dotPaint); + } } } }; - imageView.setSize(AndroidUtilities.dp(emoji ? 36 : 30), AndroidUtilities.dp(emoji ? 36 : 30)); + imageView.setSize(AndroidUtilities.dp(emoji ? 24 : 30), AndroidUtilities.dp(emoji ? 24 : 30)); imageView.setLayerNum(1); imageView.setAspectFit(true); - imageView.setLayoutParams(new RecyclerView.LayoutParams(AndroidUtilities.dp(42), AndroidUtilities.dp(42))); + imageView.setLayoutParams(new RecyclerView.LayoutParams(AndroidUtilities.dp(emoji ? 34 : 42), AndroidUtilities.dp(emoji ? 34 : 42))); return new RecyclerListView.Holder(imageView); } @@ -5765,10 +6142,44 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific TLRPC.StickerSetCovered set = (emoji ? featuredEmojiSets : featuredStickerSets).get(position); imageView.setTag(set); - TLRPC.Document document = set.cover; - if (!set.covers.isEmpty()) { - document = set.covers.get(0); + ArrayList setDocuments; + if (set instanceof TLRPC.TL_stickerSetFullCovered) { + setDocuments = ((TLRPC.TL_stickerSetFullCovered) set).documents; + } else if (set instanceof TLRPC.TL_stickerSetNoCovered) { + TLRPC.TL_messages_stickerSet fullSet = MediaDataController.getInstance(currentAccount).getStickerSet(MediaDataController.getInputStickerSet(set.set), false); + if (fullSet == null) { + setDocuments = null; + } else { + setDocuments = fullSet.documents; + } + } else { + setDocuments = set.covers; } + + TLRPC.Document document = null; + if (set.cover != null) { + document = set.cover; + } else if (setDocuments != null && !setDocuments.isEmpty()) { + if (set.set != null) { + for (int i = 0; i < setDocuments.size(); ++i) { + if (setDocuments.get(i).id == set.set.thumb_document_id) { + document = setDocuments.get(i); + break; + } + } + } + if (document == null) { + document = setDocuments.get(0); + } + } + if (document == null) { + return; + } + + if (this.emoji) { + imageView.setColorFilter(MessageObject.isTextColorEmoji(document) ? Theme.chat_animatedEmojiTextColorFilter : null); + } + TLObject object = FileLoader.getClosestPhotoSizeWithSize(set.set.thumbs, 90); SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(set.set.thumbs, Theme.key_emptyListPlaceholder, 0.2f); if (svgThumb != null) { @@ -5789,6 +6200,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } else { return; } + if (imageLocation == null) { return; } @@ -6132,7 +6544,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } case 5: { StickerSetNameCell cell = (StickerSetNameCell) holder.itemView; - cell.setText(MediaDataController.getInstance(currentAccount).loadFeaturedPremium ? LocaleController.getString("FeaturedStickersPremium", R.string.FeaturedStickersPremium) : LocaleController.getString("FeaturedStickers", R.string.FeaturedStickers), R.drawable.msg_close); + cell.setText(MediaDataController.getInstance(currentAccount).loadFeaturedPremium ? LocaleController.getString("FeaturedStickersPremium", R.string.FeaturedStickersPremium) : LocaleController.getString("FeaturedStickers", R.string.FeaturedStickers), R.drawable.msg_close, LocaleController.getString("AccDescrCloseTrendingStickers", R.string.AccDescrCloseTrendingStickers)); break; } } @@ -6178,8 +6590,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific documents = recentStickers; packStartPosition.put(key = "recent", totalItems); } else if (a == -1) { - documents = premiumStickers; - packStartPosition.put(key = "premium", totalItems); + continue; +// documents = premiumStickers; +// packStartPosition.put(key = "premium", totalItems); } else { key = null; pack = packs.get(a); @@ -6306,6 +6719,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private int trendingHeaderRow = -1; private int trendingRow = -1; private int firstTrendingRow = -1; + private int recentlyUsedHeaderRow = -1; private ArrayList frozenEmojiPacks; private ArrayList rowHashCodes = new ArrayList<>(); @@ -6317,10 +6731,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private int itemCount; public int plainEmojisCount; - void EmojiGridAdapter() { - MediaDataController mediaDataController = MediaDataController.getInstance(currentAccount); - } - @Override public int getItemCount() { return itemCount; @@ -6346,37 +6756,64 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific break; case VIEW_TYPE_HEADER: view = new StickerSetNameCell(getContext(), true, resourcesProvider); + ((StickerSetNameCell) view).setOnIconClickListener(e -> { + if (featuredEmojiSets == null || featuredEmojiSets.isEmpty() || featuredEmojiSets.get(0).set == null) { + return; + } + long lastSetId = featuredEmojiSets.get(0).set.id; + MessagesController.getEmojiSettings(currentAccount).edit().putLong("emoji_featured_hidden", lastSetId).commit(); + if (emojiAdapter != null) { + emojiAdapter.notifyItemRangeRemoved(1, 3); + } + if (emojiTabs != null) { + emojiTabs.updateEmojiPacks(getEmojipacks()); + } + updateRows(); + }); break; case VIEW_TYPE_PACK_HEADER: view = new EmojiPackHeader(getContext()); break; case VIEW_TYPE_TRENDING: TrendingListView listView = new TrendingListView(getContext(), trendingEmojiAdapter = new TrendingAdapter(true)); - listView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + listView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(4), AndroidUtilities.dp(8), 0); listView.setClipToPadding(false); listView.addItemDecoration(new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { - outRect.right = AndroidUtilities.dp(8); + outRect.right = AndroidUtilities.dp(2); } }); listView.setOnItemClickListener((item, position) -> { - ArrayList inputStickerSets = new ArrayList<>(); - List featuredStickerSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); - for (int i = 0; featuredStickerSets != null && i < featuredStickerSets.size(); ++i) { - TLRPC.StickerSetCovered set = featuredStickerSets.get(i); - if (set != null && set.set != null) { - TLRPC.TL_inputStickerSetID inputStickerSet = new TLRPC.TL_inputStickerSetID(); - inputStickerSet.id = set.set.id; - inputStickerSet.access_hash = set.set.access_hash; - inputStickerSets.add(inputStickerSet); + if (item.getTag() instanceof TLRPC.StickerSetCovered) { + TLRPC.StickerSetCovered highlightSet = (TLRPC.StickerSetCovered) item.getTag(); + ArrayList inputStickerSets = new ArrayList<>(); + ArrayList sets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + int highlight = -1; + for (int i = 0; i < sets.size(); ++i) { + TLRPC.StickerSetCovered set = sets.get(i); + if (set != null && set.set != null) { + TLRPC.TL_inputStickerSetID inputStickerSet = new TLRPC.TL_inputStickerSetID(); + inputStickerSet.id = set.set.id; + inputStickerSet.access_hash = set.set.access_hash; + inputStickerSets.add(inputStickerSet); + + if (highlightSet != null && highlightSet.set != null && highlightSet.set.id == set.set.id) { + highlight = i; + } + } + } + + MediaDataController.getInstance(currentAccount).markFeaturedStickersAsRead(true, true); + EmojiPacksAlert alert = new EmojiPacksAlert(fragment, getContext(), fragment == null ? null : fragment.getResourceProvider(), inputStickerSets); + if (highlight >= 0) { + alert.highlight(highlight); + } + if (fragment != null) { + fragment.showDialog(alert); + } else { + alert.show(); } - } - MediaDataController.getInstance(currentAccount).markFeaturedStickersAsRead(true, true); - if (fragment != null) { - fragment.showDialog(new EmojiPacksAlert(fragment, getContext(), fragment.getResourceProvider(), inputStickerSets)); - } else { - new EmojiPacksAlert(null, getContext(), resourcesProvider, inputStickerSets).show(); } }); view = listView; @@ -6413,6 +6850,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (needEmojiSearch) { position--; } + if (recentlyUsedHeaderRow >= 0) { + position--; + } if (trendingRow >= 0) { position -= 2; } @@ -6486,19 +6926,19 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific StickerSetNameCell cell = (StickerSetNameCell) holder.itemView; cell.position = position; index = positionToSection.get(position); - String text; if (position == trendingHeaderRow) { - text = LocaleController.getString("FeaturedEmojiPacks", R.string.FeaturedEmojiPacks); + cell.setText(LocaleController.getString("FeaturedEmojiPacks", R.string.FeaturedEmojiPacks), R.drawable.msg_close, LocaleController.getString("AccDescrCloseTrendingEmoji", R.string.AccDescrCloseTrendingEmoji)); + } else if (position == recentlyUsedHeaderRow) { + cell.setText(LocaleController.getString("RecentlyUsed", R.string.RecentlyUsed), 0); } else if (index >= emojiTitles.length) { try { - text = emojipacksProcessed.get(index - emojiTitles.length).set.title; + cell.setText(emojipacksProcessed.get(index - emojiTitles.length).set.title, 0); } catch (Exception ignore) { - text = ""; + cell.setText("", 0); } } else { - text = emojiTitles[index]; + cell.setText(emojiTitles[index], 0); } - cell.setText(text, 0); break; } case VIEW_TYPE_EXPAND: @@ -6563,7 +7003,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific public int getItemViewType(int position) { if (position == trendingRow) { return VIEW_TYPE_TRENDING; - } else if (position == trendingHeaderRow) { + } else if (position == trendingHeaderRow || position == recentlyUsedHeaderRow) { return VIEW_TYPE_HEADER; } else if (positionToSection.indexOfKey(position) >= 0) { return positionToSection.get(position) >= EmojiData.dataColored.length ? VIEW_TYPE_PACK_HEADER : VIEW_TYPE_HEADER; @@ -6758,17 +7198,20 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific packStartPosition.clear(); rowHashCodes.clear(); itemCount = 0; + boolean isPremium = UserConfig.getInstance(currentAccount).isPremium() || allowEmojisForNonPremium; if (needEmojiSearch) { itemCount++; rowHashCodes.add(-1); } -// if (featuredEmojiSets.size() > 0) { -// trendingHeaderRow = itemCount++; -// trendingRow = itemCount++; -// } else { -// trendingHeaderRow = -1; -// trendingRow = -1; -// } + if (isPremium && allowAnimatedEmoji && featuredEmojiSets.size() > 0 && featuredEmojiSets.get(0).set != null && MessagesController.getEmojiSettings(currentAccount).getLong("emoji_featured_hidden", 0) != featuredEmojiSets.get(0).set.id) { + trendingHeaderRow = itemCount++; + trendingRow = itemCount++; + recentlyUsedHeaderRow = itemCount++; + } else { + trendingHeaderRow = -1; + trendingRow = -1; + recentlyUsedHeaderRow = -1; + } ArrayList recent = getRecentEmoji(); if (emojiTabs != null) { emojiTabs.showRecent(!recent.isEmpty()); @@ -6788,7 +7231,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } - boolean isPremium = UserConfig.getInstance(currentAccount).isPremium() || allowEmojisForNonPremium; int maxlen = emojiLayoutManager.getSpanCount() * 3; plainEmojisCount = itemCount; firstTrendingRow = -1; @@ -7038,6 +7480,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific switch (holder.getItemViewType()) { case 0: { ImageViewEmoji imageView = (ImageViewEmoji) holder.itemView; + imageView.position = position; imageView.pack = null; String code; @@ -7093,6 +7536,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } public void search(String text) { + search(text, true); + } + + public void search(String text, boolean delay) { if (TextUtils.isEmpty(text)) { lastSearchEmojiString = null; if (emojiGridView.getAdapter() != emojiAdapter) { @@ -7107,11 +7554,11 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific AndroidUtilities.cancelRunOnUIThread(searchRunnable); } if (!TextUtils.isEmpty(lastSearchEmojiString)) { - AndroidUtilities.runOnUIThread(searchRunnable = new Runnable() { - @Override - public void run() { - emojiSearchField.progressDrawable.startAnimation(); - String query = lastSearchEmojiString; + emojiSearchField.showProgress(true); + AndroidUtilities.runOnUIThread(searchRunnable = () -> { + final LinkedHashSet documentIds = new LinkedHashSet<>(); + final String query = lastSearchEmojiString; + final Runnable fullSearch = () -> { String[] newLanguage = AndroidUtilities.getCurrentKeyboardLanguage(); if (!Arrays.equals(lastSearchKeyboardLanguage, newLanguage)) { MediaDataController.getInstance(currentAccount).fetchNewEmojiKeywords(newLanguage); @@ -7122,18 +7569,92 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific public void run(ArrayList param, String alias) { if (query.equals(lastSearchEmojiString)) { lastSearchAlias = alias; - emojiSearchField.progressDrawable.stopAnimation(); + emojiSearchField.showProgress(false); searchWas = true; if (emojiGridView.getAdapter() != emojiSearchAdapter) { emojiGridView.setAdapter(emojiSearchAdapter); } - result = param; + result.clear(); + searchByPackname(query, documentIds); + for (long documentId : documentIds) { + MediaDataController.KeywordResult r = new MediaDataController.KeywordResult(); + r.keyword = ""; + r.emoji = "animated_" + documentId; + result.add(r); + } + for (int i = 0; i < param.size(); ++i) { + MediaDataController.KeywordResult r = param.get(i); + if (r != null && r.emoji != null && (!r.emoji.startsWith("animated_") || !documentIds.contains(Long.parseLong(r.emoji.substring(9))))) { + result.add(r); + } + } notifyDataSetChanged(); } } - }, true); + }, null, true, false, true, 25); + }; + if (Emoji.fullyConsistsOfEmojis(query)) { + StickerCategoriesListView.search.fetch(UserConfig.selectedAccount, query, list -> { + if (list != null) { + documentIds.addAll(list.document_id); + } + fullSearch.run(); + }); + } else { + fullSearch.run(); } - }, 300); + }, delay ? 300 : 0); + } + } + + private ArrayList addedSets = new ArrayList<>(); + + private void searchByPackname(String query, LinkedHashSet documentIds) { + if (query == null || query.length() <= 3 || !UserConfig.getInstance(currentAccount).isPremium()) { + return; + } + String translitQuery = LocaleController.getInstance().getTranslitString(query).toLowerCase(); + + ArrayList sets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); + ArrayList featuredSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + addedSets.clear(); + + for (int i = 0; i < sets.size(); ++i) { + TLRPC.TL_messages_stickerSet fullSet = sets.get(i); + if (fullSet == null || fullSet.set == null) { + continue; + } + checkAddPackToResults(fullSet.set, fullSet.documents, translitQuery, documentIds); + } + for (int i = 0; i < featuredSets.size(); ++i) { + TLRPC.StickerSetCovered coveredSet = featuredSets.get(i); + if (coveredSet == null || coveredSet.set == null) { + continue; + } + if (coveredSet instanceof TLRPC.TL_stickerSetFullCovered) { + checkAddPackToResults(coveredSet.set, ((TLRPC.TL_stickerSetFullCovered) coveredSet).documents, translitQuery, documentIds); + } else if (coveredSet instanceof TLRPC.TL_stickerSetNoCovered) { + TLRPC.TL_inputStickerSetID inputStickerSetID = new TLRPC.TL_inputStickerSetID(); + inputStickerSetID.id = coveredSet.set.id; + TLRPC.TL_messages_stickerSet fullSet = MediaDataController.getInstance(currentAccount).getStickerSet(inputStickerSetID, true); + if (fullSet != null) { + checkAddPackToResults(fullSet.set, fullSet.documents, translitQuery, documentIds); + } + } else { + checkAddPackToResults(coveredSet.set, coveredSet.covers, translitQuery, documentIds); + } + } + } + + private void checkAddPackToResults(TLRPC.StickerSet set, ArrayList documents, String translitQuery, LinkedHashSet documentIds) { + if (set.title != null && !addedSets.contains(set.id) && LocaleController.getInstance().getTranslitString(set.title.toLowerCase()).contains(translitQuery)) { + for (TLRPC.Document document : documents) { + if (document == null) { + continue; + } + documentIds.add(document.id); + } + addedSets.add(set.id); } } } @@ -7146,8 +7667,12 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific @Override public boolean canScrollToTab(int position) { - if ((position == 1 || position == 2) && currentChatId != 0) { - showStickerBanHint(position == 1); + if ((position == 1 || position == 2) && stickersBanned) { + showStickerBanHint(true, false, position == 1); + return false; + } + if (position == 0 && emojiBanned) { + showStickerBanHint(true, true, false); return false; } return true; @@ -7158,7 +7683,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } public Drawable getPageIconDrawable(int position) { - return tabIcons[position]; + return null; +// return tabIcons[position]; } public CharSequence getPageTitle(int position) { @@ -7174,14 +7700,26 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } @Override - public void customOnDraw(Canvas canvas, int position) { - if (position == 2 && !MediaDataController.getInstance(currentAccount).getUnreadStickerSets().isEmpty() && dotPaint != null) { - int x = canvas.getWidth() / 2 + AndroidUtilities.dp(4 + 5); - int y = canvas.getHeight() / 2 - AndroidUtilities.dp(13 - 5); - canvas.drawCircle(x, y, AndroidUtilities.dp(5), dotPaint); + public int getTabPadding(int position) { + switch (position) { + case 0: + return AndroidUtilities.dp(18); + case 1: + case 2: + default: + return AndroidUtilities.dp(12); } } + @Override + public void customOnDraw(Canvas canvas, View view, int position) { +// if (position == 2 && !MediaDataController.getInstance(currentAccount).getUnreadStickerSets().isEmpty() && dotPaint != null) { +// int x = canvas.getWidth() - view.getPaddingRight(); +// int y = canvas.getHeight() / 2 - AndroidUtilities.dp(13 - 5); +// canvas.drawCircle(x, y, AndroidUtilities.dp(5), dotPaint); +// } + } + public Object instantiateItem(ViewGroup viewGroup, int position) { View view = currentTabs.get(position).view; viewGroup.addView(view); @@ -7219,6 +7757,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private int trendingSectionItem = -1; private int firstResultItem = -1; + private boolean addSearch; + private boolean showTrendingWhenSearchEmpty; public GifAdapter(Context context) { @@ -7248,7 +7788,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific @Override public int getItemViewType(int position) { - if (position == 0) { + if (position == 0 && addSearch) { return 1; // search field } else if (withRecent && position == trendingSectionItem) { return 2; // trending section @@ -7297,7 +7837,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (firstResultItem >= 0 && position >= firstResultItem) { cell.setLink(results.get(position - firstResultItem), bot, true, false, false, true); } else { - cell.setGif(recentGifs.get(position - 1), false); + cell.setGif(recentGifs.get(position - (addSearch ? 1 : 0)), false); } break; } @@ -7315,7 +7855,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific trendingSectionItem = -1; firstResultItem = -1; - itemsCount = 1; // search field + itemsCount = 0; + if (addSearch) { + itemsCount++;// search field + } if (withRecent) { itemsCount += recentItemsCount; @@ -7402,6 +7945,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } public void search(String text) { + search(text, true); + } + + public void search(String text, boolean delay) { if (withRecent) { return; } @@ -7439,13 +7986,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (!TextUtils.isEmpty(lastSearchImageString)) { AndroidUtilities.runOnUIThread(searchRunnable = () -> { search(text, "", true); - }, 300); + }, delay ? 300 : 0); } } public void searchEmoji(String emoji) { if (lastSearchIsEmoji && TextUtils.equals(lastSearchImageString, emoji)) { - gifLayoutManager.scrollToPositionWithOffset(1, 0); + gifLayoutManager.scrollToPositionWithOffset(0, 0); return; } search(emoji, "", true, true, true); @@ -7475,13 +8022,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (searchUser) { searchBotUser(); if (!withRecent) { - gifSearchField.progressDrawable.startAnimation(); + gifSearchField.showProgress(true); } } return; } if (!withRecent && TextUtils.isEmpty(offset)) { - gifSearchField.progressDrawable.startAnimation(); + gifSearchField.showProgress(true); } bot = (TLRPC.User) object; @@ -7516,7 +8063,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific req.bot = MessagesController.getInstance(currentAccount).getInputUser(bot); req.offset = offset; req.peer = new TLRPC.TL_inputPeerEmpty(); - reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors); + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate); } } @@ -7535,7 +8082,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (TextUtils.isEmpty(offset)) { results.clear(); resultsMap.clear(); - gifSearchField.progressDrawable.stopAnimation(); + gifSearchField.showProgress(false); } } @@ -7566,16 +8113,16 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific updateItems(); if (withRecent) { if (oldCount != 0) { - notifyItemChanged(recentItemsCount + 1 + oldCount); - notifyItemRangeInserted(recentItemsCount + 1 + oldCount + 1, addedCount); + notifyItemChanged(recentItemsCount + (gifAdapter.addSearch ? 1 : 0) + oldCount); + notifyItemRangeInserted(recentItemsCount + (gifAdapter.addSearch ? 1 : 0) + oldCount + 1, addedCount); } else { - notifyItemRangeInserted(recentItemsCount + 1, addedCount + 1); + notifyItemRangeInserted(recentItemsCount + (gifAdapter.addSearch ? 1 : 0), addedCount + 1); } } else { if (oldCount != 0) { notifyItemChanged(oldCount); } - notifyItemRangeInserted(oldCount + 1, addedCount); + notifyItemRangeInserted(oldCount + (gifAdapter.addSearch ? 1 : 0), addedCount); } } else { notifyDataSetChanged(); @@ -7662,10 +8209,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { - if (position == 0 || gifGridView.getAdapter() == gifSearchAdapter && gifSearchAdapter.results.isEmpty()) { + if (position == 0 && gifAdapter.addSearch || gifGridView.getAdapter() == gifSearchAdapter && gifSearchAdapter.results.isEmpty()) { return getSpanCount(); } - return getSpanSizeForItem(position - 1); + return getSpanSizeForItem(position - (gifAdapter.addSearch ? 1 : 0)); } }); } @@ -7762,13 +8309,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific imageView.setScaleType(ImageView.ScaleType.CENTER); imageView.setImageResource(R.drawable.gif_empty); imageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiPanelEmptyText), PorterDuff.Mode.MULTIPLY)); - addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 59)); + addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 8, 0, 0)); textView = new TextView(getContext()); textView.setText(LocaleController.getString("NoGIFsFound", R.string.NoGIFsFound)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); textView.setTextColor(getThemedColor(Theme.key_chat_emojiPanelEmptyText)); - addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 9)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 42, 0, 0)); progressView = new RadialProgressView(context, resourcesProvider); progressView.setVisibility(GONE); @@ -7828,34 +8375,43 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific boolean cleared; private String searchQuery; private Runnable searchRunnable = new Runnable() { + String query; + int lastId; - private void clear() { - if (cleared) { + final ArrayList serverPacks = new ArrayList<>(); + final ArrayList localPacks = new ArrayList<>(); + final HashMap localPacksByShortName = new HashMap<>(); + final HashMap localPacksByName = new HashMap<>(); + final HashMap, String> emojiStickers = new HashMap<>(); + final ArrayList> emojiArrays = new ArrayList<>(); + + final ArrayList emojiStickersArray = new ArrayList<>(0); + final LongSparseArray emojiStickersMap = new LongSparseArray<>(0); + + private void searchFinish() { + if (emojiSearchId != lastId) { return; } - cleared = true; - emojiStickers.clear(); - emojiArrays.clear(); - localPacks.clear(); - serverPacks.clear(); - localPacksByShortName.clear(); - localPacksByName.clear(); + + StickersSearchGridAdapter.this.localPacks = localPacks; + StickersSearchGridAdapter.this.serverPacks = serverPacks; + StickersSearchGridAdapter.this.localPacksByShortName = localPacksByShortName; + StickersSearchGridAdapter.this.localPacksByName = localPacksByName; + StickersSearchGridAdapter.this.emojiStickers = emojiStickers; + StickersSearchGridAdapter.this.emojiArrays = emojiArrays; + stickersSearchField.showProgress(false); + + if (stickersGridView.getAdapter() != stickersSearchGridAdapter) { + stickersGridView.setAdapter(stickersSearchGridAdapter); + } + notifyDataSetChanged(); } - @Override - public void run() { - if (TextUtils.isEmpty(searchQuery)) { - return; - } - stickersSearchField.progressDrawable.startAnimation(); - cleared = false; - int lastId = ++emojiSearchId; + private void addFromAllStickers(Runnable finished) { + final HashMap> allStickers = MediaDataController.getInstance(currentAccount).getAllStickers(); - final ArrayList emojiStickersArray = new ArrayList<>(0); - final LongSparseArray emojiStickersMap = new LongSparseArray<>(0); - HashMap> allStickers = MediaDataController.getInstance(currentAccount).getAllStickers(); - if (searchQuery.length() <= 14) { - CharSequence emoji = searchQuery; + if (query.length() <= 14) { + CharSequence emoji = query; int length = emoji.length(); for (int a = 0; a < length; a++) { if (a < length - 1 && (emoji.charAt(a) == 0xD83C && emoji.charAt(a + 1) >= 0xDFFB && emoji.charAt(a + 1) <= 0xDFFF || emoji.charAt(a) == 0x200D && (emoji.charAt(a + 1) == 0x2640 || emoji.charAt(a + 1) == 0x2642))) { @@ -7870,7 +8426,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } ArrayList newStickers = allStickers != null ? allStickers.get(emoji.toString()) : null; if (newStickers != null && !newStickers.isEmpty()) { - clear(); emojiStickersArray.addAll(newStickers); for (int a = 0, size = newStickers.size(); a < size; a++) { TLRPC.Document document = newStickers.get(a); @@ -7880,37 +8435,41 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific emojiArrays.add(emojiStickersArray); } } - if (allStickers != null && !allStickers.isEmpty() && searchQuery.length() > 1) { + finished.run(); + } + + private void addFromSuggestions(Runnable finished) { + final HashMap> allStickers = MediaDataController.getInstance(currentAccount).getAllStickers(); + + if (allStickers != null && !allStickers.isEmpty() && query.length() > 1) { String[] newLanguage = AndroidUtilities.getCurrentKeyboardLanguage(); if (!Arrays.equals(lastSearchKeyboardLanguage, newLanguage)) { MediaDataController.getInstance(currentAccount).fetchNewEmojiKeywords(newLanguage); } lastSearchKeyboardLanguage = newLanguage; - MediaDataController.getInstance(currentAccount).getEmojiSuggestions(lastSearchKeyboardLanguage, searchQuery, false, new MediaDataController.KeywordResultCallback() { - @Override - public void run(ArrayList param, String alias) { - if (lastId != emojiSearchId) { - return; - } - boolean added = false; - for (int a = 0, size = param.size(); a < size; a++) { - String emoji = param.get(a).emoji; - ArrayList newStickers = allStickers != null ? allStickers.get(emoji) : null; - if (newStickers != null && !newStickers.isEmpty()) { - clear(); - if (!emojiStickers.containsKey(newStickers)) { - emojiStickers.put(newStickers, emoji); - emojiArrays.add(newStickers); - added = true; - } + MediaDataController.getInstance(currentAccount).getEmojiSuggestions(lastSearchKeyboardLanguage, searchQuery, false, (param, alias) -> { + if (emojiSearchId != lastId) { + return; + } + + for (int a = 0, size = param.size(); a < size; a++) { + String emoji = param.get(a).emoji; + ArrayList newStickers = allStickers.get(emoji); + if (newStickers != null && !newStickers.isEmpty()) { + if (!emojiStickers.containsKey(newStickers)) { + emojiStickers.put(newStickers, emoji); + emojiArrays.add(newStickers); } } - if (added) { - notifyDataSetChanged(); - } } + finished.run(); }, false); + } else { + finished.run(); } + } + + private void addLocalPacks(Runnable finished) { ArrayList local = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_IMAGE); MessagesController.getInstance(currentAccount).filterPremiumStickers(local); int index; @@ -7918,13 +8477,11 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific TLRPC.TL_messages_stickerSet set = local.get(a); if ((index = AndroidUtilities.indexOfIgnoreCase(set.set.title, searchQuery)) >= 0) { if (index == 0 || set.set.title.charAt(index - 1) == ' ') { - clear(); localPacks.add(set); localPacksByName.put(set, index); } } else if (set.set.short_name != null && (index = AndroidUtilities.indexOfIgnoreCase(set.set.short_name, searchQuery)) >= 0) { if (index == 0 || set.set.short_name.charAt(index - 1) == ' ') { - clear(); localPacks.add(set); localPacksByShortName.put(set, true); } @@ -7936,48 +8493,50 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific TLRPC.TL_messages_stickerSet set = local.get(a); if ((index = AndroidUtilities.indexOfIgnoreCase(set.set.title, searchQuery)) >= 0) { if (index == 0 || set.set.title.charAt(index - 1) == ' ') { - clear(); localPacks.add(set); localPacksByName.put(set, index); } } else if (set.set.short_name != null && (index = AndroidUtilities.indexOfIgnoreCase(set.set.short_name, searchQuery)) >= 0) { if (index == 0 || set.set.short_name.charAt(index - 1) == ' ') { - clear(); localPacks.add(set); localPacksByShortName.put(set, true); } } } - if ((!localPacks.isEmpty() || !emojiStickers.isEmpty()) && stickersGridView.getAdapter() != stickersSearchGridAdapter) { - stickersGridView.setAdapter(stickersSearchGridAdapter); - } + finished.run(); + } + + private void searchStickerSets(Runnable finished) { final TLRPC.TL_messages_searchStickerSets req = new TLRPC.TL_messages_searchStickerSets(); - req.q = searchQuery; - reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - if (response instanceof TLRPC.TL_messages_foundStickerSets) { - AndroidUtilities.runOnUIThread(() -> { - if (req.q.equals(searchQuery)) { - clear(); - stickersSearchField.progressDrawable.stopAnimation(); - reqId = 0; - if (stickersGridView.getAdapter() != stickersSearchGridAdapter) { - stickersGridView.setAdapter(stickersSearchGridAdapter); - } - TLRPC.TL_messages_foundStickerSets res = (TLRPC.TL_messages_foundStickerSets) response; - serverPacks.addAll(res.sets); - notifyDataSetChanged(); - } - }); + req.q = query; + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (emojiSearchId != lastId) { + return; } - }); - if (Emoji.isValidEmoji(searchQuery)) { + + if (response instanceof TLRPC.TL_messages_foundStickerSets) { + reqId = 0; + TLRPC.TL_messages_foundStickerSets res = (TLRPC.TL_messages_foundStickerSets) response; + serverPacks.addAll(res.sets); + } + finished.run(); + })); + } + + private void searchStickers(Runnable finished) { + if (Emoji.fullyConsistsOfEmojis(searchQuery)) { final TLRPC.TL_messages_getStickers req2 = new TLRPC.TL_messages_getStickers(); - req2.emoticon = searchQuery; + req2.emoticon = query; req2.hash = 0; reqId2 = ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response, error) -> AndroidUtilities.runOnUIThread(() -> { - if (req2.emoticon.equals(searchQuery)) { - reqId2 = 0; + if (emojiSearchId != lastId) { + return; + } + + reqId2 = 0; + if (req2.emoticon.equals(query)) { if (!(response instanceof TLRPC.TL_messages_stickers)) { + finished.run(); return; } TLRPC.TL_messages_stickers res = (TLRPC.TL_messages_stickers) response; @@ -7995,12 +8554,48 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (oldCount == 0) { emojiArrays.add(emojiStickersArray); } - notifyDataSetChanged(); } } + finished.run(); })); + } else { + finished.run(); } - notifyDataSetChanged(); + } + + @Override + public void run() { + if (TextUtils.isEmpty(searchQuery)) { + if (stickersGridView.getAdapter() != stickersGridAdapter) { + stickersGridView.setAdapter(stickersGridAdapter); + } + notifyDataSetChanged(); + return; + } + lastId = ++emojiSearchId; + query = searchQuery; + + serverPacks.clear(); + localPacks.clear(); + localPacksByShortName.clear(); + localPacksByName.clear(); + emojiStickers.clear(); + emojiArrays.clear(); + + emojiStickersArray.clear(); + emojiStickersMap.clear(); + + stickersSearchField.showProgress(true); + + Utilities.raceCallbacks( + this::searchFinish, + + this::addFromAllStickers, + this::addFromSuggestions, + this::addLocalPacks, + this::searchStickerSets, + this::searchStickers + ); } }; @@ -8027,6 +8622,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } public void search(String text) { + search(text, true); + } + + public void search(String text, boolean delay) { if (reqId != 0) { ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); reqId = 0; @@ -8044,8 +8643,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific stickersGridView.setAdapter(stickersGridAdapter); } notifyDataSetChanged(); + stickersSearchField.showProgress(false); } else { searchQuery = text.toLowerCase(); + stickersSearchField.showProgress(true); } AndroidUtilities.cancelRunOnUIThread(searchRunnable); AndroidUtilities.runOnUIThread(searchRunnable, 300); @@ -8123,13 +8724,14 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific imageView.setScaleType(ImageView.ScaleType.CENTER); imageView.setImageResource(R.drawable.stickers_empty); imageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiPanelEmptyText), PorterDuff.Mode.MULTIPLY)); - frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 59)); + imageView.setTranslationY(-AndroidUtilities.dp(24)); + frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 42, 0, 28)); TextView textView = new TextView(context); textView.setText(LocaleController.getString("NoStickersFound", R.string.NoStickersFound)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); textView.setTextColor(getThemedColor(Theme.key_chat_emojiPanelEmptyText)); - frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 9)); + frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 42, 0, 9)); view = frameLayout; view.setLayoutParams(new RecyclerView.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java index c94c0c9c4..5bd4e387e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java @@ -166,7 +166,7 @@ public class ForwardingPreviewView extends FrameLayout { cell.drawCheckBox(canvas); canvas.save(); canvas.translate(cell.getX(), cell.getY()); - cell.drawMessageText(canvas, cell.getMessageObject().textLayoutBlocks, true, 1f, false); + cell.drawMessageText(canvas, cell.getMessageObject().textLayoutBlocks, cell.getMessageObject().textXOffset, true, 1f, false); if (cell.getCurrentMessagesGroup() != null || cell.getTransitionParams().animateBackgroundBoundsInner) { cell.drawNamesLayout(canvas, 1f); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java index 0c795fa19..116f276e8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java @@ -1960,7 +1960,9 @@ public class FragmentContextView extends FrameLayout implements NotificationCent } else { timeLayout = null; joinButton.setVisibility(VISIBLE); - if (call.call.rtmp_stream) { + if (!TextUtils.isEmpty(call.call.title)) { + titleTextView.setText(call.call.title, false); + } else if (call.call.rtmp_stream) { titleTextView.setText(LocaleController.getString(R.string.VoipChannelVoiceChat), false); } else if (ChatObject.isChannelOrGiga(chat)) { titleTextView.setText(LocaleController.getString("VoipChannelVoiceChat", R.string.VoipChannelVoiceChat), false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java index 13690d4ba..52bba9adb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java @@ -285,7 +285,7 @@ public class GestureDetector2 { if (mIsLongpressEnabled) { mHandler.removeMessages(LONG_PRESS); - mHandler.sendMessageAtTime(mHandler.obtainMessage(LONG_PRESS, 0, 0), mCurrentDownEvent.getDownTime() + ViewConfiguration.getLongPressTimeout()); + mHandler.sendMessageDelayed(mHandler.obtainMessage(LONG_PRESS, 0, 0), ViewConfiguration.getLongPressTimeout()); } mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); handled |= mListener.onDown(ev); @@ -316,7 +316,7 @@ public class GestureDetector2 { if (distance > slopSquare) { mHandler.removeMessages(LONG_PRESS); final long longPressTimeout = ViewConfiguration.getLongPressTimeout(); - mHandler.sendMessageAtTime(mHandler.obtainMessage(LONG_PRESS, 0, 0), ev.getDownTime() + (long) (longPressTimeout * multiplier)); + mHandler.sendMessageDelayed(mHandler.obtainMessage(LONG_PRESS, 0, 0), (long) (longPressTimeout * multiplier)); } slopSquare *= multiplier * multiplier; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java new file mode 100644 index 000000000..e3ed8cbfd --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java @@ -0,0 +1,106 @@ +package org.telegram.ui.Components; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; + +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Utilities; + +public class GradientTools { + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + int color1; + int color2; + int color3; + int color4; + + private final static int INTERNAL_WIDTH = 60; + private final static int INTERNAL_HEIGHT = 80; + + RectF bounds = new RectF(); + Shader shader; + Matrix matrix = new Matrix(); + + Bitmap gradientBitmap = null; + + int[] colors = new int[4]; + + public void setColors(int color1, int color2) { + setColors(color1, color2, 0, 0); + } + + public void setColors(int color1, int color2, int color3) { + setColors(color1, color2, color3, 0); + } + + public void setColors(int color1, int color2, int color3, int color4) { + if (shader != null && this.color1 == color1 && this.color2 == color2 && this.color3 == color3 && this.color4 == color4) { + return; + } + colors[0] = this.color1 = color1; + colors[1] = this.color2 = color2; + colors[2] = this.color3 = color3; + colors[3] = this.color4 = color4; + if (color2 == 0) { + paint.setShader(shader = null); + paint.setColor(color1); + } else if (color3 == 0) { + paint.setShader(shader = new LinearGradient(0, 0, 0, INTERNAL_HEIGHT, new int[]{color1, color2}, null, Shader.TileMode.CLAMP)); + } else { + if (gradientBitmap == null) { + gradientBitmap = Bitmap.createBitmap(INTERNAL_WIDTH, INTERNAL_HEIGHT, Bitmap.Config.ARGB_8888); + } + Utilities.generateGradient(gradientBitmap, true, 0, 0, gradientBitmap.getWidth(), gradientBitmap.getHeight(), gradientBitmap.getRowBytes(), colors); + paint.setShader(shader = new BitmapShader(gradientBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + } + updateBounds(); + } + + public void setBounds(RectF bounds) { + if (this.bounds.top == bounds.top && this.bounds.bottom == bounds.bottom && this.bounds.left == bounds.left && this.bounds.right == bounds.right) { + return; + } + this.bounds.set(bounds); + updateBounds(); + } + + private void updateBounds() { + if (shader == null) { + return; + } + float sx = bounds.width() / (float) INTERNAL_WIDTH; + float sy = bounds.height() / (float) INTERNAL_HEIGHT; + + matrix.reset(); + matrix.postTranslate(bounds.left, bounds.top); + matrix.preScale(sx, sy); + + shader.setLocalMatrix(matrix); + } + + public void setBounds(float left, float top, float right, float bottom) { + AndroidUtilities.rectTmp.set(left, top, right, bottom); + setBounds(AndroidUtilities.rectTmp); + } + + public int getAverageColor() { + int color = color1; + if (color2 != 0) { + color = ColorUtils.blendARGB(color, color2, 0.5f); + } + if (color3 != 0) { + color = ColorUtils.blendARGB(color, color3, 0.5f); + } + if (color4 != 0) { + color = ColorUtils.blendARGB(color, color4, 0.5f); + } + return color; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java index 211bb858e..d0f187617 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java @@ -37,6 +37,7 @@ import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; @@ -68,6 +69,10 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega ID_REMOVE_PHOTO = 3, ID_RECORD_VIDEO = 4; + public final static int FOR_TYPE_USER = 0; + public final static int FOR_TYPE_CHANNEL = 1; + public final static int FOR_TYPE_GROUP = 2; + public BaseFragment parentFragment; private ImageUpdaterDelegate delegate; private ChatAttachAlert chatAttachAlert; @@ -87,19 +92,23 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega private boolean clearAfterUpdate; private boolean useAttachMenu = true; private boolean openWithFrontfaceCamera; + private boolean supportEmojiMarkup; private boolean searchAvailable = true; private boolean uploadAfterSelect = true; private TLRPC.User user; + private boolean isUser; private TLRPC.InputFile uploadedPhoto; private TLRPC.InputFile uploadedVideo; + private TLRPC.VideoSize vectorMarkup; private double videoTimestamp; private boolean canSelectVideo; private boolean forceDarkTheme; private boolean showingFromDialog; private boolean canceled; + private boolean forUser; private final static int attach_photo = 0; @@ -108,6 +117,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega public final static int TYPE_SUGGEST_PHOTO_FOR_USER = 2; private int type; + public final int setForType; public void processEntry(MediaController.PhotoEntry photoEntry) { String path = null; @@ -128,6 +138,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega avatarObject = new MessageObject(UserConfig.selectedAccount, message, false, false); avatarObject.messageOwner.attachPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_avatar.mp4").getAbsolutePath(); avatarObject.videoEditedInfo = photoEntry.editedInfo; + avatarObject.emojiMarkup = photoEntry.emojiMarkup; bitmap = ImageLoader.loadBitmap(photoEntry.thumbPath, null, 800, 800, true); } else { bitmap = ImageLoader.loadBitmap(path, null, 800, 800, true); @@ -153,7 +164,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega } public interface ImageUpdaterDelegate { - void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo); + void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup); default String getInitialSearchString() { return null; @@ -198,9 +209,11 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega openWithFrontfaceCamera = value; } - public ImageUpdater(boolean allowVideo) { + public ImageUpdater(boolean allowVideo, int setForType, boolean supportEmojiMarkup) { imageReceiver = new ImageReceiver(null); canSelectVideo = allowVideo; + this.supportEmojiMarkup = supportEmojiMarkup; + this.setForType = setForType; } public void setCanSelectVideo(boolean canSelectVideo) { @@ -417,6 +430,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega if (type != 0) { chatAttachAlert.avatarFor(new AvatarFor(user, type)); } + chatAttachAlert.forUser = forUser; parentFragment.showDialog(chatAttachAlert); } @@ -457,6 +471,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega info.entities = photoEntry.entities; info.masks = photoEntry.stickers; info.ttl = photoEntry.ttl; + info.emojiMarkup = photoEntry.emojiMarkup; } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage searchImage = (MediaController.SearchImage) object; if (searchImage.imagePath != null) { @@ -526,6 +541,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega openSearch(); } }); + chatAttachAlert.setImageUpdater(this); } if (type == TYPE_SET_PHOTO_FOR_USER) { chatAttachAlert.getSelectedTextView().setText(LocaleController.formatString("SetPhotoFor", R.string.SetPhotoFor, user.first_name)); @@ -549,6 +565,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega avatarObject = new MessageObject(UserConfig.selectedAccount, message, false, false); avatarObject.messageOwner.attachPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_avatar.mp4").getAbsolutePath(); avatarObject.videoEditedInfo = info.videoEditedInfo; + avatarObject.emojiMarkup = info.emojiMarkup; bitmap = ImageLoader.loadBitmap(info.thumbPath, null, 800, 800, true); } else if (info.path != null) { bitmap = ImageLoader.loadBitmap(info.path, null, 800, 800, true); @@ -795,6 +812,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega uploadedPhoto = null; convertingVideo = null; videoPath = null; + vectorMarkup = avatarObject == null ? null : avatarObject.emojiMarkup; bigPhoto = ImageLoader.scaleAndSaveImage(bitmap, 800, 800, 80, false, 320, 320); smallPhoto = ImageLoader.scaleAndSaveImage(bitmap, 150, 150, 80, false, 150, 150); if (smallPhoto != null) { @@ -812,6 +830,18 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega uploadingImage = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + bigPhoto.location.volume_id + "_" + bigPhoto.location.local_id + ".jpg"; if (uploadAfterSelect) { if (avatarObject != null && avatarObject.videoEditedInfo != null) { + if (supportEmojiMarkup && !MessagesController.getInstance(currentAccount).uploadMarkupVideo) { + if (delegate != null) { + delegate.didStartUpload(true); + } + if (delegate != null) { + //skip upload step + delegate.didUploadPhoto(null, null, 0, null, bigPhoto, smallPhoto, isVideo, null); + delegate.didUploadPhoto(null, null, videoTimestamp, videoPath, bigPhoto, smallPhoto, isVideo, vectorMarkup); + cleanup(); + } + return; + } convertingVideo = avatarObject; long startTime = avatarObject.videoEditedInfo.startTime < 0 ? 0 : avatarObject.videoEditedInfo.startTime; videoTimestamp = (avatarObject.videoEditedInfo.avatarStartTime - startTime) / 1000000.0; @@ -839,7 +869,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega } } if (delegate != null) { - delegate.didUploadPhoto(null, null, 0, null, bigPhoto, smallPhoto, isVideo); + delegate.didUploadPhoto(null, null, 0, null, bigPhoto, smallPhoto, isVideo, null); } } } @@ -887,7 +917,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega NotificationCenter.getInstance(currentAccount).removeObserver(ImageUpdater.this, NotificationCenter.fileUploadFailed); if (id == NotificationCenter.fileUploaded) { if (delegate != null) { - delegate.didUploadPhoto(uploadedPhoto, uploadedVideo, videoTimestamp, videoPath, bigPhoto, smallPhoto, isVideo); + delegate.didUploadPhoto(uploadedPhoto, uploadedVideo, videoTimestamp, videoPath, bigPhoto, smallPhoto, isVideo, vectorMarkup); } } cleanup(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java index de688ad17..66597f49f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java @@ -582,14 +582,14 @@ public class LinkSpanDrawable { } else if (pressedLink.getSpan() != null) { pressedLink.getSpan().onClick(this); } + pressedLink = null; + return true; } pressedLink = null; - return true; } if (event.getAction() == MotionEvent.ACTION_CANCEL) { links.clear(); pressedLink = null; - return true; } } return pressedLink != null || super.onTouchEvent(event); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java index fcf811331..0b72cd7e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java @@ -256,7 +256,6 @@ public class LoadingDrawable extends Drawable { rectF.inset(-strokePaint.getStrokeWidth(), -strokePaint.getStrokeWidth()); canvas.saveLayerAlpha(rectF, 255, Canvas.ALL_SAVE_FLAG); } - } if (appearByGradient) { int appearGradientWidthNow = Math.max(AndroidUtilities.dp(200), bounds.width() / 3); @@ -327,7 +326,9 @@ public class LoadingDrawable extends Drawable { canvas.restore(); } - invalidateSelf(); + if (!isDisappeared()) { + invalidateSelf(); + } } public void updateBounds() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java index f2bbb287f..b12cd4694 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java @@ -53,6 +53,7 @@ public class MotionBackgroundDrawable extends Drawable { private long lastUpdateTime; private WeakReference parentView; + private boolean ignoreInterpolator; private final CubicBezierInterpolator interpolator = new CubicBezierInterpolator(0.33, 0.0, 0.0, 1.0); private int translationY; @@ -268,7 +269,7 @@ public class MotionBackgroundDrawable extends Drawable { generateNextGradient(); } - private void generateNextGradient() { + public void generateNextGradient() { if (useLegacyBitmap && intensity < 0) { try { if (legacyBitmap != null) { @@ -294,9 +295,9 @@ public class MotionBackgroundDrawable extends Drawable { Utilities.generateGradient(currentBitmap, true, phase, 1f, currentBitmap.getWidth(), currentBitmap.getHeight(), currentBitmap.getRowBytes(), colors); invalidateLegacy = true; } - for (int i = 0; i < ANIMATION_CACHE_BITMAPS_COUNT; i++) { + for (int i = -1; i < ANIMATION_CACHE_BITMAPS_COUNT; i++) { float p = (i + 1) / (float) ANIMATION_CACHE_BITMAPS_COUNT; - Utilities.generateGradient(gradientToBitmap[i], true, phase, p, currentBitmap.getWidth(), currentBitmap.getHeight(), currentBitmap.getRowBytes(), colors); + Utilities.generateGradient(i < 0 ? gradientFromBitmap : gradientToBitmap[i], true, phase, p, currentBitmap.getWidth(), currentBitmap.getHeight(), currentBitmap.getRowBytes(), colors); } } @@ -892,11 +893,14 @@ public class MotionBackgroundDrawable extends Drawable { if (posAnimationProgress > 1.0f) { posAnimationProgress = 1.0f; } - if (animationProgressProvider == null) { + if (animationProgressProvider == null && !ignoreInterpolator) { progress = interpolator.getInterpolation(posAnimationProgress); } else { progress = posAnimationProgress; } + if (ignoreInterpolator && (progress == 0 || progress == 1)) { + ignoreInterpolator = false; + } if (stageBefore == 0 && progress > 0.25f || stageBefore == 1 && progress > 0.5f || stageBefore == 2 && progress > 0.75f) { @@ -941,11 +945,14 @@ public class MotionBackgroundDrawable extends Drawable { if (posAnimationProgress > 1.0f) { posAnimationProgress = 1.0f; } - if (animationProgressProvider == null) { + if (animationProgressProvider == null && !ignoreInterpolator) { progress = interpolator.getInterpolation(posAnimationProgress); } else { progress = posAnimationProgress; } + if (ignoreInterpolator && (progress == 0 || progress == 1)) { + ignoreInterpolator = false; + } if (rotationBack) { progress = 1.0f - progress; if (posAnimationProgress >= 1.0f) { @@ -1022,6 +1029,12 @@ public class MotionBackgroundDrawable extends Drawable { } public void setIndeterminateAnimation(boolean isIndeterminateAnimation) { + if (!isIndeterminateAnimation && this.isIndeterminateAnimation) { + float progressPerPhase = 1f / 8f; + int phase = (int) (posAnimationProgress / progressPerPhase); + posAnimationProgress = 1f - (posAnimationProgress - phase * progressPerPhase) / progressPerPhase; + ignoreInterpolator = true; + } this.isIndeterminateAnimation = isIndeterminateAnimation; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/OverlayActionBarLayoutDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/OverlayActionBarLayoutDialog.java index 7b09d5c4f..cd6244648 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/OverlayActionBarLayoutDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/OverlayActionBarLayoutDialog.java @@ -2,6 +2,7 @@ package org.telegram.ui.Components; import android.app.Dialog; import android.content.Context; +import android.content.ContextWrapper; import android.graphics.Color; import android.os.Build; import android.os.Bundle; @@ -20,6 +21,7 @@ import org.telegram.messenger.R; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.LaunchActivity; import java.util.ArrayList; @@ -27,6 +29,7 @@ public class OverlayActionBarLayoutDialog extends Dialog implements INavigationL private Theme.ResourcesProvider resourcesProvider; private INavigationLayout actionBarLayout; private FrameLayout frameLayout; + private PasscodeView passcodeView; public OverlayActionBarLayoutDialog(@NonNull Context context, Theme.ResourcesProvider resourcesProvider) { super(context, R.style.TransparentDialog); @@ -46,9 +49,38 @@ public class OverlayActionBarLayoutDialog extends Dialog implements INavigationL actionBarLayout.setRemoveActionBarExtraHeight(true); VerticalPositionAutoAnimator.attach(actionBarLayout.getView()); } + passcodeView = new PasscodeView(context); + frameLayout.addView(passcodeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + setContentView(frameLayout); } + @Override + protected void onStart() { + super.onStart(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).addOverlayPasscodeView(passcodeView); + } + } + + @Override + protected void onStop() { + super.onStop(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).removeOverlayPasscodeView(passcodeView); + } + } + @Override public void onMeasureOverride(int[] measureSpec) { if (AndroidUtilities.isTablet() && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isSmallTablet()) { @@ -105,6 +137,13 @@ public class OverlayActionBarLayoutDialog extends Dialog implements INavigationL @Override public void onBackPressed() { + if (passcodeView.getVisibility() == View.VISIBLE) { + if (getOwnerActivity() != null) { + getOwnerActivity().finish(); + } + return; + } + actionBarLayout.onBackPressed(); if (actionBarLayout.getFragmentStack().size() <= 1) { dismiss(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PagerSlidingTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PagerSlidingTabStrip.java index e1d7ed532..8aa3f7e45 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PagerSlidingTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PagerSlidingTabStrip.java @@ -16,6 +16,8 @@ import android.graphics.Paint.Style; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.os.Build; +import android.util.TypedValue; +import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; @@ -23,6 +25,7 @@ import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.TextView; import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager.OnPageChangeListener; @@ -34,8 +37,9 @@ public class PagerSlidingTabStrip extends HorizontalScrollView { public interface IconTabProvider { Drawable getPageIconDrawable(int position); - void customOnDraw(Canvas canvas, int position); + void customOnDraw(Canvas canvas, View view, int position); boolean canScrollToTab(int position); + int getTabPadding(int position); } private LinearLayout.LayoutParams defaultTabLayoutParams; @@ -104,7 +108,14 @@ public class PagerSlidingTabStrip extends HorizontalScrollView { tabCount = pager.getAdapter().getCount(); for (int i = 0; i < tabCount; i++) { if (pager.getAdapter() instanceof IconTabProvider) { - addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconDrawable(i), pager.getAdapter().getPageTitle(i)); + Drawable drawable = ((IconTabProvider) pager.getAdapter()).getPageIconDrawable(i); + if (drawable != null) { + addIconTab(i, drawable, pager.getAdapter().getPageTitle(i)); + } else { + addTab(i, pager.getAdapter().getPageTitle(i)); + } + } else { + addTab(i, pager.getAdapter().getPageTitle(i)); } } updateTabStyles(); @@ -131,7 +142,7 @@ public class PagerSlidingTabStrip extends HorizontalScrollView { protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (pager.getAdapter() instanceof IconTabProvider) { - ((IconTabProvider) pager.getAdapter()).customOnDraw(canvas, position); + ((IconTabProvider) pager.getAdapter()).customOnDraw(canvas, this, position); } } @@ -166,6 +177,58 @@ public class PagerSlidingTabStrip extends HorizontalScrollView { tab.setContentDescription(contentDescription); } + private void addTab(final int position, CharSequence text) { + TextView tab = new TextView(getContext()) { + + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (pager.getAdapter() instanceof IconTabProvider) { + ((IconTabProvider) pager.getAdapter()).customOnDraw(canvas, this, position); + } + } + + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + Drawable background = getBackground(); + if (Build.VERSION.SDK_INT >= 21 && background != null) { + int color = getThemedColor(selected ? Theme.key_chat_emojiPanelIconSelected : Theme.key_chat_emojiBottomPanelIcon); + Theme.setSelectorDrawableColor(background, Color.argb(30, Color.red(color), Color.green(color), Color.blue(color)), true); + } + setTextColor(getThemedColor(selected ? Theme.key_chat_emojiPanelIconSelected : Theme.key_chat_emojiPanelBackspace)); + } + }; + tab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + tab.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + tab.setTextColor(getThemedColor(Theme.key_chat_emojiPanelBackspace)); + tab.setFocusable(true); + tab.setGravity(Gravity.CENTER); + if (Build.VERSION.SDK_INT >= 21) { + RippleDrawable rippleDrawable = (RippleDrawable) Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_emojiBottomPanelIcon), Theme.RIPPLE_MASK_CIRCLE_TO_BOUND_EDGE); + Theme.setRippleDrawableForceSoftware(rippleDrawable); + tab.setBackground(rippleDrawable); + } + tab.setText(text); + tab.setOnClickListener(v -> { + if (pager.getAdapter() instanceof IconTabProvider) { + if (!((IconTabProvider) pager.getAdapter()).canScrollToTab(position)) { + return; + } + } + pager.setCurrentItem(position, false); + }); + tab.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + tabsContainer.addView(tab, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 10, 0, 10, 0)); + tab.setSelected(position == currentPosition); + } + + private void updateTabStyles() { for (int i = 0; i < tabCount; i++) { View v = tabsContainer.getChildAt(i); @@ -173,6 +236,9 @@ public class PagerSlidingTabStrip extends HorizontalScrollView { if (shouldExpand) { v.setPadding(0, 0, 0, 0); v.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1.0F)); + } else if (pager.getAdapter() instanceof IconTabProvider) { + int padding = ((IconTabProvider) pager.getAdapter()).getTabPadding(i); + v.setPadding(padding, 0, padding, 0); } else { v.setPadding(tabPadding, 0, tabPadding, 0); } @@ -207,6 +273,9 @@ public class PagerSlidingTabStrip extends HorizontalScrollView { } } + private AnimatedFloat lineLeftAnimated = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private AnimatedFloat lineRightAnimated = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -219,26 +288,34 @@ public class PagerSlidingTabStrip extends HorizontalScrollView { if (underlineHeight != 0) { rectPaint.setColor(underlineColor); - canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint); + AndroidUtilities.rectTmp.set(0, height - underlineHeight, tabsContainer.getWidth(), height); + canvas.drawRoundRect(AndroidUtilities.rectTmp, underlineHeight / 2f, underlineHeight / 2f, rectPaint); } View currentTab = tabsContainer.getChildAt(currentPosition); if (currentTab != null) { - float lineLeft = currentTab.getLeft(); - float lineRight = currentTab.getRight(); + float lineLeft = currentTab.getLeft() + currentTab.getPaddingLeft(); + float lineRight = currentTab.getRight() - currentTab.getPaddingRight(); if (currentPositionOffset > 0f && currentPosition < tabCount - 1) { View nextTab = tabsContainer.getChildAt(currentPosition + 1); - final float nextTabLeft = nextTab.getLeft(); - final float nextTabRight = nextTab.getRight(); + final float nextTabLeft = nextTab.getLeft() + nextTab.getPaddingLeft(); + final float nextTabRight = nextTab.getRight() - nextTab.getPaddingRight(); lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft); lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight); + + lineLeftAnimated.set(lineLeft, true); + lineRightAnimated.set(lineRight, true); + } else { + lineLeft = lineLeftAnimated.set(lineLeft); + lineRight = lineRightAnimated.set(lineRight); } if (indicatorHeight != 0) { rectPaint.setColor(indicatorColor); - canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint); + AndroidUtilities.rectTmp.set(lineLeft, height - indicatorHeight, lineRight, height); + canvas.drawRoundRect(AndroidUtilities.rectTmp, indicatorHeight / 2f, indicatorHeight / 2f, rectPaint); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java index 56626b0ff..e66e5f243 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java @@ -789,12 +789,12 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh cancelButton = new PaintCancelView(context); cancelButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); - cancelButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider))); + cancelButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); bottomLayout.addView(cancelButton, LayoutHelper.createFrame(32, 32, Gravity.BOTTOM | Gravity.LEFT, 12, 0, 0, 4)); doneButton = new PaintDoneView(context); doneButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); - doneButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider))); + doneButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); doneButton.setOnClickListener(v -> { if (isColorListShown) { new ColorPickerBottomSheet(context, this.resourcesProvider).setColor(colorSwatch.color).setPipetteDelegate(new ColorPickerBottomSheet.PipetteDelegate() { @@ -1170,6 +1170,7 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh drawTab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); drawTab.setGravity(Gravity.CENTER_HORIZONTAL); drawTab.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + drawTab.setSingleLine(); drawTab.setOnClickListener(v -> { if (editingText) { selectEntity(null); @@ -1189,6 +1190,7 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh stickerTab.setGravity(Gravity.CENTER_HORIZONTAL); stickerTab.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); stickerTab.setAlpha(0.6f); + stickerTab.setSingleLine(); tabsLayout.addView(stickerTab, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f)); textTab = new TextView(context); @@ -1200,6 +1202,7 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh textTab.setGravity(Gravity.CENTER_HORIZONTAL); textTab.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); textTab.setAlpha(0.6f); + textTab.setSingleLine(); textTab.setOnClickListener(v -> { switchTab(2); if (!(currentEntityView instanceof TextPaintView)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java index 9a3eb170a..9f8a8ed17 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java @@ -65,6 +65,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.support.fingerprint.FingerprintManagerCompat; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.LaunchActivity; import java.util.ArrayList; import java.util.Collections; @@ -82,11 +83,19 @@ public class PasscodeView extends FrameLayout implements NotificationCenter.Noti if ((boolean) args[0] && SharedConfig.appLocked) { checkFingerprint(); } + } else if (id == NotificationCenter.passcodeDismissed) { + if (args[0] != this) { + setVisibility(GONE); + + if (fingerprintDialog != null) { + fingerprintDialog.dismiss(); + } + } } } public interface PasscodeViewDelegate { - void didAcceptedPassword(); + void didAcceptedPassword(PasscodeView view); } private static class AnimatingTextView extends FrameLayout { @@ -608,7 +617,9 @@ public class PasscodeView extends FrameLayout implements NotificationCenter.Noti backgroundSpringQueue.remove(callback); } for (int i : removeIndex) { - backgroundSpringNextQueue.remove(i); + if (i < backgroundSpringNextQueue.size()) { + backgroundSpringNextQueue.remove(i); + } } } } @@ -967,7 +978,7 @@ public class PasscodeView extends FrameLayout implements NotificationCenter.Noti NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetPasscode); setOnTouchListener(null); if (delegate != null) { - delegate.didAcceptedPassword(); + delegate.didAcceptedPassword(this); } AndroidUtilities.runOnUIThread(() -> { @@ -1105,6 +1116,7 @@ public class PasscodeView extends FrameLayout implements NotificationCenter.Noti super.onAttachedToWindow(); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didGenerateFingerprintKeyPair); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.passcodeDismissed); } @Override @@ -1112,6 +1124,7 @@ public class PasscodeView extends FrameLayout implements NotificationCenter.Noti super.onDetachedFromWindow(); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didGenerateFingerprintKeyPair); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.passcodeDismissed); } private void checkFingerprint() { @@ -1119,7 +1132,7 @@ public class PasscodeView extends FrameLayout implements NotificationCenter.Noti return; } Activity parentActivity = (Activity) getContext(); - if (parentActivity != null && fingerprintView.getVisibility() == VISIBLE && !ApplicationLoader.mainInterfacePaused) { + if (parentActivity != null && fingerprintView.getVisibility() == VISIBLE && !ApplicationLoader.mainInterfacePaused && (!(parentActivity instanceof LaunchActivity) || ((LaunchActivity) parentActivity).allowShowFingerprintDialog(this))) { try { if (fingerprintDialog != null && fingerprintDialog.isShowing()) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java index be397511b..90b978ea4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java @@ -255,7 +255,7 @@ public class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im final ArrayList limits = new ArrayList<>(); - PremiumGradient.GradientTools gradientTools; + PremiumGradient.PremiumGradientTools gradientTools; private int totalGradientHeight; ViewGroup containerView; @@ -263,7 +263,7 @@ public class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im public Adapter(int currentAccount, boolean drawHeader) { this.drawHeader = drawHeader; - gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); gradientTools.x1 = 0; gradientTools.y1 = 0; gradientTools.x2 = 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GiftPremiumBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GiftPremiumBottomSheet.java index 626208332..dfec32b74 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GiftPremiumBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GiftPremiumBottomSheet.java @@ -54,8 +54,8 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; public class GiftPremiumBottomSheet extends BottomSheetWithRecyclerListView { - private PremiumGradient.GradientTools gradientTools; - private PremiumGradient.GradientTools outlineGradient; + private PremiumGradient.PremiumGradientTools gradientTools; + private PremiumGradient.PremiumGradientTools outlineGradient; private PremiumButtonView premiumButtonView; private PremiumGiftTierCell dummyCell; @@ -78,7 +78,7 @@ public class GiftPremiumBottomSheet extends BottomSheetWithRecyclerListView { super(fragment, false, true); this.user = user; - gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, null, null); + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, null, null); gradientTools.exactly = true; gradientTools.x1 = 0; gradientTools.y1 = 0f; @@ -87,7 +87,7 @@ public class GiftPremiumBottomSheet extends BottomSheetWithRecyclerListView { gradientTools.cx = 0; gradientTools.cy = 0; - outlineGradient = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); + outlineGradient = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); outlineGradient.paint.setStyle(Paint.Style.STROKE); outlineGradient.paint.setStrokeWidth(AndroidUtilities.dp(1.5f)); @@ -216,8 +216,11 @@ public class GiftPremiumBottomSheet extends BottomSheetWithRecyclerListView { } private void updateButtonText(boolean animated) { + if (LocaleController.isRTL) { + animated = false; + } if (!BuildVars.useInvoiceBilling() && (!BillingController.getInstance().isReady() || giftTiers.get(selectedTierIndex).googlePlayProductDetails == null)) { - premiumButtonView.setButton(LocaleController.getString(R.string.Loading), v -> {}, true); + premiumButtonView.setButton(LocaleController.getString(R.string.Loading), v -> {}, !LocaleController.isRTL); premiumButtonView.setFlickerDisabled(true); return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java new file mode 100644 index 000000000..10d427030 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java @@ -0,0 +1,221 @@ +package org.telegram.ui.Components.Premium; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.Utilities; + +import java.util.ArrayList; +import java.util.HashMap; + +public class HelloParticles { + + private static String[] hellos = new String[] { + "Hello", "Привіт", "Привет", "Bonjour", "Hola", "Ciao", "Olá", "여보세요", "你好", "Salve", + "Sveiki", "Halo", "გამარჯობა", "Hallå", "Salam", "Tere", "Dia dhuit", "こんにちは", "Сайн уу", + "Bongu", "Ahoj", "γεια", "Zdravo", "नमस्ते", "Habari", "Hallo", "ជំរាបសួរ", "مرحبًا", "ನಮಸ್ಕಾರ", + "Салам", "Silav li wir", "سڵاو", "Kif inti", "Talofa", "Thobela", "हॅलो", "ሰላም", "Здраво", + "ഹലോ", "ہیلو", "ꯍꯦꯜꯂꯣ", "Alô", "வணக்கம்", "Mhoro", "Moni", "Alo", "สวัสดี", "Salom", "" + }; + + public static class Drawable { + + private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + + private float bitmapScale = 1; + private HashMap bitmaps = new HashMap<>(); + + public RectF rect = new RectF(); + public RectF screenRect = new RectF(); + public boolean paused; + private Paint paint = new Paint(); + + ArrayList particles = new ArrayList<>(); + public float speedScale = 1f; + + public final int count; + public boolean useGradient; + public int size1 = 14, size2 = 12, size3 = 10; + public long minLifeTime = 2000; + private int lastColor; + private final float dt = 1000 / AndroidUtilities.screenRefreshRate; + + public Drawable(int count) { + this.count = count; + textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textPaint.setColor(Color.WHITE); + switch (SharedConfig.getDevicePerformanceClass()) { + case SharedConfig.PERFORMANCE_CLASS_LOW: + bitmapScale = .25f; + break; + case SharedConfig.PERFORMANCE_CLASS_AVERAGE: + bitmapScale = .5f; + break; + case SharedConfig.PERFORMANCE_CLASS_HIGH: + default: + bitmapScale = .75f; + break; + } + textPaint.setTextSize(AndroidUtilities.dp(24 * bitmapScale)); + paint.setColor(Color.WHITE); + } + + public void init() { + if (particles.isEmpty()) { + for (int i = 0; i < count; i++) { + particles.add(new Drawable.Particle()); + } + } + } + + public void resetPositions() { + long time = System.currentTimeMillis(); + for (int i = 0; i < particles.size(); i++) { + particles.get(i).genPosition(time, i, true); + } + } + + public void onDraw(Canvas canvas) { + long time = System.currentTimeMillis(); + for (int i = 0; i < particles.size(); i++) { + Drawable.Particle particle = particles.get(i); + if (paused) { + particle.draw(canvas, i, pausedTime); + } else { + particle.draw(canvas, i, time); + } + if (particle.inProgress >= 1) { + particle.genPosition(time, i, false); + } + } + } + + public void recycle() { + for (Bitmap bitmap : bitmaps.values()) { + bitmap.recycle(); + } + bitmaps.clear(); + } + + long pausedTime; + + private class Particle { + private boolean set; + private float x, y; + private float vecX, vecY; + private int alpha; + private StaticLayout staticLayout; + private Bitmap bitmap; + private int l, w, h; + private long duration; + private float scale; + float inProgress; + + public void draw(Canvas canvas, int index, long time) { + + if (!paused) { + float speed = AndroidUtilities.dp(4) * (dt / 660f) * speedScale; +// x += vecX * speed; +// y += vecY * speed; + + if (inProgress != 1f) { + inProgress += dt / duration; + if (inProgress > 1f) { + inProgress = 1f; + } + } + } + + + if (bitmap != null) { + canvas.save(); + float t = 1f - 4f * (float) Math.pow(inProgress - .5f, 2f); + float s = scale / bitmapScale * (.7f + .4f * t); + canvas.translate(x - w / 2f, y - h / 2f); + canvas.scale(s, s, w / 2f, h / 2f); + paint.setAlpha((int) (alpha * t)); + canvas.drawBitmap(bitmap, 0, 0, paint); + canvas.restore(); + } + } + + public void genPosition(long time, int index, boolean reset) { + duration = 2250 + Math.abs(Utilities.fastRandom.nextLong() % 2250); + scale = .6f + .45f * Math.abs(Utilities.fastRandom.nextFloat()); + + String string = hellos[Math.abs(Utilities.fastRandom.nextInt() % hellos.length)]; + if (string.length() > 7) { + scale *= .6f; + } else if (string.length() > 5) { + scale *= .75f; + } + staticLayout = new StaticLayout(string, textPaint, AndroidUtilities.displaySize.x, Layout.Alignment.ALIGN_NORMAL, 1f, 0, false); + if (staticLayout.getLineCount() <= 0) { + l = w = h = 0; + } else { + l = (int) staticLayout.getLineLeft(0); + w = (int) staticLayout.getLineWidth(0); + h = staticLayout.getHeight(); + } + bitmap = bitmaps.get(string); + if (bitmap == null) { + bitmap = Bitmap.createBitmap(Math.max(1, w - Math.max(0, l)), Math.max(1, h), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.translate(-l, 0); + staticLayout.draw(canvas); + bitmaps.put(string, bitmap); + } + + float bestDistance = 0; + float minX = rect.left + w / 4f, maxX = rect.right - w / 4f; + if (index % 2 == 0) { + maxX = rect.centerX() - w / 2f; + } else { + minX = rect.centerX() + w / 2f; + } + float bestX = minX + Math.abs(Utilities.fastRandom.nextInt() % (maxX - minX)); + float bestY = rect.top + Math.abs(Utilities.fastRandom.nextInt() % rect.height()); + for (int k = 0; k < 10; k++) { + float randX = minX + Math.abs(Utilities.fastRandom.nextInt() % (maxX - minX)); + float randY = rect.top + Math.abs(Utilities.fastRandom.nextInt() % rect.height()); + float minDistance = Integer.MAX_VALUE; + for (int j = 0; j < particles.size(); j++) { + Particle p = particles.get(j); + if (!p.set) { + continue; + } + float rx = Math.min(Math.abs(p.x + p.w * (scale / bitmapScale) * 1.1f - randX), Math.abs(p.x - randX)); + float ry = p.y - randY; + float distance = rx * rx + ry * ry; + if (distance < minDistance) { + minDistance = distance; + } + } + if (minDistance > bestDistance) { + bestDistance = minDistance; + bestX = randX; + bestY = randY; + } + } + x = bestX; + y = bestY; + + double a = Math.atan2(x - rect.centerX(), y - rect.centerY()); + vecX = (float) Math.sin(a); + vecY = (float) Math.cos(a); + alpha = (int) (255 * ((50 + Utilities.fastRandom.nextInt(50)) / 100f)); + + inProgress = reset ? Math.abs((Utilities.fastRandom.nextFloat() % 1f) * .9f) : 0; + set = true; + } + } + } +} 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 95178df81..959474c7d 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 @@ -54,7 +54,7 @@ public class LimitPreviewView extends LinearLayout { TextView defaultCount; private float position; private View parentVideForGradient; - PremiumGradient.GradientTools staticGradient; + PremiumGradient.PremiumGradientTools staticGradient; int gradientYOffset; boolean wasHaptic; boolean animationCanPlay = true; @@ -283,7 +283,7 @@ public class LimitPreviewView extends LinearLayout { parentVideForGradient = containerView; } - public void setStaticGradinet(PremiumGradient.GradientTools gradientTools) { + public void setStaticGradinet(PremiumGradient.PremiumGradientTools gradientTools) { staticGradient = gradientTools; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java index bfc5c17ae..7e4ca9198 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java @@ -138,7 +138,7 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati setApplyBottomPadding(false); useBackgroundTopPadding = false; - PremiumGradient.GradientTools gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradientBottomSheet1, Theme.key_premiumGradientBottomSheet2, Theme.key_premiumGradientBottomSheet3, null); + PremiumGradient.PremiumGradientTools gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradientBottomSheet1, Theme.key_premiumGradientBottomSheet2, Theme.key_premiumGradientBottomSheet3, null); gradientTools.x1 = 0; gradientTools.y1 = 1.1f; gradientTools.x2 = 1.5f; @@ -234,7 +234,7 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati viewPager.setCurrentItem(selectedPosition); frameLayout.addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 100, 0, 0, 18, 0, 0)); - frameLayout.addView(closeLayout, LayoutHelper.createFrame(52, 52, Gravity.RIGHT | Gravity.TOP, 0, 16, 0, 0)); + frameLayout.addView(closeLayout, LayoutHelper.createFrame(52, 52, Gravity.RIGHT | Gravity.TOP, 0, 24, 0, 0)); BottomPagesView bottomPages = new BottomPagesView(getContext(), viewPager, premiumFeatures.size()); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @@ -621,6 +621,9 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_VOICE_TO_TEXT) { title.setText(LocaleController.getString(R.string.PremiumPreviewVoiceToText)); description.setText(LocaleController.getString(R.string.PremiumPreviewVoiceToTextDescription2)); + } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS) { + title.setText(LocaleController.getString(R.string.PremiumPreviewTranslations)); + description.setText(LocaleController.getString(R.string.PremiumPreviewTranslationsDescription)); } topViewOnFullHeight = false; } else { 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 4b24fc2fe..87825cb9e 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 @@ -23,7 +23,7 @@ import org.telegram.ui.ActionBar.Theme; public class PremiumGradient { - private final GradientTools mainGradient = new GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); + private final PremiumGradientTools mainGradient = new PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); // private final GradientTools grayGradient = new GradientTools(Theme.key_windowBackgroundWhiteGrayText7, Theme.key_windowBackgroundWhiteGrayText7, Theme.key_windowBackgroundWhiteGrayText7); private final Paint mainGradientPaint = mainGradient.paint; Paint lockedPremiumPaint; @@ -62,7 +62,7 @@ public class PremiumGradient { return createGradientDrawable(drawable, mainGradient); } - public InternalDrawable createGradientDrawable(Drawable drawable, PremiumGradient.GradientTools gradient) { + public InternalDrawable createGradientDrawable(Drawable drawable, PremiumGradientTools gradient) { if (drawable == null) { return null; } @@ -135,7 +135,9 @@ public class PremiumGradient { return mainGradientPaint; } } - public static class GradientTools { + + //help with update colors and position + public static class PremiumGradientTools { public float cx = 0.5f; public float cy = 0.5f; @@ -149,15 +151,15 @@ public class PremiumGradient { public float x1 = 0f, y1 = 1f, x2 = 1.5f, y2 = 0f; - public GradientTools(String colorKey1, String colorKey2, String colorKey3) { + public PremiumGradientTools(String colorKey1, String colorKey2, String colorKey3) { this(colorKey1, colorKey2, colorKey3, null, null); } - public GradientTools(String colorKey1, String colorKey2, String colorKey3, String colorKey4) { + public PremiumGradientTools(String colorKey1, String colorKey2, String colorKey3, String colorKey4) { this(colorKey1, colorKey2, colorKey3, colorKey4, null); } - public GradientTools(String colorKey1, String colorKey2, String colorKey3, String colorKey4, String colorKey5) { + public PremiumGradientTools(String colorKey1, String colorKey2, String colorKey3, String colorKey4, String colorKey5) { this.colorKey1 = colorKey1; this.colorKey2 = colorKey2; this.colorKey3 = colorKey3; @@ -165,7 +167,6 @@ public class PremiumGradient { this.colorKey5 = colorKey5; } - public void gradientMatrix(int x, int y, int x1, int y1, float xOffset, float yOffset) { chekColors(); if (exactly) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java index 2f8d73c46..1d101ea10 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java @@ -80,7 +80,7 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i int buttonRow; FireworksOverlay fireworksOverlay; - PremiumGradient.GradientTools gradientTools; + PremiumGradient.PremiumGradientTools gradientTools; StarParticlesView starParticlesView; GLIconTextureView iconTextureView; ViewGroup iconContainer; @@ -124,7 +124,7 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i buttonContainer.setVisibility(View.GONE); } - gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); gradientTools.exactly = true; gradientTools.x1 = 0; gradientTools.y1 = 1f; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumTierCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumTierCell.java index b4ce51be5..97c6265e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumTierCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumTierCell.java @@ -107,6 +107,15 @@ public class PremiumTierCell extends ViewGroup { setWillNotDraw(false); } + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + + titleView.setAlpha(enabled ? 1 : 0.6f); + pricePerMonthView.setAlpha(enabled ? 1 : 0.6f); + checkBox.setAlpha(enabled ? 1 : 0.6f); + } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -142,7 +151,7 @@ public class PremiumTierCell extends ViewGroup { checkRtlAndLayout(checkBox); int y = (int) ((getMeasuredHeight() - pricePerMonthView.getMeasuredHeight()) / 2f); - if (AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp + 24) + checkBox.getMeasuredWidth() + pricePerYearStrikeView.getMeasuredWidth() + pricePerYearView.getMeasuredWidth() + getPaddingLeft() > getMeasuredWidth() - pricePerMonthView.getMeasuredWidth() && discountView.getVisibility() == VISIBLE) { + if (AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp + 24) + checkBox.getMeasuredWidth() + (pricePerYearStrikeView.getVisibility() == VISIBLE ? pricePerYearStrikeView.getMeasuredWidth() : 0) + pricePerYearView.getMeasuredWidth() + getPaddingLeft() > getMeasuredWidth() - pricePerMonthView.getMeasuredWidth() && discountView.getVisibility() == VISIBLE) { y = getPaddingTop() + AndroidUtilities.dp(2); } AndroidUtilities.rectTmp2.set(getMeasuredWidth() - pricePerMonthView.getMeasuredWidth() - AndroidUtilities.dp(16) - getPaddingRight(), y, 0, 0); @@ -159,7 +168,7 @@ public class PremiumTierCell extends ViewGroup { AndroidUtilities.rectTmp2.set(AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp) + checkBox.getMeasuredWidth() + getPaddingLeft(), getMeasuredHeight() - pricePerYearStrikeView.getMeasuredHeight() - getPaddingBottom(), 0, 0); checkRtlAndLayout(pricePerYearStrikeView); - AndroidUtilities.rectTmp2.set(AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp + 6) + checkBox.getMeasuredWidth() + pricePerYearStrikeView.getMeasuredWidth() + getPaddingLeft(), getMeasuredHeight() - pricePerYearView.getMeasuredHeight() - getPaddingBottom(), 0, 0); + AndroidUtilities.rectTmp2.set(AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp) + checkBox.getMeasuredWidth() + (pricePerYearStrikeView.getVisibility() == VISIBLE ? pricePerYearStrikeView.getMeasuredWidth() + AndroidUtilities.dp(6) : 0) + getPaddingLeft(), getMeasuredHeight() - pricePerYearView.getMeasuredHeight() - getPaddingBottom(), 0, 0); checkRtlAndLayout(pricePerYearView); } @@ -197,8 +206,8 @@ public class PremiumTierCell extends ViewGroup { rect.bottom = rect.top + v.getMeasuredHeight(); if (LocaleController.isRTL) { int right = rect.right; - rect.right = rect.left; - rect.left = right; + rect.right = getWidth() - rect.left; + rect.left = getWidth() - right; } v.layout(AndroidUtilities.rectTmp2.left, AndroidUtilities.rectTmp2.top, AndroidUtilities.rectTmp2.right, AndroidUtilities.rectTmp2.bottom); } @@ -217,7 +226,7 @@ public class PremiumTierCell extends ViewGroup { discountView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY)); } pricePerYearStrikeView.measure(MeasureSpec.makeMeasureSpec(width - checkBox.getMeasuredWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); - pricePerYearView.measure(MeasureSpec.makeMeasureSpec(width - checkBox.getMeasuredWidth() - pricePerYearStrikeView.getMeasuredWidth() - AndroidUtilities.dp(6), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); + pricePerYearView.measure(MeasureSpec.makeMeasureSpec(width - checkBox.getMeasuredWidth() - (pricePerYearStrikeView.getVisibility() == VISIBLE ? pricePerYearStrikeView.getMeasuredWidth() : 0) - AndroidUtilities.dp(6), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); if (pricePerYearView.getVisibility() != VISIBLE) { height -= AndroidUtilities.dp(8); @@ -269,6 +278,11 @@ public class PremiumTierCell extends ViewGroup { pricePerYearStrikeView.setText(tier.getFormattedPricePerYearRegular()); pricePerYearView.setText(LocaleController.formatString(R.string.PricePerYear, tier.getFormattedPricePerYear())); pricePerMonthView.setText(LocaleController.formatString(R.string.PricePerMonthMe, tier.getFormattedPricePerMonth())); + + if (tier.subscriptionOption.current) { + pricePerYearView.setVisibility(VISIBLE); + pricePerYearView.setText(LocaleController.getString(R.string.YourCurrentPlan)); + } } else { discountView.setText(LocaleController.formatString(R.string.GiftPremiumOptionDiscount, 10)); discountView.setVisibility(VISIBLE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java index f59fac62f..3e94dfdc8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java @@ -67,12 +67,16 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, return; } - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - retriever.setDataSource(ApplicationLoader.applicationContext, Uri.fromFile(file)); - int width = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)); - int height = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)); - retriever.release(); - aspectRatio = width / (float) height; + try { + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(ApplicationLoader.applicationContext, Uri.fromFile(file)); + int width = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)); + int height = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)); + retriever.release(); + aspectRatio = width / (float) height; + } catch (Exception e) { + aspectRatio = 0.671f; + } } else { aspectRatio = 0.671f; } @@ -102,6 +106,7 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, private float roundRadius; StarParticlesView.Drawable starDrawable; SpeedLineParticles.Drawable speedLinesDrawable; + HelloParticles.Drawable helloParticlesDrawable; private final static float[] speedScaleVideoTimestamps = new float[]{0.02f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.02f}; private MatrixParticlesDrawable matrixParticlesDrawable; @@ -147,6 +152,9 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_DOWNLOAD_SPEED) { speedLinesDrawable = new SpeedLineParticles.Drawable(200); speedLinesDrawable.init(); + } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS) { + helloParticlesDrawable = new HelloParticles.Drawable(25); + helloParticlesDrawable.init(); } else { int particlesCount = 100; if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH) { @@ -188,7 +196,7 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), (int) (getMeasuredHeight() + roundRadius)); } float rad = roundRadius - AndroidUtilities.dp(3); - clipPath.addRoundRect(AndroidUtilities.rectTmp, new float[]{rad, rad, rad, rad, rad, rad, rad, rad}, Path.Direction.CW); + clipPath.addRoundRect(AndroidUtilities.rectTmp, rad, rad, Path.Direction.CW); } @Override @@ -339,13 +347,19 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, speedLinesDrawable.rect.offset(0, getMeasuredHeight() * 0.1f); speedLinesDrawable.resetPositions(); } + if (helloParticlesDrawable != null) { + helloParticlesDrawable.rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + helloParticlesDrawable.screenRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + helloParticlesDrawable.rect.inset(AndroidUtilities.dp(0), getMeasuredHeight() * 0.1f); + helloParticlesDrawable.resetPositions(); + } } } @Override protected void dispatchDraw(Canvas canvas) { - if ((starDrawable != null || speedLinesDrawable != null || matrixParticlesDrawable != null) && progress < 0.5f) { + if ((starDrawable != null || speedLinesDrawable != null || helloParticlesDrawable != null || matrixParticlesDrawable != null) && progress < 0.5f) { float s = (float) Math.pow(1f - progress, 2f); canvas.save(); canvas.scale(s, s, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); @@ -372,6 +386,8 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, float progressSpeedScale = 0.1f + 0.9f * (1f - Utilities.clamp(progress / 0.1f, 1f, 0)); speedLinesDrawable.speedScale = 150 * progressSpeedScale * videoSpeedScale; speedLinesDrawable.onDraw(canvas); + } else if (helloParticlesDrawable != null) { + helloParticlesDrawable.onDraw(canvas); } canvas.restore(); invalidate(); @@ -486,6 +502,10 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, attached = false; updateAttachState(); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileLoaded); + if (helloParticlesDrawable != null) { + helloParticlesDrawable.recycle(); + helloParticlesDrawable = null; + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java index 959b8b561..8b513a2d1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java @@ -25,6 +25,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.MessagesController; @@ -54,7 +55,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio private TLRPC.ChatFull chatInfo; private final Callback callback; - private boolean scrolledByUser; + public boolean scrolledByUser; private boolean isDownReleased; private final boolean isProfileFragment; private ImageLocation uploadingImageLocation; @@ -72,6 +73,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio private ArrayList videoLocations = new ArrayList<>(); private ArrayList imagesLocations = new ArrayList<>(); private ArrayList thumbsLocations = new ArrayList<>(); + private ArrayList vectorAvatars = new ArrayList<>(); private ArrayList imagesLocationsSizes = new ArrayList<>(); private ArrayList imagesUploadProgress = new ArrayList<>(); @@ -470,7 +472,11 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio } if (isSwipingViewPager) { - result |= super.onTouchEvent(ev); + try { + result |= super.onTouchEvent(ev); + } catch (Exception e) { + FileLog.e(e); + } } if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { @@ -486,7 +492,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio if (!photos.isEmpty() && photos.get(0) == null && chatInfo != null && FileLoader.isSamePhoto(imagesLocations.get(0).location, chatInfo.chat_photo)) { photos.set(0, chatInfo.chat_photo); if (!chatInfo.chat_photo.video_sizes.isEmpty()) { - final TLRPC.VideoSize videoSize = chatInfo.chat_photo.video_sizes.get(0); + final TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(chatInfo.chat_photo.video_sizes, 1000); videoLocations.set(0, ImageLocation.getForPhoto(videoSize, chatInfo.chat_photo)); videoFileNames.set(0, FileLoader.getAttachFileName(videoSize)); callback.onPhotosLoaded(); @@ -499,7 +505,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio } } - public boolean initIfEmpty(ImageLocation imageLocation, ImageLocation thumbLocation, boolean reload) { + public boolean initIfEmpty(VectorAvatarThumbDrawable vectorAvatar, ImageLocation imageLocation, ImageLocation thumbLocation, boolean reload) { if (imageLocation == null || thumbLocation == null || settingMainPhoto != 0) { return false; } @@ -524,6 +530,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio videoFileNames.add(null); imagesLocations.add(imageLocation); thumbsLocations.add(thumbLocation); + vectorAvatars.add(vectorAvatar); videoLocations.add(null); photos.add(null); imagesLocationsSizes.add(-1); @@ -542,6 +549,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio videoFileNames.add(0, null); imagesLocations.add(0, imageLocation); thumbsLocations.add(0, thumbLocation); + vectorAvatars.add(0, null); videoLocations.add(0, null); photos.add(0, null); imagesLocationsSizes.add(0, -1); @@ -722,6 +730,10 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio thumbsLocations.remove(index); thumbsLocations.add(0, location); + VectorAvatarThumbDrawable vectorAvatar = vectorAvatars.get(index); + vectorAvatars.remove(index); + vectorAvatars.add(0, vectorAvatar); + Integer size = imagesLocationsSizes.get(index); imagesLocationsSizes.remove(index); imagesLocationsSizes.add(0, size); @@ -748,6 +760,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio videoLocations.remove(index); imagesLocations.remove(index); thumbsLocations.remove(index); + vectorAvatars.remove(index); imagesLocationsSizes.remove(index); radialProgresses.delete(index); imagesUploadProgress.remove(index); @@ -808,6 +821,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio imagesLocations.clear(); videoLocations.clear(); thumbsLocations.clear(); + vectorAvatars.clear(); photos.clear(); imagesLocationsSizes.clear(); imagesUploadProgress.clear(); @@ -818,11 +832,12 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio if (currentImageLocation != null) { imagesLocations.add(currentImageLocation); thumbsLocations.add(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL)); + vectorAvatars.add(null); thumbsFileNames.add(null); if (chatInfo != null && FileLoader.isSamePhoto(currentImageLocation.location, chatInfo.chat_photo)) { photos.add(chatInfo.chat_photo); if (!chatInfo.chat_photo.video_sizes.isEmpty()) { - final TLRPC.VideoSize videoSize = chatInfo.chat_photo.video_sizes.get(0); + final TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(chatInfo.chat_photo.video_sizes, 1000); videoLocations.add(ImageLocation.getForPhoto(videoSize, chatInfo.chat_photo)); videoFileNames.add(FileLoader.getAttachFileName(videoSize)); } else { @@ -858,7 +873,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio if (size.location != null && size.location.local_id == currentImageLocation.location.local_id && size.location.volume_id == currentImageLocation.location.volume_id) { photos.set(0, photo); if (!photo.video_sizes.isEmpty()) { - videoLocations.set(0, ImageLocation.getForPhoto(photo.video_sizes.get(0), photo)); + videoLocations.set(0, ImageLocation.getForPhoto(FileLoader.getClosestVideoSizeWithSize(photo.video_sizes, 1000), photo)); } cont = true; break; @@ -879,13 +894,23 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio imagesLocations.add(location); thumbsFileNames.add(FileLoader.getAttachFileName(sizeThumb instanceof TLRPC.TL_photoStrippedSize ? sizeFull : sizeThumb)); thumbsLocations.add(ImageLocation.getForPhoto(sizeThumb, photo)); + if (!photo.video_sizes.isEmpty()) { - final TLRPC.VideoSize videoSize = photo.video_sizes.get(0); - videoLocations.add(ImageLocation.getForPhoto(videoSize, photo)); - videoFileNames.add(FileLoader.getAttachFileName(videoSize)); + final TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(photo.video_sizes, 1000); + final TLRPC.VideoSize vectorMarkupVideoSize = FileLoader.getVectorMarkupVideoSize(photo); + if (vectorMarkupVideoSize != null) { + vectorAvatars.add(new VectorAvatarThumbDrawable(vectorMarkupVideoSize, user != null && user.premium, VectorAvatarThumbDrawable.TYPE_PROFILE)); + videoLocations.add(null); + videoFileNames.add(null); + } else { + vectorAvatars.add(null); + videoLocations.add(ImageLocation.getForPhoto(videoSize, photo)); + videoFileNames.add(FileLoader.getAttachFileName(videoSize)); + } } else { videoLocations.add(null); videoFileNames.add(null); + vectorAvatars.add(null); } photos.add(photo); imagesLocationsSizes.add(sizeFull.size); @@ -1043,7 +1068,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio } else { ImageLocation videoLocation = videoLocations.get(imageLocationPosition); item.imageView.isVideo = videoLocation != null; - needProgress = true; + needProgress = vectorAvatars.get(imageLocationPosition) == null; String filter; if (isProfileFragment && videoLocation != null && videoLocation.imageType == FileLoader.IMAGE_TYPE_ANIMATION) { filter = "avatar"; @@ -1053,23 +1078,23 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio ImageLocation location = thumbsLocations.get(imageLocationPosition); Bitmap thumb = (parentAvatarImageView == null || !createThumbFromParent) ? null : parentAvatarImageView.getImageReceiver().getBitmap(); String parent = "avatar_" + dialogId; - if (thumb != null) { + if (thumb != null && vectorAvatars.get(imageLocationPosition) == null) { item.imageView.setImageMedia(videoLocations.get(imageLocationPosition), filter, imagesLocations.get(imageLocationPosition), null, thumb, imagesLocationsSizes.get(imageLocationPosition), 1, parent); } else if (uploadingImageLocation != null) { - item.imageView.setImageMedia(videoLocations.get(imageLocationPosition), filter, imagesLocations.get(imageLocationPosition), null, uploadingImageLocation, null, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); + item.imageView.setImageMedia(vectorAvatars.get(imageLocationPosition), videoLocations.get(imageLocationPosition), filter, imagesLocations.get(imageLocationPosition), null, uploadingImageLocation, null, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); } else { String thumbFilter = location.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; - item.imageView.setImageMedia(videoLocation, null, imagesLocations.get(imageLocationPosition), null, thumbsLocations.get(imageLocationPosition), thumbFilter, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); + item.imageView.setImageMedia(vectorAvatars.get(imageLocationPosition), videoLocation, null, imagesLocations.get(imageLocationPosition), null, thumbsLocations.get(imageLocationPosition), thumbFilter, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); } } } else { final ImageLocation videoLocation = videoLocations.get(imageLocationPosition); item.imageView.isVideo = videoLocation != null; - needProgress = true; + needProgress = vectorAvatars.get(imageLocationPosition) == null; ImageLocation location = thumbsLocations.get(imageLocationPosition); String filter = location.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; String parent = "avatar_" + dialogId; - item.imageView.setImageMedia(videoLocation, null, imagesLocations.get(imageLocationPosition), null, thumbsLocations.get(imageLocationPosition), filter, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); + item.imageView.setImageMedia(vectorAvatars.get(imageLocationPosition), videoLocation, null, imagesLocations.get(imageLocationPosition), null, thumbsLocations.get(imageLocationPosition), filter, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); } if (imagesUploadProgress.get(imageLocationPosition) != null) { needProgress = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java index 068696d5f..62945b8a5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java @@ -24,6 +24,8 @@ import android.text.TextUtils; import android.view.HapticFeedbackConstants; import android.view.View; +import com.google.gson.Gson; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.DispatchQueue; @@ -37,6 +39,7 @@ import org.telegram.messenger.utils.BitmapsCache; import java.io.File; import java.io.FileInputStream; +import java.io.FileReader; import java.io.InputStream; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -72,6 +75,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma private HashMap vibrationPattern; private boolean resetVibrationAfterRestart = false; private boolean allowVibration = true; + public static Gson gson; private WeakReference frameReadyCallback; protected WeakReference onFinishCallback; @@ -107,6 +111,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma private boolean applyingLayerColors; protected int currentFrame; private boolean shouldLimitFps; + private boolean createdForFirstFrame; private float scaleX = 1.0f; private float scaleY = 1.0f; @@ -231,12 +236,19 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma if (destroyWhenDone) { checkRunningTasks(); if (loadFrameTask == null && cacheGenerateTask == null && nativePtr != 0) { - destroy(nativePtr); + long nativePtrFinal = nativePtr; + long secondNativePtrFinal = secondNativePtr; nativePtr = 0; - if (secondNativePtr != 0) { - destroy(secondNativePtr); - secondNativePtr = 0; - } + secondNativePtr = 0; + DispatchQueuePoolBackground.execute(() -> { + if (nativePtrFinal != 0) { + destroy(nativePtrFinal); + } + if (secondNativePtrFinal != 0) { + destroy(secondNativePtrFinal); + } + }); + } } if ((nativePtr == 0 || fallbackCache) && secondNativePtr == 0 && bitmapsCache == null) { @@ -447,6 +459,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma shouldLimitFps = limitFps; this.precache = cacheOptions != null; this.fallbackCache = cacheOptions != null && cacheOptions.fallback; + this.createdForFirstFrame = cacheOptions != null && cacheOptions.firstFrame; getPaint().setFlags(Paint.FILTER_BITMAP_FLAG); this.file = file; @@ -454,21 +467,16 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma createCacheGenQueue(); } if (precache) { - bitmapsCache = new BitmapsCache(file, this, cacheOptions, w, h, !limitFps); args = new NativePtrArgs(); args.file = file.getAbsoluteFile(); args.json = null; args.colorReplacement = colorReplacement; args.fitzModifier = fitzModifier; - nativePtr = create(file.getAbsolutePath(), null, w, h, metaData, precache, colorReplacement, shouldLimitFps, fitzModifier); - if (fallbackCache) { - if (nativePtr == 0) { - file.delete(); - } - } else { - destroy(nativePtr); - nativePtr = 0; + if (createdForFirstFrame) { + return; } + bitmapsCache = new BitmapsCache(file, this, cacheOptions, w, h, !limitFps); + parseLottieMetadata(file, null, metaData); } else { nativePtr = create(file.getAbsolutePath(), null, w, h, metaData, precache, colorReplacement, shouldLimitFps, fitzModifier); if (nativePtr == 0) { @@ -487,28 +495,22 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma height = h; shouldLimitFps = limitFps; this.precache = options != null; + this.createdForFirstFrame = options != null && options.firstFrame; getPaint().setFlags(Paint.FILTER_BITMAP_FLAG); if (precache && lottieCacheGenerateQueue == null) { createCacheGenQueue(); } if (precache) { - bitmapsCache = new BitmapsCache(file, this, options, w, h, !limitFps); args = new NativePtrArgs(); args.file = file.getAbsoluteFile(); args.json = json; args.colorReplacement = colorReplacement; args.fitzModifier = fitzModifier; - nativePtr = create(file.getAbsolutePath(), json, w, h, metaData, precache, colorReplacement, shouldLimitFps, fitzModifier); - if (fallbackCache) { - if (nativePtr == 0) { - file.delete(); - } - } else { - if (nativePtr != 0) { - destroy(nativePtr); - } - nativePtr = 0; + if (createdForFirstFrame) { + return; } + bitmapsCache = new BitmapsCache(file, this, options, w, h, !limitFps); + parseLottieMetadata(file, json, metaData); } else { nativePtr = create(file.getAbsolutePath(), json, w, h, metaData, precache, colorReplacement, shouldLimitFps, fitzModifier); if (nativePtr == 0) { @@ -522,6 +524,28 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma timeBetweenFrames = Math.max(shouldLimitFps ? 33 : 16, (int) (1000.0f / metaData[1])); } + private void parseLottieMetadata(File file, String json, int[] metaData) { + if (gson == null) { + gson = new Gson(); + } + try { + LottieMetadata lottieMetadata; + if (file != null) { + lottieMetadata = gson.fromJson(new FileReader(file.getAbsolutePath()), LottieMetadata.class); + } else { + lottieMetadata = gson.fromJson(json, LottieMetadata.class); + } + metaData[0] = (int) lottieMetadata.op; + metaData[1] = (int) lottieMetadata.fr; + } catch (Exception e) { + FileLog.e(e); + long nativePtr = create(file.getAbsolutePath(), json, width, height, metaData, false, args.colorReplacement, shouldLimitFps, args.fitzModifier); + if (nativePtr != 0) { + destroy(nativePtr); + } + } + } + public RLottieDrawable(int rawRes, String name, int w, int h) { this(rawRes, name, w, h, true, null); } @@ -739,8 +763,6 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma checkCacheCancel(); } - private Runnable cancelCache; - public void checkCacheCancel() { if (bitmapsCache == null || lottieCacheGenerateQueue == null || cacheGenerateTask == null) { return; @@ -856,7 +878,11 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma } public boolean restart() { - if ((autoRepeat < 2 || autoRepeatPlayCount == 0) && autoRepeatCount < 0) { + return restart(false); + } + + public boolean restart(boolean force) { + if (!force && (autoRepeat < 2 || autoRepeatPlayCount == 0) && autoRepeatCount < 0) { return false; } autoRepeatPlayCount = 0; @@ -1256,12 +1282,16 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma @Override public void prepareForGenerateCache() { - generateCacheNativePtr = create(args.file.toString(), args.json, width, height, new int[3], false, args.colorReplacement, false, args.fitzModifier); + generateCacheNativePtr = create(args.file.toString(), args.json, width, height, createdForFirstFrame ? metaData : new int[3], false, args.colorReplacement, false, args.fitzModifier); if (generateCacheNativePtr == 0 && file != null) { file.delete(); } } + public void setGeneratingFrame(int i) { + generateCacheFramePointer = i; + } + @Override public int getNextFrame(Bitmap bitmap) { if (generateCacheNativePtr == 0) { @@ -1366,4 +1396,11 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma }); } } + + private class LottieMetadata { + float fr; + int w; + int h; + float op; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java index ee890df89..e456605f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java @@ -31,6 +31,9 @@ public class RLottieImageView extends ImageView { private boolean attachedToWindow; private boolean playing; private boolean startOnAttach; + private Integer layerNum; + private boolean onlyLastFrame; + public boolean cached; public RLottieImageView(Context context) { super(context); @@ -40,6 +43,13 @@ public class RLottieImageView extends ImageView { layerColors.clear(); } + public void setLayerNum(Integer layerNum) { + this.layerNum = layerNum; + if (this.imageReceiver != null) { + this.imageReceiver.setLayerNum(layerNum); + } + } + public void setLayerColor(String layer, int color) { if (layerColors == null) { layerColors = new HashMap<>(); @@ -95,6 +105,10 @@ public class RLottieImageView extends ImageView { } + public void setOnlyLastFrame(boolean onlyLastFrame) { + this.onlyLastFrame = onlyLastFrame; + } + public void setAnimation(TLRPC.Document document, int w, int h) { if (imageReceiver != null) { imageReceiver.onDetachedFromWindow(); @@ -103,36 +117,50 @@ public class RLottieImageView extends ImageView { if (document == null) { return; } - imageReceiver = new ImageReceiver(); - if ("video/webm".equals(document.mime_type)) { - TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); - imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h + "_pcache_" + ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForDocument(thumb, document), null, null, document.size, null, document, 1); - } else { - Drawable thumbDrawable = null; - String probableCacheKey = document.id + "@" + w + "_" + h; - if (!ImageLoader.getInstance().hasLottieMemCache(probableCacheKey)) { - SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); - if (svgThumb != null) { - svgThumb.overrideWidthAndHeight(512, 512); + imageReceiver = new ImageReceiver() { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + if (drawable != null) { + onLoaded(); } - thumbDrawable = svgThumb; + return super.setImageBitmapByKey(drawable, key, type, memCache, guid); + } + }; + if (onlyLastFrame) { + imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h + "_lastframe", null, null, null, null, null, 0, null, document, 1); + } else if ("video/webm".equals(document.mime_type)) { + TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); + imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h + (cached ? "_pcache" : "") + "_" + ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForDocument(thumb, document), null, null, document.size, null, document, 1); + } else { + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + if (svgThumb != null) { + svgThumb.overrideWidthAndHeight(512, 512); } TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); - imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h, ImageLocation.getForDocument(thumb, document), null, null, null, thumbDrawable, 0, null, document, 1); + imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h + (cached ? "_pcache" : ""), ImageLocation.getForDocument(thumb, document), null, null, null, svgThumb, 0, null, document, 1); } imageReceiver.setAspectFit(true); imageReceiver.setParentView(this); - imageReceiver.setAutoRepeat(1); - imageReceiver.setAllowStartLottieAnimation(true); - imageReceiver.setAllowStartAnimation(true); + if (autoRepeat) { + imageReceiver.setAutoRepeat(1); + imageReceiver.setAllowStartLottieAnimation(true); + imageReceiver.setAllowStartAnimation(true); + } else { + imageReceiver.setAutoRepeat(0); + } + imageReceiver.setLayerNum(layerNum != null ? layerNum : 7); imageReceiver.clip = false; setImageDrawable(new Drawable() { @Override public void draw(@NonNull Canvas canvas) { - AndroidUtilities.rectTmp2.set(getBounds()); - AndroidUtilities.rectTmp2.inset(AndroidUtilities.dp(11), AndroidUtilities.dp(11)); + AndroidUtilities.rectTmp2.set( + getBounds().centerX() - AndroidUtilities.dp(w) / 2, + getBounds().centerY() - AndroidUtilities.dp(h) / 2, + getBounds().centerX() + AndroidUtilities.dp(w) / 2, + getBounds().centerY() + AndroidUtilities.dp(h) / 2 + ); imageReceiver.setImageCoords(AndroidUtilities.rectTmp2); imageReceiver.draw(canvas); } @@ -158,6 +186,10 @@ public class RLottieImageView extends ImageView { } } + protected void onLoaded() { + + } + public void clearAnimationDrawable() { if (drawable != null) { drawable.stop(); @@ -176,6 +208,9 @@ public class RLottieImageView extends ImageView { attachedToWindow = true; if (imageReceiver != null) { imageReceiver.onAttachedToWindow(); + if (playing) { + imageReceiver.startAnimation(); + } } if (drawable != null) { drawable.setCallback(this); @@ -194,7 +229,6 @@ public class RLottieImageView extends ImageView { } if (imageReceiver != null) { imageReceiver.onDetachedFromWindow(); - imageReceiver = null; } } @@ -207,10 +241,13 @@ public class RLottieImageView extends ImageView { } public void setProgress(float progress) { - if (drawable == null) { - return; + if (drawable != null) { + drawable.setProgress(progress); } - drawable.setProgress(progress); + } + + public ImageReceiver getImageReceiver() { + return imageReceiver; } @Override @@ -220,12 +257,14 @@ public class RLottieImageView extends ImageView { } public void playAnimation() { - if (drawable == null) { + if (drawable == null && imageReceiver == null) { return; } playing = true; if (attachedToWindow) { - drawable.start(); + if (drawable != null) { + drawable.start(); + } if (imageReceiver != null) { imageReceiver.startAnimation(); } @@ -235,12 +274,14 @@ public class RLottieImageView extends ImageView { } public void stopAnimation() { - if (drawable == null) { + if (drawable == null && imageReceiver == null) { return; } playing = false; if (attachedToWindow) { - drawable.stop(); + if (drawable != null) { + drawable.stop(); + } if (imageReceiver != null) { imageReceiver.stopAnimation(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java index 740c65edd..bb7e9c956 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java @@ -71,6 +71,7 @@ public class ReactedHeaderView extends FrameLayout { avatarsImageView = new AvatarsImageView(context, false); avatarsImageView.setStyle(AvatarsDrawable.STYLE_MESSAGE_SEEN); + avatarsImageView.setAvatarsTextSize(AndroidUtilities.dp(22)); addView(avatarsImageView, LayoutHelper.createFrameRelatively(24 + 12 + 12 + 8, LayoutHelper.MATCH_PARENT, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); iconView = new ImageView(context); @@ -214,7 +215,7 @@ public class ReactedHeaderView extends FrameLayout { if (message.messageOwner.reactions != null && message.messageOwner.reactions.results.size() == 1 && !list.reactions.isEmpty()) { for (TLRPC.TL_availableReaction r : MediaDataController.getInstance(currentAccount).getReactionsList()) { if (r.reaction.equals(list.reactions.get(0).reaction)) { - reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastframe", "webp", null, r); + reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", "webp", null, r); reactView.setVisibility(VISIBLE); reactView.setAlpha(0); reactView.animate().alpha(1f).start(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java index bd0d86971..4cf9aabe1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java @@ -427,7 +427,7 @@ public class ReactedUsersListView extends FrameLayout { TLRPC.TL_availableReaction r = MediaDataController.getInstance(currentAccount).getReactionsMap().get(visibleReaction.emojicon); if (r != null) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(r.static_icon.thumbs, Theme.key_windowBackgroundGray, 1.0f); - reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastframe", "webp", svgThumb, r); + reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", "webp", svgThumb, r); hasReactImage = true; } else { reactView.setImageDrawable(null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionTabHolderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionTabHolderView.java index 2a789dc3a..3459dc4eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionTabHolderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionTabHolderView.java @@ -113,7 +113,7 @@ public class ReactionTabHolderView extends FrameLayout { for (TLRPC.TL_availableReaction r : MediaDataController.getInstance(currentAccount).getReactionsList()) { if (r.reaction.equals(reaction.emojicon)) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(r.static_icon, Theme.key_windowBackgroundGray, 1.0f); - reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastframe", "webp", svgThumb, r); + reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", "webp", svgThumb, r); reactView.setVisibility(VISIBLE); iconView.setVisibility(GONE); break; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java new file mode 100644 index 000000000..f769084b8 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java @@ -0,0 +1,380 @@ +package org.telegram.ui.Components.Reactions; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.core.math.MathUtils; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.FragmentContextView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.ReactionsContainerLayout; +import org.telegram.ui.Components.RecyclerListView; + +import java.util.Collections; +import java.util.List; + +public class ChatSelectionReactionMenuOverlay extends FrameLayout { + private ChatActivity parentFragment; + private ReactionsContainerLayout reactionsContainerLayout; + + private List selectedMessages = Collections.emptyList(); + private boolean isVisible; + private MessageObject currentPrimaryObject; + + private int mPadding = 22; + private int mSidePadding = 24; + + private float currentOffsetY; + private float toOffsetY; + private float translationOffsetY; + private long lastUpdate; + private boolean hiddenByScroll; + + private boolean messageSet; + + public ChatSelectionReactionMenuOverlay(ChatActivity fragment, Context context) { + super(context); + setVisibility(GONE); + + this.parentFragment = fragment; + + setClipToPadding(false); + setClipChildren(false); + + fragment.getChatListView().addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + invalidatePosition(); + } + }); + } + + private void checkCreateReactionsLayout() { + if (reactionsContainerLayout == null) { + reactionsContainerLayout = new ReactionsContainerLayout(parentFragment, getContext(), parentFragment.getCurrentAccount(), parentFragment.getResourceProvider()) { + float enabledAlpha = 1f; + long lastUpdate; + + { + setWillNotDraw(false); + } + + @Override + public void draw(Canvas canvas) { + long dt = Math.min(16, System.currentTimeMillis() - lastUpdate); + lastUpdate = System.currentTimeMillis(); + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (0xFF * enabledAlpha), Canvas.ALL_SAVE_FLAG); + super.draw(canvas); + canvas.restore(); + + if (!isEnabled() && enabledAlpha != 0f) { + enabledAlpha = Math.max(0, enabledAlpha - dt / 150f); + invalidate(); + + if (enabledAlpha == 0) { + setVisibility(GONE); + } + } else if (isEnabled() && enabledAlpha != 1f) { + enabledAlpha = Math.min(1, enabledAlpha + dt / 150f); + invalidate(); + } + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + + if (visibility == View.GONE && enabledAlpha != 0) { + enabledAlpha = 0; + } + } + }; + reactionsContainerLayout.setPadding(AndroidUtilities.dp(4) + (LocaleController.isRTL ? 0 : mSidePadding), AndroidUtilities.dp(4), AndroidUtilities.dp(4) + (LocaleController.isRTL ? mSidePadding : 0), AndroidUtilities.dp(mPadding)); + reactionsContainerLayout.setDelegate(new ReactionsContainerLayout.ReactionsContainerDelegate() { + @Override + public void onReactionClicked(View view, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean longpress, boolean addToRecent) { + parentFragment.selectReaction(currentPrimaryObject, reactionsContainerLayout, view, 0, 0, visibleReaction, false, longpress, addToRecent); + AndroidUtilities.runOnUIThread(() -> { + reactionsContainerLayout.dismissParent(true); + hideMenu(); + }); + } + + @Override + public void hideMenu() { + parentFragment.clearSelectionMode(true); + } + }); + reactionsContainerLayout.setClipChildren(false); + reactionsContainerLayout.setClipToPadding(false); + addView(reactionsContainerLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 70 + mPadding, Gravity.RIGHT)); + } + } + + public boolean isVisible() { + return isVisible && !hiddenByScroll; + } + + public void invalidatePosition() { + invalidatePosition(true); + } + + private int[] pos = new int[2]; + public void invalidatePosition(boolean animate) { + if (!isVisible || currentPrimaryObject == null || reactionsContainerLayout == null) { + return; + } + + long dt = Math.min(16, System.currentTimeMillis() - lastUpdate); + lastUpdate = System.currentTimeMillis(); + if (currentOffsetY != toOffsetY) { + float a = dt / 220f; + if (toOffsetY > currentOffsetY) { + currentOffsetY = Math.min(currentOffsetY + a, toOffsetY); + } else if (toOffsetY < currentOffsetY) { + currentOffsetY = Math.max(currentOffsetY - a, toOffsetY); + } + AndroidUtilities.runOnUIThread(this::invalidatePosition); + } + + RecyclerListView listView = parentFragment.getChatListView(); + listView.getLocationInWindow(pos); + float listY = pos[1]; + getLocationInWindow(pos); + float offsetY = listY - pos[1] - parentFragment.getPullingDownOffset(); + + for (int i = 0; i < listView.getChildCount(); i++) { + View ch = listView.getChildAt(i); + if (ch instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) ch; + + MessageObject obj = cell.getMessageObject(); + if (obj.getId() == currentPrimaryObject.getId()) { + boolean mirrorX = obj.isOutOwner(); + if (reactionsContainerLayout != null) { + reactionsContainerLayout.setMirrorX(mirrorX); + reactionsContainerLayout.setPadding(AndroidUtilities.dp(4) + (LocaleController.isRTL || mirrorX ? 0 : mSidePadding), AndroidUtilities.dp(mPadding), AndroidUtilities.dp(4) + (LocaleController.isRTL || mirrorX ? mSidePadding : 0), AndroidUtilities.dp(mPadding)); + } + int height = getHeight() != 0 ? getHeight() : listView.getHeight(); + int groupHeight; + + if (cell.getCurrentMessagesGroup() != null) { + MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); + groupHeight = group.transitionParams.bottom - group.transitionParams.top; + } else { + groupHeight = cell.getHeight(); + } + + float y = cell.getY() + offsetY - AndroidUtilities.dp(74); + float min = AndroidUtilities.dp(14), max = height - AndroidUtilities.dp(218); + FragmentContextView fragmentContextView = parentFragment.getFragmentContextView(); + if (fragmentContextView != null && fragmentContextView.getVisibility() == View.VISIBLE) { + min += fragmentContextView.getHeight(); + } + boolean newVisibleOffset; + boolean flippedVertically; + if (y > min - groupHeight / 2f && y < max) { + newVisibleOffset = true; + flippedVertically = false; + toOffsetY = 0f; + } else if (y < min - groupHeight - AndroidUtilities.dp(92) || y > max) { + newVisibleOffset = false; + flippedVertically = false; + } else { + newVisibleOffset = true; + translationOffsetY = groupHeight + AndroidUtilities.dp(56); + flippedVertically = true; + toOffsetY = 1f; + } + if (!animate) { + currentOffsetY = toOffsetY; + } + + y += CubicBezierInterpolator.DEFAULT.getInterpolation(currentOffsetY) * translationOffsetY; + if (reactionsContainerLayout == null) { + return; + } + if (flippedVertically != reactionsContainerLayout.isFlippedVertically()) { + reactionsContainerLayout.setFlippedVertically(flippedVertically); + AndroidUtilities.runOnUIThread(this::invalidatePosition); + } + if (newVisibleOffset != reactionsContainerLayout.isEnabled()) { + reactionsContainerLayout.setEnabled(newVisibleOffset); + reactionsContainerLayout.invalidate(); + if (newVisibleOffset) { + reactionsContainerLayout.setVisibility(VISIBLE); + if (!messageSet) { + messageSet = true; + reactionsContainerLayout.setMessage(currentPrimaryObject, parentFragment.getCurrentChatInfo()); + } + } + } + reactionsContainerLayout.setTranslationY(MathUtils.clamp(y, min, max)); + reactionsContainerLayout.setTranslationX(cell.getNonAnimationTranslationX(true)); + + boolean invalidate = false; + LayoutParams params = (LayoutParams) reactionsContainerLayout.getLayoutParams(); + int left = Math.max(0, cell.getBackgroundDrawableLeft() - AndroidUtilities.dp(32)); + int right = Math.max((int) cell.getNonAnimationTranslationX(true), cell.getWidth() - cell.getBackgroundDrawableRight() - AndroidUtilities.dp(32)); + + int minWidth = AndroidUtilities.dp(40) * 8; + if (getWidth() - right - left < minWidth) { + if (mirrorX) { + right = 0; + left = Math.min(left, getWidth() - right - minWidth); + } else { + left = 0; + right = Math.min(right, getWidth() - left - minWidth); + } + } + + int gravity = mirrorX ? Gravity.RIGHT : Gravity.LEFT; + if (gravity != params.gravity) { + params.gravity = gravity; + invalidate = true; + } + if (left != params.leftMargin) { + params.leftMargin = left; + invalidate = true; + } + if (right != params.rightMargin) { + params.rightMargin = right; + invalidate = true; + } + if (invalidate) { + reactionsContainerLayout.requestLayout(); + } + return; + } + } + } + + if (reactionsContainerLayout != null && reactionsContainerLayout.isEnabled()) { + reactionsContainerLayout.setEnabled(false); + } + } + + private MessageObject findPrimaryObject() { + if (isVisible && !selectedMessages.isEmpty()) { + MessageObject msg = selectedMessages.get(0); + + if (msg.getGroupId() != 0) { + MessageObject.GroupedMessages groupedMessages = parentFragment.getGroup(msg.getGroupId()); + + for (MessageObject obj : groupedMessages.messages) { + if (obj.messageOwner != null && obj.messageOwner.reactions != null && obj.messageOwner.reactions.results != null && + !obj.messageOwner.reactions.results.isEmpty()) { + return obj; + } + } + } + + return msg; + } + return null; + } + + private boolean isMessageTypeAllowed(MessageObject obj) { + return MessageObject.isPhoto(obj.messageOwner) || obj.getDocument() != null && MessageObject.isVideoDocument(obj.getDocument()); + } + + public void setSelectedMessages(List messages) { + this.selectedMessages = messages; + + boolean visible = false; + + if (parentFragment.getCurrentChatInfo() != null && parentFragment.getCurrentChatInfo().available_reactions instanceof TLRPC.TL_chatReactionsNone) { + visible = false; + } else if (!messages.isEmpty()) { + visible = true; + + boolean hasGroupId = false; + long groupId = 0; + for (MessageObject obj : messages) { + if (!isMessageTypeAllowed(obj)) { + visible = false; + break; + } + if (!hasGroupId) { + hasGroupId = true; + groupId = obj.getGroupId(); + } else if (groupId != obj.getGroupId() || groupId == 0) { + visible = false; + break; + } + } + } + + if (visible != isVisible) { + isVisible = visible; + hiddenByScroll = false; + animateVisible(visible); + } else if (visible) { + currentPrimaryObject = findPrimaryObject(); + } + } + + private void animateVisible(boolean visible) { + if (visible) { + currentPrimaryObject = findPrimaryObject(); + checkCreateReactionsLayout(); + invalidatePosition(false); + + setVisibility(VISIBLE); + if (reactionsContainerLayout.isEnabled()) { + messageSet = true; + reactionsContainerLayout.setMessage(currentPrimaryObject, parentFragment.getCurrentChatInfo()); + reactionsContainerLayout.startEnterAnimation(); + } else { + messageSet = false; + reactionsContainerLayout.setTransitionProgress(1f); + } + } else { + messageSet = false; + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(150); + animator.addUpdateListener(animation -> { + float val = (float) animation.getAnimatedValue(); + if (reactionsContainerLayout != null) { + reactionsContainerLayout.setAlpha(val); + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setVisibility(GONE); + if (reactionsContainerLayout != null) { + removeView(reactionsContainerLayout); + reactionsContainerLayout = null; + } + currentPrimaryObject = null; + } + }); + animator.start(); + } + } + + public void setHiddenByScroll(boolean hiddenByScroll) { + this.hiddenByScroll = hiddenByScroll; + + if (hiddenByScroll) { + animateVisible(false); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java index 76c4318d6..15603f285 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java @@ -59,6 +59,7 @@ public class CustomEmojiReactionsWindow { public RectF drawingRect = new RectF(); float enterTransitionProgress; boolean enterTransitionFinished; + boolean isShowing; SelectAnimatedEmojiDialog selectAnimatedEmojiDialog; ReactionsContainerLayout reactionsContainerLayout; @@ -150,6 +151,11 @@ public class CustomEmojiReactionsWindow { reactionsContainerLayout.onReactionClicked(emojiView, ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentId), false); AndroidUtilities.hideKeyboard(windowView); } + + @Override + protected void invalidateParent() { + containerView.invalidate(); + } }; selectAnimatedEmojiDialog.setOnLongPressedListener(new SelectAnimatedEmojiDialog.onLongPressedListener() { @Override @@ -181,14 +187,12 @@ public class CustomEmojiReactionsWindow { this.reactionsContainerLayout = reactionsContainerLayout; reactionsContainerLayout.prepareAnimation(true); - containerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - containerView.removeOnLayoutChangeListener(this); - reactionsContainerLayout.prepareAnimation(false); - createTransition(true); - } - }); + AndroidUtilities.runOnUIThread(() -> { + isShowing = true; + containerView.invalidate(); + reactionsContainerLayout.prepareAnimation(false); + createTransition(true); + }, 50); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 7); } @@ -412,6 +416,9 @@ public class CustomEmojiReactionsWindow { @Override protected void dispatchDraw(Canvas canvas) { + if (!isShowing) { + return; + } dimPaint.setAlpha((int) (0.2f * enterTransitionProgress * 255)); canvas.drawPaint(dimPaint); AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); @@ -619,7 +626,6 @@ public class CustomEmojiReactionsWindow { } selectAnimatedEmojiDialog.drawBigReaction(canvas, this); - invalidate(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java index 338ac6f21..1b5dc5437 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java @@ -593,7 +593,7 @@ public class ReactionsEffectOverlay { if (animationType != SHORT_ANIMATION) { if (availableReaction != null) { - emojiStaticImageView.getImageReceiver().setImage(ImageLocation.getForDocument(availableReaction.center_icon), "40_40_lastframe", null, "webp", availableReaction, 1); + emojiStaticImageView.getImageReceiver().setImage(ImageLocation.getForDocument(availableReaction.center_icon), "40_40_lastreactframe", null, "webp", availableReaction, 1); } container.addView(emojiStaticImageView); emojiStaticImageView.getLayoutParams().width = emojiSize; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java index c6af97580..1c9e53fc1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java @@ -526,7 +526,7 @@ public class ReactionsLayoutInBubble { if (r != null) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(r.static_icon, Theme.key_windowBackgroundGray, 1.0f); //imageReceiver.setImage(ImageLocation.getForDocument(r.static_icon), "40_40", svgThumb, "webp", r, 1); - imageReceiver.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastframe", svgThumb, "webp", r, 1); + imageReceiver.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", svgThumb, "webp", r, 1); } } else if (visibleReaction.documentId != 0) { animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW, currentAccount, visibleReaction.documentId); 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 19c21165b..affc86f77 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -106,6 +106,11 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio private int currentAccount; private long waitingLoadingChatId; + private boolean mirrorX; + private boolean isFlippedVertically; + private float flipVerticalProgress; + private long lastUpdate; + ValueAnimator cancelPressedAnimation; FrameLayout premiumLockContainer; FrameLayout customReactionsContainer; @@ -486,7 +491,6 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio return; } reactionsWindow = new CustomEmojiReactionsWindow(fragment, allReactionsList, selectedReactions, this, resourcesProvider); - reactionsWindow.onDismissListener(() -> { reactionsWindow = null; }); @@ -519,6 +523,20 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio this.delegate = delegate; } + public boolean isFlippedVertically() { + return isFlippedVertically; + } + + public void setFlippedVertically(boolean flippedVertically) { + isFlippedVertically = flippedVertically; + invalidate(); + } + + public void setMirrorX(boolean mirrorX) { + this.mirrorX = mirrorX; + invalidate(); + } + @SuppressLint("NotifyDataSetChanged") private void setVisibleReactionsList(List visibleReactionsList) { this.visibleReactionsList.clear(); @@ -560,6 +578,17 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio @Override protected void dispatchDraw(Canvas canvas) { + long dt = Math.min(16, System.currentTimeMillis() - lastUpdate); + lastUpdate = System.currentTimeMillis(); + + if (isFlippedVertically && flipVerticalProgress != 1f) { + flipVerticalProgress = Math.min(1f, flipVerticalProgress + dt / 220f); + invalidate(); + } else if (!isFlippedVertically && flipVerticalProgress != 0f) { + flipVerticalProgress = Math.max(0f, flipVerticalProgress - dt / 220f); + invalidate(); + } + float cPr = (Math.max(CLIP_PROGRESS, Math.min(transitionProgress, 1f)) - CLIP_PROGRESS) / (1f - CLIP_PROGRESS); float br = bigCircleRadius * cPr, sr = smallCircleRadius * cPr; // if (customEmojiReactionsEnterProgress != 0) { @@ -589,7 +618,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio otherViewsScale = 1 - 0.15f * pressedProgress; int s = canvas.save(); - float pivotX = LocaleController.isRTL ? getWidth() * 0.125f : getWidth() * 0.875f; + float pivotX = LocaleController.isRTL || mirrorX ? getWidth() * 0.125f : getWidth() * 0.875f; if (transitionProgress <= SCALE_PROGRESS) { float sc = transitionProgress / SCALE_PROGRESS; @@ -597,7 +626,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } float lt = 0, rt = 1; - if (LocaleController.isRTL) { + if (LocaleController.isRTL || mirrorX) { rt = Math.max(CLIP_PROGRESS, transitionProgress); } else { lt = (1f - Math.max(CLIP_PROGRESS, transitionProgress)); @@ -719,7 +748,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } canvas.clipPath(mPath); - canvas.translate((LocaleController.isRTL ? -1 : 1) * getWidth() * (1f - transitionProgress), 0); + canvas.translate((LocaleController.isRTL || mirrorX ? -1 : 1) * getWidth() * (1f - transitionProgress), 0); super.dispatchDraw(canvas); if (leftShadowPaint != null) { @@ -747,9 +776,10 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio private void drawBubbles(Canvas canvas, float br, float cPr, float sr, int alpha) { canvas.save(); - canvas.clipRect(0, rect.bottom, getMeasuredWidth(), getMeasuredHeight() + AndroidUtilities.dp(8)); - float cx = LocaleController.isRTL ? bigCircleOffset : getWidth() - bigCircleOffset; + canvas.clipRect(0, AndroidUtilities.lerp(rect.bottom, 0, CubicBezierInterpolator.DEFAULT.getInterpolation(flipVerticalProgress)), getMeasuredWidth(), AndroidUtilities.lerp(getMeasuredHeight() + AndroidUtilities.dp(8), getPaddingTop() - expandSize(), CubicBezierInterpolator.DEFAULT.getInterpolation(flipVerticalProgress))); + float cx = LocaleController.isRTL || mirrorX ? bigCircleOffset : getWidth() - bigCircleOffset; float cy = getHeight() - getPaddingBottom() + expandSize(); + cy = AndroidUtilities.lerp(cy, getPaddingTop() - expandSize(), CubicBezierInterpolator.DEFAULT.getInterpolation(flipVerticalProgress)); int sPad = AndroidUtilities.dp(3); shadow.setAlpha(alpha); bgPaint.setAlpha(alpha); @@ -757,8 +787,9 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio shadow.draw(canvas); canvas.drawCircle(cx, cy, br, bgPaint); - cx = LocaleController.isRTL ? bigCircleOffset - bigCircleRadius : getWidth() - bigCircleOffset + bigCircleRadius; + cx = LocaleController.isRTL || mirrorX ? bigCircleOffset - bigCircleRadius : getWidth() - bigCircleOffset + bigCircleRadius; cy = getHeight() - smallCircleRadius - sPad + expandSize(); + cy = AndroidUtilities.lerp(cy, smallCircleRadius + sPad - expandSize(), CubicBezierInterpolator.DEFAULT.getInterpolation(flipVerticalProgress)); sPad = -AndroidUtilities.dp(1); shadow.setBounds((int) (cx - br - sPad * cPr), (int) (cy - br - sPad * cPr), (int) (cx + br + sPad * cPr), (int) (cy + br + sPad * cPr)); shadow.draw(canvas); @@ -922,7 +953,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } } } else { - throw new RuntimeException("Unknow chat reactions type"); + throw new RuntimeException("Unknown chat reactions type: " + reactionsChat.available_reactions); } } else { allReactionsAvailable = true; @@ -1026,7 +1057,9 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio public void setCustomEmojiEnterProgress(float progress) { customEmojiReactionsEnterProgress = progress; - chatScrimPopupContainerLayout.setPopupAlpha(1f - progress); + if (chatScrimPopupContainerLayout != null) { + chatScrimPopupContainerLayout.setPopupAlpha(1f - progress); + } invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java index eaed5f039..0a134b891 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java @@ -1615,12 +1615,12 @@ public class RecyclerListView extends RecyclerView { selectorDrawable = Theme.createRadSelectorDrawable(color, selectorRadius, 0); } else if (topBottomSelectorRadius > 0) { selectorDrawable = Theme.createRadSelectorDrawable(color, topBottomSelectorRadius, topBottomSelectorRadius); - } else if (selectorRadius > 0) { + } else if (selectorRadius > 0 && selectorType != Theme.RIPPLE_MASK_CIRCLE_20DP) { selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(selectorRadius, 0, color, 0xff000000); } else if (selectorType == 2) { selectorDrawable = Theme.getSelectorDrawable(color, false); } else { - selectorDrawable = Theme.createSelectorDrawable(color, selectorType); + selectorDrawable = Theme.createSelectorDrawable(color, selectorType, selectorRadius); } selectorDrawable.setCallback(this); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java index a5f2b7c63..ff74f8115 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java @@ -662,11 +662,10 @@ public class ScrollSlidingTabStrip extends HorizontalScrollView { ImageLocation imageLocation; if (object instanceof TLRPC.Document) { - TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(sticker.thumbs, 90); if (!tabView.inited) { tabView.svgThumb = DocumentObject.getSvgThumb((TLRPC.Document) object, Theme.key_emptyListPlaceholder, 0.2f); } - imageLocation = ImageLocation.getForDocument(thumb, sticker); + imageLocation = ImageLocation.getForDocument(sticker); } else if (object instanceof TLRPC.PhotoSize) { TLRPC.PhotoSize thumb = (TLRPC.PhotoSize) object; int thumbVersion = 0; @@ -700,9 +699,9 @@ public class ScrollSlidingTabStrip extends HorizontalScrollView { } } else if (MessageObject.isAnimatedStickerDocument(sticker, true)) { if (svgThumb != null) { - imageView.setImage(ImageLocation.getForDocument(sticker), imageFilter, svgThumb, 0, parentObject); + imageView.setImage(imageLocation, imageFilter, svgThumb, 0, parentObject); } else { - imageView.setImage(ImageLocation.getForDocument(sticker), imageFilter, imageLocation, null, 0, parentObject); + imageView.setImage(imageLocation, imageFilter, imageLocation, null, 0, parentObject); } } else if (imageLocation.imageType == FileLoader.IMAGE_TYPE_LOTTIE) { imageView.setImage(imageLocation, imageFilter, "tgs", svgThumb, parentObject); @@ -740,6 +739,14 @@ public class ScrollSlidingTabStrip extends HorizontalScrollView { private Paint selectorPaint = new Paint(); + private boolean showSelected = true; + private AnimatedFloat showSelectedAlpha = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + public void showSelected(boolean show) { + this.showSelected = show; + invalidate(); + } + @Override protected void dispatchDraw(Canvas canvas) { final float dif = (stickerTabWidth - stickerTabExpandedWidth); @@ -761,6 +768,8 @@ public class ScrollSlidingTabStrip extends HorizontalScrollView { height = getHeight() - AndroidUtilities.dp(50) * (1f - expandProgress); } + float selectedAlpha = showSelectedAlpha.set(showSelected ? 1 : 0); + if (!(isInEditMode() || tabCount == 0) && indicatorHeight >= 0) { float position = currentPositionAnimated.set(currentPosition); int floorPosition = (int) Math.floor(position); @@ -808,6 +817,7 @@ public class ScrollSlidingTabStrip extends HorizontalScrollView { tabBounds.set(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2); selectorPaint.setColor(0x2effffff & getThemedColor(Theme.key_chat_emojiPanelIcon)); + selectorPaint.setAlpha((int) (selectorPaint.getAlpha() * selectedAlpha)); canvas.drawRoundRect(tabBounds, AndroidUtilities.dp(8), AndroidUtilities.dp(8), selectorPaint); } @@ -909,8 +919,10 @@ public class ScrollSlidingTabStrip extends HorizontalScrollView { } public void setUnderlineHeight(int value) { - underlineHeight = value; - invalidate(); + if (underlineHeight != value) { + underlineHeight = value; + invalidate(); + } } protected void invalidateOverlays() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchDownloadsContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchDownloadsContainer.java index 4feb1e632..20b1d4019 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchDownloadsContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchDownloadsContainer.java @@ -141,11 +141,12 @@ public class SearchDownloadsContainer extends FrameLayout implements Notificatio boolean openInPhotoViewer = message.canPreviewDocument(); if (!openInPhotoViewer) { boolean noforwards = message.messageOwner != null && message.messageOwner.noforwards; - if (message.isFromChat()) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-message.getFromChatId()); - if (chat != null) { - noforwards = chat.noforwards; - } + TLRPC.Chat chatTo = messageObject.messageOwner.peer_id.channel_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.channel_id) : null; + if (chatTo == null) { + chatTo = messageObject.messageOwner.peer_id.chat_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.chat_id) : null; + } + if (chatTo != null) { + noforwards = chatTo.noforwards; } openInPhotoViewer = openInPhotoViewer || noforwards; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchStateDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchStateDrawable.java new file mode 100644 index 000000000..7cb4bb7d9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchStateDrawable.java @@ -0,0 +1,339 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.lerp; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; + +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.zxing.common.detector.MathUtils; + +import org.telegram.messenger.AndroidUtilities; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +public class SearchStateDrawable extends Drawable { + + @IntDef({ State.STATE_SEARCH, State.STATE_BACK, State.STATE_PROGRESS }) + @Retention(RetentionPolicy.SOURCE) + public @interface State { + int STATE_SEARCH = 0; + int STATE_BACK = 1; + int STATE_PROGRESS = 2; + } + + private int alpha = 0xFF; + private Paint paint; + + private Path path = new Path(); + + private RectF progressRect = new RectF(); + private final float progressRadius = .25f; + private long progressStart = -1; + private boolean progressStartedWithOverTo; + private float progressAngleFrom = 0, progressAngleTo = 0; + private float[] progressSegments = new float[2]; + + private @State int fromState; + private @State int toState = State.STATE_SEARCH; + private boolean waitingForProgressToEnd = false, wereNotWaitingForProgressToEnd; + + private AnimatedFloat progress = new AnimatedFloat(1, this::invalidateSelf, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private Runnable delaySetProgress; + + public SearchStateDrawable() { + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.WHITE); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeJoin(Paint.Join.ROUND); + paint.setStrokeCap(Paint.Cap.ROUND); + paint.setStrokeWidth(AndroidUtilities.dp(1.333f)); + } + + public @State int getIconState() { + return this.toState; + } + + public void setIconState(@State int state) { + setIconState(state, true); + } + public void setIconState(@State int state, boolean animated) { + setIconState(state, animated, false); + } + + private void setIconState(@State int state, boolean animated, boolean skipProgressDelay) { + if (getIconState() == state) { + if (state != State.STATE_PROGRESS) { + AndroidUtilities.cancelRunOnUIThread(delaySetProgress); + delaySetProgress = null; + } + return; + } + + if (!skipProgressDelay && state == State.STATE_PROGRESS) { + if (delaySetProgress == null) { + AndroidUtilities.runOnUIThread(delaySetProgress = () -> { + delaySetProgress = null; + setIconState(state, animated, true); + }, 65); + } + return; + } else if (delaySetProgress != null) { + AndroidUtilities.cancelRunOnUIThread(delaySetProgress); + } + + if (progress.get() < 1 && animated) { + setIconState(toState, false); + } + + if (state == State.STATE_PROGRESS) { + progressAngleFrom = 180; + progressStart = -1; + } else if (toState == State.STATE_PROGRESS) { + if (state == State.STATE_SEARCH) { + progressAngleTo = -45; + } else { + progressAngleTo = 0; + } + } + + if (animated) { + fromState = toState; + toState = state; + waitingForProgressToEnd = fromState == State.STATE_PROGRESS && state != State.STATE_PROGRESS; + progress.set(0, true); + } else { + fromState = toState = state; + waitingForProgressToEnd = false; + progress.set(1, true); + } + invalidateSelf(); + } + + public void setStrokeWidth(float strokeWidth) { + paint.setStrokeWidth(strokeWidth); + } + + public void setColor(int color) { + paint.setColor(color); + } + + @Override + public void draw(@NonNull Canvas canvas) { + final Rect bounds = getBounds(); + this.mn = Math.min(bounds.width(), bounds.height()); + this.cx = bounds.centerX(); + this.cy = bounds.centerY(); + + if (alpha < 0xFF) { + canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, alpha, Canvas.ALL_SAVE_FLAG); + } + + float value = progress.set(waitingForProgressToEnd ? 0 : 1); + + float searchValue = toState == State.STATE_SEARCH ? fromState == State.STATE_SEARCH ? 1 : value : fromState == State.STATE_SEARCH ? 1f - value : 0; + float backValue = toState == State.STATE_BACK ? fromState == State.STATE_BACK ? 1 : value : fromState == State.STATE_BACK ? 1f - value : 0; + float progressValue = toState == State.STATE_PROGRESS ? fromState == State.STATE_PROGRESS ? 1 : value : fromState == State.STATE_PROGRESS ? 1f - value : 0; + + if (searchValue > 0) { + // o + drawCircle( + canvas, + lerp(x(.25f), x(.444f), searchValue), + lerp(y(.5f), y(.444f), searchValue), + lerp(0, w(.208f), searchValue) + ); + } + + if (searchValue > 0 || backValue > 0) { + // — + canvas.save(); + canvas.rotate(searchValue * 45, cx, cy); + drawLine( + canvas, + lerp3( + x(.914f), x(.7638f), fromState == State.STATE_PROGRESS ? x(.5f + progressRadius) : x(.2409f), + searchValue, backValue, progressValue + ), y(.5f), + lerp3( + x(.658f), x(.2409f), fromState == State.STATE_PROGRESS ? x(.5f + progressRadius) : x(.2409f), + searchValue, backValue, progressValue + ), y(.5f) + ); + canvas.restore(); + } + + if (backValue > 0) { + // < + float ax = fromState == State.STATE_PROGRESS ? lerp(x(.5f + progressRadius), x(.2409f), backValue) : x(.2409f); + + canvas.save(); + canvas.rotate(searchValue * 45, cx, cy); + drawLines( + canvas, + + ax + x(.2452f) * backValue, + lerp(y(.5f), y(.25f), backValue), + + ax, y(.5f), + + ax + x(.2452f) * backValue, + lerp(y(.5f), y(.75f), backValue) + ); + canvas.restore(); + } + + if (progressValue > 0) { + if (progressStart < 0 && progressValue > .8f) { + progressStart = System.currentTimeMillis(); + wereNotWaitingForProgressToEnd = waitingForProgressToEnd; + } + if (progressStart > 0) { + + CircularProgressDrawable.getSegments( + (System.currentTimeMillis() - progressStart) % 5400f, + progressSegments + ); + float fromAngle = progressSegments[0], toAngle = progressSegments[1]; + if (getIconState() != State.STATE_PROGRESS && !waitingForProgressToEnd) { + float m = Math.max(0, (float) Math.floor((fromAngle - 180) / 360f) * 360f + 180); + toAngle = Math.min(toAngle, m + progressAngleTo); + fromAngle = Math.min(fromAngle, m + progressAngleTo); + fromAngle = lerp(toAngle, fromAngle, progressValue); + } + + boolean progressOverTo = containsAngle(progressAngleTo, progressAngleFrom + fromAngle, progressAngleFrom + toAngle); + if (waitingForProgressToEnd && !wereNotWaitingForProgressToEnd) { + wereNotWaitingForProgressToEnd = waitingForProgressToEnd; + progressStartedWithOverTo = progressOverTo; + } + if (progressStartedWithOverTo && !progressOverTo) { + progressStartedWithOverTo = false; + } + if (waitingForProgressToEnd && progressOverTo && !progressStartedWithOverTo) { + waitingForProgressToEnd = false; + } + + progressRect.set(x(.5f - progressRadius), y(.5f - progressRadius), x(.5f + progressRadius), y(.5f + progressRadius)); + canvas.drawArc( + progressRect, + progressAngleFrom + fromAngle, + toAngle - fromAngle, + false, + paint + ); + + invalidateSelf(); + } + } + + if (alpha < 0xFF) { + canvas.restore(); + } + + if (value < 1) { + invalidateSelf(); + } + } + + private boolean containsAngle(float angle, float angleFrom, float angleTo) { + angleFrom = angleFrom % 360; + if (angleFrom < 0) { + angleFrom = 360 + angleFrom; + } + angleTo = angleTo % 360; + if (angleTo < 0) { + angleTo = 360 + angleTo; + } + if (angleFrom > angleTo) + return angle >= angleFrom || angle <= angleTo; + return angle >= angleFrom && angle <= angleTo; + } + + private void drawCircle(Canvas canvas, float x, float y, float r) { + if (r < w(.075f)) { + return; + } + canvas.drawCircle(x, y, r, paint); + } + + private void drawLine(Canvas canvas, float x1, float y1, float x2, float y2) { + if (MathUtils.distance(x1, y1, x2, y2) <= w(.075f)) { + return; + } + canvas.drawLine(x1, y1, x2, y2, paint); + } + + private void drawLines(Canvas canvas, float x1, float y1, float x2, float y2, float x3, float y3) { + if (Math.max(MathUtils.distance(x1, y1, x2, y2), MathUtils.distance(x3, y3, x2, y2)) <= w(.075f)) { + return; + } + path.rewind(); + path.moveTo(x1, y1); + path.lineTo(x2, y2); + path.lineTo(x3, y3); + canvas.drawPath(path, paint); + } + + private float lerp3( + float x1, + float x2, + float x3, + // t1 + t2 + t3 = 1 + float t1, + float t2, + float t3 + ) { + return x1 * t1 + x2 * t2 + x3 * t3; + } + + private float mn, cx, cy; + + private float x(float t) { + return cx - mn * (.5f - t); + } + + private float y(float t) { + return cy - mn * (.5f - t); + } + + private float w(float t) { + return mn * t; + } + + @Override + public void setAlpha(int alpha) { + this.alpha = alpha; + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + paint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public int getIntrinsicWidth() { + return AndroidUtilities.dp(24); + } + + @Override + public int getIntrinsicHeight() { + return AndroidUtilities.dp(24); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java index 90302d6ab..fbdd47ce8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -145,6 +145,14 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie } } }; + if (initialDialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + ArrayList dialogs = fragment.getDialogsArray(currentAccount, initialDialogsType, folderId, true); + ArrayList dialogIds = new ArrayList<>(); + for (int i = 0; i < dialogs.size(); ++i) { + dialogIds.add(dialogs.get(i).id); + } + dialogsSearchAdapter.setFilterDialogIds(dialogIds); + } fragmentView = (SizeNotifierFrameLayout) fragment.getFragmentView(); searchListView = new BlurredRecyclerView(context) { @@ -510,7 +518,7 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie } else if (id == forwardItemId) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { ArrayList fmessages = new ArrayList<>(); @@ -545,13 +553,14 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie args1.putLong("chat_id", -did); } if (!AccountInstance.getInstance(currentAccount).getMessagesController().checkCanOpenChat(args1, fragment1)) { - return; + return true; } } ChatActivity chatActivity = new ChatActivity(args1); fragment1.presentFragment(chatActivity, true); chatActivity.showFieldPanelForForward(true, fmessages); } + return true; }); parent.presentFragment(fragment); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java index c6210db57..ae5c86eac 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java @@ -66,7 +66,7 @@ public class SeekBarView extends FrameLayout { private float transitionProgress = 1f; private int transitionThumbX; private int separatorsCount; - private int lineWidthDp = 2; + private int lineWidthDp = 3; private boolean twoSided; private final Theme.ResourcesProvider resourcesProvider; 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 9c8ad6a83..cfdadd9d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -3254,7 +3254,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putBoolean("canSelectTopics", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { ArrayList fmessages = new ArrayList<>(); @@ -3308,7 +3308,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter args1.putLong("chat_id", -did); } if (!profileActivity.getMessagesController().checkCanOpenChat(args1, fragment1)) { - return; + return true; } } @@ -3319,6 +3319,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter fragment1.presentFragment(chatActivity, true); chatActivity.showFieldPanelForForward(true, fmessages); } + return true; }); profileActivity.presentFragment(fragment); } else if (id == gotochat) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleThemeDescription.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleThemeDescription.java index 39efa4c62..7c79b6cc4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleThemeDescription.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleThemeDescription.java @@ -18,4 +18,8 @@ public class SimpleThemeDescription { } return l; } + + public static void add(ArrayList descriptions, Runnable upd, String... keys) { + descriptions.addAll(SimpleThemeDescription.createThemeDescriptions(upd::run, keys)); + } } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java new file mode 100644 index 000000000..0e5024141 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java @@ -0,0 +1,956 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.OvershootInterpolator; + +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.LinearLayoutManager; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLiteDatabase; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Fetcher; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashSet; +import java.util.Set; + +public class StickerCategoriesListView extends RecyclerListView { + + @IntDef({CategoriesType.DEFAULT, CategoriesType.STATUS, CategoriesType.PROFILE_PHOTOS}) + @Retention(RetentionPolicy.SOURCE) + public static @interface CategoriesType { + int DEFAULT = 0; + int STATUS = 1; + int PROFILE_PHOTOS = 2; + } + + private float shownButtonsAtStart = 6.5f; + + private static EmojiGroupFetcher fetcher = new EmojiGroupFetcher(); + public static Fetcher search = new EmojiSearch(); + private EmojiCategory[] categories = null; + + private Adapter adapter; + private LinearLayoutManager layoutManager; + + private AnimatedFloat leftBoundAlpha = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private AnimatedFloat rightBoundAlpha = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private Drawable leftBoundDrawable; + private Drawable rightBoundDrawable; + private Paint backgroundPaint; + + @CategoriesType + private int categoriesType; + private static Set loadedIconsType = new HashSet<>(); + + private Paint selectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private int paddingWidth; + private int dontOccupyWidth; + private Utilities.Callback onScrollIntoOccupiedWidth; + private Utilities.Callback onScrollFully; + private boolean scrolledIntoOccupiedWidth; + private boolean scrolledFully; + + private View paddingView; + + public Integer layerNum; + + private int selectedCategoryIndex = -1; + private Utilities.Callback onCategoryClick; + + public static void preload(int account, @CategoriesType int type) { + fetcher.fetch(account, type, emojiGroups -> { + for (TLRPC.TL_emojiGroup group : emojiGroups.groups) { + AnimatedEmojiDrawable.getDocumentFetcher(account).fetchDocument(group.icon_emoji_id, null); + } + }); + } + + public StickerCategoriesListView(Context context, @CategoriesType int categoriesType) { + this(context, null, categoriesType, null); + } + + public StickerCategoriesListView(Context context, @CategoriesType int categoriesType, Theme.ResourcesProvider resourcesProvider) { + this(context, null, categoriesType, resourcesProvider); + } + + public StickerCategoriesListView(Context context, EmojiCategory[] additionalCategories, @CategoriesType int categoriesType) { + this(context, additionalCategories, categoriesType, null); + } + + public StickerCategoriesListView(Context context, EmojiCategory[] additionalCategories, @CategoriesType int categoriesType, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + + this.categoriesType = categoriesType; + setPadding(0, 0, dp(2), 0); + + setAdapter(adapter = new Adapter()); + setLayoutManager(layoutManager = new LinearLayoutManager(context)); + layoutManager.setOrientation(HORIZONTAL); + +// setSelectorRadius(dp(15)); +// setSelectorType(Theme.RIPPLE_MASK_CIRCLE_20DP); +// setSelectorDrawableColor(getThemedColor(Theme.key_listSelector)); + selectedPaint.setColor(getThemedColor(Theme.key_listSelector)); + setSelectorDrawableColor(0); + + setWillNotDraw(false); + + setOnItemClickListener((view, position) -> onItemClick(position, view)); + + long start = System.currentTimeMillis(); + fetcher.fetch(UserConfig.selectedAccount, categoriesType, (emojiGroups) -> { + if (emojiGroups != null) { + categories = new EmojiCategory[(additionalCategories == null ? 0 : additionalCategories.length) + emojiGroups.groups.size()]; + int i = 0; + if (additionalCategories != null) { + for (; i < additionalCategories.length; ++i) { + categories[i] = additionalCategories[i]; + } + } + for (int j = 0; j < emojiGroups.groups.size(); ++j) { + categories[i + j] = EmojiCategory.remote(emojiGroups.groups.get(j)); + } + adapter.notifyDataSetChanged(); + setCategoriesShownT(0); + updateCategoriesShown(categoriesShouldShow, System.currentTimeMillis() - start > 16); + } + }); + } + + public void setShownButtonsAtStart(float buttonsCount) { + shownButtonsAtStart = buttonsCount; + } + + private void onItemClick(int position, View view) { + if (position < 1) { + return; + } + + if (categories == null) { + return; + } + + EmojiCategory category = categories[position - 1]; + int minimumPadding = dp(64); + if (getMeasuredWidth() - view.getRight() < minimumPadding) { + smoothScrollBy((minimumPadding - (getMeasuredWidth() - view.getRight())), 0, CubicBezierInterpolator.EASE_OUT_QUINT); + } else if (view.getLeft() < minimumPadding) { + smoothScrollBy(-(minimumPadding - view.getLeft()), 0, CubicBezierInterpolator.EASE_OUT_QUINT); + } + if (onCategoryClick != null) { + onCategoryClick.run(category); + } + } + + private int getScrollToStartWidth() { + if (getChildCount() > 0) { + View child = getChildAt(0); + if (child instanceof CategoryButton) { + return paddingWidth + Math.max(0, (getChildAdapterPosition(child) - 1) * getHeight()) + (-child.getLeft()); + } else { + return -child.getLeft(); + } + } + return 0; + } + + public void scrollToStart() { + smoothScrollBy(-getScrollToStartWidth(), 0, CubicBezierInterpolator.EASE_OUT_QUINT); + } + + public void selectCategory(EmojiCategory category) { + int index = -1; + if (categories != null) { + for (int i = 0; i < categories.length; ++i) { + if (categories[i] == category) { + index = i; + break; + } + } + } + selectCategory(index); + } + + public void selectCategory(int categoryIndex) { + if (selectedCategoryIndex < 0) { + selectedIndex.set(categoryIndex, true); + } + this.selectedCategoryIndex = categoryIndex; + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + if (child instanceof CategoryButton) { + final int position = getChildAdapterPosition(child); + ((CategoryButton) child).setSelected(selectedCategoryIndex == position - 1, true); + } + } + invalidate(); + } + + public EmojiCategory getSelectedCategory() { + if (categories == null || selectedCategoryIndex < 0 || selectedCategoryIndex >= categories.length) { + return null; + } + return categories[selectedCategoryIndex]; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + updateCategoriesShown(categoriesShouldShow, false); + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + if (paddingView != null) { + paddingView.requestLayout(); + } + } + + private float categoriesShownT = 0; + private ValueAnimator categoriesShownAnimator; + private boolean categoriesShouldShow = true; + public void updateCategoriesShown(boolean show, boolean animated) { + categoriesShouldShow = show; + if (categories == null) { + show = false; + } + + if (categoriesShownT == (show ? 1 : 0)) { + return; + } + + if (categoriesShownAnimator != null) { + categoriesShownAnimator.cancel(); + categoriesShownAnimator = null; + } + + if (animated) { + categoriesShownAnimator = ValueAnimator.ofFloat(categoriesShownT, show ? 1 : 0); + categoriesShownAnimator.addUpdateListener(anm -> { + setCategoriesShownT((float) anm.getAnimatedValue()); + }); + categoriesShownAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setCategoriesShownT((float) categoriesShownAnimator.getAnimatedValue()); + categoriesShownAnimator = null; + } + }); + categoriesShownAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + categoriesShownAnimator.setDuration((categories == null ? 5 : categories.length) * 120L); + categoriesShownAnimator.start(); + } else { + setCategoriesShownT(show ? 1 : 0); + } + } + + private void setCategoriesShownT(float t) { + categoriesShownT = t; + + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + if (child instanceof CategoryButton) { + int position = getChildAdapterPosition(child); + float childT = AndroidUtilities.cascade(t, getChildCount() - 1 - position, getChildCount() - 1, 3f); + if (childT > 0 && child.getAlpha() <= 0) { + ((CategoryButton) child).play(); + } + child.setAlpha(childT); + child.setScaleX(childT); + child.setScaleY(childT); + } + } + + invalidate(); + } + + public boolean isCategoriesShown() { + return categoriesShownT > .5f; + } + + @Override + public void onScrolled(int dx, int dy) { + super.onScrolled(dx, dy); + + boolean scrolledIntoOccupiedWidth = false; + boolean scrolledFully = false; + if (getChildCount() > 0) { + View child = getChildAt(0); + if (child instanceof CategoryButton) { + scrolledIntoOccupiedWidth = true; + scrolledFully = true; + } else { + scrolledIntoOccupiedWidth = child.getRight() <= dontOccupyWidth; + } + } + if (this.scrolledIntoOccupiedWidth != scrolledIntoOccupiedWidth) { + this.scrolledIntoOccupiedWidth = scrolledIntoOccupiedWidth; + if (onScrollIntoOccupiedWidth != null) { + onScrollIntoOccupiedWidth.run(this.scrolledIntoOccupiedWidth ? Math.max(0, getScrollToStartWidth() - (paddingWidth - dontOccupyWidth)) : 0); + } + invalidate(); + } else if (this.scrolledIntoOccupiedWidth && onScrollIntoOccupiedWidth != null) { + onScrollIntoOccupiedWidth.run(Math.max(0, getScrollToStartWidth() - (paddingWidth - dontOccupyWidth))); + } + if (this.scrolledFully != scrolledFully) { + this.scrolledFully = scrolledFully; + if (onScrollFully != null) { + onScrollFully.run(this.scrolledFully); + } + invalidate(); + } + } + + public void setDontOccupyWidth(int dontOccupyWidth) { + this.dontOccupyWidth = dontOccupyWidth; + } + + public void setOnScrollIntoOccupiedWidth(Utilities.Callback onScrollIntoOccupiedWidth) { + this.onScrollIntoOccupiedWidth = onScrollIntoOccupiedWidth; + } + + public void setOnScrollFully(Utilities.Callback onScrollFully) { + this.onScrollFully = onScrollFully; + } + + public void setOnCategoryClick(Utilities.Callback onCategoryClick) { + this.onCategoryClick = onCategoryClick; + } + + public boolean isScrolledIntoOccupiedWidth() { + return scrolledIntoOccupiedWidth; + } + + @Override + public void setBackgroundColor(int color) { + if (backgroundPaint == null) { + backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + backgroundPaint.setColor(color); + leftBoundDrawable = getContext().getResources().getDrawable(R.drawable.gradient_right).mutate(); + leftBoundDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); + rightBoundDrawable = getContext().getResources().getDrawable(R.drawable.gradient_left).mutate(); + rightBoundDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); + } + + private AnimatedFloat selectedAlpha = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private AnimatedFloat selectedIndex = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + @Override + public void draw(Canvas canvas) { + + if (backgroundPaint != null) { + int left = Integer.MAX_VALUE; + int right = Integer.MIN_VALUE; + + for (int i = 0; i < getChildCount(); ++i) { + final View child = getChildAt(i); + if (child instanceof CategoryButton) { + left = Math.min(left, child.getLeft()); + right = Math.max(right, child.getRight()); + } + } + + if (left < right) { + left += (getWidth() + dp(32)) * (1f - categoriesShownT); + right += (getWidth() + dp(32)) * (1f - categoriesShownT); + +// if (left > 0 && rightBoundDrawable != null) { +// rightBoundDrawable.setAlpha(0xFF); +// rightBoundDrawable.setBounds(left - rightBoundDrawable.getIntrinsicWidth(), 0, left, getHeight()); +// rightBoundDrawable.draw(canvas); +// } + canvas.drawRect(left, 0, right, getHeight(), backgroundPaint); + if (right < getWidth() && leftBoundDrawable != null) { + leftBoundDrawable.setAlpha(0xFF); + leftBoundDrawable.setBounds(right, 0, right + leftBoundDrawable.getIntrinsicWidth(), getHeight()); + leftBoundDrawable.draw(canvas); + } + } + } + + drawSelectedHighlight(canvas); + + super.draw(canvas); + + if (leftBoundDrawable != null) { + leftBoundDrawable.setAlpha((int) (0xFF * leftBoundAlpha.set(canScrollHorizontally(-1) && scrolledFully ? 1 : 0) * categoriesShownT)); + if (leftBoundDrawable.getAlpha() > 0) { + leftBoundDrawable.setBounds(0, 0, leftBoundDrawable.getIntrinsicWidth(), getHeight()); + leftBoundDrawable.draw(canvas); + } + } + +// if (rightBoundDrawable != null) { +// rightBoundDrawable.setAlpha((int) (0xFF * rightBoundAlpha.set(canScrollHorizontally(1) ? 1 : 0) * categoriesShownT)); +// if (rightBoundDrawable.getAlpha() > 0) { +// rightBoundDrawable.setBounds(getWidth() - rightBoundDrawable.getIntrinsicWidth(), 0, getWidth(), getHeight()); +// rightBoundDrawable.draw(canvas); +// } +// } + } + + private RectF rect1 = new RectF(), rect2 = new RectF(), rect3 = new RectF(); + private void drawSelectedHighlight(Canvas canvas) { + float alpha = selectedAlpha.set(selectedCategoryIndex >= 0 ? 1 : 0); + float index = selectedCategoryIndex >= 0 ? selectedIndex.set(selectedCategoryIndex) : selectedIndex.get(); + + if (alpha <= 0) { + return; + } + + int fromPosition = Math.max(1, (int) Math.floor(index + 1)); + int toPosition = Math.max(1, (int) Math.ceil(index + 1)); + + View fromChild = null, toChild = null; + + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + int position = getChildAdapterPosition(child); + + if (position == fromPosition) { + fromChild = child; + } + if (position == toPosition) { + toChild = child; + } + + if (fromChild != null && toChild != null) { + break; + } + } + + int wasAlpha = selectedPaint.getAlpha(); + selectedPaint.setAlpha((int) (wasAlpha * alpha)); + if (fromChild != null && toChild != null) { + float t = fromPosition == toPosition ? .5f : (index + 1 - fromPosition) / (toPosition - fromPosition); + getChildBounds(fromChild, rect1); + getChildBounds(toChild, rect2); + AndroidUtilities.lerp(rect1, rect2, t, rect3); +// float T = selectedIndex.getTransitionProgress(); +// float isMiddle = 4f * T * (1f - T); +// float hw = rect3.width() / 2 * (1f + isMiddle * .05f); +// float hh = rect3.height() / 2 * (1f - isMiddle * .1f); +// rect3.set(rect3.centerX() - hw, rect3.centerY() - hh, rect3.centerX() + hw, rect3.centerY() + hh); + canvas.drawRoundRect(rect3, AndroidUtilities.dp(15), AndroidUtilities.dp(15), selectedPaint); + } + selectedPaint.setAlpha(wasAlpha); + } + + private void getChildBounds(View child, RectF rect) { + float cx = (child.getRight() + child.getLeft()) / 2f; + float cy = (child.getBottom() + child.getTop()) / 2f; + float r = child.getWidth() / 2f - dp(1); + float s = child instanceof CategoryButton ? ((CategoryButton) child).getScale() : 1f; + rect.set( + cx - r * s, cy - r * s, + cx + r * s, cy + r * s + ); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + final View child = findChildViewUnder(ev.getX(), ev.getY()); + if (!(child instanceof CategoryButton) || child.getAlpha() < .5f) { + return false; + } + } + return super.dispatchTouchEvent(ev); + } + + private class Adapter extends RecyclerListView.SelectionAdapter { + + private static final int VIEW_TYPE_PADDING = 0; + private static final int VIEW_TYPE_CATEGORY = 1; + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + if (viewType == VIEW_TYPE_PADDING) { + view = paddingView = new View(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int fullWidth = MeasureSpec.getSize(widthMeasureSpec); + if (fullWidth <= 0) { + fullWidth = ((View) getParent()).getMeasuredWidth(); + } + final int BUTTON_WIDTH = MeasureSpec.getSize(heightMeasureSpec) - dp(4); + super.onMeasure( + MeasureSpec.makeMeasureSpec( + paddingWidth = Math.max( + dontOccupyWidth > 0 ? dontOccupyWidth + dp(4) : 0, + (int) (fullWidth - Math.min((getItemCount() - 1) * BUTTON_WIDTH + dp(4), shownButtonsAtStart * BUTTON_WIDTH)) + ), + MeasureSpec.EXACTLY + ), + heightMeasureSpec + ); + } + }; + } else { + view = new CategoryButton(getContext()); + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + if (holder.getItemViewType() == VIEW_TYPE_CATEGORY && categories != null) { + final EmojiCategory category = categories[position - 1]; + final CategoryButton button = (CategoryButton) holder.itemView; + button.set(category, position - 1, selectedCategoryIndex == position - 1); + button.setAlpha(categoriesShownT); + button.setScaleX(categoriesShownT); + button.setScaleY(categoriesShownT); + button.play(); + } + } + + @Override + public void onViewAttachedToWindow(@NonNull ViewHolder holder) { + if (holder.getItemViewType() == VIEW_TYPE_CATEGORY) { + final CategoryButton button = (CategoryButton) holder.itemView; + final int position = holder.getAdapterPosition(); + button.setSelected(selectedCategoryIndex == position - 1, false); + button.play(); + } + } + + @Override + public int getItemViewType(int position) { + return position == 0 ? VIEW_TYPE_PADDING : VIEW_TYPE_CATEGORY; + } + + private int lastItemCount; + + @Override + public int getItemCount() { + final int itemCount = 1 + (categories == null ? 0 : categories.length); + if (itemCount != lastItemCount) { + if (paddingView != null) { + paddingView.requestLayout(); + } + lastItemCount = itemCount; + } + return itemCount; + } + + @Override + public boolean isEnabled(ViewHolder holder) { + return holder.getItemViewType() == VIEW_TYPE_CATEGORY; + } + } + + protected boolean isTabIconsAnimationEnabled(boolean loaded) { + return !SharedConfig.getLiteMode().enabled() && !loaded; + } + + static int loadedCategoryIcons = 0; + + private class CategoryButton extends RLottieImageView { + + private int imageColor; + private float selectedT; + private ValueAnimator selectedAnimator; + private int index; + + public CategoryButton(Context context) { + super(context); + + setImageColor(getThemedColor(Theme.key_chat_emojiPanelIcon)); + setScaleType(ScaleType.CENTER); + + setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_CIRCLE_20DP, dp(15))); + + setLayerNum(layerNum); + } + + public void set(EmojiCategory category, int index, boolean selected) { + this.index = index; + if (loadAnimator != null) { + loadAnimator.cancel(); + loadAnimator = null; + } + if (category.remote) { + setImageResource(0); +// cached = true; + clearAnimationDrawable(); + boolean animated = isTabIconsAnimationEnabled(true); + loaded = false; + loadProgress = 1; + AnimatedEmojiDrawable.getDocumentFetcher(UserConfig.selectedAccount) + .fetchDocument(category.documentId, document -> { + setOnlyLastFrame(!animated); + setAnimation(document, 24, 24); + playAnimation(); + }); + AndroidUtilities.runOnUIThread(() -> { + if (!loaded) { + loadProgress = 0; + } + }, 60); + } else if (category.animated) { + cached = false; + setImageResource(0); + setAnimation(category.iconResId, 24, 24); + playAnimation(); + loadProgress = 1; + } else { + clearAnimationDrawable(); + setImageResource(category.iconResId); + loadProgress = 1; + } + setSelected(selected, false); + } + + private boolean loaded = false; + + @Override + protected void onLoaded() { + loaded = true; + if (loadProgress < 1) { + if (loadAnimator != null) { + loadAnimator.cancel(); + loadAnimator = null; + } + loadAnimator = ValueAnimator.ofFloat(loadProgress, 1f); + loadAnimator.addUpdateListener(anm -> { + loadProgress = (float) anm.getAnimatedValue(); + invalidate(); + }); + loadAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + loadProgress = 1f; + invalidate(); + loadAnimator = null; + } + }); + loadAnimator.setDuration(320); + loadAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + loadAnimator.start(); + } + } + + public void setSelected(boolean selected, boolean animated) { + if (Math.abs(selectedT - (selected ? 1 : 0)) > .01f) { + if (selectedAnimator != null) { + selectedAnimator.cancel(); + selectedAnimator = null; + } + + if (animated) { + selectedAnimator = ValueAnimator.ofFloat(selectedT, selected ? 1 : 0); + selectedAnimator.addUpdateListener(anm -> { + updateSelectedT((float) anm.getAnimatedValue()); + }); + selectedAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + updateSelectedT((float) selectedAnimator.getAnimatedValue()); + selectedAnimator = null; + } + }); + selectedAnimator.setDuration(350); + selectedAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + selectedAnimator.start(); + } else { + updateSelectedT(selected ? 1 : 0); + } + } + } + + private void updateSelectedT(float t) { + selectedT = t; + setImageColor( + ColorUtils.blendARGB( + getThemedColor(Theme.key_chat_emojiPanelIcon), + getThemedColor(Theme.key_chat_emojiPanelIconSelected), + selectedT + ) + ); + invalidate(); + } + + public void setImageColor(int color) { + if (imageColor != color) { + setColorFilter(new PorterDuffColorFilter(imageColor = color, PorterDuff.Mode.MULTIPLY)); + } + } + + @Override + public void draw(Canvas canvas) { + updatePressedProgress(); + float scale = getScale(); + if (scale != 1) { + canvas.save(); + canvas.scale(scale, scale, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); + } + super.draw(canvas); + if (scale != 1) { + canvas.restore(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int size = MeasureSpec.getSize(heightMeasureSpec); + super.onMeasure( + MeasureSpec.makeMeasureSpec(size - dp(4), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY) + ); + } + + private long lastPlayed; + public void play() { + if (System.currentTimeMillis() - lastPlayed > 250) { + lastPlayed = System.currentTimeMillis(); + RLottieDrawable drawable = getAnimatedDrawable(); + if (drawable == null && getImageReceiver() != null) { + drawable = getImageReceiver().getLottieAnimation(); + } + if (drawable != null) { + drawable.stop(); + drawable.setCurrentFrame(0); + drawable.restart(true); + } else if (drawable == null) { + setProgress(0); + playAnimation(); + } + } + } + + float loadProgress = 1f; + float pressedProgress; + ValueAnimator backAnimator; + ValueAnimator loadAnimator; + + public void updatePressedProgress() { + if (isPressed() && pressedProgress != 1f) { + pressedProgress = Utilities.clamp(pressedProgress + (1000f / AndroidUtilities.screenRefreshRate) / 100f, 1f, 0); + invalidate(); + StickerCategoriesListView.this.invalidate(); + } + } + + public float getScale() { + return (0.85f + 0.15f * (1f - pressedProgress)) * loadProgress; + } + + @Override + public void setPressed(boolean pressed) { + if (isPressed() != pressed) { + super.setPressed(pressed); + invalidate(); + StickerCategoriesListView.this.invalidate(); + if (pressed) { + if (backAnimator != null) { + backAnimator.removeAllListeners(); + backAnimator.cancel(); + } + } + if (!pressed && pressedProgress != 0) { + backAnimator = ValueAnimator.ofFloat(pressedProgress, 0); + backAnimator.addUpdateListener(animation -> { + pressedProgress = (float) animation.getAnimatedValue(); + invalidate(); + }); + backAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + backAnimator = null; + } + }); + backAnimator.setInterpolator(new OvershootInterpolator(3.0f)); + backAnimator.setDuration(350); + backAnimator.start(); + } + } + } + } + + public static class EmojiCategory { + + public boolean animated; + public int iconResId; + public String emojis; + + public boolean remote; + public long documentId; + + public String title; + + public static EmojiCategory withAnimatedIcon(int animatedIconResId, String emojis) { + EmojiCategory category = new EmojiCategory(); + category.animated = true; + category.iconResId = animatedIconResId; + category.emojis = emojis; + return category; + } + + public static EmojiCategory withIcon(int iconResId, String emojis) { + EmojiCategory category = new EmojiCategory(); + category.animated = false; + category.iconResId = iconResId; + category.emojis = emojis; + return category; + } + + public static EmojiCategory remote(TLRPC.TL_emojiGroup group) { + EmojiCategory category = new EmojiCategory(); + category.remote = true; + category.documentId = group.icon_emoji_id; + category.emojis = TextUtils.concat(group.emoticons.toArray(new String[0])).toString(); + category.title = group.title; + return category; + } + } + + private static class EmojiGroupFetcher extends Fetcher { + + @Override + protected void getRemote(int currentAccount, @CategoriesType Integer type, long hash, Utilities.Callback3 onResult) { + TLObject req; + if (type == CategoriesType.STATUS) { + req = new TLRPC.TL_messages_getEmojiStatusGroups(); + ((TLRPC.TL_messages_getEmojiStatusGroups) req).hash = (int) hash; + } else if (type == CategoriesType.PROFILE_PHOTOS) { + req = new TLRPC.TL_messages_getEmojiProfilePhotoGroups(); + ((TLRPC.TL_messages_getEmojiProfilePhotoGroups) req).hash = (int) hash; + } else { + req = new TLRPC.TL_messages_getEmojiGroups(); + ((TLRPC.TL_messages_getEmojiGroups) req).hash = (int) hash; + } + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.TL_messages_emojiGroupsNotModified) { + onResult.run(true, null, 0L); + } else if (res instanceof TLRPC.TL_messages_emojiGroups) { + TLRPC.TL_messages_emojiGroups result = (TLRPC.TL_messages_emojiGroups) res; + onResult.run(false, result, (long) result.hash); + } else { + onResult.run(false, null, 0L); + } + }); + } + + @Override + protected void getLocal(int currentAccount, Integer type, Utilities.Callback2 onResult) { + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + SQLiteCursor cursor = null; + try { + SQLiteDatabase database = MessagesStorage.getInstance(currentAccount).getDatabase(); + if (database != null) { + TLRPC.messages_EmojiGroups maybeResult = null; + cursor = database.queryFinalized("SELECT data FROM emoji_groups WHERE type = ?", type); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + maybeResult = TLRPC.messages_EmojiGroups.TLdeserialize(data, data.readInt32(false), true); + data.reuse(); + } + } + + if (!(maybeResult instanceof TLRPC.TL_messages_emojiGroups)) { + onResult.run(0L, null); + } else { + TLRPC.TL_messages_emojiGroups result = (TLRPC.TL_messages_emojiGroups) maybeResult; + onResult.run((long) result.hash, result); + } + } + } catch (Exception e) { + FileLog.e(e); + onResult.run(0L, null); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + }); + } + + @Override + protected void setLocal(int currentAccount, Integer type, TLRPC.TL_messages_emojiGroups data, long hash) { + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + SQLiteDatabase database = MessagesStorage.getInstance(currentAccount).getDatabase(); + if (database != null) { + if (data == null) { + database.executeFast("DELETE FROM emoji_groups WHERE type = " + type).stepThis().dispose(); + } else { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO emoji_groups VALUES(?, ?)"); + state.requery(); + NativeByteBuffer buffer = new NativeByteBuffer(data.getObjectSize()); + data.serializeToStream(buffer); + state.bindInteger(1, type); + state.bindByteBuffer(2, buffer); + state.step(); + buffer.reuse(); + state.dispose(); + } + } + } catch (Exception e) { + FileLog.e(e); + } + }); + } + } + + private static class EmojiSearch extends Fetcher { + @Override + protected void getRemote(int currentAccount, String query, long hash, Utilities.Callback3 onResult) { + TLRPC.TL_messages_searchCustomEmoji req = new TLRPC.TL_messages_searchCustomEmoji(); + req.emoticon = query; + req.hash = hash; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.TL_emojiListNotModified) { + onResult.run(true, null, 0L); + } else if (res instanceof TLRPC.TL_emojiList) { + TLRPC.TL_emojiList list = (TLRPC.TL_emojiList) res; + onResult.run(false, list, list.hash); + } else { + onResult.run(false, null, 0L); + } + }); + } + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerMasksAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerMasksAlert.java index 00cc9d2a8..cfdd98c72 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerMasksAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerMasksAlert.java @@ -142,7 +142,7 @@ public class StickerMasksAlert extends BottomSheet implements NotificationCenter } @Override - public boolean needSend() { + public boolean needSend(int contentType) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java index af281cb38..e911a5c4c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java @@ -3,6 +3,9 @@ package org.telegram.ui.Components; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import androidx.annotation.IntDef; import androidx.annotation.NonNull; @@ -122,6 +125,10 @@ public class StickerSetBulletinLayout extends Bulletin.TwoLineLayout { imageView.setImage(null, null, "webp", null, setObject); } + if (MessageObject.isTextColorEmoji(sticker)) { + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + } + switch (type) { case TYPE_ADDED: if (stickerSet != null) { 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 d039e8215..86db403bb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java @@ -206,7 +206,7 @@ public class StickersAlert extends BottomSheet implements NotificationCenter.Not } @Override - public boolean needSend() { + public boolean needSend(int contentType) { return delegate != null; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StorageDiagramView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StorageDiagramView.java index d6a9beb59..e36918ef4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StorageDiagramView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StorageDiagramView.java @@ -271,10 +271,10 @@ public class StorageDiagramView extends View implements NotificationCenter.Notif text1.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); text2.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); if (dialogId != null) { - int textWidth = text1.getCurrentWidth() + AndroidUtilities.dp(4) + text2.getCurrentWidth(); - int leftpad = (getWidth() - textWidth) / 2; - text1.setBounds(0, AndroidUtilities.dp(115), leftpad + text1.getCurrentWidth(), AndroidUtilities.dp(115 + 30)); - text2.setBounds(leftpad + textWidth - text2.getCurrentWidth(), AndroidUtilities.dp(115 + 3), getWidth(), AndroidUtilities.dp(115 + 3 + 30)); + float textWidth = text1.getCurrentWidth() + AndroidUtilities.dp(4) + text2.getCurrentWidth(); + float leftpad = (getWidth() - textWidth) / 2; + text1.setBounds(0, AndroidUtilities.dp(115), (int) (leftpad + text1.getCurrentWidth()), AndroidUtilities.dp(115 + 30)); + text2.setBounds((int) (leftpad + textWidth - text2.getCurrentWidth()), AndroidUtilities.dp(115 + 3), getWidth(), AndroidUtilities.dp(115 + 3 + 30)); } text1.draw(canvas); text2.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SuggestEmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SuggestEmojiView.java index 919000dbc..3b014dfbe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SuggestEmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SuggestEmojiView.java @@ -11,6 +11,7 @@ import android.graphics.drawable.Drawable; import android.text.Editable; import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextWatcher; import android.view.Gravity; @@ -29,12 +30,20 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.ContentPreviewViewer; import java.util.ArrayList; import java.util.Arrays; @@ -67,9 +76,9 @@ public class SuggestEmojiView extends FrameLayout implements NotificationCenter. boolean visible = visibility == View.VISIBLE; for (int i = 0; i < listView.getChildCount(); ++i) { if (visible) { - ((Adapter.EmojiImageView) listView.getChildAt(i)).attach(); + ((EmojiImageView) listView.getChildAt(i)).attach(); } else { - ((Adapter.EmojiImageView) listView.getChildAt(i)).detach(); + ((EmojiImageView) listView.getChildAt(i)).detach(); } } } @@ -79,6 +88,117 @@ public class SuggestEmojiView extends FrameLayout implements NotificationCenter. private final Adapter adapter; private final LinearLayoutManager layout; + private ContentPreviewViewer.ContentPreviewViewerDelegate previewDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { + @Override + public boolean can() { + return true; + } + + @Override + public boolean needSend(int contentType) { + if (enterView == null) { + return false; + } + ChatActivity fragment = enterView.getParentFragment(); + return fragment != null && fragment.canSendMessage() && (UserConfig.getInstance(UserConfig.selectedAccount).isPremium() || fragment.getCurrentUser() != null && UserObject.isUserSelf(fragment.getCurrentUser())); + } + + @Override + public void sendEmoji(TLRPC.Document emoji) { + if (enterView == null) { + return; + } + ChatActivity fragment = enterView.getParentFragment(); + fragment.sendAnimatedEmoji(emoji, true, 0); + enterView.setFieldText(""); + } + + @Override + public boolean needCopy() { + return UserConfig.getInstance(UserConfig.selectedAccount).isPremium(); + } + + @Override + public void copyEmoji(TLRPC.Document document) { + Spannable spannable = SpannableStringBuilder.valueOf(MessageObject.findAnimatedEmojiEmoticon(document)); + spannable.setSpan(new AnimatedEmojiSpan(document, null), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (AndroidUtilities.addToClipboard(spannable) && enterView != null) { + BulletinFactory.of(enterView.getParentFragment()).createCopyBulletin(LocaleController.getString("EmojiCopied", R.string.EmojiCopied)).show(); + } + } + + @Override + public Boolean canSetAsStatus(TLRPC.Document document) { + if (!UserConfig.getInstance(UserConfig.selectedAccount).isPremium()) { + return null; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + if (user == null) { + return null; + } + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + return document != null && (emojiStatusId == null || emojiStatusId != document.id); + } + + @Override + public void setAsEmojiStatus(TLRPC.Document document, Integer until) { + TLRPC.EmojiStatus status; + if (document == null) { + status = new TLRPC.TL_emojiStatusEmpty(); + } else if (until != null) { + status = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) status).document_id = document.id; + ((TLRPC.TL_emojiStatusUntil) status).until = until; + } else { + status = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) status).document_id = document.id; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + final TLRPC.EmojiStatus previousEmojiStatus = user == null ? new TLRPC.TL_emojiStatusEmpty() : user.emoji_status; + MessagesController.getInstance(currentAccount).updateEmojiStatus(status); + + Runnable undoAction = () -> MessagesController.getInstance(currentAccount).updateEmojiStatus(previousEmojiStatus); + BaseFragment fragment = enterView == null ? null : enterView.getParentFragment(); + if (fragment != null) { + if (document == null) { + final Bulletin.SimpleLayout layout = new Bulletin.SimpleLayout(getContext(), resourcesProvider); + layout.textView.setText(LocaleController.getString("RemoveStatusInfo", R.string.RemoveStatusInfo)); + layout.imageView.setImageResource(R.drawable.msg_settings_premium); + Bulletin.UndoButton undoButton = new Bulletin.UndoButton(getContext(), true, resourcesProvider); + undoButton.setUndoAction(undoAction); + layout.setButton(undoButton); + Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT).show(); + } else { + BulletinFactory.of(fragment).createEmojiBulletin(document, LocaleController.getString("SetAsEmojiStatusInfo", R.string.SetAsEmojiStatusInfo), LocaleController.getString("Undo", R.string.Undo), undoAction).show(); + } + } + } + + @Override + public boolean canSchedule() { + return false; +// return delegate != null && delegate.canSchedule(); + } + + @Override + public boolean isInScheduleMode() { + if (enterView == null) { + return false; + } + ChatActivity fragment = enterView.getParentFragment(); + return fragment.isInScheduleMode(); + } + + @Override + public void openSet(TLRPC.InputStickerSet set, boolean clearsInputField) {} + + @Override + public long getDialogId() { + return 0; + } + }; + + private boolean show, forceClose; private ArrayList keywordResults = new ArrayList<>(); private boolean clear; @@ -102,6 +222,12 @@ public class SuggestEmojiView extends FrameLayout implements NotificationCenter. this.right = right; } } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = ContentPreviewViewer.getInstance().onInterceptTouchEvent(event, listView, 0, previewDelegate, resourcesProvider); + return super.onInterceptTouchEvent(event) || result; + } }; this.listView.setAdapter(this.adapter = new Adapter()); this.layout = new LinearLayoutManager(context); @@ -112,9 +238,11 @@ public class SuggestEmojiView extends FrameLayout implements NotificationCenter. itemAnimator.setTranslationInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); this.listView.setItemAnimator(itemAnimator); this.listView.setSelectorDrawableColor(Theme.getColor(Theme.key_listSelector, resourcesProvider)); - this.listView.setOnItemClickListener((view, position) -> { - onClick(((Adapter.EmojiImageView) view).emoji); + RecyclerListView.OnItemClickListener onItemClickListener; + this.listView.setOnItemClickListener(onItemClickListener = (view, position) -> { + onClick(((EmojiImageView) view).emoji); }); + listView.setOnTouchListener((v, event) -> ContentPreviewViewer.getInstance().onTouch(event, listView, 0, onItemClickListener, previewDelegate, resourcesProvider)); this.containerView.addView(this.listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 44 + 8)); this.addView(this.containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 8 + 44 + 8 + 6.66f, Gravity.BOTTOM)); @@ -619,103 +747,103 @@ public class SuggestEmojiView extends FrameLayout implements NotificationCenter. containerView.invalidate(); } - private class Adapter extends RecyclerListView.SelectionAdapter { + public class EmojiImageView extends View { - private class EmojiImageView extends View { + private String emoji; + public Drawable drawable; + private boolean attached; - private String emoji; - private Drawable drawable; - private boolean attached; + private AnimatedFloat pressed = new AnimatedFloat(this, 350, new OvershootInterpolator(5.0f)); - private AnimatedFloat pressed = new AnimatedFloat(this, 350, new OvershootInterpolator(5.0f)); + public EmojiImageView(Context context) { + super(context); + } - public EmojiImageView(Context context) { - super(context); - } - - private final int paddingDp = 3; - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setPadding(AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp + 6.66f)); - super.onMeasure( + private final int paddingDp = 3; + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setPadding(AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp + 6.66f)); + super.onMeasure( MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(44), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(44 + 8), MeasureSpec.EXACTLY) - ); - } + ); + } - private void setEmoji(String emoji) { - this.emoji = emoji; - if (emoji != null && emoji.startsWith("animated_")) { - try { - long documentId = Long.parseLong(emoji.substring(9)); - if (!(drawable instanceof AnimatedEmojiDrawable) || ((AnimatedEmojiDrawable) drawable).getDocumentId() != documentId) { - setImageDrawable(AnimatedEmojiDrawable.make(currentAccount, AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD, documentId)); - } - } catch (Exception ignore) { - setImageDrawable(null); + private void setEmoji(String emoji) { + this.emoji = emoji; + if (emoji != null && emoji.startsWith("animated_")) { + try { + long documentId = Long.parseLong(emoji.substring(9)); + if (!(drawable instanceof AnimatedEmojiDrawable) || ((AnimatedEmojiDrawable) drawable).getDocumentId() != documentId) { + setImageDrawable(AnimatedEmojiDrawable.make(currentAccount, AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD, documentId)); } - } else { - setImageDrawable(Emoji.getEmojiBigDrawable(emoji)); + } catch (Exception ignore) { + setImageDrawable(null); } - } - - public void setImageDrawable(@Nullable Drawable drawable) { - if (this.drawable instanceof AnimatedEmojiDrawable) { - ((AnimatedEmojiDrawable) this.drawable).removeView(this); - } - this.drawable = drawable; - if (drawable instanceof AnimatedEmojiDrawable && attached) { - ((AnimatedEmojiDrawable) drawable).addView(this); - } - } - - @Override - public void setPressed(boolean pressed) { - super.setPressed(pressed); - invalidate(); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - float scale = 0.8f + 0.2f * (1f - pressed.set(isPressed() ? 1f : 0f)); - if (drawable != null) { - int cx = getWidth() / 2; - int cy = (getHeight() - getPaddingBottom() + getPaddingTop()) / 2; - drawable.setBounds(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); - canvas.scale(scale, scale, cx, cy); - if (drawable instanceof AnimatedEmojiDrawable) { - ((AnimatedEmojiDrawable) drawable).setTime(System.currentTimeMillis()); - } - drawable.draw(canvas); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - attach(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - detach(); - } - - public void detach() { - if (drawable instanceof AnimatedEmojiDrawable) { - ((AnimatedEmojiDrawable) drawable).removeView(this); - } - attached = false; - } - public void attach() { - if (drawable instanceof AnimatedEmojiDrawable) { - ((AnimatedEmojiDrawable) drawable).addView(this); - } - attached = true; + } else { + setImageDrawable(Emoji.getEmojiBigDrawable(emoji)); } } + public void setImageDrawable(@Nullable Drawable drawable) { + if (this.drawable instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) this.drawable).removeView(this); + } + this.drawable = drawable; + if (drawable instanceof AnimatedEmojiDrawable && attached) { + ((AnimatedEmojiDrawable) drawable).addView(this); + } + } + + @Override + public void setPressed(boolean pressed) { + super.setPressed(pressed); + invalidate(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + float scale = 0.8f + 0.2f * (1f - pressed.set(isPressed() ? 1f : 0f)); + if (drawable != null) { + int cx = getWidth() / 2; + int cy = (getHeight() - getPaddingBottom() + getPaddingTop()) / 2; + drawable.setBounds(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); + canvas.scale(scale, scale, cx, cy); + if (drawable instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) drawable).setTime(System.currentTimeMillis()); + } + drawable.draw(canvas); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + attach(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + detach(); + } + + public void detach() { + if (drawable instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) drawable).removeView(this); + } + attached = false; + } + public void attach() { + if (drawable instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) drawable).addView(this); + } + attached = true; + } + } + + private class Adapter extends RecyclerListView.SelectionAdapter { + public Adapter() { // setHasStableIds(true); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java deleted file mode 100644 index dd647cb2a..000000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java +++ /dev/null @@ -1,1803 +0,0 @@ -package org.telegram.ui.Components; - -import static org.telegram.messenger.AndroidUtilities.displayMetrics; -import static org.telegram.messenger.AndroidUtilities.dp; -import static org.telegram.messenger.AndroidUtilities.lerp; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.app.Dialog; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; -import android.graphics.Shader; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Bundle; -import android.os.SystemClock; -import android.text.Layout; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.TextPaint; -import android.text.TextUtils; -import android.text.method.LinkMovementMethod; -import android.text.style.ClickableSpan; -import android.text.style.URLSpan; -import android.text.util.Linkify; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.Window; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.core.widget.NestedScrollView; - -import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.DispatchQueue; -import org.telegram.messenger.Emoji; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; -import org.telegram.messenger.XiaomiUtilities; -import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.BaseFragment; -import org.telegram.ui.ActionBar.Theme; - -import java.util.ArrayList; - -public class TranslateAlert extends Dialog { - - public static volatile DispatchQueue translateQueue = new DispatchQueue("translateQueue", false); - - private FrameLayout bulletinContainer; - private FrameLayout contentView; - private FrameLayout container; - private TextView titleView; - private LinearLayout subtitleView; - private InlineLoadingTextView subtitleFromView; - private ImageView subtitleArrowView; - private TextView subtitleToView; - private ImageView backButton; - private FrameLayout header; - private FrameLayout headerShadowView; - private NestedScrollView scrollView; - private TextBlocksLayout textsView; - private TextView buttonTextView; - private FrameLayout buttonView; - private FrameLayout buttonShadowView; - private TextView allTextsView; - private FrameLayout textsContainerView; - - private FrameLayout.LayoutParams titleLayout; - private FrameLayout.LayoutParams subtitleLayout; - private FrameLayout.LayoutParams headerLayout; - private FrameLayout.LayoutParams scrollViewLayout; - - private int blockIndex = 0; - private ArrayList textBlocks; - - private float containerOpenAnimationT = 0f; - private void openAnimation(float t) { - t = Math.min(Math.max(t, 0f), 1f); - if (containerOpenAnimationT == t) { - return; - } - containerOpenAnimationT = t; - - titleView.setScaleX(lerp(1f, 0.9473f, t)); - titleView.setScaleY(lerp(1f, 0.9473f, t)); - titleLayout.setMargins( - dp(lerp(22, 72, t)), - dp(lerp(22, 8, t)), - titleLayout.rightMargin, - titleLayout.bottomMargin - ); - titleView.setLayoutParams(titleLayout); - subtitleLayout.setMargins( - dp(lerp(22, 72, t)) - LoadingTextView2.paddingHorizontal, - dp(lerp(47, 30, t)) - LoadingTextView2.paddingVertical, - subtitleLayout.rightMargin, - subtitleLayout.bottomMargin - ); - subtitleView.setLayoutParams(subtitleLayout); - - backButton.setAlpha(t); - backButton.setScaleX(.75f + .25f * t); - backButton.setScaleY(.75f + .25f * t); - backButton.setClickable(t > .5f); - headerShadowView.setAlpha(scrollView.getScrollY() > 0 ? 1f : t); - - headerLayout.height = (int) lerp(dp(70), dp(56), t); - header.setLayoutParams(headerLayout); - - scrollViewLayout.setMargins( - scrollViewLayout.leftMargin, - (int) lerp(dp(70), dp(56), t), - scrollViewLayout.rightMargin, - scrollViewLayout.bottomMargin - ); - scrollView.setLayoutParams(scrollViewLayout); - } - - - private boolean openAnimationToAnimatorPriority = false; - private ValueAnimator openAnimationToAnimator = null; - private void openAnimationTo(float to, boolean priority) { - openAnimationTo(to, priority, null); - } - private void openAnimationTo(float to, boolean priority, Runnable onAnimationEnd) { - if (openAnimationToAnimatorPriority && !priority) { - return; - } - openAnimationToAnimatorPriority = priority; - to = Math.min(Math.max(to, 0), 1); - if (openAnimationToAnimator != null) { - openAnimationToAnimator.cancel(); - } - openAnimationToAnimator = ValueAnimator.ofFloat(containerOpenAnimationT, to); - openAnimationToAnimator.addUpdateListener(a -> openAnimation((float) a.getAnimatedValue())); - openAnimationToAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animator) { - openAnimationToAnimatorPriority = false; - if (onAnimationEnd != null) - onAnimationEnd.run(); - } - @Override - public void onAnimationCancel(Animator animator) { - openAnimationToAnimatorPriority = false; - } - }); - openAnimationToAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); - openAnimationToAnimator.setDuration(220); - openAnimationToAnimator.start(); - if (to >= .5 && blockIndex <= 1) { - fetchNext(); - } - } - - private int firstMinHeight = -1; - private int minHeight() { - return minHeight(false); - } - private int minHeight(boolean full) { - int textsViewHeight = textsView == null ? 0 : textsView.getMeasuredHeight(); - int height = - textsViewHeight + - dp( - 66 + // header - 1 + // button separator - 16 + // button top padding - 48 + // button - 16 // button bottom padding - ); - if (firstMinHeight < 0 && textsViewHeight > 0) - firstMinHeight = height; - if (firstMinHeight > 0 && textBlocks.size() > 1 && !full) - return firstMinHeight; - return height; - } - private boolean canExpand() { - return ( - textsView.getBlocksCount() < textBlocks.size() || - minHeight(true) >= (AndroidUtilities.displayMetrics.heightPixels * heightMaxPercent) - ); - } - private void updateCanExpand() { - boolean canExpand = canExpand(); - if (containerOpenAnimationT > 0f && !canExpand) { - openAnimationTo(0f, false); - } - - buttonShadowView.animate().alpha(canExpand ? 1f : 0f).setDuration((long) (Math.abs(buttonShadowView.getAlpha() - (canExpand ? 1f : 0f)) * 220)).start(); - } - - public interface OnLinkPress { - public boolean run(URLSpan urlSpan); - } - - private int currentAccount; - private TLRPC.InputPeer peer; - private int msgId; - private boolean allowScroll = true; - private String fromLanguage, toLanguage; - private CharSequence text; - private BaseFragment fragment; - private boolean noforwards; - private OnLinkPress onLinkPress; - private Runnable onDismiss; - public TranslateAlert(BaseFragment fragment, Context context, int currentAccount, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - this(fragment, context, currentAccount, null, -1, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); - } - public TranslateAlert(BaseFragment fragment, Context context, int currentAccount, TLRPC.InputPeer peer, int msgId, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - super(context, R.style.TransparentDialog); - - this.onLinkPress = onLinkPress; - this.noforwards = noforwards; - this.fragment = fragment; - this.fromLanguage = fromLanguage != null && fromLanguage.equals("und") ? "auto" : fromLanguage; - this.toLanguage = toLanguage; - this.text = text; - this.textBlocks = new ArrayList<>(); - this.textBlocks.add(text); -// cutInBlocks(text, 1024); - this.onDismiss = onDismiss; - - this.currentAccount = currentAccount; - this.peer = peer; - this.msgId = msgId; - - if (Build.VERSION.SDK_INT >= 30) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - } else if (Build.VERSION.SDK_INT >= 21) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - } - - if (noforwards) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); - } - - contentView = new FrameLayout(context); - contentView.setBackground(backDrawable); - contentView.setClipChildren(false); - contentView.setClipToPadding(false); - if (Build.VERSION.SDK_INT >= 21) { - contentView.setFitsSystemWindows(true); - if (Build.VERSION.SDK_INT >= 30) { - contentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - } else { - contentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - } - } - - Paint containerPaint = new Paint(); - containerPaint.setColor(Theme.getColor(Theme.key_dialogBackground)); - containerPaint.setShadowLayer(dp(2), 0, dp(-0.66f), 0x1e000000); - container = new FrameLayout(context) { - private int contentHeight = Integer.MAX_VALUE; - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int fullWidth = MeasureSpec.getSize(widthMeasureSpec); - int fullHeight = MeasureSpec.getSize(widthMeasureSpec); - int minHeight = (int) (AndroidUtilities.displayMetrics.heightPixels * heightMaxPercent); - if (textsView != null && textsView.getMeasuredHeight() <= 0) { - textsView.measure( - MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec) - textsView.getPaddingLeft() - textsView.getPaddingRight() - textsContainerView.getPaddingLeft() - textsContainerView.getPaddingRight(), MeasureSpec.EXACTLY), - 0 - ); - } - int fromHeight = Math.min(minHeight, minHeight()); - int height = (int) (fromHeight + (AndroidUtilities.displayMetrics.heightPixels - fromHeight) * containerOpenAnimationT); - updateCanExpand(); - super.onMeasure( - MeasureSpec.makeMeasureSpec( - (int) Math.max(fullWidth * 0.8f, Math.min(dp(480), fullWidth)), - MeasureSpec.getMode(widthMeasureSpec) - ), - MeasureSpec.makeMeasureSpec( - height, - MeasureSpec.EXACTLY - ) - ); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - contentHeight = Math.min(contentHeight, bottom - top); - } - - private Path containerPath = new Path(); - private RectF containerRect = new RectF(); - private RectF rectF = new RectF(); - @Override - protected void onDraw(Canvas canvas) { - int w = getWidth(), h = getHeight(), r = dp(12 * (1f - containerOpenAnimationT)); - canvas.clipRect(0, 0, w, h); - - containerRect.set(0, 0, w, h + r); - canvas.translate(0, (1f - openingT) * h); - - canvas.drawRoundRect(containerRect, r, r, containerPaint); - super.onDraw(canvas); - } - }; - container.setWillNotDraw(false); - - header = new FrameLayout(context); - - titleView = new TextView(context); - titleView.setPivotX(LocaleController.isRTL ? titleView.getWidth() : 0); - titleView.setPivotY(0); - titleView.setLines(1); - titleView.setText(LocaleController.getString("AutomaticTranslation", R.string.AutomaticTranslation)); - titleView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - titleView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp(19)); - header.addView(titleView, titleLayout = LayoutHelper.createFrame( - LayoutHelper.MATCH_PARENT, - LayoutHelper.WRAP_CONTENT, - Gravity.FILL_HORIZONTAL | Gravity.TOP, - 22, 22,22, 0 - )); - titleView.post(() -> { - titleView.setPivotX(LocaleController.isRTL ? titleView.getWidth() : 0); - }); - - subtitleView = new LinearLayout(context); - subtitleView.setOrientation(LinearLayout.HORIZONTAL); - if (Build.VERSION.SDK_INT >= 17) { - subtitleView.setLayoutDirection(LocaleController.isRTL ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); - } - subtitleView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - - String fromLanguageName = languageName(fromLanguage); - subtitleFromView = new InlineLoadingTextView(context, fromLanguageName == null ? languageName(toLanguage) : fromLanguageName, dp(14), Theme.getColor(Theme.key_player_actionBarSubtitle)) { - @Override - protected void onLoadAnimation(float t) { - MarginLayoutParams lp = (MarginLayoutParams) subtitleFromView.getLayoutParams(); - if (lp != null) { - if (LocaleController.isRTL) { - lp.leftMargin = dp(2f - t * 6f); - } else { - lp.rightMargin = dp(2f - t * 6f); - } - subtitleFromView.setLayoutParams(lp); - } - } - }; - subtitleFromView.showLoadingText = false; - subtitleArrowView = new ImageView(context); - subtitleArrowView.setImageResource(R.drawable.search_arrow); - subtitleArrowView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_player_actionBarSubtitle), PorterDuff.Mode.MULTIPLY)); - if (LocaleController.isRTL) { - subtitleArrowView.setScaleX(-1f); - } - - subtitleToView = new TextView(context); - subtitleToView.setLines(1); - subtitleToView.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); - subtitleToView.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp(14)); - subtitleToView.setText(languageName(toLanguage)); - - if (LocaleController.isRTL) { - subtitleView.setPadding(InlineLoadingTextView.paddingHorizontal, 0, 0, 0); - subtitleView.addView(subtitleToView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); - subtitleView.addView(subtitleArrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 3, 1, 0, 0)); - subtitleView.addView(subtitleFromView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 2, 0, 0, 0)); - } else { - subtitleView.setPadding(0, 0, InlineLoadingTextView.paddingHorizontal, 0); - subtitleView.addView(subtitleFromView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 2, 0)); - subtitleView.addView(subtitleArrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 1, 3, 0)); - subtitleView.addView(subtitleToView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); - } - if (fromLanguageName != null) { - subtitleFromView.set(fromLanguageName); - } - - header.addView(subtitleView, subtitleLayout = LayoutHelper.createFrame( - LayoutHelper.MATCH_PARENT, - LayoutHelper.WRAP_CONTENT, - Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), - 22 - LoadingTextView2.paddingHorizontal / AndroidUtilities.density, - 47 - LoadingTextView2.paddingVertical / AndroidUtilities.density, - 22 - LoadingTextView2.paddingHorizontal / AndroidUtilities.density, - 0 - )); - - backButton = new ImageView(context); - backButton.setImageResource(R.drawable.ic_ab_back); - backButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); - backButton.setScaleType(ImageView.ScaleType.FIT_CENTER); - backButton.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); - backButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector))); - backButton.setClickable(false); - backButton.setAlpha(0f); - backButton.setOnClickListener(e -> dismiss()); - header.addView(backButton, LayoutHelper.createFrame(56, 56, Gravity.LEFT | Gravity.CENTER_HORIZONTAL)); - - headerShadowView = new FrameLayout(context); - headerShadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); - headerShadowView.setAlpha(0); - header.addView(headerShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); - - header.setClipChildren(false); - container.addView(header, headerLayout = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 70, Gravity.FILL_HORIZONTAL | Gravity.TOP)); - - scrollView = new NestedScrollView(context) { - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - return allowScroll && containerOpenAnimationT >= 1f && canExpand() && super.onInterceptTouchEvent(ev); - } - - @Override - public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { - super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); - } - - @Override - protected void onScrollChanged(int l, int t, int oldl, int oldt) { - super.onScrollChanged(l, t, oldl, oldt); - if (checkForNextLoading()) { - openAnimationTo(1f, true); - } - } - }; - scrollView.setClipChildren(true); - - allTextsView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - canvas.translate(getPaddingLeft(), getPaddingTop()); - if (links != null && links.draw(canvas)) { - invalidate(); - } - } - @Override - public boolean onTextContextMenuItem(int id) { - if (id == android.R.id.copy && isFocused()) { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText( - "label", - getText().subSequence( - Math.max(0, Math.min(getSelectionStart(), getSelectionEnd())), - Math.max(0, Math.max(getSelectionStart(), getSelectionEnd())) - ) - ); - clipboard.setPrimaryClip(clip); - BulletinFactory.of(bulletinContainer, null).createCopyBulletin(LocaleController.getString("TextCopied", R.string.TextCopied)).show(); - clearFocus(); - return true; - } else { - return super.onTextContextMenuItem(id); - } - } - }; - links = new LinkSpanDrawable.LinkCollector(allTextsView); - allTextsView.setTextColor(0x00000000); - allTextsView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - allTextsView.setTextIsSelectable(!noforwards); - allTextsView.setHighlightColor(Theme.getColor(Theme.key_chat_inTextSelectionHighlight)); - int handleColor = Theme.getColor(Theme.key_chat_TextSelectionCursor); - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !XiaomiUtilities.isMIUI()) { - Drawable left = allTextsView.getTextSelectHandleLeft(); - left.setColorFilter(handleColor, PorterDuff.Mode.SRC_IN); - allTextsView.setTextSelectHandleLeft(left); - - Drawable right = allTextsView.getTextSelectHandleRight(); - right.setColorFilter(handleColor, PorterDuff.Mode.SRC_IN); - allTextsView.setTextSelectHandleRight(right); - } - } catch (Exception e) {} - allTextsView.setFocusable(true); - allTextsView.setMovementMethod(new LinkMovementMethod()); - - textsView = new TextBlocksLayout(context, dp(16), Theme.getColor(Theme.key_dialogTextBlack), allTextsView); - textsView.setPadding( - dp(22) - LoadingTextView2.paddingHorizontal, - dp(12) - LoadingTextView2.paddingVertical, - dp(22) - LoadingTextView2.paddingHorizontal, - dp(12) - LoadingTextView2.paddingVertical - ); - for (CharSequence blockText : textBlocks) - textsView.addBlock(blockText); - - textsContainerView = new FrameLayout(context); - textsContainerView.addView(textsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - - scrollView.addView(textsContainerView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); - - container.addView(scrollView, scrollViewLayout = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL, 0, 70, 0, 81)); - - fetchNext(); - - buttonShadowView = new FrameLayout(context); - buttonShadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); - container.addView(buttonShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, 80)); - - buttonTextView = new TextView(context); - buttonTextView.setLines(1); - buttonTextView.setSingleLine(true); - buttonTextView.setGravity(Gravity.CENTER_HORIZONTAL); - buttonTextView.setEllipsize(TextUtils.TruncateAt.END); - buttonTextView.setGravity(Gravity.CENTER); - buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); - buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - buttonTextView.setText(LocaleController.getString("CloseTranslation", R.string.CloseTranslation)); - - buttonView = new FrameLayout(context); -// buttonView.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 4)); - buttonView.setBackground(Theme.AdaptiveRipple.filledRect(Theme.getColor(Theme.key_featuredStickers_addButton), 4)); - buttonView.addView(buttonTextView); - buttonView.setOnClickListener(e -> dismiss()); - - container.addView(buttonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 16, 16, 16, 16)); - contentView.addView(container, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL)); - - bulletinContainer = new FrameLayout(context); - contentView.addView(bulletinContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 0, 81)); - } - public void showDim(boolean enable) { - contentView.setBackground(enable ? backDrawable : null); - } - - private boolean scrollAtBottom() { - View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1); - int bottom = view.getBottom(); - LoadingTextView2 lastUnloadedBlock = textsView.getFirstUnloadedBlock(); - if (lastUnloadedBlock != null) { - bottom = lastUnloadedBlock.getTop(); - } - int diff = (bottom - (scrollView.getHeight() + scrollView.getScrollY())); - return diff <= textsContainerView.getPaddingBottom(); - } - - private void setScrollY(float t) { - openAnimation(t); - openingT = Math.max(Math.min(1f + t, 1), 0); - backDrawable.setAlpha((int) (openingT * 51)); - container.invalidate(); - bulletinContainer.setTranslationY((1f - openingT) * Math.min(minHeight(), displayMetrics.heightPixels * heightMaxPercent)); - } - private void scrollYTo(float t) { - scrollYTo(t, null); - } - private void scrollYTo(float t, Runnable onAnimationEnd) { - openAnimationTo(t, false, onAnimationEnd); - openTo(1f + t, false); - } - private float fromScrollY = 0; - private float getScrollY() { - return Math.max(Math.min(containerOpenAnimationT - (1 - openingT), 1), 0); - } - - private boolean hasSelection() { - return allTextsView.hasSelection(); - } - - private Rect containerRect = new Rect(); - private Rect textRect = new Rect(); - private Rect translateMoreRect = new Rect(); - private Rect buttonRect = new Rect(); - private Rect backRect = new Rect(); - private Rect scrollRect = new Rect(); - private float fromY = 0; - private boolean pressedOutside = false; - private boolean maybeScrolling = false; - private boolean scrolling = false; - private boolean fromScrollRect = false; - private boolean fromTranslateMoreView = false; - private float fromScrollViewY = 0; - private Spannable allTexts = null; - private LinkSpanDrawable pressedLink; - private LinkSpanDrawable.LinkCollector links; - - @Override - public boolean dispatchTouchEvent(@NonNull MotionEvent event) { - try { - float x = event.getX(); - float y = event.getY(); - - container.getGlobalVisibleRect(containerRect); - if (!containerRect.contains((int) x, (int) y)) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressedOutside = true; - return true; - } else if (event.getAction() == MotionEvent.ACTION_UP) { - if (pressedOutside) { - pressedOutside = false; - dismiss(); - return true; - } - } - } - - try { - allTextsView.getGlobalVisibleRect(textRect); - if (textRect.contains((int) x, (int) y) && !maybeScrolling) { - Layout allTextsLayout = allTextsView.getLayout(); - int tx = (int) (x - allTextsView.getLeft() - container.getLeft()), - ty = (int) (y - allTextsView.getTop() - container.getTop() - scrollView.getTop() + scrollView.getScrollY()); - final int line = allTextsLayout.getLineForVertical(ty); - final int off = allTextsLayout.getOffsetForHorizontal(line, tx); - - final float left = allTextsLayout.getLineLeft(line); - if (allTexts instanceof Spannable && left <= tx && left + allTextsLayout.getLineWidth(line) >= tx) { - ClickableSpan[] linkSpans = allTexts.getSpans(off, off, ClickableSpan.class); - if (linkSpans != null && linkSpans.length >= 1) { - if (event.getAction() == MotionEvent.ACTION_UP && pressedLink.getSpan() == linkSpans[0]) { - ((ClickableSpan) pressedLink.getSpan()).onClick(allTextsView); - if (links != null) { - links.removeLink(pressedLink); - } - pressedLink = null; - allTextsView.setTextIsSelectable(!noforwards); - } else if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressedLink = new LinkSpanDrawable(linkSpans[0], fragment.getResourceProvider(), tx, ty, false); - if (links != null) { - links.addLink(pressedLink); - } - LinkPath path = pressedLink.obtainNewPath(); - int start = allTexts.getSpanStart(pressedLink.getSpan()); - int end = allTexts.getSpanEnd(pressedLink.getSpan()); - path.setCurrentLayout(allTextsLayout, start, 0); - allTextsLayout.getSelectionPath(start, end, path); - } - allTextsView.invalidate(); - return true; - } - } - } - if (pressedLink != null) { - if (links != null) { - links.clear(); - } - pressedLink = null; - } - } catch (Exception e2) { - e2.printStackTrace(); - } - - scrollView.getGlobalVisibleRect(scrollRect); - backButton.getGlobalVisibleRect(backRect); - buttonView.getGlobalVisibleRect(buttonRect); - if (pressedLink == null && /*!(scrollRect.contains((int) x, (int) y) && !canExpand() && containerOpenAnimationT < .5f && !scrolling) &&*/ !hasSelection()) { - if ( - !backRect.contains((int) x, (int) y) && - !buttonRect.contains((int) x, (int) y) && - event.getAction() == MotionEvent.ACTION_DOWN - ) { - fromScrollRect = scrollRect.contains((int) x, (int) y) && (containerOpenAnimationT > 0 || !canExpand()); - maybeScrolling = true; - scrolling = scrollRect.contains((int) x, (int) y) && textsView.getBlocksCount() > 0 && !((LoadingTextView2) textsView.getBlockAt(0)).loaded; - fromY = y; - fromScrollY = getScrollY(); - fromScrollViewY = scrollView.getScrollY(); - return super.dispatchTouchEvent(event) || true; - } else if (maybeScrolling && (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_UP)) { - float dy = fromY - y; - if (fromScrollRect) { - dy = -Math.max(0, -(fromScrollViewY + dp(48)) - dy); - if (dy < 0) { - scrolling = true; - allTextsView.setTextIsSelectable(false); - } - } else if (Math.abs(dy) > dp(4) && !fromScrollRect) { - scrolling = true; - allTextsView.setTextIsSelectable(false); - scrollView.stopNestedScroll(); - allowScroll = false; - } - float fullHeight = AndroidUtilities.displayMetrics.heightPixels, - minHeight = Math.min(minHeight(), fullHeight * heightMaxPercent); - float scrollYPx = minHeight * (1f - -Math.min(Math.max(fromScrollY, -1), 0)) + (fullHeight - minHeight) * Math.min(1, Math.max(fromScrollY, 0)) + dy; - float scrollY = scrollYPx > minHeight ? (scrollYPx - minHeight) / (fullHeight - minHeight) : -(1f - scrollYPx / minHeight); - if (!canExpand()) { - scrollY = Math.min(scrollY, 0); - } - updateCanExpand(); - - if (scrolling) { - setScrollY(scrollY); - if (event.getAction() == MotionEvent.ACTION_UP) { - scrolling = false; - allTextsView.setTextIsSelectable(!noforwards); - maybeScrolling = false; - allowScroll = true; - scrollYTo( - Math.abs(dy) > dp(16) ? - Math.round(fromScrollY) + (scrollY > fromScrollY ? 1f : -1f) * (float) Math.ceil(Math.abs(fromScrollY - scrollY)) : - Math.round(fromScrollY), - () -> { - contentView.post(this::checkForNextLoading); - } - ); - } - return true; - } - } - } - if (hasSelection() && maybeScrolling) { - scrolling = false; - allTextsView.setTextIsSelectable(!noforwards); - maybeScrolling = false; - allowScroll = true; - scrollYTo(Math.round(fromScrollY)); - } - return super.dispatchTouchEvent(event); - } catch (Exception e) { - e.printStackTrace(); - return super.dispatchTouchEvent(event); - } - } - - private float openingT = 0f; - private ValueAnimator openingAnimator; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - contentView.setPadding(0, 0, 0, 0); - setContentView(contentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - - Window window = getWindow(); - - window.setWindowAnimations(R.style.DialogNoAnimation); - WindowManager.LayoutParams params = window.getAttributes(); - params.width = ViewGroup.LayoutParams.MATCH_PARENT; - params.gravity = Gravity.TOP | Gravity.LEFT; - params.dimAmount = 0; - params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; - params.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - if (Build.VERSION.SDK_INT >= 21) { - params.flags |= - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | - WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | - WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; - } - params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; - params.height = ViewGroup.LayoutParams.MATCH_PARENT; - window.setAttributes(params); - - int navigationbarColor = Theme.getColor(Theme.key_windowBackgroundWhite); - AndroidUtilities.setNavigationBarColor(window, navigationbarColor); - AndroidUtilities.setLightNavigationBar(window, AndroidUtilities.computePerceivedBrightness(navigationbarColor) > .721); - - container.forceLayout(); - } - - protected ColorDrawable backDrawable = new ColorDrawable(0xff000000) { - @Override - public void setAlpha(int alpha) { - super.setAlpha(alpha); - container.invalidate(); - } - }; - @Override - public void show() { - super.show(); - - openAnimation(0); - openTo(1, true, true); - } - - private boolean dismissed = false; - @Override - public void dismiss() { - if (dismissed) - return; - dismissed = true; - - openTo(0, true); - } - private void openTo(float t, boolean priority) { - openTo(t, priority, false); - } - private void openTo(float t) { - openTo(t, false); - } - private float heightMaxPercent = .85f; - - private boolean fastHide = false; - private boolean openingAnimatorPriority = false; - private void openTo(float t, boolean priority, boolean setAfter) { - final float T = Math.min(Math.max(t, 0), 1); - if (openingAnimatorPriority && !priority) { - return; - } - openingAnimatorPriority = priority; - if (openingAnimator != null) { - openingAnimator.cancel(); - } - openingAnimator = ValueAnimator.ofFloat(openingT, T); - backDrawable.setAlpha((int) (openingT * 51)); - openingAnimator.addUpdateListener(a -> { - openingT = (float) a.getAnimatedValue(); - container.invalidate(); - backDrawable.setAlpha((int) (openingT * 51)); - bulletinContainer.setTranslationY((1f - openingT) * Math.min(minHeight(), displayMetrics.heightPixels * heightMaxPercent)); - }); - if (T <= 0f) { - if (onDismiss != null) { - onDismiss.run(); - } - } - openingAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animator) { - if (T <= 0f) { - dismissInternal(); - } else if (setAfter) { - allTextsView.setTextIsSelectable(!noforwards); - allTextsView.invalidate(); - scrollView.stopNestedScroll(); - openAnimation(T - 1f); - } - openingAnimatorPriority = false; - } - }); - openingAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); - openingAnimator.setDuration((long) (Math.abs(openingT - T) * (fastHide ? 200 : 380))); - openingAnimator.setStartDelay(setAfter ? 60 : 0); - openingAnimator.start(); - } - public void dismissInternal() { - try { - super.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - } - - public String languageName(String locale) { - // sorry, no more vodka - if (locale == null || locale.equals("und") || locale.equals("auto")) { - return null; - } - LocaleController.LocaleInfo thisLanguageInfo = LocaleController.getInstance().getBuiltinLanguageByPlural(locale), - currentLanguageInfo = LocaleController.getInstance().getCurrentLocaleInfo(); - if (thisLanguageInfo == null) { - return null; - } - boolean isCurrentLanguageEnglish = currentLanguageInfo != null && "en".equals(currentLanguageInfo.pluralLangCode); - if (isCurrentLanguageEnglish) { - // trying to show this language in a language of the interface, but there are only names in english and its own - return thisLanguageInfo.nameEnglish; - } else { - return thisLanguageInfo.name; - } - } - - public void updateSourceLanguage() { - if (languageName(fromLanguage) != null) { - subtitleView.setAlpha(1); - if (!subtitleFromView.loaded) { - subtitleFromView.loaded(languageName(fromLanguage)); - } - } else if (loaded) { - subtitleView.animate().alpha(0).setDuration(150).start(); - } - } - - private ArrayList cutInBlocks(CharSequence full, int maxBlockSize) { - ArrayList blocks = new ArrayList<>(); - if (full == null) { - return blocks; - } - while (full.length() > maxBlockSize) { - String maxBlockStr = full.subSequence(0, maxBlockSize).toString(); - int n = -1; - if (n == -1) n = maxBlockStr.lastIndexOf("\n\n"); - if (n == -1) n = maxBlockStr.lastIndexOf("\n"); - if (n == -1) n = maxBlockStr.lastIndexOf(". "); - if (n == -1) n = Math.min(maxBlockStr.length(), maxBlockSize); - blocks.add(full.subSequence(0, n + 1)); - full = full.subSequence(n + 1, full.length()); - } - if (full.length() > 0) { - blocks.add(full); - } - return blocks; - } - - private boolean loading = false; - private boolean loaded = false; - private boolean fetchNext() { - if (loading) { - return false; - } - loading = true; - - if (blockIndex >= textBlocks.size()) { - return false; - } - - fetchTranslation( - textBlocks.get(blockIndex), - Math.min((blockIndex + 1) * 1000, 3500), - (String translatedText, String sourceLanguage) -> { - loaded = true; - Spannable spannable = new SpannableStringBuilder(translatedText); - try { - MessageObject.addUrlsByPattern(false, spannable, false, 0, 0, true); - URLSpan[] urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); - for (int i = 0; i < urlSpans.length; ++i) { - URLSpan urlSpan = urlSpans[i]; - int start = spannable.getSpanStart(urlSpan), - end = spannable.getSpanEnd(urlSpan); - if (start == -1 || end == -1) { - continue; - } - spannable.removeSpan(urlSpan); - spannable.setSpan( - new ClickableSpan() { - @Override - public void onClick(@NonNull View view) { - if (onLinkPress != null) { - if (onLinkPress.run(urlSpan)) { - fastHide = true; - dismiss(); - } - } else { - AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); - } - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); - if (!(urlSpan instanceof URLSpanNoUnderline)) { - ds.setUnderlineText(true); - } - ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); - ds.setAlpha(alpha); - } - }, - start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ); - } - - AndroidUtilities.addLinks(spannable, Linkify.WEB_URLS); - urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); - for (int i = 0; i < urlSpans.length; ++i) { - URLSpan urlSpan = urlSpans[i]; - int start = spannable.getSpanStart(urlSpan), - end = spannable.getSpanEnd(urlSpan); - if (start == -1 || end == -1) { - continue; - } - spannable.removeSpan(urlSpan); - spannable.setSpan( - new ClickableSpan() { - @Override - public void onClick(@NonNull View view) { - AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); - if (!(urlSpan instanceof URLSpanNoUnderline)) - ds.setUnderlineText(true); - ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); - ds.setAlpha(alpha); - } - }, - start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ); - } - - spannable = (Spannable) Emoji.replaceEmoji(spannable, allTextsView.getPaint().getFontMetricsInt(), dp(14), false); - } catch (Exception e) { - e.printStackTrace(); - } - - SpannableStringBuilder allTextsBuilder = new SpannableStringBuilder(allTexts == null ? "" : allTexts); - if (blockIndex != 0) { - allTextsBuilder.append("\n"); - } - allTextsBuilder.append(spannable); - allTexts = allTextsBuilder; - textsView.setWholeText(allTexts); - - LoadingTextView2 block = textsView.getBlockAt(blockIndex); - if (block != null) { - block.loaded(spannable, () -> contentView.post(this::checkForNextLoading)); - } - - if (sourceLanguage != null) { - fromLanguage = sourceLanguage; - } - updateSourceLanguage(); - - if (blockIndex == 0 && AndroidUtilities.isAccessibilityScreenReaderEnabled()) { - if (allTextsView != null) { - allTextsView.requestFocus(); - } - } - - blockIndex++; - loading = false; - }, - (boolean rateLimit) -> { - if (rateLimit) { - Toast.makeText(getContext(), LocaleController.getString("TranslationFailedAlert1", R.string.TranslationFailedAlert1), Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(getContext(), LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2), Toast.LENGTH_SHORT).show(); - } - - if (blockIndex == 0) { - dismiss(); - } - } - ); - return true; - } - - private boolean checkForNextLoading() { - if (scrollAtBottom()) { - fetchNext(); - return true; - } - return false; - } - - public interface OnTranslationSuccess { - public void run(String translated, String sourceLanguage); - } - public interface OnTranslationFail { - public void run(boolean rateLimit); - } - private void fetchTranslation(CharSequence text, long minDuration, OnTranslationSuccess onSuccess, OnTranslationFail onFail) { - final long start = System.currentTimeMillis(); - Utilities.Callback onDone = (string) -> { - AndroidUtilities.runOnUIThread(() -> { - if (string != null) { - onSuccess.run(string, null); - } else { - onFail.run(false); - } - }, Math.max((System.currentTimeMillis() - start) - minDuration, 1)); - }; - if (peer != null) { - translateText(currentAccount, peer, msgId, fromLanguage, toLanguage, onDone); - } else if (text != null) { - translateText(currentAccount, text.toString(), fromLanguage, toLanguage, onDone); - } else { - onFail.run(false); - } - } - - private static void translateText(int currentAccount, TLRPC.InputPeer peer, int msg_id, String from_lang, String to_lang, Utilities.Callback onDone) { - if (onDone == null) { - return; - } - if (from_lang == null || from_lang.equals("und")) { - from_lang = null; - } - - TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); - req.peer = peer; - req.msg_id = msg_id; - req.flags |= 1; - if (from_lang != null) { - req.from_lang = from_lang; - req.flags |= 4; - } - req.to_lang = to_lang; - - try { - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (res instanceof TLRPC.TL_messages_translateResultText) { - onDone.run(((TLRPC.TL_messages_translateResultText) res).text); - return; - } - onDone.run(null); - }); - } catch (Exception e) { - FileLog.e(e); - } - } - - private static void translateText(int currentAccount, String text, String from_lang, String to_lang, Utilities.Callback onDone) { - if (onDone == null) { - return; - } - if (from_lang == null || from_lang.equals("und")) { - from_lang = null; - } - - TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); - req.flags |= 2; - req.text = text; - if (from_lang != null) { - req.from_lang = from_lang; - req.flags |= 4; - } - req.to_lang = to_lang; - - try { - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (res instanceof TLRPC.TL_messages_translateResultText) { - onDone.run(((TLRPC.TL_messages_translateResultText) res).text); - return; - } - onDone.run(null); - }); - } catch (Exception e) { - FileLog.e(e); - } - } - - public static TranslateAlert showAlert(Context context, BaseFragment fragment, int currentAccount, TLRPC.InputPeer peer, int msgId, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - TranslateAlert alert = new TranslateAlert(fragment, context, currentAccount, peer, msgId, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); - if (fragment != null) { - if (fragment.getParentActivity() != null) { - fragment.showDialog(alert); - } - } else { - alert.show(); - } - return alert; - } - public static TranslateAlert showAlert(Context context, BaseFragment fragment, int currentAccount, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - TranslateAlert alert = new TranslateAlert(fragment, context, currentAccount, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); - if (fragment != null) { - if (fragment.getParentActivity() != null) { - fragment.showDialog(alert); - } - } else { - alert.show(); - } - return alert; - } - - private static final int MOST_SPEC = View.MeasureSpec.makeMeasureSpec(999999, View.MeasureSpec.AT_MOST); - public static class TextBlocksLayout extends ViewGroup { - - private TextView wholeTextView; - private final int fontSize; - private final int textColor; - - public TextBlocksLayout(Context context, int fontSize, int textColor, TextView wholeTextView) { - super(context); - - this.fontSize = fontSize; - this.textColor = textColor; - - if (wholeTextView != null) { - wholeTextView.setPadding(LoadingTextView2.paddingHorizontal, LoadingTextView2.paddingVertical, LoadingTextView2.paddingHorizontal, LoadingTextView2.paddingVertical); - addView(this.wholeTextView = wholeTextView); - } - } - - public void setWholeText(CharSequence wholeText) { - // having focus on that text view can cause jumping scroll to the top after loading a new block - // TODO(dkaraush): preserve selection after setting a new text - wholeTextView.clearFocus(); - wholeTextView.setText(wholeText); - } - - public LoadingTextView2 addBlock(CharSequence fromText) { - LoadingTextView2 textView = new LoadingTextView2(getContext(), fromText, getBlocksCount() > 0, fontSize, textColor); - textView.setFocusable(false); - addView(textView); - if (wholeTextView != null) { - wholeTextView.bringToFront(); - } - return textView; - } - - public int getBlocksCount() { - return getChildCount() - (wholeTextView != null ? 1 : 0); - } - public LoadingTextView2 getBlockAt(int i) { - View child = getChildAt(i); - if (child instanceof LoadingTextView2) { - return (LoadingTextView2) child; - } - return null; - } - - public LoadingTextView2 getFirstUnloadedBlock() { - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - if (block != null && !block.loaded) - return block; - } - return null; - } - - private static final int gap = -LoadingTextView2.paddingVertical * 4 + dp(.48f); - public int height() { - int height = 0; - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - height += getBlockAt(i).height(); - } - return getPaddingTop() + height + getPaddingBottom(); - } - - protected void onHeightUpdated(int height) {} - - public void updateHeight() { - boolean updated; - int newHeight = height(); - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); - if (lp == null) { - lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, newHeight); - updated = true; - } else { - updated = lp.height != newHeight; - lp.height = newHeight; - } - - if (updated) { - this.setLayoutParams(lp); - onHeightUpdated(newHeight); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int count = getBlocksCount(); - final int innerWidthMeasureSpec = MeasureSpec.makeMeasureSpec( - MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(), - MeasureSpec.getMode(widthMeasureSpec) - ); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - block.measure(innerWidthMeasureSpec, MOST_SPEC); - } - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height(), MeasureSpec.EXACTLY)); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - int y = 0; - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - final int blockHeight = block.height(); - final int translationY = i > 0 ? gap : 0; - block.layout(getPaddingLeft(), getPaddingTop() + y + translationY, r - l - getPaddingRight(), getPaddingTop() + y + blockHeight + translationY); - y += blockHeight; - if (i > 0 && i < count - 1) { - y += gap; - } - } - - wholeTextView.measure( - MeasureSpec.makeMeasureSpec(r - l - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(b - t - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY) - ); - wholeTextView.layout( - getPaddingLeft(), - getPaddingTop(), - (r - l) - getPaddingRight(), - getPaddingTop() + wholeTextView.getMeasuredHeight() - ); - } - } - - public static class InlineLoadingTextView extends ViewGroup { - - public static final int paddingHorizontal = dp(6), - paddingVertical = 0; - - - public boolean showLoadingText = true; - - private final TextView fromTextView; - private final TextView toTextView; - - private final ValueAnimator loadingAnimator; - - private final long start = SystemClock.elapsedRealtime(); - public InlineLoadingTextView(Context context, CharSequence fromText, int fontSize, int textColor) { - super(context); - - setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); - setClipChildren(false); - setWillNotDraw(false); - - fromTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MOST_SPEC, MOST_SPEC); - } - }; - fromTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - fromTextView.setTextColor(textColor); - fromTextView.setText(fromText); - fromTextView.setLines(1); - fromTextView.setMaxLines(1); - fromTextView.setSingleLine(true); - fromTextView.setEllipsize(null); - fromTextView.setFocusable(false); - fromTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - addView(fromTextView); - - toTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MOST_SPEC, MOST_SPEC); - } - }; - toTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - toTextView.setTextColor(textColor); - toTextView.setLines(1); - toTextView.setMaxLines(1); - toTextView.setSingleLine(true); - toTextView.setEllipsize(null); - toTextView.setFocusable(true); - addView(toTextView); - - int c1 = Theme.getColor(Theme.key_dialogBackground), - c2 = Theme.getColor(Theme.key_dialogBackgroundGray); - LinearGradient gradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{ c1, c2, c1 }, new float[] { 0, 0.67f, 1f }, Shader.TileMode.REPEAT); - loadingPaint.setShader(gradient); - - loadingAnimator = ValueAnimator.ofFloat(0f, 1f); - loadingAnimator.addUpdateListener(a -> invalidate()); - loadingAnimator.setDuration(Long.MAX_VALUE); - loadingAnimator.start(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - fromTextView.measure(0, 0); - toTextView.measure(0, 0); - super.onMeasure( - MeasureSpec.makeMeasureSpec( - (int) AndroidUtilities.lerp(fromTextView.getMeasuredWidth(), toTextView.getMeasuredWidth(), loadingT) + getPaddingLeft() + getPaddingRight(), - MeasureSpec.EXACTLY - ), - MeasureSpec.makeMeasureSpec( - Math.max(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight()), - MeasureSpec.EXACTLY - ) - ); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - fromTextView.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + fromTextView.getMeasuredWidth(), getPaddingTop() + fromTextView.getMeasuredHeight()); - toTextView.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + toTextView.getMeasuredWidth(), getPaddingTop() + toTextView.getMeasuredHeight()); - updateWidth(); - } - - private void updateWidth() { - boolean updated; - - int newWidth = (int) AndroidUtilities.lerp(fromTextView.getMeasuredWidth(), toTextView.getMeasuredWidth(), loadingT) + getPaddingLeft() + getPaddingRight(); - int newHeight = Math.max(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight()); - LayoutParams lp = getLayoutParams(); - if (lp == null) { - lp = new LinearLayout.LayoutParams(newWidth, newHeight); - updated = true; - } else { - updated = lp.width != newWidth || lp.height != newHeight; - lp.width = newWidth; - lp.height = newHeight; - } - - if (updated) - setLayoutParams(lp); - } - - protected void onLoadAnimation(float t) {} - - public boolean loaded = false; - public float loadingT = 0f; - private ValueAnimator loadedAnimator = null; - public void loaded(CharSequence loadedText) { - loaded(loadedText, 350,null); - } - public void loaded(CharSequence loadedText, Runnable onLoadEnd) { - loaded(loadedText, 350, onLoadEnd); - } - public void loaded(CharSequence loadedText, long duration, Runnable onLoadEnd) { - loaded = true; - toTextView.setText(loadedText); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator == null) { - loadedAnimator = ValueAnimator.ofFloat(0f, 1f); - loadedAnimator.addUpdateListener(a -> { - loadingT = (float) a.getAnimatedValue(); - updateWidth(); - invalidate(); - onLoadAnimation(loadingT); - }); - loadedAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onLoadEnd != null) - onLoadEnd.run(); - } - }); - loadedAnimator.setDuration(duration); - loadedAnimator.setInterpolator(CubicBezierInterpolator.EASE_BOTH); - loadedAnimator.start(); - } - } - public void set(CharSequence loadedText) { - loaded = true; - toTextView.setText(loadedText); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator != null) { - loadedAnimator.cancel(); - loadedAnimator = null; - } - loadingT = 1f; - requestLayout(); - updateWidth(); - invalidate(); - onLoadAnimation(1f); - } - - private final RectF rect = new RectF(); - private final Path inPath = new Path(), - tempPath = new Path(), - loadingPath = new Path(), - shadePath = new Path(); - private final Paint loadingPaint = new Paint(); - private final float gradientWidth = dp(350f); - @Override - protected void onDraw(Canvas canvas) { - float w = getWidth(), h = getHeight(); - - float cx = LocaleController.isRTL ? Math.max(w / 2f, w - 8f) : Math.min(w / 2f, 8f), - cy = Math.min(h / 2f, 8f), - R = (float) Math.sqrt(Math.max( - Math.max(cx*cx + cy*cy, (w-cx)*(w-cx) + cy*cy), - Math.max(cx*cx + (h-cy)*(h-cy), (w-cx)*(w-cx) + (h-cy)*(h-cy)) - )), - r = loadingT * R; - inPath.reset(); - inPath.addCircle(cx, cy, r, Path.Direction.CW); - - canvas.save(); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - - loadingPaint.setAlpha((int) ((1f - loadingT) * 255)); - float dx = gradientWidth - (((SystemClock.elapsedRealtime() - start) / 1000f * gradientWidth) % gradientWidth); - shadePath.reset(); - shadePath.addRect(0, 0, w, h, Path.Direction.CW); - - loadingPath.reset(); - rect.set(0, 0, w, h); - loadingPath.addRoundRect(rect, dp(4), dp(4), Path.Direction.CW); - canvas.clipPath(loadingPath); - canvas.translate(-dx, 0); - shadePath.offset(dx, 0f, tempPath); - canvas.drawPath(tempPath, loadingPaint); - canvas.translate(dx, 0); - canvas.restore(); - - if (showLoadingText && fromTextView != null) { - canvas.save(); - rect.set(0, 0, w, h); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * .08f), Canvas.ALL_SAVE_FLAG); - fromTextView.draw(canvas); - canvas.restore(); - canvas.restore(); - } - - if (toTextView != null) { - canvas.save(); - canvas.clipPath(inPath); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * loadingT), Canvas.ALL_SAVE_FLAG); - toTextView.draw(canvas); - if (loadingT < 1f) { - canvas.restore(); - } - canvas.restore(); - } - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - return false; - } - } - - public static class LoadingTextView2 extends ViewGroup { - - public static final int paddingHorizontal = dp(6), - paddingVertical = dp(1.5f); - - public boolean showLoadingText = true; - - private final TextView fromTextView; - private final TextView toTextView; - - private final boolean scaleFromZero; - private final ValueAnimator loadingAnimator; - - private final long start = SystemClock.elapsedRealtime(); - private float scaleT = 1f; - public LoadingTextView2(Context context, CharSequence fromText, boolean scaleFromZero, int fontSize, int textColor) { - super(context); - - setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); - setClipChildren(false); - setWillNotDraw(false); - setFocusable(false); - - fromTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - }; - fromTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - fromTextView.setTextColor(textColor); - fromTextView.setText(fromText); - fromTextView.setLines(0); - fromTextView.setMaxLines(0); - fromTextView.setSingleLine(false); - fromTextView.setEllipsize(null); - fromTextView.setFocusable(false); - fromTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - addView(fromTextView); - - toTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - }; - toTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - toTextView.setTextColor(textColor); - toTextView.setLines(0); - toTextView.setMaxLines(0); - toTextView.setSingleLine(false); - toTextView.setEllipsize(null); - toTextView.setFocusable(false); - toTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - addView(toTextView); - - int c1 = Theme.getColor(Theme.key_dialogBackground), - c2 = Theme.getColor(Theme.key_dialogBackgroundGray); - LinearGradient gradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{ c1, c2, c1 }, new float[] { 0, 0.67f, 1f }, Shader.TileMode.REPEAT); - loadingPaint.setShader(gradient); - - this.scaleFromZero = scaleFromZero; - loadingAnimator = ValueAnimator.ofFloat(0f, 1f); - if (scaleFromZero) - scaleT = 0; - loadingAnimator.addUpdateListener(a -> { - invalidate(); - if (scaleFromZero) { - boolean scaleTWasNoFull = scaleT < 1f; - scaleT = Math.min(1, (SystemClock.elapsedRealtime() - start) / 400f); - if (scaleTWasNoFull) { - updateHeight(); - } - } - }); - loadingAnimator.setDuration(Long.MAX_VALUE); - loadingAnimator.start(); - } - - public int innerHeight() { - return (int) (AndroidUtilities.lerp(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight(), loadingT) * scaleT); - } - public int height() { - return getPaddingTop() + innerHeight() + getPaddingBottom(); - } - - private void updateHeight() { - ViewParent parent = getParent(); - if (parent instanceof TextBlocksLayout) { - ((TextBlocksLayout) parent).updateHeight(); - } - } - - public boolean loaded = false; - private float loadingT = 0f; - private ValueAnimator loadedAnimator = null; - public void loaded(CharSequence loadedText, Runnable onLoadEnd) { - loaded = true; - toTextView.setText(loadedText); - layout(); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator == null) { - loadedAnimator = ValueAnimator.ofFloat(0f, 1f); - loadedAnimator.addUpdateListener(a -> { - loadingT = (float) a.getAnimatedValue(); - updateHeight(); - invalidate(); - }); - loadedAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onLoadEnd != null) - onLoadEnd.run(); - } - }); - loadedAnimator.setDuration(350); - loadedAnimator.setInterpolator(CubicBezierInterpolator.EASE_BOTH); - loadedAnimator.start(); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = MeasureSpec.getSize(widthMeasureSpec), - innerWidth = width - getPaddingLeft() - getPaddingRight(); - if (fromTextView.getMeasuredWidth() <= 0 || lastWidth != innerWidth) { - measureChild(fromTextView, innerWidth); - updateLoadingPath(); - } - if (toTextView.getMeasuredWidth() <= 0 || lastWidth != innerWidth) { - measureChild(toTextView, innerWidth); - } - lastWidth = innerWidth; - super.onMeasure( - MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height(), MeasureSpec.EXACTLY) - ); - } - - int lastWidth = 0; - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - layout(r - l - getPaddingLeft() - getPaddingRight(), true); - } - private void layout(int width, boolean force) { - if (lastWidth != width || force) { - layout(lastWidth = width); - } - } - private void layout(int width) { - measureChild(fromTextView, width); - layoutChild(fromTextView, width); - updateLoadingPath(); - measureChild(toTextView, width); - layoutChild(toTextView, width); - updateHeight(); - } - private void layout() { - layout(lastWidth); - } - private void measureChild(View view, int width) { - view.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MOST_SPEC); - } - private void layoutChild(View view, int width) { - view.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + width, getPaddingTop() + view.getMeasuredHeight()); - } - - private RectF fetchedPathRect = new RectF(); - private void updateLoadingPath() { - if (fromTextView != null && fromTextView.getMeasuredWidth() > 0) { - loadingPath.reset(); - Layout loadingLayout = fromTextView.getLayout(); - if (loadingLayout != null) { - CharSequence text = loadingLayout.getText(); - final int lineCount = loadingLayout.getLineCount(); - for (int i = 0; i < lineCount; ++i) { - float s = loadingLayout.getLineLeft(i), - e = loadingLayout.getLineRight(i), - l = Math.min(s, e), - r = Math.max(s, e); - int start = loadingLayout.getLineStart(i), - end = loadingLayout.getLineEnd(i); - boolean hasNonEmptyChar = false; - for (int j = start; j < end; ++j) { - char c = text.charAt(j); - if (c != '\n' && c != '\t' && c != ' ') { - hasNonEmptyChar = true; - break; - } - } - if (!hasNonEmptyChar) - continue; - fetchedPathRect.set( - l - paddingHorizontal, - loadingLayout.getLineTop(i) - paddingVertical, - r + paddingHorizontal, - loadingLayout.getLineBottom(i) + paddingVertical - ); - loadingPath.addRoundRect(fetchedPathRect, dp(4), dp(4), Path.Direction.CW); - } - } - } - } - - private final RectF rect = new RectF(); - private final Path inPath = new Path(), - tempPath = new Path(), - loadingPath = new Path(), - shadePath = new Path(); - private final Paint loadingPaint = new Paint(); - private final float gradientWidth = dp(350f); - @Override - protected void onDraw(Canvas canvas) { - float w = getWidth(), h = getHeight(); - - float cx = LocaleController.isRTL ? Math.max(w / 2f, w - 8f) : Math.min(w / 2f, 8f), - cy = Math.min(h / 2f, 8f), - R = (float) Math.sqrt(Math.max( - Math.max(cx*cx + cy*cy, (w-cx)*(w-cx) + cy*cy), - Math.max(cx*cx + (h-cy)*(h-cy), (w-cx)*(w-cx) + (h-cy)*(h-cy)) - )), - r = loadingT * R; - inPath.reset(); - inPath.addCircle(cx, cy, r, Path.Direction.CW); - - canvas.save(); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - - loadingPaint.setAlpha((int) ((1f - loadingT) * 255)); - float dx = gradientWidth - (((SystemClock.elapsedRealtime() - start) / 1000f * gradientWidth) % gradientWidth); - shadePath.reset(); - shadePath.addRect(0, 0, w, h, Path.Direction.CW); - - canvas.translate(paddingHorizontal, paddingVertical); - canvas.clipPath(loadingPath); - canvas.translate(-paddingHorizontal, -paddingVertical); - canvas.translate(-dx, 0); - shadePath.offset(dx, 0f, tempPath); - canvas.drawPath(tempPath, loadingPaint); - canvas.translate(dx, 0); - canvas.restore(); - - if (showLoadingText && fromTextView != null) { - canvas.save(); - rect.set(0, 0, w, h); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * .08f), Canvas.ALL_SAVE_FLAG); - fromTextView.draw(canvas); - canvas.restore(); - canvas.restore(); - } - - if (toTextView != null) { - canvas.save(); - canvas.clipPath(inPath); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * loadingT), Canvas.ALL_SAVE_FLAG); - toTextView.draw(canvas); - if (loadingT < 1f) { - canvas.restore(); - } - canvas.restore(); - } - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - return false; - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java index 403f65fd2..7ae9144ac 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java @@ -1,589 +1,228 @@ package org.telegram.ui.Components; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; -import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; -import android.graphics.Shader; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.Build; -import android.os.Bundle; -import android.os.SystemClock; -import android.text.Layout; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; -import android.text.method.LinkMovementMethod; import android.text.style.ClickableSpan; import android.text.style.URLSpan; -import android.text.util.Linkify; -import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewParent; import android.view.WindowManager; +import android.view.animation.LinearInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.math.MathUtils; +import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import org.json.JSONArray; -import org.json.JSONTokener; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.DispatchQueue; import org.telegram.messenger.Emoji; -import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.TranslateController; +import org.telegram.messenger.Utilities; import org.telegram.messenger.XiaomiUtilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.HttpURLConnection; -import java.net.URI; -import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; -public class TranslateAlert2 extends BottomSheet { +public class TranslateAlert2 extends BottomSheet implements NotificationCenter.NotificationCenterDelegate { - public static volatile DispatchQueue translateQueue = new DispatchQueue("translateQueue", false); + private Integer reqId; + private CharSequence reqText; + private ArrayList reqMessageEntities; + private TLRPC.InputPeer reqPeer; + private int reqMessageId; - public RecyclerListView listView; - private LinearLayoutManager layoutManager; - private View paddingView; -// private FrameLayout container; - private TextView titleView; - private LinearLayout subtitleView; - private InlineLoadingTextView subtitleFromView; - private ImageView subtitleArrowView; - private TextView subtitleToView; - private ImageView backButton; - private HeaderView header; - private FrameLayout headerShadowView; -// private NestedScrollView scrollView; - private TextBlocksLayout textsView; - private TextView buttonTextView; - private FrameLayout buttonContainerView; - private FrameLayout buttonView; - private FrameLayout buttonShadowView; - private TextView allTextsView; -// private FrameLayout textsContainerView; - private FrameLayout bulletinContainer; - -// private FrameLayout.LayoutParams titleLayout; -// private FrameLayout.LayoutParams subtitleLayout; -// private FrameLayout.LayoutParams headerLayout; -// private FrameLayout.LayoutParams scrollViewLayout; - - private int blockIndex = 0; - private ArrayList textBlocks; -// -// private boolean canExpand() { -// return ( -// textsView.getBlocksCount() < textBlocks.size() || -// minHeight(true) >= (AndroidUtilities.displayMetrics.heightPixels * heightMaxPercent) -// ); -// } -// private void updateCanExpand() { -// boolean canExpand = canExpand(); -// if (containerOpenAnimationT > 0f && !canExpand) { -// openAnimationTo(0f, false); -// } -// -// buttonShadowView.animate().alpha(canExpand ? 1f : 0f).setDuration((long) (Math.abs(buttonShadowView.getAlpha() - (canExpand ? 1f : 0f)) * 220)).start(); -// } - - public interface OnLinkPress { - public boolean run(URLSpan urlSpan); - } - - @Override - public void onBackPressed() { - dismiss(); - } - - private class HeaderView extends FrameLayout { - - public HeaderView(Context context) { - super(context); - } - - private float expandedT = 0f; - public void setExpandedT(float value) { - backButton.setAlpha(value); - headerShadowView.setAlpha(value); - if (Math.abs(expandedT - value) > 0.01f) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && expandedT > .5f != value > .5f) { - int flags = containerView.getSystemUiVisibility(); - if (value > .5f) { - flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } else { - flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } - containerView.setSystemUiVisibility(flags); - } - expandedT = value; - invalidate(); - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - titleView.layout( - dp(22), - dp(22), - right - left - dp(22), - dp(22) + titleView.getMeasuredHeight() - ); - subtitleView.layout( - dp(22) - LoadingTextView2.paddingHorizontal, - dp(47) - LoadingTextView2.paddingVertical, - right - left - dp(22) - LoadingTextView2.paddingHorizontal, - dp(47) - LoadingTextView2.paddingVertical + subtitleView.getMeasuredHeight() - ); - backButton.layout(0, 0, dp(56), dp(56)); - headerShadowView.layout(0, dp(55), right - left, dp(56)); - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (child == titleView) { - canvas.save(); - canvas.translate(dp(50 * expandedT), dp(-14 * expandedT)); - canvas.scale(1f - expandedT * 0.111f, 1f - expandedT * 0.111f, child.getX(), child.getY() + child.getMeasuredHeight() / 2); - boolean result = super.drawChild(canvas, child, drawingTime); - canvas.restore(); - return result; - } else if (child == subtitleView) { - canvas.save(); - canvas.translate(dp(50 * expandedT), dp(-17 * expandedT)); - boolean result = super.drawChild(canvas, child, drawingTime); - canvas.restore(); - return result; - } else { - return super.drawChild(canvas, child, drawingTime); - } - } - - @Override - protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { - if (child == backButton) { - backButton.measure( - MeasureSpec.makeMeasureSpec(dp(56), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(dp(56), MeasureSpec.EXACTLY) - ); - } else { - super.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec); - } - } - } - - private boolean allowScroll = true; private String fromLanguage, toLanguage; - private CharSequence text; - private BaseFragment fragment; - private boolean noforwards; - private OnLinkPress onLinkPress; - private Runnable onDismiss; + private String prevToLanguage; - public void updateCanExpand() { - boolean canExpand = listView.canScrollVertically(1) || listView.canScrollVertically(-1); - float canExpandAlpha = canExpand ? 1f : 0f; - buttonShadowView.animate().alpha(canExpandAlpha).setDuration(200).start(); - allowScroll = canExpand; + private HeaderView headerView; + private LoadingTextView loadingTextView; + private FrameLayout textViewContainer; + private LinkSpanDrawable.LinksTextView textView; + + private boolean sheetTopNotAnimate; + private RecyclerListView listView; + private LinearLayoutManager layoutManager; + private PaddedAdapter adapter; + + private View buttonShadowView; + private FrameLayout buttonView; + private TextView buttonTextView; + + private BaseFragment fragment; + private Utilities.CallbackReturn onLinkPress; + private boolean firstTranslation = true; + + public TranslateAlert2( + Context context, + String fromLanguage, String toLanguage, + CharSequence text, ArrayList entities, + Theme.ResourcesProvider resourcesProvider + ) { + this(context, fromLanguage, toLanguage, text, entities, null, 0, resourcesProvider); } - public TranslateAlert2(BaseFragment fragment, Context context, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - super(context, false); + private TranslateAlert2( + Context context, + String fromLanguage, String toLanguage, + CharSequence text, ArrayList entities, TLRPC.InputPeer peer, int messageId, + Theme.ResourcesProvider resourcesProvider + ) { + super(context, false, resourcesProvider); + + backgroundPaddingLeft = 0; + fixNavigationBar(); - this.onLinkPress = onLinkPress; - this.noforwards = noforwards; - this.fragment = fragment; - this.fromLanguage = fromLanguage != null && fromLanguage.equals("und") ? "auto" : fromLanguage; + this.reqText = text; + this.reqPeer = peer; + this.reqMessageId = messageId; + + this.fromLanguage = fromLanguage; this.toLanguage = toLanguage; - this.text = text; - this.textBlocks = cutInBlocks(text, 1024); - this.onDismiss = onDismiss; - if (noforwards) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); - } + containerView = new ContainerView(context); + sheetTopAnimated = new AnimatedFloat(containerView, 320, CubicBezierInterpolator.EASE_OUT_QUINT); - allTextsView = new TextView(context) { + loadingTextView = new LoadingTextView(context); + loadingTextView.setPadding(dp(22), dp(12), dp(22), dp(6)); + loadingTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, SharedConfig.fontSize); + loadingTextView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); + loadingTextView.setLinkTextColor(Theme.multAlpha(getThemedColor(Theme.key_dialogTextBlack), .2f)); + loadingTextView.setText(Emoji.replaceEmoji(text == null ? "" : text.toString(), loadingTextView.getPaint().getFontMetricsInt(), true)); + + textViewContainer = new FrameLayout(context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - canvas.save(); - canvas.translate(getPaddingLeft(), getPaddingTop()); - if (links != null && links.draw(canvas)) { - invalidate(); - } - canvas.restore(); - } - @Override - public boolean onTextContextMenuItem(int id) { - if (id == android.R.id.copy && isFocused()) { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText( - "label", - getText().subSequence( - Math.max(0, Math.min(getSelectionStart(), getSelectionEnd())), - Math.max(0, Math.max(getSelectionStart(), getSelectionEnd())) - ) - ); - clipboard.setPrimaryClip(clip); - BulletinFactory.of(bulletinContainer, null).createCopyBulletin(LocaleController.getString("TextCopied", R.string.TextCopied)).show(); - clearFocus(); - return true; - } else { - return super.onTextContextMenuItem(id); - } + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), heightMeasureSpec); } }; - links = new LinkSpanDrawable.LinkCollector(allTextsView); - allTextsView.setTextColor(0x00000000); - allTextsView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - allTextsView.setTextIsSelectable(!noforwards); - allTextsView.setHighlightColor(Theme.getColor(Theme.key_chat_inTextSelectionHighlight)); + textView = new LinkSpanDrawable.LinksTextView(context, resourcesProvider); + textView.setDisablePaddingsOffsetY(true); + textView.setPadding(dp(22), dp(12), dp(22), dp(6)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, SharedConfig.fontSize); + textView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); + textView.setLinkTextColor(getThemedColor(Theme.key_chat_messageLinkIn)); + textView.setTextIsSelectable(true); + textView.setHighlightColor(getThemedColor(Theme.key_chat_inTextSelectionHighlight)); + int handleColor = getThemedColor(Theme.key_chat_TextSelectionCursor); try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !XiaomiUtilities.isMIUI()) { - final int handleColor = Theme.getColor(Theme.key_chat_TextSelectionCursor); - - Drawable left = allTextsView.getTextSelectHandleLeft(); + Drawable left = textView.getTextSelectHandleLeft(); left.setColorFilter(handleColor, PorterDuff.Mode.SRC_IN); - allTextsView.setTextSelectHandleLeft(left); + textView.setTextSelectHandleLeft(left); - Drawable right = allTextsView.getTextSelectHandleRight(); + Drawable right = textView.getTextSelectHandleRight(); right.setColorFilter(handleColor, PorterDuff.Mode.SRC_IN); - allTextsView.setTextSelectHandleRight(right); + textView.setTextSelectHandleRight(right); } - } catch (Exception ignore) {} - allTextsView.setMovementMethod(new LinkMovementMethod()); - - textsView = new TextBlocksLayout(context, dp(16), Theme.getColor(Theme.key_dialogTextBlack), allTextsView) { - @Override - protected void onHeightUpdated(int height, int dy) { -// if (dy != 0 && listView != null && listView.canScrollVertically(-dy)) { -// try { -// listView.scrollBy(0, -dy); -// } catch (Exception ignore) {} -// } - paddingView.requestFocus(); - paddingView.requestLayout(); - } - }; - textsView.setPadding( - dp(22) - LoadingTextView2.paddingHorizontal, - dp(12 + 8) - LoadingTextView2.paddingVertical, - dp(22) - LoadingTextView2.paddingHorizontal, - dp(12) - LoadingTextView2.paddingVertical - ); - for (CharSequence blockText : textBlocks) { - textsView.addBlock(blockText); - } - - final Paint backgroundPaint = new Paint(); - backgroundPaint.setColor(Theme.getColor(Theme.key_dialogBackground)); - backgroundPaint.setShadowLayer(dp(2), 0, dp(-0.66f), 0x1e000000); - final Paint navigationBarPaint = new Paint(); - navigationBarPaint.setColor(Theme.getColor(Theme.key_dialogBackgroundGray)); - - containerView = new FrameLayout(context) { - @Override - public boolean hasOverlappingRendering() { - return false; - } - - @Override - protected void dispatchDraw(Canvas canvas) { - float top = getCurrentItemTop(); - float expandedT = 1f - Math.max(0, Math.min(top / dp(48), 1)); - header.setTranslationY(top); - header.setExpandedT(expandedT); - updateCanExpand(); - float r = dp(12) * (1f - expandedT); - AndroidUtilities.rectTmp.set(backgroundPaddingLeft, getPaddingTop() + top - (AndroidUtilities.statusBarHeight + dp(8)) * expandedT + dp(8), getWidth() - backgroundPaddingLeft, getPaddingTop() + top + dp(20)); - canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, navigationBarPaint); - AndroidUtilities.rectTmp.set(backgroundPaddingLeft, getPaddingTop() + top, getWidth() - backgroundPaddingLeft, getPaddingTop() + getHeight() + dp(12)); - canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, backgroundPaint); - - super.dispatchDraw(canvas); - } - - @Override - public void setTranslationY(float translationY) { - super.setTranslationY(translationY); - onContainerTranslationYChanged(translationY); - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (child == listView) { - canvas.save(); - canvas.clipRect(0, getPaddingTop() + listView.getPaddingTop(), getWidth(), getHeight() - listView.getPaddingBottom()); - boolean result = super.drawChild(canvas, child, drawingTime); - canvas.restore(); - return result; - } else { - return super.drawChild(canvas, child, drawingTime); - } - } - }; - containerView.setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); - containerView.setClipChildren(false); - containerView.setClipToPadding(false); - containerView.setWillNotDraw(false); + } catch (Exception e) {} + textViewContainer.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); listView = new RecyclerListView(context) { - @Override - public View getFocusedChild() { - return textsView; + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getY() < getSheetTop() - getTop()) { + dismiss(); + return true; + } + return super.dispatchTouchEvent(ev); } @Override - public void onScrolled(int dx, int dy) { - checkForNextLoading(); - super.onScrolled(dx, dy); + protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { + return true; + } + + @Override + public void requestChildFocus(View child, View focused) {} + }; + listView.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS); + listView.setPadding(0, AndroidUtilities.statusBarHeight + dp(56), 0, dp(80)); + listView.setClipToPadding(true); + listView.setLayoutManager(layoutManager = new LinearLayoutManager(context)); + listView.setAdapter(adapter = new PaddedAdapter(context, loadingTextView)); + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + containerView.invalidate(); + updateButtonShadow(listView.canScrollVertically(1)); + } + + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + sheetTopNotAnimate = false; + } + if ((newState == RecyclerView.SCROLL_STATE_IDLE || newState == RecyclerView.SCROLL_STATE_SETTLING) && getSheetTop(false) > 0 && getSheetTop(false) < dp(64 + 32) && listView.canScrollVertically(1) && hasEnoughHeight()) { + sheetTopNotAnimate = true; + listView.smoothScrollBy(0, (int) getSheetTop(false)); + } + } + }); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator() { + @Override + protected void onChangeAnimationUpdate(RecyclerView.ViewHolder holder) { containerView.invalidate(); } @Override - public void onScrollStateChanged(int state) { - super.onScrollStateChanged(state); - - if (state == SCROLL_STATE_IDLE && header.expandedT > 0 && header.expandedT < 1) { - smoothScrollBy(0, (int) header.getTranslationY()); - } - } - - @Override - public boolean onTouchEvent(MotionEvent e) { - if (!allowScroll) { - return false; - } - return super.onTouchEvent(e); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent e) { - if (!allowScroll) { - return false; - } - return super.onInterceptTouchEvent(e); + protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { + containerView.invalidate(); } }; - listView.setClipChildren(true); - listView.setClipToPadding(true); - listView.setPadding(0, dp(56), 0, dp(80)); - listView.setLayoutManager(layoutManager = new LinearLayoutManager(context) { - @Override - public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { - super.onLayoutChildren(recycler, state); + itemAnimator.setDurations(180); + itemAnimator.setInterpolator(new LinearInterpolator()); + listView.setItemAnimator(itemAnimator); + containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); - } - }); - layoutManager.setOrientation(RecyclerView.VERTICAL); - layoutManager.setReverseLayout(true); - listView.setAdapter(new RecyclerView.Adapter() { - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - if (viewType == 0) { - return new RecyclerListView.Holder(textsView); - } - return new RecyclerListView.Holder(paddingView); - } + headerView = new HeaderView(context); + containerView.addView(headerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 78, Gravity.TOP | Gravity.FILL_HORIZONTAL)); - @Override - public int getItemViewType(int position) { - return position; - } + buttonView = new FrameLayout(context); + buttonView.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {} - - @Override - public int getItemCount() { - return 2; - } - }); - - View redDot = new View(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(32), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(32), MeasureSpec.EXACTLY)); - } - }; - redDot.setBackgroundColor(0xffff0000); - containerView.addView(redDot); - - containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - - header = new HeaderView(context); - header.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - containerView.addView(header, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL)); - - titleView = new TextView(context); - titleView.setPivotX(LocaleController.isRTL ? titleView.getWidth() : 0); - titleView.setPivotY(0); - titleView.setLines(1); - titleView.setText(LocaleController.getString("AutomaticTranslation", R.string.AutomaticTranslation)); - titleView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - titleView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - header.addView(titleView, LayoutHelper.createFrame( - LayoutHelper.MATCH_PARENT, - LayoutHelper.WRAP_CONTENT, - Gravity.FILL_HORIZONTAL | Gravity.TOP, - 22, 22,22, 0 - )); - titleView.post(() -> { - titleView.setPivotX(LocaleController.isRTL ? titleView.getWidth() : 0); - }); - - subtitleView = new LinearLayout(context); - subtitleView.setOrientation(LinearLayout.HORIZONTAL); - if (Build.VERSION.SDK_INT >= 17) { - subtitleView.setLayoutDirection(LocaleController.isRTL ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); - } - subtitleView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - - String fromLanguageName = languageName(fromLanguage); - subtitleFromView = new InlineLoadingTextView(context, fromLanguageName == null ? languageName(toLanguage) : fromLanguageName, dp(14), Theme.getColor(Theme.key_player_actionBarSubtitle)) { - @Override - protected void onLoadAnimation(float t) { - MarginLayoutParams lp = (MarginLayoutParams) subtitleFromView.getLayoutParams(); - if (lp != null) { - if (LocaleController.isRTL) { - lp.leftMargin = dp(2f - t * 6f); - } else { - lp.rightMargin = dp(2f - t * 6f); - } - subtitleFromView.setLayoutParams(lp); - } - } - }; - subtitleFromView.showLoadingText = false; - subtitleArrowView = new ImageView(context); - subtitleArrowView.setImageResource(R.drawable.search_arrow); - subtitleArrowView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_player_actionBarSubtitle), PorterDuff.Mode.MULTIPLY)); - if (LocaleController.isRTL) { - subtitleArrowView.setScaleX(-1f); - } - - subtitleToView = new TextView(context); - subtitleToView.setLines(1); - subtitleToView.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); - subtitleToView.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp(14)); - subtitleToView.setText(languageName(toLanguage)); - - if (LocaleController.isRTL) { - subtitleView.setPadding(InlineLoadingTextView.paddingHorizontal, 0, 0, 0); - subtitleView.addView(subtitleToView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); - subtitleView.addView(subtitleArrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 3, 1, 3, 0)); - subtitleView.addView(subtitleFromView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); - } else { - subtitleView.setPadding(0, 0, InlineLoadingTextView.paddingHorizontal, 0); - subtitleView.addView(subtitleFromView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); - subtitleView.addView(subtitleArrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 3, 1, 3, 0)); - subtitleView.addView(subtitleToView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); - } - if (fromLanguageName != null) { - subtitleFromView.set(fromLanguageName); - } - - header.addView(subtitleView, LayoutHelper.createFrame( - LayoutHelper.MATCH_PARENT, - LayoutHelper.WRAP_CONTENT, - Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), - 22 - LoadingTextView2.paddingHorizontal / AndroidUtilities.density, - 47 - LoadingTextView2.paddingVertical / AndroidUtilities.density, - 22 - LoadingTextView2.paddingHorizontal / AndroidUtilities.density, - 0 - )); - - backButton = new ImageView(context); - backButton.setImageResource(R.drawable.ic_ab_back); - backButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); - backButton.setScaleType(ImageView.ScaleType.FIT_CENTER); - backButton.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); - backButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector))); - backButton.setClickable(false); - backButton.setAlpha(0f); - backButton.setOnClickListener(e -> { - if (backButton.getAlpha() > .5f) { - dismiss(); - } - }); - header.addView(backButton, LayoutHelper.createFrame(56, 56, Gravity.LEFT | Gravity.CENTER_HORIZONTAL)); - - headerShadowView = new FrameLayout(context); - headerShadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); - headerShadowView.setAlpha(0); - header.addView(headerShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); - - paddingView = new View(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int padding = (int) Math.max(AndroidUtilities.displaySize.y * .5f, listView.getMeasuredHeight() - listView.getPaddingTop() - listView.getPaddingBottom() - textsView.height()); - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(padding, MeasureSpec.EXACTLY)); - } - }; - -// -// header.setClipChildren(false); -// container.addView(header, headerLayout = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 70, Gravity.FILL_HORIZONTAL | Gravity.TOP)); - -// textsContainerView = new FrameLayout(context); -// textsContainerView.addView(textsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - -// scrollView.addView(textsContainerView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); - -// container.addView(scrollView, scrollViewLayout = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL, 0, 70, 0, 81)); - - fetchNext(); - - -// container.addView(buttonShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, 80)); + buttonShadowView = new View(context); + buttonShadowView.setBackgroundColor(getThemedColor(Theme.key_dialogShadowLine)); + buttonShadowView.setAlpha(0); + buttonView.addView(buttonShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, AndroidUtilities.getShadowHeight() / dpf2(1), Gravity.TOP | Gravity.FILL_HORIZONTAL)); buttonTextView = new TextView(context); buttonTextView.setLines(1); @@ -595,584 +234,831 @@ public class TranslateAlert2 extends BottomSheet { buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setText(LocaleController.getString("CloseTranslation", R.string.CloseTranslation)); + buttonTextView.setBackground(Theme.AdaptiveRipple.filledRect(Theme.getColor(Theme.key_featuredStickers_addButton), 6)); + buttonTextView.setOnClickListener(e -> dismiss()); + buttonView.addView(buttonTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 16, 16, 16, 16)); - buttonView = new FrameLayout(context); - buttonView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); - buttonView.addView(buttonTextView); - buttonView.setOnClickListener(e -> dismiss()); + containerView.addView(buttonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); - buttonContainerView = new FrameLayout(context); - buttonContainerView.addView(buttonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 16, 16, 16, 16)); - - buttonShadowView = new FrameLayout(context); - buttonShadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); - buttonShadowView.setAlpha(0); - buttonContainerView.addView(buttonShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.TOP | Gravity.FILL_HORIZONTAL)); - - containerView.addView(buttonContainerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); - - bulletinContainer = new FrameLayout(context); - containerView.addView(bulletinContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 0, 81)); + translate(); } - private float getCurrentItemTop() { - View child = listView.getChildAt(0); - if (child == null) { - return 0; + private boolean hasEnoughHeight() { + float height = 0; + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (listView.getChildAdapterPosition(child) == 1) + height += child.getHeight(); } - RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); - if (holder != null && holder.getAdapterPosition() == 0) { - return Math.max(0, child.getY() - header.getMeasuredHeight()); + return height >= listView.getHeight() - listView.getPaddingTop() - listView.getPaddingBottom(); + } + + public void translate() { + if (reqId != null) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + reqId = null; + } + TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); + TLRPC.TL_textWithEntities textWithEntities = new TLRPC.TL_textWithEntities(); + textWithEntities.text = reqText == null ? "" : reqText.toString(); + if (reqMessageEntities != null) { + textWithEntities.entities = reqMessageEntities; + } + if (reqPeer != null) { + req.flags |= 1; + req.peer = reqPeer; + req.id.add(reqMessageId); + } else { + req.flags |= 2; + req.text.add(textWithEntities); + } +// if (fromLanguage != null && !"und".equals(fromLanguage)) { +// req.flags |= 4; +// req.from_lang = fromLanguage; +// } + String lang = toLanguage; + if (lang != null) { + lang = lang.split("_")[0]; + } + if ("nb".equals(lang)) { + lang = "no"; + } + req.to_lang = lang; + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { + AndroidUtilities.runOnUIThread(() -> { + reqId = null; + if (res instanceof TLRPC.TL_messages_translateResult && + !((TLRPC.TL_messages_translateResult) res).result.isEmpty() && + ((TLRPC.TL_messages_translateResult) res).result.get(0) != null && + ((TLRPC.TL_messages_translateResult) res).result.get(0).text != null + ) { + firstTranslation = false; + TLRPC.TL_textWithEntities text = preprocess(textWithEntities, ((TLRPC.TL_messages_translateResult) res).result.get(0)); + CharSequence translated = SpannableStringBuilder.valueOf(text.text); + MessageObject.addEntitiesToText(translated, text.entities, false, true, false, false); + translated = preprocessText(translated); + textView.setText(translated); + adapter.updateMainView(textViewContainer); + } else if (firstTranslation) { + dismiss(); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR, LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2)); + } else { + BulletinFactory.of((FrameLayout) containerView, resourcesProvider).createErrorBulletin(LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2)).show(); + headerView.toLanguageTextView.setText(languageName(toLanguage = prevToLanguage)); + adapter.updateMainView(textViewContainer); + } + }); + }); + } + + public static TLRPC.TL_textWithEntities preprocess(TLRPC.TL_textWithEntities source, TLRPC.TL_textWithEntities received) { + if (received == null || received.text == null) { + return null; + } + for (int i = 0; i < received.entities.size(); ++i) { + TLRPC.MessageEntity entity = received.entities.get(i); + if (entity instanceof TLRPC.TL_messageEntityTextUrl) { + if (entity.url == null) { + continue; + } + String text = received.text.substring(entity.offset, entity.offset + entity.length); + if (TextUtils.equals(text, entity.url)) { + TLRPC.TL_messageEntityUrl newEntity = new TLRPC.TL_messageEntityUrl(); + newEntity.offset = entity.offset; + newEntity.length = entity.length; + received.entities.set(i, newEntity); + } else if ( + entity.url.startsWith("https://t.me/") && + text.startsWith("@") && + TextUtils.equals(text.substring(1), entity.url.substring(13)) + ) { + TLRPC.TL_messageEntityMention newEntity = new TLRPC.TL_messageEntityMention(); + newEntity.offset = entity.offset; + newEntity.length = entity.length; + received.entities.set(i, newEntity); + } + } + } + if (source != null && source.text != null && !source.entities.isEmpty()) { + + HashMap> srcIndexes = groupEmojiRanges(source.text); + HashMap> destIndexes = groupEmojiRanges(received.text); + + for (int i = 0; i < source.entities.size(); ++i) { + TLRPC.MessageEntity entity = source.entities.get(i); + if (entity instanceof TLRPC.TL_messageEntityCustomEmoji) { + String code = source.text.substring(entity.offset, entity.offset + entity.length); + if (TextUtils.isEmpty(code)) { + continue; + } + ArrayList srcRanges = srcIndexes.get(code); + ArrayList destRanges = destIndexes.get(code); + if (srcRanges == null || destRanges == null) { + continue; + } + int srcIndex = -1; + for (int j = 0; j < srcRanges.size(); ++j) { + Emoji.EmojiSpanRange range = srcRanges.get(j); + if (range.start == entity.offset && range.end == entity.offset + entity.length) { + srcIndex = j; + break; + } + } + if (srcIndex < 0 || srcIndex >= destRanges.size()) { + continue; + } + Emoji.EmojiSpanRange destRange = destRanges.get(srcIndex); + if (destRange == null) { + continue; + } + + boolean alreadyContainsOne = false; + for (int j = 0; j < received.entities.size(); ++j) { + TLRPC.MessageEntity destEntity = received.entities.get(j); + if ( + destEntity instanceof TLRPC.TL_messageEntityCustomEmoji && + AndroidUtilities.intersect1d(destRange.start, destRange.end, destEntity.offset, destEntity.offset + destEntity.length) + ) { + alreadyContainsOne = true; + break; + } + } + if (alreadyContainsOne) { + continue; + } + + TLRPC.TL_messageEntityCustomEmoji newEntity = new TLRPC.TL_messageEntityCustomEmoji(); + newEntity.document_id = ((TLRPC.TL_messageEntityCustomEmoji) entity).document_id; + newEntity.document = ((TLRPC.TL_messageEntityCustomEmoji) entity).document; + newEntity.offset = destRange.start; + newEntity.length = destRange.end - destRange.start; + received.entities.add(newEntity); + } + } + } + return received; + } + + private static HashMap> groupEmojiRanges(CharSequence text) { + HashMap> result = new HashMap<>(); + if (text == null) { + return result; + } + ArrayList ranges = Emoji.parseEmojis(text); + if (ranges == null) { + return result; + } + String string = text.toString(); + for (int i = 0; i < ranges.size(); ++i) { + Emoji.EmojiSpanRange range = ranges.get(i); + if (range == null || range.code == null) { + continue; + } + String code = string.substring(range.start, range.end); + ArrayList codeRanges = result.get(code); + if (codeRanges == null) { + result.put(code, codeRanges = new ArrayList<>()); + } + codeRanges.add(range); + } + return result; + } + + public static ArrayList preprocess(ArrayList received) { + if (received == null) { + return null; + } + for (int i = 0; i < received.size(); ++i) { + received.set(i, preprocess(null, received.get(i))); + } + return received; + } + + private CharSequence preprocessText(CharSequence text) { + Spannable spannable = new SpannableStringBuilder(text); + URLSpan[] urlSpans; + if (onLinkPress != null || fragment != null) { + urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); + for (int i = 0; i < urlSpans.length; ++i) { + URLSpan urlSpan = urlSpans[i]; + int start = spannable.getSpanStart(urlSpan), + end = spannable.getSpanEnd(urlSpan); + if (start == -1 || end == -1) { + continue; + } + spannable.removeSpan(urlSpan); + spannable.setSpan( + new ClickableSpan() { + @Override + public void onClick(@NonNull View view) { + if (onLinkPress != null) { + if (onLinkPress.run(urlSpan)) { + dismiss(); + } + } else if (fragment != null) { + AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); + } + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); + if (!(urlSpan instanceof URLSpanNoUnderline)) { + ds.setUnderlineText(true); + } + ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); + ds.setAlpha(alpha); + } + }, + start, end, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ); + } + } + return Emoji.replaceEmoji(spannable, textView.getPaint().getFontMetricsInt(), true); + } + + @Override + public void dismissInternal() { + if (reqId != null) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + reqId = null; + } + super.dismissInternal(); + } + + public void setFragment(BaseFragment fragment) { + this.fragment = fragment; + } + + public void setOnLinkPress(Utilities.CallbackReturn onLinkPress) { + this.onLinkPress = onLinkPress; + } + + public void setNoforwards(boolean noforwards) { + if (textView != null) { + textView.setTextIsSelectable(!noforwards); + } + if (noforwards) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); + } else { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); } - return 0; } @Override protected boolean canDismissWithSwipe() { - return !listView.canScrollVertically(-1); + return false; } - // private boolean scrollAtBottom() { -// View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1); -// int bottom = view.getBottom(); -// LoadingTextView2 lastUnloadedBlock = textsView.getFirstUnloadedBlock(); -// if (lastUnloadedBlock != null) { -// bottom = lastUnloadedBlock.getTop(); -// } -// int diff = (bottom - (scrollView.getHeight() + scrollView.getScrollY())); -// return diff <= textsContainerView.getPaddingBottom(); -// } + private class LoadingTextView extends TextView { - private boolean hasSelection() { - return allTextsView.hasSelection(); - } + private final LinkPath path = new LinkPath(true); + private final LoadingDrawable loadingDrawable = new LoadingDrawable(); - private Rect containerRect = new Rect(); - private Rect textRect = new Rect(); - private Rect translateMoreRect = new Rect(); - private Rect buttonRect = new Rect(); - private Rect backRect = new Rect(); - private Rect scrollRect = new Rect(); - private float fromY = 0; - private boolean pressedOutside = false; - private boolean maybeScrolling = false; - private boolean scrolling = false; - private boolean fromScrollRect = false; - private boolean fromTranslateMoreView = false; - private float fromScrollViewY = 0; - private Spannable allTexts = null; - private LinkSpanDrawable pressedLink; - private LinkSpanDrawable.LinkCollector links; - -// @Override -// public boolean dispatchTouchEvent(@NonNull MotionEvent event) { -// try { -// float x = event.getX(); -// float y = event.getY(); -// -// container.getGlobalVisibleRect(containerRect); -// if (!containerRect.contains((int) x, (int) y)) { -// if (event.getAction() == MotionEvent.ACTION_DOWN) { -// pressedOutside = true; -// return true; -// } else if (event.getAction() == MotionEvent.ACTION_UP) { -// if (pressedOutside) { -// pressedOutside = false; -// dismiss(); -// return true; -// } -// } -// } -// -// try { -// allTextsView.getGlobalVisibleRect(textRect); -// if (textRect.contains((int) x, (int) y) && !maybeScrolling) { -// Layout allTextsLayout = allTextsView.getLayout(); -// int tx = (int) (x - allTextsView.getLeft() - container.getLeft()), -// ty = (int) (y - allTextsView.getTop() - container.getTop() - scrollView.getTop() + scrollView.getScrollY()); -// final int line = allTextsLayout.getLineForVertical(ty); -// final int off = allTextsLayout.getOffsetForHorizontal(line, tx); -// -// final float left = allTextsLayout.getLineLeft(line); -// if (allTexts instanceof Spannable && left <= tx && left + allTextsLayout.getLineWidth(line) >= tx) { -// ClickableSpan[] linkSpans = allTexts.getSpans(off, off, ClickableSpan.class); -// if (linkSpans != null && linkSpans.length >= 1) { -// if (event.getAction() == MotionEvent.ACTION_UP && pressedLink.getSpan() == linkSpans[0]) { -// ((ClickableSpan) pressedLink.getSpan()).onClick(allTextsView); -// if (links != null) { -// links.removeLink(pressedLink); -// } -// pressedLink = null; -// allTextsView.setTextIsSelectable(!noforwards); -// } else if (event.getAction() == MotionEvent.ACTION_DOWN) { -// pressedLink = new LinkSpanDrawable(linkSpans[0], fragment.getResourceProvider(), tx, ty, false); -// if (links != null) { -// links.addLink(pressedLink); -// } -// LinkPath path = pressedLink.obtainNewPath(); -// int start = allTexts.getSpanStart(pressedLink.getSpan()); -// int end = allTexts.getSpanEnd(pressedLink.getSpan()); -// path.setCurrentLayout(allTextsLayout, start, 0); -// allTextsLayout.getSelectionPath(start, end, path); -// } -// allTextsView.invalidate(); -// return true; -// } -// } -// } -// if (pressedLink != null) { -// if (links != null) { -// links.clear(); -// } -// pressedLink = null; -// } -// } catch (Exception e2) { -// e2.printStackTrace(); -// } -// -// scrollView.getGlobalVisibleRect(scrollRect); -// backButton.getGlobalVisibleRect(backRect); -// buttonView.getGlobalVisibleRect(buttonRect); -// if (pressedLink == null && /*!(scrollRect.contains((int) x, (int) y) && !canExpand() && containerOpenAnimationT < .5f && !scrolling) &&*/ !hasSelection()) { -// if ( -// !backRect.contains((int) x, (int) y) && -// !buttonRect.contains((int) x, (int) y) && -// event.getAction() == MotionEvent.ACTION_DOWN -// ) { -// fromScrollRect = scrollRect.contains((int) x, (int) y) && (containerOpenAnimationT > 0 || !canExpand()); -// maybeScrolling = true; -// scrolling = scrollRect.contains((int) x, (int) y) && textsView.getBlocksCount() > 0 && !((LoadingTextView2) textsView.getBlockAt(0)).loaded; -// fromY = y; -// fromScrollY = getScrollY(); -// fromScrollViewY = scrollView.getScrollY(); -// return super.dispatchTouchEvent(event) || true; -// } else if (maybeScrolling && (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_UP)) { -// float dy = fromY - y; -// if (fromScrollRect) { -// dy = -Math.max(0, -(fromScrollViewY + dp(48)) - dy); -// if (dy < 0) { -// scrolling = true; -// allTextsView.setTextIsSelectable(false); -// } -// } else if (Math.abs(dy) > dp(4) && !fromScrollRect) { -// scrolling = true; -// allTextsView.setTextIsSelectable(false); -// scrollView.stopNestedScroll(); -// allowScroll = false; -// } -// float fullHeight = AndroidUtilities.displayMetrics.heightPixels, -// minHeight = Math.min(minHeight(), fullHeight * heightMaxPercent); -// float scrollYPx = minHeight * (1f - -Math.min(Math.max(fromScrollY, -1), 0)) + (fullHeight - minHeight) * Math.min(1, Math.max(fromScrollY, 0)) + dy; -// float scrollY = scrollYPx > minHeight ? (scrollYPx - minHeight) / (fullHeight - minHeight) : -(1f - scrollYPx / minHeight); -// if (!canExpand()) { -// scrollY = Math.min(scrollY, 0); -// } -// updateCanExpand(); -// -// if (scrolling) { -// setScrollY(scrollY); -// if (event.getAction() == MotionEvent.ACTION_UP) { -// scrolling = false; -// allTextsView.setTextIsSelectable(!noforwards); -// maybeScrolling = false; -// allowScroll = true; -// scrollYTo( -// Math.abs(dy) > dp(16) ? -// Math.round(fromScrollY) + (scrollY > fromScrollY ? 1f : -1f) * (float) Math.ceil(Math.abs(fromScrollY - scrollY)) : -// Math.round(fromScrollY), -// () -> { -// contentView.post(this::checkForNextLoading); -// } -// ); -// } -// return true; -// } -// } -// } -// if (hasSelection() && maybeScrolling) { -// scrolling = false; -// allTextsView.setTextIsSelectable(!noforwards); -// maybeScrolling = false; -// allowScroll = true; -// scrollYTo(Math.round(fromScrollY)); -// } -// return super.dispatchTouchEvent(event); -// } catch (Exception e) { -// e.printStackTrace(); -// return super.dispatchTouchEvent(event); -// } -// return super.dispatchTouchEvent(event); -// } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - containerView.setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); - } -// -// contentView.setPadding(0, AndroidUtilities.statusBarHeight, 0, 0); -// contentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); -// setContentView(contentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); -// -// Window window = getWindow(); -// window.setWindowAnimations(R.style.DialogNoAnimation); -// WindowManager.LayoutParams params = window.getAttributes(); -// params.width = ViewGroup.LayoutParams.MATCH_PARENT; -// params.gravity = Gravity.TOP | Gravity.LEFT; -// params.dimAmount = 0; -// params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; -// if (Build.VERSION.SDK_INT >= 21) { -// params.flags |= -// WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | -// WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | -// WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | -// WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; -// } -// params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; -// params.height = ViewGroup.LayoutParams.MATCH_PARENT; -// if (Build.VERSION.SDK_INT >= 28) { -// params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; -// } -// window.setAttributes(params); -// } - - protected ColorDrawable backDrawable = new ColorDrawable(0xff000000) { - @Override - public void setAlpha(int alpha) { - super.setAlpha(alpha); -// contentView.invalidate(); + public LoadingTextView(Context context) { + super(context); + loadingDrawable.usePath(path); + loadingDrawable.setSpeed(.65f); + loadingDrawable.setRadiiDp(4); + setBackground(loadingDrawable); } - }; - public String languageName(String locale) { - // sorry, no more vodka + @Override + public void setTextColor(int color) { + super.setTextColor(Theme.multAlpha(color, .2f)); + loadingDrawable.setColors( + Theme.multAlpha(color, 0.03f), + Theme.multAlpha(color, 0.175f), + Theme.multAlpha(color, 0.2f), + Theme.multAlpha(color, 0.45f) + ); + } + + private void updateDrawable() { + if (path == null || loadingDrawable == null) { + return; + } + + path.rewind(); + if (getLayout() != null && getLayout().getText() != null) { + path.setCurrentLayout(getLayout(), 0, getPaddingLeft(), getPaddingTop()); + getLayout().getSelectionPath(0, getLayout().getText().length(), path); + } + loadingDrawable.updateBounds(); + } + + @Override + public void setText(CharSequence text, BufferType type) { + super.setText(text, type); + updateDrawable(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + updateDrawable(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + loadingDrawable.reset(); + } + } + + private static class PaddedAdapter extends RecyclerListView.Adapter { + + private Context mContext; + private View mMainView; + + public PaddedAdapter(Context context, View mainView) { + mContext = context; + mMainView = mainView; + } + + private int mainViewType = 1; + + public void updateMainView(View newMainView) { + if (mMainView == newMainView) { + return; + } + mainViewType++; + mMainView = newMainView; + notifyItemChanged(1); + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + if (viewType == 0) { + return new RecyclerListView.Holder(new View(mContext) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec((int) (AndroidUtilities.displaySize.y * .4f), MeasureSpec.EXACTLY) + ); + } + }); + } else { + return new RecyclerListView.Holder(mMainView); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {} + + @Override + public int getItemViewType(int position) { + if (position == 0) { + return 0; + } else { + return mainViewType; + } + } + + @Override + public int getItemCount() { + return 2; + } + } + + private AnimatedFloat sheetTopAnimated; + private float getSheetTop() { + return getSheetTop(true); + } + private float getSheetTop(boolean animated) { + float top = listView.getTop(); + if (listView.getChildCount() >= 1) { + top += Math.max(0, listView.getChildAt(listView.getChildCount() - 1).getTop()); + } + top = Math.max(0, top - dp(78)); + if (animated && sheetTopAnimated != null) { + if (!listView.scrollingByUser && !sheetTopNotAnimate) { + top = sheetTopAnimated.set(top); + } else { + sheetTopAnimated.set(top, true); + } + } + return top; + } + + private class HeaderView extends FrameLayout { + + private ImageView backButton; + private TextView titleTextView; + private LinearLayout subtitleView; + private TextView fromLanguageTextView; + private ImageView arrowView; + private AnimatedTextView toLanguageTextView; + + private View backgroundView; + + private View shadow; + + public HeaderView(Context context) { + super(context); + + backgroundView = new View(context); + backgroundView.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); + addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 44, Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 12, 0, 0)); + + backButton = new ImageView(context); + backButton.setScaleType(ImageView.ScaleType.CENTER); + backButton.setImageResource(R.drawable.ic_ab_back); + backButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); + backButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector))); + backButton.setAlpha(0f); + backButton.setOnClickListener(e -> dismiss()); + addView(backButton, LayoutHelper.createFrame(54, 54, Gravity.TOP, 1, 1, 1, 1)); + + titleTextView = new TextView(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (LocaleController.isRTL) { + titleTextView.setPivotX(getMeasuredWidth()); + } + } + }; + titleTextView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleTextView.setText(LocaleController.getString("AutomaticTranslation", R.string.AutomaticTranslation)); + titleTextView.setPivotX(0); + titleTextView.setPivotY(0); + addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL, 22, 20, 22, 0)); + + subtitleView = new LinearLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (LocaleController.isRTL) { + subtitleView.setPivotX(getMeasuredWidth()); + } + } + }; + if (LocaleController.isRTL) { + subtitleView.setGravity(Gravity.RIGHT); + } + subtitleView.setPivotX(0); + subtitleView.setPivotY(0); + if (!TextUtils.isEmpty(fromLanguage) && !"und".equals(fromLanguage)) { + fromLanguageTextView = new TextView(context); + fromLanguageTextView.setLines(1); + fromLanguageTextView.setTextColor(getThemedColor(Theme.key_player_actionBarSubtitle)); + fromLanguageTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + fromLanguageTextView.setText(capitalFirst(languageName(fromLanguage))); + fromLanguageTextView.setPadding(0, dp(2), 0, dp(2)); + } + + arrowView = new ImageView(context); + arrowView.setImageResource(R.drawable.search_arrow); + arrowView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_player_actionBarSubtitle), PorterDuff.Mode.MULTIPLY)); + if (LocaleController.isRTL) { + arrowView.setScaleX(-1f); + } + + toLanguageTextView = new AnimatedTextView(context) { + private Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(); + + @Override + protected void onDraw(Canvas canvas) { + if (LocaleController.isRTL) { + AndroidUtilities.rectTmp.set(getWidth() - width(), (getHeight() - dp(18)) / 2f, getWidth(), (getHeight() + dp(18)) / 2f); + } else { + AndroidUtilities.rectTmp.set(0, (getHeight() - dp(18)) / 2f, width(), (getHeight() + dp(18)) / 2f); + } + bgPaint.setColor(Theme.multAlpha(getThemedColor(Theme.key_player_actionBarSubtitle), .1175f)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(4), dp(4), bgPaint); + if (links.draw(canvas)) { + invalidate(); + } + + super.onDraw(canvas); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + LinkSpanDrawable link = new LinkSpanDrawable(null, resourcesProvider, event.getX(), event.getY()); + link.setColor(Theme.multAlpha(getThemedColor(Theme.key_player_actionBarSubtitle), .1175f)); + LinkPath path = link.obtainNewPath(); + if (LocaleController.isRTL) { + AndroidUtilities.rectTmp.set(getWidth() - width(), (getHeight() - dp(18)) / 2f, getWidth(), (getHeight() + dp(18)) / 2f); + } else { + AndroidUtilities.rectTmp.set(0, (getHeight() - dp(18)) / 2f, width(), (getHeight() + dp(18)) / 2f); + } + path.addRect(AndroidUtilities.rectTmp, Path.Direction.CW); + links.addLink(link); + invalidate(); + return true; + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (event.getAction() == MotionEvent.ACTION_UP) { + performClick(); + } + links.clear(); + invalidate(); + } + return super.onTouchEvent(event); + } + }; + if (LocaleController.isRTL) { + toLanguageTextView.setGravity(Gravity.RIGHT); + } + toLanguageTextView.setAnimationProperties(.25f, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + toLanguageTextView.setTextColor(getThemedColor(Theme.key_player_actionBarSubtitle)); + toLanguageTextView.setTextSize(dp(14)); + toLanguageTextView.setText(capitalFirst(languageName(toLanguage))); + toLanguageTextView.setPadding(dp(4), dp(2), dp(4), dp(2)); + toLanguageTextView.setOnClickListener(e -> openLanguagesSelect()); + + if (LocaleController.isRTL) { + subtitleView.addView(toLanguageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, fromLanguageTextView != null ? 3 : 0, 0)); + if (fromLanguageTextView != null) { + subtitleView.addView(arrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 1, 0, 0)); + subtitleView.addView(fromLanguageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 4, 0, 0, 0)); + } + } else { + if (fromLanguageTextView != null) { + subtitleView.addView(fromLanguageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 4, 0)); + subtitleView.addView(arrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 1, 0, 0)); + } + subtitleView.addView(toLanguageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, fromLanguageTextView != null ? 3 : 0, 0, 0, 0)); + } + + addView(subtitleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL, 22, 43, 22, 0)); + + shadow = new View(context); + shadow.setBackgroundColor(getThemedColor(Theme.key_dialogShadowLine)); + shadow.setAlpha(0); + addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, AndroidUtilities.getShadowHeight() / dpf2(1), Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 56, 0, 0)); + } + + public void openLanguagesSelect() { + ActionBarPopupWindow.ActionBarPopupWindowLayout layout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, + MeasureSpec.makeMeasureSpec(Math.min((int) (AndroidUtilities.displaySize.y * .33f), MeasureSpec.getSize(heightMeasureSpec)), MeasureSpec.EXACTLY) + ); + } + }; + + Drawable shadowDrawable2 = ContextCompat.getDrawable(getContext(), R.drawable.popup_fixed_alert).mutate(); + shadowDrawable2.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground), PorterDuff.Mode.MULTIPLY)); + layout.setBackground(shadowDrawable2); + + final Runnable[] dismiss = new Runnable[1]; + + ArrayList locales = TranslateController.getLocales(); + boolean first = true; + for (int i = 0; i < locales.size(); ++i) { + LocaleController.LocaleInfo localeInfo = locales.get(i); + + if ( + localeInfo.pluralLangCode.equals(fromLanguage) || + !"remote".equals(localeInfo.pathToFile) + ) { + continue; + } + + ActionBarMenuSubItem button = new ActionBarMenuSubItem(getContext(), 2, first, i == locales.size() - 1, resourcesProvider); + button.setText(capitalFirst(languageName(localeInfo.pluralLangCode))); + button.setChecked(TextUtils.equals(toLanguage, localeInfo.pluralLangCode)); + button.setOnClickListener(e -> { + if (dismiss[0] != null) { + dismiss[0].run(); + } + + if (TextUtils.equals(toLanguage, localeInfo.pluralLangCode)) { + return; + } + + if (adapter.mMainView == textViewContainer) { + prevToLanguage = toLanguage; + } + toLanguageTextView.setText(capitalFirst(languageName(toLanguage = localeInfo.pluralLangCode))); + adapter.updateMainView(loadingTextView); + setToLanguage(toLanguage); + translate(); + }); + layout.addView(button); + + first = false; + } + + ActionBarPopupWindow window = new ActionBarPopupWindow(layout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + dismiss[0] = () -> window.dismiss(); + window.setPauseNotifications(true); + window.setDismissAnimationDuration(220); + window.setOutsideTouchable(true); + window.setClippingEnabled(true); + window.setAnimationStyle(R.style.PopupContextAnimation); + window.setFocusable(true); + int[] location = new int[2]; + toLanguageTextView.getLocationInWindow(location); + layout.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, MeasureSpec.AT_MOST)); + int height = layout.getMeasuredHeight(); + int y = location[1] > AndroidUtilities.displaySize.y * .9f - height ? location[1] - height + dp(8) : location[1] + toLanguageTextView.getMeasuredHeight() - dp(8); + window.showAtLocation(containerView, Gravity.TOP | Gravity.LEFT, location[0] - dp(8), y); + } + + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + + float t = MathUtils.clamp((translationY - AndroidUtilities.statusBarHeight) / dp(64), 0, 1); + if (!hasEnoughHeight()) { + t = 1; + } + t = CubicBezierInterpolator.EASE_OUT.getInterpolation(t); + + titleTextView.setScaleX(AndroidUtilities.lerp(.85f, 1f, t)); + titleTextView.setScaleY(AndroidUtilities.lerp(.85f, 1f, t)); + titleTextView.setTranslationY(AndroidUtilities.lerp(dpf2(-12), 0, t)); + if (!LocaleController.isRTL) { + titleTextView.setTranslationX(AndroidUtilities.lerp(dpf2(50), 0, t)); + subtitleView.setTranslationX(AndroidUtilities.lerp(dpf2(50), 0, t)); + } + + subtitleView.setTranslationY(AndroidUtilities.lerp(dpf2(-22), 0, t)); + + backButton.setTranslationX(AndroidUtilities.lerp(0, dpf2(-25), t)); + backButton.setAlpha(1f - t); + + shadow.setTranslationY(AndroidUtilities.lerp(0, dpf2(22), t)); + shadow.setAlpha(1f - t); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(78), MeasureSpec.EXACTLY) + ); + } + } + + private class ContainerView extends FrameLayout { + public ContainerView(Context context) { + super(context); + + bgPaint.setColor(getThemedColor(Theme.key_dialogBackground)); + Theme.applyDefaultShadow(bgPaint); + } + + private Path bgPath = new Path(); + private Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void dispatchDraw(Canvas canvas) { + + float top = getSheetTop(); + final float R = AndroidUtilities.lerp(0, dp(12), MathUtils.clamp(top / dpf2(24), 0, 1)); + headerView.setTranslationY(Math.max(AndroidUtilities.statusBarHeight, top)); + updateLightStatusBar(top <= AndroidUtilities.statusBarHeight / 2f); + + bgPath.rewind(); + AndroidUtilities.rectTmp.set(0, top, getWidth(), getHeight() + R); + bgPath.addRoundRect(AndroidUtilities.rectTmp, R, R, Path.Direction.CW); + canvas.drawPath(bgPath, bgPaint); + + super.dispatchDraw(canvas); + } + + private Boolean lightStatusBarFull; + private void updateLightStatusBar(boolean full) { + if (lightStatusBarFull == null || lightStatusBarFull != full) { + lightStatusBarFull = full; + AndroidUtilities.setLightStatusBar(getWindow(), AndroidUtilities.computePerceivedBrightness( + full ? + getThemedColor(Theme.key_dialogBackground) : + Theme.blendOver( + getThemedColor(Theme.key_actionBarDefault), + 0x33000000 + ) + ) > .721f); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY)); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Bulletin.addDelegate(this, new Bulletin.Delegate() { + @Override + public int getBottomOffset(int tag) { + return AndroidUtilities.dp(16 + 48 + 16); + } + }); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Bulletin.removeDelegate(this); + } + } + + public static String capitalFirst(String text) { + if (text == null) { + return null; + } + return text.substring(0, 1).toUpperCase() + text.substring(1); + } + + public static String languageName(String locale) { if (locale == null || locale.equals("und") || locale.equals("auto")) { return null; } + LocaleController.LocaleInfo currentLanguageInfo = LocaleController.getInstance().getCurrentLocaleInfo(); + try { + Locale[] allLocales = Locale.getAvailableLocales(); + String simplifiedLocale = locale.split("_")[0]; + if ("nb".equals(simplifiedLocale)) { + simplifiedLocale = "no"; + } + Locale found = null; + for (int i = 0; i < allLocales.length; ++i) { + if (TextUtils.equals(simplifiedLocale, allLocales[i].getLanguage())) { + found = allLocales[i]; + break; + } + } + if (found != null) { + return found.getDisplayLanguage(Locale.getDefault()); + } + } catch (Exception e) {} + if ("no".equals(locale)) { + locale = "nb"; + } LocaleController.LocaleInfo thisLanguageInfo = LocaleController.getInstance().getBuiltinLanguageByPlural(locale); if (thisLanguageInfo == null) { return null; } - LocaleController.LocaleInfo currentLanguageInfo = LocaleController.getInstance().getCurrentLocaleInfo(); boolean isCurrentLanguageEnglish = currentLanguageInfo != null && "en".equals(currentLanguageInfo.pluralLangCode); +// try { +// String lang = LocaleController.getString("PassportLanguage_" + thisLanguageInfo.pluralLangCode.toUpperCase()); +// if (lang != null && !lang.startsWith("LOC_ERR")) { +// return lang; +// } +// } catch (Exception ignore) {} if (isCurrentLanguageEnglish) { - // trying to show this language in a language of the interface, but there are only names in english and its own return thisLanguageInfo.nameEnglish; } else { return thisLanguageInfo.name; } } - public void updateSourceLanguage() { - String fromLanguageName = languageName(fromLanguage); - if (fromLanguageName != null) { - subtitleView.setAlpha(1); - if (!subtitleFromView.loaded) { - subtitleFromView.loaded(fromLanguageName); - } - } else if (loaded) { - subtitleView.animate().alpha(0).setDuration(150).start(); - titleView.animate().scaleX(1.2f).scaleY(1.2f).translationY(dp(5)).setDuration(150).start(); - } - } - - private ArrayList cutInBlocks(CharSequence full, int maxBlockSize) { - ArrayList blocks = new ArrayList<>(); - if (full == null) { - return blocks; - } - while (full.length() > maxBlockSize) { - String maxBlockStr = full.subSequence(0, maxBlockSize).toString(); - int n = maxBlockStr.lastIndexOf("\n\n"); - if (n == -1) n = maxBlockStr.lastIndexOf("\n"); - if (n == -1) n = maxBlockStr.lastIndexOf(". "); - if (n == -1) n = maxBlockStr.length(); - blocks.add(full.subSequence(0, n + 1)); - full = full.subSequence(n + 1, full.length()); - } - if (full.length() > 0) { - blocks.add(full); - } - return blocks; - } - - private boolean loading = false; - private boolean loaded = false; - private boolean fetchNext() { - if (loading) { - return false; - } - loading = true; - - if (blockIndex >= textBlocks.size()) { - return false; - } - - fetchTranslation( - textBlocks.get(blockIndex), - Math.min((blockIndex + 1) * 1000, 3500), - (String translatedText, String sourceLanguage) -> { - loaded = true; - Spannable spannable = new SpannableStringBuilder(translatedText); - try { - MessageObject.addUrlsByPattern(false, spannable, false, 0, 0, true); - URLSpan[] urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); - for (int i = 0; i < urlSpans.length; ++i) { - URLSpan urlSpan = urlSpans[i]; - int start = spannable.getSpanStart(urlSpan), - end = spannable.getSpanEnd(urlSpan); - if (start == -1 || end == -1) { - continue; - } - spannable.removeSpan(urlSpan); - spannable.setSpan( - new ClickableSpan() { - @Override - public void onClick(@NonNull View view) { - if (onLinkPress != null) { - onLinkPress.run(urlSpan); - dismiss(); - } else { - AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); - } - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); - if (!(urlSpan instanceof URLSpanNoUnderline)) { - ds.setUnderlineText(true); - } - ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); - ds.setAlpha(alpha); - } - }, - start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ); - } - - AndroidUtilities.addLinks(spannable, Linkify.WEB_URLS); - urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); - for (int i = 0; i < urlSpans.length; ++i) { - URLSpan urlSpan = urlSpans[i]; - int start = spannable.getSpanStart(urlSpan), - end = spannable.getSpanEnd(urlSpan); - if (start == -1 || end == -1) { - continue; - } - spannable.removeSpan(urlSpan); - spannable.setSpan( - new ClickableSpan() { - @Override - public void onClick(@NonNull View view) { - AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); - if (!(urlSpan instanceof URLSpanNoUnderline)) - ds.setUnderlineText(true); - ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); - ds.setAlpha(alpha); - } - }, - start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ); - } - - spannable = (Spannable) Emoji.replaceEmoji(spannable, allTextsView.getPaint().getFontMetricsInt(), dp(14), false); - } catch (Exception e) { - e.printStackTrace(); - } - - SpannableStringBuilder allTextsBuilder = new SpannableStringBuilder(allTexts == null ? "" : allTexts); - if (blockIndex != 0) { - allTextsBuilder.append("\n"); - } - allTextsBuilder.append(spannable); - allTexts = allTextsBuilder; - textsView.setWholeText(allTexts); - - LoadingTextView2 block = textsView.getBlockAt(blockIndex); - if (block != null) { - block.loaded(spannable, () -> AndroidUtilities.runOnUIThread(this::checkForNextLoading)); - } - - if (sourceLanguage != null) { - fromLanguage = sourceLanguage; - updateSourceLanguage(); - } - - blockIndex++; - loading = false; - }, - (boolean rateLimit) -> { - Toast.makeText( - getContext(), - rateLimit ? - LocaleController.getString("TranslationFailedAlert1", R.string.TranslationFailedAlert1) : - LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2), - Toast.LENGTH_SHORT - ).show(); - - if (blockIndex == 0) { - dismiss(); - } - } - ); - return true; + @Override + public void show() { + super.show(); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); } @Override - public void dismissInternal() { - super.dismissInternal(); - if (onDismiss != null) { - onDismiss.run(); + public void dismiss() { + super.dismiss(); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.emojiLoaded) { + loadingTextView.invalidate(); + textView.invalidate(); } } -// @Override -// public boolean dispatchTouchEvent(@NonNull MotionEvent event) { -// if (event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < contentView.getPaddingTop() + header.getTranslationY()) { -// dismiss(); -// return true; -// } -// return super.dispatchTouchEvent(event); -// } - - private void checkForNextLoading() { - if (!listView.canScrollVertically(-1)) { - fetchNext(); + private Boolean buttonShadowShown; + private void updateButtonShadow(boolean show) { + if (buttonShadowShown == null || buttonShadowShown != show) { + buttonShadowShown = show; + buttonShadowView.animate().cancel(); + buttonShadowView.animate().alpha(show ? 1f : 0f).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).setDuration(320).start(); } } - public interface OnTranslationSuccess { - public void run(String translated, String sourceLanguage); - } - public interface OnTranslationFail { - public void run(boolean rateLimit); - } - private void fetchTranslation(CharSequence text, long minDuration, OnTranslationSuccess onSuccess, OnTranslationFail onFail) { - if (!translateQueue.isAlive()) { - translateQueue.start(); - } - translateQueue.postRunnable(() -> { - String uri = ""; - HttpURLConnection connection = null; - long start = SystemClock.elapsedRealtime(); - try { - uri = "https://translate.googleapis.com/translate_a/single?client=gtx&sl="; - uri += Uri.encode(fromLanguage); - uri += "&tl="; - uri += Uri.encode(toLanguage); - uri += "&dt=t&ie=UTF-8&oe=UTF-8&otf=1&ssel=0&tsel=0&kc=7&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&q="; - uri += Uri.encode(text.toString()); - connection = (HttpURLConnection) new URI(uri).toURL().openConnection(); - connection.setRequestMethod("GET"); - connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"); - connection.setRequestProperty("Content-Type", "application/json"); - - StringBuilder textBuilder = new StringBuilder(); - try (Reader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charset.forName("UTF-8")))) { - int c; - while ((c = reader.read()) != -1) { - textBuilder.append((char) c); - } - } - String jsonString = textBuilder.toString(); - - JSONTokener tokener = new JSONTokener(jsonString); - JSONArray array = new JSONArray(tokener); - JSONArray array1 = array.getJSONArray(0); - String sourceLanguage = null; - try { - sourceLanguage = array.getString(2); - } catch (Exception e2) {} - if (sourceLanguage != null && sourceLanguage.contains("-")) { - sourceLanguage = sourceLanguage.substring(0, sourceLanguage.indexOf("-")); - } - StringBuilder result = new StringBuilder(); - for (int i = 0; i < array1.length(); ++i) { - String blockText = array1.getJSONArray(i).getString(0); - if (blockText != null && !blockText.equals("null")) { - result.append(blockText); - } - } - if (text.length() > 0 && text.charAt(0) == '\n') { - result.insert(0, "\n"); - } - final String finalResult = result.toString(); - final String finalSourceLanguage = sourceLanguage; - - long elapsed = SystemClock.elapsedRealtime() - start; - AndroidUtilities.runOnUIThread(() -> { - if (onSuccess != null) { - onSuccess.run(finalResult, finalSourceLanguage); - } - }, Math.max(0, minDuration - elapsed)); - } catch (Exception e) { - try { - Log.e("translate", "failed to translate a text " + (connection != null ? connection.getResponseCode() : null) + " " + (connection != null ? connection.getResponseMessage() : null)); - } catch (IOException ioException) { - ioException.printStackTrace(); - } - e.printStackTrace(); - - if (onFail != null) { - try { - final boolean rateLimit = connection != null && connection.getResponseCode() == 429; - AndroidUtilities.runOnUIThread(() -> { - onFail.run(rateLimit); - }); - } catch (Exception e2) { - AndroidUtilities.runOnUIThread(() -> { - onFail.run(false); - }); - } + public static TranslateAlert2 showAlert(Context context, BaseFragment fragment, int currentAccount, TLRPC.InputPeer peer, int msgId, String fromLanguage, String toLanguage, CharSequence text, ArrayList entities, boolean noforwards, Utilities.CallbackReturn onLinkPress, Runnable onDismiss) { + TranslateAlert2 alert = new TranslateAlert2(context, fromLanguage, toLanguage, text, entities, peer, msgId, null) { + @Override + public void dismiss() { + super.dismiss(); + if (onDismiss != null) { + onDismiss.run(); } } - }); - } - private static void translateText(int currentAccount, TLRPC.InputPeer peer, int msg_id, String from_lang, String to_lang) { - TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); - - req.peer = peer; - req.msg_id = msg_id; - req.flags |= 1; - - if (from_lang != null) { - req.from_lang = from_lang; - req.flags |= 4; - } - - req.to_lang = to_lang; - - try { - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (error, res) -> {}); - } catch (Exception e) { - FileLog.e(e); - } - } - - public static TranslateAlert2 showAlert(Context context, BaseFragment fragment, int currentAccount, TLRPC.InputPeer peer, int msgId, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - if (peer != null) { - translateText(currentAccount, peer, msgId, fromLanguage != null && fromLanguage.equals("und") ? null : fromLanguage, toLanguage); - } - TranslateAlert2 alert = new TranslateAlert2(fragment, context, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); - if (fragment != null) { - if (fragment.getParentActivity() != null) { - fragment.showDialog(alert); - } - } else { - alert.show(); - } - return alert; - } - public static TranslateAlert2 showAlert(Context context, BaseFragment fragment, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - TranslateAlert2 alert = new TranslateAlert2(fragment, context, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); + }; + alert.setNoforwards(noforwards); + alert.setFragment(fragment); + alert.setOnLinkPress(onLinkPress); if (fragment != null) { if (fragment.getParentActivity() != null) { fragment.showDialog(alert); @@ -1183,631 +1069,38 @@ public class TranslateAlert2 extends BottomSheet { return alert; } - private static final int MOST_SPEC = View.MeasureSpec.makeMeasureSpec(999999, View.MeasureSpec.AT_MOST); - public static class TextBlocksLayout extends ViewGroup { - - private TextView wholeTextView; - private final int fontSize; - private final int textColor; - - public TextBlocksLayout(Context context, int fontSize, int textColor, TextView wholeTextView) { - super(context); - - this.fontSize = fontSize; - this.textColor = textColor; - - if (wholeTextView != null) { - wholeTextView.setPadding(LoadingTextView2.paddingHorizontal, LoadingTextView2.paddingVertical, LoadingTextView2.paddingHorizontal, LoadingTextView2.paddingVertical); - addView(this.wholeTextView = wholeTextView); - } - } - - public void setWholeText(CharSequence wholeText) { - // having focus on that text view can cause jumping scroll to the top after loading a new block - // TODO(dkaraush): preserve selection after setting a new text - wholeTextView.clearFocus(); - wholeTextView.setText(wholeText); - } - - public LoadingTextView2 addBlock(CharSequence fromText) { - LoadingTextView2 textView = new LoadingTextView2(getContext(), fromText, getBlocksCount() > 0, fontSize, textColor); - addView(textView); - if (wholeTextView != null) { - wholeTextView.bringToFront(); - } - return textView; - } - - public int getBlocksCount() { - return getChildCount() - (wholeTextView != null ? 1 : 0); - } - public LoadingTextView2 getBlockAt(int i) { - View child = getChildAt(i); - if (child instanceof LoadingTextView2) { - return (LoadingTextView2) child; - } - return null; - } - - public LoadingTextView2 getFirstUnloadedBlock() { - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - if (block != null && !block.loaded) - return block; - } - return null; - } - - private static final int gap = -LoadingTextView2.paddingVertical * 4 + dp(.48f); - public int height() { - int height = 0; - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - height += getBlockAt(i).height(); - } - return getPaddingTop() + height + getPaddingBottom(); - } - - protected void onHeightUpdated(int height, int dy) {} - - public void updateHeight() { - boolean updated; - int newHeight = height(); - int dy = 0; - RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) getLayoutParams(); - if (lp == null) { - lp = new RecyclerView.LayoutParams(LayoutParams.MATCH_PARENT, newHeight); - updated = true; - } else { - updated = lp.height != newHeight; - dy = newHeight - lp.height; - lp.height = newHeight; - } - - if (updated) { - this.setLayoutParams(lp); - onHeightUpdated(newHeight, dy); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int count = getBlocksCount(); - final int innerWidthMeasureSpec = MeasureSpec.makeMeasureSpec( - MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(), - MeasureSpec.getMode(widthMeasureSpec) - ); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - block.measure(innerWidthMeasureSpec, MOST_SPEC); - } - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height(), MeasureSpec.EXACTLY)); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - int y = 0; - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - final int blockHeight = block.height(); - final int translationY = i > 0 ? gap : 0; - block.layout(getPaddingLeft(), getPaddingTop() + y + translationY, r - l - getPaddingRight(), getPaddingTop() + y + blockHeight + translationY); - y += blockHeight; - if (i > 0 && i < count - 1) { - y += gap; + public static TranslateAlert2 showAlert(Context context, BaseFragment fragment, int currentAccount, String fromLanguage, String toLanguage, CharSequence text, ArrayList entities, boolean noforwards, Utilities.CallbackReturn onLinkPress, Runnable onDismiss) { + TranslateAlert2 alert = new TranslateAlert2(context, fromLanguage, toLanguage, text, entities, null) { + @Override + public void dismiss() { + super.dismiss(); + if (onDismiss != null) { + onDismiss.run(); } } - - wholeTextView.measure( - MeasureSpec.makeMeasureSpec(r - l - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(b - t - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY) - ); - wholeTextView.layout( - getPaddingLeft(), - getPaddingTop(), - (r - l) - getPaddingRight(), - getPaddingTop() + wholeTextView.getMeasuredHeight() - ); + }; + alert.setNoforwards(noforwards); + alert.setFragment(fragment); + alert.setOnLinkPress(onLinkPress); + if (fragment != null) { + if (fragment.getParentActivity() != null) { + fragment.showDialog(alert); + } + } else { + alert.show(); } + return alert; } - public static class InlineLoadingTextView extends ViewGroup { - - public static final int paddingHorizontal = dp(4), - paddingVertical = 0; - - - public boolean showLoadingText = true; - - private final TextView fromTextView; - private final TextView toTextView; - - private final ValueAnimator loadingAnimator; - - private final long start = SystemClock.elapsedRealtime(); - public InlineLoadingTextView(Context context, CharSequence fromText, int fontSize, int textColor) { - super(context); - - setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); - setClipChildren(false); - setWillNotDraw(false); - - fromTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MOST_SPEC, MOST_SPEC); - } - }; - fromTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - fromTextView.setTextColor(textColor); - fromTextView.setText(fromText); - fromTextView.setLines(1); - fromTextView.setMaxLines(1); - fromTextView.setSingleLine(true); - fromTextView.setEllipsize(null); - addView(fromTextView); - - toTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MOST_SPEC, MOST_SPEC); - } - }; - toTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - toTextView.setTextColor(textColor); - toTextView.setLines(1); - toTextView.setMaxLines(1); - toTextView.setSingleLine(true); - toTextView.setEllipsize(null); - addView(toTextView); - - int c1 = Theme.getColor(Theme.key_dialogBackground), - c2 = Theme.getColor(Theme.key_dialogBackgroundGray); - LinearGradient gradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{ c1, c2, c1 }, new float[] { 0, 0.67f, 1f }, Shader.TileMode.REPEAT); - loadingPaint.setShader(gradient); - - loadingAnimator = ValueAnimator.ofFloat(0f, 1f); - loadingAnimator.addUpdateListener(a -> invalidate()); - loadingAnimator.setDuration(Long.MAX_VALUE); - loadingAnimator.start(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - fromTextView.measure(0, 0); - toTextView.measure(0, 0); - super.onMeasure( - MeasureSpec.makeMeasureSpec( - (int) AndroidUtilities.lerp(fromTextView.getMeasuredWidth(), toTextView.getMeasuredWidth(), loadingT) + getPaddingLeft() + getPaddingRight(), - MeasureSpec.EXACTLY - ), - MeasureSpec.makeMeasureSpec( - Math.max(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight()), - MeasureSpec.EXACTLY - ) - ); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - fromTextView.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + fromTextView.getMeasuredWidth(), getPaddingTop() + fromTextView.getMeasuredHeight()); - toTextView.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + toTextView.getMeasuredWidth(), getPaddingTop() + toTextView.getMeasuredHeight()); - updateWidth(); - } - - private void updateWidth() { - boolean updated; - - int newWidth = (int) AndroidUtilities.lerp(fromTextView.getMeasuredWidth(), toTextView.getMeasuredWidth(), loadingT) + getPaddingLeft() + getPaddingRight(); - int newHeight = Math.max(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight()); - LayoutParams lp = getLayoutParams(); - if (lp == null) { - lp = new LinearLayout.LayoutParams(newWidth, newHeight); - updated = true; - } else { - updated = lp.width != newWidth || lp.height != newHeight; - lp.width = newWidth; - lp.height = newHeight; - } - - if (updated) - setLayoutParams(lp); - } - - protected void onLoadAnimation(float t) {} - - public boolean loaded = false; - public float loadingT = 0f; - private ValueAnimator loadedAnimator = null; - public void loaded(CharSequence loadedText) { - loaded(loadedText, 350,null); - } - public void loaded(CharSequence loadedText, Runnable onLoadEnd) { - loaded(loadedText, 350, onLoadEnd); - } - public void loaded(CharSequence loadedText, long duration, Runnable onLoadEnd) { - loaded = true; - toTextView.setText(loadedText); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator == null) { - loadedAnimator = ValueAnimator.ofFloat(0f, 1f); - loadedAnimator.addUpdateListener(a -> { - loadingT = (float) a.getAnimatedValue(); - updateWidth(); - invalidate(); - onLoadAnimation(loadingT); - }); - loadedAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onLoadEnd != null) - onLoadEnd.run(); - } - }); - loadedAnimator.setDuration(duration); - loadedAnimator.setInterpolator(CubicBezierInterpolator.EASE_BOTH); - loadedAnimator.start(); - } - } - public void set(CharSequence loadedText) { - loaded = true; - toTextView.setText(loadedText); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator != null) { - loadedAnimator.cancel(); - loadedAnimator = null; - } - loadingT = 1f; - requestLayout(); - updateWidth(); - invalidate(); - onLoadAnimation(1f); - } - - private final RectF rect = new RectF(); - private final Path inPath = new Path(), - tempPath = new Path(), - loadingPath = new Path(), - shadePath = new Path(); - private final Paint loadingPaint = new Paint(); - private final float gradientWidth = dp(350f); - @Override - protected void onDraw(Canvas canvas) { - float w = getWidth(), h = getHeight(); - - float cx = LocaleController.isRTL ? Math.max(w / 2f, w - 8f) : Math.min(w / 2f, 8f), - cy = Math.min(h / 2f, 8f), - R = (float) Math.sqrt(Math.max( - Math.max(cx*cx + cy*cy, (w-cx)*(w-cx) + cy*cy), - Math.max(cx*cx + (h-cy)*(h-cy), (w-cx)*(w-cx) + (h-cy)*(h-cy)) - )), - r = loadingT * R; - inPath.reset(); - inPath.addCircle(cx, cy, r, Path.Direction.CW); - - canvas.save(); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - - loadingPaint.setAlpha((int) ((1f - loadingT) * 255)); - float dx = gradientWidth - (((SystemClock.elapsedRealtime() - start) / 1000f * gradientWidth) % gradientWidth); - shadePath.reset(); - shadePath.addRect(0, 0, w, h, Path.Direction.CW); - - loadingPath.reset(); - rect.set(0, 0, w, h); - loadingPath.addRoundRect(rect, dp(4), dp(4), Path.Direction.CW); - canvas.clipPath(loadingPath); - canvas.translate(-dx, 0); - shadePath.offset(dx, 0f, tempPath); - canvas.drawPath(tempPath, loadingPaint); - canvas.translate(dx, 0); - canvas.restore(); - - if (showLoadingText && fromTextView != null) { - canvas.save(); - rect.set(0, 0, w, h); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * .08f), Canvas.ALL_SAVE_FLAG); - fromTextView.draw(canvas); - canvas.restore(); - canvas.restore(); - } - - if (toTextView != null) { - canvas.save(); - canvas.clipPath(inPath); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * loadingT), Canvas.ALL_SAVE_FLAG); - toTextView.draw(canvas); - if (loadingT < 1f) { - canvas.restore(); - } - canvas.restore(); - } - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - return false; - } + public static String getToLanguage() { + return MessagesController.getGlobalMainSettings().getString("translate_to_language", LocaleController.getInstance().getCurrentLocale().getLanguage()); } - public static class LoadingTextView2 extends ViewGroup { + public static void setToLanguage(String toLang) { + MessagesController.getGlobalMainSettings().edit().putString("translate_to_language", toLang).apply(); + } - public static final int paddingHorizontal = dp(4), - paddingVertical = dp(1.5f); - - public boolean showLoadingText = true; - - private final TextView fromTextView; - private final TextView toTextView; - - private final boolean scaleFromZero; - private final ValueAnimator loadingAnimator; - - private final long start = SystemClock.elapsedRealtime(); - private float scaleT = 1f; - public LoadingTextView2(Context context, CharSequence fromText, boolean scaleFromZero, int fontSize, int textColor) { - super(context); - - setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); - setClipChildren(false); - setWillNotDraw(false); - - fromTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - }; - fromTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - fromTextView.setTextColor(textColor); - fromTextView.setText(fromText); - fromTextView.setLines(0); - fromTextView.setMaxLines(0); - fromTextView.setSingleLine(false); - fromTextView.setEllipsize(null); - addView(fromTextView); - - toTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - }; - toTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - toTextView.setTextColor(textColor); - toTextView.setLines(0); - toTextView.setMaxLines(0); - toTextView.setSingleLine(false); - toTextView.setEllipsize(null); - addView(toTextView); - - int c1 = Theme.getColor(Theme.key_dialogBackground), - c2 = Theme.getColor(Theme.key_dialogBackgroundGray); - LinearGradient gradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{ c1, c2, c1 }, new float[] { 0, 0.67f, 1f }, Shader.TileMode.REPEAT); - loadingPaint.setShader(gradient); - - this.scaleFromZero = scaleFromZero; - loadingAnimator = ValueAnimator.ofFloat(0f, 1f); - if (scaleFromZero) - scaleT = 0; - loadingAnimator.addUpdateListener(a -> { - invalidate(); - if (scaleFromZero) { - boolean scaleTWasNoFull = scaleT < 1f; - scaleT = Math.min(1, (SystemClock.elapsedRealtime() - start) / 400f); - if (scaleTWasNoFull) { - updateHeight(); - } - } - }); - loadingAnimator.setDuration(Long.MAX_VALUE); - loadingAnimator.start(); - } - - public int innerHeight() { - return (int) (AndroidUtilities.lerp(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight(), loadingT) * scaleT); - } - public int height() { - return getPaddingTop() + innerHeight() + getPaddingBottom(); - } - - private void updateHeight() { - ViewParent parent = getParent(); - if (parent instanceof TextBlocksLayout) { - ((TextBlocksLayout) parent).updateHeight(); - } - } - - public boolean loaded = false; - private float loadingT = 0f; - private ValueAnimator loadedAnimator = null; - public void loaded(CharSequence loadedText, Runnable onLoadEnd) { - loaded = true; - toTextView.setText(loadedText); - layout(); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator == null) { - loadedAnimator = ValueAnimator.ofFloat(0f, 1f); - loadedAnimator.addUpdateListener(a -> { - loadingT = (float) a.getAnimatedValue(); - updateHeight(); - invalidate(); - }); - loadedAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onLoadEnd != null) - onLoadEnd.run(); - } - }); - loadedAnimator.setDuration(350); - loadedAnimator.setInterpolator(CubicBezierInterpolator.EASE_BOTH); - loadedAnimator.start(); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = MeasureSpec.getSize(widthMeasureSpec), - innerWidth = width - getPaddingLeft() - getPaddingRight(); - if (fromTextView.getMeasuredWidth() <= 0 || lastWidth != innerWidth) { - measureChild(fromTextView, innerWidth); - updateLoadingPath(); - } - if (toTextView.getMeasuredWidth() <= 0 || lastWidth != innerWidth) { - measureChild(toTextView, innerWidth); - } - lastWidth = innerWidth; - super.onMeasure( - MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height(), MeasureSpec.EXACTLY) - ); - } - - int lastWidth = 0; - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - layout(r - l - getPaddingLeft() - getPaddingRight(), true); - } - private void layout(int width, boolean force) { - if (lastWidth != width || force) { - layout(lastWidth = width); - } - } - private void layout(int width) { - measureChild(fromTextView, width); - layoutChild(fromTextView, width); - updateLoadingPath(); - measureChild(toTextView, width); - layoutChild(toTextView, width); - updateHeight(); - } - private void layout() { - layout(lastWidth); - } - private void measureChild(View view, int width) { - view.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MOST_SPEC); - } - private void layoutChild(View view, int width) { - view.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + width, getPaddingTop() + view.getMeasuredHeight()); - } - - private RectF fetchedPathRect = new RectF(); - private void updateLoadingPath() { - if (fromTextView != null && fromTextView.getMeasuredWidth() > 0) { - loadingPath.reset(); - Layout loadingLayout = fromTextView.getLayout(); - if (loadingLayout != null) { - CharSequence text = loadingLayout.getText(); - final int lineCount = loadingLayout.getLineCount(); - for (int i = 0; i < lineCount; ++i) { - float s = loadingLayout.getLineLeft(i), - e = loadingLayout.getLineRight(i), - l = Math.min(s, e), - r = Math.max(s, e); - int start = loadingLayout.getLineStart(i), - end = loadingLayout.getLineEnd(i); - boolean hasNonEmptyChar = false; - for (int j = start; j < end; ++j) { - char c = text.charAt(j); - if (c != '\n' && c != '\t' && c != ' ') { - hasNonEmptyChar = true; - break; - } - } - if (!hasNonEmptyChar) - continue; - fetchedPathRect.set( - l - paddingHorizontal, - loadingLayout.getLineTop(i) - paddingVertical, - r + paddingHorizontal, - loadingLayout.getLineBottom(i) + paddingVertical - ); - loadingPath.addRoundRect(fetchedPathRect, dp(4), dp(4), Path.Direction.CW); - } - } - } - } - - private final RectF rect = new RectF(); - private final Path inPath = new Path(), - tempPath = new Path(), - loadingPath = new Path(), - shadePath = new Path(); - private final Paint loadingPaint = new Paint(); - private final float gradientWidth = dp(350f); - @Override - protected void onDraw(Canvas canvas) { - float w = getWidth(), h = getHeight(); - - float cx = LocaleController.isRTL ? Math.max(w / 2f, w - 8f) : Math.min(w / 2f, 8f), - cy = Math.min(h / 2f, 8f), - R = (float) Math.sqrt(Math.max( - Math.max(cx*cx + cy*cy, (w-cx)*(w-cx) + cy*cy), - Math.max(cx*cx + (h-cy)*(h-cy), (w-cx)*(w-cx) + (h-cy)*(h-cy)) - )), - r = loadingT * R; - inPath.reset(); - inPath.addCircle(cx, cy, r, Path.Direction.CW); - - canvas.save(); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - - loadingPaint.setAlpha((int) ((1f - loadingT) * 255)); - float dx = gradientWidth - (((SystemClock.elapsedRealtime() - start) / 1000f * gradientWidth) % gradientWidth); - shadePath.reset(); - shadePath.addRect(0, 0, w, h, Path.Direction.CW); - - canvas.translate(paddingHorizontal, paddingVertical); - canvas.clipPath(loadingPath); - canvas.translate(-paddingHorizontal, -paddingVertical); - canvas.translate(-dx, 0); - shadePath.offset(dx, 0f, tempPath); - canvas.drawPath(tempPath, loadingPaint); - canvas.translate(dx, 0); - canvas.restore(); - - if (showLoadingText && fromTextView != null) { - canvas.save(); - rect.set(0, 0, w, h); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * .08f), Canvas.ALL_SAVE_FLAG); - fromTextView.draw(canvas); - canvas.restore(); - canvas.restore(); - } - - if (toTextView != null) { - canvas.save(); - canvas.clipPath(inPath); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * loadingT), Canvas.ALL_SAVE_FLAG); - toTextView.draw(canvas); - if (loadingT < 1f) { - canvas.restore(); - } - canvas.restore(); - } - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - return false; - } + public static void resetToLanguage() { + MessagesController.getGlobalMainSettings().edit().remove("translate_to_language").apply(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateButton.java new file mode 100644 index 000000000..c82ee9583 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateButton.java @@ -0,0 +1,262 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.DynamicDrawableSpan; +import android.text.style.ImageSpan; +import android.view.Gravity; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ScrollView; + +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.messenger.TranslateController; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.RestrictedLanguagesSelectActivity; + +import java.util.ArrayList; + +public class TranslateButton extends FrameLayout { + + private final int currentAccount; + private final long dialogId; + private final BaseFragment fragment; + + private Theme.ResourcesProvider resourcesProvider; + + private AnimatedTextView textView; + public final SpannableString translateIcon; + + private ImageView menuView; + + public TranslateButton(Context context, ChatActivity chatActivity, Theme.ResourcesProvider resourcesProvider) { + this(context, chatActivity.getCurrentAccount(), chatActivity.getDialogId(), chatActivity, resourcesProvider); + } + + public TranslateButton(Context context, int currentAccount, long dialogId, BaseFragment fragment, Theme.ResourcesProvider resourcesProvider) { + super(context); + + this.currentAccount = currentAccount; + this.dialogId = dialogId; + this.fragment = fragment; + this.resourcesProvider = resourcesProvider; + + textView = new AnimatedTextView(context, true, true, false); + textView.setAnimationProperties(.3f, 0, 450, CubicBezierInterpolator.EASE_OUT_QUINT); + textView.setTextColor(Theme.getColor(Theme.key_chat_addContact, resourcesProvider)); + textView.setTextSize(AndroidUtilities.dp(15)); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + textView.setGravity(Gravity.CENTER_HORIZONTAL); + textView.setIgnoreRTL(!LocaleController.isRTL); + textView.adaptWidth = false; + textView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_chat_addContact, resourcesProvider) & 0x19ffffff, 3)); + textView.setOnClickListener(e -> onButtonClick()); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + final Drawable translateDrawable = getContext().getResources().getDrawable(R.drawable.msg_translate).mutate(); + translateDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_addContact, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + translateDrawable.setBounds(0, AndroidUtilities.dp(-8), AndroidUtilities.dp(20), AndroidUtilities.dp(20 - 8)); + translateIcon = new SpannableString("x"); + translateIcon.setSpan(new ImageSpan(translateDrawable, DynamicDrawableSpan.ALIGN_BOTTOM), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + menuView = new ImageView(context); + menuView.setScaleType(ImageView.ScaleType.CENTER); + menuView.setImageResource(R.drawable.msg_mini_customize); + menuView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_addContact, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + menuView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_chat_addContact, resourcesProvider) & 0x19ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + menuView.setOnClickListener(e -> onMenuClick()); + addView(menuView, LayoutHelper.createFrame(32, 32, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 0, 8, 0)); + } + + protected void onButtonClick() { + + } + + protected void onMenuClick() { + TranslateController translateController = MessagesController.getInstance(currentAccount).getTranslateController(); + + final ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), R.drawable.popup_fixed_alert2, resourcesProvider, ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_USE_SWIPEBACK); + final ActionBarPopupWindow popupWindow = new ActionBarPopupWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + popupLayout.setBackgroundColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); + + LinearLayout swipeBack = new LinearLayout(getContext()); + swipeBack.setOrientation(LinearLayout.VERTICAL); + ScrollView swipeBackScrollView = new ScrollView(getContext()); + LinearLayout swipeBackScroll = new LinearLayout(getContext()); + swipeBackScrollView.addView(swipeBackScroll); + swipeBackScroll.setOrientation(LinearLayout.VERTICAL); + popupLayout.swipeBackGravityRight = true; + final int swipeBackIndex = popupLayout.addViewToSwipeBack(swipeBack); + + ActionBarMenuSubItem translateToButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); + translateToButton.setTextAndIcon(LocaleController.getString("TranslateTo", R.string.TranslateTo), R.drawable.msg_translate); + translateToButton.setSubtext(TranslateAlert2.capitalFirst(TranslateAlert2.languageName(translateController.getDialogTranslateTo(dialogId)))); + translateToButton.setItemHeight(56); + translateToButton.setOnClickListener(e -> popupLayout.getSwipeBack().openForeground(swipeBackIndex)); + popupLayout.addView(translateToButton); + + ActionBarMenuSubItem backButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); + backButton.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.ic_ab_back); + backButton.setOnClickListener(e -> popupLayout.getSwipeBack().closeForeground()); + swipeBack.addView(backButton); + + swipeBack.addView(new ActionBarPopupWindow.GapView(getContext(), resourcesProvider), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + swipeBack.addView(swipeBackScrollView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 420)); + + String detectedLanguage = translateController.getDialogDetectedLanguage(dialogId); + String detectedLanguageName = TranslateAlert2.languageName(detectedLanguage); + String currentTranslateTo = translateController.getDialogTranslateTo(dialogId); + + ArrayList suggestedLanguages = TranslateController.getSuggestedLanguages(currentTranslateTo); + ArrayList allLanguages = TranslateController.getLanguages(); + if (currentTranslateTo != null) { + String displayName = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(currentTranslateTo)); + if (displayName != null) { + ActionBarMenuSubItem button = new ActionBarMenuSubItem(getContext(), 2, false, false, resourcesProvider); + button.setChecked(true); + button.setText(displayName); + swipeBackScroll.addView(button); + } + } + for (TranslateController.Language lng : suggestedLanguages) { + final String code = lng.code; + if (TextUtils.equals(code, detectedLanguage)) { + continue; + } + + ActionBarMenuSubItem button = new ActionBarMenuSubItem(getContext(), 2, false, false, resourcesProvider); + final boolean checked = currentTranslateTo != null && currentTranslateTo.equals(code); + button.setChecked(checked); + button.setText(lng.displayName); + if (!checked) { + button.setOnClickListener(e -> { + translateController.setDialogTranslateTo(dialogId, code); + popupWindow.dismiss(); + updateText(); + }); + } + swipeBackScroll.addView(button); + } + swipeBackScroll.addView(new ActionBarPopupWindow.GapView(getContext(), resourcesProvider), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + for (TranslateController.Language lng : allLanguages) { + final String code = lng.code; + if (TextUtils.equals(code, detectedLanguage)) { + continue; + } + + ActionBarMenuSubItem button = new ActionBarMenuSubItem(getContext(), 2, false, false, resourcesProvider); + final boolean checked = currentTranslateTo != null && currentTranslateTo.equals(code); + button.setChecked(checked); + button.setText(lng.displayName); + if (!checked) { + button.setOnClickListener(e -> { + translateController.setDialogTranslateTo(dialogId, code); + popupWindow.dismiss(); + updateText(); + }); + } + swipeBackScroll.addView(button); + } + +// if (detectedLanguage != null) { +// ActionBarMenuSubItem translateFromButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); +// translateFromButton.setTextAndIcon(LocaleController.getString("DetectedLanguage", R.string.DetectedLanguage), R.drawable.msg_language); +// translateFromButton.setSubtext(TranslateAlert2.languageName(detectedLanguage)); +// translateFromButton.setItemHeight(56); +// popupLayout.addView(translateFromButton); +// } + + popupLayout.addView(new ActionBarPopupWindow.GapView(getContext(), resourcesProvider), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + + if (detectedLanguageName != null && detectedLanguage != null) { + ActionBarMenuSubItem dontTranslateButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); + String text; + String lang = LocaleController.getString("TranslateLanguage" + detectedLanguage.toUpperCase()); + if (lang == null || lang.startsWith("LOC_ERR")) { + lang = detectedLanguageName; + text = LocaleController.formatString("DoNotTranslateLanguageOther", R.string.DoNotTranslateLanguageOther, lang); + } else { + text = LocaleController.formatString("DoNotTranslateLanguage", R.string.DoNotTranslateLanguage, lang); + } + dontTranslateButton.setTextAndIcon(text, R.drawable.msg_block2); + dontTranslateButton.setOnClickListener(e -> { + RestrictedLanguagesSelectActivity.toggleLanguage(detectedLanguage, true); + translateController.checkRestrictedLanguagesUpdate(); + translateController.setHideTranslateDialog(dialogId, true); + BulletinFactory.of(fragment).createSimpleBulletin(R.raw.msg_translate, AndroidUtilities.replaceTags(LocaleController.formatString("AddedToDoNotTranslate", R.string.AddedToDoNotTranslate, TranslateAlert2.capitalFirst(detectedLanguageName))), LocaleController.getString("Settings", R.string.Settings), () -> { + fragment.presentFragment(new RestrictedLanguagesSelectActivity()); + }).show(); + popupWindow.dismiss(); + }); + popupLayout.addView(dontTranslateButton); + } + + ActionBarMenuSubItem hideButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); + hideButton.setTextAndIcon(LocaleController.getString("Hide", R.string.Hide), R.drawable.msg_cancel); + hideButton.setOnClickListener(e -> { + translateController.setHideTranslateDialog(dialogId, true); + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + final boolean isChannel = chat != null && ChatObject.isChannelAndNotMegaGroup(chat); + final CharSequence message = AndroidUtilities.replaceTags( + isChannel ? + LocaleController.getString("TranslationBarHiddenForChannel", R.string.TranslationBarHiddenForChannel) : + chat != null ? + LocaleController.getString("TranslationBarHiddenForGroup", R.string.TranslationBarHiddenForGroup) : + LocaleController.getString("TranslationBarHiddenForChat", R.string.TranslationBarHiddenForChat) + ); + BulletinFactory.of(fragment).createSimpleBulletin(R.raw.msg_translate, message, LocaleController.getString("Undo", R.string.Undo), () -> { + translateController.setHideTranslateDialog(dialogId, false); + }).show(); + popupWindow.dismiss(); + }); + popupLayout.addView(hideButton); + + popupWindow.setPauseNotifications(true); + popupWindow.setDismissAnimationDuration(220); + popupWindow.setOutsideTouchable(true); + popupWindow.setClippingEnabled(true); + popupWindow.setAnimationStyle(R.style.PopupContextAnimation); + popupWindow.setFocusable(true); + popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); + popupWindow.showAsDropDown(menuView, 0, -menuView.getMeasuredHeight() - AndroidUtilities.dp(8)); + } + + public void updateText() { + TranslateController translateController = MessagesController.getInstance(currentAccount).getTranslateController(); + if (translateController.isTranslatingDialog(dialogId)) { + textView.setText(TextUtils.concat(translateIcon, " ", LocaleController.getString("ShowOriginalButton", R.string.ShowOriginalButton))); + } else { + String lng = translateController.getDialogTranslateTo(dialogId); + if (lng == null) { + lng = "en"; + } + String text; + String lang = LocaleController.getString("TranslateLanguage" + lng.toUpperCase()); + if (lang == null || lang.startsWith("LOC_ERR")) { + lang = TranslateAlert2.languageName(lng); + text = LocaleController.formatString("TranslateToButtonOther", R.string.TranslateToButtonOther, lang); + } else { + text = LocaleController.formatString("TranslateToButton", R.string.TranslateToButton, lang); + } + textView.setText(TextUtils.concat(translateIcon, " ", text)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java new file mode 100644 index 000000000..af5577a7c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java @@ -0,0 +1,239 @@ +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; + +import com.google.android.exoplayer2.util.Log; + +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; + +import java.util.HashSet; + +public class VectorAvatarThumbDrawable extends Drawable implements AnimatedEmojiSpan.InvalidateHolder, AttachableDrawable, NotificationCenter.NotificationCenterDelegate { + + public static final int TYPE_SMALL = 1; + public static final int TYPE_PROFILE = 2; + public static final int TYPE_STATIC = 3; + public final GradientTools gradientTools = new GradientTools(); + private final int type; + float roundRadius; + boolean isPremium; + + ImageReceiver currentParent; + HashSet parents = new HashSet<>(); + + AnimatedEmojiDrawable animatedEmojiDrawable; + ImageReceiver imageReceiver; + ImageReceiver stickerPreloadImageReceiver = new ImageReceiver(); + final int currentAccount = UserConfig.selectedAccount; + boolean imageSeted; + TLRPC.TL_videoSizeStickerMarkup sizeStickerMarkup; + + public VectorAvatarThumbDrawable(TLRPC.VideoSize vectorImageMarkup, boolean isPremiumUser, int type) { + this.type = type; + this.isPremium = isPremiumUser; + int color1 = ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(0), 255); + int color2 = vectorImageMarkup.background_colors.size() > 1 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(1), 255) : 0; + int color3 = vectorImageMarkup.background_colors.size() > 2 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(2), 255) : 0; + int color4 = vectorImageMarkup.background_colors.size() > 3 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(3), 255) : 0; + gradientTools.setColors(color1, color2, color3, color4); + if (vectorImageMarkup instanceof TLRPC.TL_videoSizeEmojiMarkup) { + TLRPC.TL_videoSizeEmojiMarkup emojiMarkup = (TLRPC.TL_videoSizeEmojiMarkup) vectorImageMarkup; + int cacheType = AnimatedEmojiDrawable.STANDARD_LOTTIE_FRAME; + if (type == TYPE_SMALL && isPremiumUser) { + cacheType = AnimatedEmojiDrawable.CACHE_TYPE_EMOJI_STATUS; + } else if (type == TYPE_PROFILE) { + cacheType = AnimatedEmojiDrawable.CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2; + } + + animatedEmojiDrawable = new AnimatedEmojiDrawable(cacheType, UserConfig.selectedAccount, emojiMarkup.emoji_id); + } else if (vectorImageMarkup instanceof TLRPC.TL_videoSizeStickerMarkup) { + sizeStickerMarkup = (TLRPC.TL_videoSizeStickerMarkup) vectorImageMarkup; + imageReceiver = new ImageReceiver() { + @Override + public void invalidate() { + VectorAvatarThumbDrawable.this.invalidate(); + } + }; + imageReceiver.setInvalidateAll(true); + if (type == TYPE_SMALL) { + imageReceiver.setAutoRepeatCount(2); + } + setImage(); + } + } + + private void setImage() { + TLRPC.TL_messages_stickerSet set = MediaDataController.getInstance(currentAccount).getStickerSet(sizeStickerMarkup.stickerset, false); + if (set != null) { + imageSeted = true; + for (int i = 0; i < set.documents.size(); i++) { + if (set.documents.get(i).id == sizeStickerMarkup.sticker_id) { + TLRPC.Document document = set.documents.get(i); + TLRPC.Document thumb = null; + String filter = "50_50_firstframe"; + String thumbFilter = null; + if (isPremium && type == TYPE_SMALL) { + filter = "50_50"; + thumbFilter = "50_50_firstframe"; + thumb = document; + } else if (type == TYPE_PROFILE) { + filter = "100_100"; + thumbFilter = "50_50_firstframe"; + thumb = document; + } + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + imageReceiver.setImage(ImageLocation.getForDocument(document), filter, ImageLocation.getForDocument(thumb), thumbFilter, null, null, svgThumb, 0, "tgs", document, 0); + if (type == TYPE_STATIC) { + stickerPreloadImageReceiver.setImage(ImageLocation.getForDocument(document), "100_100", null, null, null, 0, "tgs", document, 0); + } + break; + } + } + } + } + + @Override + public void draw(@NonNull Canvas canvas) { + gradientTools.setBounds(getBounds().left, getBounds().top, getBounds().right, getBounds().bottom); + + if (currentParent != null) { + roundRadius = currentParent.getRoundRadius()[0]; + } + if (roundRadius == 0) { + canvas.drawRect(getBounds(), gradientTools.paint); + } else { + canvas.drawRoundRect(gradientTools.bounds, roundRadius, roundRadius, gradientTools.paint); + } + int cx = getBounds().centerX(); + int cy = getBounds().centerY(); + int size = (int) (getBounds().width() * AvatarConstructorFragment.STICKER_DEFAULT_SCALE) >> 1; + if (animatedEmojiDrawable != null) { + if (animatedEmojiDrawable.getImageReceiver() != null) { + animatedEmojiDrawable.getImageReceiver().setRoundRadius((int) (size * 2 * AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS)); + } + animatedEmojiDrawable.setBounds(cx - size, cy - size, cx + size, cy + size); + animatedEmojiDrawable.draw(canvas); + } + if (imageReceiver != null) { + imageReceiver.setRoundRadius((int) (size * 2 * AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS)); + imageReceiver.setImageCoords(cx - size, cy - size, size * 2, size * 2); + imageReceiver.draw(canvas); + } + } + + @Override + public void setAlpha(int alpha) { + gradientTools.paint.setAlpha(alpha); + if (animatedEmojiDrawable != null) { + animatedEmojiDrawable.setAlpha(alpha); + } + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return 0; + } + + public void setRoundRadius(float roundRadius) { + this.roundRadius = roundRadius; + } + + @Override + public void onAttachedToWindow(ImageReceiver parent) { + if (parent == null) { + return; + } + roundRadius = parent.getRoundRadius()[0]; + if (parents.isEmpty()) { + if (animatedEmojiDrawable != null) { + animatedEmojiDrawable.addView(this); + } + if (imageReceiver != null) { + imageReceiver.onAttachedToWindow(); + } + if (stickerPreloadImageReceiver != null) { + stickerPreloadImageReceiver.onAttachedToWindow(); + } + } + parents.add(parent); + if (sizeStickerMarkup != null) { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.groupStickersDidLoad); + } + } + + @Override + public void onDetachedFromWindow(ImageReceiver parent) { + parents.remove(parent); + if (parents.isEmpty()) { + if (animatedEmojiDrawable != null) { + animatedEmojiDrawable.removeView(this); + } + if (imageReceiver != null) { + imageReceiver.onDetachedFromWindow(); + } + if (stickerPreloadImageReceiver != null) { + stickerPreloadImageReceiver.onDetachedFromWindow(); + } + + } + if (sizeStickerMarkup != null) { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.groupStickersDidLoad); + } + } + + @Override + public void invalidate() { + for (ImageReceiver parent : parents) { + parent.invalidate(); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VectorAvatarThumbDrawable that = (VectorAvatarThumbDrawable) o; + if (type == that.type && gradientTools.color1 == that.gradientTools.color1 && gradientTools.color2 == that.gradientTools.color2 && gradientTools.color3 == that.gradientTools.color3 && gradientTools.color4 == that.gradientTools.color4) { + if (animatedEmojiDrawable != null && that.animatedEmojiDrawable != null) { + return animatedEmojiDrawable.getDocumentId() == that.animatedEmojiDrawable.getDocumentId(); + } + if (sizeStickerMarkup != null && that.sizeStickerMarkup != null) { + return sizeStickerMarkup.stickerset.id == that.sizeStickerMarkup.stickerset.id && sizeStickerMarkup.sticker_id == that.sizeStickerMarkup.sticker_id; + } + } + return false; + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.groupStickersDidLoad) { + if (!imageSeted) { + setImage(); + return; + } + } + } + + public void setParent(ImageReceiver imageReceiver) { + currentParent = imageReceiver; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java index 6d85da83f..e44643b8c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java @@ -812,6 +812,7 @@ public class ViewPagerFixed extends FrameLayout { public String title; public int titleWidth; public int counter; + public float alpha = 1f; public Tab(int i, String t) { id = i; @@ -851,6 +852,7 @@ public class ViewPagerFixed extends FrameLayout { currentTab = tab; currentPosition = position; setContentDescription(tab.title); + setAlpha(tab.alpha); requestLayout(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java index c6b08d291..cd999dc34 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java @@ -5,7 +5,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; -import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; @@ -49,7 +48,6 @@ import org.telegram.ui.Components.TextStyleSpan; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Stack; @@ -60,7 +58,6 @@ public class SpoilerEffect extends Drawable { public final static int PARTICLES_PER_CHARACTER = measureParticlesPerCharacter(); private final static float VERTICAL_PADDING_DP = 2.5f; private final static int RAND_REPEAT = 14; - private final static float KEYPOINT_DELTA = 5f; private final static int FPS = 30; private final static int renderDelayMs = 1000 / FPS + 1; public final static float[] ALPHAS = { @@ -92,7 +89,6 @@ public class SpoilerEffect extends Drawable { private ValueAnimator rippleAnimator; private List spaces = new ArrayList<>(); - private List keyPoints; private int mAlpha = 0xFF; private TimeInterpolator rippleInterpolator = input -> input; @@ -248,16 +244,6 @@ public class SpoilerEffect extends Drawable { this.rippleInterpolator = rippleInterpolator; } - /** - * Sets new keypoints - * - * @param keyPoints New keypoints - */ - public void setKeyPoints(List keyPoints) { - this.keyPoints = keyPoints; - invalidateSelf(); - } - /** * Gets ripple path */ @@ -439,15 +425,8 @@ public class SpoilerEffect extends Drawable { } private void generateRandomLocation(Particle newParticle, int i) { - if (keyPoints != null && !keyPoints.isEmpty()) { - float rf = particleRands[i % RAND_REPEAT]; - long kp = keyPoints.get(Utilities.fastRandom.nextInt(keyPoints.size())); - newParticle.x = getBounds().left + (kp >> 16) + rf * AndroidUtilities.dp(KEYPOINT_DELTA) - AndroidUtilities.dp(KEYPOINT_DELTA / 2f); - newParticle.y = getBounds().top + (kp & 0xFFFF) + rf * AndroidUtilities.dp(KEYPOINT_DELTA) - AndroidUtilities.dp(KEYPOINT_DELTA / 2f); - } else { - newParticle.x = getBounds().left + Utilities.fastRandom.nextFloat() * getBounds().width(); - newParticle.y = getBounds().top + Utilities.fastRandom.nextFloat() * getBounds().height(); - } + newParticle.x = getBounds().left + Utilities.fastRandom.nextFloat() * getBounds().width(); + newParticle.y = getBounds().top + Utilities.fastRandom.nextFloat() * getBounds().height(); } @Override @@ -521,42 +500,6 @@ public class SpoilerEffect extends Drawable { return PixelFormat.TRANSPARENT; } - /** - * @param textLayout Text layout to measure - * @return Measured key points - */ - public static synchronized List measureKeyPoints(Layout textLayout) { - int w = textLayout.getWidth(); - int h = textLayout.getHeight(); - - if (w <= 0 || h <= 0) - return Collections.emptyList(); - - Bitmap measureBitmap = Bitmap.createBitmap(Math.round(w), Math.round(h), Bitmap.Config.ARGB_4444); // We can use 4444 as we don't need accuracy here - Canvas measureCanvas = new Canvas(measureBitmap); - textLayout.draw(measureCanvas); - - int[] pixels = new int[measureBitmap.getWidth() * measureBitmap.getHeight()]; - measureBitmap.getPixels(pixels, 0, measureBitmap.getWidth(), 0, 0, w, h); - - int sX = -1; - ArrayList keyPoints = new ArrayList<>(pixels.length); - for (int x = 0; x < w; x++) { - for (int y = 0; y < h; y++) { - int clr = pixels[y * measureBitmap.getWidth() + x]; - if (Color.alpha(clr) >= 0x80) { - if (sX == -1) { - sX = x; - } - keyPoints.add(((long) (x - sX) << 16) + y); - } - } - } - keyPoints.trimToSize(); - measureBitmap.recycle(); - return keyPoints; - } - /** * @return Max particles count */ @@ -662,8 +605,6 @@ public class SpoilerEffect extends Drawable { spoilerEffect.setBounds((int) Math.min(ps, pe), (int) lineTop, (int) Math.max(ps, pe), (int) lineBottom); spoilerEffect.setColor(textLayout.getPaint().getColor()); spoilerEffect.setRippleInterpolator(Easings.easeInQuad); - if (!spoilerEffect.isLowDevice) - spoilerEffect.setKeyPoints(SpoilerEffect.measureKeyPoints(newLayout)); spoilerEffect.updateMaxParticles(); if (v != null) { spoilerEffect.setParentView(v); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java index 0b6b2c74e..bc45e4538 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java @@ -113,13 +113,13 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent public ContactAddActivity(Bundle args) { super(args); - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); } public ContactAddActivity(Bundle args, Theme.ResourcesProvider resourcesProvider) { super(args); this.resourcesProvider = resourcesProvider; - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); } @Override @@ -450,7 +450,7 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent LocaleController.formatString("ResetToOriginalPhotoMessage", R.string.ResetToOriginalPhotoMessage, user.first_name), LocaleController.getString("Reset", R.string.Reset), () -> { avatar = null; - sendPhotoChangedRequest(null, null,null, null, 0, TYPE_SET); + sendPhotoChangedRequest(null, null,null, null, null, 0, TYPE_SET); TLRPC.User user1 = getMessagesController().getUser(user_id); user1.photo.personal = false; @@ -670,7 +670,7 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent } @Override - public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { if (imageUpdater.isCanceled()) { return; @@ -701,7 +701,7 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent getNotificationCenter().postNotificationName(NotificationCenter.reloadDialogPhotos); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_AVATAR); } - sendPhotoChangedRequest(avatar, bigSize.location, photo, video, videoStartTimestamp, photoSelectedTypeFinal); + sendPhotoChangedRequest(avatar, bigSize.location, photo, video, emojiMarkup, videoStartTimestamp, photoSelectedTypeFinal); showAvatarProgress(false, true); } else { avatarImage.setImage(ImageLocation.getForLocal(avatar), "50_50", avatarDrawable, getMessagesController().getUser(user_id)); @@ -761,7 +761,7 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent getMessagesController().photoSuggestion.put(message.local_id, imageUpdater); } - private void sendPhotoChangedRequest(TLRPC.FileLocation avatar, TLRPC.FileLocation bigAvatar, TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, int photoSelectedTypeFinal) { + private void sendPhotoChangedRequest(TLRPC.FileLocation avatar, TLRPC.FileLocation bigAvatar, TLRPC.InputFile photo, TLRPC.InputFile video, TLRPC.VideoSize emojiMarkup, double videoStartTimestamp, int photoSelectedTypeFinal) { TLRPC.TL_photos_uploadContactProfilePhoto req = new TLRPC.TL_photos_uploadContactProfilePhoto(); req.user_id = getMessagesController().getInputUser(user_id); @@ -775,6 +775,10 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.flags |= 32; + req.video_emoji_markup = emojiMarkup; + } if (photoSelectedTypeFinal == TYPE_SUGGEST) { req.suggest = true; req.flags |= 8; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 04a82ea12..9d05030f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -620,7 +620,14 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter floatingButtonContainer = new FrameLayout(context); frameLayout.addView(floatingButtonContainer, LayoutHelper.createFrame((Build.VERSION.SDK_INT >= 21 ? 56 : 60) + 20, (Build.VERSION.SDK_INT >= 21 ? 56 : 60) + 20, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.BOTTOM, LocaleController.isRTL ? 4 : 0, 0, LocaleController.isRTL ? 0 : 4, 0)); floatingButtonContainer.setOnClickListener(v -> { - new NewContactBottomSheet(ContactsActivity.this, getContext()).show(); + AndroidUtilities.requestAdjustNothing(getParentActivity(), getClassGuid()); + new NewContactBottomSheet(ContactsActivity.this, getContext()) { + @Override + public void dismissInternal() { + super.dismissInternal(); + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + } + }.show(); }); floatingButton = new RLottieImageView(context); @@ -681,9 +688,9 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter TLRPC.Chat chat = getMessagesController().getChat(channelId); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); if (ChatObject.canAddAdmins(chat)) { - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setTitle(LocaleController.getString("AddBotAdminAlert", R.string.AddBotAdminAlert)); builder.setMessage(LocaleController.getString("AddBotAsAdmin", R.string.AddBotAsAdmin)); - builder.setPositiveButton(LocaleController.getString("MakeAdmin", R.string.MakeAdmin), (dialogInterface, i) -> { + builder.setPositiveButton(LocaleController.getString("AddAsAdmin", R.string.AddAsAdmin), (dialogInterface, i) -> { if (delegate != null) { delegate.didSelectContact(user, param, this); delegate = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsWidgetConfigActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsWidgetConfigActivity.java index 981dd27a3..c8b3d60dc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsWidgetConfigActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsWidgetConfigActivity.java @@ -23,7 +23,7 @@ public class ContactsWidgetConfigActivity extends ExternalActionActivity { if (creatingAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 10); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_WIDGET); args.putBoolean("allowSwitchAccount", true); EditWidgetActivity fragment = new EditWidgetActivity(EditWidgetActivity.TYPE_CONTACTS, creatingAppWidgetId); fragment.setDelegate(dialogs -> { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java index 22dabdb56..08aa8d33b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java @@ -60,9 +60,14 @@ import org.telegram.ui.Cells.ContextLinkCell; import org.telegram.ui.Cells.StickerCell; import org.telegram.ui.Cells.StickerEmojiCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.EmojiPacksAlert; +import org.telegram.ui.Components.EmojiView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SuggestEmojiView; import java.util.ArrayList; @@ -85,14 +90,14 @@ public class ContentPreviewViewer { return true; } - void sendSticker(TLRPC.Document sticker, String query, Object parent, boolean notify, int scheduleDate); - void openSet(TLRPC.InputStickerSet set, boolean clearInputField); - boolean needSend(); + boolean needSend(int contentType); + default void sendSticker(TLRPC.Document sticker, String query, Object parent, boolean notify, int scheduleDate) {} + default void sendGif(Object gif, Object parent, boolean notify, int scheduleDate) {} + default void sendEmoji(TLRPC.Document emoji) {} boolean canSchedule(); - boolean isInScheduleMode(); long getDialogId(); @@ -100,7 +105,6 @@ public class ContentPreviewViewer { default boolean needRemove() { return false; } - default void remove(SendMessagesHelper.ImportingSticker sticker) { } @@ -113,22 +117,34 @@ public class ContentPreviewViewer { return true; } - default void sendGif(Object gif, Object parent, boolean notify, int scheduleDate) { - - } - - default void gifAddedOrDeleted() { - - } + default void gifAddedOrDeleted() {} default boolean needMenu() { return true; } + + default Boolean canSetAsStatus(TLRPC.Document document) { + return null; + } + default void setAsEmojiStatus(TLRPC.Document document, Integer until) {} + + default boolean needCopy() { + return false; + } + default void copyEmoji(TLRPC.Document document) {} + + default void resetTouch() {} + + default boolean needRemoveFromRecent(TLRPC.Document document) { + return false; + } + default void removeFromRecent(TLRPC.Document document) {} } - private final static int CONTENT_TYPE_NONE = -1; - private final static int CONTENT_TYPE_STICKER = 0; - private final static int CONTENT_TYPE_GIF = 1; + public final static int CONTENT_TYPE_NONE = -1; + public final static int CONTENT_TYPE_STICKER = 0; + public final static int CONTENT_TYPE_GIF = 1; + public final static int CONTENT_TYPE_EMOJI = 2; private static TextPaint textPaint; @@ -196,12 +212,12 @@ public class ContentPreviewViewer { menuVisible = true; containerView.invalidate(); if (delegate != null) { - if (delegate.needSend() && !delegate.isInScheduleMode()) { + if (delegate.needSend(currentContentType) && !delegate.isInScheduleMode()) { items.add(LocaleController.getString("SendStickerPreview", R.string.SendStickerPreview)); icons.add(R.drawable.msg_send); actions.add(0); } - if (delegate.needSend() && !delegate.isInScheduleMode()) { + if (delegate.needSend(currentContentType) && !delegate.isInScheduleMode()) { items.add(LocaleController.getString("SendWithoutSound", R.string.SendWithoutSound)); icons.add(R.drawable.input_notify_off); actions.add(6); @@ -273,7 +289,7 @@ public class ContentPreviewViewer { } } }; - ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(containerView.getContext(), R.drawable.popup_fixed_alert2, resourcesProvider); + 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); @@ -329,13 +345,144 @@ public class ContentPreviewViewer { popupWindow.showAtLocation(containerView, 0, (int) ((containerView.getMeasuredWidth() - previewMenu.getMeasuredWidth()) / 2f), y); containerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - } else if (delegate != null) { + } else if (currentContentType == CONTENT_TYPE_EMOJI && delegate != null) { menuVisible = true; + containerView.invalidate(); ArrayList items = new ArrayList<>(); final ArrayList actions = new ArrayList<>(); ArrayList icons = new ArrayList<>(); - if (delegate.needSend() && !delegate.isInScheduleMode()) { + if (delegate.needSend(currentContentType)) { + items.add(LocaleController.getString("SendEmojiPreview", R.string.SendEmojiPreview)); + icons.add(R.drawable.msg_send); + actions.add(0); + } + Boolean canSetAsStatus = delegate.canSetAsStatus(currentDocument); + if (canSetAsStatus != null) { + if (canSetAsStatus) { + items.add(LocaleController.getString("SetAsEmojiStatus", R.string.SetAsEmojiStatus)); + icons.add(R.drawable.msg_smile_status); + actions.add(1); + } else { + items.add(LocaleController.getString("RemoveStatus", R.string.RemoveStatus)); + icons.add(R.drawable.msg_smile_status); + actions.add(2); + } + } + if (delegate.needCopy()) { + items.add(LocaleController.getString("CopyEmojiPreview", R.string.CopyEmojiPreview)); + icons.add(R.drawable.msg_copy); + actions.add(3); + } + if (delegate.needRemoveFromRecent(currentDocument)) { + items.add(LocaleController.getString("RemoveFromRecent", R.string.RemoveFromRecent)); + icons.add(R.drawable.msg_delete); + actions.add(4); + } + if (items.isEmpty()) { + return; + } + + int[] ic = new int[icons.size()]; + for (int a = 0; a < icons.size(); a++) { + 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; + } + int which = (int) v.getTag(); + int action = actions.get(which); + if (action == 0) { + delegate.sendEmoji(currentDocument); + } else if (action == 1) { + delegate.setAsEmojiStatus(currentDocument, null); + } else if (action == 2) { + delegate.setAsEmojiStatus(null, null); + } else if (action == 3) { + delegate.copyEmoji(currentDocument); + } else if (action == 4) { + delegate.removeFromRecent(currentDocument); + } + if (popupWindow != null) { + popupWindow.dismiss(); + } + }; + + for (int i = 0; i < items.size(); i++) { + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(i == 0, i == items.size() - 1, previewMenu, icons.get(i), items.get(i), false, resourcesProvider); + if (actions.get(i) == 4) { + item.setIconColor(getThemedColor(Theme.key_dialogRedIcon)); + item.setTextColor(getThemedColor(Theme.key_dialogTextRed2)); + } + item.setTag(i); + item.setOnClickListener(onItemClickListener); + } + popupWindow = new ActionBarPopupWindow(previewMenu, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { + @Override + public void dismiss() { + super.dismiss(); + popupWindow = null; + menuVisible = false; + if (closeOnDismiss) { + close(); + } + } + }; + popupWindow.setPauseNotifications(true); + popupWindow.setDismissAnimationDuration(150); + popupWindow.setScaleOut(true); + popupWindow.setOutsideTouchable(true); + popupWindow.setClippingEnabled(true); + popupWindow.setAnimationStyle(R.style.PopupContextAnimation); + popupWindow.setFocusable(true); + previewMenu.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + popupWindow.getContentView().setFocusableInTouchMode(true); + + int insets = 0; + int top; + if (Build.VERSION.SDK_INT >= 21 && lastInsets != null) { + insets = lastInsets.getStableInsetBottom() + lastInsets.getStableInsetTop(); + top = lastInsets.getStableInsetTop(); + } else { + top = AndroidUtilities.statusBarHeight; + } + int size = Math.min(containerView.getWidth(), containerView.getHeight() - insets) - AndroidUtilities.dp(40f); + + int y = (int) (moveY + Math.max(size / 2 + top + (stickerEmojiLayout != null ? AndroidUtilities.dp(40) : 0), (containerView.getHeight() - insets - keyboardHeight) / 2) + size / 2); + y += AndroidUtilities.dp(24) - moveY; + popupWindow.showAtLocation(containerView, 0, (int) ((containerView.getMeasuredWidth() - previewMenu.getMeasuredWidth()) / 2f), y); + ActionBarPopupWindow.startAnimation(previewMenu); + + containerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + + if (moveY != 0) { + if (finalMoveY == 0) { + finalMoveY = 0; + startMoveY = moveY; + } + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f); + valueAnimator.addUpdateListener(animation -> { + currentMoveYProgress = (float) animation.getAnimatedValue(); + moveY = startMoveY + (finalMoveY - startMoveY) * currentMoveYProgress; + ContentPreviewViewer.this.containerView.invalidate(); + }); + valueAnimator.setDuration(350); + valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + valueAnimator.start(); + } + } else if (delegate != null) { + menuVisible = true; + containerView.invalidate(); + ArrayList items = new ArrayList<>(); + final ArrayList actions = new ArrayList<>(); + ArrayList icons = new ArrayList<>(); + + if (delegate.needSend(currentContentType) && !delegate.isInScheduleMode()) { items.add(LocaleController.getString("SendGifPreview", R.string.SendGifPreview)); icons.add(R.drawable.msg_send); actions.add(0); @@ -360,6 +507,9 @@ public class ContentPreviewViewer { } else { canDelete = false; } + if (items.isEmpty()) { + return; + } int[] ic = new int[icons.size()]; for (int a = 0; a < icons.size(); a++) { @@ -626,10 +776,19 @@ public class ContentPreviewViewer { contentType = CONTENT_TYPE_GIF; centerImage.setRoundRadius(AndroidUtilities.dp(6)); } + } else if (view instanceof EmojiPacksAlert.EmojiImageView) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); + } else if (view instanceof EmojiView.ImageViewEmoji && ((EmojiView.ImageViewEmoji) view).getSpan() != null) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); } if (contentType == CONTENT_TYPE_NONE || view == currentPreviewCell) { break; } + if (delegate != null) { + delegate.resetTouch(); + } if (currentPreviewCell instanceof StickerEmojiCell) { ((StickerEmojiCell) currentPreviewCell).setScaled(false); } else if (currentPreviewCell instanceof StickerCell) { @@ -660,6 +819,38 @@ public class ContentPreviewViewer { if (contentType != CONTENT_TYPE_GIF) { contextLinkCell.setScaled(true); } + } else if (currentPreviewCell instanceof EmojiPacksAlert.EmojiImageView) { + EmojiPacksAlert.EmojiImageView imageView = (EmojiPacksAlert.EmojiImageView) currentPreviewCell; + TLRPC.Document document = imageView.getDocument(); + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentType, false, null, resourcesProvider); + } + } else if (currentPreviewCell instanceof EmojiView.ImageViewEmoji) { + EmojiView.ImageViewEmoji imageView = (EmojiView.ImageViewEmoji) currentPreviewCell; + AnimatedEmojiSpan span = imageView.getSpan(); + TLRPC.Document document = null; + if (span != null) { + document = span.document; + if (document == null) { + document = AnimatedEmojiDrawable.findDocument(currentAccount, span.getDocumentId()); + } + } + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentType, false, null, resourcesProvider); + } else { + return false; + } + } else if (currentPreviewCell instanceof SuggestEmojiView.EmojiImageView) { + SuggestEmojiView.EmojiImageView emojiImageView = (SuggestEmojiView.EmojiImageView) currentPreviewCell; + Drawable drawable = emojiImageView.drawable; + TLRPC.Document document = null; + if (drawable instanceof AnimatedEmojiDrawable) { + document = ((AnimatedEmojiDrawable) drawable).getDocument(); + } + if (document == null) { + return false; + } + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentType, false, null, resourcesProvider); } runSmoothHaptic(); @@ -744,6 +935,19 @@ public class ContentPreviewViewer { centerImage.setRoundRadius(AndroidUtilities.dp(6)); } } + } else if (view instanceof EmojiPacksAlert.EmojiImageView) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); + } else if (view instanceof EmojiView.ImageViewEmoji && ((EmojiView.ImageViewEmoji) view).getSpan() != null) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); + } else if (view instanceof SuggestEmojiView.EmojiImageView) { + SuggestEmojiView.EmojiImageView emojiImageView = (SuggestEmojiView.EmojiImageView) view; + Drawable drawable = emojiImageView.drawable; + if (drawable instanceof AnimatedEmojiDrawable) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); + } } if (contentType == CONTENT_TYPE_NONE) { return false; @@ -756,6 +960,7 @@ public class ContentPreviewViewer { if (openPreviewRunnable == null) { return; } + boolean opened = false; listView.setOnItemClickListener((RecyclerListView.OnItemClickListener) null); listView.requestDisallowInterceptTouchEvent(true); openPreviewRunnable = null; @@ -765,20 +970,60 @@ public class ContentPreviewViewer { if (currentPreviewCell instanceof StickerEmojiCell) { StickerEmojiCell stickerEmojiCell = (StickerEmojiCell) currentPreviewCell; open(stickerEmojiCell.getSticker(), stickerEmojiCell.getStickerPath(), stickerEmojiCell.getEmoji(), delegate != null ? delegate.getQuery(false) : null, null, contentTypeFinal, stickerEmojiCell.isRecent(), stickerEmojiCell.getParentObject(), resourcesProvider); + opened = true; stickerEmojiCell.setScaled(true); } else if (currentPreviewCell instanceof StickerCell) { StickerCell stickerCell = (StickerCell) currentPreviewCell; open(stickerCell.getSticker(), null, null, delegate != null ? delegate.getQuery(false) : null, null, contentTypeFinal, false, stickerCell.getParentObject(), resourcesProvider); + opened = true; stickerCell.setScaled(true); clearsInputField = stickerCell.isClearsInputField(); } else if (currentPreviewCell instanceof ContextLinkCell) { ContextLinkCell contextLinkCell = (ContextLinkCell) currentPreviewCell; open(contextLinkCell.getDocument(), null, null, delegate != null ? delegate.getQuery(true) : null, contextLinkCell.getBotInlineResult(), contentTypeFinal, false, contextLinkCell.getBotInlineResult() != null ? contextLinkCell.getInlineBot() : contextLinkCell.getParentObject(), resourcesProvider); + opened = true; if (contentTypeFinal != CONTENT_TYPE_GIF) { contextLinkCell.setScaled(true); } + } else if (currentPreviewCell instanceof EmojiPacksAlert.EmojiImageView) { + EmojiPacksAlert.EmojiImageView imageView = (EmojiPacksAlert.EmojiImageView) currentPreviewCell; + TLRPC.Document document = imageView.getDocument(); + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentTypeFinal, false, null, resourcesProvider); + opened = true; + } + } else if (currentPreviewCell instanceof EmojiView.ImageViewEmoji) { + EmojiView.ImageViewEmoji imageView = (EmojiView.ImageViewEmoji) currentPreviewCell; + AnimatedEmojiSpan span = imageView.getSpan(); + TLRPC.Document document = null; + if (span != null) { + document = span.document; + if (document == null) { + document = AnimatedEmojiDrawable.findDocument(currentAccount, span.getDocumentId()); + } + } + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentTypeFinal, false, null, resourcesProvider); + opened = true; + } + } else if (currentPreviewCell instanceof SuggestEmojiView.EmojiImageView) { + SuggestEmojiView.EmojiImageView emojiImageView = (SuggestEmojiView.EmojiImageView) currentPreviewCell; + Drawable drawable = emojiImageView.drawable; + TLRPC.Document document = null; + if (drawable instanceof AnimatedEmojiDrawable) { + document = ((AnimatedEmojiDrawable) drawable).getDocument(); + } + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentTypeFinal, false, null, resourcesProvider); + opened = true; + } + } + if (opened) { + currentPreviewCell.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + if (delegate != null) { + delegate.resetTouch(); + } } - currentPreviewCell.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); }; AndroidUtilities.runOnUIThread(openPreviewRunnable, 200); return true; @@ -876,7 +1121,8 @@ public class ContentPreviewViewer { stickerEmojiLayout = null; backgroundDrawable.setColor(Theme.getActiveTheme().isDark() ? 0x71000000 : 0x64E6E6E6); drawEffect = false; - if (contentType == CONTENT_TYPE_STICKER) { + centerImage.setColorFilter(null); + if (contentType == CONTENT_TYPE_STICKER || contentType == CONTENT_TYPE_EMOJI) { if (document == null && sticker == null) { return; } @@ -896,7 +1142,11 @@ public class ContentPreviewViewer { break; } } - if (newSet != null && (delegate == null || delegate.needMenu())) { + if (contentType == CONTENT_TYPE_EMOJI && emojiPath != null) { + CharSequence emoji = Emoji.replaceEmoji(emojiPath, textPaint.getFontMetricsInt(), AndroidUtilities.dp(24), false); + stickerEmojiLayout = new StaticLayout(emoji, textPaint, AndroidUtilities.dp(100), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + } + if ((newSet != null || contentType == CONTENT_TYPE_EMOJI) && (delegate == null || delegate.needMenu())) { AndroidUtilities.cancelRunOnUIThread(showSheetRunnable); AndroidUtilities.runOnUIThread(showSheetRunnable, 1300); } @@ -911,6 +1161,9 @@ public class ContentPreviewViewer { effectImage.setImage(ImageLocation.getForDocument(MessageObject.getPremiumStickerAnimation(document), document), null, null, null, "tgs", currentStickerSet, 1); } } + if (MessageObject.isTextColorEmoji(document)) { + centerImage.setColorFilter(Theme.chat_animatedEmojiTextColorFilter); + } for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeSticker) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java index f26e242e1..757160f37 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java @@ -11,6 +11,7 @@ package org.telegram.ui; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.os.Build; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.ReplacementSpan; @@ -49,11 +50,14 @@ import org.telegram.ui.Components.RecyclerListView; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Timer; @@ -236,6 +240,7 @@ public class CountrySelectActivity extends BaseFragment { public static class Country { public String name; + public String defaultName; public String code; public String shortname; @@ -301,10 +306,17 @@ public class CountrySelectActivity extends BaseFragment { FileLog.e(e); } } - Collections.sort(sortedCountries, String::compareTo); + Comparator comparator; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Collator collator = Collator.getInstance(LocaleController.getInstance().getCurrentLocale() != null ? LocaleController.getInstance().getCurrentLocale() : Locale.getDefault()); + comparator = collator::compare; + } else { + comparator = String::compareTo; + } + Collections.sort(sortedCountries, comparator); for (ArrayList arr : countries.values()) { - Collections.sort(arr, (country, country2) -> country.name.compareTo(country2.name)); + Collections.sort(arr, (country, country2) -> comparator.compare(country.name, country2.name)); } } @@ -411,7 +423,11 @@ public class CountrySelectActivity extends BaseFragment { for (List list : countries.values()) { for (Country country : list) { countryList.add(country); - countrySearchMap.put(country, Arrays.asList(country.name.split(" "))); + List keys = new ArrayList<>(Arrays.asList(country.name.split(" "))); + if (country.defaultName != null) { + keys.addAll(Arrays.asList(country.defaultName.split(" "))); + } + countrySearchMap.put(country, keys); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DataSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DataSettingsActivity.java index 45238714f..c7ecdfdfc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DataSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DataSettingsActivity.java @@ -13,6 +13,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Build; +import android.os.Bundle; import android.text.TextUtils; import android.view.Gravity; import android.view.View; @@ -31,7 +32,9 @@ import org.telegram.messenger.ImageLoader; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; +import org.telegram.messenger.SaveToGallerySettingsHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.StatsController; import org.telegram.messenger.voip.Instance; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -43,6 +46,7 @@ import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.NotificationsCheckCell; import org.telegram.ui.Cells.RadioColorCell; import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; @@ -103,6 +107,10 @@ public class DataSettingsActivity extends BaseFragment { private boolean updateVoipUseLessData; + private boolean updateStorageUsageAnimated; + private boolean storageUsageLoading; + private long storageUsageSize; + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); @@ -163,6 +171,61 @@ public class DataSettingsActivity extends BaseFragment { return true; } + private void loadCacheSize() { + final Runnable fireLoading = () -> { + storageUsageLoading = true; + if (listAdapter != null && storageUsageRow >= 0) { + rebind(storageUsageRow); + } + }; + AndroidUtilities.runOnUIThread(fireLoading, 100); + + final long start = System.currentTimeMillis(); + CacheControlActivity.calculateTotalSize(size -> { + AndroidUtilities.cancelRunOnUIThread(fireLoading); + updateStorageUsageAnimated = updateStorageUsageAnimated || (System.currentTimeMillis() - start) > 120; + storageUsageSize = size; + storageUsageLoading = false; + if (listAdapter != null && storageUsageRow >= 0) { + rebind(storageUsageRow); + } + }); + + } + + private void rebind(int position) { + if (listView == null || listAdapter == null) { + return; + } + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + RecyclerView.ViewHolder holder = listView.getChildViewHolder(child); + if (holder != null && holder.getAdapterPosition() == position) { + listAdapter.onBindViewHolder(holder, position); + return; + } + } + } + + private void rebindAll() { + if (listView == null || listAdapter == null) { + return; + } + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + RecyclerView.ViewHolder holder = listView.getChildViewHolder(child); + if (holder != null) { + listAdapter.onBindViewHolder(holder, listView.getChildAdapterPosition(child)); + } + } + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + CacheControlActivity.canceled = true; + } + @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); @@ -201,9 +264,15 @@ public class DataSettingsActivity extends BaseFragment { } else { flag = SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; } - SharedConfig.toggleSaveToGalleryFlag(flag); - TextCheckCell textCheckCell = (TextCheckCell) view; - textCheckCell.setChecked((SharedConfig.saveToGalleryFlags & flag) != 0); + if (LocaleController.isRTL && x <= AndroidUtilities.dp(76) || !LocaleController.isRTL && x >= view.getMeasuredWidth() - AndroidUtilities.dp(76)) { + SaveToGallerySettingsHelper.getSettings(flag).toggle(); + AndroidUtilities.updateVisibleRows(listView); + } else { + Bundle bundle = new Bundle(); + bundle.putInt("type", flag); + presentFragment(new SaveToGallerySettingsActivity(bundle)); + } + } else if (position == mobileRow || position == roamingRow || position == wifiRow) { if (LocaleController.isRTL && x <= AndroidUtilities.dp(76) || !LocaleController.isRTL && x >= view.getMeasuredWidth() - AndroidUtilities.dp(76)) { boolean wasEnabled = listAdapter.isRowEnabled(resetDownloadRow); @@ -365,7 +434,7 @@ public class DataSettingsActivity extends BaseFragment { setVisibleDialog(dlg); dlg.show(); } else if (position == dataUsageRow) { - presentFragment(new DataUsageActivity()); + presentFragment(new DataUsage2Activity()); } else if (position == storageNumRow) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("StoragePath", R.string.StoragePath)); @@ -461,9 +530,8 @@ public class DataSettingsActivity extends BaseFragment { @Override public void onResume() { super.onResume(); - if (listAdapter != null) { - listAdapter.notifyDataSetChanged(); - } + loadCacheSize(); + rebindAll(); } private class ListAdapter extends RecyclerListView.SelectionAdapter { @@ -490,14 +558,38 @@ public class DataSettingsActivity extends BaseFragment { } break; } + case 6: { + TextCell textCell = (TextCell) holder.itemView; + if (position == storageUsageRow) { + if (storageUsageLoading) { + textCell.setTextAndValueAndColorfulIcon(LocaleController.getString("StorageUsage", R.string.StorageUsage), "", false, R.drawable.msg_filled_storageusage, getThemedColor(Theme.key_color_lightblue), true); + textCell.setDrawLoading(true, 45, updateStorageUsageAnimated); + } else { + textCell.setTextAndValueAndColorfulIcon(LocaleController.getString("StorageUsage", R.string.StorageUsage), storageUsageSize <= 0 ? "" : AndroidUtilities.formatFileSize(storageUsageSize), true, R.drawable.msg_filled_storageusage, getThemedColor(Theme.key_color_lightblue), true); + textCell.setDrawLoading(false, 45, updateStorageUsageAnimated); + } + updateStorageUsageAnimated = false; + } else if (position == dataUsageRow) { + StatsController statsController = StatsController.getInstance(currentAccount); + long size = ( + statsController.getReceivedBytesCount(0, StatsController.TYPE_TOTAL) + + statsController.getReceivedBytesCount(1, StatsController.TYPE_TOTAL) + + statsController.getReceivedBytesCount(2, StatsController.TYPE_TOTAL) + + statsController.getSentBytesCount(0, StatsController.TYPE_TOTAL) + + statsController.getSentBytesCount(1, StatsController.TYPE_TOTAL) + + statsController.getSentBytesCount(2, StatsController.TYPE_TOTAL) + ); + textCell.setTextAndValueAndColorfulIcon(LocaleController.getString("NetworkUsage", R.string.NetworkUsage), AndroidUtilities.formatFileSize(size), true, R.drawable.msg_filled_datausage, getThemedColor(Theme.key_color_green), storageNumRow != -1); + } else if (position == storageNumRow) { + textCell.setTextAndColorfulIcon(LocaleController.getString("StoragePath", R.string.StoragePath), R.drawable.msg_filled_sdcard, getThemedColor(Theme.key_color_yellow), false); + } + break; + } case 1: { TextSettingsCell textCell = (TextSettingsCell) holder.itemView; textCell.setCanDisable(false); textCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); - if (position == storageUsageRow) { - textCell.setIcon(R.drawable.msg_storage_usage); - textCell.setText(LocaleController.getString("StorageUsage", R.string.StorageUsage), true); - } else if (position == useLessDataForCallsRow) { + if (position == useLessDataForCallsRow) { textCell.setIcon(0); SharedPreferences preferences = MessagesController.getGlobalMainSettings(); String value = null; @@ -517,12 +609,6 @@ public class DataSettingsActivity extends BaseFragment { } textCell.setTextAndValue(LocaleController.getString("VoipUseLessData", R.string.VoipUseLessData), value, updateVoipUseLessData, true); updateVoipUseLessData = false; - } else if (position == dataUsageRow) { - textCell.setIcon(R.drawable.msg_data_usage); - textCell.setText(LocaleController.getString("NetworkUsage", R.string.NetworkUsage), storageNumRow != -1); - } else if (position == storageNumRow) { - textCell.setIcon(R.drawable.msg_storage_path); - textCell.setText(LocaleController.getString("StoragePath", R.string.StoragePath), false); } else if (position == proxyRow) { textCell.setIcon(0); textCell.setText(LocaleController.getString("ProxySettings", R.string.ProxySettings), false); @@ -555,7 +641,7 @@ public class DataSettingsActivity extends BaseFragment { } else if (position == autoplayHeaderRow) { headerCell.setText(LocaleController.getString("AutoplayMedia", R.string.AutoplayMedia)); } else if (position == saveToGallerySectionRow) { - headerCell.setText(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); + headerCell.setText(LocaleController.getString("SaveToGallerySettings", R.string.SaveToGallerySettings)); } break; } @@ -573,12 +659,6 @@ public class DataSettingsActivity extends BaseFragment { checkCell.setTextAndCheck(LocaleController.getString("AutoplayGIF", R.string.AutoplayGIF), SharedConfig.autoplayGifs, true); } else if (position == autoplayVideoRow) { checkCell.setTextAndCheck(LocaleController.getString("AutoplayVideo", R.string.AutoplayVideo), SharedConfig.autoplayVideo, false); - } else if (position == saveToGalleryPeerRow) { - checkCell.setTextAndCheck(LocaleController.getString("SaveToGalleryPrivate", R.string.SaveToGalleryPrivate), (SharedConfig.saveToGalleryFlags & SharedConfig.SAVE_TO_GALLERY_FLAG_PEER) != 0, true); - } else if (position == saveToGalleryGroupsRow) { - checkCell.setTextAndCheck(LocaleController.getString("SaveToGalleryGroups", R.string.SaveToGalleryGroups), (SharedConfig.saveToGalleryFlags & SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP) != 0, true); - } else if (position == saveToGalleryChannelsRow) { - checkCell.setTextAndCheck(LocaleController.getString("SaveToGalleryChannels", R.string.SaveToGalleryChannels), (SharedConfig.saveToGalleryFlags & SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS) != 0, false); } break; } @@ -593,10 +673,22 @@ public class DataSettingsActivity extends BaseFragment { NotificationsCheckCell checkCell = (NotificationsCheckCell) holder.itemView; String text; - StringBuilder builder = new StringBuilder(); - DownloadController.Preset preset; + CharSequence description = null; + DownloadController.Preset preset = null; boolean enabled; - if (position == mobileRow) { + if (position == saveToGalleryPeerRow) { + text = LocaleController.getString("SaveToGalleryPrivate", R.string.SaveToGalleryPrivate); + description = SaveToGallerySettingsHelper.user.createDescription(currentAccount); + enabled = SaveToGallerySettingsHelper.user.enabled(); + } else if (position == saveToGalleryGroupsRow) { + text = LocaleController.getString("SaveToGalleryGroups", R.string.SaveToGalleryGroups); + description = SaveToGallerySettingsHelper.groups.createDescription(currentAccount); + enabled = SaveToGallerySettingsHelper.groups.enabled(); + } else if (position == saveToGalleryChannelsRow) { + text = LocaleController.getString("SaveToGalleryChannels", R.string.SaveToGalleryChannels); + description = SaveToGallerySettingsHelper.channels.createDescription(currentAccount); + enabled = SaveToGallerySettingsHelper.channels.enabled(); + } else if (position == mobileRow) { text = LocaleController.getString("WhenUsingMobileData", R.string.WhenUsingMobileData); enabled = DownloadController.getInstance(currentAccount).mobilePreset.enabled; preset = DownloadController.getInstance(currentAccount).getCurrentMobilePreset(); @@ -609,47 +701,55 @@ public class DataSettingsActivity extends BaseFragment { enabled = DownloadController.getInstance(currentAccount).roamingPreset.enabled; preset = DownloadController.getInstance(currentAccount).getCurrentRoamingPreset(); } - - boolean photos = false; - boolean videos = false; - boolean files = false; - int count = 0; - for (int a = 0; a < preset.mask.length; a++) { - if (!photos && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_PHOTO) != 0) { - photos = true; - count++; - } - if (!videos && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_VIDEO) != 0) { - videos = true; - count++; - } - if (!files && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_DOCUMENT) != 0) { - files = true; - count++; - } - } - if (preset.enabled && count != 0) { - if (photos) { - builder.append(LocaleController.getString("AutoDownloadPhotosOn", R.string.AutoDownloadPhotosOn)); - } - if (videos) { - if (builder.length() > 0) { - builder.append(", "); + boolean checked; + if (preset != null) { + StringBuilder builder = new StringBuilder(); + boolean photos = false; + boolean videos = false; + boolean files = false; + int count = 0; + for (int a = 0; a < preset.mask.length; a++) { + if (!photos && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_PHOTO) != 0) { + photos = true; + count++; } - builder.append(LocaleController.getString("AutoDownloadVideosOn", R.string.AutoDownloadVideosOn)); - builder.append(String.format(" (%1$s)", AndroidUtilities.formatFileSize(preset.sizes[DownloadController.typeToIndex(DownloadController.AUTODOWNLOAD_TYPE_VIDEO)], true))); - } - if (files) { - if (builder.length() > 0) { - builder.append(", "); + if (!videos && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_VIDEO) != 0) { + videos = true; + count++; + } + if (!files && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_DOCUMENT) != 0) { + files = true; + count++; } - builder.append(LocaleController.getString("AutoDownloadFilesOn", R.string.AutoDownloadFilesOn)); - builder.append(String.format(" (%1$s)", AndroidUtilities.formatFileSize(preset.sizes[DownloadController.typeToIndex(DownloadController.AUTODOWNLOAD_TYPE_DOCUMENT)], true))); } + if (preset.enabled && count != 0) { + if (photos) { + builder.append(LocaleController.getString("AutoDownloadPhotosOn", R.string.AutoDownloadPhotosOn)); + } + if (videos) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("AutoDownloadVideosOn", R.string.AutoDownloadVideosOn)); + builder.append(String.format(" (%1$s)", AndroidUtilities.formatFileSize(preset.sizes[DownloadController.typeToIndex(DownloadController.AUTODOWNLOAD_TYPE_VIDEO)], true))); + } + if (files) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("AutoDownloadFilesOn", R.string.AutoDownloadFilesOn)); + builder.append(String.format(" (%1$s)", AndroidUtilities.formatFileSize(preset.sizes[DownloadController.typeToIndex(DownloadController.AUTODOWNLOAD_TYPE_DOCUMENT)], true))); + } + } else { + builder.append(LocaleController.getString("NoMediaAutoDownload", R.string.NoMediaAutoDownload)); + } + checked = (photos || videos || files) && enabled; + description = builder; } else { - builder.append(LocaleController.getString("NoMediaAutoDownload", R.string.NoMediaAutoDownload)); + checked = enabled; } - checkCell.setTextAndValueAndCheck(text, builder, (photos || videos || files) && enabled, 0, true, true); + checkCell.setAnimationsEnabled(true); + checkCell.setTextAndValueAndCheck(text, description, checked, 0, true, true); break; } } @@ -706,7 +806,7 @@ public class DataSettingsActivity extends BaseFragment { view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 2: - view = new HeaderCell(mContext); + view = new HeaderCell(mContext, 22); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 3: @@ -718,10 +818,14 @@ public class DataSettingsActivity extends BaseFragment { view.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); break; case 5: - default: view = new NotificationsCheckCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; + case 6: + default: + view = new TextCell(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; } view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); return new RecyclerListView.Holder(view); @@ -733,12 +837,14 @@ public class DataSettingsActivity extends BaseFragment { return 0; } else if (position == mediaDownloadSectionRow || position == streamSectionRow || position == callsSectionRow || position == usageSectionRow || position == proxySectionRow || position == autoplayHeaderRow || position == saveToGallerySectionRow) { return 2; - } else if (position == enableCacheStreamRow || position == enableStreamRow || position == enableAllStreamRow || position == enableMkvRow || position == autoplayGifsRow || position == autoplayVideoRow || position == saveToGalleryGroupsRow || position == saveToGalleryPeerRow || position == saveToGalleryChannelsRow) { + } else if (position == enableCacheStreamRow || position == enableStreamRow || position == enableAllStreamRow || position == enableMkvRow || position == autoplayGifsRow || position == autoplayVideoRow) { return 3; } else if (position == enableAllStreamInfoRow) { return 4; - } else if (position == mobileRow || position == wifiRow || position == roamingRow) { + } else if (position == mobileRow || position == wifiRow || position == roamingRow || position == saveToGalleryGroupsRow || position == saveToGalleryPeerRow || position == saveToGalleryChannelsRow) { return 5; + } else if (position == storageUsageRow || position == dataUsageRow || position == storageNumRow) { + return 6; } else { return 1; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java b/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java new file mode 100644 index 000000000..85ae7afdc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java @@ -0,0 +1,1108 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +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.TextUtils; +import android.text.style.DynamicDrawableSpan; +import android.text.style.ImageSpan; +import android.text.style.MetricAffectingSpan; +import android.text.style.RelativeSizeSpan; +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.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.StatsController; +import org.telegram.ui.ActionBar.ActionBar; +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.TextCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Components.CacheChart; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.TypefaceSpan; +import org.telegram.ui.Components.ViewPagerFixed; + +import java.util.ArrayList; +import java.util.Arrays; + +public class DataUsage2Activity extends BaseFragment { + + private Theme.ResourcesProvider resourcesProvider; + + public DataUsage2Activity() { + this(null); + } + + public DataUsage2Activity(Theme.ResourcesProvider resourcesProvider) { + super(); + this.resourcesProvider = resourcesProvider; + } + + private ViewPagerFixed pager; + private ViewPagerFixed.Adapter pageAdapter; + private ViewPagerFixed.TabsView tabsView; + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setTitle(LocaleController.getString("NetworkUsage", R.string.NetworkUsage)); + actionBar.setBackgroundColor(getThemedColor(Theme.key_actionBarActionModeDefault)); + actionBar.setTitleColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + actionBar.setItemsColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), false); + actionBar.setItemsBackgroundColor(getThemedColor(Theme.key_listSelector), false); + actionBar.setCastShadows(false); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + FrameLayout frameLayout = new FrameLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY)); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (getParentLayout() != null && tabsView != null) { + float y = tabsView.getMeasuredHeight(); + canvas.drawLine(0, y, getWidth(), y, Theme.dividerPaint); + } + } + }; + frameLayout.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + + pager = new ViewPagerFixed(context); + pager.setAdapter(pageAdapter = new PageAdapter()); + + tabsView = pager.createTabsView(true, 8); + tabsView.setBackgroundColor(getThemedColor(Theme.key_actionBarActionModeDefault)); + frameLayout.addView(tabsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.FILL_HORIZONTAL)); + + frameLayout.addView(pager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 48, 0, 0)); + + return fragmentView = frameLayout; + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return resourcesProvider; + } + + private class PageAdapter extends ViewPagerFixed.Adapter { + + @Override + public int getItemCount() { + return 4; + } + + @Override + public View createView(int viewType) { + return new ListView(getContext()); + } + + @Override + public void bindView(View view, int position, int viewType) { + ((ListView) view).setType(position); + ((ListView) view).scrollToPosition(0); + } + + @Override + public String getItemTitle(int position) { + switch (position) { + case ListView.TYPE_ALL: return LocaleController.getString("NetworkUsageAllTab", R.string.NetworkUsageAllTab); + case ListView.TYPE_MOBILE: return LocaleController.getString("NetworkUsageMobileTab", R.string.NetworkUsageMobileTab); + case ListView.TYPE_WIFI: return LocaleController.getString("NetworkUsageWiFiTab", R.string.NetworkUsageWiFiTab); + case ListView.TYPE_ROAMING: return LocaleController.getString("NetworkUsageRoamingTab", R.string.NetworkUsageRoamingTab); + default: return ""; + } + } + } + + private static String[] colors = { + Theme.key_statisticChartLine_blue, + Theme.key_statisticChartLine_green, + Theme.key_statisticChartLine_lightblue, + Theme.key_statisticChartLine_golden, + Theme.key_statisticChartLine_red, + Theme.key_statisticChartLine_purple, + Theme.key_statisticChartLine_cyan + }; + + private static int[] particles = { + R.drawable.msg_filled_data_videos, + R.drawable.msg_filled_data_files, + R.drawable.msg_filled_data_photos, + R.drawable.msg_filled_data_messages, + R.drawable.msg_filled_data_music, + R.drawable.msg_filled_data_voice, + R.drawable.msg_filled_data_calls + }; + + private static int[] titles = { + R.string.LocalVideoCache, + R.string.LocalDocumentCache, + R.string.LocalPhotoCache, + R.string.MessagesSettings, + R.string.LocalMusicCache, + R.string.LocalAudioCache, + R.string.CallsDataUsage + }; + + private static int[] stats = { + StatsController.TYPE_VIDEOS, + StatsController.TYPE_FILES, + StatsController.TYPE_PHOTOS, + StatsController.TYPE_MESSAGES, + StatsController.TYPE_MUSIC, + StatsController.TYPE_AUDIOS, + StatsController.TYPE_CALLS, + }; + + + class ListView extends RecyclerListView { + + public static final int TYPE_ALL = 0; + public static final int TYPE_MOBILE = 1; + public static final int TYPE_WIFI = 2; + public static final int TYPE_ROAMING = 3; + + private boolean animateChart = false; + + int currentType = TYPE_ALL; + + LinearLayoutManager layoutManager; + Adapter adapter; + + public ListView(Context context) { + super(context); + setLayoutManager(layoutManager = new LinearLayoutManager(context)); + setAdapter(adapter = new Adapter()); + setOnItemClickListener((view, position) -> { + if (view instanceof Cell && position >= 0 && position < itemInners.size()) { + ItemInner item = itemInners.get(position); + if (item != null) { + if (item.index >= 0) { + collapsed[item.index] = !collapsed[item.index]; + updateRows(true); + } else if (item.index == -2) { + presentFragment(new DataAutoDownloadActivity(currentType - 1)); + } + } + } else if (view instanceof TextCell) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("ResetStatisticsAlertTitle", R.string.ResetStatisticsAlertTitle)); + builder.setMessage(LocaleController.getString("ResetStatisticsAlert", R.string.ResetStatisticsAlert)); + builder.setPositiveButton(LocaleController.getString("Reset", R.string.Reset), (dialogInterface, j) -> { + removedSegments.clear(); + for (int i = 0; i < segments.length; ++i) { + long size = segments[i].size; + if (size > 0) { + removedSegments.add(segments[i].index); + } + } + + StatsController.getInstance(currentAccount).resetStats(0); + StatsController.getInstance(currentAccount).resetStats(1); + StatsController.getInstance(currentAccount).resetStats(2); + + animateChart = true; + setup(); + updateRows(true); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + AlertDialog dialog = builder.create(); + showDialog(dialog); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_dialogTextRed2)); + } + } + }); + + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(220); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + setItemAnimator(itemAnimator); + } + + public void setType(int type) { + this.currentType = type; + + removedSegments.clear(); + empty = getBytesCount(StatsController.TYPE_TOTAL) <= 0; + setup(); + updateRows(false); + } + + private void setup() { + totalSize = getBytesCount(StatsController.TYPE_TOTAL); + totalSizeIn = getReceivedBytesCount(StatsController.TYPE_TOTAL); + totalSizeOut = getSentBytesCount(StatsController.TYPE_TOTAL); + if (segments == null) { + segments = new Size[7]; + } + if (chartSegments == null) { + chartSegments = new Size[7]; + } + for (int i = 0; i < stats.length; ++i) { + long size = getBytesCount(stats[i]); + chartSegments[i] = segments[i] = new Size( + i, + size, + getReceivedBytesCount(stats[i]), + getSentBytesCount(stats[i]), + getReceivedItemsCount(stats[i]), + getSentItemsCount(stats[i]) + ); + tempSizes[i] = size / (float) totalSize; + } + Arrays.sort(segments, (a, b) -> Long.compare(b.size, a.size)); + AndroidUtilities.roundPercents(tempSizes, tempPercents); + Arrays.fill(collapsed, true); + } + + private ArrayList oldItems = new ArrayList<>(); + private ArrayList itemInners = new ArrayList<>(); + + private float[] tempSizes = new float[7]; + private int[] tempPercents = new int[7]; + + private ArrayList removedSegments = new ArrayList<>(); + private Size[] segments, chartSegments; + private boolean[] collapsed = new boolean[7]; + private long totalSize, totalSizeIn, totalSizeOut; + private boolean empty; + + private CacheChart chart; + + private String formatPercent(int percent) { + return percent <= 0 ? String.format("<%d%%", 1) : String.format("%d%%", percent); + } + + class Size extends CacheChart.SegmentSize { + + int index; + long inSize, outSize; + int inCount, outCount; + + public Size(int index, long size, long inSize, long outSize, int inCount, int outCount) { + this.index = index; + + this.size = size; + this.selected = true; + + this.inSize = inSize; + this.inCount = inCount; + this.outSize = outSize; + this.outCount = outCount; + } + } + + private void updateRows(boolean animated) { + oldItems.clear(); + oldItems.addAll(itemInners); + + itemInners.clear(); + + itemInners.add(new ItemInner(VIEW_TYPE_CHART)); + final String sinceText = totalSize > 0 ? + LocaleController.formatString("YourNetworkUsageSince", R.string.YourNetworkUsageSince, LocaleController.getInstance().formatterStats.format(getResetStatsDate())) : + LocaleController.formatString("NoNetworkUsageSince", R.string.NoNetworkUsageSince, LocaleController.getInstance().formatterStats.format(getResetStatsDate())); + itemInners.add(ItemInner.asSubtitle(sinceText)); + + ArrayList sections = new ArrayList<>(); + for (int i = 0; i < segments.length; ++i) { + long size = segments[i].size; + int index = segments[i].index; + boolean emptyButShown = empty || removedSegments.contains(index); + if (size <= 0 && !emptyButShown) { + continue; + } + SpannableString percent = new SpannableString(formatPercent(tempPercents[index])); + percent.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, percent.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + percent.setSpan(new RelativeSizeSpan(.8f), 0, percent.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + percent.setSpan(new CustomCharacterSpan(.1), 0, percent.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + sections.add(ItemInner.asCell( + i, + particles[index], + getThemedColor(colors[index]), + size == 0 ? + LocaleController.getString(titles[index]) : + TextUtils.concat(LocaleController.getString(titles[index]), " ", percent), + AndroidUtilities.formatFileSize(size) + )); + } + + if (!sections.isEmpty()) { + + SpannableString sentIcon = new SpannableString("^"); + Drawable sentIconDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_upload).mutate(); + sentIconDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), PorterDuff.Mode.MULTIPLY)); + sentIconDrawable.setBounds(0, AndroidUtilities.dp(2), AndroidUtilities.dp(16), AndroidUtilities.dp(2 + 16)); + sentIcon.setSpan(new ImageSpan(sentIconDrawable, DynamicDrawableSpan.ALIGN_CENTER), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + SpannableString receivedIcon = new SpannableString("v"); + Drawable receivedIconDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_download).mutate(); + receivedIconDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), PorterDuff.Mode.MULTIPLY)); + receivedIconDrawable.setBounds(0, AndroidUtilities.dp(2), AndroidUtilities.dp(16), AndroidUtilities.dp(2 + 16)); + receivedIcon.setSpan(new ImageSpan(receivedIconDrawable, DynamicDrawableSpan.ALIGN_CENTER), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + for (int i = 0; i < sections.size(); ++i) { + int index = sections.get(i).index; + if (index >= 0 && !collapsed[index]) { + Size size = segments[index]; + if (stats[size.index] == StatsController.TYPE_CALLS) { + if (size.outSize > 0 || size.outCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + LocaleController.formatPluralStringComma("OutgoingCallsCount", size.outCount), + AndroidUtilities.formatFileSize(size.outSize) + )); + } + if (size.inSize > 0 || size.inCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + LocaleController.formatPluralStringComma("IncomingCallsCount", size.inCount), + AndroidUtilities.formatFileSize(size.inSize) + )); + } + } else if (stats[size.index] != StatsController.TYPE_MESSAGES) { + if (size.outSize > 0 || size.outCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + TextUtils.concat(sentIcon, " ", AndroidUtilities.replaceTags(LocaleController.formatPluralStringComma("FilesSentCount", size.outCount))), + AndroidUtilities.formatFileSize(size.outSize) + )); + } + if (size.inSize > 0 || size.inCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + TextUtils.concat(receivedIcon, " ", AndroidUtilities.replaceTags(LocaleController.formatPluralStringComma("FilesReceivedCount", size.inCount))), + AndroidUtilities.formatFileSize(size.inSize) + )); + } + } else { + if (size.outSize > 0 || size.outCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + TextUtils.concat(sentIcon, " ", LocaleController.getString("BytesSent", R.string.BytesSent)), + AndroidUtilities.formatFileSize(size.outSize) + )); + } + if (size.inSize > 0 || size.inCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + TextUtils.concat(receivedIcon, " ", LocaleController.getString("BytesReceived", R.string.BytesReceived)), + AndroidUtilities.formatFileSize(size.inSize) + )); + } + } + } + } +// itemInners.add(new ItemInner(VIEW_TYPE_ROUNDING)); + itemInners.addAll(sections); +// itemInners.add(new ItemInner(VIEW_TYPE_END)); + if (!empty) { + itemInners.add(ItemInner.asSeparator(LocaleController.getString("DataUsageSectionsInfo", R.string.DataUsageSectionsInfo))); + } + } + + if (!empty) { + itemInners.add(ItemInner.asHeader(LocaleController.getString("TotalNetworkUsage", R.string.TotalNetworkUsage))); + itemInners.add(ItemInner.asCell( + -1, + R.drawable.msg_filled_data_sent, + getThemedColor(Theme.key_statisticChartLine_lightblue), + LocaleController.getString("BytesSent", R.string.BytesSent), + AndroidUtilities.formatFileSize(totalSizeOut) + )); + itemInners.add(ItemInner.asCell( + -1, + R.drawable.msg_filled_data_received, + getThemedColor(Theme.key_statisticChartLine_green), + LocaleController.getString("BytesReceived", R.string.BytesReceived), + AndroidUtilities.formatFileSize(totalSizeIn) + )); + } + + if (!sections.isEmpty()) { + itemInners.add(ItemInner.asSeparator(sinceText)); + } + + if (currentType != TYPE_ALL) { + if (sections.isEmpty()) { + itemInners.add(ItemInner.asSeparator()); + } + itemInners.add(ItemInner.asCell( + -2, + R.drawable.msg_download_settings, + getThemedColor(Theme.key_statisticChartLine_lightblue), + LocaleController.getString("AutomaticDownloadSettings", R.string.AutomaticDownloadSettings), + null + )); + String info; + switch (currentType) { + case TYPE_MOBILE: + info = LocaleController.getString("AutomaticDownloadSettingsInfoMobile", R.string.AutomaticDownloadSettingsInfoMobile); + break; + case TYPE_ROAMING: + info = LocaleController.getString("AutomaticDownloadSettingsInfoRoaming", R.string.AutomaticDownloadSettingsInfoRoaming); + break; + default: + case TYPE_WIFI: + info = LocaleController.getString("AutomaticDownloadSettingsInfoWiFi", R.string.AutomaticDownloadSettingsInfoWiFi); + break; + } + itemInners.add(ItemInner.asSeparator(info)); + } + + if (!sections.isEmpty()) { + itemInners.add(new ItemInner(VIEW_TYPE_RESET_BUTTON, LocaleController.getString("ResetStatistics", R.string.ResetStatistics))); + } + itemInners.add(ItemInner.asSeparator()); + + if (adapter != null) { + if (animated) { + adapter.setItems(oldItems, itemInners); + } else { + adapter.notifyDataSetChanged(); + } + } + } + + private CharSequence bold(CharSequence text) { + SpannableString string = new SpannableString(text); + string.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return string; + } + + private class Adapter extends AdapterWithDiffUtils { + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case VIEW_TYPE_CHART: + chart = new CacheChart(getContext(), colors.length, colors, CacheChart.TYPE_NETWORK, particles) { + + @Override + protected int heightDp() { + return 216; + } + + @Override + protected int padInsideDp() { + return 10; + } + + @Override + protected void onSectionDown(int index, boolean down) { + if (!down) { + ListView.this.removeHighlightRow(); + return; + } + if (index < 0 || index >= segments.length) { + return; + } + int pos = -1; + for (int i = 0; i < segments.length; ++i) { + if (segments[i].index == index) { + pos = i; + break; + } + } + int position = -1; + for (int i = 0; i < itemInners.size(); ++i) { + ItemInner item2 = itemInners.get(i); + if (item2 != null && item2.viewType == VIEW_TYPE_SECTION && item2.index == pos) { + position = i; + break; + } + } + + if (position >= 0) { + final int finalPosition = position; + ListView.this.highlightRow(() -> finalPosition, 0); + } else { + ListView.this.removeHighlightRow(); + } + } + }; + chart.setInterceptTouch(false); + view = chart; + break; + case VIEW_TYPE_SUBTITLE: + view = new SubtitleCell(getContext()); + break; + case VIEW_TYPE_SEPARATOR: + view = new TextInfoPrivacyCell(getContext()); + break; + case VIEW_TYPE_HEADER: + view = new HeaderCell(getContext()); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_RESET_BUTTON: + TextCell textCell = new TextCell(getContext()); + textCell.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteRedText5)); + textCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = textCell; + break; + case VIEW_TYPE_END: + view = new View(getContext()) { + { setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(4), MeasureSpec.EXACTLY)); + } + }; + break; + case VIEW_TYPE_ROUNDING: + view = new RoundingCell(getContext()); + break; + case VIEW_TYPE_SECTION: + default: + view = new Cell(getContext()); + break; + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + ItemInner item = itemInners.get(holder.getAdapterPosition()); + int viewType = holder.getItemViewType(); + if (viewType == VIEW_TYPE_CHART) { + CacheChart chart = (CacheChart) holder.itemView; + if (segments != null) { + chart.setSegments(totalSize, animateChart, chartSegments); + } + animateChart = false; + } else if (viewType == VIEW_TYPE_SUBTITLE) { + SubtitleCell subtitleCell = (SubtitleCell) holder.itemView; + subtitleCell.setText(item.text); + int bottomViewType; + boolean bottom = position + 1 < itemInners.size() && (bottomViewType = itemInners.get(position + 1).viewType) != item.viewType && bottomViewType != VIEW_TYPE_SEPARATOR && bottomViewType != VIEW_TYPE_ROUNDING; + if (bottom) { + subtitleCell.setBackground(Theme.getThemedDrawable(getContext(), R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); + } else { + subtitleCell.setBackground(null); + } + } else if (viewType == VIEW_TYPE_SECTION) { + Cell cell = (Cell) holder.itemView; + cell.set(item.imageColor, item.imageResId, item.text, item.valueText, position + 1 < getItemCount() && itemInners.get(position + 1).viewType == viewType); + cell.setArrow(item.pad || item.index < 0 || item.index < segments.length && segments[item.index].size <= 0 ? null : collapsed[item.index]); + } else if (viewType == VIEW_TYPE_SEPARATOR) { + TextInfoPrivacyCell view = (TextInfoPrivacyCell) holder.itemView; + boolean top = position > 0 && item.viewType != itemInners.get(position - 1).viewType; + boolean bottom = position + 1 < itemInners.size() && itemInners.get(position + 1).viewType != item.viewType; + if (top && bottom) { + view.setBackground(Theme.getThemedDrawable(getContext(), R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + } else if (top) { + view.setBackground(Theme.getThemedDrawable(getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } else if (bottom) { + view.setBackground(Theme.getThemedDrawable(getContext(), R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); + } else { + view.setBackground(null); + } + view.setText(item.text); + } else if (viewType == VIEW_TYPE_HEADER) { + HeaderCell header = (HeaderCell) holder.itemView; + header.setText(item.text); + } else if (viewType == VIEW_TYPE_RESET_BUTTON) { + TextCell textCell = (TextCell) holder.itemView; + textCell.setText(item.text.toString(), false); + } else if (viewType == VIEW_TYPE_ROUNDING) { + ((RoundingCell) holder.itemView).setTop(true); + } + } + + @Override + public int getItemCount() { + return itemInners.size(); + } + + @Override + public int getItemViewType(int position) { + return itemInners.get(position).viewType; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + ItemInner item = itemInners.get(holder.getAdapterPosition()); + return item.viewType == VIEW_TYPE_RESET_BUTTON || item.viewType == VIEW_TYPE_SECTION && item.index != -1; + } + } + + private int getSentItemsCount(int dataType) { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getSentItemsCount(currentType - 1, dataType); + case TYPE_ALL: + default: + return ( + StatsController.getInstance(currentAccount).getSentItemsCount(0, dataType) + + StatsController.getInstance(currentAccount).getSentItemsCount(1, dataType) + + StatsController.getInstance(currentAccount).getSentItemsCount(2, dataType) + ); + } + } + + private int getReceivedItemsCount(int dataType) { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getRecivedItemsCount(currentType - 1, dataType); + case TYPE_ALL: + default: + return ( + StatsController.getInstance(currentAccount).getRecivedItemsCount(0, dataType) + + StatsController.getInstance(currentAccount).getRecivedItemsCount(1, dataType) + + StatsController.getInstance(currentAccount).getRecivedItemsCount(2, dataType) + ); + } + } + + private long getBytesCount(int dataType) { + return getSentBytesCount(dataType) + getReceivedBytesCount(dataType); + } + + private long getSentBytesCount(int dataType) { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getSentBytesCount(currentType - 1, dataType); + case TYPE_ALL: + default: + return ( + StatsController.getInstance(currentAccount).getSentBytesCount(0, dataType) + + StatsController.getInstance(currentAccount).getSentBytesCount(1, dataType) + + StatsController.getInstance(currentAccount).getSentBytesCount(2, dataType) + ); + } + } + + private long getReceivedBytesCount(int dataType) { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getReceivedBytesCount(currentType - 1, dataType); + case TYPE_ALL: + default: + return ( + StatsController.getInstance(currentAccount).getReceivedBytesCount(0, dataType) + + StatsController.getInstance(currentAccount).getReceivedBytesCount(1, dataType) + + StatsController.getInstance(currentAccount).getReceivedBytesCount(2, dataType) + ); + } + } + + private long getResetStatsDate() { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getResetStatsDate(currentType - 1); + case TYPE_ALL: + default: + return min( + StatsController.getInstance(currentAccount).getResetStatsDate(0), + StatsController.getInstance(currentAccount).getResetStatsDate(1), + StatsController.getInstance(currentAccount).getResetStatsDate(2) + ); + } + } + + private long min(long... numbers) { + long min = Long.MAX_VALUE; + for (int i = 0; i < numbers.length; ++i) { + if (min > numbers[i]) + min = numbers[i]; + } + return min; + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + super.onMeasure(widthSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightSpec), MeasureSpec.EXACTLY)); + } + } + + private static final int VIEW_TYPE_CHART = 0; + private static final int VIEW_TYPE_SUBTITLE = 1; + private static final int VIEW_TYPE_SECTION = 2; + private static final int VIEW_TYPE_SEPARATOR = 3; + private static final int VIEW_TYPE_HEADER = 4; + private static final int VIEW_TYPE_RESET_BUTTON = 5; + private static final int VIEW_TYPE_ROUNDING = 6; + private static final int VIEW_TYPE_END = 7; + + private static class ItemInner extends AdapterWithDiffUtils.Item { + + public int imageResId; + public int imageColor; + public CharSequence text; + public CharSequence valueText; + + public int index; + public boolean pad; + + public int key; + + public ItemInner(int viewType) { + super(viewType, false); + } + + public ItemInner(int viewType, int key) { + super(viewType, false); + this.key = key; + } + + private ItemInner(int viewType, CharSequence text) { + super(viewType, false); + this.text = text; + } + + private ItemInner(int viewType, CharSequence text, CharSequence valueText) { + super(viewType, false); + this.text = text; + this.valueText = valueText; + } + + private ItemInner(int viewType, int index, CharSequence text, CharSequence valueText) { + super(viewType, false); + this.index = index; + this.text = text; + this.valueText = valueText; + } + + private ItemInner(int viewType, int index, int imageResId, int imageColor, CharSequence text, CharSequence valueText) { + super(viewType, false); + this.index = index; + this.imageResId = imageResId; + this.imageColor = imageColor; + this.text = text; + this.valueText = valueText; + } + + public static ItemInner asSeparator() { + return new ItemInner(VIEW_TYPE_SEPARATOR); + } + + public static ItemInner asSeparator(String hint) { + return new ItemInner(VIEW_TYPE_SEPARATOR, hint); + } + + public static ItemInner asHeader(String text) { + return new ItemInner(VIEW_TYPE_HEADER, text); + } + + public static ItemInner asSubtitle(String text) { + return new ItemInner(VIEW_TYPE_SUBTITLE, text); + } + + public static ItemInner asCell(int index, int imageResId, int imageColor, CharSequence text, CharSequence valueText) { + return new ItemInner(VIEW_TYPE_SECTION, index, imageResId, imageColor, text, valueText); + } + + public static ItemInner asCell(String text, CharSequence valueText) { + return new ItemInner(VIEW_TYPE_SECTION, text, valueText); + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof ItemInner)) { + return false; + } + ItemInner item = (ItemInner) object; + if (item.viewType != viewType) { + return false; + } + if (viewType == VIEW_TYPE_SUBTITLE || viewType == VIEW_TYPE_HEADER || viewType == VIEW_TYPE_SEPARATOR || viewType == VIEW_TYPE_RESET_BUTTON) { + return TextUtils.equals(text, item.text); + } + if (viewType == VIEW_TYPE_SECTION) { + return item.index == index && TextUtils.equals(text, item.text) && item.imageColor == imageColor && item.imageResId == imageResId; + } + return item.key == key; + } + } + + class SubtitleCell extends FrameLayout { + + TextView textView; + + public SubtitleCell(Context context) { + super(context); + + textView = new TextView(context); + textView.setGravity(Gravity.CENTER); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText)); + + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL, 24, 0, 24, 14)); + } + + public void setText(CharSequence text) { + textView.setText(text); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), heightMeasureSpec); + } + } + + public static class RoundingCell extends View { + Path path = new Path(); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public RoundingCell(Context context) { + super(context); + paint.setShadowLayer(dp(1), 0, dp(-0.66f), 0x0f000000); + paint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } + + private boolean top = true; + + public void setTop(boolean top) { + path.rewind(); + float r; + if (this.top = top) { + r = AndroidUtilities.dp(14); + AndroidUtilities.rectTmp.set(0, AndroidUtilities.dp(4), getMeasuredWidth(), AndroidUtilities.dp(4) + getMeasuredHeight() * 2); + path.addRoundRect(AndroidUtilities.rectTmp, r, r, Path.Direction.CW); + } else { + r = AndroidUtilities.dp(8); + AndroidUtilities.rectTmp.set(0, -getMeasuredHeight() * 2 - AndroidUtilities.dp(4), getMeasuredWidth(), getMeasuredHeight() - AndroidUtilities.dp(4)); + path.addRoundRect(AndroidUtilities.rectTmp, r, r, Path.Direction.CW); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawPath(path, paint); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(13), MeasureSpec.EXACTLY)); + setTop(this.top); + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + requestLayout(); + } + } + + class Cell extends FrameLayout { + + ImageView imageView; + LinearLayout linearLayout, linearLayout2; + TextView textView; + ImageView arrowView; + TextView valueTextView; + boolean divider; + + public Cell(Context context) { + super(context); + + setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); +// imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); + addView(imageView, LayoutHelper.createFrame(28, 28, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 18, 0, 18, 0)); + + linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(2); + addView(linearLayout, LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 64, 0, 20, 0)); + + linearLayout2 = new LinearLayout(context); + linearLayout2.setOrientation(LinearLayout.HORIZONTAL); + if (LocaleController.isRTL) { + linearLayout2.setGravity(Gravity.RIGHT); + } + linearLayout2.setWeightSum(2); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setSingleLine(); + textView.setLines(1); + + arrowView = new ImageView(context); + arrowView.setScaleType(ImageView.ScaleType.FIT_CENTER); + arrowView.setImageResource(R.drawable.arrow_more); + arrowView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), PorterDuff.Mode.MULTIPLY)); + arrowView.setTranslationY(AndroidUtilities.dp(1)); + arrowView.setVisibility(View.GONE); + + if (LocaleController.isRTL) { + linearLayout2.addView(arrowView, LayoutHelper.createLinear(16, 16, Gravity.CENTER_VERTICAL | Gravity.RIGHT, 3, 0, 0, 0)); + linearLayout2.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.RIGHT)); + } else { + linearLayout2.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + linearLayout2.addView(arrowView, LayoutHelper.createLinear(16, 16, Gravity.CENTER_VERTICAL, 3, 0, 0, 0)); + } + + valueTextView = new TextView(context); + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + valueTextView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueText2)); + valueTextView.setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + + if (LocaleController.isRTL) { + linearLayout.addView(valueTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.LEFT)); + linearLayout.addView(linearLayout2, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 2, Gravity.CENTER_VERTICAL | Gravity.RIGHT)); + } else { + linearLayout.addView(linearLayout2, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 2, Gravity.CENTER_VERTICAL)); + linearLayout.addView(valueTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.RIGHT)); + } + } + + public void set( + int imageColor, + int imageResId, + CharSequence title, + CharSequence value, + boolean divider + ) { + if (imageResId == 0) { + imageView.setVisibility(View.GONE); + } else { + imageView.setVisibility(View.VISIBLE); + imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(9), imageColor)); + imageView.setImageResource(imageResId); + } + + textView.setText(title); + valueTextView.setText(value); + + setWillNotDraw(!(this.divider = divider)); + } + + public void setArrow(Boolean value) { + if (value == null) { + arrowView.setVisibility(View.GONE); + } else { + arrowView.setVisibility(View.VISIBLE); + arrowView.animate().rotation(value ? 0 : 180).setDuration(360).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (divider) { + canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(64), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(64) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY) + ); + } + } + + public class CustomCharacterSpan extends MetricAffectingSpan { + double ratio = 0.5; + + public CustomCharacterSpan() { + } + + public CustomCharacterSpan(double ratio) { + this.ratio = ratio; + } + + @Override + public void updateDrawState(TextPaint paint) { + paint.baselineShift += (int) (paint.ascent() * ratio); + } + + @Override + public void updateMeasureState(TextPaint paint) { + paint.baselineShift += (int) (paint.ascent() * ratio); + } + } + + private boolean changeStatusBar; + + @Override + public void onTransitionAnimationProgress(boolean isOpen, float progress) { + if (progress > .5f && !changeStatusBar) { + changeStatusBar = true; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + super.onTransitionAnimationProgress(isOpen, progress); + } + + @Override + public boolean isLightStatusBar() { + if (!changeStatusBar) { + return super.isLightStatusBar(); + } + return AndroidUtilities.computePerceivedBrightness(Theme.getColor(Theme.key_actionBarActionModeDefault)) > 0.721f; + } + + @Override + public boolean isSwipeBackEnabled(MotionEvent event) { + if (event.getY() <= ActionBar.getCurrentActionBarHeight() + AndroidUtilities.dp(48)) { + return true; + } + return pager.getCurrentPosition() == 0; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DataUsageActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DataUsageActivity.java index a80f046c8..92752bf25 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DataUsageActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DataUsageActivity.java @@ -27,6 +27,9 @@ import android.view.animation.Interpolator; import android.widget.FrameLayout; import android.widget.TextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; @@ -46,9 +49,6 @@ import org.telegram.ui.Components.ScrollSlidingTextTabStrip; import java.util.ArrayList; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - public class DataUsageActivity extends BaseFragment { private class ViewPage extends FrameLayout { @@ -806,7 +806,7 @@ public class DataUsageActivity extends BaseFragment { } case 3: { TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; - cell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + cell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); cell.setText(LocaleController.formatString("NetworkUsageSince", R.string.NetworkUsageSince, LocaleController.getInstance().formatterStats.format(StatsController.getInstance(currentAccount).getResetStatsDate(currentType)))); break; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java index 11301655a..4fdd14c0c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java @@ -87,18 +87,19 @@ public class DialogOrContactPickerActivity extends BaseFragment { args.putBoolean("onlySelect", true); args.putBoolean("checkCanWrite", false); args.putBoolean("resetDelegate", false); - args.putInt("dialogsType", 9); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_BLOCK); dialogsActivity = new DialogsActivity(args); dialogsActivity.setDelegate((fragment, dids, message, param) -> { if (dids.isEmpty()) { - return; + return true; } long did = dids.get(0).dialogId; if (!DialogObject.isUserDialog(did)) { - return; + return true; } TLRPC.User user = getMessagesController().getUser(did); showBlockAlert(user); + return true; }); dialogsActivity.onFragmentCreate(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 822d1c4ee..253b85884 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -110,6 +110,7 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.XiaomiUtilities; import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -134,6 +135,7 @@ import org.telegram.ui.Cells.AccountSelectCell; import org.telegram.ui.Cells.ArchiveHintInnerCell; import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.DialogsEmptyCell; +import org.telegram.ui.Cells.DialogsHintCell; import org.telegram.ui.Cells.DividerCell; import org.telegram.ui.Cells.DrawerActionCell; import org.telegram.ui.Cells.DrawerAddCell; @@ -145,6 +147,7 @@ import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.HintDialogCell; import org.telegram.ui.Cells.LoadingCell; import org.telegram.ui.Cells.ProfileSearchCell; +import org.telegram.ui.Cells.RequestPeerRequirementsCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; @@ -199,9 +202,10 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; public class DialogsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, FloatingDebugProvider { - public final static int DIALOGS_TYPE_START_ATTACH_BOT = 14; + public final static boolean DISPLAY_SPEEDOMETER_IN_DOWNLOADS_SEARCH = true; private boolean canShowFilterTabsView; @@ -213,6 +217,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private boolean rightFragmentTransitionInProgress; private boolean allowGlobalSearch = true; + private TLRPC.RequestPeerType requestPeerType; + private long requestPeerBotId; + public MessagesStorage.TopicKey getOpenedDialogId() { return openedDialogId; } @@ -242,12 +249,12 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } public boolean isDefaultDialogType() { - return dialogsType == 0 || dialogsType == 7 || dialogsType == 8; + return dialogsType == DIALOGS_TYPE_DEFAULT || dialogsType == 7 || dialogsType == 8; } boolean updating; Runnable updateListRunnable = () -> { - dialogsAdapter.updateList(listView, dialogsType == 0 && hasHiddenArchive() && archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN, actionBar.getTranslationY()); + dialogsAdapter.updateList(listView, dialogsType == DIALOGS_TYPE_DEFAULT && hasHiddenArchive() && archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN, actionBar.getTranslationY()); listView.updateDialogsOnNextDraw = true; updating = false; }; @@ -378,6 +385,8 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private FragmentContextView fragmentLocationContextView; private FragmentContextView fragmentContextView; + private DialogsHintCell dialogsHintCell; + private Long cacheSize, deviceSize; private ArrayList frozenDialogsList; private boolean dialogsListFrozen; @@ -506,6 +515,8 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private int debugLastUpdateAction = -1; private boolean slowedReloadAfterDialogClick; + private boolean isPremiumHintUpgrade; + private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable statusDrawable; private DrawerProfileCell.AnimatedStatusView animatedStatusView; public RightSlidingDialogContainer rightSlidingDialogContainer; @@ -629,7 +640,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. return true; } boolean result; - if (child == viewPages[0] || (viewPages.length > 1 && child == viewPages[1]) || child == fragmentContextView || child == fragmentLocationContextView) { + if (child == viewPages[0] || (viewPages.length > 1 && child == viewPages[1]) || child == fragmentContextView || child == fragmentLocationContextView || child == dialogsHintCell) { canvas.save(); canvas.clipRect(0, -getY() + actionBar.getY() + getActionBarFullHeight(), getMeasuredWidth(), getMeasuredHeight()); if (slideFragmentProgress != 1f) { @@ -876,12 +887,12 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. int contentWidthSpec = View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY); int h; if (filterTabsView != null && filterTabsView.getVisibility() == VISIBLE) { - h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - AndroidUtilities.dp(44) - topPadding; + h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - AndroidUtilities.dp(44) - topPadding - (dialogsHintCell != null ? dialogsHintCell.height() : 0); if (rightSlidingDialogContainer.hasFragment()) { h += AndroidUtilities.dp(44); } } else { - h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - (onlySelect ? 0 : actionBar.getMeasuredHeight()) - topPadding; + h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - (onlySelect ? 0 : actionBar.getMeasuredHeight()) - topPadding - (dialogsHintCell != null ? dialogsHintCell.height() : 0); } if (filtersTabAnimator != null && filterTabsView != null && filterTabsView.getVisibility() == VISIBLE) { h += filterTabsMoveFrom; @@ -1017,6 +1028,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } childTop += topPadding; + if (dialogsHintCell != null) { + childTop += dialogsHintCell.height(); + } + } else if (child instanceof DialogsHintCell) { + childTop += actionBar.getMeasuredHeight() + (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE ? filterTabsView.getMeasuredHeight() : 0); } else if (child instanceof FragmentContextView) { childTop += actionBar.getMeasuredHeight(); } else if (child == floatingButtonContainer && selectAnimatedEmojiDialog != null) { @@ -1642,7 +1658,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. RecyclerView.ViewHolder holder = parentPage.listView.findViewHolderForAdapterPosition(pos); if (holder != null) { int top = holder.itemView.getTop(); - if (parentPage.dialogsType == 0 && hasHiddenArchive() && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN) { + if (parentPage.dialogsType == DIALOGS_TYPE_DEFAULT && hasHiddenArchive() && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN) { pos = Math.max(1, pos); } ignoreLayout = true; @@ -1664,7 +1680,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } if (firstLayout && getMessagesController().dialogsLoaded) { - if (parentPage.dialogsType == 0 && hasHiddenArchive()) { + if (parentPage.dialogsType == DIALOGS_TYPE_DEFAULT && hasHiddenArchive()) { ignoreLayout = true; LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager(); layoutManager.scrollToPositionWithOffset(1, 0); @@ -1788,7 +1804,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } boolean result = super.onTouchEvent(e); - if (parentPage.dialogsType == 0 && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive()) { + if (parentPage.dialogsType == DIALOGS_TYPE_DEFAULT && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive()) { LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager(); int currentPosition = layoutManager.findFirstVisibleItemPosition(); if (currentPosition == 0) { @@ -1901,7 +1917,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. int p = adapter.findDialogPosition(anchorView.getDialogId()); int offset = (int) (anchorView.getTop() - anchorListView.getPaddingTop() + scrollOffset); if (p >= 0) { - ((LinearLayoutManager) animationSupportListView.getLayoutManager()).scrollToPositionWithOffset(p, adapter.fixScrollGap(this, p, offset, parentPage.dialogsType == 0 && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive(), opened)); + ((LinearLayoutManager) animationSupportListView.getLayoutManager()).scrollToPositionWithOffset(p, adapter.fixScrollGap(this, p, offset, parentPage.dialogsType == DIALOGS_TYPE_DEFAULT && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive(), opened)); } } } @@ -2185,7 +2201,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } public interface DialogsActivityDelegate { - void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param); + boolean didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param); } public DialogsActivity(Bundle args) { @@ -2196,11 +2212,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. public boolean onFragmentCreate() { super.onFragmentCreate(); - if (getArguments() != null) { + if (arguments != null) { onlySelect = arguments.getBoolean("onlySelect", false); - canSelectTopics = arguments.getBoolean("canSelectTopics", false); + canSelectTopics = arguments.getBoolean("canSelectTopics", false); cantSendToChannels = arguments.getBoolean("cantSendToChannels", false); - initialDialogsType = arguments.getInt("dialogsType", 0); + initialDialogsType = arguments.getInt("dialogsType", DIALOGS_TYPE_DEFAULT); selectAlertString = arguments.getString("selectAlertString"); selectAlertStringGroup = arguments.getString("selectAlertStringGroup"); addToGroupAlertString = arguments.getString("addToGroupAlertString"); @@ -2220,9 +2236,19 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. allowBots = arguments.getBoolean("allowBots", true); closeFragment = arguments.getBoolean("closeFragment", true); allowGlobalSearch = arguments.getBoolean("allowGlobalSearch", true); + + byte[] requestPeerTypeBytes = arguments.getByteArray("requestPeerType"); + if (requestPeerTypeBytes != null) { + try { + SerializedData buffer = new SerializedData(requestPeerTypeBytes); + requestPeerType = TLRPC.RequestPeerType.TLdeserialize(buffer, buffer.readInt32(true), true); + buffer.cleanup(); + } catch (Exception e) {} + } + requestPeerBotId = arguments.getLong("requestPeerBotId", 0); } - if (initialDialogsType == 0) { + if (initialDialogsType == DIALOGS_TYPE_DEFAULT) { askAboutContacts = MessagesController.getGlobalNotificationsSettings().getBoolean("askAboutContacts", true); SharedConfig.loadProxyList(); } @@ -2308,12 +2334,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (statusDrawable == null || actionBar == null) { return; } - if (user != null && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - statusDrawable.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, animated); - actionBar.setRightDrawableOnClick(e -> showSelectStatusDialog()); - SelectAnimatedEmojiDialog.preload(currentAccount); - } else if (user != null && user.emoji_status instanceof TLRPC.TL_emojiStatus) { - statusDrawable.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, animated); + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { + statusDrawable.set(emojiStatusId, animated); actionBar.setRightDrawableOnClick(e -> showSelectStatusDialog()); SelectAnimatedEmojiDialog.preload(currentAccount); } else if (user != null && MessagesController.getInstance(currentAccount).isPremiumUser(user)) { @@ -2632,17 +2655,31 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } }); - if (initialDialogsType == 2 || initialDialogsType == DIALOGS_TYPE_START_ATTACH_BOT) { + if (initialDialogsType == DIALOGS_TYPE_ADD_USERS_TO || initialDialogsType == DIALOGS_TYPE_START_ATTACH_BOT) { searchItem.setVisibility(View.GONE); } searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); searchItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); if (onlySelect) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); - if (initialDialogsType == 3 && selectAlertString == null) { + if (initialDialogsType == DIALOGS_TYPE_FORWARD && selectAlertString == null) { actionBar.setTitle(LocaleController.getString("ForwardTo", R.string.ForwardTo)); - } else if (initialDialogsType == 10) { + } else if (initialDialogsType == DIALOGS_TYPE_WIDGET) { actionBar.setTitle(LocaleController.getString("SelectChats", R.string.SelectChats)); + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeUser) { + if (((TLRPC.TL_requestPeerTypeUser) requestPeerType).bot != null) { + if (((TLRPC.TL_requestPeerTypeUser) requestPeerType).bot) { + actionBar.setTitle(LocaleController.getString("ChooseBot", R.string.ChooseBot)); + } else { + actionBar.setTitle(LocaleController.getString("ChooseUser", R.string.ChooseUser)); + } + } else { + actionBar.setTitle(LocaleController.getString("ChooseUser", R.string.ChooseUser)); + } + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + actionBar.setTitle(LocaleController.getString("ChooseChannel", R.string.ChooseChannel)); + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeChat) { + actionBar.setTitle(LocaleController.getString("ChooseGroup", R.string.ChooseGroup)); } else { actionBar.setTitle(LocaleController.getString("SelectChat", R.string.SelectChat)); } @@ -2683,7 +2720,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. scrollToTop(); }); - if (initialDialogsType == 0 && folderId == 0 && !onlySelect && TextUtils.isEmpty(searchString)) { + if (initialDialogsType == DIALOGS_TYPE_DEFAULT && folderId == 0 && !onlySelect && TextUtils.isEmpty(searchString)) { scrimPaint = new Paint() { @Override public void setAlpha(int a) { @@ -3083,7 +3120,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ContentView contentView = new ContentView(context); fragmentView = contentView; - int pagesCount = folderId == 0 && initialDialogsType == 0 && !onlySelect ? 2 : 1; + int pagesCount = folderId == 0 && initialDialogsType == DIALOGS_TYPE_DEFAULT && !onlySelect ? 2 : 1; viewPages = new ViewPage[pagesCount]; for (int a = 0; a < pagesCount; a++) { final ViewPage viewPage = new ViewPage(context) { @@ -3116,6 +3153,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. viewPage.listView.setAnimateEmptyView(true, RecyclerListView.EMPTY_VIEW_ANIMATION_TYPE_ALPHA); viewPage.listView.setClipToPadding(false); viewPage.listView.setPivotY(0); + if (initialDialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER) { + viewPage.listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + } viewPage.dialogsItemAnimator = new DialogsItemAnimator(viewPage.listView) { @Override public void onRemoveStarting(RecyclerView.ViewHolder item) { @@ -3175,7 +3215,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. int measuredDy = dy; int pTop = viewPage.listView.getPaddingTop(); - if (viewPage.dialogsType == 0 && !onlySelect && folderId == 0 && dy < 0 && getMessagesController().hasHiddenArchive() && viewPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN) { + if (viewPage.dialogsType == DIALOGS_TYPE_DEFAULT && !onlySelect && folderId == 0 && dy < 0 && getMessagesController().hasHiddenArchive() && viewPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN) { viewPage.listView.setOverScrollMode(View.OVER_SCROLL_ALWAYS); int currentPosition = viewPage.layoutManager.findFirstVisibleItemPosition(); if (currentPosition == 0) { @@ -3223,7 +3263,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. viewPage.listView.setViewsOffset(ty); } - if (viewPage.dialogsType == 0 && viewPage.archivePullViewState != ARCHIVE_ITEM_STATE_PINNED && hasHiddenArchive()) { + if (viewPage.dialogsType == DIALOGS_TYPE_DEFAULT && viewPage.archivePullViewState != ARCHIVE_ITEM_STATE_PINNED && hasHiddenArchive()) { int usedDy = super.scrollVerticallyBy(measuredDy, recycler, state); if (viewPage.pullForegroundDrawable != null) { viewPage.pullForegroundDrawable.scrollDy = usedDy; @@ -3309,10 +3349,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. viewPage.listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); viewPage.addView(viewPage.listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); viewPage.listView.setOnItemClickListener((view, position) -> { - if (initialDialogsType == 10) { + if (initialDialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER && view instanceof TextCell) { + viewPage.dialogsAdapter.onCreateGroupForThisClick(); + return; + } else if (initialDialogsType == DIALOGS_TYPE_WIDGET) { onItemLongClick(viewPage.listView, view, position, 0, 0, viewPage.dialogsType, viewPage.dialogsAdapter); return; - } else if ((initialDialogsType == 11 || initialDialogsType == 13) && position == 1) { + } else if ((initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY) && position == 1) { Bundle args = new Bundle(); args.putBoolean("forImport", true); long[] array = new long[]{getUserConfig().getClientUserId()}; @@ -3410,7 +3453,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. int actionBarHeight = ActionBar.getCurrentActionBarHeight(); if (scrollY != 0 && scrollY != actionBarHeight) { if (scrollY < actionBarHeight / 2) { - recyclerView.smoothScrollBy(0, -scrollY); + if (viewPages[0].listView.canScrollVertically(-1)) { + recyclerView.smoothScrollBy(0, -scrollY); + } } else if (viewPages[0].listView.canScrollVertically(1)) { recyclerView.smoothScrollBy(0, actionBarHeight - scrollY); } @@ -3451,7 +3496,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } if (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE && recyclerView == viewPages[0].listView && !searching && !actionBar.isActionModeShowed() && !disableActionBarScrolling && filterTabsViewIsVisible && !rightSlidingDialogContainer.hasFragment()) { - if (dy > 0 && hasHiddenArchive() && viewPages[0].dialogsType == 0) { + if (dy > 0 && hasHiddenArchive() && viewPages[0].dialogsType == DIALOGS_TYPE_DEFAULT) { View child = recyclerView.getChildAt(0); if (child != null) { RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(child); @@ -3504,7 +3549,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. viewPage.pullForegroundDrawable.setWillDraw(viewPage.archivePullViewState != ARCHIVE_ITEM_STATE_PINNED); } - viewPage.dialogsAdapter = new DialogsAdapter(this, context, viewPage.dialogsType, folderId, onlySelect, selectedDialogs, currentAccount) { + viewPage.dialogsAdapter = new DialogsAdapter(this, context, viewPage.dialogsType, folderId, onlySelect, selectedDialogs, currentAccount, requestPeerType) { @Override public void notifyDataSetChanged() { viewPage.lastItemsCount = getItemCount(); @@ -3513,6 +3558,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } catch (Exception e) { FileLog.e(e); } + if (initialDialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER) { + searchItem.setVisibility(isEmpty ? View.GONE : View.VISIBLE); + } } @Override @@ -3533,6 +3581,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. public void onButtonLongPress(DialogCell dialogCell) { onItemLongClick(viewPage.listView, dialogCell, viewPage.listView.getChildAdapterPosition(dialogCell), 0, 0, viewPage.dialogsType, viewPage.dialogsAdapter); } + + @Override + public void onCreateGroupForThisClick() { + createGroupForThis(); + } }; viewPage.dialogsAdapter.setRecyclerListView(viewPage.listView); viewPage.dialogsAdapter.setForceShowEmptyCell(afterSignup); @@ -3743,7 +3796,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. }); searchViewPager.searchListView.setOnItemClickListener((view, position) -> { - if (initialDialogsType == 10) { + if (initialDialogsType == DIALOGS_TYPE_WIDGET) { onItemLongClick(searchViewPager.searchListView, view, position, 0, 0, -1, searchViewPager.dialogsSearchAdapter); return; } @@ -3789,7 +3842,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. finishPreviewFragment(); return; } - if (initialDialogsType == 10) { + if (initialDialogsType == DIALOGS_TYPE_WIDGET) { if (delegate == null || selectedDialogs.isEmpty()) { return; } @@ -3812,7 +3865,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. floatingButton = new RLottieImageView(context); floatingButton.setScaleType(ImageView.ScaleType.CENTER); floatingButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_actionIcon), PorterDuff.Mode.MULTIPLY)); - if (initialDialogsType == 10) { + if (initialDialogsType == DIALOGS_TYPE_WIDGET) { floatingButton.setImageResource(R.drawable.floating_check); floatingButtonContainer.setContentDescription(LocaleController.getString("Done", R.string.Done)); } else { @@ -3872,7 +3925,19 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. fragmentContextView.setAdditionalContextView(fragmentLocationContextView); fragmentLocationContextView.setAdditionalContextView(fragmentContextView); - } else if (initialDialogsType == 3) { + + dialogsHintCell = new DialogsHintCell(context); + updateDialogsHint(); + CacheControlActivity.calculateTotalSize(size -> { + cacheSize = size; + updateDialogsHint(); + }); + CacheControlActivity.getDeviceTotalSize((totalSize, totalFreeSize) -> { + deviceSize = totalSize; + updateDialogsHint(); + }); + contentView.addView(dialogsHintCell); + } else if (initialDialogsType == DIALOGS_TYPE_FORWARD) { if (commentView != null) { commentView.onDestroy(); } @@ -4154,7 +4219,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. contentView.addView(animatedStatusView, LayoutHelper.createFrame(20, 20, Gravity.LEFT | Gravity.TOP)); } - if (searchString == null && initialDialogsType == 0) { + if (searchString == null && initialDialogsType == DIALOGS_TYPE_DEFAULT) { updateLayout = new FrameLayout(context) { private Paint paint = new Paint(); @@ -4301,7 +4366,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. actionBar.setSearchTextColor(Theme.getColor(Theme.key_actionBarDefaultArchivedSearchPlaceholder), true); } - if (!onlySelect && initialDialogsType == 0) { + if (!onlySelect && initialDialogsType == DIALOGS_TYPE_DEFAULT) { blurredView = new View(context) { @Override public void setAlpha(float alpha) { @@ -4421,7 +4486,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. LinearLayoutManager layoutManager = new LinearLayoutManager(context); layoutManager.setNeedFixEndGap(false); transitionPage.animationSupportListView.setLayoutManager(layoutManager); - transitionPage.animationSupportDialogsAdapter = new DialogsAdapter(DialogsActivity.this, context, transitionPage.dialogsType, folderId, onlySelect, selectedDialogs, currentAccount); + transitionPage.animationSupportDialogsAdapter = new DialogsAdapter(DialogsActivity.this, context, transitionPage.dialogsType, folderId, onlySelect, selectedDialogs, currentAccount, requestPeerType); transitionPage.animationSupportDialogsAdapter.setIsTransitionSupport(); transitionPage.animationSupportListView.setAdapter(transitionPage.animationSupportDialogsAdapter); transitionPage.addView(transitionPage.animationSupportListView); @@ -4461,7 +4526,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. rightFragmentTransitionInProgress = false; actionBar.setAllowOverlayTitle(!hasFragment()); contentView.requestLayout(); - transitionPage.layoutManager.setNeedFixEndGap(!hasFragment()); + // transitionPage.layoutManager.setNeedFixEndGap(!hasFragment()); DialogsActivity.this.setScrollY(0); searchViewPager.updateTabs(); updateDrawerSwipeEnabled(); @@ -4526,6 +4591,46 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. return fragmentView; } + public boolean isPremiumHintVisible() { + if (!MessagesController.getInstance(currentAccount).premiumLocked && folderId == 0) { + if (MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_UPGRADE") && getUserConfig().isPremium() || MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_ANNUAL") && !getUserConfig().isPremium()) { + if (UserConfig.getInstance(currentAccount).isPremium() ? !BuildVars.useInvoiceBilling() && MediaDataController.getInstance(currentAccount).getPremiumHintAnnualDiscount(true) != null : MediaDataController.getInstance(currentAccount).getPremiumHintAnnualDiscount(false) != null) { + isPremiumHintUpgrade = MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_UPGRADE"); + return true; + } + } + } + return false; + } + + private boolean isCacheHintVisible() { + if (cacheSize == null || deviceSize == null) { + return false; + } + if ((cacheSize / (float) deviceSize) < 0.30F) { + clearCacheHintVisible(); + return false; + } + SharedPreferences prefs = MessagesController.getGlobalMainSettings(); + return System.currentTimeMillis() > prefs.getLong("cache_hint_showafter", 0L); + } + + private void resetCacheHintVisible() { + SharedPreferences prefs = MessagesController.getGlobalMainSettings(); + final long week = 1000L * 60L * 60L * 24L * 7L; + final long month = 1000L * 60L * 60L * 24L * 30L; + long period = prefs.getLong("cache_hint_period", week); + if (period <= week) { + period = month; + } + long showafter = System.currentTimeMillis() + period; + prefs.edit().putLong("cache_hint_showafter", showafter).putLong("cache_hint_period", period).apply(); + } + + private void clearCacheHintVisible() { + MessagesController.getGlobalMainSettings().edit().remove("cache_hint_showafter").remove("cache_hint_period").apply(); + } + // @Override // public ActionBar getActionBar() { // return rightSlidingDialogContainer != null && rightSlidingDialogContainer.currentActionBarView != null && rightSlidingDialogContainer.isOpenned ? rightSlidingDialogContainer.currentActionBarView : super.getActionBar(); @@ -4554,31 +4659,21 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(this, getContext(), true, xoff, SelectAnimatedEmojiDialog.TYPE_EMOJI_STATUS, getResourceProvider()) { @Override protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { - TLRPC.TL_account_updateEmojiStatus req = new TLRPC.TL_account_updateEmojiStatus(); + TLRPC.EmojiStatus emojiStatus; if (documentId == null) { - req.emoji_status = new TLRPC.TL_emojiStatusEmpty(); + emojiStatus = new TLRPC.TL_emojiStatusEmpty(); } else if (until != null) { - req.emoji_status = new TLRPC.TL_emojiStatusUntil(); - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).document_id = documentId; - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).until = until; + emojiStatus = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id = documentId; + ((TLRPC.TL_emojiStatusUntil) emojiStatus).until = until; } else { - req.emoji_status = new TLRPC.TL_emojiStatus(); - ((TLRPC.TL_emojiStatus) req.emoji_status).document_id = documentId; - } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); - if (user != null) { - user.emoji_status = req.emoji_status; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userEmojiStatusUpdated, user); - getMessagesController().updateEmojiStatusUntilUpdate(user.id, user.emoji_status); + emojiStatus = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) emojiStatus).document_id = documentId; } + getMessagesController().updateEmojiStatus(emojiStatus); if (documentId != null) { animatedStatusView.animateChange(ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentId)); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (!(res instanceof TLRPC.TL_boolTrue)) { - // TODO: reject - } - }); if (popup[0] != null) { selectAnimatedEmojiDialog = null; popup[0].dismiss(); @@ -4631,6 +4726,225 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. commentViewPreviousTop = top; } + private void updateDialogsHint() { + if (dialogsHintCell == null) { + return; + } + if (isPremiumHintVisible()) { + dialogsHintCell.setVisibility(View.VISIBLE); + dialogsHintCell.setOnClickListener(v -> { + presentFragment(new PremiumPreviewFragment("dialogs_hint").setSelectAnnualByDefault()); + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).removeSuggestion(0, isPremiumHintUpgrade ? "PREMIUM_UPGRADE" : "PREMIUM_ANNUAL"); + updateDialogsHint(); + }, 250); + }); + dialogsHintCell.setText( + AndroidUtilities.replaceSingleTag( + LocaleController.formatString(isPremiumHintUpgrade ? R.string.SaveOnAnnualPremiumTitle : R.string.UpgradePremiumTitle, MediaDataController.getInstance(currentAccount).getPremiumHintAnnualDiscount(false)), + Theme.key_windowBackgroundWhiteValueText, + 0, + null + ), + LocaleController.getString(isPremiumHintUpgrade ? R.string.UpgradePremiumMessage : R.string.SaveOnAnnualPremiumMessage) + ); + } else if (isCacheHintVisible()) { + dialogsHintCell.setVisibility(View.VISIBLE); + dialogsHintCell.setOnClickListener(v -> { + presentFragment(new CacheControlActivity()); + AndroidUtilities.runOnUIThread(() -> { + resetCacheHintVisible(); + updateDialogsHint(); + }, 250); + }); + dialogsHintCell.setText( + AndroidUtilities.replaceSingleTag( + LocaleController.formatString(R.string.ClearStorageHintTitle, AndroidUtilities.formatFileSize(cacheSize)), + Theme.key_windowBackgroundWhiteValueText, + 0, + null + ), + LocaleController.getString(R.string.ClearStorageHintMessage) + ); + } else { + dialogsHintCell.setVisibility(View.GONE); + } + } + + private void createGroupForThis() { + AlertDialog progress = new AlertDialog(getContext(), AlertDialog.ALERT_TYPE_SPINNER); + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + Bundle args = new Bundle(); + args.putInt("step", 0); + if (requestPeerType.has_username != null) { + args.putBoolean("forcePublic", requestPeerType.has_username); + } + ChannelCreateActivity fragment = new ChannelCreateActivity(args); + fragment.setOnFinishListener((fragment2, chatId) -> { + Utilities.doCallbacks( + next -> { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + showSendToBotAlert(chat, next, () -> { + DialogsActivity.this.removeSelfFromStack(); + fragment.removeSelfFromStack(); + fragment2.finishFragment(); + }); + }, + next -> { + progress.showDelayed(150); + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().addUserToChat(chatId, bot, 0, null, DialogsActivity.this, false, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + if (requestPeerType.bot_admin_rights != null) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().setUserAdminRole(chatId, bot, requestPeerType.bot_admin_rights, null, false, DialogsActivity.this, !(requestPeerType.bot_participant != null && requestPeerType.bot_participant), true, null, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + if (requestPeerType.user_admin_rights != null) { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + getMessagesController().setUserAdminRole(chatId, getAccountInstance().getUserConfig().getCurrentUser(), ChatRightsEditActivity.rightsOR(chat.admin_rights, requestPeerType.user_admin_rights), null, true, DialogsActivity.this, false, true, null, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + progress.dismiss(); + getMessagesController().loadChannelParticipants(chatId); + DialogsActivityDelegate delegate = DialogsActivity.this.delegate; + DialogsActivity.this.removeSelfFromStack(); + fragment.removeSelfFromStack(); + fragment2.finishFragment(); + if (delegate != null) { + ArrayList keys = new ArrayList<>(); + keys.add(MessagesStorage.TopicKey.of(-chatId, 0)); + delegate.didSelectDialogs(DialogsActivity.this, keys, null, false); + } + } + ); + }); + presentFragment(fragment); + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeChat) { + Bundle args = new Bundle(); + long[] array; + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + array = new long[]{ getUserConfig().getClientUserId(), requestPeerBotId }; + } else { + array = new long[]{ getUserConfig().getClientUserId() }; + } + args.putLongArray("result", array); + args.putInt("chatType", requestPeerType.forum != null && requestPeerType.forum ? ChatObject.CHAT_TYPE_FORUM : ChatObject.CHAT_TYPE_MEGAGROUP); + args.putBoolean("canToggleTopics", false); + GroupCreateFinalActivity activity = new GroupCreateFinalActivity(args); + activity.setDelegate(new GroupCreateFinalActivity.GroupCreateFinalActivityDelegate() { + @Override + public void didStartChatCreation() {} + @Override + public void didFailChatCreation() {} + @Override + public void didFinishChatCreation(GroupCreateFinalActivity fragment, long chatId) { + BaseFragment[] lastFragments = new BaseFragment[] { fragment, null }; + Utilities.doCallbacks( + next -> { + if (requestPeerType.has_username != null && requestPeerType.has_username) { + Bundle args = new Bundle(); + args.putInt("step", 1); + args.putLong("chat_id", chatId); + args.putBoolean("forcePublic", requestPeerType.has_username); + ChannelCreateActivity fragment2 = new ChannelCreateActivity(args); + fragment2.setOnFinishListener((_fragment, _chatId) -> next.run()); + presentFragment(fragment2); + lastFragments[1] = fragment2; + } else { + next.run(); + } + }, + next -> { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + showSendToBotAlert(chat, next, () -> { + DialogsActivity.this.removeSelfFromStack(); + if (lastFragments[1] != null) { + lastFragments[0].removeSelfFromStack(); + lastFragments[1].finishFragment(); + } else { + lastFragments[0].finishFragment(); + } + }); + }, + next -> { + progress.showDelayed(150); + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().addUserToChat(chatId, bot, 0, null, DialogsActivity.this, false, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + if (requestPeerType.bot_admin_rights != null) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().setUserAdminRole(chatId, bot, requestPeerType.bot_admin_rights, null, false, DialogsActivity.this, !(requestPeerType.bot_participant != null && requestPeerType.bot_participant), true, null, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + if (requestPeerType.user_admin_rights != null) { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + getMessagesController().setUserAdminRole(chatId, getAccountInstance().getUserConfig().getCurrentUser(), ChatRightsEditActivity.rightsOR(chat.admin_rights, requestPeerType.user_admin_rights), null, false, DialogsActivity.this, false, true, null, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + progress.dismiss(); + getMessagesController().loadChannelParticipants(chatId); + DialogsActivityDelegate delegate = DialogsActivity.this.delegate; + DialogsActivity.this.removeSelfFromStack(); + if (lastFragments[1] != null) { + lastFragments[0].removeSelfFromStack(); + lastFragments[1].finishFragment(); + } else { + lastFragments[0].finishFragment(); + } + if (delegate != null) { + ArrayList keys = new ArrayList<>(); + keys.add(MessagesStorage.TopicKey.of(-chatId, 0)); + delegate.didSelectDialogs(DialogsActivity.this, keys, null, false); + } + } + ); + } + }); + presentFragment(activity); + } + } + private void updateAppUpdateViews(boolean animated) { if (updateLayout == null) { return; @@ -5065,7 +5379,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. viewPages[1].isLocked = filter.locked; viewPages[a].dialogsAdapter.setDialogsType(viewPages[a].dialogsType); - viewPages[a].layoutManager.scrollToPositionWithOffset(viewPages[a].dialogsType == 0 && hasHiddenArchive() && viewPages[a].archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN ? 1 : 0, (int) actionBar.getTranslationY()); + viewPages[a].layoutManager.scrollToPositionWithOffset(viewPages[a].dialogsType == DIALOGS_TYPE_DEFAULT && hasHiddenArchive() && viewPages[a].archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN ? 1 : 0, (int) actionBar.getTranslationY()); checkListLoad(viewPages[a]); } @@ -5171,7 +5485,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. canShowFilterTabsView = false; updateFilterTabsVisibility(animated); for (int a = 0; a < viewPages.length; a++) { - if (viewPages[a].dialogsType == 0 && viewPages[a].archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive()) { + if (viewPages[a].dialogsType == DIALOGS_TYPE_DEFAULT && viewPages[a].archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive()) { int p = viewPages[a].layoutManager.findFirstVisibleItemPosition(); if (p == 0 || p == 1) { viewPages[a].layoutManager.scrollToPositionWithOffset(1, (int) actionBar.getTranslationY()); @@ -5358,7 +5672,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. @Override public int getTopOffset(int tag) { - return (actionBar != null ? actionBar.getMeasuredHeight() + (int) actionBar.getTranslationY() : 0) + (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE ? filterTabsView.getMeasuredHeight() : 0) + (fragmentContextView != null && fragmentContextView.isCallTypeVisible() ? AndroidUtilities.dp(fragmentContextView.getStyleHeight()) : 0); + return (actionBar != null ? actionBar.getMeasuredHeight() + (int) actionBar.getTranslationY() : 0) + (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE ? filterTabsView.getMeasuredHeight() : 0) + (fragmentContextView != null && fragmentContextView.isCallTypeVisible() ? AndroidUtilities.dp(fragmentContextView.getStyleHeight()) : 0) + (dialogsHintCell.getVisibility() == View.VISIBLE ? dialogsHintCell.getHeight() : 0); } }); if (searchIsShowed) { @@ -6270,7 +6584,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (!validateSlowModeDialog(dialogId)) { return; } - if (!getMessagesController().isForum(dialogId) && (!selectedDialogs.isEmpty() || (initialDialogsType == 3 && selectAlertString != null))) { + if (!getMessagesController().isForum(dialogId) && (!selectedDialogs.isEmpty() || (initialDialogsType == DIALOGS_TYPE_FORWARD && selectAlertString != null))) { if (!selectedDialogs.contains(dialogId) && !checkCanWrite(dialogId)) { return; } @@ -6913,6 +7227,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (filterTabsView != null) { filterTabsView.setTranslationY(value); } + if (dialogsHintCell != null) { + dialogsHintCell.setTranslationY(value); + } if (animatedStatusView != null) { animatedStatusView.translateY2((int) value); animatedStatusView.setAlpha(1f - -value / ActionBar.getCurrentActionBarHeight()); @@ -6944,7 +7261,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. @Override public void onTransitionAnimationProgress(boolean isOpen, float progress) { - if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + if (rightSlidingDialogContainer != null && rightSlidingDialogContainer.hasFragment()) { + rightSlidingDialogContainer.getFragment().onTransitionAnimationProgress(isOpen, progress); + } else if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { if (isOpen) { blurredView.setAlpha(1.0f - progress); } else { @@ -6955,16 +7274,21 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. @Override public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { - if (isOpen && blurredView != null && blurredView.getVisibility() == View.VISIBLE) { - blurredView.setVisibility(View.GONE); - blurredView.setBackground(null); - } - if (isOpen && afterSignup) { - try { - fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } catch (Exception ignored) {} - if (getParentActivity() instanceof LaunchActivity) { - ((LaunchActivity) getParentActivity()).getFireworksOverlay().start(); + if (rightSlidingDialogContainer != null && rightSlidingDialogContainer.hasFragment()) { + rightSlidingDialogContainer.getFragment().onTransitionAnimationEnd(isOpen, backward); + } else { + if (isOpen && blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + blurredView.setVisibility(View.GONE); + blurredView.setBackground(null); + } + if (isOpen && afterSignup) { + try { + fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignored) { + } + if (getParentActivity() instanceof LaunchActivity) { + ((LaunchActivity) getParentActivity()).getFireworksOverlay().start(); + } } } } @@ -8148,7 +8472,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } actionBar.setTitle(LocaleController.formatPluralString("Recipient", selectedDialogs.size())); } - } else if (initialDialogsType == 10) { + } else if (initialDialogsType == DIALOGS_TYPE_WIDGET) { hideFloatingButton(selectedDialogs.isEmpty()); } @@ -8491,6 +8815,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. showFiltersHint(); } else if (id == NotificationCenter.newSuggestionsAvailable) { showNextSupportedSuggestion(); + updateDialogsHint(); } else if (id == NotificationCenter.forceImportContactsStart) { setFloatingProgressVisible(true, true); for (ViewPage page : viewPages) { @@ -8673,17 +8998,34 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } + public static final int DIALOGS_TYPE_DEFAULT = 0; + public static final int DIALOGS_TYPE_BOT_SHARE = 1; // selecting group to write with inline bot query, including sharing a game + public static final int DIALOGS_TYPE_ADD_USERS_TO = 2; // Chats + My channels + My groups + public static final int DIALOGS_TYPE_FORWARD = 3; + public static final int DIALOGS_TYPE_USERS_ONLY = 4; + public static final int DIALOGS_TYPE_CHANNELS_ONLY = 5; + public static final int DIALOGS_TYPE_GROUPS_ONLY = 6; + public static final int DIALOGS_TYPE_7 = 7; + public static final int DIALOGS_TYPE_8 = 8; + public static final int DIALOGS_TYPE_BLOCK = 9; + public static final int DIALOGS_TYPE_WIDGET = 10; + public static final int DIALOGS_TYPE_IMPORT_HISTORY_GROUPS = 11; // groups only + public static final int DIALOGS_TYPE_IMPORT_HISTORY_USERS = 12; // users only + public static final int DIALOGS_TYPE_IMPORT_HISTORY = 13; + public static final int DIALOGS_TYPE_START_ATTACH_BOT = 14; + public static final int DIALOGS_TYPE_BOT_REQUEST_PEER = 15; + @NonNull public ArrayList getDialogsArray(int currentAccount, int dialogsType, int folderId, boolean frozen) { if (frozen && frozenDialogsList != null) { return frozenDialogsList; } MessagesController messagesController = AccountInstance.getInstance(currentAccount).getMessagesController(); - if (dialogsType == 0) { + if (dialogsType == DIALOGS_TYPE_DEFAULT) { return messagesController.getDialogs(folderId); - } else if (dialogsType == 1 || dialogsType == 10 || dialogsType == 13) { + } else if (dialogsType == DIALOGS_TYPE_BOT_SHARE || dialogsType == DIALOGS_TYPE_WIDGET || dialogsType == DIALOGS_TYPE_IMPORT_HISTORY) { return messagesController.dialogsServerOnly; - } else if (dialogsType == 2) { + } else if (dialogsType == DIALOGS_TYPE_ADD_USERS_TO) { ArrayList dialogs = new ArrayList<>(messagesController.dialogsCanAddUsers.size() + messagesController.dialogsMyChannels.size() + messagesController.dialogsMyGroups.size() + 2); if (messagesController.dialogsMyChannels.size() > 0 && allowChannels) { dialogs.add(new DialogsHeader(DialogsHeader.HEADER_TYPE_MY_CHANNELS)); @@ -8709,13 +9051,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } return dialogs; - } else if (dialogsType == 3) { + } else if (dialogsType == DIALOGS_TYPE_FORWARD) { return messagesController.dialogsForward; - } else if (dialogsType == 4 || dialogsType == 12) { + } else if (dialogsType == DIALOGS_TYPE_USERS_ONLY || dialogsType == DIALOGS_TYPE_IMPORT_HISTORY_USERS) { return messagesController.dialogsUsersOnly; - } else if (dialogsType == 5) { + } else if (dialogsType == DIALOGS_TYPE_CHANNELS_ONLY) { return messagesController.dialogsChannelsOnly; - } else if (dialogsType == 6 || dialogsType == 11) { + } else if (dialogsType == DIALOGS_TYPE_GROUPS_ONLY || dialogsType == DIALOGS_TYPE_IMPORT_HISTORY_GROUPS) { return messagesController.dialogsGroupsOnly; } else if (dialogsType == 7 || dialogsType == 8) { MessagesController.DialogFilter dialogFilter = messagesController.selectedDialogFilter[dialogsType == 7 ? 0 : 1]; @@ -8724,13 +9066,14 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } else { return dialogFilter.dialogs; } - } else if (dialogsType == 9) { + } else if (dialogsType == DIALOGS_TYPE_BLOCK) { return messagesController.dialogsForBlock; } else if (dialogsType == DIALOGS_TYPE_START_ATTACH_BOT) { ArrayList dialogs = new ArrayList<>(); if (allowUsers || allowBots) { for (TLRPC.Dialog d : messagesController.dialogsUsersOnly) { - if (messagesController.getUser(d.id).bot ? allowBots : allowUsers) { + TLRPC.User user = messagesController.getUser(d.id); + if (user != null && !UserObject.isUserSelf(user) && (user.bot ? allowBots : allowUsers)) { dialogs.add(d); } } @@ -8742,10 +9085,79 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. dialogs.addAll(messagesController.dialogsChannelsOnly); } return dialogs; + } else if (dialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER) { + ArrayList dialogs = new ArrayList<>(); + TLRPC.User bot = messagesController.getUser(requestPeerBotId); + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeUser) { + ConcurrentHashMap users = messagesController.getUsers(); + for (TLRPC.Dialog dialog : messagesController.dialogsUsersOnly) { + TLRPC.User user = getMessagesController().getUser(dialog.id); + if (meetRequestPeerRequirements(user)) { + dialogs.add(dialog); + } + } + for (TLRPC.User user : users.values()) { + if (user != null && !messagesController.dialogs_dict.containsKey(user.id) && meetRequestPeerRequirements(user)) { + TLRPC.Dialog d = new TLRPC.TL_dialog(); + d.peer = new TLRPC.TL_peerUser(); + d.peer.user_id = user.id; + d.id = user.id; + dialogs.add(d); + } + } + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeChat || requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + ConcurrentHashMap chats = messagesController.getChats(); + ArrayList sourceDialogs = requestPeerType instanceof TLRPC.TL_requestPeerTypeChat ? messagesController.dialogsGroupsOnly : messagesController.dialogsChannelsOnly; + for (TLRPC.Dialog dialog : sourceDialogs) { + TLRPC.Chat chat = getMessagesController().getChat(-dialog.id); + if (meetRequestPeerRequirements(bot, chat)) { + dialogs.add(dialog); + } + } + for (TLRPC.Chat chat : chats.values()) { + if (chat != null && !messagesController.dialogs_dict.containsKey(-chat.id) && meetRequestPeerRequirements(bot, chat)) { + TLRPC.Dialog d = new TLRPC.TL_dialog(); + if (ChatObject.isChannel(chat)) { + d.peer = new TLRPC.TL_peerChannel(); + d.peer.channel_id = chat.id; + } else { + d.peer = new TLRPC.TL_peerChat(); + d.peer.chat_id = chat.id; + } + d.id = -chat.id; + dialogs.add(d); + } + } + } + return dialogs; } return new ArrayList<>(); } + private boolean meetRequestPeerRequirements(TLRPC.User user) { + TLRPC.TL_requestPeerTypeUser type = (TLRPC.TL_requestPeerTypeUser) requestPeerType; + return ( + user != null && + !UserObject.isReplyUser(user) && + !UserObject.isDeleted(user) && + (type.bot == null || type.bot == user.bot) && + (type.premium == null || type.premium == user.premium) + ); + } + + private boolean meetRequestPeerRequirements(TLRPC.User bot, TLRPC.Chat chat) { + return ( + chat != null && + ChatObject.isChannelAndNotMegaGroup(chat) == requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast && + (requestPeerType.creator == null || !requestPeerType.creator || chat.creator) && + (requestPeerType.bot_participant == null || !requestPeerType.bot_participant || getMessagesController().isInChatCached(chat, bot) || ChatObject.canAddBotsToChat(chat)) && + (requestPeerType.has_username == null || requestPeerType.has_username == (ChatObject.getPublicUsername(chat) != null)) && + (requestPeerType.forum == null || requestPeerType.forum == ChatObject.isForum(chat)) && + (requestPeerType.user_admin_rights == null || getMessagesController().matchesAdminRights(chat, getUserConfig().getCurrentUser(), requestPeerType.user_admin_rights)) && + (requestPeerType.bot_admin_rights == null || getMessagesController().matchesAdminRights(chat, bot, requestPeerType.bot_admin_rights) || ChatObject.canAddAdmins(chat)) + ); + } + public void setSideMenu(RecyclerView recyclerView) { sideMenu = recyclerView; sideMenu.setBackgroundColor(Theme.getColor(Theme.key_chats_menuBackground)); @@ -9062,7 +9474,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } private boolean checkCanWrite(final long dialogId) { - if (addToGroupAlertString == null && checkCanWrite) { + if (addToGroupAlertString == null && initialDialogsType != DIALOGS_TYPE_BOT_REQUEST_PEER && checkCanWrite) { if (DialogObject.isChatDialog(dialogId)) { TLRPC.Chat chat = getMessagesController().getChat(-dialogId); if (ChatObject.isChannel(chat) && !chat.megagroup && ((cantSendToChannels || !ChatObject.isCanWriteToChannel(-dialogId, currentAccount)) || hasPoll == 2)) { @@ -9097,7 +9509,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (!checkCanWrite(dialogId)) { return; } - if (initialDialogsType == 11 || initialDialogsType == 12 || initialDialogsType == 13) { + if (initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY_USERS || initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY) { if (checkingImportDialog) { return; } @@ -9205,12 +9617,41 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. builder.setPositiveButton(buttonText, (dialogInterface, i) -> didSelectResult(dialogId, topicId,false, false)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); + } else if (initialDialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER) { + Runnable send = () -> { + if (delegate != null) { + ArrayList dids = new ArrayList<>(); + dids.add(MessagesStorage.TopicKey.of(dialogId, topicId)); + delegate.didSelectDialogs(DialogsActivity.this, dids, null, param); + if (resetDelegate) { + delegate = null; + } + } else { + finishFragment(); + } + }; + Runnable checkBotRightsAndSend = () -> { + if (requestPeerType.bot_admin_rights != null) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().setUserAdminRole(-dialogId, bot, requestPeerType.bot_admin_rights, null, false, DialogsActivity.this, true, true, null, send, err -> { + send.run(); + return true; + }); + } else { + send.run(); + } + }; + if (dialogId < 0) { + showSendToBotAlert(getMessagesController().getChat(-dialogId), checkBotRightsAndSend, null); + } else { + showSendToBotAlert(getMessagesController().getUser(dialogId), checkBotRightsAndSend, null); + } } else { if (delegate != null) { ArrayList dids = new ArrayList<>(); dids.add(MessagesStorage.TopicKey.of(dialogId, topicId)); - delegate.didSelectDialogs(DialogsActivity.this, dids, null, param); - if (resetDelegate) { + boolean res = delegate.didSelectDialogs(DialogsActivity.this, dids, null, param); + if (res && resetDelegate) { delegate = null; } } else { @@ -9219,6 +9660,52 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } + private void showSendToBotAlert(TLRPC.User user, Runnable ok, Runnable cancel) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + + showDialog( + new AlertDialog.Builder(getContext()) + .setTitle(LocaleController.formatString(R.string.AreYouSureSendChatToBotTitle, UserObject.getFirstName(user), UserObject.getFirstName(bot))) + .setMessage(TextUtils.concat( + AndroidUtilities.replaceTags(LocaleController.formatString(R.string.AreYouSureSendChatToBotMessage, UserObject.getFirstName(user), UserObject.getFirstName(bot))) + )) + .setPositiveButton(LocaleController.formatString("Send", R.string.Send), (di, p) -> ok.run()) + .setNegativeButton(LocaleController.formatString("Cancel", R.string.Cancel), (di, p) -> { + if (cancel != null) { + cancel.run(); + } + }).create() + ); + } + + private void showSendToBotAlert(TLRPC.Chat chat, Runnable ok, Runnable cancel) { + final TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + final boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); + + showDialog( + new AlertDialog.Builder(getContext()) + .setTitle(LocaleController.formatString(R.string.AreYouSureSendChatToBotTitle, chat.title, UserObject.getFirstName(bot))) + .setMessage(TextUtils.concat( + AndroidUtilities.replaceTags(LocaleController.formatString(R.string.AreYouSureSendChatToBotMessage, chat.title, UserObject.getFirstName(bot))), + ( + requestPeerType.bot_participant != null && requestPeerType.bot_participant && !getMessagesController().isInChatCached(chat, bot) || + requestPeerType.bot_admin_rights != null + ) ? + TextUtils.concat("\n\n", AndroidUtilities.replaceTags( + (requestPeerType.bot_admin_rights == null) ? + LocaleController.formatString(R.string.AreYouSureSendChatToBotAdd, UserObject.getFirstName(bot), chat.title) : + LocaleController.formatString(R.string.AreYouSureSendChatToBotAddRights, UserObject.getFirstName(bot), chat.title, RequestPeerRequirementsCell.rightsToString(requestPeerType.bot_admin_rights, isChannel)) + )) : "" + )) + .setPositiveButton(LocaleController.formatString("Send", R.string.Send), (di, p) -> ok.run()) + .setNegativeButton(LocaleController.formatString("Cancel", R.string.Cancel), (di, p) -> { + if (cancel != null) { + cancel.run(); + } + }).create() + ); + } + public RLottieImageView getFloatingButton() { return floatingButton; } @@ -9585,6 +10072,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundPink)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundSaved)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundRed)); + arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_background2Red)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_background2Orange)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_background2Violet)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_background2Green)); @@ -9849,6 +10337,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. }, Theme.key_actionBarActionModeDefaultIcon, Theme.key_actionBarActionModeDefaultSelector)); } + if (dialogsHintCell != null) { + SimpleThemeDescription.add(arrayList, dialogsHintCell::updateColors, Theme.key_windowBackgroundWhite, Theme.key_windowBackgroundWhiteBlackText, Theme.key_windowBackgroundWhiteGrayText); + } + return arrayList; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java index 8ebe46907..76cb37b90 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java @@ -215,7 +215,7 @@ public class ExternalActionActivity extends Activity implements INavigationLayou passcodeView.onShow(true, false); SharedConfig.isWaitingForPasscodeEnter = true; drawerLayoutContainer.setAllowOpenDrawer(false, false); - passcodeView.setDelegate(() -> { + passcodeView.setDelegate(view -> { SharedConfig.isWaitingForPasscodeEnter = false; if (passcodeSaveIntent != null) { handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true, passcodeSaveIntentAccount, passcodeSaveIntentState); @@ -226,6 +226,8 @@ public class ExternalActionActivity extends Activity implements INavigationLayou if (AndroidUtilities.isTablet()) { layersActionBarLayout.showLastFragment(); } + + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.passcodeDismissed, view); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FeedWidgetConfigActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/FeedWidgetConfigActivity.java index 3556a038c..ef48da26f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FeedWidgetConfigActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FeedWidgetConfigActivity.java @@ -27,7 +27,7 @@ public class FeedWidgetConfigActivity extends ExternalActionActivity { if (creatingAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 5); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); args.putBoolean("allowSwitchAccount", true); args.putBoolean("checkCanWrite", false); DialogsActivity fragment = new DialogsActivity(args); @@ -47,6 +47,7 @@ public class FeedWidgetConfigActivity extends ExternalActionActivity { resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, creatingAppWidgetId); setResult(RESULT_OK, resultValue); finish(); + return true; }); if (AndroidUtilities.isTablet()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java index 32174bb20..de0cec26b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java @@ -554,7 +554,7 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente resultArray = new ArrayList<>(); ArrayList resultArrayNames = new ArrayList<>(); ArrayList encUsers = new ArrayList<>(); - MessagesStorage.getInstance(currentAccount).localSearch(0, query, resultArray, resultArrayNames, encUsers, includeFolder ? 1 : 0); + MessagesStorage.getInstance(currentAccount).localSearch(0, query, resultArray, resultArrayNames, encUsers, null, includeFolder ? 1 : 0); } final TLRPC.TL_messages_searchGlobal req = new TLRPC.TL_messages_searchGlobal(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java index 0e24b2b13..b587e67c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java @@ -6922,7 +6922,6 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter cells[num].setChecked(!cells[num].isChecked(), true); }); - builder.setCustomViewOffset(12); builder.setView(linearLayout); builder.setDialogButtonColorKey(Theme.key_voipgroup_listeningText); builder.setPositiveButton(LocaleController.getString("VoipGroupLeave", R.string.VoipGroupLeave), (dialogInterface, position) -> processOnLeave(call, cells[0].isChecked(), selfId, onLeave)); @@ -7101,7 +7100,9 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter if (currentAvatarUpdater != null && currentAvatarUpdater.isUploadingImage()) { return; } - currentAvatarUpdater = new ImageUpdater(true); + TLRPC.User user = accountInstance.getUserConfig().getCurrentUser(); + + currentAvatarUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); currentAvatarUpdater.setOpenWithFrontfaceCamera(true); currentAvatarUpdater.setForceDarkTheme(true); currentAvatarUpdater.setSearchAvailable(true, true); @@ -7109,7 +7110,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter currentAvatarUpdater.parentFragment = parentActivity.getActionBarLayout().getLastFragment(); currentAvatarUpdater.setDelegate(avatarUpdaterDelegate = new AvatarUpdaterDelegate(peerId)); - TLRPC.User user = accountInstance.getUserConfig().getCurrentUser(); + currentAvatarUpdater.openMenu(user.photo != null && user.photo.photo_big != null && !(user.photo instanceof TLRPC.TL_userProfilePhotoEmpty), () -> accountInstance.getMessagesController().deleteUserPhoto(null), dialog -> { }, 0); @@ -7454,7 +7455,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter avatarsViewPager.setHasActiveVideo(hasAttachedRenderer); avatarsViewPager.setData(peerId, true); avatarsViewPager.setCreateThumbFromParent(true); - avatarsViewPager.initIfEmpty(imageLocation, thumbLocation, true); + avatarsViewPager.initIfEmpty(null, imageLocation, thumbLocation, true); if (scrimRenderer != null) { scrimRenderer.setShowingAsScrimView(true, true); } @@ -8355,9 +8356,9 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter } @Override - public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { - if (photo != null || video != null) { + if (photo != null || video != null || emojiMarkup != null) { if (peerId > 0) { TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); if (photo != null) { @@ -8370,6 +8371,10 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.video_emoji_markup = emojiMarkup; + req.flags |= 16; + } accountInstance.getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (uploadingImageLocation != null) { @@ -8439,7 +8444,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter thumb = thumbLocation; } avatarsViewPager.setCreateThumbFromParent(false); - avatarsViewPager.initIfEmpty(imageLocation, thumb, true); + avatarsViewPager.initIfEmpty(null, imageLocation, thumb, true); avatar = null; avatarBig = null; AndroidUtilities.updateVisibleRows(listView); @@ -8451,7 +8456,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter accountInstance.getUserConfig().saveConfig(true); })); } else { - accountInstance.getMessagesController().changeChatAvatar(-peerId, null, photo, video, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, () -> { + accountInstance.getMessagesController().changeChatAvatar(-peerId, null, photo, video, emojiMarkup, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, () -> { if (uploadingImageLocation != null) { avatarsViewPager.removeUploadingImage(uploadingImageLocation); uploadingImageLocation = null; @@ -8467,7 +8472,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter thumb = thumbLocation; } avatarsViewPager.setCreateThumbFromParent(false); - avatarsViewPager.initIfEmpty(imageLocation, thumb, true); + avatarsViewPager.initIfEmpty(null, imageLocation, thumb, true); avatar = null; avatarBig = null; AndroidUtilities.updateVisibleRows(listView); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java index f1b4b119e..e86de5f44 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java @@ -727,9 +727,9 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen TLRPC.Chat chat = getMessagesController().getChat(channelId); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); if (ChatObject.canAddAdmins(chat)) { - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setTitle(LocaleController.getString("AddBotAdminAlert", R.string.AddBotAdminAlert)); builder.setMessage(LocaleController.getString("AddBotAsAdmin", R.string.AddBotAsAdmin)); - builder.setPositiveButton(LocaleController.getString("MakeAdmin", R.string.MakeAdmin), (dialogInterface, i) -> { + builder.setPositiveButton(LocaleController.getString("AddAsAdmin", R.string.AddAsAdmin), (dialogInterface, i) -> { delegate2.needAddBot(user); if (editText.length() > 0) { editText.setText(null); @@ -1013,7 +1013,6 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen linearLayout.addView(cells[0], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); cells[0].setOnClickListener(v -> cells[0].setChecked(!cells[0].isChecked(), true)); - builder.setCustomViewOffset(12); builder.setView(linearLayout); } builder.setPositiveButton(LocaleController.getString("Add", R.string.Add), (dialogInterface, i) -> onAddToGroupDone(cells[0] != null && cells[0].isChecked() ? 100 : 0)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java index d4f2780e5..7dfdc44d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java @@ -105,6 +105,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati private TLRPC.FileLocation avatarBig; private TLRPC.InputFile inputPhoto; private TLRPC.InputFile inputVideo; + private TLRPC.VideoSize inputEmojiMarkup; private String inputVideoPath; private double videoTimestamp; private ArrayList selectedContacts; @@ -113,6 +114,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati private ImageUpdater imageUpdater; private String nameToSet; private int chatType; + private boolean canToggleTopics; private RLottieDrawable cameraDrawable; @@ -142,6 +144,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati currentGroupCreateLocation = args.getParcelable("location"); forImport = args.getBoolean("forImport", false); nameToSet = args.getString("title", null); + canToggleTopics = args.getBoolean("canToggleTopics", true); } @Override @@ -149,7 +152,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.updateInterfaces); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatDidCreated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatDidFailCreate); - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_GROUP, true); imageUpdater.parentFragment = this; imageUpdater.setDelegate(this); long[] contacts = getArguments().getLongArray("result"); @@ -442,7 +445,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati super.invalidate(l, t, r, b); } }; - avatarImage.setRoundRadius(AndroidUtilities.dp(32)); + avatarImage.setRoundRadius(AndroidUtilities.dp(chatType == ChatObject.CHAT_TYPE_FORUM ? 16 : 32)); avatarDrawable.setInfo(5, null, null); avatarImage.setImageDrawable(avatarDrawable); avatarImage.setContentDescription(LocaleController.getString("ChoosePhoto", R.string.ChoosePhoto)); @@ -454,7 +457,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati avatarOverlay = new View(context) { @Override protected void onDraw(Canvas canvas) { - if (avatarImage != null && avatarProgressView.getVisibility() == VISIBLE) { + if (avatarImage != null && avatarProgressView.getVisibility() == VISIBLE && avatarImage.getImageReceiver().hasNotThumb()) { paint.setAlpha((int) (0x55 * avatarImage.getImageReceiver().getCurrentAlpha() * avatarProgressView.getAlpha())); canvas.drawCircle(getMeasuredWidth() / 2.0f, getMeasuredHeight() / 2.0f, getMeasuredWidth() / 2.0f, paint); } @@ -468,6 +471,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati inputPhoto = null; inputVideo = null; inputVideoPath = null; + inputEmojiMarkup = null; videoTimestamp = 0; showAvatarProgress(false, true); avatarImage.setImage(null, null, avatarDrawable, null); @@ -523,7 +527,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati showAvatarProgress(false, false); editText = new EditTextEmoji(context, sizeNotifierFrameLayout, this, EditTextEmoji.STYLE_FRAGMENT, false); - editText.setHint(chatType == ChatObject.CHAT_TYPE_CHAT || chatType == ChatObject.CHAT_TYPE_MEGAGROUP ? LocaleController.getString("EnterGroupNamePlaceholder", R.string.EnterGroupNamePlaceholder) : LocaleController.getString("EnterListName", R.string.EnterListName)); + editText.setHint(chatType == ChatObject.CHAT_TYPE_CHAT || chatType == ChatObject.CHAT_TYPE_MEGAGROUP || chatType == ChatObject.CHAT_TYPE_FORUM ? LocaleController.getString("EnterGroupNamePlaceholder", R.string.EnterGroupNamePlaceholder) : LocaleController.getString("EnterListName", R.string.EnterListName)); if (nameToSet != null) { editText.setText(nameToSet); nameToSet = null; @@ -563,7 +567,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati }); presentFragment(fragment); } - if (view instanceof TextCell) { + if (view instanceof TextCell && chatType != ChatObject.CHAT_TYPE_FORUM) { if (popupWindow != null && popupWindow.isShowing()) { return; } @@ -682,11 +686,12 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati } @Override - public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { - if (photo != null || video != null) { + if (photo != null || video != null || emojiMarkup != null) { inputPhoto = photo; inputVideo = video; + inputEmojiMarkup = emojiMarkup; inputVideoPath = videoPath; videoTimestamp = videoStartTimestamp; if (createAfterUpload) { @@ -850,8 +855,8 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati args2.putBoolean("just_created_chat", true); presentFragment(new ChatActivity(args2), true); } - if (inputPhoto != null || inputVideo != null) { - getMessagesController().changeChatAvatar(chatId, null, inputPhoto, inputVideo, videoTimestamp, inputVideoPath, avatar, avatarBig, null); + if (inputPhoto != null || inputVideo != null || inputEmojiMarkup != null) { + getMessagesController().changeChatAvatar(chatId, null, inputPhoto, inputVideo, inputEmojiMarkup, videoTimestamp, inputVideoPath, avatar, avatarBig, null); } } } @@ -919,6 +924,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati private final static int VIEW_TYPE_TEXT_SETTINGS = 3; private final static int VIEW_TYPE_AUTO_DELETE = 4; private final static int VIEW_TYPE_TEXT_INFO_CELL = 5; + private final static int VIEW_TYPE_TOPICS = 6; ArrayList items = new ArrayList<>(); @@ -930,8 +936,13 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati public void notifyDataSetChanged() { items.clear(); items.add(new InnerItem(VIEW_TYPE_SHADOW_SECTION_CELL)); - items.add(new InnerItem(VIEW_TYPE_AUTO_DELETE)); - items.add(new InnerItem(VIEW_TYPE_TEXT_INFO_CELL, LocaleController.getString("GroupCreateAutodeleteDescription", R.string.GroupCreateAutodeleteDescription))); + if (chatType == ChatObject.CHAT_TYPE_FORUM) { + items.add(new InnerItem(VIEW_TYPE_TOPICS)); + items.add(new InnerItem(VIEW_TYPE_TEXT_INFO_CELL, LocaleController.getString("ForumToggleDescription", R.string.ForumToggleDescription))); + } else { + items.add(new InnerItem(VIEW_TYPE_AUTO_DELETE)); + items.add(new InnerItem(VIEW_TYPE_TEXT_INFO_CELL, LocaleController.getString("GroupCreateAutodeleteDescription", R.string.GroupCreateAutodeleteDescription))); + } if (currentGroupCreateAddress != null) { items.add(new InnerItem(VIEW_TYPE_HEADER_CELL)); items.add(new InnerItem(VIEW_TYPE_TEXT_SETTINGS)); @@ -953,7 +964,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() == VIEW_TYPE_TEXT_SETTINGS || holder.getItemViewType() == VIEW_TYPE_AUTO_DELETE; + return holder.getItemViewType() == VIEW_TYPE_TEXT_SETTINGS || holder.getItemViewType() == VIEW_TYPE_AUTO_DELETE || holder.getItemViewType() == VIEW_TYPE_TOPICS && canToggleTopics; } @Override @@ -986,6 +997,9 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati combinedDrawable.setFullsize(true); view.setBackgroundDrawable(combinedDrawable); break; + case VIEW_TYPE_TOPICS: + view = new TextCell(context, 23, false, true, getResourceProvider()); + break; case 3: default: view = new TextSettingsCell(context); @@ -1029,6 +1043,12 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati textCell.setTextAndValueAndIcon(LocaleController.getString("AutoDeleteMessages", R.string.AutoDeleteMessages), value, fragmentBeginToShow, R.drawable.msg_autodelete, false); break; } + case VIEW_TYPE_TOPICS: { + TextCell textCell = (TextCell) holder.itemView; + textCell.setTextAndCheckAndIcon(LocaleController.getString("ChannelTopics", R.string.ChannelTopics), true, R.drawable.msg_topics, false); + textCell.getCheckBox().setAlpha(.75f); + break; + } case VIEW_TYPE_TEXT_INFO_CELL: TextInfoPrivacyCell textInfoPrivacyCell = (TextInfoPrivacyCell) holder.itemView; textInfoPrivacyCell.setText(items.get(position).string); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/KeepMediaPopupView.java b/TMessagesProj/src/main/java/org/telegram/ui/KeepMediaPopupView.java index 2abe5c21d..adf114f6c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/KeepMediaPopupView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/KeepMediaPopupView.java @@ -90,11 +90,11 @@ public class KeepMediaPopupView extends ActionBarPopupWindow.ActionBarPopupWindo args.putBoolean("onlySelect", true); args.putBoolean("checkCanWrite", false); if (currentType == CacheControlActivity.KEEP_MEDIA_TYPE_GROUP) { - args.putInt("dialogsType", 6); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY); } else if (currentType == CacheControlActivity.KEEP_MEDIA_TYPE_CHANNEL) { - args.putInt("dialogsType", 5); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); } else { - args.putInt("dialogsType", 4); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_USERS_ONLY); } args.putBoolean("allowGlobalSearch", false); DialogsActivity activity = new DialogsActivity(args); @@ -120,6 +120,7 @@ public class KeepMediaPopupView extends ActionBarPopupWindow.ActionBarPopupWindo cacheChatsExceptionsFragment.setExceptions(exceptions); parentFragment.presentFragment(cacheChatsExceptionsFragment); AndroidUtilities.runOnUIThread(() -> cacheChatsExceptionsFragment.showPopupFor(finalNewException), 150); + return true; }); baseFragment.presentFragment(activity); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java index ef62e44d9..30acc549b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java @@ -16,6 +16,7 @@ import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Canvas; +import android.graphics.drawable.Drawable; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -35,6 +36,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.TranslateController; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.ui.ActionBar.ActionBar; @@ -54,12 +56,15 @@ import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.TranslateAlert2; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; +import java.util.Iterator; import java.util.Timer; public class LanguageSelectActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { @@ -188,18 +193,50 @@ public class LanguageSelectActivity extends BaseFragment implements Notification } }; itemAnimator.setDurations(400); + itemAnimator.setDelayAnimations(false); itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); listView.setItemAnimator(itemAnimator); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); listView.setOnItemClickListener((view, position) -> { try { + if (view instanceof TextCheckCell) { + final boolean prevFullValue = getContextValue() || getChatValue(); + if (position == 1) { + boolean value = !getContextValue(); + getMessagesController().getTranslateController().setContextTranslateEnabled(value); + ((TextCheckCell) view).setChecked(value); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateSearchSettings); + } else if (position == 2) { + boolean value = !getChatValue(); + if (value && !getUserConfig().isPremium()) { + showDialog(new PremiumFeatureBottomSheet(LanguageSelectActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS, false)); + return; + } + MessagesController.getMainSettings(currentAccount).edit().putBoolean("translate_chat_button", value).apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateSearchSettings); + ((TextCheckCell) view).setChecked(value); + } + final boolean currentFullValue = getContextValue() || getChatValue(); + if (currentFullValue != prevFullValue) { + listAdapter.notifyItemChanged(2); + if (currentFullValue) { + listAdapter.notifyItemInserted(3); + } else { + listAdapter.notifyItemRemoved(3); + } + } + return; + } else if (view instanceof TextSettingsCell) { + presentFragment(new RestrictedLanguagesSelectActivity()); + return; + } if (getParentActivity() == null || parentLayout == null || !(view instanceof TextRadioCell)) { return; } boolean search = listView.getAdapter() == searchListViewAdapter; if (!search) { - position -= 2; + position -= (getChatValue() || getContextValue()) ? 7 : 6; } LocaleController.LocaleInfo localeInfo; if (search) { @@ -236,16 +273,19 @@ public class LanguageSelectActivity extends BaseFragment implements Notification HashSet selectedLanguages = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); HashSet newSelectedLanguages = new HashSet(selectedLanguages); - if (selectedLanguages.contains(langCode)) { - newSelectedLanguages.removeIf(s -> s != null && s.equals(langCode)); - if (!selectedLanguages.contains(prevLangCode)) - newSelectedLanguages.add(prevLangCode); + if (selectedLanguages.contains(prevLangCode) && !selectedLanguages.contains(langCode)) { + newSelectedLanguages.removeIf(s -> s != null && s.equals(prevLangCode)); + newSelectedLanguages.add(langCode); } preferences.edit().putStringSet("translate_button_restricted_languages", newSelectedLanguages).apply(); + MessagesController.getInstance(currentAccount).getTranslateController().checkRestrictedLanguagesUpdate(); + MessagesController.getInstance(currentAccount).getTranslateController().cleanup(); if (!sameLang) { progressDialog.showDelayed(500); } + + TranslateController.invalidateSuggestedLanguageCodes(); } } catch (Exception e) { FileLog.e(e); @@ -259,7 +299,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification } boolean search = listView.getAdapter() == searchListViewAdapter; if (!search) { - position -= 2; + position -= (getChatValue() || getContextValue()) ? 7 : 6; } LocaleController.LocaleInfo localeInfo; if (search) { @@ -459,24 +499,28 @@ public class LanguageSelectActivity extends BaseFragment implements Notification private HeaderCell header; private TextCheckCell showButtonCheck; + private TextCheckCell showChatButtonCheck; private TextSettingsCell doNotTranslateCell; private TextInfoPrivacyCell info; private TextInfoPrivacyCell info2; private ValueAnimator doNotTranslateCellAnimation = null; // private HeaderCell header2; - private SharedPreferences.OnSharedPreferenceChangeListener listener; - // private float HEIGHT_OPEN = 243; // private float HEIGHT_CLOSED = HEIGHT_OPEN - 50; + private Drawable topShadow, bottomShadow; + public TranslateSettings(Context context) { super(context); setFocusable(false); setOrientation(VERTICAL); - preferences = MessagesController.getGlobalMainSettings(); + topShadow = Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow); + bottomShadow = Theme.getThemedDrawable(context, R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow); + + preferences = MessagesController.getMainSettings(currentAccount); header = new HeaderCell(context); header.setFocusable(true); @@ -485,20 +529,41 @@ public class LanguageSelectActivity extends BaseFragment implements Notification header.setContentDescription(LocaleController.getString("TranslateMessages", R.string.TranslateMessages)); addView(header, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - boolean value = getValue(); + final boolean value = getValue(); + showButtonCheck = new TextCheckCell(context); showButtonCheck.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector))); showButtonCheck.setTextAndCheck( LocaleController.getString("ShowTranslateButton", R.string.ShowTranslateButton), - value, - value + getContextValue(), + true ); showButtonCheck.setOnClickListener(e -> { - preferences.edit().putBoolean("translate_button", !getValue()).apply(); + getMessagesController().getTranslateController().setContextTranslateEnabled(!getContextValue()); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateSearchSettings); + update(); }); addView(showButtonCheck, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + showChatButtonCheck = new TextCheckCell(context); + showChatButtonCheck.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector))); + showChatButtonCheck.setTextAndCheck( + LocaleController.getString("ShowTranslateChatButton", R.string.ShowTranslateChatButton), + getChatValue(), + value + ); + showChatButtonCheck.setOnClickListener(e -> { + if (!getUserConfig().isPremium()) { + showDialog(new PremiumFeatureBottomSheet(LanguageSelectActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS, false)); + return; + } + MessagesController.getMainSettings(currentAccount).edit().putBoolean("translate_chat_button", !getChatValue()).apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateSearchSettings); + update(); + }); + showChatButtonCheck.setCheckBoxIcon(!getUserConfig().isPremium() ? R.drawable.permission_locked : 0); + addView(showChatButtonCheck, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + doNotTranslateCell = new TextSettingsCell(context); doNotTranslateCell.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector))); doNotTranslateCell.setOnClickListener(e -> { @@ -537,11 +602,28 @@ public class LanguageSelectActivity extends BaseFragment implements Notification update(); } + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + + float topShadowY = Math.max(showChatButtonCheck.getY() + showChatButtonCheck.getHeight(), doNotTranslateCell.getY() + doNotTranslateCell.getHeight() * doNotTranslateCell.getAlpha()); + topShadow.setBounds(0, (int) topShadowY, getWidth(), (int) (topShadowY + AndroidUtilities.dp(12))); + topShadow.draw(canvas); + + float bottomShadowY = getHeight(); + bottomShadow.setBounds(0, (int) (bottomShadowY - AndroidUtilities.dp(12)), getWidth(), (int) bottomShadowY); + bottomShadow.draw(canvas); + } + public void updateTranslations() { header.setText(LocaleController.getString("TranslateMessages", R.string.TranslateMessages)); showButtonCheck.setTextAndCheck( - LocaleController.getString("ShowTranslateButton", R.string.ShowTranslateButton), getValue(), getValue() + LocaleController.getString("ShowTranslateButton", R.string.ShowTranslateButton), getContextValue(), true ); + showChatButtonCheck.setTextAndCheck( + LocaleController.getString("ShowTranslateChatButton", R.string.ShowTranslateChatButton), getChatValue(), getValue() + ); + showChatButtonCheck.setCheckBoxIcon(!getUserConfig().isPremium() ? R.drawable.permission_locked : 0); showButtonCheck.updateRTL(); doNotTranslateCell.updateRTL(); info.setText(LocaleController.getString("TranslateMessagesInfo1", R.string.TranslateMessagesInfo1)); @@ -553,36 +635,48 @@ public class LanguageSelectActivity extends BaseFragment implements Notification } private boolean getValue() { - return preferences.getBoolean("translate_button", false); - } - private ArrayList getRestrictedLanguages() { - String currentLang = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; - ArrayList langCodes = new ArrayList<>(RestrictedLanguagesSelectActivity.getRestrictedLanguages()); - if (!langCodes.contains(currentLang)) - langCodes.add(currentLang); - return langCodes; + return getContextValue() || getChatValue(); } public void update() { boolean value = getValue() && LanguageDetector.hasSupport(); - showButtonCheck.setChecked(getValue()); + showButtonCheck.setChecked(getContextValue()); + showChatButtonCheck.setChecked(getChatValue()); if (doNotTranslateCellAnimation != null) { doNotTranslateCellAnimation.cancel(); } - showButtonCheck.setDivider(value); - ArrayList langCodes = getRestrictedLanguages(); + showChatButtonCheck.setDivider(value); + HashSet langCodes = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); + final String doNotTranslateCellName = LocaleController.getString("DoNotTranslate", R.string.DoNotTranslate); String doNotTranslateCellValue = null; - if (langCodes.size() == 1) { - try { - doNotTranslateCellValue = LocaleController.getInstance().getLanguageFromDict(langCodes.get(0)).name; - } catch (Exception e) {} - } + try { + if (langCodes.size() == 1) { + doNotTranslateCellValue = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(langCodes.iterator().next())); + } else { + Iterator iterator = langCodes.iterator(); + boolean first = true; + StringBuilder string = new StringBuilder(); + while (iterator.hasNext()) { + String lang = iterator.next(); + if (!first) { + string.append(", "); + } + string.append(TranslateAlert2.capitalFirst(TranslateAlert2.languageName(lang))); + first = false; + } + doNotTranslateCellValue = string.toString(); + if (doNotTranslateCell.getValueTextView().getPaint().measureText(doNotTranslateCellValue) > + Math.min((AndroidUtilities.displaySize.x - AndroidUtilities.dp(34)) / 2f, AndroidUtilities.displaySize.x - AndroidUtilities.dp(21 * 4) - doNotTranslateCell.getTextView().getPaint().measureText(doNotTranslateCellName))) { + doNotTranslateCellValue = null; + } + } + } catch (Exception ignore) {} if (doNotTranslateCellValue == null) - doNotTranslateCellValue = String.format(LocaleController.getPluralString("Languages", getRestrictedLanguages().size()), getRestrictedLanguages().size()); - doNotTranslateCell.setTextAndValue(LocaleController.getString("DoNotTranslate", R.string.DoNotTranslate), doNotTranslateCellValue, false); + doNotTranslateCellValue = String.format(LocaleController.getPluralString("Languages", langCodes.size()), langCodes.size()); + doNotTranslateCell.setTextAndValue(doNotTranslateCellName, doNotTranslateCellValue, false, false); doNotTranslateCell.setClickable(value); info2.setVisibility(View.VISIBLE); @@ -593,10 +687,12 @@ public class LanguageSelectActivity extends BaseFragment implements Notification doNotTranslateCell.setAlpha(t); doNotTranslateCell.setTranslationY(-AndroidUtilities.dp(8) * (1f - t)); info.setTranslationY(-doNotTranslateCell.getHeight() * (1f - t)); + t = 1f; info2.setAlpha(1f - t); info2.setTranslationY(-doNotTranslateCell.getHeight() * (1f - t)); translateSettingsBackgroundHeight = header.getMeasuredHeight() + showButtonCheck.getMeasuredHeight() + (int) (doNotTranslateCell.getAlpha() * doNotTranslateCell.getMeasuredHeight()); + invalidate(); }); doNotTranslateCellAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -609,6 +705,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification } translateSettingsBackgroundHeight = header.getMeasuredHeight() + showButtonCheck.getMeasuredHeight() + (int) (doNotTranslateCell.getAlpha() * doNotTranslateCell.getMeasuredHeight()); + invalidate(); } }); doNotTranslateCellAnimation.setDuration((long) (Math.abs(doNotTranslateCell.getAlpha() - (value ? 1f : 0f)) * 200)); @@ -631,6 +728,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification void updateHeight() { header.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); showButtonCheck.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); + showChatButtonCheck.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); doNotTranslateCell.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); info.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); info2.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); @@ -643,11 +741,13 @@ public class LanguageSelectActivity extends BaseFragment implements Notification lp.height = newHeight; setLayoutParams(lp); } + invalidate(); } int height() { return Math.max(AndroidUtilities.dp(40), header.getMeasuredHeight()) + Math.max(AndroidUtilities.dp(50), showButtonCheck.getMeasuredHeight()) + + Math.max(AndroidUtilities.dp(50), showChatButtonCheck.getMeasuredHeight()) + Math.max(Math.max(AndroidUtilities.dp(50), doNotTranslateCell.getMeasuredHeight()), (info2.getMeasuredHeight() <= 0 ? AndroidUtilities.dp(51) : info2.getMeasuredHeight())) + (info.getMeasuredHeight() <= 0 ? AndroidUtilities.dp(62) : info.getMeasuredHeight());/* + header2.getHeight()*/ } @@ -662,23 +762,25 @@ public class LanguageSelectActivity extends BaseFragment implements Notification protected void onAttachedToWindow() { super.onAttachedToWindow(); update(); - preferences.registerOnSharedPreferenceChangeListener(listener = new SharedPreferences.OnSharedPreferenceChangeListener() { - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { - preferences = sharedPreferences; - update(); - } - }); updateHeight(); } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - preferences.unregisterOnSharedPreferenceChangeListener(listener); - } } + private boolean getContextValue() { + return getMessagesController().getTranslateController().isContextTranslateEnabled(); + } + + private boolean getChatValue() { + return getMessagesController().getTranslateController().isFeatureAvailable(); + } + + public static final int VIEW_TYPE_LANGUAGE = 0; + public static final int VIEW_TYPE_SHADOW = 1; + public static final int VIEW_TYPE_SWITCH = 2; + public static final int VIEW_TYPE_HEADER = 3; + public static final int VIEW_TYPE_SETTINGS = 4; + public static final int VIEW_TYPE_INFO = 5; + private class ListAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; @@ -691,7 +793,8 @@ public class LanguageSelectActivity extends BaseFragment implements Notification @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() == 0; + final int viewType = holder.getItemViewType(); + return viewType == VIEW_TYPE_LANGUAGE || viewType == VIEW_TYPE_SETTINGS || viewType == VIEW_TYPE_SWITCH; } @Override @@ -709,7 +812,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification if (!unofficialLanguages.isEmpty()) { count += unofficialLanguages.size() + 1; } - return 2 + count; + return 5 + (getChatValue() || getContextValue() ? 1 : 0) + 1 + count; } } @@ -717,22 +820,31 @@ public class LanguageSelectActivity extends BaseFragment implements Notification public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: { -// view = new LanguageCell(mContext, false); + case VIEW_TYPE_LANGUAGE: { view = new TextRadioCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; } - case 2: - TranslateSettings translateSettings = new TranslateSettings(mContext); - view = translateSettings; + case VIEW_TYPE_SWITCH: + TextCheckCell switchCell = new TextCheckCell(mContext); + switchCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view = switchCell; break; - case 3: + case VIEW_TYPE_SETTINGS: + TextSettingsCell settingsCell = new TextSettingsCell(mContext); + settingsCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view = settingsCell; + break; + case VIEW_TYPE_HEADER: HeaderCell header = new HeaderCell(mContext); header.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); view = header; break; - case 1: + case VIEW_TYPE_INFO: + TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(mContext); + view = infoCell; + break; + case VIEW_TYPE_SHADOW: default: { view = new ShadowSectionCell(mContext); break; @@ -744,9 +856,9 @@ public class LanguageSelectActivity extends BaseFragment implements Notification @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: { + case VIEW_TYPE_LANGUAGE: { if (!search) { - position -= 2; + position -= (getChatValue() || getContextValue()) ? 7 : 6; } TextRadioCell textSettingsCell = (TextRadioCell) holder.itemView; LocaleController.LocaleInfo localeInfo = null; @@ -778,7 +890,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification textSettingsCell.setChecked(localeInfo == LocaleController.getInstance().getCurrentLocaleInfo()); break; } - case 1: { + case VIEW_TYPE_SHADOW: { if (!search) position--; ShadowSectionCell sectionCell = (ShadowSectionCell) holder.itemView; @@ -789,15 +901,66 @@ public class LanguageSelectActivity extends BaseFragment implements Notification } break; } - case 2: { - TranslateSettings translateSettings = (TranslateSettings) holder.itemView; - translateSettings.setVisibility(searching ? View.GONE : View.VISIBLE); - translateSettings.updateTranslations(); + case VIEW_TYPE_SETTINGS: { + TextSettingsCell settingsCell = (TextSettingsCell) holder.itemView; + HashSet langCodes = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); + final String doNotTranslateCellName = LocaleController.getString("DoNotTranslate", R.string.DoNotTranslate); + String doNotTranslateCellValue = null; + try { + if (langCodes.size() == 1) { + doNotTranslateCellValue = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(langCodes.iterator().next())); + } else { + Iterator iterator = langCodes.iterator(); + boolean first = true; + StringBuilder string = new StringBuilder(); + while (iterator.hasNext()) { + String lang = iterator.next(); + if (!first) { + string.append(", "); + } + string.append(TranslateAlert2.capitalFirst(TranslateAlert2.languageName(lang))); + first = false; + } + doNotTranslateCellValue = string.toString(); + if (settingsCell.getValueTextView().getPaint().measureText(doNotTranslateCellValue) > Math.min((AndroidUtilities.displaySize.x - AndroidUtilities.dp(34)) / 2f, AndroidUtilities.displaySize.x - AndroidUtilities.dp(21 * 4) - settingsCell.getTextView().getPaint().measureText(doNotTranslateCellName))) { + doNotTranslateCellValue = null; + } + } + } catch (Exception ignore) {} + if (doNotTranslateCellValue == null) { + doNotTranslateCellValue = String.format(LocaleController.getPluralString("Languages", langCodes.size()), langCodes.size()); + } + settingsCell.setTextAndValue(doNotTranslateCellName, doNotTranslateCellValue, true, false); break; } - case 3: { + case VIEW_TYPE_SWITCH: { + TextCheckCell cell = (TextCheckCell) holder.itemView; + if (position == 1) { + cell.setTextAndCheck(LocaleController.getString("ShowTranslateButton", R.string.ShowTranslateButton), getContextValue(), true); + } else if (position == 2) { + cell.setTextAndCheck(LocaleController.getString("ShowTranslateChatButton", R.string.ShowTranslateChatButton), getChatValue(), getContextValue() || getChatValue()); + cell.setCheckBoxIcon(!getUserConfig().isPremium() ? R.drawable.permission_locked : 0); + } + break; + } + case VIEW_TYPE_INFO: { + TextInfoPrivacyCell infoCell = (TextInfoPrivacyCell) holder.itemView; + if (position == (getContextValue() || getChatValue() ? 4 : 3)) { + infoCell.setText(LocaleController.getString("TranslateMessagesInfo1", R.string.TranslateMessagesInfo1)); + infoCell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + infoCell.setTopPadding(11); + infoCell.setBottomPadding(16); + } else { + infoCell.setTopPadding(0); + infoCell.setBottomPadding(16); + infoCell.setText(LocaleController.getString("TranslateMessagesInfo2", R.string.TranslateMessagesInfo2)); + infoCell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); + } + break; + } + case VIEW_TYPE_HEADER: { HeaderCell header = (HeaderCell) holder.itemView; - header.setText(LocaleController.getString("Language", R.string.Language)); + header.setText(position == 0 ? LocaleController.getString("TranslateMessages", R.string.TranslateMessages) : LocaleController.getString("Language", R.string.Language)); break; } } @@ -805,19 +968,23 @@ public class LanguageSelectActivity extends BaseFragment implements Notification @Override public int getItemViewType(int i) { - if (!search) - i -= 2; - if (i == -2) - return 2; - if (i == -1) - return 3; if (search) { - return 0; + return VIEW_TYPE_LANGUAGE; + } else { + if (i-- == 0) return VIEW_TYPE_HEADER; + if (i-- == 0) return VIEW_TYPE_SWITCH; + if (i-- == 0) return VIEW_TYPE_SWITCH; + if (getChatValue() || getContextValue()) { + if (i-- == 0) return VIEW_TYPE_SETTINGS; + } + if (i-- == 0) return VIEW_TYPE_INFO; + if (i-- == 0) return VIEW_TYPE_INFO; + if (i-- == 0) return VIEW_TYPE_HEADER; + if (!unofficialLanguages.isEmpty() && (i == unofficialLanguages.size() || i == unofficialLanguages.size() + 1 + sortedLanguages.size() + 1) || unofficialLanguages.isEmpty() && i == sortedLanguages.size()) { + return VIEW_TYPE_SHADOW; + } + return VIEW_TYPE_LANGUAGE; } - if (!unofficialLanguages.isEmpty() && (i == unofficialLanguages.size() || i == unofficialLanguages.size() + sortedLanguages.size() + 1) || unofficialLanguages.isEmpty() && i == sortedLanguages.size()) { - return 1; - } - return 0; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 842e2bcf9..4f5294557 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -44,8 +44,13 @@ import android.os.StrictMode; import android.os.SystemClock; import android.provider.ContactsContract; import android.provider.Settings; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; import android.text.TextUtils; +import android.text.style.ClickableSpan; import android.util.Base64; +import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TypedValue; @@ -83,6 +88,7 @@ import com.google.firebase.appindexing.Action; import com.google.firebase.appindexing.FirebaseUserActions; import com.google.firebase.appindexing.builders.AssistActionBuilder; +import org.telegram.messenger.BackupAgent; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; @@ -238,6 +244,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati public DrawerLayoutContainer drawerLayoutContainer; private DrawerLayoutAdapter drawerLayoutAdapter; private PasscodeView passcodeView; + private List overlayPasscodeViews = new ArrayList<>(); private TermsOfServiceView termsOfServiceView; private BlockingUpdateView blockingUpdateView; private AlertDialog visibleDialog; @@ -294,6 +301,8 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } }; + public static LaunchActivity instance; + @Override protected void onCreate(Bundle savedInstanceState) { if (BuildVars.DEBUG_VERSION) { @@ -301,6 +310,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati .detectLeakedClosableObjects() .build()); } + instance = this; ApplicationLoader.postInitApplication(); AndroidUtilities.checkDisplaySize(this, getResources().getConfiguration()); currentAccount = UserConfig.selectedAccount; @@ -860,7 +870,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); - if (am.isBackgroundRestricted() && System.currentTimeMillis() - SharedConfig.BackgroundActivityPrefs.getLastCheckedBackgroundActivity() >= 86400000L) { + if (am.isBackgroundRestricted() && System.currentTimeMillis() - SharedConfig.BackgroundActivityPrefs.getLastCheckedBackgroundActivity() >= 86400000L && SharedConfig.BackgroundActivityPrefs.getDismissedCount() < 3) { AlertsCreator.createBackgroundActivityDialog(this).show(); SharedConfig.BackgroundActivityPrefs.setLastCheckedBackgroundActivity(System.currentTimeMillis()); } @@ -879,6 +889,9 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } }); } + BackupAgent.requestBackup(this); + + RestrictedLanguagesSelectActivity.checkRestrictedLanguages(false); } @Override @@ -1112,22 +1125,20 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati @Override protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { - TLRPC.TL_account_updateEmojiStatus req = new TLRPC.TL_account_updateEmojiStatus(); + TLRPC.EmojiStatus emojiStatus; if (documentId == null) { - req.emoji_status = new TLRPC.TL_emojiStatusEmpty(); + emojiStatus = new TLRPC.TL_emojiStatusEmpty(); } else if (until != null) { - req.emoji_status = new TLRPC.TL_emojiStatusUntil(); - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).document_id = documentId; - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).until = until; + emojiStatus = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id = documentId; + ((TLRPC.TL_emojiStatusUntil) emojiStatus).until = until; } else { - req.emoji_status = new TLRPC.TL_emojiStatus(); - ((TLRPC.TL_emojiStatus) req.emoji_status).document_id = documentId; + emojiStatus = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) emojiStatus).document_id = documentId; } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + MessagesController.getInstance(currentAccount).updateEmojiStatus(emojiStatus); + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); if (user != null) { - user.emoji_status = req.emoji_status; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userEmojiStatusUpdated, user); - MessagesController.getInstance(currentAccount).updateEmojiStatusUntilUpdate(user.id, user.emoji_status); for (int i = 0; i < sideMenu.getChildCount(); ++i) { View child = sideMenu.getChildAt(i); if (child instanceof DrawerUserCell) { @@ -1154,11 +1165,6 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } } } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (!(res instanceof TLRPC.TL_boolTrue)) { - // TODO: reject - } - }); if (popup[0] != null) { selectAnimatedEmojiDialog = null; popup[0].dismiss(); @@ -1318,6 +1324,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (drawerLayoutAdapter != null) { drawerLayoutAdapter.notifyDataSetChanged(); } + RestrictedLanguagesSelectActivity.checkRestrictedLanguages(true); clearFragments(); actionBarLayout.rebuildLogout(); if (AndroidUtilities.isTablet()) { @@ -1519,7 +1526,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (messageObject != null && messageObject.isRoundVideo()) { MediaController.getInstance().cleanupPlayer(true, true); } - passcodeView.onShow(fingerprint, animated, x, y, () -> { + passcodeView.onShow(overlayPasscodeViews.isEmpty() && fingerprint, animated, x, y, () -> { actionBarLayout.getView().setVisibility(View.INVISIBLE); if (AndroidUtilities.isTablet()) { if (layersActionBarLayout != null && layersActionBarLayout.getView() != null && layersActionBarLayout.getView().getVisibility() == View.VISIBLE) { @@ -1533,9 +1540,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati onShow.run(); } }, onStart); + for (int i = 0; i < overlayPasscodeViews.size(); i++) { + PasscodeView overlay = overlayPasscodeViews.get(i); + overlay.onShow(fingerprint && i == overlayPasscodeViews.size() - 1, animated, x, y, null, null); + } SharedConfig.isWaitingForPasscodeEnter = true; drawerLayoutContainer.setAllowOpenDrawer(false, false); - passcodeView.setDelegate(() -> { + PasscodeView.PasscodeViewDelegate delegate = view -> { SharedConfig.isWaitingForPasscodeEnter = false; if (passcodeSaveIntent != null) { handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true); @@ -1552,7 +1563,16 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } rightActionBarLayout.getView().setVisibility(View.VISIBLE); } - }); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.passcodeDismissed, view); + }; + passcodeView.setDelegate(delegate); + for (PasscodeView overlay : overlayPasscodeViews) { + overlay.setDelegate(delegate); + } + } + + public boolean allowShowFingerprintDialog(PasscodeView passcodeView) { + return overlayPasscodeViews.isEmpty() ? passcodeView == this.passcodeView : overlayPasscodeViews.get(overlayPasscodeViews.size() - 1) == passcodeView; } private boolean handleIntent(Intent intent, boolean isNew, boolean restore, boolean fromPassword) { @@ -2522,7 +2542,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati req.hash = phoneHash; req.settings = new TLRPC.TL_codeSettings(); req.settings.allow_flashcall = false; - req.settings.allow_app_hash = PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices(); + req.settings.allow_app_hash = req.settings.allow_firebase = PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices(); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); if (req.settings.allow_app_hash) { preferences.edit().putString("sms_hash", BuildVars.SMS_HASH).apply(); @@ -2671,12 +2691,19 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (push_topic_id > 0) { TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(push_chat_id, push_topic_id); + FileLog.d(push_chat_id + " " + push_topic_id + " TL_forumTopic " + topic); if (topic != null) { TLRPC.Message message = topic.topicStartMessage; ArrayList messageObjects = new ArrayList<>(); TLRPC.Chat chatLocal = MessagesController.getInstance(currentAccount).getChat(push_chat_id); messageObjects.add(new MessageObject(currentAccount, message, false, false)); fragment.setThreadMessages(messageObjects, chatLocal, topic.id, topic.read_inbox_max_id, topic.read_outbox_max_id, topic); + } else { + boolean finalIsNew = isNew; + MessagesController.getInstance(currentAccount).getTopicsController().loadTopic(push_chat_id, push_topic_id, () -> { + handleIntent(intent, finalIsNew, restore, fromPassword, progress); + }); + return true; } } if (actionBarLayout.presentFragment(new INavigationLayout.NavigationParams(fragment).setNoAnimation(true))) { @@ -2990,7 +3017,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putBoolean("canSelectTopics", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putBoolean("allowSwitchAccount", true); if (contactsToSend != null) { if (contactsToSend.size() != 1) { @@ -3198,16 +3225,16 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati args.putBoolean("allowSwitchAccount", true); if (res.pm) { - args.putInt("dialogsType", 12); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS); } else if (res.group) { - args.putInt("dialogsType", 11); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS); } else { String uri = importUri.toString(); Set uris = MessagesController.getInstance(intentAccount).exportPrivateUri; boolean ok = false; for (String u : uris) { if (uri.contains(u)) { - args.putInt("dialogsType", 12); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS); ok = true; break; } @@ -3216,13 +3243,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati uris = MessagesController.getInstance(intentAccount).exportGroupUri; for (String u : uris) { if (uri.contains(u)) { - args.putInt("dialogsType", 11); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS); ok = true; break; } } if (!ok) { - args.putInt("dialogsType", 13); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY); } } } @@ -3498,6 +3525,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); actionBarLayout.presentFragment(new ChatActivity(args1), true, false, true, false); } + return true; }); } else { dialogsActivity = null; @@ -3560,7 +3588,6 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati allowWrite.set(allow); }); - builder.setCustomViewOffset(12); builder.setView(cell); } builder.show(); @@ -3584,7 +3611,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putBoolean("cantSendToChannels", true); - args.putInt("dialogsType", 1); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_BOT_SHARE); args.putString("selectAlertString", LocaleController.getString("SendGameToText", R.string.SendGameToText)); args.putString("selectAlertStringGroup", LocaleController.getString("SendGameToGroupText", R.string.SendGameToGroupText)); DialogsActivity fragment = new DialogsActivity(args); @@ -3609,6 +3636,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); actionBarLayout.presentFragment(new ChatActivity(args1), true, false, true, false); } + return true; }); boolean removeLast; if (AndroidUtilities.isTablet()) { @@ -3648,7 +3676,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 2); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO); args.putBoolean("resetDelegate", false); args.putBoolean("closeFragment", false); args.putBoolean("allowGroups", botChat != null); @@ -3779,6 +3807,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati }); builder.show(); } + return true; }); presentFragment(fragment); } else { @@ -4132,7 +4161,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } else if (message != null) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment13, dids, m, param) -> { long did = dids.get(0).dialogId; @@ -4151,6 +4180,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati MediaDataController.getInstance(intentAccount).saveDraft(did, 0, message, null, null, false); actionBarLayout.presentFragment(new ChatActivity(args13), true, false, true, false); } + return true; }); presentFragment(fragment, false, true); } else if (auth != null) { @@ -4891,7 +4921,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } @Override - public void didSelectDialogs(DialogsActivity dialogsFragment, ArrayList dids, CharSequence message, boolean param) { + public boolean didSelectDialogs(DialogsActivity dialogsFragment, ArrayList dids, CharSequence message, boolean param) { final int account = dialogsFragment != null ? dialogsFragment.getCurrentAccount() : currentAccount; if (exportingChatUri != null) { @@ -4951,7 +4981,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati args.putLong("chat_id", -did); } if (!MessagesController.getInstance(account).checkCanOpenChat(args, dialogsFragment)) { - return; + return false; } fragment = new ChatActivity(args); ForumUtilities.applyTopic(fragment, dids.get(0)); @@ -4982,7 +5012,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati for (int i = 0; i < dids.size(); i++) { final long did = dids.get(i).dialogId; if (AlertsCreator.checkSlowMode(this, currentAccount, did, attachesCount > 1)) { - return; + return false; } } @@ -5082,6 +5112,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati contactsToSend = null; contactsToSendUri = null; exportingChatUri = null; + return true; } private void onFinish() { @@ -5282,6 +5313,9 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (passcodeView != null) { passcodeView.onPause(); } + for (PasscodeView overlay : overlayPasscodeViews) { + overlay.onPause(); + } ConnectionsManager.getInstance(currentAccount).setAppPaused(true, false); if (PhotoViewer.hasInstance() && PhotoViewer.getInstance().isVisible()) { PhotoViewer.getInstance().onPause(); @@ -5425,6 +5459,10 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } } passcodeView.onResume(); + + for (PasscodeView overlay : overlayPasscodeViews) { + overlay.onResume(); + } } ConnectionsManager.getInstance(currentAccount).setAppPaused(false, false); updateCurrentConnectionState(currentAccount); @@ -5595,8 +5633,28 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati builder.setMessage(LocaleController.getString("NobodyLikesSpam2", R.string.NobodyLikesSpam2)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); } else if (reason == 2) { - builder.setMessage((String) args[1]); + SpannableStringBuilder span = SpannableStringBuilder.valueOf((String) args[1]); String type = (String) args[2]; + if (type.startsWith("PREMIUM_GIFT_SELF_REQUIRED_")) { + String msg = (String) args[1]; + int start = msg.indexOf('*'), end = msg.indexOf('*', start + 1); + if (start != -1 && end != -1 && start != end) { + span.replace(start, end + 1, msg.substring(start + 1, end)); + span.setSpan(new ClickableSpan() { + @Override + public void onClick(@NonNull View widget) { + getActionBarLayout().presentFragment(new PremiumPreviewFragment("gift")); + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }, start, end - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + builder.setMessage(span); if (type.startsWith("AUTH_KEY_DROP_")) { builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.setNegativeButton(LocaleController.getString("LogOut", R.string.LogOut), (dialog, which) -> MessagesController.getInstance(currentAccount).performLogout(2)); @@ -6465,6 +6523,14 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati SharedConfig.saveConfig(); } + public void addOverlayPasscodeView(PasscodeView overlay) { + overlayPasscodeViews.add(overlay); + } + + public void removeOverlayPasscodeView(PasscodeView overlay) { + overlayPasscodeViews.remove(overlay); + } + private void onPasscodeResume() { if (lockRunnable != null) { if (BuildVars.LOGS_ENABLED) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index 55664a5a4..94f4dd900 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -40,13 +40,16 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Looper; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.text.Editable; import android.text.InputType; +import android.text.Layout; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.SpannedString; import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; @@ -89,10 +92,14 @@ import com.google.android.gms.auth.api.signin.GoogleSignInAccount; import com.google.android.gms.auth.api.signin.GoogleSignInClient; import com.google.android.gms.auth.api.signin.GoogleSignInOptions; import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.safetynet.SafetyNet; +import org.json.JSONException; +import org.json.JSONObject; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.AuthTokensHelper; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; @@ -134,6 +141,8 @@ import org.telegram.ui.Components.Easings; import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LoadingDrawable; import org.telegram.ui.Components.LoginOrView; import org.telegram.ui.Components.OutlineTextContainerView; import org.telegram.ui.Components.RLottieDrawable; @@ -153,6 +162,7 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -321,6 +331,8 @@ public class LoginActivity extends BaseFragment { private Runnable[] editDoneCallback = new Runnable[2]; private boolean[] postedEditDoneCallback = new boolean[2]; + private boolean forceDisableSafetyNet; + private static class ProgressView extends View { private final Path path = new Path(); @@ -1259,6 +1271,10 @@ public class LoginActivity extends BaseFragment { if (animated && doneProgressVisible[currentDoneType] == show && !fromCallback) { return; } + if (Looper.myLooper() != Looper.getMainLooper()) { + AndroidUtilities.runOnUIThread(() -> showEditDoneProgress(show, animated, fromCallback)); + return; + } boolean floating = currentDoneType == DONE_TYPE_FLOATING; if (!fromCallback && !floating) { @@ -1550,6 +1566,7 @@ public class LoginActivity extends BaseFragment { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); LocaleController.getInstance().loadRemoteLanguages(currentAccount); + RestrictedLanguagesSelectActivity.checkRestrictedLanguages(true); } } else if (getParentActivity() instanceof ExternalActionActivity) { ((ExternalActionActivity) getParentActivity()).onFinishLogin(); @@ -1577,6 +1594,12 @@ public class LoginActivity extends BaseFragment { MessagesController.getInstance(currentAccount).checkPromoInfo(true); ConnectionsManager.getInstance(currentAccount).updateDcSettings(); + if (res.future_auth_token != null) { + AuthTokensHelper.saveLogInToken(res); + } else { + FileLog.d("onAuthSuccess future_auth_token is empty"); + } + if (afterSignup) { MessagesController.getInstance(currentAccount).putDialogsEndReachedAfterRegistration(); } @@ -1591,11 +1614,106 @@ public class LoginActivity extends BaseFragment { setPage(VIEW_CODE_EMAIL_SETUP, true, params, false); } - private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res) { + private void fillNextCodeParams(Bundle params, TLRPC.auth_SentCode res) { fillNextCodeParams(params, res, true); } - private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res, boolean animate) { + private void resendCodeFromSafetyNet(Bundle params, TLRPC.auth_SentCode res) { + needHideProgress(false); + isRequestingFirebaseSms = false; + + TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); + req.phone_number = params.getString("phoneFormated"); + req.phone_code_hash = res.phone_code_hash; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + AndroidUtilities.runOnUIThread(() -> fillNextCodeParams(params, (TLRPC.auth_SentCode) response)); + } else { + AndroidUtilities.runOnUIThread(() -> { + if (getParentActivity() == null || getParentActivity().isFinishing() || getContext() == null) { + return; + } + new AlertDialog.Builder(getContext()) + .setTitle(LocaleController.getString(R.string.RestorePasswordNoEmailTitle)) + .setMessage(LocaleController.getString(R.string.SafetyNetErrorOccurred)) + .setPositiveButton(LocaleController.getString(R.string.OK), (dialog, which) -> { + forceDisableSafetyNet = true; + if (currentViewNum != VIEW_PHONE_INPUT) { + setPage(VIEW_PHONE_INPUT, true, null, true); + } + }) + .show(); + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } + + private boolean isRequestingFirebaseSms; + private void fillNextCodeParams(Bundle params, TLRPC.auth_SentCode res, boolean animate) { + if (res.type instanceof TLRPC.TL_auth_sentCodeTypeFirebaseSms && !res.type.verifiedFirebase && !isRequestingFirebaseSms) { + if (PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices()) { + needShowProgress(0); + isRequestingFirebaseSms = true; + SafetyNet.getClient(ApplicationLoader.applicationContext).attest(res.type.nonce, BuildVars.SAFETYNET_KEY) + .addOnSuccessListener(attestationResponse -> { + String jws = attestationResponse.getJwsResult(); + + if (jws != null) { + TLRPC.TL_auth_requestFirebaseSms req = new TLRPC.TL_auth_requestFirebaseSms(); + req.phone_number = params.getString("phoneFormated"); + req.phone_code_hash = res.phone_code_hash; + req.safety_net_token = jws; + req.flags |= 1; + + String[] spl = jws.split("\\."); + if (spl.length > 0) { + try { + JSONObject obj = new JSONObject(new String(Base64.decode(spl[1].getBytes(StandardCharsets.UTF_8), 0))); + + if (obj.optBoolean("basicIntegrity") && obj.optBoolean("ctsProfileMatch")) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + needHideProgress(false); + isRequestingFirebaseSms = false; + if (response instanceof TLRPC.TL_boolTrue) { + res.type.verifiedFirebase = true; + AndroidUtilities.runOnUIThread(() -> fillNextCodeParams(params, res, animate)); + } else { + FileLog.d("Resend firebase sms because auth.requestFirebaseSms = false"); + resendCodeFromSafetyNet(params, res); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } else { + FileLog.d("Resend firebase sms because ctsProfileMatch or basicIntegrity = false"); + resendCodeFromSafetyNet(params, res); + } + } catch (JSONException e) { + FileLog.e(e); + + FileLog.d("Resend firebase sms because of exception"); + resendCodeFromSafetyNet(params, res); + } + } else { + FileLog.d("Resend firebase sms because can't split JWS token"); + resendCodeFromSafetyNet(params, res); + } + } else { + FileLog.d("Resend firebase sms because JWS = null"); + resendCodeFromSafetyNet(params, res); + } + }) + .addOnFailureListener(e -> { + FileLog.e(e); + + FileLog.d("Resend firebase sms because of safetynet exception"); + resendCodeFromSafetyNet(params, res); + }); + } else { + FileLog.d("Resend firebase sms because firebase is not available"); + resendCodeFromSafetyNet(params, res); + } + return; + } + params.putString("phoneHash", res.phone_code_hash); if (res.next_type instanceof TLRPC.TL_auth_codeTypeCall) { params.putInt("nextType", AUTH_TYPE_CALL); @@ -1625,9 +1743,10 @@ public class LoginActivity extends BaseFragment { params.putInt("type", AUTH_TYPE_FLASH_CALL); params.putString("pattern", res.type.pattern); setPage(VIEW_CODE_FLASH_CALL, animate, params, false); - } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeSms) { + } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeSms || res.type instanceof TLRPC.TL_auth_sentCodeTypeFirebaseSms) { params.putInt("type", AUTH_TYPE_SMS); params.putInt("length", res.type.length); + params.putBoolean("firebase", res.type instanceof TLRPC.TL_auth_sentCodeTypeFirebaseSms); setPage(VIEW_CODE_SMS, animate, params, false); } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeFragmentSms) { params.putInt("type", AUTH_TYPE_FRAGMENT_SMS); @@ -1860,6 +1979,9 @@ public class LoginActivity extends BaseFragment { if (c.code.startsWith(text)) { matchedCountries++; if (c.code.equals(text)) { + if (lastMatchedCountry != null && lastMatchedCountry.code.equals(c.code)) { + matchedCountries--; + } lastMatchedCountry = c; } } @@ -2126,7 +2248,7 @@ public class LoginActivity extends BaseFragment { }); } - if (BuildVars.DEBUG_PRIVATE_VERSION && activityMode == MODE_LOGIN) { + if (BuildVars.DEBUG_VERSION && activityMode == MODE_LOGIN) { testBackendCheckBox = new CheckBoxCell(context, 2); testBackendCheckBox.setText(LocaleController.getString(R.string.DebugTestBackend), "", testBackend, false); addView(testBackendCheckBox, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 16, 0, 16 + (LocaleController.isRTL && AndroidUtilities.isSmallScreen() ? Build.VERSION.SDK_INT >= 21 ? 56 : 60 : 0), 0)); @@ -2139,7 +2261,7 @@ public class LoginActivity extends BaseFragment { testBackend = !testBackend; cell.setChecked(testBackend, true); - boolean testBackend = BuildVars.DEBUG_PRIVATE_VERSION && getConnectionsManager().isTestBackend(); + boolean testBackend = BuildVars.DEBUG_VERSION && getConnectionsManager().isTestBackend(); if (testBackend != LoginActivity.this.testBackend) { getConnectionsManager().switchBackend(false); } @@ -2226,7 +2348,7 @@ public class LoginActivity extends BaseFragment { private void loadCountries() { TLRPC.TL_help_getCountriesList req = new TLRPC.TL_help_getCountriesList(); - req.lang_code = ""; + req.lang_code = LocaleController.getInstance().getCurrentLocaleInfo() != null ? LocaleController.getInstance().getCurrentLocaleInfo().getLangCode() : Locale.getDefault().getCountry(); getConnectionsManager().sendRequest(req, (response, error) -> { AndroidUtilities.runOnUIThread(() -> { if (error == null) { @@ -2241,7 +2363,11 @@ public class LoginActivity extends BaseFragment { TLRPC.TL_help_countryCode countryCode = c.country_codes.get(k); if (countryCode != null) { CountrySelectActivity.Country countryWithCode = new CountrySelectActivity.Country(); - countryWithCode.name = c.default_name; + countryWithCode.name = c.name; + countryWithCode.defaultName = c.default_name; + if (countryWithCode.name == null && countryWithCode.defaultName != null) { + countryWithCode.name = countryWithCode.defaultName; + } countryWithCode.code = countryCode.country_code; countryWithCode.shortname = c.iso2; @@ -2491,7 +2617,7 @@ public class LoginActivity extends BaseFragment { @Override public void onNextPressed(String code) { - if (getParentActivity() == null || nextPressed) { + if (getParentActivity() == null || nextPressed || isRequestingFirebaseSms) { return; } @@ -2707,17 +2833,41 @@ public class LoginActivity extends BaseFragment { TLRPC.TL_codeSettings settings = new TLRPC.TL_codeSettings(); settings.allow_flashcall = simcardAvailable && allowCall && allowCancelCall && allowReadCallLog; settings.allow_missed_call = simcardAvailable && allowCall; - settings.allow_app_hash = PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices(); + settings.allow_app_hash = settings.allow_firebase = PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices(); + if (forceDisableSafetyNet || TextUtils.isEmpty(BuildVars.SAFETYNET_KEY)) { + settings.allow_firebase = false; + } - ArrayList tokens = MessagesController.getSavedLogOutTokens(); + ArrayList loginTokens = AuthTokensHelper.getSavedLogInTokens(); + if (loginTokens != null) { + for (int i = 0; i < loginTokens.size(); i++) { + if (loginTokens.get(i).future_auth_token == null) { + continue; + } + if (settings.logout_tokens == null) { + settings.logout_tokens = new ArrayList<>(); + } + if (BuildVars.DEBUG_VERSION) { + FileLog.d("login token to check " + new String(loginTokens.get(i).future_auth_token, StandardCharsets.UTF_8)); + } + settings.logout_tokens.add(loginTokens.get(i).future_auth_token); + if (settings.logout_tokens.size() >= 20) { + break; + } + } + } + ArrayList tokens = AuthTokensHelper.getSavedLogOutTokens(); if (tokens != null) { for (int i = 0; i < tokens.size(); i++) { if (settings.logout_tokens == null) { settings.logout_tokens = new ArrayList<>(); } settings.logout_tokens.add(tokens.get(i).future_auth_token); + if (settings.logout_tokens.size() >= 20) { + break; + } } - MessagesController.saveLogOutTokens(tokens); + AuthTokensHelper.saveLogOutTokens(tokens); } if (settings.logout_tokens != null) { settings.flags |= 64; @@ -2784,7 +2934,21 @@ public class LoginActivity extends BaseFragment { int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; if (error == null) { - fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); + + if (response instanceof TLRPC.TL_auth_sentCodeSuccess) { + TLRPC.auth_Authorization auth = ((TLRPC.TL_auth_sentCodeSuccess) response).authorization; + if (auth instanceof TLRPC.TL_auth_authorizationSignUpRequired) { + TLRPC.TL_auth_authorizationSignUpRequired authorization = (TLRPC.TL_auth_authorizationSignUpRequired) response; + if (authorization.terms_of_service != null) { + currentTermsOfService = authorization.terms_of_service; + } + setPage(VIEW_REGISTER, true, params, false); + } else { + onAuthSuccess((TLRPC.TL_auth_authorization) auth); + } + } else { + fillNextCodeParams(params, (TLRPC.auth_SentCode) response); + } } else { if (error.text != null) { if (error.text.contains("SESSION_PASSWORD_NEEDED")) { @@ -2827,7 +2991,9 @@ public class LoginActivity extends BaseFragment { } } } - needHideProgress(false); + if (!isRequestingFirebaseSms) { + needHideProgress(false); + } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagTryDifferentDc | ConnectionsManager.RequestFlagEnableUnauthorized); needShowProgress(reqId); } @@ -3070,6 +3236,8 @@ public class LoginActivity extends BaseFragment { @AuthType private int nextType; + private boolean isResendingCode = false; + private String pattern = "*"; private String prefix = ""; private String catchedPhone; @@ -3234,13 +3402,81 @@ public class LoginActivity extends BaseFragment { problemFrame = new FrameLayout(context); - timeText = new TextView(context); + timeText = new TextView(context) { + private LoadingDrawable loadingDrawable = new LoadingDrawable(); + + { + loadingDrawable.setAppearByGradient(true); + } + + @Override + public void setText(CharSequence text, BufferType type) { + super.setText(text, type); + + updateLoadingLayout(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + updateLoadingLayout(); + } + + private void updateLoadingLayout() { + Layout layout = getLayout(); + if (layout == null) { + return; + } + CharSequence text = layout.getText(); + if (text == null) { + return; + } + LinkPath path = new LinkPath(true); + int start = 0; + int end = text.length(); + path.setCurrentLayout(layout, start, 0); + layout.getSelectionPath(start, end, path); + loadingDrawable.usePath(path); + loadingDrawable.setRadiiDp(4); + + int color = getThemedColor(Theme.key_chat_linkSelectBackground); + loadingDrawable.setColors( + Theme.multAlpha(color, 0.85f), + Theme.multAlpha(color, 2f), + Theme.multAlpha(color, 3.5f), + Theme.multAlpha(color, 6f) + ); + + loadingDrawable.updateBounds(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isResendingCode) { + canvas.save(); + canvas.translate(getPaddingLeft(), getPaddingTop()); + loadingDrawable.draw(canvas); + canvas.restore(); + invalidate(); + } + } + }; timeText.setLineSpacing(AndroidUtilities.dp(2), 1.0f); - timeText.setPadding(0, AndroidUtilities.dp(2), 0, AndroidUtilities.dp(10)); + timeText.setPadding(AndroidUtilities.dp(6), AndroidUtilities.dp(8), AndroidUtilities.dp(6), AndroidUtilities.dp(16)); timeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); timeText.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); timeText.setOnClickListener(v-> { - if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS || nextType == AUTH_TYPE_MISSED_CALL) { + if (isRequestingFirebaseSms || isResendingCode) { + return; + } + isResendingCode = true; + timeText.invalidate(); + timeText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteValueText)); + + if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS || nextType == AUTH_TYPE_MISSED_CALL || nextType == AUTH_TYPE_FRAGMENT_SMS) { timeText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_MISSED_CALL) { timeText.setText(LocaleController.getString("Calling", R.string.Calling)); @@ -3362,7 +3598,7 @@ public class LoginActivity extends BaseFragment { if (currentType != AUTH_TYPE_FRAGMENT_SMS) { problemText.setOnClickListener(v -> { - if (nextPressed) { + if (nextPressed || timeText.getVisibility() != View.GONE) { return; } boolean email = nextType == 0; @@ -3449,6 +3685,14 @@ public class LoginActivity extends BaseFragment { } private void resendCode() { + if (nextPressed) { + return; + } + + isResendingCode = true; + timeText.invalidate(); + problemText.invalidate(); + final Bundle params = new Bundle(); params.putString("phone", phone); params.putString("ephone", emailPhone); @@ -5391,6 +5635,10 @@ public class LoginActivity extends BaseFragment { resendCodeView.setMaxLines(2); resendCodeView.setText(LocaleController.getString(R.string.ResendCode)); resendCodeView.setOnClickListener(v -> { + if (resendCodeView.getVisibility() != View.VISIBLE || resendCodeView.getAlpha() != 1f) { + return; + } + showResendCodeView(false); TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); @@ -6593,7 +6841,7 @@ public class LoginActivity extends BaseFragment { setOrientation(VERTICAL); - imageUpdater = new ImageUpdater(false); + imageUpdater = new ImageUpdater(false, ImageUpdater.FOR_TYPE_USER, false); imageUpdater.setOpenWithFrontfaceCamera(true); imageUpdater.setSearchAvailable(false); imageUpdater.setUploadAfterSelect(false); @@ -6894,7 +7142,7 @@ public class LoginActivity extends BaseFragment { } @Override - public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { avatar = smallSize.location; avatarBig = bigSize.location; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java index 6bcf59d8b..5a2b889ff 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java @@ -40,6 +40,7 @@ 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.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.BaseFragment; @@ -104,6 +105,7 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On public NewContactBottomSheet(BaseFragment parentFragment, Context context) { super(context, true); + waitingKeyboard = true; smoothKeyboardAnimationEnabled = true; classGuid = ConnectionsManager.generateClassGuid(); this.parentFragment = parentFragment; @@ -628,7 +630,6 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On plusTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); codeDividerView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputField)); - return fragmentView; } @@ -699,7 +700,7 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On firstNameField.getEditText().requestFocus(); AndroidUtilities.runOnUIThread(() -> { AndroidUtilities.showKeyboard(firstNameField.getEditText()); - }, 200); + }, 50); } private void showEditDoneProgress(boolean show, boolean animated) { @@ -740,6 +741,27 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On public void setInitialPhoneNumber(String value, boolean withCoutryCode) { initialPhoneNumber = value; initialPhoneNumberWithCountryCode = withCoutryCode; + + if (!TextUtils.isEmpty(initialPhoneNumber)) { + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); + if (initialPhoneNumber.startsWith("+")) { + codeField.setText(initialPhoneNumber.substring(1)); + } else if (initialPhoneNumberWithCountryCode || user == null || TextUtils.isEmpty(user.phone)) { + codeField.setText(initialPhoneNumber); + } else { + String phone = user.phone; + for (int a = 4; a >= 1; a--) { + String sub = phone.substring(0, a); + List country = codesMap.get(sub); + if (country != null && country.size() > 0) { + codeField.setText(country.get(0).code); + break; + } + } + phoneField.setText(initialPhoneNumber); + } + initialPhoneNumber = null; + } } public void setInitialName(String firstName, String lastName) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java index b89a03f51..05f1a3e44 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java @@ -397,11 +397,11 @@ public class NotificationsCustomSettingsActivity extends BaseFragment implements args.putBoolean("onlySelect", true); args.putBoolean("checkCanWrite", false); if (currentType == NotificationsController.TYPE_GROUP) { - args.putInt("dialogsType", 6); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY); } else if (currentType == NotificationsController.TYPE_CHANNEL) { - args.putInt("dialogsType", 5); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); } else { - args.putInt("dialogsType", 4); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_USERS_ONLY); } DialogsActivity activity = new DialogsActivity(args); activity.setDelegate((fragment, dids, message, param) -> { @@ -414,6 +414,7 @@ public class NotificationsCustomSettingsActivity extends BaseFragment implements updateRows(true); }); presentFragment(profileNotificationsActivity, true); + return true; }); presentFragment(activity); } else if (position == deleteAllRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 38e5b1ece..4772d679d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -67,6 +67,7 @@ import android.transition.TransitionManager; import android.transition.TransitionSet; import android.transition.TransitionValues; import android.util.FloatProperty; +import android.util.Log; import android.util.Property; import android.util.Range; import android.util.SparseArray; @@ -3327,13 +3328,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imagesArrLocationsVideo.clear(); imagesArrMessages.clear(); avatarsArr.clear(); + for (int a = 0; a < photos.size(); a++) { TLRPC.Photo photo = photos.get(a); if (photo == null || photo instanceof TLRPC.TL_photoEmpty || photo.sizes == null) { continue; } TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 640); - TLRPC.VideoSize videoSize = photo.video_sizes.isEmpty() ? null : photo.video_sizes.get(0); + TLRPC.VideoSize videoSize = photo.video_sizes.isEmpty() ? null : FileLoader.getClosestVideoSizeWithSize(photo.video_sizes, 1000); if (sizeFull != null) { if (setToImage == -1 && currentFileLocation != null) { for (int b = 0; b < photo.sizes.size(); b++) { @@ -3344,6 +3346,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } } + if (setToImage == -1 && currentFileLocation != null) { + for (int b = 0; b < photo.video_sizes.size(); b++) { + TLRPC.VideoSize size = photo.video_sizes.get(b); + if (size.location != null && size.location.local_id == currentFileLocation.location.local_id && size.location.volume_id == currentFileLocation.location.volume_id) { + setToImage = imagesArrLocations.size(); + break; + } + } + } if (photo.dc_id != 0) { sizeFull.location.dc_id = photo.dc_id; sizeFull.location.file_reference = photo.file_reference; @@ -4353,7 +4364,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); final ArrayList fmessages = new ArrayList<>(); fmessages.add(currentMessageObject); @@ -4394,6 +4405,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat fragment1.finishFragment(); } } + return true; }); ((LaunchActivity) parentActivity).presentFragment(fragment, false, true); closePhoto(false, false); @@ -4526,7 +4538,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (avatarsDialogId > 0) { MessagesController.getInstance(currentAccount).deleteUserPhoto(null); } else { - MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, null, null, null, 0, null, null, null, null); + MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, null, null, null, null, 0, null, null, null, null); } closePhoto(false, false); } else { @@ -4740,7 +4752,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat inputChatPhoto.id.id = photo.id; inputChatPhoto.id.access_hash = photo.access_hash; inputChatPhoto.id.file_reference = photo.file_reference; - MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, inputChatPhoto, null, null, 0, null, null, null, null); + MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, inputChatPhoto, null, null, null, 0, null, null, null, null); chat.photo.dc_id = photo.dc_id; chat.photo.photo_small = smallSize.location; chat.photo.photo_big = bigSize.location; @@ -5602,7 +5614,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else if (a == 3) { cell.setTextAndIcon(LocaleController.getString("SendAsNewPhoto", R.string.SendAsNewPhoto), R.drawable.msg_send); } else if (a == 4) { - cell.setTextAndIcon(LocaleController.getString("SendWithoutCompression", R.string.SendWithoutCompression), R.drawable.msg_sendfile); + if (placeProvider != null && placeProvider.getSelectedCount() > 1) { + cell.setTextAndIcon(LocaleController.getString(R.string.SendAsFiles), R.drawable.msg_sendfile); + } else { + cell.setTextAndIcon(LocaleController.getString(R.string.SendAsFile), R.drawable.msg_sendfile); + } } cell.setMinimumWidth(AndroidUtilities.dp(196)); cell.setColors(0xffffffff, 0xffffffff); @@ -6727,6 +6743,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ((MediaController.MediaEditState) entry).editedInfo = videoEditedInfo; } } + if (parentChatActivity != null && parentChatActivity.getCurrentChat() != null) { + boolean isVideo = (isCurrentVideo || videoEditedInfo != null); + if (isVideo && !ChatObject.canSendVideo(parentChatActivity.getCurrentChat())) { + BulletinFactory.of(containerView, resourcesProvider).createErrorBulletin(LocaleController.getString(R.string.GlobalAttachVideoRestricted)).show(); + return; + } + if (!isVideo && !ChatObject.canSendPhoto(parentChatActivity.getCurrentChat())) { + BulletinFactory.of(containerView, resourcesProvider).createErrorBulletin(LocaleController.getString(R.string.GlobalAttachPhotoRestricted)).show(); + return; + } + } doneButtonPressed = true; if (videoEditedInfo != null) { long sizeToCheck = (long) (videoEditedInfo.estimatedSize * 0.9f); @@ -7141,14 +7168,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat videoTextureView.setTranslationX(fromX * (1f - xValue) + (toX2) * xValue); videoTextureView.setTranslationY(fromY * (1f - yValue) + (toY2) * yValue); videoTextureView.invalidateOutline(); - } - if (firstFrameView != null) { - firstFrameView.setTranslationX(videoTextureView.getTranslationX()); - firstFrameView.setTranslationY(videoTextureView.getTranslationY()); - firstFrameView.setScaleX(videoTextureView.getScaleX()); - firstFrameView.setScaleY(videoTextureView.getScaleY()); - firstFrameView.invalidateOutline(); + if (firstFrameView != null) { + firstFrameView.setTranslationX(videoTextureView.getTranslationX()); + firstFrameView.setTranslationY(videoTextureView.getTranslationY()); + firstFrameView.setScaleX(videoTextureView.getScaleX()); + firstFrameView.setScaleY(videoTextureView.getScaleY()); + firstFrameView.invalidateOutline(); + } } }); @@ -7914,12 +7941,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat videoPlayerTotalTime[1] = (int) (total % 60); } String current, total; - if (videoPlayerCurrentTime[0] > 60) { + if (videoPlayerCurrentTime[0] >= 60) { current = String.format(Locale.ROOT, "%02d:%02d:%02d", videoPlayerCurrentTime[0] / 60, videoPlayerCurrentTime[0] % 60, videoPlayerCurrentTime[1]); } else { current = String.format(Locale.ROOT, "%02d:%02d", videoPlayerCurrentTime[0], videoPlayerCurrentTime[1]); } - if (videoPlayerTotalTime[0] > 60) { + if (videoPlayerTotalTime[0] >= 60) { total = String.format(Locale.ROOT, "%02d:%02d:%02d", videoPlayerTotalTime[0] / 60, videoPlayerTotalTime[0] % 60, videoPlayerTotalTime[1]); } else { total = String.format(Locale.ROOT, "%02d:%02d", videoPlayerTotalTime[0], videoPlayerTotalTime[1]); @@ -11449,7 +11476,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } private boolean canSendMediaToParentChatActivity() { - return parentChatActivity != null && (parentChatActivity.currentUser != null || parentChatActivity.currentChat != null && !ChatObject.isNotInChat(parentChatActivity.currentChat) && ChatObject.canSendMedia(parentChatActivity.currentChat)); + return parentChatActivity != null && (parentChatActivity.currentUser != null || parentChatActivity.currentChat != null && !ChatObject.isNotInChat(parentChatActivity.currentChat) && (ChatObject.canSendPhoto(parentChatActivity.currentChat) || ChatObject.canSendVideo(parentChatActivity.currentChat))); } private void setDoubleTapEnabled(boolean value) { @@ -11496,6 +11523,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } newMessageObject = imagesArr.get(switchingToIndex); + newMessageObject.updateTranslation(); isVideo = newMessageObject.isVideo(); boolean isInvoice = newMessageObject.isInvoice(); boolean noforwards = MessagesController.getInstance(currentAccount).isChatNoForwards(newMessageObject.getChatId()) || (newMessageObject.messageOwner != null && newMessageObject.messageOwner.noforwards) || newMessageObject.hasRevealedExtendedMedia(); @@ -12134,6 +12162,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } MessageObject newMessageObject = imagesArr.get(currentIndex); sameImage = init && currentMessageObject != null && currentMessageObject.getId() == newMessageObject.getId(); + if (sameImage) { + newMessageObject.putInDownloadsStore = currentMessageObject.putInDownloadsStore; + } currentMessageObject = newMessageObject; isVideo = newMessageObject.isVideo(); if (sharedMediaType == MediaDataController.MEDIA_FILE) { @@ -14672,6 +14703,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (doneButtonPressed) { releasePlayer(true); } + if (currentMessageObject != null && !currentMessageObject.putInDownloadsStore) { + FileLoader.getInstance(currentAccount).cancelLoadFile(currentMessageObject.getDocument()); + } isVisible = false; cropInitied = false; disableShowCheck = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java index 6ea2e3d4c..08b0a7c26 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java @@ -750,7 +750,9 @@ public class PinchToZoomHelper { invalidateViews(); } else if ((ev.getActionMasked() == MotionEvent.ACTION_UP || (ev.getActionMasked() == MotionEvent.ACTION_POINTER_UP && checkPointerIds(ev)) || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) && isInPinchToZoomTouchMode) { isInPinchToZoomTouchMode = false; - child.getParent().requestDisallowInterceptTouchEvent(false); + if (child != null && child.getParent() != null) { + child.getParent().requestDisallowInterceptTouchEvent(false); + } finishZoom(); } return isInOverlayModeFor(child); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java index 63b1511c0..4cd90b5bb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -2,6 +2,7 @@ package org.telegram.ui; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; @@ -95,14 +96,17 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Objects; public class PremiumPreviewFragment extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { - private final static boolean IS_PREMIUM_TIERS_UNAVAILABLE = true; + public final static String TRANSACTION_PATTERN = "^(.*?)(?:\\.\\.\\d*|)$"; + private final static boolean IS_PREMIUM_TIERS_UNAVAILABLE = false; RecyclerListView listView; ArrayList premiumFeatures = new ArrayList<>(); ArrayList subscriptionTiers = new ArrayList<>(); int selectedTierIndex = 0; + SubscriptionTier currentSubscriptionTier; int rowCount; int paddingRow; @@ -144,6 +148,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification public final static int PREMIUM_FEATURE_APPLICATION_ICONS = 10; public final static int PREMIUM_FEATURE_ANIMATED_EMOJI = 11; public final static int PREMIUM_FEATURE_EMOJI_STATUS = 12; + public final static int PREMIUM_FEATURE_TRANSLATIONS = 13; private int statusBarHeight; private int firstViewHeight; private boolean isDialogVisible; @@ -156,10 +161,12 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification float totalProgress; private String source; + private boolean selectAnnualByDefault; + final Bitmap gradientTextureBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); final Canvas gradientCanvas = new Canvas(gradientTextureBitmap); - PremiumGradient.GradientTools gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradientBackground1, Theme.key_premiumGradientBackground2, Theme.key_premiumGradientBackground3, Theme.key_premiumGradientBackground4); - PremiumGradient.GradientTools tiersGradientTools; + PremiumGradient.PremiumGradientTools gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradientBackground1, Theme.key_premiumGradientBackground2, Theme.key_premiumGradientBackground3, Theme.key_premiumGradientBackground4); + PremiumGradient.PremiumGradientTools tiersGradientTools; private boolean forcePremium; float progressToFull; @@ -192,6 +199,8 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification return PREMIUM_FEATURE_ANIMATED_EMOJI; case "emoji_status": return PREMIUM_FEATURE_EMOJI_STATUS; + case "translations": + return PREMIUM_FEATURE_TRANSLATIONS; } return -1; } @@ -224,6 +233,8 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification return "app_icons"; case PREMIUM_FEATURE_EMOJI_STATUS: return "emoji_status"; + case PREMIUM_FEATURE_TRANSLATIONS: + return "translations"; } return null; } @@ -239,7 +250,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification } { - tiersGradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, null, null); + tiersGradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, null, null); tiersGradientTools.exactly = true; tiersGradientTools.x1 = 0; tiersGradientTools.y1 = 0f; @@ -249,6 +260,11 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification tiersGradientTools.cy = 0; } + public PremiumPreviewFragment setSelectAnnualByDefault() { + this.selectAnnualByDefault = true; + return this; + } + @SuppressLint("NotifyDataSetChanged") @Override public View createView(Context context) { @@ -335,7 +351,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification } backgroundView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); particlesView.getLayoutParams().height = backgroundView.getMeasuredHeight(); - int buttonHeight = (getUserConfig().isPremium() || forcePremium ? 0 : AndroidUtilities.dp(68)); + int buttonHeight = (buttonContainer == null || buttonContainer.getVisibility() == View.GONE ? 0 : AndroidUtilities.dp(68)); layoutManager.setAdditionalHeight(buttonHeight + statusBarHeight - AndroidUtilities.dp(16)); layoutManager.setMinimumLastViewHeight(buttonHeight); super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -420,13 +436,13 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification backgroundView.tierListView.setAlpha(alpha); particlesView.setAlpha(1f - totalProgress); - particlesView.setTranslationY(-(particlesView.getMeasuredHeight() - backgroundView.imageView.getMeasuredWidth()) / 2f + backgroundView.getY() + backgroundView.imageView.getY()); + particlesView.setTranslationY(-(particlesView.getMeasuredHeight() - backgroundView.imageView.getMeasuredWidth()) / 2f + backgroundView.getY() + backgroundView.imageFrameLayout.getY()); 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))); - backgroundView.imageView.mRenderer.gradientStartX = (backgroundView.getX() + backgroundView.imageView.getX() + getMeasuredWidth() * 0.1f * progress) / getMeasuredWidth(); - backgroundView.imageView.mRenderer.gradientStartY = (backgroundView.getY() + backgroundView.imageView.getY()) / getMeasuredHeight(); + backgroundView.imageView.mRenderer.gradientStartX = (backgroundView.getX() + backgroundView.imageFrameLayout.getX() + getMeasuredWidth() * 0.1f * progress) / getMeasuredWidth(); + backgroundView.imageView.mRenderer.gradientStartY = (backgroundView.getY() + backgroundView.imageFrameLayout.getY()) / getMeasuredHeight(); if (!isDialogVisible) { invalidate(); @@ -513,11 +529,13 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification // bottomSheet.setParentFragment(PremiumPreviewFragment.this); // showDialog(bottomSheet); // } else { - if (subscriptionTiers.isEmpty()) { - return; - } - showDialog(new PremiumFeatureBottomSheet(PremiumPreviewFragment.this, cell.data.type, false, subscriptionTiers.get(selectedTierIndex))); +// if (subscriptionTiers.isEmpty()) { +// return; +// } // } + + SubscriptionTier tier = selectedTierIndex < 0 || selectedTierIndex >= subscriptionTiers.size() ? null : subscriptionTiers.get(selectedTierIndex); + showDialog(new PremiumFeatureBottomSheet(PremiumPreviewFragment.this, cell.data.type, false, tier)); } }); contentView.addView(listView); @@ -588,6 +606,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_AVATARS, R.drawable.msg_premium_avatar, LocaleController.getString("PremiumPreviewAnimatedProfiles", R.string.PremiumPreviewAnimatedProfiles), LocaleController.getString("PremiumPreviewAnimatedProfilesDescription", R.string.PremiumPreviewAnimatedProfilesDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_APPLICATION_ICONS, R.drawable.msg_premium_icons, LocaleController.getString("PremiumPreviewAppIcon", R.string.PremiumPreviewAppIcon), LocaleController.getString("PremiumPreviewAppIconDescription", R.string.PremiumPreviewAppIconDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_EMOJI_STATUS, R.drawable.msg_premium_status, LocaleController.getString("PremiumPreviewEmojiStatus", R.string.PremiumPreviewEmojiStatus), LocaleController.getString("PremiumPreviewEmojiStatusDescription", R.string.PremiumPreviewEmojiStatusDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_TRANSLATIONS, R.drawable.msg_premium_translate, LocaleController.getString("PremiumPreviewTranslations", R.string.PremiumPreviewTranslations), LocaleController.getString("PremiumPreviewTranslationsDescription", R.string.PremiumPreviewTranslationsDescription))); if (messagesController.premiumFeaturesTypesToPosition.size() > 0) { for (int i = 0; i < premiumFeatures.size(); i++) { @@ -622,16 +641,29 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification } public static void buyPremium(BaseFragment fragment, String source) { - buyPremium(fragment, null, source); + buyPremium(fragment, null, source, true); + } + + public static void buyPremium(BaseFragment fragment, String source, boolean forcePremium) { + buyPremium(fragment, null, source, forcePremium); } public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, String source) { + buyPremium(fragment, tier, source, true); + } + + public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, String source, boolean forcePremium) { + buyPremium(fragment, tier, source, forcePremium, null); + } + + public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, String source, boolean forcePremium, BillingFlowParams.SubscriptionUpdateParams updateParams) { if (BuildVars.IS_BILLING_UNAVAILABLE) { fragment.showDialog(new PremiumNotAvailableBottomSheet(fragment)); return; } if (tier == null) { + forcePremium = true; for (TLRPC.TL_premiumSubscriptionOption option : fragment.getAccountInstance().getMediaDataController().getPremiumPromo().period_options) { if (option.months == 1) { tier = new SubscriptionTier(option); @@ -685,17 +717,24 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification return; } + boolean finalForcePremium = forcePremium; BillingController.getInstance().queryPurchases(BillingClient.ProductType.SUBS, (billingResult1, list) -> AndroidUtilities.runOnUIThread(() -> { if (billingResult1.getResponseCode() == BillingClient.BillingResponseCode.OK) { Runnable onSuccess = () -> { if (fragment instanceof PremiumPreviewFragment) { PremiumPreviewFragment premiumPreviewFragment = (PremiumPreviewFragment) fragment; - premiumPreviewFragment.setForcePremium(); + if (finalForcePremium) { + premiumPreviewFragment.setForcePremium(); + } premiumPreviewFragment.getMediaDataController().loadPremiumPromo(false); premiumPreviewFragment.listView.smoothScrollToPosition(0); } else { - fragment.presentFragment(new PremiumPreviewFragment(null).setForcePremium()); + PremiumPreviewFragment previewFragment = new PremiumPreviewFragment(null); + if (finalForcePremium) { + previewFragment.setForcePremium(); + } + fragment.presentFragment(previewFragment); } if (fragment.getParentActivity() instanceof LaunchActivity) { try { @@ -705,7 +744,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification ((LaunchActivity) fragment.getParentActivity()).getFireworksOverlay().start(); } }; - if (list != null && !list.isEmpty()) { + if (list != null && !list.isEmpty() && !fragment.getUserConfig().isPremium()) { for (Purchase purchase : list) { if (purchase.getProducts().contains(BillingController.PREMIUM_PRODUCT_ID)) { TLRPC.TL_payments_assignPlayMarketTransaction req = new TLRPC.TL_payments_assignPlayMarketTransaction(); @@ -713,6 +752,9 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification req.receipt.data = purchase.getOriginalJson(); TLRPC.TL_inputStorePaymentPremiumSubscription purpose = new TLRPC.TL_inputStorePaymentPremiumSubscription(); purpose.restore = true; + if (updateParams != null) { + purpose.upgrade = true; + } req.purpose = purpose; fragment.getConnectionsManager().sendRequest(req, (response, error) -> { if (response instanceof TLRPC.Updates) { @@ -736,16 +778,20 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification }); TLRPC.TL_payments_canPurchasePremium req = new TLRPC.TL_payments_canPurchasePremium(); - req.purpose = new TLRPC.TL_inputStorePaymentPremiumSubscription(); + TLRPC.TL_inputStorePaymentPremiumSubscription purpose = new TLRPC.TL_inputStorePaymentPremiumSubscription(); + if (updateParams != null) { + purpose.upgrade = true; + } + req.purpose = purpose; fragment.getConnectionsManager().sendRequest(req, (response, error) -> { AndroidUtilities.runOnUIThread(() -> { if (response instanceof TLRPC.TL_boolTrue) { - BillingController.getInstance().launchBillingFlow(fragment.getParentActivity(), fragment.getAccountInstance(), new TLRPC.TL_inputStorePaymentPremiumSubscription(), Collections.singletonList( + BillingController.getInstance().launchBillingFlow(fragment.getParentActivity(), fragment.getAccountInstance(), purpose, Collections.singletonList( BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(BillingController.PREMIUM_PRODUCT_DETAILS) .setOfferToken(selectedTier.getOfferDetails().getOfferToken()) .build() - )); + ), updateParams, false); } else { AlertsCreator.processError(fragment.getCurrentAccount(), error, fragment, req); } @@ -802,7 +848,8 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification if (!BuildVars.useInvoiceBilling() && tier.getOfferDetails() == null) { return LocaleController.getString(R.string.Loading); } - return LocaleController.formatString(R.string.SubscribeToPremium, tier.getFormattedPricePerMonth()); + return LocaleController.formatString(UserConfig.getInstance(currentAccount).isPremium() ? tier.getMonths() == 12 ? R.string.UpgradePremiumPerYear : R.string.UpgradePremiumPerMonth : + tier.getMonths() == 12 ? R.string.SubscribeToPremiumPerYear : R.string.SubscribeToPremium, tier.getMonths() == 12 ? tier.getFormattedPricePerYear() : tier.getFormattedPricePerMonth()); } } @@ -829,11 +876,8 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification featuresEndRow = rowCount; statusRow = rowCount++; lastPaddingRow = rowCount++; - if (getUserConfig().isPremium() || forcePremium) { - buttonContainer.setVisibility(View.GONE); - } else { - buttonContainer.setVisibility(View.VISIBLE); - } + + AndroidUtilities.updateViewVisibilityAnimated(buttonContainer, !getUserConfig().isPremium() || currentSubscriptionTier != null && currentSubscriptionTier.getMonths() < subscriptionTiers.get(selectedTierIndex).getMonths() && !forcePremium, 1f, false); int buttonHeight = buttonContainer.getVisibility() == View.VISIBLE ? AndroidUtilities.dp(64) : 0; layoutManager.setAdditionalHeight(buttonHeight + statusBarHeight - AndroidUtilities.dp(16)); @@ -877,6 +921,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.billingProductDetailsUpdated || id == NotificationCenter.premiumPromoUpdated) { updateButtonText(false); + backgroundView.updatePremiumTiers(); } if (id == NotificationCenter.currentUserPremiumStatusChanged || id == NotificationCenter.premiumPromoUpdated) { backgroundView.updateText(); @@ -1077,6 +1122,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification TextView titleView; private final TextView subtitleView; + private final FrameLayout imageFrameLayout; private final GLIconTextureView imageView; private RecyclerListView tierListView; @@ -1084,6 +1130,8 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification public BackgroundView(Context context) { super(context); setOrientation(VERTICAL); + imageFrameLayout = new FrameLayout(context); + addView(imageFrameLayout, LayoutHelper.createLinear(190, 190, Gravity.CENTER_HORIZONTAL)); imageView = new GLIconTextureView(context, GLIconRenderer.FRAGMENT_STYLE) { @Override public void onLongPress() { @@ -1106,7 +1154,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification settingsView.animate().translationY(1).setDuration(300); } }; - addView(imageView, LayoutHelper.createLinear(190, 190, Gravity.CENTER_HORIZONTAL)); + imageFrameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); titleView = new TextView(context); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 22); @@ -1175,7 +1223,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return true; + return !subscriptionTiers.get(holder.getAdapterPosition()).subscriptionOption.current; } @Override @@ -1184,6 +1232,9 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification } }); tierListView.setOnItemClickListener((view, position) -> { + if (!view.isEnabled()) { + return; + } if (view instanceof PremiumTierCell) { PremiumTierCell tierCell = (PremiumTierCell) view; selectedTierIndex = subscriptionTiers.indexOf(tierCell.getTier()); @@ -1229,6 +1280,8 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification } } } + + AndroidUtilities.updateViewVisibilityAnimated(buttonContainer, !getUserConfig().isPremium() || currentSubscriptionTier != null && currentSubscriptionTier.getMonths() < subscriptionTiers.get(selectedTierIndex).getMonths() && !forcePremium); } }); Path path = new Path(); @@ -1252,8 +1305,8 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification }); addView(tierListView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 12, 16, 12, 0)); - updateText(); updatePremiumTiers(); + updateText(); } private void measureGradient(int w, int h) { @@ -1271,11 +1324,25 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification @SuppressLint("NotifyDataSetChanged") public void updatePremiumTiers() { subscriptionTiers.clear(); + selectedTierIndex = -1; + currentSubscriptionTier = null; long pricePerYearMax = 0; if (getMediaDataController().getPremiumPromo() != null) { for (TLRPC.TL_premiumSubscriptionOption option : getMediaDataController().getPremiumPromo().period_options) { + if (getUserConfig().isPremium() && !option.can_purchase_upgrade && !option.current) { + continue; + } + SubscriptionTier subscriptionTier = new SubscriptionTier(option); subscriptionTiers.add(subscriptionTier); + if (selectAnnualByDefault) { + if (option.months == 12) { + selectedTierIndex = subscriptionTiers.size() - 1; + } + } + if (option.current) { + currentSubscriptionTier = subscriptionTier; + } if (BuildVars.useInvoiceBilling()) { if (subscriptionTier.getPricePerYear() > pricePerYearMax) { pricePerYearMax = subscriptionTier.getPricePerYear(); @@ -1283,6 +1350,17 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification } } } + if (BuildVars.useInvoiceBilling() && getUserConfig().isPremium()) { + subscriptionTiers.clear(); + currentSubscriptionTier = null; + } else if (!BuildVars.useInvoiceBilling() && currentSubscriptionTier != null && !Objects.equals(BillingController.getInstance().getLastPremiumTransaction(), + currentSubscriptionTier.subscriptionOption != null ? currentSubscriptionTier.subscriptionOption.transaction != null ? + currentSubscriptionTier.subscriptionOption.transaction.replaceAll(TRANSACTION_PATTERN, "$1") : null : null) || + currentSubscriptionTier != null && currentSubscriptionTier.getMonths() == 12) { + subscriptionTiers.clear(); + currentSubscriptionTier = null; + } + if (BuildVars.useInvoiceBilling()) { for (SubscriptionTier tier : subscriptionTiers) { tier.setPricePerYearRegular(pricePerYearMax); @@ -1303,39 +1381,102 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification } } - for (int i = 0; i < subscriptionTiers.size(); i++) { - SubscriptionTier tier = subscriptionTiers.get(i); - if (tier.getMonths() == 1) { - selectedTierIndex = i; - break; + if (selectedTierIndex == -1) { + for (int i = 0; i < subscriptionTiers.size(); i++) { + SubscriptionTier tier = subscriptionTiers.get(i); + if (tier.getMonths() == 12) { + selectedTierIndex = i; + break; + } + } + if (selectedTierIndex == -1) { + selectedTierIndex = 0; } } updateButtonText(false); tierListView.getAdapter().notifyDataSetChanged(); } + private boolean setTierListViewVisibility; + private boolean tierListViewVisible; public void updateText() { titleView.setText(LocaleController.getString(forcePremium ? R.string.TelegramPremiumSubscribedTitle : R.string.TelegramPremium)); subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(getUserConfig().isPremium() || forcePremium ? R.string.TelegramPremiumSubscribedSubtitle : R.string.TelegramPremiumSubtitle))); - tierListView.setVisibility(getUserConfig().isPremium() || forcePremium || BuildVars.IS_BILLING_UNAVAILABLE || IS_PREMIUM_TIERS_UNAVAILABLE ? GONE : VISIBLE); + boolean tierNotVisible = forcePremium || BuildVars.IS_BILLING_UNAVAILABLE || IS_PREMIUM_TIERS_UNAVAILABLE || subscriptionTiers.size() <= 1; + if (!setTierListViewVisibility || !tierNotVisible) { + tierListView.setVisibility(tierNotVisible ? GONE : VISIBLE); + setTierListViewVisibility = true; + } else if (tierListView.getVisibility() == VISIBLE && tierNotVisible && tierListViewVisible == tierNotVisible) { + View v = tierListView; + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(250); + animator.addUpdateListener(animation -> { + float val = (float) animation.getAnimatedValue(); + v.setAlpha(val); + v.setScaleX(val); + v.setScaleY(val); + + float f = animator.getAnimatedFraction(); + for (int i = 0; i < backgroundView.getChildCount(); i++) { + View ch = backgroundView.getChildAt(i); + if (ch != tierListView) { + float offset = 0; + if (ch == imageFrameLayout) { + offset -= AndroidUtilities.dp(15) * f; + } else { + offset += AndroidUtilities.dp(8) * f; + } + ch.setTranslationY(f * v.getMeasuredHeight() + offset); + } + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + v.setVisibility(GONE); + + for (int i = 0; i < backgroundView.getChildCount(); i++) { + View ch = backgroundView.getChildAt(i); + if (ch != tierListView) { + ch.setTranslationY(0); + } + } + } + }); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.start(); + } + tierListViewVisible = !tierNotVisible; } } private void updateButtonText(boolean animated) { - if (premiumButtonView == null) { + if (premiumButtonView == null || getUserConfig().isPremium() && currentSubscriptionTier != null && subscriptionTiers.get(selectedTierIndex).getMonths() < currentSubscriptionTier.getMonths()) { return; } + if (LocaleController.isRTL) { + animated = false; + } if (BuildVars.IS_BILLING_UNAVAILABLE) { premiumButtonView.setButton(getPremiumButtonText(currentAccount, subscriptionTiers.get(selectedTierIndex)), v -> buyPremium(this), animated); return; } - if (!BuildVars.useInvoiceBilling() && (!BillingController.getInstance().isReady() || subscriptionTiers.isEmpty() || subscriptionTiers.get(selectedTierIndex).googlePlayProductDetails == null)) { + if (!BuildVars.useInvoiceBilling() && (!BillingController.getInstance().isReady() || subscriptionTiers.isEmpty() || selectedTierIndex >= subscriptionTiers.size() || subscriptionTiers.get(selectedTierIndex).googlePlayProductDetails == null)) { premiumButtonView.setButton(LocaleController.getString(R.string.Loading), v -> {}, animated); premiumButtonView.setFlickerDisabled(true); return; } if (!subscriptionTiers.isEmpty()) { - premiumButtonView.setButton(getPremiumButtonText(currentAccount, subscriptionTiers.get(selectedTierIndex)), v -> buyPremium(this, subscriptionTiers.get(selectedTierIndex), "settings"), animated); + premiumButtonView.setButton(getPremiumButtonText(currentAccount, subscriptionTiers.get(selectedTierIndex)), v -> { + SubscriptionTier tier = subscriptionTiers.get(selectedTierIndex); + BillingFlowParams.SubscriptionUpdateParams updateParams = null; + if (currentSubscriptionTier != null && currentSubscriptionTier.subscriptionOption != null && currentSubscriptionTier.subscriptionOption.transaction != null) { + updateParams = BillingFlowParams.SubscriptionUpdateParams.newBuilder() + .setOldPurchaseToken(BillingController.getInstance().getLastPremiumToken()) + .setReplaceProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE) + .build(); + } + buyPremium(this, tier, "settings", true, updateParams); + }, animated); premiumButtonView.setFlickerDisabled(false); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java index a0440988a..1b919d33f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java @@ -148,7 +148,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification private TLRPC.Photo avatarForRestPhoto; @Override - public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { avatarForRest = smallSize; avatarForRestPhoto = null; @@ -165,6 +165,10 @@ public class PrivacyControlActivity extends BaseFragment implements Notification req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.video_emoji_markup = emojiMarkup; + req.flags |= 16; + } req.fallback = true; req.flags |= 8; @@ -389,7 +393,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification ContactsController.getInstance(currentAccount).loadPrivacySettings(); } if (rulesType == PRIVACY_RULES_TYPE_PHOTO) { - imageUpdater = new ImageUpdater(false); + imageUpdater = new ImageUpdater(false, ImageUpdater.FOR_TYPE_USER, true); imageUpdater.parentFragment = this; imageUpdater.setDelegate(this); TLRPC.UserFull userFull = getMessagesController().getUserFull(getUserConfig().clientUserId); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index c115a9719..590aec6c7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -86,7 +86,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private int sessionsRow; private int passcodeRow; private int autoDeleteMesages; - private int autoDeleteDetailRow; + private int sessionsDetailRow; private int newChatsHeaderRow; private int newChatsRow; private int newChatsSectionRow; @@ -602,16 +602,15 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio rowCount = 0; securitySectionRow = rowCount++; - blockedRow = rowCount++; - sessionsRow = rowCount++; - passcodeRow = rowCount++; passwordRow = rowCount++; - + autoDeleteMesages = rowCount++; + passcodeRow = rowCount++; if (currentPassword != null ? currentPassword.login_email_pattern != null : SharedConfig.hasEmailLogin) { emailLoginRow = rowCount++; } else { emailLoginRow = -1; } + blockedRow = rowCount++; if (currentPassword != null) { boolean hasEmail = currentPassword.login_email_pattern != null; if (SharedConfig.hasEmailLogin != hasEmail) { @@ -619,8 +618,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio SharedConfig.saveConfig(); } } - autoDeleteMesages = rowCount++; - autoDeleteDetailRow = rowCount++; + sessionsRow = rowCount++; + sessionsDetailRow = rowCount++; privacySectionRow = rowCount++; phoneNumberRow = rowCount++; @@ -1028,8 +1027,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } else if (position == groupsDetailRow) { privacyCell.setText(LocaleController.getString("GroupsAndChannelsHelp", R.string.GroupsAndChannelsHelp)); privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); - } else if (position == autoDeleteDetailRow) { - privacyCell.setText(LocaleController.getString("AutoDeleteSettingsInfo", R.string.AutoDeleteSettingsInfo)); + } else if (position == sessionsDetailRow) { + privacyCell.setText(LocaleController.getString("SessionsSettingsInfo", R.string.SessionsSettingsInfo)); privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } else if (position == secretDetailRow) { privacyCell.setText(LocaleController.getString("SecretWebPageInfo", R.string.SecretWebPageInfo)); @@ -1087,6 +1086,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio showLoading = false; loadingLen = 16; value = null; + textCell2.setPrioritizeTitleOverValue(false); if (position == autoDeleteMesages) { int ttl = getUserConfig().getGlobalTTl(); if (ttl == -1) { @@ -1096,23 +1096,39 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } else { value = LocaleController.getString("PasswordOff", R.string.PasswordOff); } - textCell2.setTextAndValueAndIcon(LocaleController.getString("AutoDeleteMessages", R.string.AutoDeleteMessages), value, R.drawable.msg_autodelete, false); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("AutoDeleteMessages", R.string.AutoDeleteMessages), value, true, R.drawable.msg_filled_autodelete, getThemedColor(Theme.key_color_lightblue), true); } else if (position == sessionsRow) { String count = ""; - if (sessionsActivityPreload.getSessionsCount() == 0) { if (getMessagesController().lastKnownSessionsCount == 0) { showLoading = true; } else { - count = Integer.toString(getMessagesController().lastKnownSessionsCount); + count = String.format(LocaleController.getInstance().getCurrentLocale(), "%d", getMessagesController().lastKnownSessionsCount); } } else { - count = Integer.toString(sessionsActivityPreload.getSessionsCount()); + count = String.format(LocaleController.getInstance().getCurrentLocale(), "%d", sessionsActivityPreload.getSessionsCount()); } getMessagesController().lastKnownSessionsCount = sessionsActivityPreload.getSessionsCount(); - textCell2.setTextAndValueAndIcon(LocaleController.getString("SessionsTitle", R.string.SessionsTitle), count, R.drawable.msg_devices, true); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("SessionsTitle", R.string.SessionsTitle), count, true, R.drawable.msg_filled_devices, getThemedColor(Theme.key_color_yellow), false); } else if (position == emailLoginRow) { - textCell2.setTextAndValueAndIcon(LocaleController.getString(R.string.EmailLogin), "", R.drawable.msg_email, true); + CharSequence val = ""; + if (currentPassword == null) { + showLoading = true; + } else { + SpannableStringBuilder spannable = SpannableStringBuilder.valueOf(currentPassword.login_email_pattern); + int startIndex = currentPassword.login_email_pattern.indexOf('*'); + int endIndex = currentPassword.login_email_pattern.lastIndexOf('*'); + if (startIndex != endIndex && startIndex != -1 && endIndex != -1) { + TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun(); + run.flags |= TextStyleSpan.FLAG_STYLE_SPOILER; + run.start = startIndex; + run.end = endIndex + 1; + spannable.setSpan(new TextStyleSpan(run), startIndex, endIndex + 1, 0); + } + val = spannable; + } + textCell2.setPrioritizeTitleOverValue(true); + textCell2.setTextAndSpoilersValueAndColorfulIcon(LocaleController.getString(R.string.EmailLogin), val, R.drawable.msg_filled_email, getThemedColor(Theme.key_color_orange), true); } else if (position == passwordRow) { value = ""; if (currentPassword == null) { @@ -1122,24 +1138,28 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } else { value = LocaleController.getString("PasswordOff", R.string.PasswordOff); } - textCell2.setTextAndValueAndIcon(LocaleController.getString("TwoStepVerification", R.string.TwoStepVerification), value, R.drawable.msg_secret, true); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("TwoStepVerification", R.string.TwoStepVerification), value, true, R.drawable.msg_filled_permissions, getThemedColor(Theme.key_color_blue), true); } else if (position == passcodeRow) { + int icon; if (SharedConfig.passcodeHash.length() != 0) { value = LocaleController.getString("PasswordOn", R.string.PasswordOn); + icon = R.drawable.msg_filled_passcode_on; } else { value = LocaleController.getString("PasswordOff", R.string.PasswordOff); + icon = R.drawable.msg_filled_passcode_off; } - textCell2.setTextAndValueAndIcon(LocaleController.getString("Passcode", R.string.Passcode), value, R.drawable.msg_permissions, true); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("Passcode", R.string.Passcode), value, true, icon, getThemedColor(Theme.key_color_green), true); } else if (position == blockedRow) { int totalCount = getMessagesController().totalBlockedCount; if (totalCount == 0) { - textCell2.setTextAndValueAndIcon(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), LocaleController.getString("BlockedEmpty", R.string.BlockedEmpty), R.drawable.msg_block2, true); + value = LocaleController.getString("BlockedEmpty", R.string.BlockedEmpty); } else if (totalCount > 0) { - textCell2.setTextAndValueAndIcon(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), String.format("%d", totalCount), R.drawable.msg_block2, true); + value = String.format(LocaleController.getInstance().getCurrentLocale(), "%d", totalCount); } else { showLoading = true; - textCell2.setTextAndValueAndIcon(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), "", R.drawable.msg_block2, true); + value = ""; } + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), value, true, R.drawable.msg_filled_blocked, getThemedColor(Theme.key_color_red), true); } textCell2.setDrawLoading(showLoading, loadingLen, animated); break; @@ -1152,7 +1172,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio position == deleteAccountRow || position == webSessionsRow || position == groupsRow || position == paymentsClearRow || position == secretMapRow || position == contactsDeleteRow) { return 0; - } else if (position == deleteAccountDetailRow || position == groupsDetailRow || position == autoDeleteDetailRow || position == secretDetailRow || position == botsDetailRow || position == contactsDetailRow || position == newChatsSectionRow) { + } else if (position == deleteAccountDetailRow || position == groupsDetailRow || position == sessionsDetailRow || position == secretDetailRow || position == botsDetailRow || position == contactsDetailRow || position == newChatsSectionRow) { return 1; } else if (position == securitySectionRow || position == advancedSectionRow || position == privacySectionRow || position == secretSectionRow || position == botsSectionRow || position == contactsSectionRow || position == newChatsHeaderRow) { return 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 4d22c1461..c8a67e934 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -27,7 +27,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.DataSetObserver; -import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -202,9 +201,10 @@ import org.telegram.ui.Components.SharedMediaLayout; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.StickerEmptyView; import org.telegram.ui.Components.TimerDrawable; -import org.telegram.ui.Components.TranslateAlert; +import org.telegram.ui.Components.TranslateAlert2; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.UndoView; +import org.telegram.ui.Components.VectorAvatarThumbDrawable; import org.telegram.ui.Components.voip.VoIPHelper; import java.io.BufferedInputStream; @@ -626,6 +626,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private ImageReceiver foregroundImageReceiver; private float foregroundAlpha; private ImageReceiver.BitmapHolder drawableHolder; + boolean drawForeground = true; ProfileGalleryView avatarsViewPager; @@ -706,11 +707,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override protected void onDraw(Canvas canvas) { ImageReceiver imageReceiver = animatedEmojiDrawable != null ? animatedEmojiDrawable.getImageReceiver() : this.imageReceiver; - if (imageReceiver != null && foregroundAlpha < 1f) { + if (imageReceiver != null && (foregroundAlpha < 1f || !drawForeground)) { imageReceiver.setImageCoords(0, 0, getMeasuredWidth(), getMeasuredHeight()); imageReceiver.draw(canvas); } - if (foregroundAlpha > 0f) { + if (foregroundAlpha > 0f && drawForeground) { if (foregroundImageReceiver.getDrawable() != null) { foregroundImageReceiver.setImageCoords(0, 0, getMeasuredWidth(), getMeasuredHeight()); foregroundImageReceiver.setAlpha(foregroundAlpha); @@ -731,6 +732,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. avatarsViewPager.invalidate(); } } + + public void drawForeground(boolean drawForeground) { + this.drawForeground = drawForeground; + } } private class TopView extends View { @@ -1503,7 +1508,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. participantsMap = null; if (UserObject.isUserSelf(user)) { - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); imageUpdater.setOpenWithFrontfaceCamera(true); imageUpdater.parentFragment = this; imageUpdater.setDelegate(this); @@ -1805,7 +1810,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } else if (id == share_contact) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putString("selectAlertString", LocaleController.getString("SendContactToText", R.string.SendContactToText)); args.putString("selectAlertStringGroup", LocaleController.getString("SendContactToGroupText", R.string.SendContactToGroupText)); DialogsActivity fragment = new DialogsActivity(args); @@ -1895,7 +1900,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 2); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO); args.putBoolean("resetDelegate", false); args.putBoolean("closeFragment", false); // args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); @@ -1945,6 +1950,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. }); showDialog(builder.create()); } + return true; }); presentFragment(fragment); } else if (id == share) { @@ -2147,7 +2153,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. int position = avatarsViewPager.getRealPosition(); TLRPC.Photo photo = avatarsViewPager.getPhoto(position); TLRPC.UserFull userFull = getUserInfo(); - if (hasFallbackPhoto && userFull != null && userFull.fallback_photo != null && userFull.fallback_photo.id == photo.id) { + if (hasFallbackPhoto && photo != null && userFull != null && userFull.fallback_photo != null && userFull.fallback_photo.id == photo.id) { userFull.fallback_photo = null; userFull.flags &= ~4194304; getMessagesStorage().updateUserInfo(userFull, true); @@ -2454,6 +2460,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. }); wasPortrait = portrait; } + + if (searchItem != null && qrItem != null) { + float translation = AndroidUtilities.dp(48) * currentExpandAnimatorValue; + // qrItem.setTranslationX(translation); + } } @Override @@ -2961,7 +2972,6 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. cells[0].setOnClickListener(v -> { cells[0].setChecked(!cells[0].isChecked(), true); }); - builder.setCustomViewOffset(12); builder.setView(linearLayout); } @@ -3211,9 +3221,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } else if (position == policyRow) { Browser.openUrl(getParentActivity(), LocaleController.getString("PrivacyPolicyUrl", R.string.PrivacyPolicyUrl)); } else if (position == sendLogsRow) { - sendLogs(false); + sendLogs(getParentActivity(), false); } else if (position == sendLastLogsRow) { - sendLogs(true); + sendLogs(getParentActivity(), true); } else if (position == clearLogsRow) { FileLog.cleanupLogs(); } else if (position == switchBackendRow) { @@ -3286,6 +3296,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. (AndroidUtilities.isTabletInternal() && BuildVars.DEBUG_PRIVATE_VERSION) ? (SharedConfig.forceDisableTabletMode ? "Enable tablet mode" : "Disable tablet mode") : null, LocaleController.getString(SharedConfig.useLNavigation ? R.string.AltNavigationDisable : R.string.AltNavigationEnable), BuildVars.DEBUG_PRIVATE_VERSION ? LocaleController.getString(SharedConfig.isFloatingDebugActive ? R.string.FloatingDebugDisable : R.string.FloatingDebugEnable) : null, + BuildVars.DEBUG_PRIVATE_VERSION ? "Force remove premium suggestions" : null }; builder.setItems(items, (dialog, which) -> { @@ -3312,7 +3323,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. SharedConfig.setNoSoundHintShowed(false); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("bganimationhint").remove("filterhint").commit(); - MessagesController.getEmojiSettings(currentAccount).edit().remove("featured_hidden").commit(); + MessagesController.getEmojiSettings(currentAccount).edit().remove("featured_hidden").remove("emoji_featured_hidden").commit(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; SharedConfig.stickersReorderingHintUsed = false; @@ -3322,6 +3333,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. SharedConfig.dayNightThemeSwitchHintCount = 3; SharedConfig.fastScrollHintCount = 3; ChatThemeController.getInstance(currentAccount).clearCache(); + getNotificationCenter().postNotificationName(NotificationCenter.newSuggestionsAvailable); + RestrictedLanguagesSelectActivity.cleanup(); } else if (which == 7) { VoIPHelper.showCallDebugSettings(getParentActivity()); } else if (which == 8) { @@ -3381,6 +3394,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. getParentActivity().recreate(); } else if (which == 22) { FloatingDebugController.setActive((LaunchActivity) getParentActivity(), !FloatingDebugController.isActive()); + } else if (which == 23) { + TLRPC.TL_help_dismissSuggestion req = new TLRPC.TL_help_dismissSuggestion(); + req.suggestion = "VALIDATE_PHONE_NUMBER"; + req.peer = new TLRPC.TL_inputPeerEmpty(); + getConnectionsManager().sendRequest(req, (response, error) -> { + TLRPC.TL_help_dismissSuggestion req2 = new TLRPC.TL_help_dismissSuggestion(); + req2.suggestion = "VALIDATE_PASSWORD"; + req2.peer = new TLRPC.TL_inputPeerEmpty(); + getConnectionsManager().sendRequest(req2, (res2, err2) -> { + getMessagesController().loadAppConfig(); + }); + }); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -4083,10 +4108,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (sharedMediaLayout != null && sharedMediaLayout.getCurrentListView() != null) { sharedMediaLayout.getCurrentListView().cancelClickRunnables(true); } - Bitmap bitmap = pinchToZoomHelper.getPhotoImage() == null ? null : pinchToZoomHelper.getPhotoImage().getBitmap(); - if (bitmap != null) { - topView.setBackgroundColor(ColorUtils.blendARGB(AndroidUtilities.calcBitmapColor(bitmap), getThemedColor(Theme.key_windowBackgroundWhite), 0.1f)); - } + topView.setBackgroundColor(ColorUtils.blendARGB(getAverageColor(pinchToZoomHelper.getPhotoImage()), getThemedColor(Theme.key_windowBackgroundWhite), 0.1f)); } }); avatarsViewPager.setPinchToZoomHelper(pinchToZoomHelper); @@ -4182,6 +4204,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. nameTextView[1].setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_profile_title), Color.WHITE, value)); actionBar.setItemsColor(ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, value), false); + actionBar.setMenuOffsetSuppressed(true); avatarImage.setForegroundAlpha(value); @@ -4903,7 +4926,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } final String[] fromLanguage = new String[1]; fromLanguage[0] = "und"; - final boolean translateButtonEnabled = MessagesController.getGlobalMainSettings().getBoolean("translate_button", false); + final boolean translateButtonEnabled = MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled(); final boolean[] withTranslate = new boolean[1]; withTranslate[0] = position == bioRow || position == channelInfoRow || position == userInfoRow; final String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); @@ -4945,7 +4968,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. BulletinFactory.of(this).createCopyBulletin(LocaleController.getString("TextCopied", R.string.TextCopied)).show(); } } else if (j == 1) { - TranslateAlert.showAlert(fragmentView.getContext(), this, currentAccount, fromLanguage[0], toLang, finalText, false, span -> { + TranslateAlert2.showAlert(fragmentView.getContext(), this, currentAccount, fromLanguage[0], toLang, finalText, null, false, span -> { if (span != null) { openUrl(span.getURL(), null); return true; @@ -5583,7 +5606,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (!doNotSetForeground) { BackupImageView imageView = avatarsViewPager.getCurrentItemView(); if (imageView != null) { - avatarImage.setForegroundImageDrawable(imageView.getImageReceiver().getDrawableSafe()); + if (imageView.getImageReceiver().getDrawable() instanceof VectorAvatarThumbDrawable) { + avatarImage.drawForeground(false); + } else { + avatarImage.drawForeground(true); + avatarImage.setForegroundImageDrawable(imageView.getImageReceiver().getDrawableSafe()); + } } } avatarImage.setForegroundAlpha(1f); @@ -5762,7 +5790,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private void setForegroundImage(boolean secondParent) { Drawable drawable = avatarImage.getImageReceiver().getDrawable(); - if (drawable instanceof AnimatedFileDrawable) { + if (drawable instanceof VectorAvatarThumbDrawable) { + avatarImage.setForegroundImage(null, null, drawable); + } else if (drawable instanceof AnimatedFileDrawable) { AnimatedFileDrawable fileDrawable = (AnimatedFileDrawable) drawable; avatarImage.setForegroundImage(null, null, fileDrawable); if (secondParent) { @@ -6482,7 +6512,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. animators.add(ObjectAnimator.ofFloat(writeButton, View.ALPHA, 1.0f)); } if (playProfileAnimation == 2) { - avatarColor = AndroidUtilities.calcBitmapColor(avatarImage.getImageReceiver().getBitmap()); + avatarColor = getAverageColor(avatarImage.getImageReceiver()); nameTextView[1].setTextColor(Color.WHITE); onlineTextView[1].setTextColor(Color.argb(179, 255, 255, 255)); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); @@ -6632,6 +6662,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return null; } + private int getAverageColor(ImageReceiver imageReceiver) { + if (imageReceiver.getDrawable() instanceof VectorAvatarThumbDrawable) { + return ((VectorAvatarThumbDrawable)imageReceiver.getDrawable()).gradientTools.getAverageColor(); + } + return AndroidUtilities.calcBitmapColor(avatarImage.getImageReceiver().getBitmap()); + } + private void updateOnlineCount(boolean notify) { onlineCount = 0; int currentTime = getConnectionsManager().getCurrentTime(); @@ -7205,7 +7242,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } private void updateProfileData(boolean reload) { - if (avatarContainer == null || nameTextView == null) { + if (avatarContainer == null || nameTextView == null || getParentActivity() == null) { return; } String onlineTextOverride; @@ -7241,11 +7278,23 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. final ImageLocation imageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_BIG); final ImageLocation thumbLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL); - final ImageLocation videoThumbLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_VIDEO_THUMB); + final ImageLocation videoThumbLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_VIDEO_BIG); + VectorAvatarThumbDrawable vectorAvatarThumbDrawable = null; + TLRPC.VideoSize vectorAvatar = null; + if (userInfo != null) { + vectorAvatar = FileLoader.getVectorMarkupVideoSize(user.photo != null && user.photo.personal ? userInfo.personal_photo : userInfo.profile_photo); + if (vectorAvatar != null) { + vectorAvatarThumbDrawable = new VectorAvatarThumbDrawable(vectorAvatar, user.premium, VectorAvatarThumbDrawable.TYPE_PROFILE); + } + } final ImageLocation videoLocation = avatarsViewPager.getCurrentVideoLocation(thumbLocation, imageLocation); - avatarsViewPager.initIfEmpty(imageLocation, thumbLocation, reload); + if (avatar == null) { + avatarsViewPager.initIfEmpty(vectorAvatarThumbDrawable, imageLocation, thumbLocation, reload); + } if (avatarBig == null) { - if (videoThumbLocation != null && !user.photo.personal) { + if (vectorAvatar != null) { + avatarImage.setImageDrawable(vectorAvatarThumbDrawable); + } else if (videoThumbLocation != null && !user.photo.personal) { avatarImage.getImageReceiver().setVideoThumbIsSame(true); avatarImage.setImage(videoThumbLocation, "avatar", thumbLocation, "50_50", avatarDrawable, user); } else { @@ -7647,7 +7696,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. videoLocation = avatarsViewPager.getCurrentVideoLocation(thumbLocation, imageLocation); } - boolean initied = avatarsViewPager.initIfEmpty(imageLocation, thumbLocation, reload); + boolean initied = avatarsViewPager.initIfEmpty(null, imageLocation, thumbLocation, reload); if ((imageLocation == null || initied) && isPulledDown) { final View view = layoutManager.findViewByPosition(0); if (view != null) { @@ -7970,7 +8019,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { + public boolean didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { long did = dids.get(0).dialogId; Bundle args = new Bundle(); args.putBoolean("scrollToTopOnResume", true); @@ -7982,7 +8031,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. args.putLong("chat_id", -did); } if (!getMessagesController().checkCanOpenChat(args, fragment)) { - return; + return false; } getNotificationCenter().removeObserver(this, NotificationCenter.closeChats); @@ -7995,6 +8044,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. AccountInstance accountInstance = AccountInstance.getInstance(currentAccount); SendMessagesHelper.prepareSendingText(accountInstance, message.toString(), did, true, 0); } + return true; } @Override @@ -8239,9 +8289,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } @Override - public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { - if (photo != null || video != null) { + if (photo != null || video != null || emojiMarkup != null) { TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); if (photo != null) { req.file = photo; @@ -8253,8 +8303,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.video_emoji_markup = emojiMarkup; + req.flags |= 16; + } getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { - avatarsViewPager.removeUploadingImage(uploadingImageLocation); if (error == null) { TLRPC.User user = getMessagesController().getUser(getUserConfig().getClientUserId()); if (user == null) { @@ -8266,11 +8319,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } else { getUserConfig().setCurrentUser(user); } + TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; ArrayList sizes = photos_photo.photo.sizes; TLRPC.PhotoSize small = FileLoader.getClosestPhotoSizeWithSize(sizes, 150); TLRPC.PhotoSize big = FileLoader.getClosestPhotoSizeWithSize(sizes, 800); - TLRPC.VideoSize videoSize = photos_photo.photo.video_sizes.isEmpty() ? null : photos_photo.photo.video_sizes.get(0); + TLRPC.VideoSize videoSize = photos_photo.photo.video_sizes.isEmpty() ? null : FileLoader.getClosestVideoSizeWithSize(photos_photo.photo.video_sizes, 1000); user.photo = new TLRPC.TL_userProfilePhoto(); user.photo.photo_id = photos_photo.photo.id; if (small != null) { @@ -8288,32 +8342,37 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. String newKey = small.location.volume_id + "_" + small.location.local_id + "@50_50"; ImageLoader.getInstance().replaceImageInCache(oldKey, newKey, ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), false); } - if (big != null && avatarBig != null) { - File destFile = FileLoader.getInstance(currentAccount).getPathToAttach(big, true); - File src = FileLoader.getInstance(currentAccount).getPathToAttach(avatarBig, true); - src.renameTo(destFile); - } + if (videoSize != null && videoPath != null) { File destFile = FileLoader.getInstance(currentAccount).getPathToAttach(videoSize, "mp4", true); File src = new File(videoPath); src.renameTo(destFile); + } else if (big != null && avatarBig != null) { + File destFile = FileLoader.getInstance(currentAccount).getPathToAttach(big, true); + File src = FileLoader.getInstance(currentAccount).getPathToAttach(avatarBig, true); + src.renameTo(destFile); } - - getMessagesStorage().clearUserPhotos(user.id); + getMessagesStorage().addDialogPhoto(user.id, ((TLRPC.TL_photos_photo) response).photo); ArrayList users = new ArrayList<>(); users.add(user); getMessagesStorage().putUsersAndChats(users, null, false, true); + TLRPC.UserFull userFull = getMessagesController().getUserFull(userId); + userFull.profile_photo = photos_photo.photo; + getMessagesStorage().updateUserInfo(userFull, false); } allowPullingDown = !AndroidUtilities.isTablet() && !isInLandscapeMode && avatarImage.getImageReceiver().hasNotThumb() && !AndroidUtilities.isAccessibilityScreenReaderEnabled(); avatar = null; avatarBig = null; + avatarsViewPager.scrolledByUser = true; + avatarsViewPager.removeUploadingImage(uploadingImageLocation); avatarsViewPager.setCreateThumbFromParent(false); updateProfileData(true); showAvatarProgress(false, true); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_ALL); getNotificationCenter().postNotificationName(NotificationCenter.mainUserInfoChanged); getUserConfig().saveConfig(true); + })); } else { avatar = smallSize.location; @@ -8400,11 +8459,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } - private void sendLogs(boolean last) { - if (getParentActivity() == null) { + public static void sendLogs(Activity activity, boolean last) { + if (activity == null) { return; } - AlertDialog progressDialog = new AlertDialog(getParentActivity(), AlertDialog.ALERT_TYPE_SPINNER); + AlertDialog progressDialog = new AlertDialog(activity, AlertDialog.ALERT_TYPE_SPINNER); progressDialog.setCanCancel(false); progressDialog.show(); Utilities.globalQueue.postRunnable(() -> { @@ -8425,7 +8484,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } if (FileLog.databaseIsMalformed) { - files.addAll(getMessagesStorage().getDatabaseFiles()); + files.addAll(MessagesStorage.getInstance(UserConfig.selectedAccount).getDatabaseFiles()); } boolean[] finished = new boolean[1]; @@ -8479,7 +8538,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (finished[0]) { Uri uri; if (Build.VERSION.SDK_INT >= 24) { - uri = FileProvider.getUriForFile(getParentActivity(), ApplicationLoader.getApplicationId() + ".provider", zipFile); + uri = FileProvider.getUriForFile(activity, ApplicationLoader.getApplicationId() + ".provider", zipFile); } else { uri = Uri.fromFile(zipFile); } @@ -8492,16 +8551,16 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. i.putExtra(Intent.EXTRA_EMAIL, ""); i.putExtra(Intent.EXTRA_SUBJECT, "Logs from " + LocaleController.getInstance().formatterStats.format(System.currentTimeMillis())); i.putExtra(Intent.EXTRA_STREAM, uri); - if (getParentActivity() != null) { + if (activity != null) { try { - getParentActivity().startActivityForResult(Intent.createChooser(i, "Select email application."), 500); + activity.startActivityForResult(Intent.createChooser(i, "Select email application."), 500); } catch (Exception e) { FileLog.e(e); } } } else { - if (getParentActivity() != null) { - Toast.makeText(getParentActivity(), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show(); + if (activity != null) { + Toast.makeText(activity, LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show(); } } }); @@ -9522,7 +9581,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. new SearchResult(203, LocaleController.getString("KeepMedia", R.string.KeepMedia), "keepMediaRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), new SearchResult(204, LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), "cacheRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), new SearchResult(205, LocaleController.getString("LocalDatabase", R.string.LocalDatabase), "databaseRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), - new SearchResult(206, LocaleController.getString("NetworkUsage", R.string.NetworkUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataUsageActivity())), + new SearchResult(206, LocaleController.getString("NetworkUsage", R.string.NetworkUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataUsage2Activity())), new SearchResult(207, LocaleController.getString("AutomaticMediaDownload", R.string.AutomaticMediaDownload), "mediaDownloadSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), new SearchResult(208, LocaleController.getString("WhenUsingMobileData", R.string.WhenUsingMobileData), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(0))), new SearchResult(209, LocaleController.getString("WhenConnectedOnWiFi", R.string.WhenConnectedOnWiFi), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(1))), @@ -9599,7 +9658,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. new SearchResult(400, LocaleController.getString("Language", R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())), new SearchResult(405, LocaleController.getString(R.string.ShowTranslateButton), LocaleController.getString(R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())), - MessagesController.getGlobalMainSettings().getBoolean("translate_button", false) ? new SearchResult(406, LocaleController.getString(R.string.DoNotTranslate), LocaleController.getString(R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())) : null, + MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled() ? new SearchResult(406, LocaleController.getString(R.string.DoNotTranslate), LocaleController.getString(R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())) : null, new SearchResult(402, LocaleController.getString("AskAQuestion", R.string.AskAQuestion), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> showDialog(AlertsCreator.createSupportAlert(ProfileActivity.this, null))), new SearchResult(403, LocaleController.getString("TelegramFAQ", R.string.TelegramFAQ), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> Browser.openUrl(getParentActivity(), LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl))), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java index f1c31c161..eee2f7b8b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java @@ -41,6 +41,7 @@ import org.telegram.messenger.DownloadController; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.ProxyRotationController; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.tgnet.ConnectionsManager; @@ -62,12 +63,14 @@ import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SlideChooseView; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ProxyListActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + private final static boolean IS_PROXY_ROTATION_AVAILABLE = true; private static final int MENU_DELETE = 0; private static final int MENU_SHARE = 1; @@ -83,13 +86,16 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente private int rowCount; private int useProxyRow; - private int useProxyDetailRow; + private int useProxyShadowRow; private int connectionsHeaderRow; private int proxyStartRow; private int proxyEndRow; private int proxyAddRow; - private int proxyDetailRow; + private int proxyShadowRow; private int callsRow; + private int rotationRow; + private int rotationTimeoutRow; + private int rotationTimeoutInfoRow; private int callsDetailRow; private int deleteAllRow; @@ -149,7 +155,7 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente checkImageView.setOnClickListener(v -> presentFragment(new ProxySettingsActivity(currentInfo))); checkBox = new CheckBox2(context, 21); - checkBox.setColor(Theme.key_radioBackground, Theme.key_radioBackground, Theme.key_checkboxCheck); + checkBox.setColor(Theme.key_checkbox, Theme.key_radioBackground, Theme.key_checkboxCheck); checkBox.setDrawBackgroundAsArc(14); checkBox.setVisibility(GONE); addView(checkBox, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 16, 0, 8, 0)); @@ -324,6 +330,7 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente SharedConfig.loadProxyList(); currentConnectionState = ConnectionsManager.getInstance(currentAccount).getConnectionState(); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxyChangedByRotation); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxySettingsChanged); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxyCheckDone); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.didUpdateConnectionState); @@ -340,6 +347,7 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente @Override public void onFragmentDestroy() { super.onFragmentDestroy(); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.proxyChangedByRotation); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.proxySettingsChanged); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.proxyCheckDone); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.didUpdateConnectionState); @@ -404,6 +412,7 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente } } useProxySettings = !useProxySettings; + updateRows(true); SharedPreferences preferences = MessagesController.getGlobalMainSettings(); @@ -434,7 +443,13 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente cell.updateStatus(); } } + } else if (position == rotationRow) { + SharedConfig.proxyRotationEnabled = !SharedConfig.proxyRotationEnabled; + TextCheckCell textCheckCell = (TextCheckCell) view; + textCheckCell.setChecked(SharedConfig.proxyRotationEnabled); + SharedConfig.saveConfig(); + updateRows(true); } else if (position == callsRow) { useProxyForCalls = !useProxyForCalls; TextCheckCell textCheckCell = (TextCheckCell) view; @@ -609,7 +624,25 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente private void updateRows(boolean notify) { rowCount = 0; useProxyRow = rowCount++; - useProxyDetailRow = rowCount++; + if (useProxySettings && SharedConfig.currentProxy != null && SharedConfig.proxyList.size() > 1 && IS_PROXY_ROTATION_AVAILABLE) { + rotationRow = rowCount++; + if (SharedConfig.proxyRotationEnabled) { + rotationTimeoutRow = rowCount++; + rotationTimeoutInfoRow = rowCount++; + } else { + rotationTimeoutRow = -1; + rotationTimeoutInfoRow = -1; + } + } else { + rotationRow = -1; + rotationTimeoutRow = -1; + rotationTimeoutInfoRow = -1; + } + if (rotationTimeoutInfoRow == -1) { + useProxyShadowRow = rowCount++; + } else { + useProxyShadowRow = -1; + } connectionsHeaderRow = rowCount++; if (notify) { @@ -653,22 +686,22 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente proxyEndRow = -1; } proxyAddRow = rowCount++; - proxyDetailRow = rowCount++; + proxyShadowRow = rowCount++; if (SharedConfig.currentProxy == null || SharedConfig.currentProxy.secret.isEmpty()) { boolean change = callsRow == -1; callsRow = rowCount++; callsDetailRow = rowCount++; if (!notify && change) { - listAdapter.notifyItemChanged(proxyDetailRow); - listAdapter.notifyItemRangeInserted(proxyDetailRow + 1, 2); + listAdapter.notifyItemChanged(proxyShadowRow); + listAdapter.notifyItemRangeInserted(proxyShadowRow + 1, 2); } } else { boolean change = callsRow != -1; callsRow = -1; callsDetailRow = -1; if (!notify && change) { - listAdapter.notifyItemChanged(proxyDetailRow); - listAdapter.notifyItemRangeRemoved(proxyDetailRow + 1, 2); + listAdapter.notifyItemChanged(proxyShadowRow); + listAdapter.notifyItemRangeRemoved(proxyShadowRow + 1, 2); } } if (proxyList.size() >= 10) { @@ -719,7 +752,18 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente @Override public void didReceivedNotification(int id, int account, Object... args) { - if (id == NotificationCenter.proxySettingsChanged) { + if (id == NotificationCenter.proxyChangedByRotation) { + listView.forAllChild(view -> { + RecyclerView.ViewHolder holder = listView.getChildViewHolder(view); + if (holder.itemView instanceof TextDetailProxyCell) { + TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; + cell.setChecked(cell.currentInfo == SharedConfig.currentProxy); + cell.updateStatus(); + } + }); + + updateRows(false); + } else if (id == NotificationCenter.proxySettingsChanged) { updateRows(true); } else if (id == NotificationCenter.didUpdateConnectionState) { int state = ConnectionsManager.getInstance(account).getConnectionState(); @@ -772,6 +816,13 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente } private class ListAdapter extends RecyclerListView.SelectionAdapter { + private final static int VIEW_TYPE_SHADOW = 0, + VIEW_TYPE_TEXT_SETTING = 1, + VIEW_TYPE_HEADER = 2, + VIEW_TYPE_TEXT_CHECK = 3, + VIEW_TYPE_INFO = 4, + VIEW_TYPE_PROXY_DETAIL = 5, + VIEW_TYPE_SLIDE_CHOOSER = 6; public static final int PAYLOAD_CHECKED_CHANGED = 0; public static final int PAYLOAD_SELECTION_CHANGED = 1; @@ -828,15 +879,15 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: { - if (position == proxyDetailRow && callsRow == -1) { + case VIEW_TYPE_SHADOW: { + if (position == proxyShadowRow && callsRow == -1) { holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } else { holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } break; } - case 1: { + case VIEW_TYPE_TEXT_SETTING: { TextSettingsCell textCell = (TextSettingsCell) holder.itemView; textCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); if (position == proxyAddRow) { @@ -847,31 +898,36 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente } break; } - case 2: { + case VIEW_TYPE_HEADER: { HeaderCell headerCell = (HeaderCell) holder.itemView; if (position == connectionsHeaderRow) { headerCell.setText(LocaleController.getString("ProxyConnections", R.string.ProxyConnections)); } break; } - case 3: { + case VIEW_TYPE_TEXT_CHECK: { TextCheckCell checkCell = (TextCheckCell) holder.itemView; if (position == useProxyRow) { - checkCell.setTextAndCheck(LocaleController.getString("UseProxySettings", R.string.UseProxySettings), useProxySettings, false); + checkCell.setTextAndCheck(LocaleController.getString("UseProxySettings", R.string.UseProxySettings), useProxySettings, rotationRow != -1); } else if (position == callsRow) { checkCell.setTextAndCheck(LocaleController.getString("UseProxyForCalls", R.string.UseProxyForCalls), useProxyForCalls, false); + } else if (position == rotationRow) { + checkCell.setTextAndCheck(LocaleController.getString(R.string.UseProxyRotation), SharedConfig.proxyRotationEnabled, true); } break; } - case 4: { + case VIEW_TYPE_INFO: { TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; if (position == callsDetailRow) { cell.setText(LocaleController.getString("UseProxyForCallsInfo", R.string.UseProxyForCallsInfo)); - cell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + cell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } else if (position == rotationTimeoutInfoRow) { + cell.setText(LocaleController.getString(R.string.ProxyRotationTimeoutInfo)); + cell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } break; } - case 5: { + case VIEW_TYPE_PROXY_DETAIL: { TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; SharedConfig.ProxyInfo info = proxyList.get(position - proxyStartRow); cell.setProxy(info); @@ -880,13 +936,29 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente cell.setSelectionEnabled(!selectedItems.isEmpty(), false); break; } + case VIEW_TYPE_SLIDE_CHOOSER: { + if (position == rotationTimeoutRow) { + SlideChooseView chooseView = (SlideChooseView) holder.itemView; + ArrayList options = new ArrayList<>(ProxyRotationController.ROTATION_TIMEOUTS); + String[] values = new String[options.size()]; + for (int i = 0; i < options.size(); i++) { + values[i] = LocaleController.formatString(R.string.ProxyRotationTimeoutSeconds, options.get(i)); + } + chooseView.setCallback(i -> { + SharedConfig.proxyRotationTimeout = i; + SharedConfig.saveConfig(); + }); + chooseView.setOptions(SharedConfig.proxyRotationTimeout, values); + } + break; + } } } @SuppressWarnings("unchecked") @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List payloads) { - if (holder.getItemViewType() == 5 && !payloads.isEmpty()) { + if (holder.getItemViewType() == VIEW_TYPE_PROXY_DETAIL && !payloads.isEmpty()) { TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; if (payloads.contains(PAYLOAD_SELECTION_CHANGED)) { cell.setItemSelected(selectedItems.contains(proxyList.get(position - proxyStartRow)), true); @@ -894,12 +966,14 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente if (payloads.contains(PAYLOAD_SELECTION_MODE_CHANGED)) { cell.setSelectionEnabled(!selectedItems.isEmpty(), true); } - } else if (holder.getItemViewType() == 3 && payloads.contains(PAYLOAD_CHECKED_CHANGED)) { + } else if (holder.getItemViewType() == VIEW_TYPE_TEXT_CHECK && payloads.contains(PAYLOAD_CHECKED_CHANGED)) { TextCheckCell checkCell = (TextCheckCell) holder.itemView; if (position == useProxyRow) { checkCell.setChecked(useProxySettings); } else if (position == callsRow) { checkCell.setChecked(useProxyForCalls); + } else if (position == rotationRow) { + checkCell.setChecked(SharedConfig.proxyRotationEnabled); } } else { super.onBindViewHolder(holder, position, payloads); @@ -909,13 +983,15 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { int viewType = holder.getItemViewType(); - if (viewType == 3) { + if (viewType == VIEW_TYPE_TEXT_CHECK) { TextCheckCell checkCell = (TextCheckCell) holder.itemView; int position = holder.getAdapterPosition(); if (position == useProxyRow) { checkCell.setChecked(useProxySettings); } else if (position == callsRow) { checkCell.setChecked(useProxyForCalls); + } else if (position == rotationRow) { + checkCell.setChecked(SharedConfig.proxyRotationEnabled); } } } @@ -923,33 +999,37 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int position = holder.getAdapterPosition(); - return position == useProxyRow || position == callsRow || position == proxyAddRow || position == deleteAllRow || position >= proxyStartRow && position < proxyEndRow; + return position == useProxyRow || position == rotationRow || position == callsRow || position == proxyAddRow || position == deleteAllRow || position >= proxyStartRow && position < proxyEndRow; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_SHADOW: view = new ShadowSectionCell(mContext); break; - case 1: + case VIEW_TYPE_TEXT_SETTING: view = new TextSettingsCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 2: + case VIEW_TYPE_HEADER: view = new HeaderCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 3: + case VIEW_TYPE_TEXT_CHECK: view = new TextCheckCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 4: + case VIEW_TYPE_INFO: view = new TextInfoPrivacyCell(mContext); - view.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + view.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); break; - case 5: + case VIEW_TYPE_SLIDE_CHOOSER: + view = new SlideChooseView(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_PROXY_DETAIL: default: view = new TextDetailProxyCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -962,9 +1042,9 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente @Override public long getItemId(int position) { // Random stable ids, could be anything non-repeating - if (position == useProxyDetailRow) { + if (position == useProxyShadowRow) { return -1; - } else if (position == proxyDetailRow) { + } else if (position == proxyShadowRow) { return -2; } else if (position == proxyAddRow) { return -3; @@ -976,6 +1056,12 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente return -6; } else if (position == deleteAllRow) { return -8; + } else if (position == rotationRow) { + return -9; + } else if (position == rotationTimeoutRow) { + return -10; + } else if (position == rotationTimeoutInfoRow) { + return -11; } else if (position >= proxyStartRow && position < proxyEndRow) { return proxyList.get(position - proxyStartRow).hashCode(); } else { @@ -985,18 +1071,20 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente @Override public int getItemViewType(int position) { - if (position == useProxyDetailRow || position == proxyDetailRow) { - return 0; + if (position == useProxyShadowRow || position == proxyShadowRow) { + return VIEW_TYPE_SHADOW; } else if (position == proxyAddRow || position == deleteAllRow) { - return 1; - } else if (position == useProxyRow || position == callsRow) { - return 3; + return VIEW_TYPE_TEXT_SETTING; + } else if (position == useProxyRow || position == rotationRow || position == callsRow) { + return VIEW_TYPE_TEXT_CHECK; } else if (position == connectionsHeaderRow) { - return 2; + return VIEW_TYPE_HEADER; + } else if (position == rotationTimeoutRow) { + return VIEW_TYPE_SLIDE_CHOOSER; } else if (position >= proxyStartRow && position < proxyEndRow) { - return 5; + return VIEW_TYPE_PROXY_DETAIL; } else { - return 4; + return VIEW_TYPE_INFO; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/RestrictedLanguagesSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/RestrictedLanguagesSelectActivity.java index a74266424..a9151e2c8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/RestrictedLanguagesSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/RestrictedLanguagesSelectActivity.java @@ -8,56 +8,60 @@ package org.telegram.ui; -import android.animation.ValueAnimator; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; +import android.content.res.Resources; +import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; import android.widget.EditText; import android.widget.FrameLayout; -import android.widget.LinearLayout; import android.widget.TextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.TranslateController; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; -import org.telegram.ui.ActionBar.AlertDialog; -import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.ActionBar.ThemeDescription; -import org.telegram.ui.Cells.CheckBoxCell; -import org.telegram.ui.Cells.HeaderCell; -import org.telegram.ui.Cells.LanguageCell; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.LanguageCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCheckbox2Cell; -import org.telegram.ui.Cells.TextCheckCell; -import org.telegram.ui.Cells.TextInfoPrivacyCell; -import org.telegram.ui.Cells.TextRadioCell; -import org.telegram.ui.Cells.TextSettingsCell; -import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.TranslateAlert2; +import java.io.BufferedReader; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; -import java.util.Set; +import java.util.List; import java.util.Timer; -import java.util.TimerTask; - -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; public class RestrictedLanguagesSelectActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { @@ -72,52 +76,22 @@ public class RestrictedLanguagesSelectActivity extends BaseFragment implements N private Timer searchTimer; private ArrayList searchResult; private ArrayList sortedLanguages; -// private ArrayList unofficialLanguages; private SharedPreferences preferences; - private SharedPreferences.OnSharedPreferenceChangeListener listener; - private HashSet selectedLanguages = null; + private HashSet firstSelectedLanguages; + private HashSet selectedLanguages; public static HashSet getRestrictedLanguages() { -// String currentLangCode = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; -// String[] onlyCurrentLang = new String[] { currentLangCode }; - return new HashSet<>(MessagesController.getGlobalMainSettings().getStringSet("translate_button_restricted_languages", new HashSet(/*Arrays.asList(onlyCurrentLang)*/))); + String currentLangCode = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; + String[] onlyCurrentLang = new String[] { currentLangCode }; + return new HashSet<>(MessagesController.getGlobalMainSettings().getStringSet("translate_button_restricted_languages", new HashSet(Arrays.asList(onlyCurrentLang)))); } @Override public boolean onFragmentCreate() { preferences = MessagesController.getGlobalMainSettings(); + firstSelectedLanguages = getRestrictedLanguages(); selectedLanguages = getRestrictedLanguages(); - preferences.registerOnSharedPreferenceChangeListener(listener = new SharedPreferences.OnSharedPreferenceChangeListener() { - public int langPos(String lng) { - if (lng == null) - return -1; - ArrayList arr = (searching ? searchResult : sortedLanguages); - if (arr == null) - return -1; - for (int i = 0; i < arr.size(); ++i) - if (lng.equals(arr.get(i).pluralLangCode)) - return i; - return -1; - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { - preferences = sharedPreferences; - HashSet newSelectedLanguages = getRestrictedLanguages(); - if (listView != null && listView.getAdapter() != null) { - RecyclerView.Adapter adapter = listView.getAdapter(); - int offset = !searching ? 1 : 0; - for (String lng : selectedLanguages) - if (!newSelectedLanguages.contains(lng)) - adapter.notifyItemChanged(langPos(lng) + offset); - for (String lng : newSelectedLanguages) - if (!selectedLanguages.contains(lng)) - adapter.notifyItemChanged(langPos(lng) + offset); - } - selectedLanguages = newSelectedLanguages; - } - }); fillLanguages(); LocaleController.getInstance().loadRemoteLanguages(currentAccount); @@ -125,13 +99,55 @@ public class RestrictedLanguagesSelectActivity extends BaseFragment implements N return super.onFragmentCreate(); } + private void rebind(int position) { + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + RecyclerView.ViewHolder holder = listView.getChildViewHolder(child); + if (holder == null) { + continue; + } + int childPosition = holder.getAdapterPosition(); + if (childPosition == RecyclerView.NO_POSITION) { + continue; + } + if (childPosition == position) { + listAdapter.onBindViewHolder(holder, position); + return; + } + } + } + @Override public void onFragmentDestroy() { super.onFragmentDestroy(); - preferences.unregisterOnSharedPreferenceChangeListener(listener); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.suggestedLangpack); } + public static boolean toggleLanguage(String language, boolean doNotTranslate) { + if (language == null) { + return false; + } + LocaleController.LocaleInfo currentLocaleInfo = LocaleController.getInstance().getCurrentLocaleInfo(); + HashSet selectedLanguages = getRestrictedLanguages(); + if (language != null && language.equals(currentLocaleInfo.pluralLangCode) && doNotTranslate) { +// AndroidUtilities.shakeViewSpring(view); +// BotWebViewVibrationEffect.APP_ERROR.vibrate(); + return false; + } + if (!doNotTranslate) { + selectedLanguages.remove(language); + } else { + selectedLanguages.add(language); + } + if (selectedLanguages.size() == 1 && selectedLanguages.contains(currentLocaleInfo.pluralLangCode)) { + MessagesController.getGlobalMainSettings().edit().remove("translate_button_restricted_languages").commit(); + } else { + MessagesController.getGlobalMainSettings().edit().putStringSet("translate_button_restricted_languages", selectedLanguages).commit(); + } + TranslateController.invalidateSuggestedLanguageCodes(); + return true; + } + @Override public View createView(Context context) { searching = false; @@ -214,6 +230,7 @@ public class RestrictedLanguagesSelectActivity extends BaseFragment implements N return; } boolean search = listView.getAdapter() == searchListViewAdapter; + final int realPosition = position; if (!search) position--; LocaleController.LocaleInfo localeInfo; @@ -225,20 +242,24 @@ public class RestrictedLanguagesSelectActivity extends BaseFragment implements N if (localeInfo != null) { LocaleController.LocaleInfo currentLocaleInfo = LocaleController.getInstance().getCurrentLocaleInfo(); String langCode = localeInfo.pluralLangCode; - if (langCode != null && langCode.equals(currentLocaleInfo.pluralLangCode)) { - AndroidUtilities.shakeView(((TextCheckbox2Cell) view).checkbox); + boolean value = selectedLanguages.contains(langCode); + if (langCode != null && langCode.equals(currentLocaleInfo.pluralLangCode) && value) { + AndroidUtilities.shakeViewSpring(view); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); return; } - boolean value = selectedLanguages.contains(langCode); - HashSet newSelectedLanguages = new HashSet(selectedLanguages); if (value) - newSelectedLanguages.removeIf(s -> s != null && s.equals(langCode)); + selectedLanguages.removeIf(s -> s != null && s.equals(langCode)); else - newSelectedLanguages.add(langCode); - if (newSelectedLanguages.size() == 1 && newSelectedLanguages.contains(currentLocaleInfo.pluralLangCode)) - preferences.edit().remove("translate_button_restricted_languages").apply(); - else - preferences.edit().putStringSet("translate_button_restricted_languages", newSelectedLanguages).apply(); + selectedLanguages.add(langCode); + if (selectedLanguages.size() == 1 && selectedLanguages.contains(currentLocaleInfo.pluralLangCode)) { + preferences.edit().remove("translate_button_restricted_languages").remove("translate_button_restricted_languages_changed").apply(); + } else { + preferences.edit().putStringSet("translate_button_restricted_languages", selectedLanguages).putBoolean("translate_button_restricted_languages_changed", true).apply(); + } + rebind(realPosition); + + MessagesController.getInstance(currentAccount).getTranslateController().checkRestrictedLanguagesUpdate(); } }); @@ -331,11 +352,17 @@ public class RestrictedLanguagesSelectActivity extends BaseFragment implements N ArrayList arrayList = LocaleController.getInstance().languages; for (int a = 0, size = arrayList.size(); a < size; a++) { LocaleController.LocaleInfo info = arrayList.get(a); - if (info != null && info.serverIndex != Integer.MAX_VALUE/* && (info.pluralLangCode == null || !info.pluralLangCode.equals(currentLocale.pluralLangCode))*/) { + if (info != null && info.serverIndex != Integer.MAX_VALUE && !"en_raw".equals(info.shortName) && (info == currentLocale || !firstSelectedLanguages.contains(info.pluralLangCode))) { sortedLanguages.add(info); } } Collections.sort(sortedLanguages, comparator); + for (int a = 0, size = arrayList.size(); a < size; a++) { + LocaleController.LocaleInfo info = arrayList.get(a); + if (info != null && info.serverIndex != Integer.MAX_VALUE && !"en_raw".equals(info.shortName) && !(info == currentLocale || !firstSelectedLanguages.contains(info.pluralLangCode))) { + sortedLanguages.add(1, info); + } + } } @Override @@ -467,23 +494,21 @@ public class RestrictedLanguagesSelectActivity extends BaseFragment implements N case 0: { if (!search) position--; -// LanguageCell textSettingsCell = (LanguageCell) holder.itemView; TextCheckbox2Cell textSettingsCell = (TextCheckbox2Cell) holder.itemView; - LocaleController.LocaleInfo localeInfo; - boolean last; + LocaleController.LocaleInfo localeInfo = null; + boolean last = false; if (search) { - localeInfo = searchResult.get(position); + if (position >= 0 && position < searchResult.size()) { + localeInfo = searchResult.get(position); + } last = position == searchResult.size() - 1; - } /*else if (!unofficialLanguages.isEmpty() && position >= 0 && position < unofficialLanguages.size()) { - localeInfo = unofficialLanguages.get(position); - last = position == unofficialLanguages.size() - 1; - } */else { -// if (!unofficialLanguages.isEmpty()) { -// position -= unofficialLanguages.size() + 1; -// } + } else if (position >= 0 && position < sortedLanguages.size()) { localeInfo = sortedLanguages.get(position); last = position == sortedLanguages.size() - 1; } + if (localeInfo == null) { + return; + } String langCode = localeInfo.pluralLangCode; boolean value = selectedLanguages.contains(langCode); if (localeInfo.isLocal()) { @@ -491,9 +516,7 @@ public class RestrictedLanguagesSelectActivity extends BaseFragment implements N } else { textSettingsCell.setTextAndValue(localeInfo.name, localeInfo.nameEnglish, false, !last); } - - boolean isCurrent = langCode != null && langCode.equals(LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode); - textSettingsCell.setChecked(value || isCurrent); + textSettingsCell.setChecked(value); break; } case 1: { @@ -558,4 +581,207 @@ public class RestrictedLanguagesSelectActivity extends BaseFragment implements N return themeDescriptions; } + + public static void cleanup() { + MessagesController.getGlobalMainSettings().edit() + .remove("translate_button_restricted_languages_changed") + .remove("translate_button_restricted_languages_version") + .remove("translate_button_restricted_languages") + .apply(); + checkRestrictedLanguages(false); + } + + public static final int LAST_DO_NOT_TRANSLATE_VERSION = 2; + public static void checkRestrictedLanguages(boolean accountsChanged) { + boolean manualChanged = MessagesController.getGlobalMainSettings().getBoolean("translate_button_restricted_languages_changed", false); + int version = MessagesController.getGlobalMainSettings().getInt("translate_button_restricted_languages_version", 0); + + if (version != LAST_DO_NOT_TRANSLATE_VERSION || accountsChanged && !manualChanged) { + getExtendedDoNotTranslate(languages -> { + final String currentLangCode = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; + + languages.addAll(getRestrictedLanguages()); + SharedPreferences.Editor edit = MessagesController.getGlobalMainSettings().edit(); + if (languages.size() == 1 && TextUtils.equals(languages.iterator().next(), currentLangCode)) { + edit.remove("translate_button_restricted_languages"); + } else { + edit.putStringSet("translate_button_restricted_languages", languages); + } + edit.putInt("translate_button_restricted_languages_version", LAST_DO_NOT_TRANSLATE_VERSION).apply(); + + for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; ++i) { + final int account = i; + try { + MessagesController.getInstance(account).getTranslateController().checkRestrictedLanguagesUpdate(); + } catch (Exception ignore) {} + } + }); + } + } + + public static void getExtendedDoNotTranslate(Utilities.Callback> onDone) { + if (onDone == null) { + return; + } + + final HashSet result = new HashSet<>(); + + final HashMap countries = new HashMap<>(); +// final HashMap languages = new HashMap<>(); + final HashMap uniquePhoneCodes = new HashMap<>(); + +// final Utilities.Callback pushCountry = countryCode -> { +// if (countryCode == null) { +// return; +// } +// String[] countryLanguages = languages.get(countryCode.toUpperCase()); +// if (countryLanguages == null) { +// return; +// } +// for (int j = 1; j < Math.min(2, countryLanguages.length); ++j) { +// String language = countryLanguages[j]; +// if (language.contains("-")) { +// language = language.split("-")[0]; +// } +// if (TranslateAlert2.languageName(language) != null) { +// result.add(language); +// } +// } +// }; + + Utilities.doCallbacks( + next -> { + try { + String language = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; + if (TranslateAlert2.languageName(language) != null) { + result.add(language); + } + } catch (Exception e0) { + FileLog.e(e0); + } + next.run(); + }, + next -> { + try { + String language = Resources.getSystem().getConfiguration().locale.getLanguage(); + if (TranslateAlert2.languageName(language) != null) { + result.add(language); + } + } catch (Exception e1) { + FileLog.e(e1); + } + next.run(); + }, + next -> { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(ApplicationLoader.applicationContext.getResources().getAssets().open("countries.txt"))); + ArrayList multipleCodes = new ArrayList<>(); + String line; + while ((line = reader.readLine()) != null) { + String[] args = line.split(";"); + if (args.length >= 3) { + countries.put(args[2], args[1]); + if (uniquePhoneCodes.containsKey(args[0]) && !"7".equals(args[0])) { + multipleCodes.add(args[0]); + uniquePhoneCodes.remove(args[0]); + } else if (!multipleCodes.contains(args[0])) { + uniquePhoneCodes.put(args[0], args[1]); + } + } + } + reader.close(); + +// reader = new BufferedReader(new InputStreamReader(ApplicationLoader.applicationContext.getResources().getAssets().open("languages.txt"))); +// while ((line = reader.readLine()) != null) { +// String[] args = line.split(","); +// if (args.length >= 2) { +// languages.put(args[0], args); +// } +// } +// reader.close(); + } catch (Exception e) { + FileLog.e(e); + } + next.run(); + }, +// next -> { +// ArrayList> getAuthorizationsCallbacks = new ArrayList<>(); +// for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; ++i) { +// final int account = i; +// if (UserConfig.getInstance(account).getClientUserId() != 0 && !ConnectionsManager.getInstance(account).isTestBackend()) { +// getAuthorizationsCallbacks.add(nextInternal -> { +// try { +// ConnectionsManager.getInstance(account).sendRequest(new TLRPC.TL_account_getAuthorizations(), (response, error) -> AndroidUtilities.runOnUIThread(() -> { +// if (error == null) { +// TLRPC.TL_account_authorizations res = (TLRPC.TL_account_authorizations) response; +// if (!res.authorizations.isEmpty()) { +// TLRPC.TL_authorization auth = res.authorizations.get(0); +// String[] separated = auth.country.split(", "); +// if (separated.length > 0) { +// pushCountry.run(countries.get(separated[separated.length - 1])); +// } +// } +// } +// nextInternal.run(); +// })); +// } catch (Exception e2) { +// FileLog.e(e2); +// nextInternal.run(); +// } +// }); +// } +// } +// getAuthorizationsCallbacks.add(n -> next.run()); +// Utilities.doCallbacks(getAuthorizationsCallbacks.toArray(new Utilities.Callback[0])); +// }, +// next -> { +// for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; ++i) { +// final int account = i; +// try { +// TLRPC.User user = UserConfig.getInstance(account).getCurrentUser(); +// if (user != null && user.phone != null) { +// for (int j = 4; j > 0; j--) { +// String code = user.phone.substring(0, j); +// String countryCode = uniquePhoneCodes.get(code); +// if (countryCode != null) { +// pushCountry.run(countryCode); +// break; +// } +// } +// } +// } catch (Exception e3) { +// FileLog.e(e3); +// } +// } +// next.run(); +// }, + next -> { + try { + InputMethodManager imm = (InputMethodManager) ApplicationLoader.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE); + List ims = imm.getEnabledInputMethodList(); + + for (InputMethodInfo method : ims) { + List submethods = imm.getEnabledInputMethodSubtypeList(method, true); + for (InputMethodSubtype submethod : submethods) { + if ("keyboard".equals(submethod.getMode())) { + String currentLocale = submethod.getLocale(); + if (currentLocale != null && currentLocale.contains("_")) { + currentLocale = currentLocale.split("_")[0]; + } + + if (TranslateAlert2.languageName(currentLocale) != null) { + result.add(currentLocale); + } + } + } + } + } catch (Exception e4) { + FileLog.e(e4); + } + + next.run(); + }, + next -> onDone.run(result) + ); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SaveToGallerySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SaveToGallerySettingsActivity.java new file mode 100644 index 000000000..a8cbe0efb --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/SaveToGallerySettingsActivity.java @@ -0,0 +1,663 @@ +package org.telegram.ui; + +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS; +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP; +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; + +import android.content.Context; +import android.graphics.Canvas; +import android.os.Bundle; +import android.util.LongSparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +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.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.DialogObject; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.SaveToGallerySettingsHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Cells.UserCell2; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SeekBarView; + +import java.util.ArrayList; +import java.util.Objects; + +public class SaveToGallerySettingsActivity extends BaseFragment { + + int type; + long dialogId; + SaveToGallerySettingsHelper.DialogException dialogException; + boolean isNewException; + + public SaveToGallerySettingsActivity(Bundle bundle) { + super(bundle); + } + + @Override + public boolean onFragmentCreate() { + type = getArguments().getInt("type"); + exceptionsDialogs = getUserConfig().getSaveGalleryExceptions(type); + dialogId = getArguments().getLong("dialog_id"); + if (dialogId != 0) { + dialogException = UserConfig.getInstance(currentAccount).getSaveGalleryExceptions(type).get(dialogId); + if (dialogException == null) { + isNewException = true; + dialogException = new SaveToGallerySettingsHelper.DialogException(); + SaveToGallerySettingsHelper.Settings globalSettings = SaveToGallerySettingsHelper.getSettings(type); + + dialogException.savePhoto = globalSettings.savePhoto; + dialogException.saveVideo = globalSettings.saveVideo; + dialogException.limitVideo = globalSettings.limitVideo; + + dialogException.dialogId = dialogId; + } + } + return super.onFragmentCreate(); + } + + private final int VIEW_TYPE_ADD_EXCEPTION = 1; + private final int VIEW_TYPE_CHAT = 2; + private final int VIEW_TYPE_DIVIDER = 3; + private final int VIEW_TYPE_DELETE_ALL = 4; + private final int VIEW_TYPE_HEADER = 5; + private final int VIEW_TYPE_TOGGLE = 6; + private final int VIEW_TYPE_DIVIDER_INFO = 7; + private final int VIEW_TYPE_CHOOSER = 8; + private static final int VIEW_TYPE_USER_INFO = 9; + private final int VIEW_TYPE_DIVIDER_LAST = 10; + + + int savePhotosRow; + int saveVideosRow; + int videoDividerRow; + + Adapter adapter; + + RecyclerListView recyclerListView; + + ArrayList items = new ArrayList<>(); + LongSparseArray exceptionsDialogs = new LongSparseArray<>(); + + @Override + public View createView(Context context) { + FrameLayout frameLayout = new FrameLayout(context); + fragmentView = frameLayout; + + actionBar.setBackButtonDrawable(new BackDrawable(false)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + return; + } + } + }); + if (dialogException != null) { + if (isNewException) { + actionBar.setTitle(LocaleController.getString(R.string.NotificationsNewException)); + } else { + actionBar.setTitle(LocaleController.getString(R.string.SaveToGalleryException)); + } + } else { + if (type == SAVE_TO_GALLERY_FLAG_PEER) { + actionBar.setTitle(LocaleController.getString(R.string.SaveToGalleryPrivate)); + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + actionBar.setTitle(LocaleController.getString(R.string.SaveToGalleryGroups)); + } else { + actionBar.setTitle(LocaleController.getString(R.string.SaveToGalleryChannels)); + } + } + + recyclerListView = new RecyclerListView(context); + DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator(); + defaultItemAnimator.setDurations(400); + defaultItemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + defaultItemAnimator.setDelayAnimations(false); + defaultItemAnimator.setSupportsChangeAnimations(false); + recyclerListView.setItemAnimator(defaultItemAnimator); + recyclerListView.setLayoutManager(new LinearLayoutManager(context)); + recyclerListView.setAdapter(adapter = new Adapter()); + recyclerListView.setOnItemClickListener((view, position, x, y) -> { + if (position == savePhotosRow) { + SaveToGallerySettingsHelper.Settings settings = getSettings(); + settings.savePhoto = !settings.savePhoto; + onSettingsUpdated(); + updateRows(); + } else if (position == saveVideosRow) { + SaveToGallerySettingsHelper.Settings settings = getSettings(); + settings.saveVideo = !settings.saveVideo; + onSettingsUpdated(); + updateRows(); + } else if (items.get(position).viewType == VIEW_TYPE_ADD_EXCEPTION) { + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putBoolean("checkCanWrite", false); + if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY); + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); + } else { + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_USERS_ONLY); + } + args.putBoolean("allowGlobalSearch", false); + DialogsActivity activity = new DialogsActivity(args); + activity.setDelegate((fragment, dids, message, param) -> { + Bundle args2 = new Bundle(); + args2.putLong("dialog_id", dids.get(0).dialogId); + args2.putInt("type", type); + SaveToGallerySettingsActivity addExceptionActivity = new SaveToGallerySettingsActivity(args2); + presentFragment(addExceptionActivity, true); + return true; + }); + presentFragment(activity); + } else if (items.get(position).viewType == VIEW_TYPE_CHAT) { + Bundle args2 = new Bundle(); + args2.putLong("dialog_id", items.get(position).exception.dialogId); + args2.putInt("type", type); + SaveToGallerySettingsActivity addExceptionActivity = new SaveToGallerySettingsActivity(args2); + presentFragment(addExceptionActivity); + } else if (items.get(position).viewType == VIEW_TYPE_DELETE_ALL) { + AlertDialog alertDialog = AlertsCreator.createSimpleAlert(getContext(), + LocaleController.getString("NotificationsDeleteAllExceptionTitle", R.string.NotificationsDeleteAllExceptionTitle), + LocaleController.getString("NotificationsDeleteAllExceptionAlert", R.string.NotificationsDeleteAllExceptionAlert), + LocaleController.getString("Delete", R.string.Delete), + () -> { + exceptionsDialogs.clear(); + getUserConfig().updateSaveGalleryExceptions(type, exceptionsDialogs); + updateRows(); + }, null).create(); + alertDialog.show(); + alertDialog.redPositive(); + } + }); + recyclerListView.setOnItemLongClickListener((view, position, x, y) -> { + if (items.get(position).viewType == VIEW_TYPE_CHAT) { + + SaveToGallerySettingsHelper.DialogException exception = items.get(position).exception; + ActionBarPopupWindow.ActionBarPopupWindowLayout actionBarPopupWindowLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext()); + ActionBarMenuSubItem edit = ActionBarMenuItem.addItem(actionBarPopupWindowLayout, R.drawable.msg_customize, LocaleController.getString("EditException", R.string.EditException), false, null); + ActionBarMenuSubItem delete = ActionBarMenuItem.addItem(actionBarPopupWindowLayout, R.drawable.msg_delete, LocaleController.getString("DeleteException", R.string.DeleteException), false, null); + delete.setColors(Theme.getColor(Theme.key_windowBackgroundWhiteRedText), Theme.getColor(Theme.key_windowBackgroundWhiteRedText)); + ActionBarPopupWindow popupWindow = AlertsCreator.createSimplePopup(SaveToGallerySettingsActivity.this, actionBarPopupWindowLayout, view, x, y); + actionBarPopupWindowLayout.setParentWindow(popupWindow); + + edit.setOnClickListener(v -> { + popupWindow.dismiss(); + Bundle args2 = new Bundle(); + args2.putLong("dialog_id", items.get(position).exception.dialogId); + args2.putInt("type", type); + SaveToGallerySettingsActivity addExceptionActivity = new SaveToGallerySettingsActivity(args2); + presentFragment(addExceptionActivity); + }); + delete.setOnClickListener(v -> { + popupWindow.dismiss(); + LongSparseArray allExceptions = getUserConfig().getSaveGalleryExceptions(type); + allExceptions.remove(exception.dialogId); + getUserConfig().updateSaveGalleryExceptions(type, allExceptions); + updateRows(); + }); + return true; + } + return false; + }); + frameLayout.addView(recyclerListView); + frameLayout.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + if (dialogException != null) { + // ((ViewGroup.MarginLayoutParams)recyclerListView.getLayoutParams()).bottomMargin = AndroidUtilities.dp() + + FrameLayout button = new FrameLayout(getContext()); + button.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 8)); + + TextView textView = new TextView(getContext()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setText(isNewException ? LocaleController.getString("AddException", R.string.AddException) : LocaleController.getString("SaveException", R.string.SaveException)); + textView.setGravity(Gravity.CENTER); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + button.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + button.setOnClickListener(v -> { + if (isNewException) { + LongSparseArray allExceptions = getUserConfig().getSaveGalleryExceptions(type); + allExceptions.put(dialogException.dialogId, dialogException); + getUserConfig().updateSaveGalleryExceptions(type, allExceptions); + } + finishFragment(); + }); + frameLayout.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 16, 16, 16, 16)); + + } + updateRows(); + return fragmentView; + } + + private void updateRows() { + boolean animated = !isPaused && adapter != null; + ArrayList oldItems = null; + if (animated) { + oldItems = new ArrayList(); + oldItems.addAll(items); + } + + items.clear(); + + if (dialogException != null) { + items.add(new Item(VIEW_TYPE_USER_INFO)); + items.add(new Item(VIEW_TYPE_DIVIDER)); + } + items.add(new Item(VIEW_TYPE_HEADER, LocaleController.getString("SaveToGallery", R.string.SaveToGallery))); + savePhotosRow = items.size(); + items.add(new Item(VIEW_TYPE_TOGGLE)); + saveVideosRow = items.size(); + items.add(new Item(VIEW_TYPE_TOGGLE)); + String text = null; + if (dialogException != null) { + text = LocaleController.getString("SaveToGalleryHintCurrent", R.string.SaveToGalleryHintCurrent); + } else if (type == SAVE_TO_GALLERY_FLAG_PEER) { + text = LocaleController.getString("SaveToGalleryHintUser", R.string.SaveToGalleryHintUser); + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + text = LocaleController.getString("SaveToGalleryHintChannels", R.string.SaveToGalleryHintChannels); + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + text = LocaleController.getString("SaveToGalleryHintGroup", R.string.SaveToGalleryHintGroup); + } + items.add(new Item(VIEW_TYPE_DIVIDER_INFO, text)); + + if (getSettings().saveVideo) { + items.add(new Item(VIEW_TYPE_HEADER, LocaleController.getString("MaxVideoSize", R.string.MaxVideoSize))); + items.add(new Item(VIEW_TYPE_CHOOSER)); + videoDividerRow = items.size(); + items.add(new Item(VIEW_TYPE_DIVIDER_INFO)); + } else { + videoDividerRow = -1; + } + + if (dialogException == null) { + exceptionsDialogs = getUserConfig().getSaveGalleryExceptions(type); + items.add(new Item(VIEW_TYPE_ADD_EXCEPTION)); + boolean added = false; + for (int i = 0; i < exceptionsDialogs.size(); i++) { + items.add(new Item(VIEW_TYPE_CHAT, exceptionsDialogs.valueAt(i))); + added = true; + } + + if (added) { + items.add(new Item(VIEW_TYPE_DIVIDER)); + items.add(new Item(VIEW_TYPE_DELETE_ALL)); + } + items.add(new Item(VIEW_TYPE_DIVIDER_LAST)); + } + + if (adapter != null) { + if (oldItems != null) { + adapter.setItems(oldItems, items); + } else { + adapter.notifyDataSetChanged(); + } + } + } + + private class Adapter extends AdapterWithDiffUtils { + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = null; + switch (viewType) { + case VIEW_TYPE_USER_INFO: + UserCell2 userCell2 = new UserCell2(getContext(), 4, 0, getResourceProvider()); + TLObject object; + if (DialogObject.isUserDialog(dialogId)) { + object = MessagesController.getInstance(currentAccount).getUser(dialogId); + } else { + object = MessagesController.getInstance(currentAccount).getChat(-dialogId); + } + userCell2.setData(object, null, null, 0); + view = userCell2; + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_CHAT: + view = new UserCell(parent.getContext(), 4, 0, false, false); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_ADD_EXCEPTION: + TextCell textCell = new TextCell(parent.getContext()); + textCell.setTextAndIcon(LocaleController.getString("NotificationsAddAnException", R.string.NotificationsAddAnException), R.drawable.msg_contact_add, true); + textCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); + view = textCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_DIVIDER_LAST: + view = new ShadowSectionCell(parent.getContext()); + view.setBackgroundDrawable(Theme.getThemedDrawable(getContext(), R.drawable.greydivider_bottom, Theme.getColor(Theme.key_windowBackgroundGrayShadow, getResourceProvider()))); + break; + case VIEW_TYPE_DIVIDER: + view = new ShadowSectionCell(parent.getContext()); + break; + case VIEW_TYPE_DELETE_ALL: + textCell = new TextCell(parent.getContext()); + textCell.setText(LocaleController.getString("NotificationsDeleteAllException", R.string.NotificationsDeleteAllException), false); + textCell.setColors(null, Theme.key_windowBackgroundWhiteRedText5); + view = textCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_HEADER: + HeaderCell headerCell = new HeaderCell(parent.getContext()); + view = headerCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_TOGGLE: + TextCheckCell textCheckCell = new TextCheckCell(parent.getContext()); + view = textCheckCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_DIVIDER_INFO: + TextInfoPrivacyCell textInfoPrivacyCell = new TextInfoPrivacyCell(parent.getContext()); + view = textInfoPrivacyCell; + break; + case VIEW_TYPE_CHOOSER: + LinearLayout linearLayout = new LinearLayout(getContext()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + SeekBarView slideChooseView = new SeekBarView(getContext()); + FrameLayout textContainer = new FrameLayout(getContext()); + + SelectableAnimatedTextView lowerTextView = new SelectableAnimatedTextView(getContext()); + lowerTextView.setTextSize(AndroidUtilities.dp(13)); + lowerTextView.setText(AndroidUtilities.formatFileSize(1024 * 512, true)); + textContainer.addView(lowerTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM)); + + SelectableAnimatedTextView midTextView = new SelectableAnimatedTextView(getContext()); + midTextView.setTextSize(AndroidUtilities.dp(13)); + // midTextView.setText(AndroidUtilities.formatFileSize(1024 * 512, true)); + textContainer.addView(midTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); + + SelectableAnimatedTextView topTextView = new SelectableAnimatedTextView(getContext()); + topTextView.setTextSize(AndroidUtilities.dp(13)); + topTextView.setText(AndroidUtilities.formatFileSize(SaveToGallerySettingsHelper.MAX_VIDEO_LIMIT, true)); + textContainer.addView(topTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT | Gravity.BOTTOM)); + + + linearLayout.addView(textContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 20, 0, 21, 10, 21, 0)); + linearLayout.addView(slideChooseView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 38, 0, 5, 0, 5, 4)); + SaveToGallerySettingsHelper.Settings settings = getSettings(); + long currentValue = settings.limitVideo; + long maxValue = 4L * 1000 * 1024 * 1024; + if (currentValue < 0 || currentValue > SaveToGallerySettingsHelper.MAX_VIDEO_LIMIT) { + currentValue = SaveToGallerySettingsHelper.MAX_VIDEO_LIMIT; + } + slideChooseView.setReportChanges(true); + slideChooseView.setDelegate(new SeekBarView.SeekBarViewDelegate() { + @Override + public void onSeekBarDrag(boolean stop, float progress) { + boolean animated = slideChooseView.isAttachedToWindow(); + long limitExtremum = 100 * 1024 * 1024; + float limitExtremumF = 0.7f; + float limitExtremumK = 1f - limitExtremumF; + long value; + if (progress > limitExtremumF) { + float p = (progress - limitExtremumF) / limitExtremumK; + value = (long) (limitExtremum + (SaveToGallerySettingsHelper.MAX_VIDEO_LIMIT - limitExtremum) * p); + } else { + float p = progress / limitExtremumF; + value = (long) (1024 * 512 + (limitExtremum - 1024 * 512) * p); + } + if (progress >= 1f) { + lowerTextView.setSelectedInternal(false, animated); + midTextView.setSelectedInternal(false, animated); + topTextView.setSelectedInternal(true, animated); + AndroidUtilities.updateViewVisibilityAnimated(midTextView, false, 0.8f, animated); + } else if (progress == 0f) { + lowerTextView.setSelectedInternal(true, animated); + midTextView.setSelectedInternal(false, animated); + topTextView.setSelectedInternal(false, animated); + AndroidUtilities.updateViewVisibilityAnimated(midTextView, false, 0.8f, animated); + } else { + midTextView.setText( + LocaleController.formatString("UpToFileSize", R.string.UpToFileSize, + AndroidUtilities.formatFileSize(value, true) + ), false); + lowerTextView.setSelectedInternal(false, animated); + midTextView.setSelectedInternal(true, animated); + topTextView.setSelectedInternal(false, animated); + AndroidUtilities.updateViewVisibilityAnimated(midTextView, true, 0.8f, animated); + } + if (stop) { + getSettings().limitVideo = value; + onSettingsUpdated(); + } + + } + + @Override + public void onSeekBarPressed(boolean pressed) { + + } + }); + + long limitExtremum = 100 * 1024 * 1024; + float limitExtremumF = 0.7f; + float limitExtremumK = 1f - limitExtremumF; + long mimValue = 1024 * 512; + float currentProgress; + if (currentValue > limitExtremum * limitExtremumF) { + float p = (currentValue - limitExtremum) / (float) (maxValue - limitExtremum); + currentProgress = limitExtremumF + limitExtremumK * p; + } else { + float p = (currentValue - mimValue) / (float) (limitExtremum - mimValue); + currentProgress = limitExtremumF * p; + } + slideChooseView.setProgress(currentProgress); + slideChooseView.delegate.onSeekBarDrag(false, slideChooseView.getProgress()); + + view = linearLayout; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + } + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (items.get(position).viewType == VIEW_TYPE_ADD_EXCEPTION) { + TextCell cell = (TextCell) holder.itemView; + cell.setNeedDivider(exceptionsDialogs.size() > 0); + } else if (items.get(position).viewType == VIEW_TYPE_TOGGLE) { + TextCheckCell cell = (TextCheckCell) holder.itemView; + SaveToGallerySettingsHelper.Settings settings = getSettings(); + if (position == savePhotosRow) { + cell.setTextAndCheck(LocaleController.getString(R.string.SaveToGalleryPhotos), settings.savePhoto, true); + cell.setColorfullIcon(getThemedColor(Theme.key_statisticChartLine_lightblue), R.drawable.msg_filled_data_photos); + } else { + cell.setTextAndCheck(LocaleController.getString(R.string.SaveToGalleryVideos), settings.saveVideo, false); + cell.setColorfullIcon(getThemedColor(Theme.key_statisticChartLine_green), R.drawable.msg_filled_data_videos); + } + + } else if (items.get(position).viewType == VIEW_TYPE_DIVIDER_INFO) { + TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; + if (position == videoDividerRow) { + long limit = getSettings().limitVideo; + if (limit == -1) { + limit = 4L * 1000 * 1024 * 1024; + } + if (dialogException != null) { + cell.setText(LocaleController.formatString("SaveToGalleryVideoHintCurrent", R.string.SaveToGalleryVideoHintCurrent)); + } else if (type == SAVE_TO_GALLERY_FLAG_PEER) { + cell.setText(LocaleController.formatString("SaveToGalleryVideoHintUser", R.string.SaveToGalleryVideoHintUser)); + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + cell.setText(LocaleController.formatString("SaveToGalleryVideoHintChannels", R.string.SaveToGalleryVideoHintChannels)); + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + cell.setText(LocaleController.formatString("SaveToGalleryVideoHintGroup", R.string.SaveToGalleryVideoHintGroup)); + } + } else { + cell.setText(items.get(position).title); + } + } else if (items.get(position).viewType == VIEW_TYPE_HEADER) { + HeaderCell cell = (HeaderCell) holder.itemView; + cell.setText(items.get(position).title); + } else if (items.get(position).viewType == VIEW_TYPE_CHAT) { + UserCell cell = (UserCell) holder.itemView; + SaveToGallerySettingsHelper.DialogException exception = items.get(position).exception; + TLObject object = getMessagesController().getUserOrChat(exception.dialogId); + String title = null; + if (object instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) object; + if (user.self) { + title = LocaleController.getString("SavedMessages", R.string.SavedMessages); + } else { + title = ContactsController.formatName(user.first_name, user.last_name); + } + } else if (object instanceof TLRPC.Chat) { + TLRPC.Chat chat = (TLRPC.Chat) object; + title = chat.title; + } + cell.setSelfAsSavedMessages(true); + cell.setData(object, title, exception.createDescription(currentAccount), 0, !(position != items.size() - 1 && items.get(position + 1).viewType != VIEW_TYPE_CHAT)); + } + } + + @Override + public int getItemCount() { + return items.size(); + } + + @Override + public int getItemViewType(int position) { + return items.get(position).viewType; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == VIEW_TYPE_ADD_EXCEPTION || holder.getItemViewType() == VIEW_TYPE_CHAT + || holder.getItemViewType() == VIEW_TYPE_DELETE_ALL || holder.getItemViewType() == VIEW_TYPE_TOGGLE; + } + } + + private class Item extends AdapterWithDiffUtils.Item { + final SaveToGallerySettingsHelper.DialogException exception; + String title; + + + private Item(int viewType) { + super(viewType, false); + exception = null; + } + + private Item(int viewType, SaveToGallerySettingsHelper.DialogException exception) { + super(viewType, false); + this.exception = exception; + } + + private Item(int viewType, String title) { + super(viewType, false); + this.title = title; + exception = null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Item item = (Item) o; + if (viewType != item.viewType) { + return false; + } + if (title != null) { + return Objects.equals(title, item.title); + } + if (exception != null && item.exception != null) { + return exception.dialogId == item.exception.dialogId; + } + return true; + } + } + + SaveToGallerySettingsHelper.Settings getSettings() { + if (dialogException != null) { + return dialogException; + } + return SaveToGallerySettingsHelper.getSettings(type); + } + + @Override + public void onResume() { + super.onResume(); + updateRows(); + } + + private void onSettingsUpdated() { + if (isNewException) { + return; + } + if (dialogException != null) { + LongSparseArray allExceptions = getUserConfig().getSaveGalleryExceptions(type); + allExceptions.put(dialogException.dialogId, dialogException); + getUserConfig().updateSaveGalleryExceptions(type, allExceptions); + return; + } else { + SaveToGallerySettingsHelper.saveSettings(type); + } + } + + private class SelectableAnimatedTextView extends AnimatedTextView { + + boolean selected; + AnimatedFloat progressToSelect = new AnimatedFloat(this); + + public SelectableAnimatedTextView(Context context) { + super(context, true, true, false); + getDrawable().setAllowCancel(true); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + progressToSelect.set(selected ? 1f : 0); + setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_windowBackgroundWhiteGrayText), getThemedColor(Theme.key_windowBackgroundWhiteBlueText), progressToSelect.get())); + super.dispatchDraw(canvas); + } + + public void setSelectedInternal(boolean selected, boolean animated) { + if (this.selected != selected) { + this.selected = selected; + progressToSelect.set(selected ? 1f : 0, animated); + invalidate(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java index d0cb2350f..d9a9490d9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java @@ -26,6 +26,7 @@ import android.os.SystemClock; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; +import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; import android.util.SparseIntArray; @@ -50,6 +51,7 @@ import android.widget.PopupWindow; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import androidx.core.math.MathUtils; import androidx.recyclerview.widget.DefaultItemAnimator; @@ -76,6 +78,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; 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; @@ -103,11 +106,14 @@ import org.telegram.ui.Components.Premium.PremiumButtonView; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumLockIconView; import org.telegram.ui.Components.RLottieImageView; +import org.telegram.ui.Components.Reactions.CustomEmojiReactionsWindow; import org.telegram.ui.Components.Reactions.ReactionsEffectOverlay; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.Reactions.ReactionsUtils; import org.telegram.ui.Components.RecyclerAnimationScrollHelper; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SearchStateDrawable; +import org.telegram.ui.Components.StickerCategoriesListView; import java.lang.reflect.Field; import java.util.ArrayList; @@ -115,6 +121,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; @@ -124,6 +131,11 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public final static int TYPE_REACTIONS = 1; public final static int TYPE_SET_DEFAULT_REACTION = 2; public static final int TYPE_TOPIC_ICON = 3; + public static final int TYPE_AVATAR_CONSTRUCTOR = 4; + + private final int SPAN_COUNT_FOR_EMOJI = 8; + private final int SPAN_COUNT_FOR_STICKER = 5; + private final int SPAN_COUNT = 40; private final int RECENT_MAX_LINES = 5; private final int EXPAND_MAX_LINES = 3; @@ -138,7 +150,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private int longtapHintRow; private int defaultTopicIconRow; private int topicEmojiHeaderRow; - + private EmojiPackExpand recentExpandButton; public onLongPressedListener bigReactionListener; @@ -151,6 +163,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private Drawable forumIconDrawable; private ImageViewEmoji forumIconImage; private boolean animationsEnabled; + private boolean showStickers; + private boolean forUser; + private ArrayList stickerSets = new ArrayList<>(); public void putAnimatedEmojiToCache(AnimatedEmojiDrawable animatedEmojiDrawable) { emojiGridView.animatedEmojiDrawables.put(animatedEmojiDrawable.getDocumentId(), animatedEmojiDrawable); @@ -167,6 +182,11 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } + public void setForUser(boolean forUser) { + this.forUser = forUser; + updateRows(false, false); + } + public static class SelectAnimatedEmojiDialogWindow extends PopupWindow { private static final Field superListenerField; private ViewTreeObserver.OnScrollChangedListener mSuperScrollListener; @@ -303,11 +323,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } - private int currentAccount = UserConfig.selectedAccount; + private final static int currentAccount = UserConfig.selectedAccount; private int type; private FrameLayout contentView; private View backgroundView; + private EmojiTabsStrip[] cachedEmojiTabs = new EmojiTabsStrip[2]; private EmojiTabsStrip emojiTabs; private View emojiTabsShadow; private SearchBox searchBox; @@ -337,6 +358,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private ArrayList installedEmojiSets = new ArrayList<>(); private boolean recentExpanded = false; private ArrayList recent = new ArrayList<>(); + private ArrayList recentStickers = new ArrayList<>(); private ArrayList topReactions = new ArrayList<>(); private ArrayList recentReactions = new ArrayList<>(); private ArrayList defaultStatuses = new ArrayList<>(); @@ -363,6 +385,10 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private int topMarginDp; DefaultItemAnimator emojiItemAnimator; + protected void invalidateParent() { + + } + public SelectAnimatedEmojiDialog(BaseFragment baseFragment, Context context, boolean includeEmpty, Theme.ResourcesProvider resourcesProvider) { this(baseFragment, context, includeEmpty, null, TYPE_EMOJI_STATUS, resourcesProvider); } @@ -433,7 +459,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati return; } canvas.save(); - paint.setShadowLayer(dp(2), 0, dp(-0.66f), 0x1e000000); + Theme.applyDefaultShadow(paint); paint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); paint.setAlpha((int) (255 * getAlpha())); float px = (bubbleX == null ? getWidth() / 2f : bubbleX) + AndroidUtilities.dp(20); @@ -475,55 +501,84 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati addView(bubble2View, LayoutHelper.createFrame(17, 9, Gravity.TOP | Gravity.LEFT, bubbleX / AndroidUtilities.density + (bubbleRight ? -25 : 10), 6 + 8 - 9 + topMarginDp, 0, 0)); } - boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON; - emojiTabs = new EmojiTabsStrip(context, null, false, true, type, showSettings ? () -> { - onSettings(); - baseFragment.presentFragment(new StickersActivity(MediaDataController.TYPE_EMOJIPACKS, frozenEmojiPacks)); - if (dismiss != null) { - dismiss.run(); - } - } : null) { - - @Override - protected ColorFilter getEmojiColorFilter() { - return premiumStarColorFilter; - } - - @Override - protected boolean onTabClick(int index) { - if (smoothScrolling) { - return false; + boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR; + for (int i = 0; i < 2; i++) { + EmojiTabsStrip emojiTabs = new EmojiTabsStrip(context, null, false, true, type, showSettings ? () -> { + search(null, false, false); + onSettings(); + baseFragment.presentFragment(new StickersActivity(MediaDataController.TYPE_EMOJIPACKS, frozenEmojiPacks)); + if (dismiss != null) { + dismiss.run(); } - int position = searchRow == -1 ? 1 : 0; - if (index > 0 && sectionToPosition.indexOfKey(index - 1) >= 0) { - position = sectionToPosition.get(index - 1); + } : null) { + + @Override + protected ColorFilter getEmojiColorFilter() { + return premiumStarColorFilter; + } + + @Override + protected boolean onTabClick(int index) { + if (smoothScrolling) { + return false; + } + if (type == TYPE_AVATAR_CONSTRUCTOR) { + if (index == 0) { + showStickers = !showStickers; + SelectAnimatedEmojiDialog.this.emojiTabs.setVisibility(View.GONE); + SelectAnimatedEmojiDialog.this.emojiTabs = cachedEmojiTabs[showStickers ? 1 : 0]; + SelectAnimatedEmojiDialog.this.emojiTabs.setVisibility(View.VISIBLE); + SelectAnimatedEmojiDialog.this.emojiTabs.toggleEmojiStickersTab.setDrawable(ContextCompat.getDrawable(getContext(), showStickers ? R.drawable.msg_emoji_stickers : R.drawable.msg_emoji_smiles)); + updateRows(true, false, false); + layoutManager.scrollToPositionWithOffset(0, 0); + return true; + } + index--; + } + int position = 0; + if (index > 0 && sectionToPosition.indexOfKey(index - 1) >= 0) { + position = sectionToPosition.get(index - 1); + } + scrollToPosition(position, AndroidUtilities.dp(-2)); + SelectAnimatedEmojiDialog.this.emojiTabs.select(index); + emojiGridView.scrolledByUserOnce = true; + search(null); + if (searchBox != null && searchBox.categoriesListView != null) { + searchBox.categoriesListView.selectCategory(null); + } + return true; + } + + @Override + protected void onTabCreate(EmojiTabsStrip.EmojiTabButton button) { + if (showAnimator == null || showAnimator.isRunning()) { + button.setScaleX(0); + button.setScaleY(0); + } + } + }; + emojiTabs.recentTab.setOnLongClickListener(e -> { + onRecentLongClick(); + try { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception ignore) { } - scrollToPosition(position, AndroidUtilities.dp(-2)); - emojiTabs.select(index); - emojiGridView.scrolledByUserOnce = true; return true; + }); + emojiTabs.updateButtonDrawables = false; + if (type == TYPE_AVATAR_CONSTRUCTOR) { + emojiTabs.setAnimatedEmojiCacheType(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); + } else { + emojiTabs.setAnimatedEmojiCacheType(type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); } + emojiTabs.animateAppear = bubbleX == null; + emojiTabs.setPaddingLeft(5); + contentView.addView(emojiTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); + cachedEmojiTabs[i] = emojiTabs; + } - @Override - protected void onTabCreate(EmojiTabsStrip.EmojiTabButton button) { - if (showAnimator == null || showAnimator.isRunning()) { - button.setScaleX(0); - button.setScaleY(0); - } - } - }; - emojiTabs.recentTab.setOnLongClickListener(e -> { - onRecentLongClick(); - try { - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - } catch (Exception ignore) {} - return true; - }); - emojiTabs.updateButtonDrawables = false; - emojiTabs.setAnimatedEmojiCacheType(type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); - emojiTabs.animateAppear = bubbleX == null; - emojiTabs.setPaddingLeft(5); - contentView.addView(emojiTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); + emojiTabs = cachedEmojiTabs[0]; + cachedEmojiTabs[1].setVisibility(View.GONE); emojiTabsShadow = new View(context) { @Override @@ -546,7 +601,8 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati updateTabsPosition(layoutManager.findFirstCompletelyVisibleItemPosition()); } updateSearchBox(); - AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0, 1f, true); + AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_REACTIONS, 1f, true); + invalidateParent(); } @Override @@ -575,7 +631,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati emojiGridView.setItemAnimator(emojiItemAnimator); emojiGridView.setPadding(dp(5), dp(2), dp(5), dp(2 + 36)); emojiGridView.setAdapter(adapter = new Adapter()); - emojiGridView.setLayoutManager(layoutManager = new GridLayoutManager(context, 8) { + emojiGridView.setLayoutManager(layoutManager = new GridLayoutManager(context, SPAN_COUNT) { @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { try { @@ -595,7 +651,11 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { - return (positionToSection.indexOfKey(position) >= 0 || positionToButton.indexOfKey(position) >= 0 || position == recentReactionsSectionRow || position == popularSectionRow || position == longtapHintRow || position == searchRow || position == topicEmojiHeaderRow) ? layoutManager.getSpanCount() : 1; + if (positionToSection.indexOfKey(position) >= 0 || positionToButton.indexOfKey(position) >= 0 || position == recentReactionsSectionRow || position == popularSectionRow || position == longtapHintRow || position == searchRow || position == topicEmojiHeaderRow) { + return layoutManager.getSpanCount(); + } else { + return showStickers ? 8 : 5; + } } }); @@ -619,7 +679,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati emojiSearchGridView.getItemAnimator().setMoveInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); } TextView emptyViewText = new TextView(context); - if (type == TYPE_EMOJI_STATUS) { + if (type == TYPE_AVATAR_CONSTRUCTOR) { + emptyViewText.setText(LocaleController.getString("NoEmojiOrStickersFound", R.string.NoEmojiOrStickersFound)); + } else if (type == TYPE_EMOJI_STATUS) { emptyViewText.setText(LocaleController.getString("NoEmojiFound", R.string.NoEmojiFound)); } else if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { emptyViewText.setText(LocaleController.getString("NoReactionsFound", R.string.NoReactionsFound)); @@ -636,9 +698,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati emojiSearchEmptyView.setVisibility(View.GONE); emojiSearchEmptyView.setAlpha(0); gridViewContainer.addView(emojiSearchEmptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); - emojiSearchGridView.setPadding(dp(5), dp(52 + 2), dp(5), dp(2)); + emojiSearchGridView.setPadding(dp(5), dp(52 + 2), dp(5), dp(36 + 2)); emojiSearchGridView.setAdapter(searchAdapter = new SearchAdapter()); - emojiSearchGridView.setLayoutManager(searchLayoutManager = new GridLayoutManager(context, 8) { + emojiSearchGridView.setLayoutManager(searchLayoutManager = new GridLayoutManager(context, SPAN_COUNT) { @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { try { @@ -655,13 +717,20 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } }); -// searchLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { -// @Override -// public int getSpanSize(int position) { -// return position == 0 ? layoutManager.getSpanCount() : 1; -// } -// }); + searchLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + int viewType = searchAdapter.getItemViewType(position); + if (viewType == SearchAdapter.VIEW_TYPE_HEADER) { + return layoutManager.getSpanCount(); + } + if (viewType == SearchAdapter.VIEW_TYPE_STICKER) { + return 8; + } + return 5; + } + }); emojiSearchGridView.setVisibility(View.GONE); gridViewContainer.addView(emojiSearchGridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 0, 0)); contentView.addView(gridViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, 36 + (1 / AndroidUtilities.density), 0, 0)); @@ -706,6 +775,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati setBigReactionAnimatedEmoji(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_LARGE, currentAccount, selectedReactionView.span.documentId)); } emojiGridView.invalidate(); + invalidateParent(); return true; } if (view instanceof ImageViewEmoji && ((ImageViewEmoji) view).span != null && type == TYPE_EMOJI_STATUS) { @@ -781,6 +851,8 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if (viewEmoji.isDefaultReaction) { incrementHintUse(); onReactionClick(viewEmoji, viewEmoji.reaction); + } else if (viewEmoji.isStaticIcon && viewEmoji.document != null) { + onStickerClick(viewEmoji, viewEmoji.document); } else { onEmojiClick(viewEmoji, viewEmoji.span); } @@ -812,9 +884,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati emojiSearchGridView.setOnItemClickListener(onItemClick); searchBox = new SearchBox(context); - searchBox.setTranslationY(-AndroidUtilities.dp(4 + 52)); + searchBox.setTranslationY(-AndroidUtilities.dp( 52)); searchBox.setVisibility(View.INVISIBLE); - gridViewContainer.addView(searchBox, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 52, Gravity.TOP, 0, 0, 0, 0)); + gridViewContainer.addView(searchBox, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 52, Gravity.TOP, 0, -4, 0, 0)); topGradientView = new View(context) { @Override @@ -850,6 +922,10 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati updateRows(true, false); } + private void onStickerClick(ImageViewEmoji viewEmoji, TLRPC.Document document) { + onEmojiSelected(viewEmoji, null, document, null); + } + protected void onSettings() { } @@ -933,12 +1009,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private void updateTabsPosition(int position) { if (position != RecyclerView.NO_POSITION) { - final int recentmaxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; + final int recentmaxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; int recentSize = recent.size() > recentmaxlen && !recentExpanded ? recentmaxlen : recent.size() + (includeEmpty ? 1 : 0); if (position <= recentSize || position <= recentReactions.size()) { emojiTabs.select(0); // recent } else { - final int maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; for (int i = 0; i < positionToSection.size(); ++i) { int startPosition = positionToSection.keyAt(i); int index = i - (defaultStatuses.isEmpty() ? 0 : 1); @@ -963,20 +1039,20 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if (searched) { searchBox.clearAnimation(); searchBox.setVisibility(View.VISIBLE); - searchBox.animate().translationY(-AndroidUtilities.dp(4)).start(); + searchBox.animate().translationY(0).start(); } else { if (emojiGridView.getChildCount() > 0) { View first = emojiGridView.getChildAt(0); if (emojiGridView.getChildAdapterPosition(first) == searchRow && "searchbox".equals(first.getTag())) { searchBox.setVisibility(View.VISIBLE); - searchBox.setTranslationY(first.getY() - AndroidUtilities.dp(4)); + searchBox.setTranslationY(first.getY()); } else { // searchBox.setVisibility(View.INVISIBLE); - searchBox.setTranslationY(-AndroidUtilities.dp(4 + 52)); + searchBox.setTranslationY(-AndroidUtilities.dp(52)); } } else { // searchBox.setVisibility(View.INVISIBLE); - searchBox.setTranslationY(-AndroidUtilities.dp(4 + 52)); + searchBox.setTranslationY(-AndroidUtilities.dp(52)); } } } @@ -1134,7 +1210,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private void scrollToPosition(int p, int offset) { View view = layoutManager.findViewByPosition(p); int firstPosition = layoutManager.findFirstVisibleItemPosition(); - if ((view == null && Math.abs(p - firstPosition) > layoutManager.getSpanCount() * 9f) || !SharedConfig.animationsEnabled()) { + if ((view == null && Math.abs(p - firstPosition) > SPAN_COUNT_FOR_EMOJI * 9f) || !SharedConfig.animationsEnabled()) { scrollHelper.setScrollDirection(layoutManager.findFirstVisibleItemPosition() < p ? RecyclerAnimationScrollHelper.SCROLL_DIRECTION_DOWN : RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP); scrollHelper.scrollToPosition(p, offset, false, true); } else { @@ -1158,12 +1234,18 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public boolean searching = false; public boolean searched = false; + public boolean searchedLiftUp = false; private String lastQuery; private ArrayList searchResult; + private ArrayList stickersSearchResult; private ValueAnimator gridSwitchAnimator; - private boolean gridSearch = false; public void switchGrids(boolean search) { + switchGrids(search, true); + } + + private boolean gridSearch = false; + public void switchGrids(boolean search, boolean liftUp) { if (gridSearch == search) { return; } @@ -1184,7 +1266,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati t = 1f - t; } emojiGridView.setAlpha(1f - t); + emojiGridView.setTranslationY(AndroidUtilities.dp(8) * t); emojiSearchGridView.setAlpha(t); + emojiSearchGridView.setTranslationY(AndroidUtilities.dp(8) * (1f - t)); emojiSearchEmptyView.setAlpha(emojiSearchGridView.getAlpha() * t); }); gridSwitchAnimator.addListener(new AnimatorListenerAdapter() { @@ -1199,22 +1283,27 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } }); - gridSwitchAnimator.setDuration(280); + gridSwitchAnimator.setDuration(320); gridSwitchAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); gridSwitchAnimator.start(); ((View) emojiGridView.getParent()).animate() - .translationY(gridSearch ? -AndroidUtilities.dp(36) : 0) + .translationY(gridSearch && liftUp ? -AndroidUtilities.dp(36) : 0) .setInterpolator(CubicBezierInterpolator.DEFAULT) .setDuration(160) .start(); + if (gridSearch && liftUp) { + emojiSearchGridView.setPadding(dp(5), dp(52 + 2), dp(5), dp(2)); + } else { + emojiSearchGridView.setPadding(dp(5), dp(52 + 2), dp(5), dp(36 + 2)); + } checkScroll(); } private ArrayList emptyViewEmojis = new ArrayList(4); { - emptyViewEmojis.add("\uD83D\uDE16"); - emptyViewEmojis.add("\uD83D\uDE2B"); - emptyViewEmojis.add("\uD83E\uDEE0"); - emptyViewEmojis.add("\uD83D\uDE28"); + emptyViewEmojis.add("😖"); + emptyViewEmojis.add("😫"); + emptyViewEmojis.add("🫠"); + emptyViewEmojis.add("😨"); emptyViewEmojis.add("❓"); }; public void updateSearchEmptyViewImage() { @@ -1226,6 +1315,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati ArrayList featuredSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); List shuffledFeaturedSets = new ArrayList<>(featuredSets); Collections.shuffle(shuffledFeaturedSets); + int skip = (int) Math.round(Math.random() * 10); for (int i = 0; i < shuffledFeaturedSets.size(); ++i) { if (shuffledFeaturedSets.get(i) instanceof TLRPC.TL_stickerSetFullCovered && ((TLRPC.TL_stickerSetFullCovered) shuffledFeaturedSets.get(i)).documents != null) { List documents = new ArrayList<>(((TLRPC.TL_stickerSetFullCovered) shuffledFeaturedSets.get(i)).documents); @@ -1234,15 +1324,16 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati TLRPC.Document document = documents.get(j); if (document != null && emptyViewEmojis.contains(MessageObject.findAnimatedEmojiEmoticon(document, null))) { emoji = document; - break; + if (skip-- <= 0) + break; } } } - if (emoji != null) { + if (emoji != null && skip <= 0) { break; } } - if (emoji == null) { + if (emoji == null || skip > 0) { ArrayList sets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); List shuffledSets = new ArrayList<>(sets); Collections.shuffle(shuffledSets); @@ -1254,11 +1345,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati TLRPC.Document document = documents.get(j); if (document != null && emptyViewEmojis.contains(MessageObject.findAnimatedEmojiEmoticon(document, null))) { emoji = document; - break; + if (skip-- <= 0) + break; } } } - if (emoji != null) { + if (emoji != null && skip <= 0) { break; } } @@ -1328,7 +1420,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private static String[] lastSearchKeyboardLanguage; private Runnable clearSearchRunnable; private Runnable searchRunnable; + public void search(String query) { + search(query, true, true); + } + + public void search(String query, boolean liftUp, boolean delay) { if (clearSearchRunnable != null) { AndroidUtilities.cancelRunOnUIThread(clearSearchRunnable); clearSearchRunnable = null; @@ -1337,12 +1434,13 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati AndroidUtilities.cancelRunOnUIThread(searchRunnable); searchRunnable = null; } - if (query == null) { + if (TextUtils.isEmpty(query)) { searching = false; searched = false; - switchGrids(false); - if (searchBox != null && searchBox.clearDrawable != null) { - searchBox.clearDrawable.stopAnimation(); + switchGrids(false, liftUp); + if (searchBox != null) { + searchBox.showProgress(false); + searchBox.toggleClear(false); } searchAdapter.updateRows(true); lastQuery = null; @@ -1350,8 +1448,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati boolean firstSearch = !searching; searching = true; searched = false; - if (searchBox != null && searchBox.clearDrawable != null) { - searchBox.clearDrawable.startAnimation(); + searchedLiftUp = liftUp; + if (searchBox != null) { + searchBox.showProgress(true); } if (firstSearch) { if (searchResult != null) { @@ -1373,45 +1472,146 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } lastSearchKeyboardLanguage = newLanguage; AndroidUtilities.runOnUIThread(searchRunnable = () -> { - MediaDataController.getInstance(currentAccount).getAnimatedEmojiByKeywords(query, _documentIds -> { - final ArrayList documentIds = _documentIds == null ? new ArrayList<>() : _documentIds; - final HashMap availableReactions = MediaDataController.getInstance(currentAccount).getReactionsMap(); - if (Emoji.fullyConsistsOfEmojis(query)) { - ArrayList stickerSets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); - String emoticon; + final LinkedHashSet documentIds = new LinkedHashSet<>(); + final HashMap availableReactions = MediaDataController.getInstance(currentAccount).getReactionsMap(); + final ArrayList reactions = new ArrayList<>(); + final boolean queryFullyConsistsOfEmojis = Emoji.fullyConsistsOfEmojis(query); + final ArrayList> emojiArrays = new ArrayList<>(); + final HashMap, String> emojiStickers = new HashMap<>(); + Utilities.doCallbacks( + next -> { + if (queryFullyConsistsOfEmojis) { + StickerCategoriesListView.search.fetch(UserConfig.selectedAccount, query, list -> { + if (list != null) { + documentIds.addAll(list.document_id); + } + next.run(); + }); + } else { + next.run(); + } + }, + next -> { + MediaDataController.getInstance(currentAccount).getAnimatedEmojiByKeywords(query, _documentIds -> { + if (_documentIds != null) { + documentIds.addAll(_documentIds); + } + next.run(); + }); + }, + next -> { + if (queryFullyConsistsOfEmojis) { + ArrayList stickerSets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); + String emoticon; - for (int i = 0; i < stickerSets.size(); ++i) { - if (stickerSets.get(i).documents != null) { - ArrayList documents = stickerSets.get(i).documents; - if (documents != null) { - for (int j = 0; j < documents.size(); ++j) { - emoticon = MessageObject.findAnimatedEmojiEmoticon(documents.get(j), null); - long id = documents.get(j).id; - if (emoticon != null && !documentIds.contains(id) && query.contains(emoticon.toLowerCase())) { - documentIds.add(id); + for (int i = 0; i < stickerSets.size(); ++i) { + if (stickerSets.get(i).documents != null) { + ArrayList documents = stickerSets.get(i).documents; + if (documents != null) { + for (int j = 0; j < documents.size(); ++j) { + emoticon = MessageObject.findAnimatedEmojiEmoticon(documents.get(j), null); + long id = documents.get(j).id; + if (emoticon != null && !documentIds.contains(id) && query.contains(emoticon.toLowerCase())) { + documentIds.add(id); + } + } } } } - } - } - ArrayList featuredStickerSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); - for (int i = 0; i < featuredStickerSets.size(); ++i) { - if (featuredStickerSets.get(i) instanceof TLRPC.TL_stickerSetFullCovered && - ((TLRPC.TL_stickerSetFullCovered) featuredStickerSets.get(i)).keywords != null) { - ArrayList documents = ((TLRPC.TL_stickerSetFullCovered) featuredStickerSets.get(i)).documents; - if (documents != null) { - for (int j = 0; j < documents.size(); ++j) { - emoticon = MessageObject.findAnimatedEmojiEmoticon(documents.get(j), null); - long id = documents.get(j).id; - if (emoticon != null && !documentIds.contains(id) && query.contains(emoticon)) { - documentIds.add(id); + ArrayList featuredStickerSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + for (int i = 0; i < featuredStickerSets.size(); ++i) { + if (featuredStickerSets.get(i) instanceof TLRPC.TL_stickerSetFullCovered && + ((TLRPC.TL_stickerSetFullCovered) featuredStickerSets.get(i)).keywords != null) { + ArrayList documents = ((TLRPC.TL_stickerSetFullCovered) featuredStickerSets.get(i)).documents; + if (documents != null) { + for (int j = 0; j < documents.size(); ++j) { + emoticon = MessageObject.findAnimatedEmojiEmoticon(documents.get(j), null); + long id = documents.get(j).id; + if (emoticon != null && !documentIds.contains(id) && query.contains(emoticon)) { + documentIds.add(id); + } + } } } } + + next.run(); + } else { + MediaDataController.getInstance(currentAccount).getEmojiSuggestions( + lastSearchKeyboardLanguage, query, false, + (result, alias) -> { + try { + for (int i = 0; i < result.size(); ++i) { + if (result.get(i).emoji.startsWith("animated_")) { + documentIds.add(Long.parseLong(result.get(i).emoji.substring(9))); + } else { + if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { + TLRPC.TL_availableReaction reaction = availableReactions.get(result.get(i).emoji); + if (reaction != null) { + reactions.add(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction)); + } + } + } + } + } catch (Exception ignore) { + } + next.run(); + }, + null, true, type == TYPE_TOPIC_ICON, false, 30 + ); } - } - AndroidUtilities.runOnUIThread(() -> { + }, + next -> { + if (type != TYPE_AVATAR_CONSTRUCTOR) { + next.run(); + return; + } + final ArrayList emojiStickersArray = new ArrayList<>(0); + final LongSparseArray emojiStickersMap = new LongSparseArray<>(0); + HashMap> allStickers = MediaDataController.getInstance(currentAccount).getAllStickers(); + if (query.length() <= 14) { + CharSequence emoji = query; + int length = emoji.length(); + for (int a = 0; a < length; a++) { + if (a < length - 1 && (emoji.charAt(a) == 0xD83C && emoji.charAt(a + 1) >= 0xDFFB && emoji.charAt(a + 1) <= 0xDFFF || emoji.charAt(a) == 0x200D && (emoji.charAt(a + 1) == 0x2640 || emoji.charAt(a + 1) == 0x2642))) { + emoji = TextUtils.concat(emoji.subSequence(0, a), emoji.subSequence(a + 2, emoji.length())); + length -= 2; + a--; + } else if (emoji.charAt(a) == 0xfe0f) { + emoji = TextUtils.concat(emoji.subSequence(0, a), emoji.subSequence(a + 1, emoji.length())); + length--; + a--; + } + } + ArrayList newStickers = allStickers != null ? allStickers.get(emoji.toString()) : null; + if (newStickers != null && !newStickers.isEmpty()) { + emojiStickersArray.addAll(newStickers); + for (int a = 0, size = newStickers.size(); a < size; a++) { + TLRPC.Document document = newStickers.get(a); + emojiStickersMap.put(document.id, document); + } + emojiArrays.add(emojiStickersArray); + } + } + if (allStickers != null && !allStickers.isEmpty() && query.length() > 1) { + MediaDataController.getInstance(currentAccount).getEmojiSuggestions(lastSearchKeyboardLanguage, query, false, (param, alias) -> { + boolean added = false; + for (int a = 0, size = param.size(); a < size; a++) { + String emoji = param.get(a).emoji; + ArrayList newStickers = allStickers != null ? allStickers.get(emoji) : null; + if (newStickers != null && !newStickers.isEmpty()) { + if (!emojiStickers.containsKey(newStickers)) { + emojiStickers.put(newStickers, emoji); + emojiArrays.add(newStickers); + } + } + } + next.run(); + }, false); + } + }, + next -> AndroidUtilities.runOnUIThread(() -> { if (clearSearchRunnable != null) { AndroidUtilities.cancelRunOnUIThread(clearSearchRunnable); clearSearchRunnable = null; @@ -1421,101 +1621,61 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati return; } searched = true; - switchGrids(true); - if (searchBox != null && searchBox.clearDrawable != null) { - searchBox.clearDrawable.stopAnimation(); + switchGrids(true, liftUp); + if (searchBox != null) { + searchBox.showProgress(false); } if (searchResult == null) { searchResult = new ArrayList<>(); } else { searchResult.clear(); } + if (stickersSearchResult == null) { + stickersSearchResult = new ArrayList<>(); + } else { + stickersSearchResult.clear(); + } emojiSearchGridView.scrollToPosition(0); - searched = true; if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { - TLRPC.TL_availableReaction reaction = availableReactions.get(query); - if (reaction != null) { - searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction)); + if (!reactions.isEmpty()) { + searchResult.addAll(reactions); + } else { + TLRPC.TL_availableReaction reaction = availableReactions.get(query); + if (reaction != null) { + searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction)); + } } } - for (int i = 0; i < documentIds.size(); ++i) { - searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentIds.get(i))); + for (long documentId : documentIds) { + searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentId)); + } + for (ArrayList array : emojiArrays) { + stickersSearchResult.addAll(array); } searchAdapter.updateRows(!firstSearch); - }); - } else { - MediaDataController.getInstance(currentAccount).getEmojiSuggestions( - lastSearchKeyboardLanguage, - query, - false, - (result, alias) -> { - if (clearSearchRunnable != null) { - AndroidUtilities.cancelRunOnUIThread(clearSearchRunnable); - clearSearchRunnable = null; - } - if (query != lastQuery) { - return; - } - searched = true; - switchGrids(true); - if (searchBox != null && searchBox.clearDrawable != null) { - searchBox.clearDrawable.stopAnimation(); - } - if (searchResult == null) { - searchResult = new ArrayList<>(); - } else { - searchResult.clear(); - } - for (int i = 0; i < result.size(); ++i) { - try { - if (result.get(i).emoji.startsWith("animated_")) { - documentIds.add(Long.parseLong(result.get(i).emoji.substring(9))); - } else { - if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { - TLRPC.TL_availableReaction reaction = availableReactions.get(result.get(i).emoji); - if (reaction != null) { - searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction)); - } - } - } - } catch (Exception ignore) {} - } - emojiSearchGridView.scrollToPosition(0); - searched = true; - for (int i = 0; i < documentIds.size(); ++i) { - searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentIds.get(i))); - } - searchAdapter.updateRows(!firstSearch); - }, - null, - true, - type == TYPE_TOPIC_ICON, - 30 - ); - } - }); - }, 425); - } - updateSearchBox(); - - if (searchBox != null && searchBox.clear != null) { - boolean showed = searchBox.clear.getAlpha() != 0; - if (searching != showed) { - searchBox.clear.animate() - .alpha(searching ? 1.0f : 0.0f) - .setDuration(150) - .scaleX(searching ? 1.0f : 0.1f) - .scaleY(searching ? 1.0f : 0.1f) - .start(); + }) + ); + }, delay ? 425 : 0); + if (searchBox != null) { + searchBox.showProgress(true); + searchBox.toggleClear(liftUp); } } + updateSearchBox(); } private class SearchAdapter extends RecyclerListView.SelectionAdapter { - public int VIEW_TYPE_SEARCH = 7; - public int VIEW_TYPE_EMOJI = 3; - public int VIEW_TYPE_REACTION = 4; + public final static int VIEW_TYPE_SEARCH = 7; + public final static int VIEW_TYPE_EMOJI = 3; + public final static int VIEW_TYPE_REACTION = 4; + public final static int VIEW_TYPE_STICKER = 5; + public final static int VIEW_TYPE_HEADER = 6; + + int stickersStartRow; + int emojiStartRow; + int emojiHeaderRow = -1; + int stickersHeaderRow = -1; @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { @@ -1526,7 +1686,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; - if (viewType == VIEW_TYPE_SEARCH) { + if (viewType == VIEW_TYPE_HEADER) { + view = new HeaderView(getContext()); + } else if (viewType == VIEW_TYPE_SEARCH) { view = new View(getContext()) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -1546,16 +1708,50 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati @Override public int getItemViewType(int position) { - if (searchResult == null || position < 0 || position >= searchResult.size() || searchResult.get(position).emojicon == null) { - return VIEW_TYPE_EMOJI; - } else { - return VIEW_TYPE_REACTION; + if (position == emojiHeaderRow || position == stickersHeaderRow) { + return VIEW_TYPE_HEADER; } + if (position > stickersStartRow && position - stickersStartRow - 1 < stickersSearchResult.size()) { + return VIEW_TYPE_STICKER; + } + if (searchResult == null) { + return VIEW_TYPE_EMOJI; + } + if (position > emojiStartRow && position - emojiStartRow - 1 < searchResult.size()) { + if (searchResult.get(position - emojiStartRow - 1 ).documentId != 0) { + return VIEW_TYPE_EMOJI; + } + } + return VIEW_TYPE_REACTION; } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == VIEW_TYPE_REACTION) { + if (holder.getItemViewType() == VIEW_TYPE_HEADER) { + HeaderView header = (HeaderView) holder.itemView; + if (position == emojiHeaderRow) { + header.setText(LocaleController.getString("Emoji", R.string.Emoji), false); + } else { + header.setText(LocaleController.getString("AccDescrStickers", R.string.AccDescrStickers), false); + } + header.closeIcon.setVisibility(View.GONE); + } else if (holder.getItemViewType() == VIEW_TYPE_STICKER) { + int p = position - stickersStartRow - 1; + TLRPC.Document document = stickersSearchResult.get(p); + ImageViewEmoji imageView = (ImageViewEmoji) holder.itemView; + if (imageView.imageReceiver == null) { + imageView.imageReceiver = new ImageReceiver(imageView); + imageView.imageReceiver.setLayerNum(7); + imageView.imageReceiver.onAttachedToWindow(); + imageView.imageReceiver.setAspectFit(true); + } + imageView.imageReceiver.setParentView(emojiSearchGridView); + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + imageView.imageReceiver.setImage(ImageLocation.getForDocument(document), "100_100_firstframe", null, null, svgThumb, 0, "tgs", document, 0); + imageView.isStaticIcon = true; + imageView.document = document; + imageView.span = null; + } else if (holder.getItemViewType() == VIEW_TYPE_REACTION) { ImageViewEmoji imageView = (ImageViewEmoji) holder.itemView; imageView.position = position; if (searchResult == null || position < 0 || position >= searchResult.size()) { @@ -1581,7 +1777,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if (SharedConfig.getLiteMode().enabled()) { imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), "60_60_firstframe", null, null, svgThumb, 0, "tgs", currentReaction, 0); } else { - imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, null, null, svgThumb, 0, "tgs", currentReaction, 0); + imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, ImageLocation.getForDocument(reaction.select_animation), "30_30_firstframe", null, null, svgThumb, 0, "tgs", currentReaction, 0); } MediaDataController.getInstance(currentAccount).preloadImage(imageView.preloadEffectImageReceiver, ImageLocation.getForDocument(reaction.around_animation), ReactionsEffectOverlay.getFilterForAroundAnimation()); } else { @@ -1652,7 +1848,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } public void updateRows(boolean diff) { - if (!isAttached) { + if (!isAttached || type == TYPE_AVATAR_CONSTRUCTOR) { diff = false; } ArrayList prevRowHashCodes = new ArrayList<>(rowHashCodes); @@ -1660,16 +1856,32 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati count = 0; rowHashCodes.clear(); -// count++; -// rowHashCodes.add(132); - if (searchResult != null) { + if (type == TYPE_AVATAR_CONSTRUCTOR && !searchResult.isEmpty()) { + emojiHeaderRow = count++; + rowHashCodes.add(1); + } + + emojiStartRow = count; for (int i = 0; i < searchResult.size(); ++i) { count++; rowHashCodes.add(Objects.hash(-4342, searchResult.get(i))); } } + if (stickersSearchResult != null) { + if (type == TYPE_AVATAR_CONSTRUCTOR && !stickersSearchResult.isEmpty()) { + stickersHeaderRow = count++; + rowHashCodes.add(2); + } + + stickersStartRow = count; + for (int i = 0; i < stickersSearchResult.size(); ++i) { + count++; + rowHashCodes.add(Objects.hash(-7453, stickersSearchResult.get(i))); + } + } + if (diff) { DiffUtil.calculateDiff(new DiffUtil.Callback() { @Override @@ -1711,6 +1923,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public int VIEW_TYPE_HINT = 6; public int VIEW_TYPE_SEARCH = 7; public int VIEW_TYPE_TOPIC_ICON = 8; + public int VIEW_TYPE_STICKER = 9; @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { @@ -1793,7 +2006,11 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } if (position == defaultTopicIconRow) { return VIEW_TYPE_TOPIC_ICON; } else { - return VIEW_TYPE_EMOJI; + if (showStickers) { + return VIEW_TYPE_EMOJI; + } else { + return VIEW_TYPE_EMOJI; + } } } @@ -1824,10 +2041,14 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } if (position == recentReactionsSectionRow) { header.setText(LocaleController.getString("RecentlyUsed", R.string.RecentlyUsed), false); - header.closeIcon.setVisibility(View.VISIBLE); - header.closeIcon.setOnClickListener((view) -> { - clearRecent(); - }); + if (type == TYPE_AVATAR_CONSTRUCTOR) { + header.closeIcon.setVisibility(View.GONE); + } else { + header.closeIcon.setVisibility(View.VISIBLE); + header.closeIcon.setOnClickListener((view) -> { + clearRecent(); + }); + } return; } header.closeIcon.setVisibility(View.GONE); @@ -1839,7 +2060,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati int index = positionToSection.get(position); if (index >= 0) { EmojiView.EmojiPack pack = packs.get(index); - header.setText(pack.set.title, !pack.free && !UserConfig.getInstance(currentAccount).isPremium()); + header.setText(pack.set.title, !pack.free && !UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR); } else { header.setText(null, false); } @@ -1871,7 +2092,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if (SharedConfig.getLiteMode().enabled()) { imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), "60_60_firstframe", null, null, svgThumb, 0, "tgs", currentReaction, 0); } else { - imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, null, null, svgThumb, 0, "tgs", currentReaction, 0); + imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, ImageLocation.getForDocument(reaction.select_animation), "30_30_firstframe", null, null, svgThumb, 0, "tgs", currentReaction, 0); } MediaDataController.getInstance(currentAccount).preloadImage(imageView.preloadEffectImageReceiver, ImageLocation.getForDocument(reaction.around_animation), ReactionsEffectOverlay.getFilterForAroundAnimation()); } else { @@ -1913,13 +2134,13 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati EmojiView.EmojiPack pack = i >= 0 && i < packs.size() ? packs.get(i) : null; if (i == -1) { recentExpandButton = button; - final int maxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; button.textView.setText("+" + (recent.size() - maxlen + (includeEmpty ? 1 : 0) + 1)); } else if (pack != null) { if (recentExpandButton == button) { recentExpandButton = null; } - final int maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; button.textView.setText("+" + (pack.documents.size() - maxlen + 1)); } else { if (recentExpandButton == button) { @@ -1962,36 +2183,75 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } else if (viewType == VIEW_TYPE_SEARCH) { + } else if (viewType == VIEW_TYPE_STICKER) { + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; + for (int i = 0; i < positionToSection.size(); ++i) { + int startPosition = positionToSection.keyAt(i); + int index = i - (defaultStatuses.isEmpty() ? 0 : 1); + EmojiView.EmojiPack pack = index >= 0 ? packs.get(index) : null; + if (pack == null) { + continue; + } + int count = pack.expanded ? pack.documents.size() : Math.min(pack.documents.size(), maxlen); + if (position > startPosition && position <= startPosition + 1 + count) { + TLRPC.Document document = pack.documents.get(position - startPosition - 1); + if (document != null) { +// imageView.span = new AnimatedEmojiSpan(document, null); +// imageView.document = document; + } + } + } } else { ImageViewEmoji imageView = (ImageViewEmoji) holder.itemView; imageView.empty = false; imageView.position = position; imageView.setPadding(AndroidUtilities.dp(1), AndroidUtilities.dp(1), AndroidUtilities.dp(1), AndroidUtilities.dp(1)); - final int recentmaxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; - final int maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + final int recentmaxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; int recentSize; - if (type == TYPE_TOPIC_ICON) { + if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers) { + recentSize = recentStickers.size(); + } else if (type == TYPE_AVATAR_CONSTRUCTOR || type == TYPE_TOPIC_ICON) { recentSize = recent.size(); } else { recentSize = recent.size() > recentmaxlen && !recentExpanded ? recentmaxlen : recent.size() + (includeEmpty ? 1 : 0); } boolean selected = false; imageView.setDrawable(null); - if (includeEmpty && position == (searchRow != -1 ? 1 : 0) + (includeHint ? 1 : 0)) { + if (includeEmpty && position == (searchRow != -1 ? 1 : 0) + (longtapHintRow != -1 ? 1 : 0)) { selected = selectedDocumentIds.contains(null); imageView.empty = true; imageView.setPadding(AndroidUtilities.dp(5), AndroidUtilities.dp(5), AndroidUtilities.dp(5), AndroidUtilities.dp(5)); imageView.span = null; imageView.document = null; - } else if (position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) < recentSize) { - imageView.span = recent.get(position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) - (includeEmpty ? 1 : 0)); - imageView.document = imageView.span == null ? null : imageView.span.document; - selected = imageView.span != null && selectedDocumentIds.contains(imageView.span.getDocumentId()); - } else if (!defaultStatuses.isEmpty() && position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) - recentSize - 1 >= 0 && position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) - recentSize - 1 < defaultStatuses.size()) { - int index = position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) - recentSize - 1; + imageView.isStaticIcon = false; + if (imageView.imageReceiver != null) { + imageView.imageReceiver.clearImage(); + } + } else if (position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) < recentSize) { + int resentPosition = position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) - (includeEmpty ? 1 : 0); + if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers) { + TLRPC.Document document = recentStickers.get(resentPosition); + imageView.setSticker(document); + + } else { + imageView.span = recent.get(resentPosition); + imageView.document = imageView.span == null ? null : imageView.span.document; + selected = imageView.span != null && selectedDocumentIds.contains(imageView.span.getDocumentId()); + imageView.isStaticIcon = false; + if (imageView.imageReceiver != null) { + imageView.imageReceiver.clearImage(); + } + } + } else if (!defaultStatuses.isEmpty() && position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) - recentSize - 1 >= 0 && position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) - recentSize - 1 < defaultStatuses.size()) { + int index = position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) - recentSize - 1; imageView.span = defaultStatuses.get(index); imageView.document = imageView.span == null ? null : imageView.span.document; selected = imageView.span != null && selectedDocumentIds.contains(imageView.span.getDocumentId()); + imageView.isStaticIcon = false; + if (imageView.imageReceiver != null) { + imageView.imageReceiver.clearImage(); + } } else { for (int i = 0; i < positionToSection.size(); ++i) { int startPosition = positionToSection.keyAt(i); @@ -2004,7 +2264,15 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if (position > startPosition && position <= startPosition + 1 + count) { TLRPC.Document document = pack.documents.get(position - startPosition - 1); if (document != null) { - imageView.span = new AnimatedEmojiSpan(document, null); + if (showStickers) { + imageView.setSticker(document); + } else { + imageView.isStaticIcon = false; + if (imageView.imageReceiver != null) { + imageView.imageReceiver.clearImage(); + } + imageView.span = new AnimatedEmojiSpan(document, null); + } imageView.document = document; } } @@ -2434,11 +2702,25 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } + + public void setSticker(TLRPC.Document document) { + this.document = document; + if (imageReceiver == null) { + imageReceiver = new ImageReceiver(); + imageReceiver.setLayerNum(7); + imageReceiver.onAttachedToWindow(); + imageReceiver.setAspectFit(true); + } + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + imageReceiver.setImage(ImageLocation.getForDocument(document), "100_100_firstframe", null, null, svgThumb, 0, "tgs", document, 0); + isStaticIcon = true; + span = null; + } } public void onEmojiClick(View view, AnimatedEmojiSpan span) { incrementHintUse(); - if (span == null) { + if (span == null || type == TYPE_EMOJI_STATUS && selectedDocumentIds.contains(span.documentId)) { onEmojiSelected(view, null, null, null); } else { TLRPC.TL_emojiStatus status = new TLRPC.TL_emojiStatus(); @@ -2492,6 +2774,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati MediaDataController.getInstance(account).fetchEmojiStatuses(0, true); } else if (type == TYPE_TOPIC_ICON) { MediaDataController.getInstance(account).checkDefaultTopicIcons(); + } else if (type == TYPE_AVATAR_CONSTRUCTOR) { + MediaDataController.getInstance(currentAccount).loadRecents(MediaDataController.TYPE_IMAGE, false, true, false); + MediaDataController.getInstance(account).checkStickers(MediaDataController.TYPE_IMAGE); } MediaDataController.getInstance(account).getStickerSet(new TLRPC.TL_inputStickerSetEmojiDefaultStatuses(), false); } @@ -2505,20 +2790,26 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati MediaDataController.getInstance(account).checkReactions(); MediaDataController.getInstance(account).getStickerSet(new TLRPC.TL_inputStickerSetEmojiDefaultStatuses(), false); MediaDataController.getInstance(account).checkDefaultTopicIcons(); + StickerCategoriesListView.preload(account, StickerCategoriesListView.CategoriesType.STATUS); } private boolean defaultSetLoading = false; - private void updateRows(boolean updateEmojipacks, boolean diff) { + + private void updateRows(boolean updateEmojipacks, boolean animated) { + updateRows(updateEmojipacks, animated, true); + } + + private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff) { if (!animationsEnabled) { - diff = false; + animated = false; } - MediaDataController mediaDataController = MediaDataController.getInstance(UserConfig.selectedAccount); + MediaDataController mediaDataController = MediaDataController.getInstance(currentAccount); if (mediaDataController == null) { return; } if (updateEmojipacks || frozenEmojiPacks == null) { - frozenEmojiPacks = new ArrayList<>(mediaDataController.getStickerSets(MediaDataController.TYPE_EMOJIPACKS)); + frozenEmojiPacks = new ArrayList<>(mediaDataController.getStickerSets(showStickers ? MediaDataController.TYPE_IMAGE : MediaDataController.TYPE_EMOJIPACKS)); } ArrayList installedEmojipacks = frozenEmojiPacks; ArrayList featuredEmojiPacks = new ArrayList<>(mediaDataController.getFeaturedEmojiSets()); @@ -2542,15 +2833,36 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati positionToExpand.clear(); rowHashCodes.clear(); positionToButton.clear(); + stickerSets.clear(); + recentStickers.clear(); - if (!installedEmojipacks.isEmpty()) { + if (!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) { searchRow = totalCount++; rowHashCodes.add(9); } else { searchRow = -1; } - if (type == TYPE_TOPIC_ICON) { + if (type == TYPE_AVATAR_CONSTRUCTOR) { + if (showStickers) { + recentStickers.addAll(MediaDataController.getInstance(currentAccount).getRecentStickersNoCopy(MediaDataController.TYPE_IMAGE)); + for (int i = 0; i < recentStickers.size(); ++i) { + rowHashCodes.add(Objects.hash(62425, recentStickers.get(i).id)); + totalCount++; + } + } else { + TLRPC.TL_emojiList emojiList = forUser ? MediaDataController.getInstance(currentAccount).profileAvatarConstructorDefault : MediaDataController.getInstance(currentAccount).groupAvatarConstructorDefault; + if (emojiList != null && emojiList.document_id != null && !emojiList.document_id.isEmpty()) { + for (int i = 0; i < emojiList.document_id.size(); ++i) { + recent.add(new AnimatedEmojiSpan(emojiList.document_id.get(i), null)); + } + for (int i = 0; i < recent.size(); ++i) { + rowHashCodes.add(Objects.hash(43223, recent.get(i).getDocumentId())); + totalCount++; + } + } + } + } else if (type == TYPE_TOPIC_ICON) { topicEmojiHeaderRow = totalCount++; rowHashCodes.add(12); defaultTopicIconRow = totalCount++; @@ -2586,7 +2898,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } - if (includeHint && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_TOPIC_ICON) { + if (includeHint && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) { longtapHintRow = totalCount++; rowHashCodes.add(6); } @@ -2643,9 +2955,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati rowHashCodes.add(2); } ArrayList defaultEmojiStatuses = MediaDataController.getInstance(currentAccount).getDefaultEmojiStatuses(); - final int maxrecentlen = layoutManager.getSpanCount() * (RECENT_MAX_LINES + 8); + final int maxrecentlen = SPAN_COUNT_FOR_EMOJI * (RECENT_MAX_LINES + 8); if (defaultSet.documents != null && !defaultSet.documents.isEmpty()) { - for (int i = 0; i < Math.min(layoutManager.getSpanCount() - 1, defaultSet.documents.size()); ++i) { + for (int i = 0; i < Math.min(SPAN_COUNT_FOR_EMOJI - 1, defaultSet.documents.size()); ++i) { recent.add(new AnimatedEmojiSpan(defaultSet.documents.get(i), null)); if (recent.size() + (includeEmpty ? 1 : 0) >= maxrecentlen) { break; @@ -2654,12 +2966,8 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } if (recentEmojiStatuses != null && !recentEmojiStatuses.isEmpty()) { for (TLRPC.EmojiStatus emojiStatus : recentEmojiStatuses) { - long did; - if (emojiStatus instanceof TLRPC.TL_emojiStatus) { - did = ((TLRPC.TL_emojiStatus) emojiStatus).document_id; - } else if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000)) { - did = ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id; - } else { + Long did = UserObject.getEmojiStatusDocumentId(emojiStatus); + if (did == null) { continue; } boolean foundDuplicate = false; @@ -2679,12 +2987,8 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } if (defaultEmojiStatuses != null && !defaultEmojiStatuses.isEmpty()) { for (TLRPC.EmojiStatus emojiStatus : defaultEmojiStatuses) { - long did; - if (emojiStatus instanceof TLRPC.TL_emojiStatus) { - did = ((TLRPC.TL_emojiStatus) emojiStatus).document_id; - } else if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000)) { - did = ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id; - } else { + Long did = UserObject.getEmojiStatusDocumentId(emojiStatus); + if (did == null) { continue; } boolean foundDuplicate = false; @@ -2703,7 +3007,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } - final int maxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; int len = maxlen - (includeEmpty ? 1 : 0); if (recent.size() > len && !recentExpanded) { for (int i = 0; i < len - 1; ++i) { @@ -2727,7 +3031,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if (installedEmojipacks != null) { for (int i = 0, j = 0; i < installedEmojipacks.size(); ++i) { TLRPC.TL_messages_stickerSet set = installedEmojipacks.get(i); - if (set != null && set.set != null && set.set.emojis && !installedEmojiSets.contains(set.set.id)) { + if (set != null && set.set != null && (set.set.emojis || showStickers) && !installedEmojiSets.contains(set.set.id)) { positionToSection.put(totalCount, packs.size()); sectionToPosition.put(packs.size(), totalCount); totalCount++; @@ -2750,8 +3054,8 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } } - if (featuredEmojiPacks != null) { - final int maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + if (featuredEmojiPacks != null && !showStickers) { + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; for (int i = 0; i < featuredEmojiPacks.size(); ++i) { TLRPC.StickerSetCovered set1 = featuredEmojiPacks.get(i); TLRPC.StickerSet set = set1.set; @@ -2808,7 +3112,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } - if (!pack.installed) { + if (!pack.installed && type != TYPE_AVATAR_CONSTRUCTOR) { positionToButton.put(totalCount, packs.size()); totalCount++; rowHashCodes.add(Objects.hash(3321, set.id)); @@ -2823,35 +3127,39 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati emojiTabs.updateEmojiPacks(packs); }); - if (diff) { + if (animated) { emojiGridView.setItemAnimator(emojiItemAnimator); } else { emojiGridView.setItemAnimator(null); } - DiffUtil.calculateDiff(new DiffUtil.Callback() { - @Override - public int getOldListSize() { - return prevRowHashCodes.size(); - } + if (diff) { + DiffUtil.calculateDiff(new DiffUtil.Callback() { + @Override + public int getOldListSize() { + return prevRowHashCodes.size(); + } - @Override - public int getNewListSize() { - return rowHashCodes.size(); - } + @Override + public int getNewListSize() { + return rowHashCodes.size(); + } - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - return prevRowHashCodes.get(oldItemPosition).equals(rowHashCodes.get(newItemPosition)); - } + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return prevRowHashCodes.get(oldItemPosition).equals(rowHashCodes.get(newItemPosition)); + } - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - return true; - } - }, false).dispatchUpdatesTo(adapter); + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return true; + } + }, false).dispatchUpdatesTo(adapter); + } else { + adapter.notifyDataSetChanged(); + } if (!emojiGridView.scrolledByUserOnce) { - emojiGridView.scrollToPosition(1); + emojiGridView.scrollToPosition(0); } } @@ -2863,7 +3171,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati int fromCount, start, toCount; animateExpandFromButtonTranslate = 0; if (index >= 0 && index < packs.size()) { - maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; EmojiView.EmojiPack pack = packs.get(index); if (pack.expanded) { return; @@ -2880,12 +3188,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati pack.expanded = true; toCount = pack.documents.size(); } else if (index == -1) { - maxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; + maxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; if (recentExpanded) { return; } last = false; - start = (searchRow != -1 ? 1 : 0) + (includeHint ? 1 : 0) + (includeEmpty ? 1 : 0); + start = (searchRow != -1 ? 1 : 0) + (longtapHintRow != -1 ? 1 : 0) + (includeEmpty ? 1 : 0); fromCount = recentExpanded ? recent.size() : Math.min(maxlen - (includeEmpty ? 1 : 0) - 2, recent.size()); toCount = recent.size(); recentExpanded = true; @@ -2924,7 +3232,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (drawBackground && type != TYPE_TOPIC_ICON) { + if (drawBackground && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) { super.onMeasure( MeasureSpec.makeMeasureSpec((int) Math.min(AndroidUtilities.dp(340 - 16), AndroidUtilities.displaySize.x * .95f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f), MeasureSpec.AT_MOST) @@ -2935,6 +3243,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } private int getCacheType() { + if (type == TYPE_AVATAR_CONSTRUCTOR) { + return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC; + } return type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW; } @@ -3000,6 +3311,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private int lastChildCount = -1; + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + invalidate(); + } + @Override public void dispatchDraw(Canvas canvas) { if (getVisibility() != View.VISIBLE) { @@ -3119,7 +3436,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati int w = getMeasuredWidth() - firstView.getLeft() * 2; int h = firstView.getMeasuredHeight(); if (w > 0 && h > 0) { - drawable.draw(canvas, time, w, h, 1f); + drawable.draw(canvas, time, w, h, getAlpha()); } canvas.restore(); } @@ -3182,7 +3499,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati skewAlpha = .25f + .75f * skewAlpha; } } - boolean drawInUi = skewAlpha < 1 || isAnimating() || imageViewEmojis.size() <= 4 || SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW || showAnimator != null && showAnimator.isRunning() || SharedConfig.getLiteMode().enabled(); + boolean drawInUi = skewAlpha < 1 || isAnimating() || imageViewEmojis.size() <= 4 || SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW || (showAnimator != null && showAnimator.isRunning()) || SharedConfig.getLiteMode().enabled() || type == TYPE_AVATAR_CONSTRUCTOR; if (!drawInUi) { boolean animatedExpandIn = animateExpandStartTime > 0 && (SystemClock.elapsedRealtime() - animateExpandStartTime) < animateExpandDuration(); for (int i = 0; i < imageViewEmojis.size(); i++) { @@ -3193,7 +3510,6 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } } -// canvas.drawRect(0,0,w,h,Theme.DEBUG_RED); if (drawInUi) { prepareDraw(System.currentTimeMillis()); drawInUiThread(canvas, alpha); @@ -3203,7 +3519,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } - float[] verts = new float[16]; +// float[] verts = new float[16]; @Override public void drawBitmap(Canvas canvas, Bitmap bitmap, Paint paint) { @@ -3296,7 +3612,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati alpha *= alphaT; } } else { - alpha = imageView.getAlpha(); + alpha *= imageView.getAlpha(); } if (!imageView.isDefaultReaction && !imageView.isStaticIcon) { @@ -3339,7 +3655,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati int w = imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight(); int h = imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom(); AndroidUtilities.rectTmp2.set(imageView.getPaddingLeft(), imageView.getPaddingTop(), imageView.getWidth() - imageView.getPaddingRight(), imageView.getHeight() - imageView.getPaddingBottom()); - if (imageView.selected && type != TYPE_TOPIC_ICON) { + if (imageView.selected && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) { AndroidUtilities.rectTmp2.set( (int) Math.round(AndroidUtilities.rectTmp2.centerX() - AndroidUtilities.rectTmp2.width() / 2f * 0.86f), (int) Math.round(AndroidUtilities.rectTmp2.centerY() - AndroidUtilities.rectTmp2.height() / 2f * 0.86f), @@ -3389,7 +3705,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati float scale = imageView.getScaleX(); if (imageView.pressedProgress != 0 || imageView.selected) { - scale *= 0.8f + 0.2f * (1f - ((imageView.selected && type != TYPE_TOPIC_ICON) ? 0.7f : imageView.pressedProgress)); + scale *= 0.8f + 0.2f * (1f - ((imageView.selected && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) ? 0.7f : imageView.pressedProgress)); } boolean animatedExpandIn = animateExpandStartTime > 0 && (SystemClock.elapsedRealtime() - animateExpandStartTime) < animateExpandDuration(); boolean animatedExpandInLocal = animatedExpandIn && animateExpandFromPosition >= 0 && animateExpandToPosition >= 0 && animateExpandStartTime > 0; @@ -3406,7 +3722,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati alpha = alphaT; } } else { - alpha = imageView.getAlpha(); + alpha *= imageView.getAlpha(); } AndroidUtilities.rectTmp2.set((int) imageView.getX() + imageView.getPaddingLeft(), imageView.getPaddingTop(), (int) imageView.getX() + imageView.getWidth() - imageView.getPaddingRight(), imageView.getHeight() - imageView.getPaddingBottom()); @@ -3473,8 +3789,11 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } else if ((imageView.isDefaultReaction || imageView.isStaticIcon) && imageView.imageReceiver != null) { + canvas.save(); + canvas.clipRect(imageView.imageReceiver.getDrawRegion().left, imageView.imageReceiver.getDrawRegion().top, imageView.imageReceiver.getDrawRegion().right, imageView.imageReceiver.getDrawRegion().bottom); imageView.imageReceiver.setAlpha(alpha); imageView.imageReceiver.draw(canvas); + canvas.restore(); } } @@ -3534,12 +3853,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } - private Runnable updateRowsDelayed = () -> updateRows(true, true); + private final Runnable updateRowsDelayed = () -> NotificationCenter.getInstance(currentAccount).doOnIdle(() -> updateRows(true, true)); @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.stickersDidLoad) { - if (((int) args[0]) == MediaDataController.TYPE_EMOJIPACKS) { + if (((int) args[0]) == MediaDataController.TYPE_EMOJIPACKS || (((int) args[0]) == MediaDataController.TYPE_IMAGE && showStickers)) { updateRows(true, true); } } else if (id == NotificationCenter.featuredEmojiDidLoad) { @@ -3584,7 +3903,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati hideAnimator.cancel(); hideAnimator = null; } - boolean animated = type != TYPE_TOPIC_ICON; + boolean animated = type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR; if (animated) { showAnimator = ValueAnimator.ofFloat(0, 1); @@ -3625,11 +3944,16 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private FrameLayout box; private ImageView search; private ImageView clear; - private CloseProgressDrawable2 clearDrawable; + private FrameLayout inputBox; + private View inputBoxGradient; + private SearchStateDrawable searchStateDrawable; private EditTextCaption input; + private StickerCategoriesListView categoriesListView; + public SearchBox(Context context) { super(context); + setClickable(true); setBackgroundColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); box = new FrameLayout(context); @@ -3643,16 +3967,33 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } }); } - addView(box, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.FILL_HORIZONTAL, 8, 4 + 8, 8, 8)); + addView(box, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.FILL_HORIZONTAL, 8, 8 + 4, 8, 8)); search = new ImageView(context); search.setScaleType(ImageView.ScaleType.CENTER); - search.setImageResource(R.drawable.smiles_inputsearch); - search.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + searchStateDrawable = new SearchStateDrawable(); + searchStateDrawable.setIconState(SearchStateDrawable.State.STATE_SEARCH, false); + searchStateDrawable.setColor(Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider)); + search.setImageDrawable(searchStateDrawable); + search.setOnClickListener(e -> { + if (searchStateDrawable.getIconState() == SearchStateDrawable.State.STATE_BACK) { + input.setText(""); + search(null, true, false); + if (categoriesListView != null) { + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(true, true); + } + input.clearAnimation(); + input.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + showInputBoxGradient(false); + } + }); box.addView(search, LayoutHelper.createFrame(36, 36, Gravity.LEFT | Gravity.TOP)); - input = new EditTextCaption(context, resourcesProvider) { + inputBox = new FrameLayout(context); + box.addView(inputBox, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 36, 0, 0, 0)); + input = new EditTextCaption(context, resourcesProvider) { @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { if (focused) { @@ -3667,30 +4008,28 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati }; input.addTextChangedListener(new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - + public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { - search(input.getText() == null || AndroidUtilities.trim(input.getText(), null).length() == 0 ? null : input.getText().toString()); + final String query = input.getText() == null || AndroidUtilities.trim(input.getText(), null).length() == 0 ? null : input.getText().toString(); + search(query); + if (categoriesListView != null) { + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(TextUtils.isEmpty(query), true); + } + if (input != null) { + input.clearAnimation(); + input.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + showInputBoxGradient(false); } }); input.setBackground(null); input.setPadding(0, 0, AndroidUtilities.dp(4), 0); input.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - if (type == TYPE_EMOJI_STATUS) { - input.setHint(LocaleController.getString(R.string.SearchEmojiHint)); - } else if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { - input.setHint(LocaleController.getString(R.string.SearchReactionsHint)); - } else { - input.setHint(LocaleController.getString(R.string.SearchIconsHint)); - } + input.setHint(LocaleController.getString("Search", R.string.Search)); input.setHintTextColor(Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider)); input.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); @@ -3702,36 +4041,146 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati input.setMaxLines(1); input.setSingleLine(true); input.setLines(1); - box.addView(input, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 36, -1, 32, 0)); + input.setTranslationY(AndroidUtilities.dp(-1)); + inputBox.addView(input, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 32, 0)); - clear = new ImageView(context); - clear.setScaleType(ImageView.ScaleType.CENTER); - clear.setImageDrawable(clearDrawable = new CloseProgressDrawable2(1.25f) { - @Override - protected int getCurrentColor() { - return Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider); - } - }); - clearDrawable.setSide(AndroidUtilities.dp(7)); - clear.setScaleX(0.1f); - clear.setScaleY(0.1f); - clear.setAlpha(0.0f); - box.addView(clear, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP)); - clear.setOnClickListener(v -> { - input.setText(""); - search(null); - }); + inputBoxGradient = new View(context); + Drawable gradientDrawable = context.getResources().getDrawable(R.drawable.gradient_right).mutate(); + gradientDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_emojiPanelBackground, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + inputBoxGradient.setBackground(gradientDrawable); + inputBoxGradient.setAlpha(0f); + inputBox.addView(inputBoxGradient, LayoutHelper.createFrame(18, LayoutHelper.MATCH_PARENT, Gravity.LEFT)); setOnClickListener(e -> { onInputFocus(); input.requestFocus(); scrollToPosition(0, 0); }); + + if (type == TYPE_REACTIONS || type == TYPE_EMOJI_STATUS || type == TYPE_AVATAR_CONSTRUCTOR) { + int categoriesType; + switch (type) { + case TYPE_EMOJI_STATUS: + categoriesType = StickerCategoriesListView.CategoriesType.STATUS; + break; + case TYPE_AVATAR_CONSTRUCTOR: + categoriesType = StickerCategoriesListView.CategoriesType.PROFILE_PHOTOS; + break; + case TYPE_REACTIONS: + default: + categoriesType = StickerCategoriesListView.CategoriesType.DEFAULT; + break; + } + categoriesListView = new StickerCategoriesListView(context, categoriesType, resourcesProvider) { + @Override + public void selectCategory(int categoryIndex) { + super.selectCategory(categoryIndex); + updateButton(); + } + + @Override + protected boolean isTabIconsAnimationEnabled(boolean loaded) { + return !SharedConfig.getLiteMode().enabled() && (!loaded || type == TYPE_AVATAR_CONSTRUCTOR); + } + }; + categoriesListView.setShownButtonsAtStart(type == TYPE_AVATAR_CONSTRUCTOR ? 6.5f : 4.5f); + categoriesListView.setDontOccupyWidth((int) (input.getPaint().measureText(input.getHint() + ""))); + categoriesListView.setBackgroundColor(Theme.getColor(Theme.key_chat_emojiPanelBackground, resourcesProvider)); + categoriesListView.setOnScrollIntoOccupiedWidth(scrolled -> { + input.setTranslationX(-Math.max(0, scrolled)); + showInputBoxGradient(scrolled > 0); + updateButton(); + }); + categoriesListView.setOnCategoryClick(category -> { + if (categoriesListView.getSelectedCategory() == category) { + search(null, false, false); + categoriesListView.selectCategory(null); + } else { + search(category.emojis, false, false); + categoriesListView.selectCategory(category); + } + }); + box.addView(categoriesListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 36, 0, 0, 0)); + } + + clear = new ImageView(context); + clear.setScaleType(ImageView.ScaleType.CENTER); + clear.setImageDrawable(new CloseProgressDrawable2(1.25f) { + { setSide(AndroidUtilities.dp(7)); } + @Override + protected int getCurrentColor() { + return Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider); + } + }); + clear.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), Theme.RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(15))); + clear.setAlpha(0f); + clear.setOnClickListener(e -> { + input.setText(""); + search(null, true, false); + if (categoriesListView != null) { + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(true, true); + } + input.clearAnimation(); + input.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + showInputBoxGradient(false); + }); + box.addView(clear, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP)); + } + + private Runnable delayedToggle; + private void toggleClear(boolean enabled) { + if (enabled) { + if (delayedToggle == null) { + AndroidUtilities.runOnUIThread(delayedToggle = () -> { + AndroidUtilities.updateViewShow(clear, true); + }, 340); + } + } else { + if (delayedToggle != null) { + AndroidUtilities.cancelRunOnUIThread(delayedToggle); + delayedToggle = null; + } + AndroidUtilities.updateViewShow(clear, false); + } + } + + private boolean inputBoxShown = false; + private void showInputBoxGradient(boolean show) { + if (show == inputBoxShown || inputBoxGradient == null) { + return; + } + inputBoxShown = show; + inputBoxGradient.clearAnimation(); + inputBoxGradient.animate().alpha(show ? 1 : 0).setDuration(120).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + + public boolean isInProgress() { + return searchStateDrawable.getIconState() == SearchStateDrawable.State.STATE_PROGRESS; + } + + public void showProgress(boolean progress) { + if (progress) { + searchStateDrawable.setIconState(SearchStateDrawable.State.STATE_PROGRESS); + } else { + updateButton(true); + } + } + + private void updateButton() { + updateButton(false); + } + + private void updateButton(boolean force) { + if (!isInProgress() || input.length() == 0 && (categoriesListView == null || categoriesListView.getSelectedCategory() == null) || force) { + boolean backButton = input.length() > 0 || categoriesListView != null && categoriesListView.isCategoriesShown() && (categoriesListView.isScrolledIntoOccupiedWidth() || categoriesListView.getSelectedCategory() != null); + searchStateDrawable.setIconState(backButton ? SearchStateDrawable.State.STATE_BACK : SearchStateDrawable.State.STATE_SEARCH); + } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(4 + 8+36+8), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(8+36+8), MeasureSpec.EXACTLY)); } } @@ -4056,7 +4505,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if (skew < 1) { canvas.translate(AndroidUtilities.rectTmp2.left, AndroidUtilities.rectTmp2.top); canvas.scale(1f, skew, 0, 0); - canvas.skew((1f - 2f * imageViewEmoji.skewIndex / layoutManager.getSpanCount()) * (1f - skew), 0); + canvas.skew((1f - 2f * imageViewEmoji.skewIndex / SPAN_COUNT_FOR_EMOJI) * (1f - skew), 0); canvas.translate(-AndroidUtilities.rectTmp2.left, -AndroidUtilities.rectTmp2.top); } canvas.clipRect(0, 0, getWidth(), clipBottom + showT * AndroidUtilities.dp(45)); @@ -4068,9 +4517,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati AndroidUtilities.rectTmp2.offset(AndroidUtilities.dp(8 * skew), 0); } else if (imageViewEmoji.skewIndex == 1) { AndroidUtilities.rectTmp2.offset(AndroidUtilities.dp(4 * skew), 0); - } else if (imageViewEmoji.skewIndex == layoutManager.getSpanCount() - 2) { + } else if (imageViewEmoji.skewIndex == SPAN_COUNT_FOR_EMOJI - 2) { AndroidUtilities.rectTmp2.offset(-AndroidUtilities.dp(-4 * skew), 0); - } else if (imageViewEmoji.skewIndex == layoutManager.getSpanCount() - 1) { + } else if (imageViewEmoji.skewIndex == SPAN_COUNT_FOR_EMOJI - 1) { AndroidUtilities.rectTmp2.offset(AndroidUtilities.dp(-8 * skew), 0); } canvas.saveLayerAlpha(AndroidUtilities.rectTmp2.left, AndroidUtilities.rectTmp2.top, AndroidUtilities.rectTmp2.right, AndroidUtilities.rectTmp2.bottom, (int) (255 * (1f - showT)), Canvas.ALL_SAVE_FLAG); @@ -4295,7 +4744,11 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } animateShow(false, () -> { onEnd(date); - super.dismiss(); + try { + super.dismiss(); + } catch (Exception ignore) { + + } }, () -> { if (date != null) { try { @@ -4530,7 +4983,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati return; } - void setAnimationsEnabled(boolean aniationsEnabled) { + public void setAnimationsEnabled(boolean aniationsEnabled) { this.animationsEnabled = aniationsEnabled; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java index 97261b362..2a69c142e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java @@ -1170,7 +1170,7 @@ public class StickersActivity extends BaseFragment implements NotificationCenter TLRPC.TL_availableReaction availableReaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get(reaction); if (availableReaction != null) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(availableReaction.static_icon.thumbs, Theme.key_windowBackgroundGray, 1.0f); - settingsCell.getValueBackupImageView().getImageReceiver().setImage(ImageLocation.getForDocument(availableReaction.center_icon), "100_100_lastframe", svgThumb, "webp", availableReaction, 1); + settingsCell.getValueBackupImageView().getImageReceiver().setImage(ImageLocation.getForDocument(availableReaction.center_icon), "100_100_lastreactframe", svgThumb, "webp", availableReaction, 1); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java b/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java index 881c90abe..799f575bc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java @@ -427,7 +427,7 @@ public class TextMessageEnterTransition implements MessageEnterTransitionContain if (messageView.animatedEmojiStack != null) { messageView.animatedEmojiStack.clearPositions(); } - messageView.drawMessageText(bitmapCanvas, messageView.getMessageObject().textLayoutBlocks, true, 1f, true); + messageView.drawMessageText(bitmapCanvas, messageView.getMessageObject().textLayoutBlocks, messageView.getMessageObject().textXOffset, true, 1f, true); messageView.drawAnimatedEmojis(bitmapCanvas, 1f); } float listViewBottom = listView.getY() - container.getY() + listView.getMeasuredHeight(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java index b5ebb2bf6..4f6064071 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java @@ -177,6 +177,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No private int themeAccentListRow; private int themeInfoRow; private int chatBlurRow; + private int pauseOnRecordRow; private int swipeGestureHeaderRow; private int swipeGestureRow; @@ -514,6 +515,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No chatListRow = -1; chatListInfoRow = -1; chatBlurRow = -1; + pauseOnRecordRow = -1; lightModeRow = -1; lightModeTopInfoRow = -1; @@ -618,6 +620,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No directShareRow = rowCount++; enableAnimationsRow = rowCount++; raiseToSpeakRow = rowCount++; + pauseOnRecordRow = rowCount++; bluetoothScoRow = rowCount++; sendByEnterRow = rowCount++; if (SharedConfig.canBlurChat()) { @@ -626,7 +629,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No distanceRow = rowCount++; settings2Row = rowCount++; - if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW || BuildVars.DEBUG_VERSION) { + if (SharedConfig.getDevicePerformanceClass() <= SharedConfig.PERFORMANCE_CLASS_AVERAGE || BuildVars.DEBUG_VERSION) { lightModeRow = rowCount++; lightModeTopInfoRow = rowCount++; } @@ -903,7 +906,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No if (setFontSize(AndroidUtilities.isTablet() ? 18 : 16)) { changed = true; } - if (setBubbleRadius(10, true)) { + if (setBubbleRadius(17, true)) { changed = true; } if (changed) { @@ -1018,6 +1021,11 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(SharedConfig.raiseToSpeak); } + } else if (position == pauseOnRecordRow) { + SharedConfig.togglePauseMusicOnRecord(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(SharedConfig.pauseMusicOnRecord); + } } else if (position == distanceRow) { if (getParentActivity() == null) { return; @@ -1310,7 +1318,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No } int fontSize = AndroidUtilities.isTablet() ? 18 : 16; Theme.ThemeInfo currentTheme = Theme.getCurrentTheme(); - if (SharedConfig.fontSize != fontSize || SharedConfig.bubbleRadius != 10 || !currentTheme.firstAccentIsDefault || currentTheme.currentAccentId != Theme.DEFALT_THEME_ACCENT_ID || accent != null && accent.overrideWallpaper != null && !Theme.DEFAULT_BACKGROUND_SLUG.equals(accent.overrideWallpaper.slug)) { + if (SharedConfig.fontSize != fontSize || SharedConfig.bubbleRadius != 17 || !currentTheme.firstAccentIsDefault || currentTheme.currentAccentId != Theme.DEFALT_THEME_ACCENT_ID || accent != null && accent.overrideWallpaper != null && !Theme.DEFAULT_BACKGROUND_SLUG.equals(accent.overrideWallpaper.slug)) { menuItem.showSubItem(reset_settings); } else { menuItem.hideSubItem(reset_settings); @@ -2237,6 +2245,8 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No textCheckCell.setTextAndCheck(LocaleController.getString("SendByEnter", R.string.SendByEnter), preferences.getBoolean("send_by_enter", false), true); } else if (position == raiseToSpeakRow) { textCheckCell.setTextAndCheck(LocaleController.getString("RaiseToSpeak", R.string.RaiseToSpeak), SharedConfig.raiseToSpeak, true); + } else if (position == pauseOnRecordRow) { + textCheckCell.setTextAndCheck(LocaleController.getString(R.string.PauseMusicOnRecord), SharedConfig.pauseMusicOnRecord, true); } else if (position == customTabsRow) { textCheckCell.setTextAndValueAndCheck(LocaleController.getString("ChromeCustomTabs", R.string.ChromeCustomTabs), LocaleController.getString("ChromeCustomTabsInfo", R.string.ChromeCustomTabsInfo), SharedConfig.customTabs, false, true); } else if (position == directShareRow) { @@ -2352,7 +2362,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No } else if (position == automaticBrightnessRow) { return TYPE_BRIGHTNESS; } else if (position == scheduleLocationRow || position == enableAnimationsRow || position == sendByEnterRow || - position == raiseToSpeakRow || position == customTabsRow || + position == raiseToSpeakRow || position == pauseOnRecordRow || position == customTabsRow || position == directShareRow || position == chatBlurRow || position == lightModeRow) { return TYPE_TEXT_CHECK; } else if (position == textSizeRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java index 4edde87cd..61debde21 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java @@ -2042,6 +2042,9 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N private void toggleSelection(View view) { if (view instanceof TopicDialogCell) { TopicDialogCell cell = (TopicDialogCell) view; + if (cell.forumTopic == null) { + return; + } int id = cell.forumTopic.id; if (!selectedTopics.remove(id)) { selectedTopics.add(id); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java index 209c36dee..6a3b4e4d8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java @@ -564,7 +564,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification } else if (id == forward) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { StringBuilder fmessage = new StringBuilder(); @@ -614,7 +614,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification args1.putLong("chat_id", -did); } if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args1, fragment1)) { - return; + return true; } } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); @@ -623,6 +623,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification presentFragment(chatActivity, true); SendMessagesHelper.getInstance(currentAccount).sendMessage(fmessage.toString(), did, null, null, null, true, null, null, null, true, 0, null, false); } + return true; }); presentFragment(fragment); } diff --git a/TMessagesProj/src/main/java/org/webrtc/DefaultVideoEncoderFactory.java b/TMessagesProj/src/main/java/org/webrtc/DefaultVideoEncoderFactory.java index 76896b6b2..87dccd7f8 100644 --- a/TMessagesProj/src/main/java/org/webrtc/DefaultVideoEncoderFactory.java +++ b/TMessagesProj/src/main/java/org/webrtc/DefaultVideoEncoderFactory.java @@ -11,6 +11,9 @@ package org.webrtc; import androidx.annotation.Nullable; + +import com.google.android.exoplayer2.util.Log; + import java.util.Arrays; import java.util.LinkedHashSet; diff --git a/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java b/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java index 8e9bac2ec..a14729569 100644 --- a/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java +++ b/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java @@ -11,18 +11,20 @@ package org.webrtc; import static org.webrtc.MediaCodecUtils.EXYNOS_PREFIX; +import static org.webrtc.MediaCodecUtils.EXYNOS_PREFIX_C2; +import static org.webrtc.MediaCodecUtils.HISI_PREFIX; import static org.webrtc.MediaCodecUtils.INTEL_PREFIX; import static org.webrtc.MediaCodecUtils.QCOM_PREFIX; -import static org.webrtc.MediaCodecUtils.HISI_PREFIX; import android.media.MediaCodecInfo; -import android.media.MediaCodecList; import android.os.Build; +import android.util.Log; + +import androidx.annotation.Nullable; import org.telegram.messenger.voip.Instance; import org.telegram.messenger.voip.VoIPService; -import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; @@ -222,7 +224,8 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { || (name.startsWith(EXYNOS_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) // Intel Vp8 encoder is supported in LOLLIPOP or later, with the intel encoder enabled. || (name.startsWith(INTEL_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP - && enableIntelVp8Encoder); + && enableIntelVp8Encoder) + || ((name.startsWith(EXYNOS_PREFIX_C2) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)); } private boolean isHardwareSupportedInCurrentSdkVp9(MediaCodecInfo info) { diff --git a/TMessagesProj/src/main/java/org/webrtc/MediaCodecUtils.java b/TMessagesProj/src/main/java/org/webrtc/MediaCodecUtils.java index 40dca27a5..f59a21d92 100644 --- a/TMessagesProj/src/main/java/org/webrtc/MediaCodecUtils.java +++ b/TMessagesProj/src/main/java/org/webrtc/MediaCodecUtils.java @@ -16,14 +16,12 @@ import android.media.MediaCodecInfo.CodecCapabilities; import android.media.MediaCodecList; import android.os.Build; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.voip.VoIPService; - import androidx.annotation.Nullable; +import org.telegram.messenger.FileLog; + import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Map; @@ -35,6 +33,7 @@ class MediaCodecUtils { // Prefixes for supported hardware encoder/decoder component names. static final String EXYNOS_PREFIX = "OMX.Exynos."; + static final String EXYNOS_PREFIX_C2 = "c2.exynos."; static final String INTEL_PREFIX = "OMX.Intel."; static final String NVIDIA_PREFIX = "OMX.Nvidia."; static final String QCOM_PREFIX = "OMX.qcom."; diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_channel_create.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_channel_create.png new file mode 100644 index 0000000000000000000000000000000000000000..c7ecdb1815b8cc8ac119105faa54ca3998e4f54d GIT binary patch literal 970 zcmV;*12z1KP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0G)Y83R9Fe^m`g}hQ5eT(Dm9@X zkf;`t1mQv>qINwraM7Y7C|a~=QPiSEts@BK~v1o$nNB> z2hE_SWDrh!fM}qkb4&+vt^<#i+|VfeG)Narg)w8Cvjv@E8dMM*1LHQg$FCGjiDOwC zBHu#L?KJQMSXZz)~MVP#C$%8sG;e8$##=g{IQ+&kit% zw9xU>D>@3?yw@4e^Jf8_rIWJF0b9Uq4N6cw_SN7O86@ulwIGbvqHHsUU+{zJboy$T zqobQ#*lK7i*ajqvT0pA==+u8U`KeuZ(~PwUHyODYdyR1?&Ace)RMf`Pms~^m90ET< zF?xz|e$iqWodg;A&eBI*;)y#!EyyAAG&s2~WBlffBZ*-Rjho1cNEyoP6xPsfYP<&* z%3Lc_I=heqXQufjgJpptVIgmZSY&I!f`t1B%H=dfBipg`f=7Wz!a`0%)V9ZZbHaTD z<@|>14%7Ki9e5=u_zev?wO2WEVxr&BeJb1Y=M1w{l~^aHP|mhz%lFenJGLWWBhY>2 z68sH_a$#G9pQX80m=>pj8t@QImxf5NvQ#rpk&Jx(SC(Ry#?Wha4uh{?stp#9b^qsLEhyMYVLN8}3XdU30yavJ)INmWqBk<4*8TuQ>r_bhK ztn2Hb(Tn9=U*(5RH%m(=q|19{QhL;7#`-$ZNghVOjWRg9c=bB%b#!zaTO<4#)%TjQ zm~NJqbeStnB&Y(z<}rH0BCvHC`=D<}uUYVa0zE-@9()0!?_h}^TX2l?Sw$II?mMEt zXl%p2&5p6RfRDz{W%>!U&-z8;1T;DsI{YAP=Zt;Cx4C0{>Ocq3;{OEh0qyAcMBrT@ z8Ut-^2FBL**40;3rl|fLuv=Nv+ykzGUSP>?fQt4KB&X_TpamF4{U~)9PK(lUqba(S s82#+s0P4UfcmUej>Yw2=RM8pu2e`taY+6)-cK`qY07*qoM6N<$f}>cgp#T5? literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_download_settings.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_download_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..da98eae6c8b77bbcf5d4e9f3dfbd60750d67f7b2 GIT binary patch literal 635 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*;7v!$B+ol zx6{1!SsVq9mz%9|_fXNcD2OTiBDvwnRrd+DYksgj3g+OHj(1VwvrzKmo0B7B!^ih% zYRAXbcW1u%^6ktQJD;X?PwcPuuUhwN)ysFMQe<{={MpD+;raVxt$p_ykr`~|56*nv z<6iNr#n`ogH{{onV8-T^RV@cMy=q-pJ9AdBgjPfP(N5)C*$K=xnvbXYxv$htIv9HF zck@o!A6)-?^=s$cY?<4{7_g|Gv7Yhl1?xlAYbvvswoFV`<*JPB+{v7}?`oRp(K-9J z%~25UWogbYxZL^5Sku(ftntr;b;46O6|-Y}=ZaBODeyYuWyUzV_apu{A-x#lVcOWcd+J z#hpT@=5AQLUhsEGLdd0!JkJ_!WG8(V-r)Lg{e!-seutb>x4x=*>|8A(#iXe&aOC3q zl_EX=1)`;sZ*wnLp7{GD^P=q{9WSRIQhA)XRN<=gyw``ngt5Icm~*l*D`wB^8OEVp zLBXvizjJrqGurF?iRrZW9X;1jt}I@YRnmd+Z*R@nb704QzvV1Zo{{ENhZR-@MWpDd ztkkNTcB5yth>)|-l&EzgJ;&`XE^1})+v#;s$gTe~ HDWM4f{J8vK literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_activities.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_activities.png index 6df9449732942ed8ca85044330caf647de836da6..d9f07f2792028297a4b96d92e6837a8777edb78e 100644 GIT binary patch delta 1021 zcmVp~CbMCq4o_oFDeHn=qq%Z>un}KLP%@c`41MLpME?5U^L4Ps^qwoN_qtWOf`rioy ziNg@&DvFIS`iMwc4FldN-ePw^Gt@$bqaOVYB)?NC`Kz|oi!v}0#b5#?lW-J@{p6I( z-~^0-V!lIAlq2T1o42h5@Dn62;JKfKvIcSzMnN5(1!ci=#X^5Gzx+#5LH7 zRu1Ko3|LG~ng-fU63xgmXoNoylndDs61>Va*rGUW>gLPzN~ttCV4+d(%%@n5K-;|8_shno6S^DJ z`Bk_NzJGkBu+`dO>vWe4n{QT4kWN}j#<@cIJoL@lkP7Ox8#U-Kd5u#utwVE<3rK%T z%Ufbb4tgmuKeENKKD3_H$(oS3P587?v~IPoB&Jg(e!~{Eo)8jyQlv_eNEybI6|(4w zEOqVFX(`y}dl!ri8<5^JlA4rC|IRr>E^@X3^?xygr{NWG8(pmRmF^^LKzdwB4y082 zS7*|GKFM*&xa}@%(VUORfW7b*e5* z2-3wYX@dNpA4*Pw-~%nW0r2ap@FnYi76eX#Hp3OyD8C1q8&r%W_Jq~rN>hFjv~Z8X zZP5F<6T)_^{xIEvk3f?D6V^TfNn)VCN_L{h)i|_y^|~%TK|iDqQ*7-fEnvk3 delta 816 zcmV-01JC^M2&4y)fqxE3L_t(o3GJ6LYg9oH$8(8jCrTt@EL5x{c7h-%_W|Uv6KvCn zphiqDeu8|5^l2>YmD5HHS_D&wO+?X15CjX0`279v%{+IPx9{C~2T{zx+|JJY=fCsz z?Y`Zcn%bBDaR!Q_n2}E6**l|>*ua;`yM|stPoi_EWE=f}_J7ew=(A3zvr9X9u~}H8 zeUA<+!YXGXvsXP8gbU~f>av5eie5)ApeIaa%cqzyF3Me~2*)uX>Y?9^S%WO2huS!W zF{~FRj$T_{V_XF2E-HDB9&1df2`UGDib}-wXGM{y*W@#UIUqeyGiIxc+%*xHh;y{p zM}oGoubG$F-+xib-PX|)06F&tnMLt~cHL}o55Ld>YiCIG{x#*d)Irogl8l+{f<0_G zG{qfMT;h-{W)s5zK+TSC?PbNx_l8!o6ylp~u-X8UPv~GH(7I1!w9gWtE-KNJRJ#fL zww%c8rXs=^*jIy$qIl?j`r3UyOI`P8Tfi$uvKoT$&3~dlE#_b55E9wo^lg%8XB`iN z^!1&Rtb~5q)2V~LjswZ#vMGN#0(P)A&37q`W$cUQ-z4{Qf^lvis|wc@q_au#u56;; z4eOnWy!D;4=JuQr<=j426^jaD3bn}mb$qN)zYWcjWVUP?e~((!b3(9l&)Jw&EGnq- z<_%xuBY)o#@|1BTD#)%1xI&*x^lF8|;9YA0o-*Hh7|Yl%%zuvDXxrm=ZXYW{ft%zm zDoH<#4@!6OB%d8ez)$4ESa)74wDG zcUry@i+~;faJ7OoOX2lHR|m<>)+!PJIZK1gajqX$RC+;MOU4?yOF`pZ(0n9_dZ=Gv z``CMTg-wd`tE_gO7HaD{62`E8)euL|dB!0N ukSR3sz5grS^kgb>lv!xv+K>HnGw=)kR}iHiM_WJu0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~&`Cr=R9Fe^mp^M1VGxINY9S$# z(nPU1l@w|du&_`rDaAsIqzVXue1U*pAf2tEA3&@Ht?be$q!CgH38;<6%F2MCh3oSy z?;LxV-M!m0>VX;f@y^ctX5P8?|4mFB$-Uzft3D2@@p13>U1~?1O0Od2-1FyjI zR;#s5`{#s0mcR}eR^%=ndPO8{gRMdpAJHFyn_v!1C8%rDCnv<%_MsF;q7L{1ls&Kp zjt@#MCvlBY%+VPXSL-(c_yLp`;8bluiPM-AOOxjsttf(>rWlzA=*LR>8_HxXcnB18 zHlIF%V$C=*BNr1Dn**3j*$VqmEdlN(#rbbMO;w$kE9InVu=^m#)?SO`*jnHMmEz+ZYVc<6VNZ6R!BEgTO|WwXrRV}s-`ROWgd=>z*Lc$?rFxe`2dzb_@9oYJ+1 z-4k8ejo8W-(tb|mIw&LITTgzQ^?uGEzkE1T1|$3Z@uQqC?+Z!Z74%RC`GaSh6+cRK zs;-@~JWG}>!&@#*fKlH7f1@cIYEf4eGmM>LD;M>Nk_0}k7Qrp>vc#X8Na|sC6`Th? z(i9(OAHW+PXLZwIZpFUpg^o%O#)!f{3GRb|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKNxdgkfk7!tvm zoFKuvSkXX=X|bY16~~|d|KpoVVofeEmT+hbtY=9QSh1i@ROg8lQwf81zI3XnUQu^*J660Tt7$d6l?HpqO5R%!#S#(?5(T9L7A_P`U9f=Z znE1A)32B|PR=kib6$w0OB2{~Y?Xm)&<`=U-Ue3BhE2q3^5{zK|!!}Eb@yO~0%l;qC wPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~-bqA3R9Fe^m&;33Q5?r-N=*$4 z!Yq_Bu!m(Zi(XWOi)hg%T15pG;jUfO#zo*N>JLbQqNmt40@p!{3^$djJtXL1FDeBy z%SN0&Upp6u%bYWF&)kL<^M%ixbI&=y$35rVbMGV)WtC_KGMUVBxCpNx4S`-$>4DWH zN+ppXSQQL_OOteNElE-YI&3m|N!bbugTU0+z-^F5pd#pty~KGv9D!>v1l_PU9Ei3` z7zHU6?vLdf$DJ^x2qDdKeFZAB195%RjBC$s57)h>565zP4(8wvJb^To*^7A#oI>6KnvGhlwpn2uoAYz zy>O@NI&wld)6!@;mcUuCNeNHbI&JNd6G|qN)6B{q93B9hz4lf=V;|cB+uCgoZR3OX zAu0=Ckf3uU*i3z#`ULe_>P^(2QAU=W`bZn|5p&`(tPCX_aTRL*AARn6`*U4<9Ed#INXP0-6;dB^hTkQ_8&FHk;*0dxI- z79{O=Fk+bEmUjMw+iEdB+lZm}oR+$e8UE;u#o#e0m3qR-=4}S=V0}e1jSs)Y*(Z+E*Ey_cq&{37Nrq zbfwn6MJ&IYjF%TSZ?1$M7^8hQV~_T|#-=~AElaiAtoH{>y&8%VJ{mwDZu-Qn_i~2e zLy#^((#r`(*j7LvNVi;moIx<&hVgx|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31CxlSi(^Ox z=iBLf{SF(5v`Q!F1e;3)v|j05$lqY4EY@b{6wh&_`9h=YN@sVrXs5w-kdZsAtg+{yrp&?J z3LJ8p=IlLR9J8&7Rvo;I3&XN zpl;fZq?k2DESX<6eG2>L%~0o@$iW}3R$(>uagpY;sHZ*?*Q9QmxpUdR=aTy2lZzhm ziY$q&`RTE#+RZrlR*&U0wkgvLwtb6H<-FzFbZ!3!qouq`y30KS6TS=PL|0Exi`yof zo6D6r$-DW$I~$u@+h*?8oSvb>k^9!JTIB`f?1uOEE(k|Rd|L9ibJf+qR%aImZ`mlu z{DbFZslpxiqi%J+w~s~f6m3}XH}p%MP~0M=pQlTZ4}pa zGNuP)=(%6K))fEh4Cm2T{3;I7m!F;&l8yN>Eypr#^7V(CcI2NdX?fuwt2ys6=d8Ma zH#u`(>&=u6zxVjps^2^>ZIqpt8zgqTZriOc7ZT5WNz5dSX`ia}&W_VADO<&t*t3x>6^@SL0?o4URFM8D2i z->c7!Px$P-dFkC|cc!a8BL4#Z+@F8x|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM315>@Hi(^Ox z=iBN29-@IF$I`b<+0ay`B(6XY=uM-DaSDc<8rhCfw!lDDctE1S~W?xhby4@MD z&}nVd4vxtSdd`G)-%@o8`O*Hd{L7p@`E!2X+f#T?=Zox*dwaiIf4}qjtYvw{dsfH0 zuS9Poi*lT{^%rqf{}9iZ`}Et?kFG!VHTx&1@i<4O8y|^b|L+iIcHD99)GI1s9S$qc zq+eh;c0ftMdhv|JKUywalV6oFS{Ac@30$dp>`U7MN8QsM(yZn2Kc)5JGyTpuesD;x zHR=9Jv?%fMdtg?$4Z`-sXq6hc?YQEcdGBz(cQP zSGhKEt(`t+Qr*XCYfnE=$+ey*GA%S<8P`R#&g#WZyFLqSxjn6ut@?10V2bYP5XH48 zw)9QUoIQ7Wh(Jni95=F~3vNeoJ{*#j)=;u@| z&QLr#-`ags@PqAYvOVez`7GYA-go@Y-lTT3L2b(JBC~lc@0R|0DkPq)QnSQUT*CXF z#pE^M}02$7FNmnDw6~>&1Vz^z>)`U4AK$ne6Mzn%F4aZiYESc z;I?2t(p7o+&T`dE4mZ{6CfoAwVpi^Fd_VB%G|x|v*&?R3XkO0!@C4?dZVhWWMfq+DU!NyZa=T!l*5(JwF z!A7k72mA-Lvi5(tLi==q5DX!Tl3<}J6q7&*Nf*#Ujj(>c>&&t{dwVyYdlBUxe0OHv zy!U-?-_DP_QmHNN3f!{_1kJop7=~s1UVwhk>u?-1{sne}Ab;3*=87AVL^oIj2f$Zk zE1z!POuQ-tVFki<@XQeZp?wd2f)kLG9tKarICugiKfr4$wiS(T@*tTRa0(=!!6fKt z#3>tN`-N5_j+sV&b>|_d7$TZ*6?E2eKtBPdbLKjYFHMw`s(pRIS!?FISdi5`2Il&} zg^ZBrb?o#)5`S@euc??1CoM*aK2uy7`XW98BQmB9z&jwjhekI-UpDcJ&{w7G=Ua>e z`F3!&yJ<4%gI<9ob4h)&uerzqTSu?;Cpk#!8}@N1M{Z&Gn>Mw88IJ-5e2_<^Ib#!5 z(b}QYLKmk*XPKX1JR7-$;hLX^zZJY|hI_V_S63}1x_?olAHaDj$EI2JfN``j>hqAm zJosncqLs~=V!7F*PHGGWG589!K0bjxpnIuEc?_9O@K@j*40D2iqslGZS^XzbtoT~0nHUC-z(>&Pt-qsKZW8VqDzOFsV)Pd1&|GF*sE89t z-axEaDaj<1n!Sa=ok>Xl93-hT;!1Vnr{%OUQiOSz>jz_{pBd^Fb$uuq`#WmG#PDlK zWCgTJR`Rk)U9PSX*^Hrk3EV$}uBq=>pJ{{LwIA*4(6(z=;Lcaz61vob%2kYNwg3PC M07*qoM6N<$f*CSD0{{R3 delta 807 zcmV+?1K9kU2AT(ufPVu7Nkl8Mm4 z%ud)v>El~zV){tumTe^zTMgTx31+*6>DvY225;SQ{HqFLy{=})K85zcQ&n_q5dQ*f zRAE|oLFY|u1Ap-wU@h_clekDKX;RnT)A{KJ@NdIwCpL~h27jEGT=l!5K5=4S0>UF8 z`vvDt9iHzxcbr!Tk_NP98e;4#X zwN{H?50621&&E@=2o8lZ3ZxQ{M80-zQCvRbOTj*9yMHe?>Ktk{$z48?FIFfN#^I}P z%*GfWz`tVpZ8q+TOgWh)^-^x<$kQGvRA^u4?06N&-fd0MdhY?r{+d%&yPJphU l4j^{s9c|UBJMd3-;4ks5I(0}bQ*ZzP002ovPDHLkV1g}~h=KqB diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_happy.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_happy.png new file mode 100644 index 0000000000000000000000000000000000000000..d6242143e4776aa68fe216f34a6a406f30825c28 GIT binary patch literal 884 zcmV-)1B?8LP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~-bqA3R9Fe^mpy9~Q51%E)Xs^br7 zov)qAssZz=(c_hVYEDW)@UyctNEgbxOTMdI$l+wcm!42Acw4>#e{BuTbu z{~Rc!3wPnTkZ*V56_KsWpwn% z{GHLvG%m&~Rt~6K!j|jDY6;M467>9QKc=EVl*@9`)L4Bu`_f)1O5RjYZY>I7cdQ&Z zE~f6oWt&+|*b>+?W;WI_>{@-kC1`^!2hM9ySkLoBuVNg%*at(YUHU95Nq-k9+>h!+`FTrnc zm6QJ+ZHz&z$n+U_&#GStjp$ZQ|B`ke{N4lAf@LuC$E^m-v*n7ypoly6i_v%}SjD!hI$Py(0X4vZn)G8{SQ=r_N9 zSV3))R9?{VnT47)aWIr62igDWU4qBpVDPTPHq3~4EzFEL5lp^pCncQ0000< KMNUMnLSTZIXoVU8 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_hi.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_hi.png new file mode 100644 index 0000000000000000000000000000000000000000..61a5e910c24a02da9a3f999d9c4d864a1ecdb74d GIT binary patch literal 1097 zcmV-P1h)H$P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0vq?ljR9Fe^mRpF8Q547L3?sLY zOYR{xNN%Nx@}QJRDdiF=BDX}IH042gkxL%rL6a%MOpPdcqTFVLk_RNj!?@pxTqhjA z|994!_8I4V=Nr>eYF7Pb?fu_tt-a5l@7wz;DQUO=YzIo<#n1cn8N*snjR@ zzcD874ugF*+S?(tmvqMXc+otQq+kzx1K9)E9JSKvANWIX-TJrj9g4OX6=s4;n@sL~ z&{lJo#dM~9-^NxHdqMYXqIvjEP-A_$XhF89C8jsxI~8qF6n|n9jkk%r(!XWeS9~-% zz7%enzM&`!qIiF}WRslmN$8IPEk?F4(C22P^mBaIKp#&32t0y^Pz}R;Jdr11K754G zmU=ScA{+RQ?-J-&O|O(jyB}zQE$szDZ_kVM1ggjft8fvow@20lBR!e+F^O1Bpv}lg z>38^^P-p!H{5a!^X=^<%))TzY5*idpy91mzO}{oeQ1NB(8h*kEFG~9y$m%mL+UcRe zc$MkvT#NMt`x|q?1JSgoYgXuVpif5o1!3$|i*vWpMh7TH!;KpkCm`l&fFAIw+`}(%T|^wsgGyb-ST^ z5O7Mnbnw(hkzpjUsi>+aDiK&D+D?z%kv zqZ+{0hkD*NftpA*(F!c1-2__HPEVvg2=2m6*W9BW2ibPl+@n2>MsoZRkIC``>#dPB zKX9~%fDSa7CW}tzti+(h_+!xS3aj zl4z3F1~ExFoP#*4XRu#uYqu$$38z36XeadP@)}OTqBa$7Pj26VR_?%W*nug}6A6Ex P00000NkvXXu0mjfN+R*` literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_home.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_home.png new file mode 100644 index 0000000000000000000000000000000000000000..36b9d3080d29d83886bebf2ee14b2d24181f7659 GIT binary patch literal 915 zcmV;E18n?>P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~{YgYYR9Fe^mrsaIaTLej8>7b1 zlxdV{l#*E}qbx)glVrj|k(9DfnvI&2jk2+sjTMO$#lnJ(&_od%8&V{bSWuHv@@J;R zU@-6cd}n^=_3nMYd!PHelgOOIfG@vf<+2hcn?gtPVV5Jy7625nj+e{YgzCxR9pkc@J+A)Zo1ew zep^zQ*qmgn(6I#J49F(oK&>Fh&2SE6KViSkGhPU9;Ht$6d4%S}4Ul~SUC3Tz?ue3{ z9mSWS*ByWM7Uc;dv=|;b!T0!ejq1tS3*SL@5jIYZqNrFyh^&ASC-wrryiqeYPwpo8 z=xQH3AKnlG+U7AQbRXYgi~X*rW)-}48ghDG(e09ZGAAFQS1o4xo`nwKcGKVk;zsV z0@+vCsbqX>YEj?>nuB0A=#^pimdp5nU#}#5J6!S>1O(CAY-No5LAxY7Y4NHjco+0O z>Q)f1)At01t4TEj;(hQElBQT+O=@*WT(|x%3ozaax}HWXR`mp9pCTN0gRHJ0VtRLJ zCw0d>0zEW^#)@gK?nWRs4BC}8TbOZ&u;WxuQV+;{4RuXVMMFse;&vT&dFIrRY-MuJ zj_ZDfO*HUUH|fcP4+pm>&Rrge6U}0beJ??V|4S%_|nVLnZ!QoMHhzG?#*1q}r)h%#GrMEVv=9 z<`xcK+}Cl|MO|?PSvfwWsdaCM0+xSTuFRwe2hSQQ}OI?Bsq@FTP zhd$1(leZmiGd_+Vb9H%LI|cfbQ6tx+omXHgpC&rt8O)SPt23(^yE{^I5YVsM2WvsU pG{m&C58!<8?u4v5Tk~J;z%PX3bbxqid945d002ovPDHLkV1jg*j^6+P literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_like.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_like.png new file mode 100644 index 0000000000000000000000000000000000000000..a596b56e09f3da5e43b58b88c7d503f94d565b2a GIT binary patch literal 813 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31JiU*7srqY z&bQOgdy58&98V7s;%%8^vdTB(fzy;ahl^SsYc_;(=Kf+Xx~6~;uX5R+G&Kd(X$&H*3cAuP~f0F6i!%wZf zo+bJo>1Vk9wao6=c}LN(^7gAcTb+)n>}1(?kWa%>Xos}Jn@~m89gdzwJT;SZZfw|{ zcKkzsb7-<$gx*^Ixz!;q7mN$`K4@5H`ndgorUB!+AN%$<^GohJFEICk;Ec;h=(Zyc5vSL@%7B^gRBZ=-4f^j^L+o|eL&w~&GEd{JF*5f@jBt1>c=J=i#%q&q-!D5 z{Xv>B+8|9$$15ye|r=pS+}4-Tq1DW@?wfU+H(}qwY1WDonZA@4f2U;!e59 z#h1|&?;F+@enUIfmVF-M#`zDDD#E)Y7cmBg-!$tew{`vXL$_n8#>*+Tc5O3#t&EtT m*xy?Gab{M|TIT~+kWY#!+*Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~l}SWFR9Fe^mb+^eK@`TbMn$56 zNzlXxDB8tB@qvYfg{@ko5Q`wBjfGAAj0mDOqKK%qkU}AXfKox3mZ#bOWqnAvl_^UY-LW_R1#s;Ew&I)Ub%K#;{g48vvU4nQ9)hbg!d z1i?4Px9g+>fcMO>dU zzW~?Zek8AjcEC=EZu}nCSK&NNfQyl$n;9|(oy0)ggxnsuWty*yLNNxr6Z8Y*<)s*k z*Bf5b&;xVoB>H_~YVB}YA`8vi8|eE@C+{Agt}c&w*cwOcim?Q`0InFR|0L)}K`|V& z@?RnzueF5XA-`&&f_8;i$oOaI4x9J5Ulps+Fk?-iXB{h}Ixktj=Bp=^~#!P%Hsi|b{xbz+ zoBS~-UV-;LM@^fV1jQ5R%C%TlF~;360g9LK_w&_xkc)0cUzuxNttq1x0R7d9*RaVg z#9VLk=b+FDHFq_Qy=X=9^AM6GFlnQOQHJgcSs*^=^v&Q2QiEgKB>Bzz>;WX%p pJ`HEVeM_};FV$kz3H-Mw@CR^s|2a|H3+Vs=002ovPDHLkV1j7AXD9#w literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_neutral.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_neutral.png new file mode 100644 index 0000000000000000000000000000000000000000..370cad77f71f8ac9996437e1884275a16300aae1 GIT binary patch literal 809 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31Jh(r7srqY z&bQNTvqc?6+BRniDqd@HQfOJx>!GE+a|usoP>YF~<|F}I}f(rVSaz^=I4*+ZqA&0^JZt~#vb$1?(PmP01Tr_o;Ypa;~m)Qq)e6zan~cUC$mRkMsj&0Y?RYv2Wmb z*Qm+=a?{D>62ec<^(-;yuzDck(Ra{lN1W?A3HjABofcN1l}qac8;TWPHbpPx6kJ|Z zqvw0dG$v3bdsa@$y@m1JU&2o>iTNPsapY#rFON;-Zpy|bhG82m8g{7MPFsI<(t@ih z7yp>gTeisW$WzNqsWo;@xtZ(5C-P^vM|V4Iitlbd@YCdu?(I`oL%K~knxa>q-^P-= zfmx{9d<(Ppt~Xoi=gf*#oXyOh!0(eTw>)t-Z`nb`iW%Rl&#l`Y9shH~8@Wlo3Xx~l z%xwFc`>J&M^qI#qXUu2+*I&8+-N)?DQ*xgD-6(izyXU9FrvGF3nNELqFgM-Oy6fjv zsqJ4yf3cOWvh&V6P62az?${%m>}&6ch3?Z790#*>kP?)TR%Fxj$TLEQsZ zksoUp#8=L`A^d_vaienUZt1sIcldwWvazXT-o!Jzo&~KtmRtMPdgsOKMycGTj5>|I zXXfma?%!F@tma(ZS=aYo)cbF?p4%Ovuc3Np@*f`Sc;8yTf0oJm!*ZTFcO@np+$fo} zW$k_T^A)?!H^zSKKj6DLbj$va?+;wuY_a33$>&%kB8h@ z*BQ@>Urk(ctFR^1QHU!jux!fT{p~g3K~W*qbtd~jj?%JV kH|x5k$wzy0!|Pc7G3^!T(GLicz6469p00i_>zopr0IBF-zyJUM literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_omg.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_omg.png new file mode 100644 index 0000000000000000000000000000000000000000..eef79fee4ffaf4c865ac8a91f6bc790b1145d693 GIT binary patch literal 909 zcmV;819JR{P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~_en%SR9Fe^m%VCKK@`VxRZv6h zw27#sF^Dz+Ln>KPnGnGgc?8Krs7)R~L`iL7;YX(rU@SB&XpuJQ1c`+RS}15h*57}2 zPMAz)?pHP_xCefjGjl%X?99D$CnF<68Lq&=R-kAT-s|djQT0Bp29OY9aqHI8E<<+E8nYd5|l%^B;7c!v`>KECW-c6ORj|X;TuRk zz+1Q+Ct~ahtb=?cU*R5%f^yk2RsZcH$X;#t0Mma2-$5(00Ow#dF2?$@!Fjj=&*29= zhGU?dl1=k3ZE>7(?)}$RZ;D>!*Ki$7PS+TKfi_@BO^go`W&(>9%hU|5xzYBYmzSrrE)$WF+1FbmWrba~E=QrzEb~r^6St=i?eDr;17V zovX&%CKGY(KCZr~uAk6dKf>gUFGt1vr2i`#TaIGdUq5_7*$WyI&w##pi!cs_N4myj zo3Vn>Rm{OIXuhZpiFQDumHK;E*x=W7D8#O^x?H(ClG$@DetMhaYZo%*Xm_8ECn1rx z&z>n%cc0M}LI<2q-7$}Jjmc(r9#j|G{2m<_68A~0x6h6QO;jcFt$$Tz!XlouPM=Bs jjen)<6g%|!?^fUs?~|>IlEP7*00000NkvXXu0mjfQpAh0 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_party.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_party.png new file mode 100644 index 0000000000000000000000000000000000000000..8bfcd1de3d3fe4fcaae65cb83a621aa67d8f1923 GIT binary patch literal 1288 zcmV+j1^4=iP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz1a!Eu%R9Fe^muZMrRT#$|XWW-k zE7uVjlgOMg5lL~&tQ4WZQkf4UN};HsA0#GlYZ;dhDu_nu2f;By1qHG6gC=IUAxbKQ zl`Z1}j-@TwVx(Pv|MQ;ba=P>0_npQWrVl>w<5|x0Jm=hd&pr2jTeP?@jc^B|C~5^W zU@?>=TN0ZJPbA|_;xmyJa~Mqi!kBH7VHbg7+bkxH-wqZ)aTxbwvxrYf#_Q!%I1MD1 zVJrLtcVMD5z%GM_0>35x+aOtOacTTVT{Mbrq6@;Ydf60J`Uda&hD*Hv1-dZVgxCN$ z?Q^vFc;UXjkXSV=PS)1Tr*ITVbVZMV9?|z885cIee;j_*08#@lh2xE8(|DI=K%P-k zbd~d>XiYc?u}wa{1KmCxYgC)&x+`VY6uU2c4pS{Ajc*Gt593X4GjXeIlMtT=l3M5$ z=HT~-cOYwRn44--ycEvB!%9N82OR<0tlz=A(Ayed7r;J{d=kXF;Oi}wd|>hatSLSY zf5UJUqu&C_5Adh6qUaWSITZOEP5zS~>*`}|@Q?af!``l-`7qfM8h-1WZbx?oJpxLLv>7a}F10Kv&y4p_oFPMMNnr7p{Eoc)<_CWki!yXEnFqDfpI=w%Hulzu5w)yhLDE`VV& z>jq!@u}x@u40_8XI;U2^lVP1~VioYOQ$CrK)u(6(Nc0+)CXRT%Z-NSOR zOCdfyE#4qaBl|XCM$57_AwCG~5go*S!1A!Qmwtx}(9+@!(lpRSdYf*5L~oEgjgt+D z_lC0|(SC_HEcOWnkx5pE{UV$L_m)~brzUwDNGd^BD5**-VyrXlRg#x#v^Ka7KFKPp z#nzpaOtx4~P2yv42d+a$7!KM;w_$9qV#epf&tRfD$s*OEb>}6&LHu}g^;D6rP7;3z zv6s0>=0L1SYe0@JU=f6i(t+v@OtgL>NOV4(f;ZE8xi|@Wb97Z|7+(Q)A#4DXjTj}? z47)q%t8ZU=%;*3-Z#mNVcF1bnB>saC<~o~U;~3M&cnerf&uqE2AYGN@>9i!q2EuO8oz$Wv+7s)cUs_!lCr=w*ay5+Cu}RqH z(xT|uuELoH0lfM%rYtwREoP^h1S`-~ZcTy1D2402pU~&Ot z4z$hLFlCTB{if1B?Vgg736r3&x84eg-h{*OqZ}_f=w60Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0I7vi7R9Fe^mpxBZK@^5rH57`8 z32N}8kSJ;iMoU8rodtB1)cyy4f`rC@V4@^yH2wf%C?rS;Vqs7y3?_cXL=#z`XLp9( zy*u~rWkF*iCwZB<=Y7wavom+*4m~{wb}$2bn}JF<;niw>%MaCO8Mq0&Np)fal<0 zrBZoC`{#^8Ccp|PYicL2PW{%NLafQ4Iz)zq(0>=vj5~ML9mZp}gyP^nonc~dcp?@ebUMZKcU>0cR z-2L(q6yF(VCRq&rG4L2{2G}1h-_?nBm&Kik*DTl%J zpj)I}hT9I$d5yU>$0{}kDcttO(dAgi$ldmBH%7!BR!iVLxWKRdl^q7nC44u4OOri1 zoSilBlGr!2Ek>+|?OSjjTtn0OR!LCu(}BMq+yiAzZ9fC=7|(^DjP4 zG8$uGFmrWxg^dH40K`+-U%J~%zA>6P_Et<&Q7&J6r%djB#f8H6r1GkN^Mx07*qoM6N<$g5tlYasU7T literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sad.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sad.png new file mode 100644 index 0000000000000000000000000000000000000000..e14a99ed701539f5f4775fc8e37c1c00f84decca GIT binary patch literal 858 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31Je;t7srqY z&bQO;vqc;wj&078%ytdjq4ZKDD8gkz@NR)_5l2?(?jMYQIDT???Q2-jJGDt^iN|E6 z*48eCPP42Irw!hU9Gm{lyIYx>R`xBgeD90K?+1#FKmVKk{n>v%Uta^sMtkYTHQm+o zo)`bnJ?QEe2f)65c@-HR?oI3t9 zNMz$K)z;0+PP#pl`>NdePpb0?_j_kY!`uGye%sPajOI?>*dxlUHEl!cCpT5TTfR-t z_J1|GTDmAgPtCRaZu`dEw^MgLh<$qG+A@J{(nk*ztTWKxo||gE@bm-SioJRYyHqQr z!bAbvE28)7)cS_Tb<7Vd zBSY%aZ93!4KduSY_`6H}pX}{lpGp(wt|{-jW7+8Jd(+9B+5SNJhn$?|H!L;0_J@i$ z#^pY-y4X5*irs|7l7JaSvMgPKW*zo#e_3=KUbakUo8_4@Id*$7?u^%*3twKE{K(d) zseXlQ1#etK`kae;PrZNiEI;nA?k)N)=I5*+HY2NB1&4PEXzXG8Rr%xO&81u~pV>}d z(B-Gkl&BnV!K3$r+9&M-!F>&k9E)0a@ohbJ@4)d7#v)rz|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31Cx-ai(^Ox z=iBMN8ZL<2nOL-}B|J3#tn>1ll__S$VYnRULRrNYGZNt{7XEj_mPEOf0$!(Ki zWXBPc$@4$Xd3I-4`L6KKpI>U9UAg`HZ_Dr1_urcozw=QE>hxkgwYnkr-sAoDbI+#D zKAFLN@>kN|YlU;pPpI8|dd5pu$q&(UHow&N+8Qan@AABvvCVw{jsc%Cl?lFax18KvGn z!_XEKHCJ?U8q;q9r?(v*>pvdjwRQg06{61O`y!3$-?c)iIED8P&(k;#vhS_6>+NRh zp8ZpLUS*^x_iN|dFLsH(NYvTitNN-)WM;Ff`l{mTMm*>4bQV6lR{J0{e}8Jsf*H() zioEar&dxbtdekQ0MEqk^!K$<;t~ZlH7Th>&uwil9y@!bx7~X_%Jj@di(bxG`Y0g(A zsJ3#&o|9``5|TyKLzMr=JGQl@e_P%(RXg0}e>H0zL;Yvg3l)k|N}yEY>FVdQ&MBb@ E0F%fUu>b%7 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_stickers.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_stickers.png new file mode 100644 index 0000000000000000000000000000000000000000..b0eec704924fa20b37241b37702e3abaddb387f1 GIT binary patch literal 951 zcmV;o14#UdP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0AxT6*R9Fe^m%D3JK@`S!<0HYK zq81TcA>tFU5>$fmQP>D#qlm=EzhI?J6brGj(tjYeK?o>_O^U=WF=`_SqF@ol2MQ`$ z_{jSEvU6@`XYai`cQ@(wz;|cn%y%ApX6D}6QmG@I3ba>&a;$l^TCKo63^sw@NV}i# z-hs#Ea(On=CZ9$k17HHQEAlarAFWi%tq=}|ac~2O_XCWB*Wee3kyVhkfn#7bsDf)$ z>n3e6Q8HdhM(D3C=3#*?TOc1M`l0cHm6mDFSr5fq<}>j(j?+y#&i!z{**L92nKlFyf1e|4q!mK(_4}Po$k`q$Y+NWIHsl>EXPh z5lSStj7Biga_zQ3*cMJGbdWYCi4EwlgF|2sh>jCY#A%ecVA!nxV+iCEU z1g-%8#9T$MW3LT=0z3zQ8HdvE6slIf5a2S9+)87jKL}ok;K^tDf?Zj(9H|1Q8|cF= zsicy8B_zAEjQM)M52p*90;52Qm{>wRKHu*{yy(a?zCN=Lx$yM^8~y5)E>OcpwP4Km zg13%$&h$-N3|hLNxj?B2F;@m-j`LLGrimBPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0bxA})R9Fe^ms>~`Q51$fYGP_3 zl9&_<5tP+Kln)X`MM4nyQ1noC!Kha$C@MmbE)U(_DyRqoi*8s+Sy0$Z5k-XtQ9)32 zeJBf!E@D~J_n&6T%sA>fbL`C@KKI&tueJ7^nZ4JHX=%e6z5}V}a zbU|w@7Hdy6XQX&8WC7d-uYS^LfRac_qXelLa=!Z*7e1Qy<$A=x~nQ!7hcUZI0UANx16odI-$NCudSf9fXcgUX& zTRG%_;s(stdqvi#y0B!6mAT1v7f^1Tb@K_P9+Gq#< zHEu9|Wzgitsrd-CFv64nf+o;X8w+i5&>MXn==EW*5EU}hO^oueV8+M6ap(a_hh+zh zl0R)VRJ!(AY-xE|uHG>mrpMhJ=aLQ5*U8unpWQjVn^bw{fnLCh*$evgkW^$<(~3Mf z_GtoDX^gfZ-gBJQ<`dfDWEa#HbYLzY_JA#n>62aP#E{s_uBTm)N{mz!^!4>|m=p4WB@7^O+tupUK=+kQQlzR)^<26#E>59UL-2A7Cn6%YyU4K0fKe zv0xvc8PEaJz!wk|84ek~14DKP{sP;p?PfAAKv4hy002ovPDHLk FV1he*xikO( literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_tongue.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_tongue.png new file mode 100644 index 0000000000000000000000000000000000000000..01f4df165567d0d47ba5fa71db6a052f523e8420 GIT binary patch literal 1035 zcmV+m1oZofP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0bxA})R9Fe^mpy1yK@^3v{t$&# zjGaFLS5TWR5(^7K77I~HV-Z`i2zE&mFrARj!op}8A#FMf?F2E176CyeVv!~w(I`qP z6G0TSerI;>@^;?a_x8Q4m3!gr%)9s8GsFCEUtiC9Be1;@C>2Ss*XzUNT>`P5Z2r9?tQaG(*og!J&WFs>}eMdrj z9l4YX?g5!J^G_d1wq`Ukg*#(CmIjcPY|;E3l_Y34$u$4Dr>R{d((;-VId&gp+uCC$ zj&Cp6ZQq@i%2BTIscTcnmd%%1LL7GV#7Wj89#=&yEBg zu;~VQ8pvitCcY8y8?1n9pxI&L%I9O^h&y62EAi=^l1-bhZ3$_?Q90m}NW`XmT*Zr! zBVQyw6~^^VT!*J@A&e*O9^Fl{l|~W!-H3R~k-Al*zVGG?O4GKsf^g)MUT?U*a~(w7 zu8MyEeD(1Ml(8KsA5cst?m&W0*+pq9jK#horgdnJ_$s&%OAH+1c`CE15ZO=VC#dqQcAl66?U0iVDzhW?M(_$MjusE%!c_uw^H z1>$Z3O~oKM0nP$j(3|ME4Sf5JXy_2%{Xo-s3LFHQs$0P92bD8kx7g+ClVi^hgmqD>F*PEKomD<}vJtMo zqICBdW%1{S7p)+&?uBP0D8G!l-9=d)(zX|0o!Q<4%?s5KialZR-3PMF4#DZp6ILCP zAy@-8QhKmyQQicy;|*5pFaFy=3wsAL^`002ovPDHLk FV1iMjzX$*T literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_vacation.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_vacation.png new file mode 100644 index 0000000000000000000000000000000000000000..6c6283b078fd6cbd9d6aa890cbd84a1ca463c00a GIT binary patch literal 1127 zcmV-t1ep7YP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0(Md!>R9Fe^m{~|vQ5eT(TB&HU zjnYzjXru5UA_%g2QUfWUf}-*zq=yzLho!)ozuPNo^z&9=)V#_fpFsH_*T#JMp8Q#`anxK z9DW<$tCwq-!~!@1jS#B`RFuNRUY9}bEn}8{x0a>D-$E}PUryX z{ZHfn{mkF}Fjxa)vm@nptaKU1_2{HXxJQ{$D{O>kpx3nuZh&+TrrW^sp$;V3G1iun zCDCGKL?1w}Yyn86N{sCTCGZW@XO<0!KNK#2q*p!2+LE#)=nG9Ctxyu|HWg5go0M`c zv_UguSR4K@&}5{;R-cq5!4f}>=UuS`lq=yY#QkfjD*~w&I=2w~N$?J&e9P5sORzp| zsn~+?U&2i*$6DGBf>Z>Vun!)CsU$WgaG4CZBU#+V`jNWI*d)}Af<>?zw3gn2Jr!K< z1(ZSZi<{s#AoaBg;A@?nRv9}G)`GhYP>j+kN|PVXCK>39fX^l6^(S9q_k*>9}Jt}H8eyG7NkJXaggpnT9B9^ zeaNLNa@@@`VJrbzpbLCEOiI+5_B5Ce`ZXIR>arjQqK+WS`ao1a1rn}dKOvp;HA&?* z0{&#s*L48=y$hQQ`f(`f5?A2#*Oz5_g)>KOSmkN42CRNcjkmZiEgjZJ0=8HO$|J$n zR0aMz&}Xd)?S(|R6=m6a?b@u57A?fa3?t3hH8>dT4Cw(1jWZe#wM?(#m z^hyiW2b%|)l&Jy7-+QpjKz&WyEiV;?FxASkzki2LZ-NI>%me-J$9eXYht^EnH2k^n t0V-+x=(Ooa!+fZt{-V|YxBtWw_yIl|_41`Qj$!}+002ovPDHLkV1nIH_b~tf literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_what.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_what.png new file mode 100644 index 0000000000000000000000000000000000000000..bdca1b7e757f34057f94e2059406f9837d97c3d3 GIT binary patch literal 1237 zcmV;`1SPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz1KS@MER9Fe^mrbZuRTzfvxhm#Q zQe6l!F*OW@67Il3sa%M_BEm3{kU$F2kC>;Ye-g_ng8ydXP>o>$9>j5`<|Ok!WW*i*8bM_eQVvd*U!FPUH5f=2L9a))CLot zWmzwAufS}0490;v3;l2qzNpn|$0+|hF_8Ii0tPC5=il=Yk#rIqZW_fI>YLz2coIej ztZTDPpD1G|-IIZls1MGA>W9TJq$;^S!PgjNj=rk6w(TZ>>!5bQgKYy6jmCsniagig z21T&1DbCD#>fPX9Jpp>b_7RCOw3zTSb^|DLcK-SZifhK1F<}p^gX8cw{0yJNvvCB} zYv6!qz-*WXkAm@HE_FD@45%c)-K2c~PWf2)7S6&pcpo;yA@DDL#>A9w!D)!PM&%oL z8-{_o;+h)x?jtB}?Zu&^sn~YH(_rGI;A?vbo`dnh?`7&M;Z0ZqAHsI{9;O8!H-$Rk zbER;!BjvVj*-h9!0Cf>YrV?U*9vs-HVmmh1p}Ca@YyiG5GrTK}0^^uas^ zt^}Vo#de=*^PEyEi|yS-1J7OuYInV8`Hk1XWm?X(wAQbY2ZH^nM7yS#JNDIZ8``Md zsdzW3AL~WS??+hvfUmf#98^(1VfYPt;2@+FbH~0?K6M+@cqyMuu7h%~_ASIufd!Df zys?i4b*Y#sHA6+8$efckLolzs=C4F{4Rl$0)7PwnB+KbF`!I~c}$%0i%GFLdoJL(X3kTu98B37@;XpMps`kR%blM%h`%u1pfm42*N2Px zC728Oha2S)Sjf6LMcKJX{vN2wWzn=v&pq1z_~kk9Pt`V^dDr;9y+($m{ID+qbq@SO z5YI1T+!WPcgQ>)2HWGSCstd3dUIp)Xr#{-!DGq*FVcy#`0&7BtJt)_;>` zcAB%wzjPNh2hy?sv5p0gfva$u1$v$G|F3@lP1l5mlBa)k00000NkvXXu0mjf&l^G9 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_work.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_work.png new file mode 100644 index 0000000000000000000000000000000000000000..df3ee4b8e6707242fe5dfc4cc45c5a6750756347 GIT binary patch literal 576 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*(y&L$B+ol zx6^$64jTxx&gPmbn|ivhwpD=rL4IpUA-e^u4C9TWrg;t43f~%9EEuFC4ma6zp86iu zFL**R@6`&&Qy%L#zA=CAd(87y*y_$@%$G|Qv?tri@L50k>R_(^f8x*EI;ZayU%TuR z>>(}FlpY}RsN?p$Bei)#Mt7JCSnLjpRxmA$NGKAO*?n}fK;|mTcUzd_4zSU*_!T>$O8J?1^6cX>k7r1FT}Uo{p_;+R#|N0^KbVXk+Y|z zTezZ1R(lDp;`#hZZei29$h%C;?0P4YpWcGawuU6-InK!<81d2URS3j3^P6Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0C`m*?R9Fe^mR*QVQ547TF&{q0 z$Hum5F;1I}Uvo{KFga_cVUjzz+(@ukTMd5eamds{E zu^PBoEFNtJ>39xZuvZ7gp9j{y@i0N-sauNF!yQ{0UsmEOG()YcII$xz0AgJ(op(P) zYN1!E8SBAcpEZ7QFzBx`EMJ|Cg`P<~nN^RuNfEyqyJlnev;+V=5=?A`Sd}B89>R^#gFT3cCBLMOTMqx#_sgiZsVWgFQA$r~o3sUUlX+S-J%Lt&DZ!(C0Ly$}+N z^??H0OflJML%+^d51s7H=U@obp5aV(<#_c|;GkBcz2%dHPR_QsCQn>h<&~~{VzS4{ ztMLgAyL9puoB*{>r?416xDe#UkJ_=gT*RS&!fK=Ei(TSDD|Gm4=&y;yZu6Y9Z%r~e zcFbIKLj6YQvy=c>+;w>QW!!>9! zp;#B~QrH7ioI-+)p!OTbXO*1wG6^sVdu+63QnZpHOz4a*5$$Vm-g(lDL%n_Q22Oe9 zBb);Rpmy9V(L+SRbs!f!wIv>Dg;V*gX3)y+yV)x-K}4N)Q}+XYT|&xm7@=IGUPh8P zcqPY(sHYpE+{JgtNJ~Q`$U!NmwVD)Z0k89|wBm3N`O9E|D<0cV;tu!<)_Qr6y(hY< zhH4R)Eu<43!KP5Kk_U>d208ho)<;Jh90fUGM>aV8nIQKewZ2N`P?Aek`SLD7{JeTv#oIwtCX`0}Mbg_AI{dK!1Nsa{Y9kh^d*$em{~%!LjP g)ppu(`@dG;53T%3Ap)nUTmS$707*qoM6N<$f>(;DH2?qr literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_blocked.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_blocked.png new file mode 100644 index 0000000000000000000000000000000000000000..fa005bc31c9b843afa6dc71f97dc7dad81a180a0 GIT binary patch literal 563 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*<4Q-$B+ol zx8WQ84jTyM3J7s4#|G3d_W8s3vwhP=`3LH^`WedV7G$@!9I>CWGD$Of_W_}Mjk-I( z$v%0rW0Q-Ym8#wS-PJo|a?%Z6EM4yq#kwk@;9 zdaB{zeV2(&3a@5PxqhVJr&*v+tv{p4q= zB`kG|%wVl+pI0_>Zs*qKw`bxn?&P{yHeoi;$Hg*JviT--T4LoC~C+Cwb&J5HPOQu}Ow(%Yolci6Q{r6(wc k9a~=#eQ59f{VNZM3#~l#`+8mMMo@%#y85}Sb4q9e05tC4WdHyG literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_calls.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_calls.png new file mode 100644 index 0000000000000000000000000000000000000000..43f3b8a2105311fcd5023bbe036d6e010196ef9a GIT binary patch literal 604 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*)dNS$B+ol zx6`b>nH@!1Hzz$@9JVG$M?_}}w^EXRSE!VJj*aX*#n}^m$?ueOk_QG=4%3Ft?F3M?}r+Z2{=W$Ex`>ojiZs!Pijb?j<|fnWuX@ zqYD>pd3&b&^o)*)nhWZF)=RDzpR4`CO@O)k%zoyN_xsKM+P+(|cne=~_K_n6EKiz5 zZ5pbdo!*rs)oJF)z2fbxgKJVASTe5*F}k`x(I%#6b{|*M>Id8_e0}CMFOxF)vYpFR zB}rwHmyMLru0y}ooFnzz-bUSP4)4%f(LAkel4Zu3Y?U)noXsl*-U!WPpU(OCjp^gg5-rpU+&x#A^SbVb#13U(SXf2v1ND a{lRV>bz)UhyEG^rFnGH9xvX|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`S)!+lV@L$& z+v)yZ&V~ZVelK~!xI|R^k(Wqy$FB9}pZMk-YCWCzXY-3g+#({HA}-w`g-h85RR1w) zZc(f>p0Lj~kxBlu(afJ|Kcr?Yxw^4kqC4_fG$5|d`_&Ifx@cl389kqwbjHaaKb?kQ%Jjugp!6vWxLGrfl>Uk&l zo=6#gdC4NzSm`k%;k(cl&+B2AqF4gwKf~pWzYRZC3pBP1uU+eN{q6;> z$}A`6t)|kqomZxr*kyYJofI)@RbgFHdfWMR(2HoLpmp6gx8}cziwxk}J((%w^_;b_ z57sYHJsh8ZR6F;r|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM315>7_i(^Ox z=i6y}y<;2&4!jR>^7zoaz)&kIho{2DXII1C1&f?IeloLc^hsCUC=?W(A-rbN0x``a zN~Ks+uz?)6;jpoeIP&E z!RSfdrkgqJKi_`fnRh@_#@TA7Pu_yZ;b!BZn^@cFee{xOYjh&xx`%d3A17Up z+Hy?8jA6Ne(j{!2WpGQbdciiqR>lLr}->^9udx8Ix#nwN^D!Aue#fzBJS7Eay6=@{))sMZu``EtIa%sJviZ% zyV%wXyuTAp&nk@E?|Dt!+IZR5@ZH?^m4D~4AKMbQ<@GbZxjPS<$ZfpW8g)57CHmhP z)53E~>8C9fo6d30(1o zj;flw-P^6o<-r_2y{2i!H=XY~$FJSPyK+fh{3qML-beN?lKj~pI>X?W)QJ`w`J(W| z5Bb(Bb|@Fj`P=SxM(rENiFB8LZKtm9;$7v?y=P(O5606zPnO@~xO8V~4VRyT-K6^q t_)o>Uezb2BTT$|Mdd*VKKi7qKFqUk1{_gLK^v|Hg=jrO_vd$@?2>{1eODF&U literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_music.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_music.png new file mode 100644 index 0000000000000000000000000000000000000000..3ab045237851128d6fd176cc63d009d69f032701 GIT binary patch literal 635 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*;7v!$B+ol zx6}7}F*}O1ZeGOlnMKLYQD9Bd^mFI-G)G9*u*e@!;!jANYRC9`%gZarjzzI-+_2S) z<@)hvQNAX|0_Mz~7r&VJ-hLw2%)DWJ$-SR7 z%>15{bgpd9vNted2>!tNkL#uIxy;l&f%lD;9K0uAPR-&us2I^^b@GF1c|@0Hi<{)b z8_zUOP5HAbg1zlex6?9#Nw&h9ec1H(_q!O^_)mPYxl#PXyaVPOos}1K7V50u=0B&y z;E3{vSCc0^6gR%HiWgx~N=I{Q^u zJG{DGdTp|N$b!+`bSKNn70)WxK`Zc6I1SHXwYg$V|K)%;|mdK II;Vst0Ki26MgRZ+ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_photos.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_photos.png new file mode 100644 index 0000000000000000000000000000000000000000..1d308d57d6c0e6db27b576b9a57f601bfec4208f GIT binary patch literal 556 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*)&fV$B+ol zx6=*1k2nal3Sac&c5Hd=a>UJL%^%LDwQJ|byj;KW+Nu2oOT)ODws!RPUXP535!wBt zH?2SN&fU{$g3Rv@B$uZ@+dJ1rQGBzGYmtKGhvR%xQfD?R?qC%bkUk{1F5}5sIrc`z z9W1e}8N5=wtbuc07D;>#SS0ygL}lZT?MW|+GtY%9)XS{cs$02r@3q9UEz#n)@4a~_ zUO7*HXV$_-FY$$|Wtc7B^Zh-!YnQc`I$NLXuPn52O zet2}bQ)-#em(05XH(1L1+LUVrzdF005BK_h^;UJuy%YH%%%}O^Z+>N6${D;r!1nUm z)#fv18@)Z-sTO#Pm30Rj_pY>WPo^J~h)8_3HN5+8?T)0MAIntB8JgycT>0K8x|Q9q zS8TVAy~X;OQIkdg?Y#CSv*n(1tI|pSw-Iw^=g5nAX0I-pb~al5cft9>^%!)4Q~Lo3Rt~+=B+poRxQ1UeM9JRoE!~_gBl*kCLnG<$oSKe`;mjAL*1fuWVrW cT{zU}A8GgL-_-i%|Dc%iboFyt=akR{03D9tl>h($ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_received.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_received.png new file mode 100644 index 0000000000000000000000000000000000000000..68caa3dd4c86b5f2273a24085ecf6d7e041770e8 GIT binary patch literal 465 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`nYE{jV@L$& z+iAX8OpXGra}^A=H=A@+Fui}^8nd%>rmx?G*rG0-J2RzUh#rxC!5G7lbjN33lL=46 zw<(u>9ac28=la4?i>9 z>t6I@<&#VO9Xtm(??@Sap0uy=5W`1_H;txC%GU%u^;R@svOer~$@tWAnM5a#b@{@P zURli?uK$FZ&L=F@**Ybv&XrmDkgNf_;*&duJ#o33>%w|i#RU4U@BhXh_x_T_tK43h zjyTEdA30vL@JMfr=gal1EnNHj^d!Z@PQeqbml?j?wO{`4je^5bQ#R)<%y%j0ZQW}4 kFe-!f{7&X~2kI?9a61Q1FHFq-83hVXPgg&ebxsLQ0Me4L82|tP literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_sent.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_sent.png new file mode 100644 index 0000000000000000000000000000000000000000..fbddd3a92a1de78d472291a316b54a8937ecdf6b GIT binary patch literal 501 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`S-hudS-!j;>qfA zyZO0YcRUx{zJGhJ@AxH4&qrN+F6^uLL|i{Qh4{-&Xq=!~5HQ2e;ZUuLOUePk3*Eop z#9e&M*PMR9Ra?{bS(>evrw~uf6qXs=y3e^LeiDe7CBjj8jn7JuEvYM#+c{SA+ZKJU zCCLxo%+j0l{6z1rl9!UqCfk}Ao_(==e8IgZyl~bs@d?7)T@9<^yI5a+y0rQFx09=P zwLj80ky=#p;=bhQW$A3$ys7-*St0C`pl%*b+^6?aNPGf98)aY@`) U_4|x(EkHr;>FVdQ&MBb@0MRwJQvd(} literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_videos.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_videos.png new file mode 100644 index 0000000000000000000000000000000000000000..5443cb1e260d20603345ef011778d7ff26565325 GIT binary patch literal 506 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`S&FBNV@L$& z+i82foE-&PH)kbww6-QFXCzN_+Hz^SfX-LW8Ya)@nGcB8=f&AYp^ciiQXDN8G><5O3h9p>#T8o(OD7@FY6Xe{2jKka&XpnvQJA zf0HVhwjZ0}6sITayo_6I!OFWAH^?a+xU0H@k$s_5{=7E9h$~e^8qK#B#7q8A%3fsH zdw=S)W$!jv&3PvKL8Cn+d(Qr6GUso8d=eBay-q;L{fF{~w?!K_zw4HIy>@T2&+J8v z9!kmVX{ty5ByY$TUmBI?)O#Z0(oW8$T*j+|os2b^{PJ4un5vs!-f5A$@kjE`yPYRo zS8Ul`ky3BrckswDO)=#!(~J}XKEL}kq3W1DOY-#S7f-^sso$S>WXFPcE_$lz2SjHu zWq;qKCUtoO*Sdq^9$Uk?&L=hRywChR;c~e6-{xmh8Qb!MVsj53H!iiUTE(=gL2Cim bpUF)1JEa!%w|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*-K9s$B+ol zw_%#H$QGXstjb%Eh6!C*!hb1@XjYu@N z=%SCdH+YNXt9ReL+oD^zceHkao=GKX8m<{ zDNoxm<^w6sG3|#$bQ_`#C5v_EFAS^c3Mgh-v+RnI`?*8UtOG7DoXoAR_SpJ@n~$bk z!NVh~YS_Ct|AsA)II-<~Wq^28k{JC`4- zKU9uX1u{O#a)@3yZNmG`s;t!Cn_3*=IrbgQcb`3L-AUGn#cT5)>4~)8S{iobC!-AW zYc;`VBJDA`;%fVPtoMFca3cK?*A3yL=Rdd~(EYILQMAR+r4<}Gt0nrSA29I$+TD>_ zY#1VG!Mu+#TzR_b)114(s}%3CxHbH-ERZyMcH-l&ET7DLzlD*a53&<^G8UhYxEk~G zxTJ~w#mg7Y-#YhgS=q(^A}TMt3;Oi7U1E?Em9pHX7bPm~apwU4CHWtgAHz3#fg<12 L)z4*}Q$iB}bQS-h literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_datausage.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_datausage.png new file mode 100644 index 0000000000000000000000000000000000000000..d083c94fb782dba6b8f94555edf7e1dbecb67c6d GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKNxdhhAt7!twx zHuNG_vjNYQhrbi-cc|N+>Hk>H_KrDBe}k8$*QKPl5-I_&Os_w&h?ZsJFFzn#!2U{x zL-CA+bX&`r;@H+>Z`N}N3MX4%PO{k?`K^m9Z>e1Cxu-}MU{ex2IV8~$|JYOdv_4<9lA=qx-wf&V$v^7t9Ao#NQp z!yoK}_e@6?=*-E$N>elAG7rF~%Go5GWNZd-YuhxANIt=aNQ^+iU8?GAboFyt I=akR{0Af^+H~;_u literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_devices.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_devices.png new file mode 100644 index 0000000000000000000000000000000000000000..553b5fe50500f34b9703a9cb5890f7d338ddb187 GIT binary patch literal 348 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKNxI_Bx(7!twx zcA6vCVFdx#WR4c07raGQ{1@YvnZH;zTV_q`rM#^D0Sh~RxC(CiaY(@E{!e4O7z>^# zB?Ts>4arRBc1jky?h#yjy1HWh&R-`qwyh0Td6k>Dz);;Ox-(8W-S(z~Devqo6M@6( zPD)2O3}VYYS|k{kZMH5+XA`ZuR;<)EeSV$FZ?9B)pAR}~Z{D=q6Tj_<^s?|*V)FNo zaF*05m3Mre`!D`OY>(mm2lIDbN$=?2u<-Hq?-qagFK?W_#?^tvWx|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`S(m4aV@L$& z+pvv(OpXFidBnDqsfcS!X-V5P%+r4${efR+%eGMI-W-zeK< ze@1lbgINa@Kd5}#IN_Gyg%Vr6+Kpz7TNUGfpJLemUC5&SHsiSl)db1nD59%-YfK+!Ot1RH z`cQDgdx!aV+?Mes>|LqtJ7?D6%i?qPpG=-#)t9l~CZNRDXLcFLzEoTlD&1jUZ0 LtDnm{r-UW|(*x4O literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_off.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_off.png new file mode 100644 index 0000000000000000000000000000000000000000..564806bb1a7cec4e5906462095c6d22076fd813a GIT binary patch literal 665 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM30~52Si(^Ox z=i6!a-pq~yM}?I&xRg4sEoyDz*w)m`(bU@e%T{NrsG^zKwmL@cjTa9oMRc@gtmH@% zooI3^LzzqQqxnNKp6R>qzPT$YVEkdm&6_vP&)>E;oc{Wj{BNe8CRMM${?d3o{UFN^ zHvR`n^Uv2mv`**HY|#C{dMHeB<0V5=lh@4QiK2p!liXb{R_I^(Gx4LM1yg?3I=4Mv zRxiphU|zKW;9=y>3evJI6aZcRh1G`Y_=9OVfwDrfpomApK}SSYcY?diBd@UqwG0 zxpt>&UGC~T-U3SZ67S}ATP99?KTS2~^1n^fvZdoreU(+)&Y9-;`7G!4)?>vz$D8li z{^RVh=h#5m&g*WwF_LgWgZS-|F}p}{bT0&33p~Bx17+{QCnZB<*j|f z#9#M_z|L)Jvbc=Dfb85XD)}n&&k421k8{2>6i=ASIsL10#Qega#!OA2PL}GP=jY^1 ou6b*GZh~Ss-(<4!+f?yS8K7k0>FVdQ&MBb@0KR4wfdBvi literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_on.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_on.png new file mode 100644 index 0000000000000000000000000000000000000000..3b31d978f4606b15c8c57452633406ca7767d470 GIT binary patch literal 641 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*=tW1$B+ol zw^R3eF*}O1ZtkqtFiT3F>ZBTxIbZz)qt4r$HE)g_V*eoOqq=0IQH( zJ?Q-Uo=5TX0;WfAc%SQi_;uq*{NV*kJJ|JBPYm$5W8tgB%v7*avofKcOYgvHvD^N} z>V>?A%eFMSzfoVz_CZyFb^qr0zDG0Ho8&i~IQNK6AcmnoQ0R4H%)FD+%~^T=l|Hl= z+~Z!Ecs}P`bze-LbAh_APKW;7g}3LtsL^P%lO}xlK(=6d;MB|y;NxW zwYvR*q@|yvns_${&B9NC?Fv|h`uD0-Ril4Ibt*eIiUjn7vt z{$)-n!FSGhb-uVPqWo*cSJn$pn!8r+)3SGOx4*q*Wvh3<^^g~j-6s^jJF$0@4vVS9 z+O+~*{O6Cjnp_lXyjL3_qcQ(#PFJn}igTp_;{T63#r1#742ySs~^+BH&cG{N@#j`SZ1c=H?z%y2kf&%?HVqZ*Qinp0KddOAvli-TvrV<|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*(XmI$B+ol zx6{sQy97!cd+s;6f7Xmi{g-m4Ol93Tskd#@hQ#FL`{PVX{-fhMs2sSJ4T)do*@*J4#1|ntWV#>~5RN?uHz%KNnud z^j+&IQUAV^6+Y--X zgL@{gX&0>)>WX=)Db>;aL3T=aHHW#>r7d^^50$P>^vq zR&hc0ss-Y~>{pGHuaveG+4YIld}>@$x;|$nA8Wwtms3*rJ&bI>{DI|=@Q-5k54@jp VpRZ1c-@*h+1)i>cF6*2UngBWn3Gx5{ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_plus.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e13b41d0c8116918e559101e21a9475cb9632a GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKNxy6EZR7!tvm zoFKuvSkXX=2}m4qe(?YQe>R62{w`j&JJt^EXIPUYW_Yh`o}ppNuwuUSNuCt5Nd_N% zvMf3(Zg&J&zEW^%G?8*@aq5^jfhnPmZL020haPSANT#Px7Cf_Ix^#SDPRT3nfCM9D z<;ScgoGEsOe7o4MEa+I%$@HyuLGzRkFXc-zJ6PvuFD!C&n3Wai)>1n~lX2Nb(G6A1 zN0yy2VQX^~PhHHXB(ij|qD#L3)6@e74QJXqFHUC*)pf9`n6=@{*MBQ=!LC1Sz{0?u V|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`S-Gc+V@L$& z+v$6~m;(h`!zX6w)QDP(YAbRmacqlX`5$-K<-#TLje$CsB3ahdu)oz6jXwLU_soG^ zFV5-Q>}aWeXi%PZ&bItpil@i4rBh`*`2IMvf3k^Znf^dJ8ifQHLoUM?0KTXBUe~XKslJx;=ey&|d+` z6XBT?3`Lo5x@Yhw@BESSdw!Lo{Bx%@@0SGMyTI-htGj;k`&tzcyeG0!N=f$9=Ea4^o3w?t6!hmG wb^gHeMBn$WYWkBmfjFVdQ&MBb@0PsxE1poj5 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_storageusage.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_storageusage.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3959fda02096c6533b680f78f025d7f321b6de GIT binary patch literal 830 zcmV-E1Ht@>P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~s7XXYR9Fe^m(6PwK@i1vg9btT zj;K)(R3aE92SEaYH&KtlFYw^Sn+iejB8Y!Nz=Qq+N>Idu9`zCwK}94gE;%1R!Q1YtdiAR4-5GjowYIfS;6I!|v)SwegJ8F|x7eRtpXTP> zr_ny}066=}=74KtdtfnV583Q>`FUFrT>-ARF0x*Bjfh{8oO7?SS?YL|R)o623#S}d z54#5B4h8ZqWEvYCx1|+<)nMEy$~uOBM1_eR1rx$`?rSz(T9f2c*a7Z3C2xJpegM>C zLgYHZDew-c-6PNutBuAfI-^SXFTu)aktE=*1r4BfTB!Lh)l0w!QL(RKLw;p8OU)Xf zLroG}mSsmGkk10&KI3eQ&LPvo7NQ#GCuGJO2VbOe+q(#v>;J@5V zXH!yf4hfAO6Y|V@WS+Rtue}#t{|Rc;>-F)RUP&o5UO^o5$kwCZ^JllAfi?@NA$}Ei zREoRBuZ0F$E~NM3S8+c|@hb6y15FEQvG`S7ebgsaEObJjgtT7#Dz0ixs90#A=R)e| zX;>h!R^9JX_(uG!Yt6wl@NFQ=EFVGeAaJjgkz@smuKLrk9|fJs0y#u=X zzz^W;Tw3=C3zg$eN!F+M_5;lfW-)LK7)R}9q*Zzt#q+A_`Svv42e-g=@EF)tC1$0+ z^5CSXp8(%tT@vDUA^ZDhAlRgA5W(%h|4)`M$1G)p&n;#9CGioigZ)hg`SRBjWY>nW$7q)EK^V>rv~ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_lock3.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_lock3.png new file mode 100644 index 0000000000000000000000000000000000000000..e1fa596d0a6d92a3f4f026a5d419aa462e451bc2 GIT binary patch literal 404 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfU{quBj4DsN7 z8|2M($Us0>t3!MGrRp252Xpx^30ExC^Ui<7YSXA4+vV-J;{8>YLngk$!H!27+do%+ zPMc%mx$oqyZLxxr-?Lm4vS8w8{qXzU^EDUVMlJK}VFyo&zR0frKi{Eo`GU}* z;AgwIEH*t8T|ATj)a=VeH;=@GR~E9#*QrVORxsDEd(=Jg`nq!yo!4EBVP3<#@MJ%K zgoW8H$*s2UYK@b2Wh<+FPdSn&p0u^jmt2xv=LYe~&(yw!IrLQ;GFA@Ply8p9PAE;7$Zck)d3xbj)Ln7R1$ zhH~}m2i5A!%AU>tzyI#--71zdC#K%yjc5?RkX!PY<6fiwf@HUXs~wz93xD{(E863! z@NX9P`WdC>|IIm%xV|tnuPD#@+IL!5p?p1C(Kor}m#h~Sa(wG+h&gz`aAp;oxSx^o zcE(}@zsn_W3;qRNQIqig!?R@htpzKEjrPiF9Dkg>c4_0>%1!>e^}3U5t}pP};P*Et zpem|W`H`6o2Vcp{(yNvIVsDqgz~%VOdrVep iJ#33V<}RAFcuxGgtsDQ($vb!#6q=r{elF{r5}E+2y|7OJ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_premium_translate.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_premium_translate.png new file mode 100644 index 0000000000000000000000000000000000000000..17c47dd47e3e973c567b20a0374d8fb6844851e4 GIT binary patch literal 868 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31JgNA7srqY z&bQNdXNLp|9NR4A!z1-^;whz8g^mSblbkk8Tribig~O~{AuE8pd1`BzVJc6O;8%Hp zTo!Haqh>2Y6%uL`w7U3By81I>>f>!T`0Gj+e#4t6uZP!WNcfrw#mk-E8BzTp_R9Ai z6+Qd3M7Yi;ckVJga=!V>H|c}6rL%(ttes;c)$}&Fwbz$Uv;6!{sLoSbxV)(O1$J-Zu4+#r))n*$(;=oQ8{f<{}Wl7C^+;Kl#JZHfzl_K>t z?SKC)!`A9~&XJqEaAxj7nb@M-2azi(o8zsPD|~HW3wPQa|3h@@uOn?vaqoOm?S9Ts zV~;)jcOT=&wGP})YjCtzH+K(c|D`@5*4%N&wyYS(9JZX|ow_|={}^7D zopCN;ujrKh55qkr?PZdR4)2qGyjoAa>iF~GVix`#Y|kGozY`ICHPQEh_QCM!=BvVk zq?|X3-njdXHShLE!F@N&6KxpI{0ZIj{fZ1>o|JcwT5`^#>oWh~!rzg=6eA6FB8&*t7RFVHA<=}V3;AEulv zKfWdF*o-ZlHmv53XZdwLwKqi8`^;E!ZsyH^HENMPdfz&YSo`bl2wqoqY>!&@KjO`9 zo10c?tpe`?+Y`#V-Dd|p-aotR;-Wo{vv_W0eUQ$2Iq^M9mBXpLE30xX+Bewc+c$7W qx~#C~vuj)&`D(W5S?v$;@s0NUJOA5dN%UUPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0F-b&0R9Fekn9phyK@i5XqKTm3 zL2@t#69TT{O+^Tz7!?H3gWxmx0OsUn_v{mx+d__#H%LGfJ%)hbEfPdf!HWk)C8Fc+ zn{;hzXQyX7>u%hFFJ0aB)t~hAbocDo*oaB3-+Hnvo5J@rP%B7225i=9HR;0@il~DI zSO>jC9C7OduZp14pap(|y^4I~J3WxX2($=(052PKn&3LntQ`%It})rf@$#L{V&6sK zJOP${MD!JKCN-$I!H1?TiaC)QBj?Ehyl98WvMu!aJq2-O`2xi-QS9`hAp4nlPXD-z z-N1wsCL+%=M~G zoWLC~<6_g6VAAN~V6o$1qstfu;H-uS+q4T6yanvyNLDL&wt231aB!N+U3dO8JB*=& zX~uD+J}u*EOtu2|R2dge)A8~H`amG+)HZo(N}GQ4D&vK*C$!>7)`IU&uk)|ZmDg}E*nL4&_n5ozuYh+X+3JkF+ry^K?<^y; z;MK0BOY^xp3i8b8bdzWs;xkW<>7n3g(ZSE>%9n&aGGFP5Sdt-(`&^$CzpS8>vBW%v zNnnpTMr)75Jq9ke2f7uXE1wiAXwz}8I=!tD_!^zhK>O8X+YnLU%wl>2#J>}v`CPt+ zeDA2-7zug{n7l@*N0MkCx&Yn=@*mpEWn9L~H%5^$rW_rQLlQN*)-HjYUodp|&Y6Xc-Y+-+Xuu{fh%U^4jbLsE{LYglD_+!h87>pl z%G<5Bmw%zrruk0{&$x)WsJzf@<+NZuX%+Hx%IztJ+?Ji%Okb`XF2DX;bT7m64LP?B zW-U10Xe52^om+fm%#-^LT>lQRcVuc*iC#L$^xGoP=$+IpO%6Gw3zyer^50Es-^pL| z_Rxu5XZ0&59ZPKDA1Kc`oc=27;_8B#YXp3bByDUyJ*n%cXWqirZE9QH-%RFFZ$Dza z;qPOqgXLt+E>)SaWH8=Dj}Q1Jl|gle|Q{x|$trLXE!# z&wFLiA?lPao^Zq9jA+sd`@``MrntRJOHU0;cUL2}oP$XBWS5H{EM_vEKS*(v8;no0?rW{B~Tl z`Y>0SrH*EYO5*9LV?HYtZqLy?U-Riv$;Gox?`E&_xl%XJa<@uHU^UD7kL(XvRyiJS zSBR?Ua$m6fpZK08sSAc4QH!keCnQez7w|=?HuCVsdY$W%Q@2k@^q088y=z_l0UP&4 di+9L>;&+J?V9>sQWDY3tc)I$ztaD0e0s!&ZCN2N~ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_download_settings.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_download_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..2f3c231aee627b6b21f77e24d3ea537707f6299b GIT binary patch literal 508 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEX~u!F~o!S z?G#&YW=Dax%^5=0xlIcaQYR~gnSB#G*niHc$@M^(_3J5SV*eT@C{0jPU~&8?&$6Z^ zB68`)LtdS+JoC<<;JKq3=QE9kTehO&d0AOnS^j&oi9gKen+vcsHit&EZ}IQFA;Y!K zk^795Mf*n1$1ECK82Y1risd?l&)(Mr$yi1KiJGxeu4X|c_6!g!P?})Pg|RJEZEc6Isc%8 z@hqSB+MDuBX5On$@U4rznabr=z@EF};He{GZX2ZyUa$Pz`jpM3+rU7e&HF2Of= z0q0-{dSEL&f$#7I7N7Sqvd4UJ76OEu)PfCd9AC0a~PBnd(iv9 zo8qC4z)tWWC&8KThi5Pcn?sH_O&P9MZxtMC^)-4z@Os+QX&}B)xE^AodW^9NoQN_O z^V*jZd$MdL=KQZ_%i{IkrNEKIzl-)1%qISv^r4r3Xd$phaQsxP z!}jq+*>;!=u$GR8;Ah30cn0OLs!dS&W9O`Hz;W;q-GafGf$f>hfW>_yl`W5PZQ4L^ zC4O5zfW>`8pMF^6|fK9z%|$d3x8lVK)P)5i6d^MR3Q<; z5qJgLV7MqyK2QhZD(34VkZk4(+9*nHb~tN5+;k;o@7Y7rHy2T}Isq+Eco5_RZO{Ze zK(WPpf>WEO@2aIQ1Ibp;*^hr~;jgT_d2Mg997qdwhrDm>pdk zuN*qosrXINIe#Ak&5kQ=FKB1nIIqrPICI8hbmdU4RD1!uL=WbqZ-Z$!&QxZpy_p0z znK6ni)^bI@fa7KAJDQGd;YMf70>u~5^_Pryy0o33z2`|toGn#@?Uuom^I5Fr`m}-; z#AmSX0#?v3-8ipaVOVlT#VUt#bqk-uAJciplEEBPl~^O0zi6k7@4!&^R5})X{av(B z#GVS>%GILeW`|S$sR#vr_px(DY$dw>gL|%R>7me%e>kNs5G&BzGWcJnU(KJ@KL9K% V9n-*iQ&s=~002ovPDHLkV1lED;Hm%s diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_angry.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_angry.png new file mode 100644 index 0000000000000000000000000000000000000000..4917f47527ad6d41c249a9082436e533b0eb9efc GIT binary patch literal 618 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?24z0V~7Xu z)v0U!nH>d=zV}d_svyuYNo~m@3n85*k>GaryGs-w@-NsX6Jy(yDs`G5D2jr5D}zgbH}H>CV>Kb9xaCT})B zZ$W{i%L4XGYJM9(^{<{R(j->FzCA%c1Qk3YhXw`k-S?26sAN_{SKq;$)UuD;70*Uk1lsd%RP_*S3s+I1V( zJgc~`&viIY~cz*7xNG?t8PaOG;U{>-&aoAMM*rpY~4NaV|w#NBZZ1 zih~E^Zr|ZO724~vk9*a9!H)P~*$u`>U1y?u7Epm_Fl^>bP0l+XkK(7N^i literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_back.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_back.png new file mode 100644 index 0000000000000000000000000000000000000000..7b5a9f347891bde1a3dc4e7dc02df1841f5b57bc GIT binary patch literal 271 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUReHKOhIsHM zCrGd^R%GCA{Qv*IH}gj;1+&)9z}_~gI%$vpOiA9WBzcTD&VD!$c=({A!`XyH7yjS{ z4;411JLvEo@o)HHEFjE0k6HAmfsxTahp;m(XBJA&p5@qb`QqYf4|t?L_^;gUvxLq;(JxW464?`4_e|w} zqv_`?c@2cKWy;t^B%jv0fff3i9f1FbzU$ndbXs{?Y|FLRW%z-uc zj;JT{J*lvp{n2jUs-HhyE;*drD;_%g_q->Su2k8g6@PAB!zOXd3Dw6>FH&Jo6f(MUZ>Os$_lzc+IzcI)`2O#k z{3oR=sJpG>uRk{VdBXYmw|=bAezE@VtEc@h8`Ji)W<2Hh|8e!d{$2i@t;~1sMLrD# OMZc%3pUXO@geCxDzzJpm literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_busy.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_busy.png new file mode 100644 index 0000000000000000000000000000000000000000..2059e0b32d1a729db4a1a6e53e6020afe9285900 GIT binary patch literal 479 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%+u4wF~o!S z>QqC&!wv$jxl@{&xEQ*@JKDQh`C6_{7%DUg(=Jd4(z%b9?xt|+`g%;zTv2S z&?El!+@GJz)Az)MU#;I><-?eJ``iQF1Fj$DOPZI))*t(`gYltd#sO^)-}xJVrj$;~ z+Q1h5fg>z|@f?%gYhyL{cPsKjgbvF7VDK)ObbH~(2PaIQe^8omr!^yTLOw%1c z?~zY^R;Rt-D(9E*S9Xh*>v8;?^1Qm>-p@%NTYvJ(->LqwJ7%lg7vFcK9KP~5awm#? z)xNP|t$BfMZMD7RvsDYPtqXMBnf$6qC*YfNw`*N-=$&`pR6ho|-aM_hN~1jXJ9k(4 yqweoqoor0H~(9(C~5hGVF2;lDw0nc8eqK$ByFnb1XMoTYIW~me*7l`1!d|X0`)qRohv|&`+GleCj|Fp5TR zKm9`Q;i2nae(VkUIZH} zg@6xXX=^P$K`JFE*7gcErm;$p^*iHSne307jh4A^a_^jb?wQ$5$VAa1O5Q+R(vOlP zsiWBh8=&F!WAZC_isN|VxoQdH8aM+ZP!#G(Q>*08Kno1P2Y--32dtWjYR{=BjkGQ6 z|C$l%cw%2N={7Demshm0MQ_z(u`4U|Fx~rbAwTXLLtqTKD9k};u zBGz}n85yT6PCetObui89N0A>iw}7IPuPA0U<0kP4Rq1!O@0%xxk3-=M^|IIOl82^W zvI4_B>T~b{K7Wm`kTvrRF1*+DDC89wOtaNj@{pHJ{yYK13V651AF@2;g0000iXWMjup zcC2-GilvQWp{x{pQOcIQ!U`piJPPHNo9Fob?=>28A9E)wPW|Sb&i6mxW9FOV^Zj)* zyd1zZ%~JFghG8rdXA%dX25!hr<9}yNIt=^J0tX;_jykh8-hb?A@sde$>5OUTvv3J@ z&;_!qsPph-XT^|Xl@O1>H9SC(^7uJ8wlq#3a{|N$^nrGG2AXUIdWdy`Y&e2;a$9(v zV2QW{?`{Z(-~%S01A1WrlncW(NmoEn1}_kD3dvQ$7_7q#41ixcd>$;q z8GOG|=NuAhw}0AIe$1dtf|_!Wb=sxQZ_v!(E_eFgE=nb)<`CTl)Z6vW1+o~tvkN@N zd+00dHO>XX4CdMe9%F6r$zJ1JK*y}+J?dxjWYlP`DmYJAh^PrfAQ)~YS z8$fM%(rrg*LhuT4Pn;2N0)Cn`3i=qEQZZf&se5V?UB!Jk0bK^Ql~HOo@!pKd2SF#X z?1n(iO^r{cwlWUR>z?{T6c<1MDy=GFKQuz2mHWT`6PshEhHd}MkpKVy07*qoM6N<$ Eg3spdG5`Po diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_happy.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_happy.png new file mode 100644 index 0000000000000000000000000000000000000000..3011b2e419fdc4b2b3e8872ba0dea673242986e9 GIT binary patch literal 614 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?1HC@V~7Xu z)v0^+SOO&+(gX6G9X$dxSExj1xIX0!iMlGbr?Hkbe*^1BKCb))f;ZikFSzZbuJU-! z%xZPx&BycmAn42=!ByTBUpN`Ioy})IWUdbBJWf-@19%b2s@*bsAS0br!5SXmEW} z%Jgp%Huq<5VCiCxb7o5yI2xmRO{?nPr>)7ed)^A!gzDYT=?UXEtDP?T`-Yl({5_!< z>t$cAEADeX|6)61sq6h+C%4R(zbs%+)Pu-}o)$!uQ%+ zZOsi;Ki@4lzWk91-;G|CkM1^#z_?6|mMX~yO2|8@kfi8-G2 naG9Ur`_t$Dr<$?ddm`dv-X|#jG7h9h0l+P_#a@)ITRictSQ4j z_aL|Qtu}q{113ur^3QYD%3(G=k@bM5roB}9R>yyCDILE@ubon+>z1?EYv(j;Fv-5F z&0cZrx?+E{P0RmFf4qNeO8@8ZXZeGFj4L=c*&8G@>pjSxEZ6OSTS{4dcVeO8zIQvq zKia!Jv^lZvpzVnRD_YiU{h+YDGa`I|vq9$+?RbO4=Rd3fVQ~%9o^9 z8_RZ@oU`#we<)ki60vZ?oPXM1T4S3Z9r`sdN$PZ>T**{_hx|g;k^|Wn%2((4AC6IC zt0>^U=e%yO>WcEOmFt?c&l`LVIjH&LQRO}M>EHgJ_|IxMZ$e4=x|dTy3B}XZ&t;uc GLK6V~S{X3_ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_home.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_home.png new file mode 100644 index 0000000000000000000000000000000000000000..6c92c48fc3f8310253573868b458e817bea7575f GIT binary patch literal 627 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?5?MaV~7Xu z-Ko31m;(jcHoG14kop+L!6>M@ULi@@X~P94?vJb@I!$6tbJtFAl9u*NRTgBeWfx@? z%no$o$`x_k<02@$KfZkW-Lr49Pe#f z^L)kDg;ukcFXS*U;9q`0G)ltNVX@-wmx9^WUkH?3m)5Vr_xc0lXHzEsh8pHI zjeJV0|1+@YZs1Ry@!`v=*NbAAY*U1@mi^UIyU3|tz|CB0Ej8(iPZQrZcFy@N4)QSv zm%jb}gGJEn%F8VFhkSht59=mxW@6`R+SiqyC)8fcWtMQ;txjvfN#V=ZFWF_wuFfv6 z6)FxWVzzk0z2Nm_$Cf`%4#7%h>m;(BPUK&4Kk(=K_qkVgSpTtkvSn$-#MF?w1HZPo zhnGEiX8tavKGD=SA?vqC!HmiFH%=yo9d*)u#d5mj()%+#y){72C6+rcE$6y9?UrO& z#(D38>dw9$j`=({Z>e}*{dLCVpki0piNGC4qdtaS$tyXL8PJ<`xc69OMdJ#!+-p~U w9^dc7^+jp-!IIv4akDmdKI;Vst06$ywyZ`_I literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_like.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_like.png new file mode 100644 index 0000000000000000000000000000000000000000..e8c4789309069c9931f5d1043d44f43c2c15ea70 GIT binary patch literal 566 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=NhXV~7Xu z+sU@x%#H$W#Znsu4!Ug=c$33)E22Y_#Zf?Y?$lm|jtBM|HuT)!2r~;~^h|uJ-Zht_ z$uV2nk=vC!P$!8?_|fN6xi{7r9zVMIQe*qfxwC7Z=jEA;{VopEn{F%7V3^Tc!XVU= zYcNeYqjL>s(&`Ufo)Szq6I6HwCS`D@sdo4`=zM(4)=_eRS4P6{k;sW#zUvhG8|q%^ z-Em$ns2JC%y*clMvOv4Z9_LG9iM4#M%k&J=npv(t;EQ{}+hy=PPi=ZT(~5VJC5x8b z-L+$KM1n2<=?@&;8y;8QW4pJNQ>eD?(&5)8xtErB{GB#`eVNUfL-S4w%|AFPlD#s^ zxFG4e=}qpW+Q5USME}m2x=Q-qr!7SSAur7W&TZSk>vp3ik(wRg*_e}6%7=IQF^vd$@?2>_}M)+7J` literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_love.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_love.png new file mode 100644 index 0000000000000000000000000000000000000000..de4e490c910e4ac91f0bb2b734f54194640314b1 GIT binary patch literal 568 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>}snV~7Xu z+bOpCEP*0z=@U4-Rk9;nx?DKQUTSXGdaM7!>n*DnJ!D_8MQfJnA+HGn7lkgr{q;sA z$LUz{q`N2Q&fb|e&1tiGWzl)d_to#tytyNLI_pUNf2M6O*=)|wc8_lI-_aO*dzYZPXsLOGloIEl7Kna8XgtaqIUf#ew zRcq3Bt*U9iM89S4y&!s6#^Xr|v#s>DMDI@mw(jvsVb}ji70PDZ?;+x|A4P>%JDZrzJ*0; zmwu!@IP>DTiu)JdYdvbs2Ylq7sGO`nA|ny@ka^kJbqkuznTuM&o4h<)J^i|v^-d)J zm#EnFP>%0l#UZBI2|fpPW1P|*LbxtIV2XJWxa7r@#zc*SoGM>9t8yPS%=s%A+aGFd z!RBAU^3V0e?S%}VJZJW7oq6&IoA3vY;};k?3mnYO&v^Fg)#i&9C$3*%tz7siq<(kt pU%nd!0%i%qZ6$jH|Nj#I!4?wIGkO0_iCdsp^K|udS?83{1ONq<;g0|S literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_neutral.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_neutral.png new file mode 100644 index 0000000000000000000000000000000000000000..146e446e52300819c23c86338393c6a68b383ad0 GIT binary patch literal 567 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfY@w%%V~7Xu z)v0^Em>or0%S|J0-io-vs&Z6G<3_ZHoO6!Or6;_1{A#$^o96l_=BiF|7tmhodiK}c zuYNP`o;{M1=%_#E%$?%%dpCcct@88zv~@;}i!`cUuq9moa(>HY6JPtY`PTz>@XJ)N zmI^PAsDJxPWvK$Y`~%LOgA6&+SHzdkFuAmDi&SUJ1F=2Lf;T#97bY#67-qSjzsVzh zam(b0hgSM)pFa5-anyZ@>Gdh@Qx9P(OZPGzpBLP{zBim#_Vp^qG>2uM?acppo)kOUsQ&SL@9xiYqAcd>MT&h& zl`o2Dv*=0`$eSzqLgI8=V((IBlNN6dE^{^x^Wf|8+rD4k^6Tr)ePKd*$EHlme;~4A zz3El8dkwxnxpUac56&*hH+;IvZKnRZqR$#H9`rf5UE-;4|7Xcz&r+Tj|3&7O_?D<% z_YV#AZnsTb?#7w$o>Z{R_#F~sX21Jbz@FR3&!t_wTP*8$;@gpnuYO(kos;zOcyH3w oU=cC?-y$!c=^M*DIsa`x<0?!3O}DSz7X?L{r>mdKI;Vst0DJD^lK=n! literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_omg.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_omg.png new file mode 100644 index 0000000000000000000000000000000000000000..17d6835bd4e4dce376baf829d626a8568eeab455 GIT binary patch literal 642 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?2V_3V~7Xu z)v5cvm>mV$i=`GX=#7v(qQ|m$nQ!W3r$?J_{NP~RYGU@%mL>iG`-k()D>$SCqdVtb zTO_bQepB(C*mpZL1WO(im!;Pk&%S%xx_IaRyn7nbFTPe)mWXOt)r#N$X!HK^+4^T0 zF--Dtig{g{;lIktyKFKJvEMn!7m{#p;l`v>p2}}MmQS24;P*gwTcXliajoYjmsY7& z3%dL=)mm|wN9T}~&n+jZ-7|_Vd90qbEK|sqY3|N#YvT8@9KX=29kE@hH`ZsTvPM%@ z$n1YU9={e8$2M?VG#H(UF8Y1jj+RH9Boi;DhUOdd)!x}6Yc!;I9FPoWb zLDbg^Tl=IAYMm&#|NB@3_gkl%NzX)!cP@}DzN;5`wWLw~#*5`Uy2MiQSaZ8)s$Vbr z^@0DA=`>TH=~b+AA4vY^NDmYE^juHfciYBS7X(woT}8iakY#rlx#!6KQ#!}(G@EhP z@>ph5O_j`;wN)#wZwSn|ZnCGKuYx!3fY0No9n8ghufDtPG^srY0qlhfb<0 zaVfayx1hsxT3jkB8%(Nh}ysZ+KcV@-n$+=x{%p^-s{S9mFFwZ&7QnDQhD;p zH!X`Nm5&ty2-cvop-mn_S((PNlPX#2;|p)xO0Bb zTHc-m@foFtU!*U*e&ga9B>JaGFN2l$yC~zY=oziSovzoo4J=vNr?l6wsju0`9;>|j z^VclbM?Pk|x3Wra>~~(c_49?Vtm_r-|BAY>-a$Z9tZc#-{(lX9FBe?hue{$u|A~{X zj`Qx=2V%d>HTbW0Z}nWWL0Ep#Yo)96wALy4Cvt4zyc~FaYiyMcYOcYYD?p;HxgIW^&A4+ z7sc)}-q&x(zDqo|$ns9J{DQ@^n#?~)pSi9kw%vNS?<1ZkQPtABiO|BQNu8Xvex$?%~$(!ST&Wv-4H!5&UyYO{~ zU6a@=manyJRu1KpnhalVY);@@A$tC>Y(!I*y<~KG0cXj-Uy6DMn4c=RC!S@!a(~yE zwHsvbMeo+!azgM=@&a=se%^r0w=|Ec-Hu0cyqectq)>j4 z;lc!`ck!0z ftLz{Czx#WBQ# z_v+OBUNV6q?d3FXMn)?;+-_4yVTh7Z-_272(JInpW&(7~H-*&a?{j}as43+cx7e_bnJN}>i zF?(8Sf8xJ-=HA;ETJHy#CO^BS|IROvP4)-(^$pD22BH_t)BJjGO}yvktvKg^{EfDa z%dAbrO|sTX)(N`Y>t$V?nfz?>2ALUao`iKqU-o=#D&P42j{7~o$!EeJu)AE2Uzt%8 zl|B1^+Rp!wX) zT0)z1Qs>SEfz?ch?aQudw>WRO@c8|sozAoDu4lPt&%3igyvTRggOBTH85WoshHY;uPT)3dObwSePpjyVYHNxDEOw*Lu=BG%j5AjLcB)l87E!F`?=&Gk z`A}Z$L#_Or6EDMRRc9-FzoRNYMJ8C{S<9VY#)=B;@3P-+yK*+w@5I^T#~#dKEpt=n zJ#dfRc7sIam&yWOKIP{fZx2Qv-c~pLi}%~ltObT8qWfoOtWH>&&{p{RMl|R0taYYq zLdDYVGJ9!%O)x(gb!z3|wM{#x9N*SEb?*sr?@pJ}C)?}}e|_Tl<+W4+{{y$$NlT)i zd<_q4JN#k#qI=!K1^k!AUp21&R(qy*tJ_kK71mFTYx*BZykS{!dTy^)kNuM?@5P=h zxU%d<`GXZA9g55KKfRd0ePts{?T(Cs+Y2PQj|Te1C;9KoV4Hk}^?t3E-{Y38%17(J zZ{%KGAQb*+_mi1_?iA0}>pe8jlP~A&suM3)*Wb|yd;54x-NN7}<^PPjCI4;u#P;`y VAu~(Eu~ncL^>p=fS?83{1OOTH{EPqq literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sleep.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sleep.png new file mode 100644 index 0000000000000000000000000000000000000000..8a58a9671ce7363111eb0432faa34af87bde267e GIT binary patch literal 515 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEZ5V;F~o!S z?G#6ECP#_3SWST?-AXN-rEB!$TsV|Cl{kW4JlnYV`?|ZI9_W8~!q3s9#9>u>A-aTX z56i>_l^iUpD;GpW%@=Gci?yuMdrr!nd9!@0X76+S=RUKX-_W`#UV!^g{^1hl zBa-or7lW(cu^i^Gag^svkQSQf6w7!>IK#JMnf@WI8w%UK=f;^Y|0jMoSfy+`dt^sp zWbT}!uhr{aavvq|Zsw^uSZTm6F1pO~#UW;w7_ZvphrCj!R4GiuuOk_4RHn>Cz$U6c%iIuDu) zbhmhDu{lLwe}Dhp?K#DFXM2awdvg8roabNnY+1hX#(tAxroP82irnHKxDu7-CyC7F zc_sQ?np5U*83*Ty!@PSOCzK?~w7F_HtI74p8?tqWF_stbtbDNIeb~`MoEqi@>RWZ@ z+U`UxSI=H}sGmuwZ&sXR^*POT=dQ_ZKcrt= zTEm@sdw0RL69u9-pM1VKb+r_4W_HHIQ!;w7b=Jo}EHrq@6Z~P(PDSRnxZwIr2~$r@ z36F`ql)0(x)&A9TKYcrM95yl=AG}cfqS@q>!M3I{Q|@UlW*ZjW<#fHg;wsvU#dUwHFYqp&kT87_b1nBg#R!jUw>Lei3>7I`z||knpgiG) z=SG%jzOH2#_cOn)KC?<|!Ra^cxdjWvRjz+s_|G#@cJ{p`O_|$Env~{qB|UTO)j3$g z#eX5y@(ky>6UX~zq^_u_e32RO(dfnY#FP2+UuSMge;{j?$Rc*X5 zy5$3xL#}TUx!E<_&*p8sz0NnI_j~%8q47soaDHum#(^j0ad9epTV_lQB)!$57(f0n2h zJg-+66`a_Y1vy!jI1{JBr{GuWBB3pRIkN}m(m*i(5YAUj}TA(PpQ>w-D1Nk=4=R3xLF zZavojSsd!6#5n&We{}_a^2gOyyZN^M{O~{~eqoqMkiUU+@`aDT+pa6RE@P+^cPrp} z`&;^nB-08m)6)|7E1Iettb8lE3f49h zmMnky`s~}bdynqFaM`rKY}&qiUvyT4{#G;nFHrN&n^iV6Y3qzewX4@&ex4|45|+Q^ zk=44-1+zczvpX2^=Y#l@Hjx(20O{uP3-bpp6Oea3f%p+YF~Kb z+`*Zm{6*u+{hT(r2ZB`(OxiA-KWI^+BOaLZWYI1o1J2wF;$H=-4%|xD-PL_;h1wSF rv_&NuMRULUmOQwYzvr$MzeyeA++X!GGoIZM1Emd5S3j3^P6nl#Ui)i|?va^2G?UrovGwVs#Gd_C2@(LtE|YDDfYbH#;Bv$At_USxXI<{q80 z`0quj=~>$UKD&HYU9dQ!#pw9^%ahtJK0hL+aLZ#`O;=-)QCRRX9iia$J06^Ac6n|q zbnWRZa~|`#lfO>;dBs4e#wvDF&65(gb56QP0>9M6{#f^r=a|j^89zl{fBIu}Y*N!_ zSLLF__(2K_l zPEEEy*|}cWlqq;Y;acI#f0smkE%-WP-h>%8%hZ3&sY$RoY+GZs{H5cU{^M7&Ku0)^5!CIy<#o6~lZ@r1P&P175(HplygnrAdDNnqebtiP=s?ykn8kILw zKYDJeQ+#cEp?8&f{=ZGZ!dzQA?;VM~9{R>}d*jis?e`tBuW!vxlFqadtzi5c^4WmT zdcm=-rSW-no2$%xtr8?lX5Kx-_~q*ApY|K|4Hf287^HkF1f>v9S3j3^P6I0IFL^QUS|YFi{{!yzSmNWq1P|DtO^fJjfkm2M8tm!2(7E1a)) zsaTf;9ElO%CBarXL4YOvV2IL(ziX#_{VhFjY2w|;vOvMA2b<3ufBrN7zwz%g#>R$* z&tw18)pM;=dU$1BYs$(O$C;R(HXO6i@-q?SluHz?4hZ7c3g~xSvBx>-im>4dw)Tv} z`5}+jX5J5Vx-~W8poE^Q4d=m~H`*tOC(CYBTd8)>t<&<{^1YqcFZz6FVZ5y7sQ$M9 z+(8-hWX_WwM~YWWv3%TgTUm9ppW?h{S*3&NpaQt7+z6chu66EihOu z$a}GL3#iGI5J!_7-J* zm2ZyOZ*=aSI?%bkLbP&Q{lss2hVAoL6n|jYedD24eZcCTM+@&-b<3~&H|=M1)V|C5 zD*eshYMr;-oNIowRLA@4bU*!5vCT17I@3Sz+W7Iy-S&C?**iK-a-6I)#BNiw1LN0!+Zk!+}8)aw|BnSynXRJX8kW}x$e8}3O;L} zq4OnCeEZ>+Tf!xROQy%%`0l+zrRUN s{)iZpx8hf-KE9mKmXy_e{J;EhcQYM!w~kNS#Xzaa)78&qol`;+0Pu_@1^@s6 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_what.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_what.png new file mode 100644 index 0000000000000000000000000000000000000000..32aba82e910d016cb4b5aa7c4aa3f72d0f0e6811 GIT binary patch literal 747 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfhp9}#WBQ# z_v%zzkEwwY$KPvvNm;h=s){IPBs@|OY7w}>-r*AL%e(8!qX`c#gmCgUZsD55vHeh6 zL19)G_oA&4%}Zxb@D^$97Wk65{l5Rb@1N#<`D8 zo%7$EtbSm+r=c>U@pZziWr>1Z9|ZWCi|0t+@%-S)^7+jb?z;vY@e4Vt9&pMu^X}k@ zKQQB0xdFTO2A@*i%WcOVeN9O1S*F~>y+HQNkMNIo&;Qs{aec!Y=fgL7XMK$`I#&K5 z_oQQcq41x!>5}`eE}hwUp@8pA%ZWmXl{QY*!snJO?%6A!tMGApy_ZmD^by?>eFy29 z=F$kI^Zgmw=3-t!CT{x~f**9wJD48Pkb0vjcf&jXCFKcwvb!dE|7*OktB!ASz$%kp zy$jySMC{vcEFH2xrPZf`=N4l|bLkE?;}48m`~|L5*=*cca-rAIrE67 zL<`QmKO$|LxF4+k;mlpq@$2C79cMn6A5i_kXLX6`*s?3jAI05@zvf=RoVJOv#;!qc z14H^`i`vVNPWGO4dbv-?_kz-fZSpLBY(MtIyfvAzYp?BfpEu3C9Dav>h@_lVSL9C> zpJ$h_VFIJto<$$!)D9d!7r*U&u=pL;vlYJeGpCw;Xx+mq{*WW*p!AFf*Iys{Km9M` Xt528Q1asHagA$sjtDnm{r-UW|nZZF` literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_work.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_work.png new file mode 100644 index 0000000000000000000000000000000000000000..829ca59ca69426d0d59bfb7c39b9ceee89b29a16 GIT binary patch literal 485 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%-_?+F~o!S z?UaRn%#I?i>5T~<0v=5n!XlhZfp&~`3<3+Xe)IqBl={KQ>Urk8ZHn;)?0U&rg_n+0T=kA`NSs>5ozuitv9#>aX00W; zB7eAlGN1k$s`_W8VosCbkK7Zt*UV06c(5@{r0{fb1-oEpF^8Rlwbl%$6RYL+<(!nC zu)gv9f@wxm!fkcD>?NPg*nY#%H7e+nuZ)S*>jO5;-?!{r7N>qYN!|C0X_&CUM%~O^ z5lZW&e$@QnugTN<`G0o8nO!>n6LX)0@^=?>wi&P=Tc+L~apka*4SVbiJL$yf&nK@; z^Dbe3+o&8LcWb@LefI*klG)2z@-A!l9jNWfTv&R4sr+vJ)f>D%fP&c5)z4*}Q$iB} D)8w(3 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_autodelete.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_autodelete.png new file mode 100644 index 0000000000000000000000000000000000000000..cd741c8e16ad85e03a5cb83a6ac7f3df07e4d679 GIT binary patch literal 655 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?5C%TV~7Xu z)v4YZ%K~MN)t=emb5`W(C6^P2_UdSGm#tZ*p{kj3(k;=w%qw{FMgcD&>1frQ+%rk1 zoW#0r`s~d0Fg*44bG6-j!RLG0{ln({s(rra{QsZxzkk|0y``mp-HB{o@t4DlHdiNw9n)ysZ@_*s|CTiG&kd|@$9@v~hryGpBW!+i$ZeY-9@f8d^>{Qt1cZO%%bO>;j;YuQe`Q7WsX@V8kf-(ZPD zom;QQH+f4zu9XF=Sh5P4ra7v~-s(BKN1%kQ`B=4C&=1B-_ck|eb+i>Mx$B>BS?jks z=YN*WJJT11G5^Y6@;@Le{o^Ucv{tZ~koE8qD+D;6aGtjhB4x>$Nw$ zzM@&u{N>;Gp3PQl-06pS?>L4=JX7tTXCl!UmEZSB$K$oYuc{BGljVbzqrRq=h*c)Y zZOeS-pU;#(pDRV(A$-BttqbHV?q*%$dLb>Kl@+h(@9JjTFms{fZIv4=;tH{clu8=y ztPBm;HyH0|5_){x_EHFs6?63dEga7tuWqfZahKaxKC5)e;tg!KFXR=SIsG6v-uUvL a#ADU0o>E&o%4 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_blocked.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_blocked.png new file mode 100644 index 0000000000000000000000000000000000000000..c26c84d67c2ccf239c62f0c48259759afbdac6a0 GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfU{qb~h4DsN7 z8+w}ekO5DwfUtqH>Vz2!W2{(;zn)^7tJEPo;grzcl7qoU((s*AH5pQ zzRW4kcKI0H@uW@sfPBTIDIM!;kA}}-y=#4>+K$~mY*BmAs|OZOWbfGUE;+XD+hq@# z#h#tF3RUmUeBR*mGtT6eiPV$7Ave^1+LifLRZkMwY4UW}t`~wwE9)#STK~M+q@JEw V_F#%(U^pl|JYD@<);T3K0RZmGj>iB1 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_calls.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_calls.png new file mode 100644 index 0000000000000000000000000000000000000000..ebd73c3bb2aab892a94f9ae7ce10546b871687f8 GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfOvcm2F~oy6 zIYEMzS(d5ihRlcm|La*7>|hc2&-h5Xr>7^r!K9So!UqclH#YMInY1F`^h1j-3i|rU zp4jdvtURmxY!iD#iFSgZvKPl}R`U%nL=Gsq%@Z)#liKh@K1k&c!=|ezjCtGj7BsR? z(8)Nmu%{+*!NX1uu@{r`h4|(=9G=e{ zC-aiY7pF2FWod{Ih@F#R7htR`u%0DJVg_dl2a}<_fIs7-{SG`#^BXIK1x^d+TKFgi z2y57>F&XmgVKa(5V3F~~XNKLR%mt2|4m?IO@)53^4xW%|P-{N4hrPr8!G=`5O;ww2 zIvl>)Xu;9(obh9!LLK{&@`i}%InM5;mvmSdf{dLe?=2FP1cjHUtDnm{r-UW|M?{4k literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_files.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_files.png new file mode 100644 index 0000000000000000000000000000000000000000..88e155d3dc54982fa45cdab41d55db13cc024d07 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUo%M8a4DsN7 zJH?iZ$xy(}yv*#8;I>Udu}2?QbRNAXT_JF^nIlPgTG+RL2gH)nYhE__Buz@={(LZb z`pGlqCmn)BB6Iy6cA72N`fgL$VTpa8rINIlUYVIcD`NxWbUmGz#3|4GM33rExBkc} z^MEZhNSLcuEAq`@xpxM=c}^4kml~=pWVfz35Ri3gViV&=%QoXrY#UnCbrfPGj$~=? zTt3g?lTh-`Mhh|P8?QRH?48_DZ+O4FDY#+fT%qabRaZRVcrP!0XisFe!TS7b_I?kT XZJOn36CZHLf;{Ny>gTe~DWM4f<`r}* literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_messages.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_messages.png new file mode 100644 index 0000000000000000000000000000000000000000..51ed58fc9e704f19c18e99484647647b319f1f85 GIT binary patch literal 545 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgftlQJYF~o!S z?G%4)mq3vN@0GbHb!Z4my6$USw5Ep1T6%S4#H|~*B2M~6{uVMjbxlRvBvrX{rJzvK zu|Jh{>9fAyn;HH2-t67;g7;TGzw`P1z0dEYlXp!rVAMY-zpM8C`~worbw65~o>$(t zx!byE@dkeW1n=Hf?i(%l`gTv)!YDt%Z5_uf@4GDz-kOB2oe}=#=n*xRwT&|OUEg_1 zW!z?2&c0o5YUsJRm}XJY7pv?hOWZprxBB+3RQtsGm0RV%xTpSpQGQCSRA^a~>F$Fi z4<5{HmYmTZzv2MXnM0NxDL=)Y9DQf9=7syd>1{W7mv|_sPI@hoy24a*v)XRG#*R52 zE@lf{uXkRXd3T-Z51X>UwI@UO1b&mR;#-yFd*$PbRhJ5MA{+IdZPm(*ay#jS_z3l4_&OgjsPTl&H SRnr^`iXKl_KbLh*2~7Ytm)`UM literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_music.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_music.png new file mode 100644 index 0000000000000000000000000000000000000000..cf0f6d5ee40e05286af02080f2bee2620fcd8775 GIT binary patch literal 444 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfOwH59F~o!S z?NnR7Lk2vp+AT*I1(c)N*Bv-;Knd9sn`9>e6%F+%XI&6h0~i9XEch;DeBNGK78t9Vc$V6o5?Irf5Mbx*dB1ii9Y0u z^I{6rs#o8k>r^wZo>L_^Qt!q&vss_~n&KNL=d4h(<&oWRk>lr{eIEsu81G5aK750z zSpTHYIi2qhdt+~%*G@HB!nvdBMCQ!s9!2l@)k_sDxsGgXuPM?9JS-b>LHtLIbKO&x zc7dB)11qP06kF~o!S z?G#(SLk2vp(RC{87#{KHbR-{`E5NM0{ROWDC$o75dx8TGkH?hrfl51dC$KTT3h?&d z79aQM#uS&p?A|#J^PVS9Xb}0~W3ov0dX`(u0~ROWZ$G*fCf%;d^4!_I!>6E#%UtKP z>1Un3#}lvFX-~*@%PiPV{YlAO>jQT%KAJ`njxgN@xNADT#;H literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_sent.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_sent.png new file mode 100644 index 0000000000000000000000000000000000000000..f03c8cd983ce694b4cf3fe45d46c5ba395a73ef9 GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUz4vr+4DsN7 z8|=t+$UuNcDdPWwtI>h=0UsW*|1#eHQ25AdcK>|~@7ca`>@Y43cAC}J+p%1aXZOi- zK9`mnruD@89f-14EV8+pBB7s9qq^jrrTW>{M9w=5;%iQC@w(X>$a<&IU`M!S?jsY4 zD+i2AzFm8BweV|t`K+u(+u8aK-Bdciv`%6Ek~l^ACI9RmF6%A-?Dl%ezwRwc4zfvAS=i_MEaAyyuxLF54Kdcv*Y!gJ<&dc;O0Wf1Ahkj?3~AKtbT?>gTe~ HDWM4f_wb9I literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_videos.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_videos.png new file mode 100644 index 0000000000000000000000000000000000000000..e68b58bf203323b9c3e018861d371b219e72287d GIT binary patch literal 395 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUef4y44DsMi zPLN<-tmu%*VX#R0!~g&Fi3=i31+p0o+iU{fa0}?Crlj0qSQ5w(pf4TpN4!hHihV@} zyMQp${|2rv2~~|bVhZy(j?_2qU{ULv%BJ;$^~jM1kqL|rt%n@;hRVh zEoPYGq!4b*tXjsnQP7N4!B8zm$ffHv)76J2GAV3J#R`OqIF^bD7|lw4}$aARCb;};PX}dL^qw6sZ30_9476yib7ssWa@m!7o1%#)o KpUXO@geCyHy>w;( literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_voice.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_voice.png new file mode 100644 index 0000000000000000000000000000000000000000..eec3fbf10ace96578d1a763ebf994df5ab5c8341 GIT binary patch literal 461 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%-qw(F~o!S z?Ic^j!wv$in^it0&S5TBVV6wfG_^&~c?8ovxKws6S>WI?gn=IU>A80=9__?ot zeM(>KwZ5BmQ`$naqT6`JWjR07%99$A6Ow}F#m`}#v_3rH-$B+tvdLe1)^X(>P)=H# zKIbjt9L1wi2G0d*S6$$|+IDQs+1XQdW=QPeHaM@n`si`3PvvPoPP&y$`D+ptC)BjO zyU^|V^TZz3ok^2rq-Gx|{?ZzE(e=&Ioi@ow&L!*5zAUirsY6}&Ip@hmt4{`Rxh^{6 zjpt;$cecMA6u+qiaa1P#Iew1sEpx`aMeJK#cX4^{%(}d9p8R!*7mL#x{tIhK-P4Nb hzoxfiP3(u?Kl2s2bBd<-{{ux9gQu&X%Q~loCIC!puu%X2 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_datausage.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_datausage.png new file mode 100644 index 0000000000000000000000000000000000000000..8f402616390939ce074af88064836f0aafeaf04c GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfU&G&S14DsMi zPLN=A)?)eh|NnZ1BhMVpxRB#gDQce-a6YX$Ei)y}I- z2?_zaYa%b?vPtrZ?B*BU&%7jbVa_Iv96JT=HHA0(&N9Vh6?Q%54(d@jl*z@%>E!6e zEB}BuC@Z4jaK6C9hnWZYRqX5Ck|t~MUF*^njb%Euh0$=uo=Da(Rz(j{_e)l%WUeVP YFmPo%F$d^9(FZx%)78&qol`;+02yjgw*UYD literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_devices.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_devices.png new file mode 100644 index 0000000000000000000000000000000000000000..d712d51a2958f15f17436b587674dd0bb8bb7e76 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUE%J164DsMi zPLN$#=;uVEyLcqnp5IEMwW>$H2OrX`_VCB%fcR0rxA7zV>BF ccPTP3tPx268TRwzQ;@4YUHx3vIVCg!0L|}Lga7~l literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_email.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_email.png new file mode 100644 index 0000000000000000000000000000000000000000..45c57009ad387e9d16514a2df4439c90c12d1214 GIT binary patch literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfjK|Z(F~oy6 zIYEN;upNuU#o8bL|JTbdh~N_NUU*vYfj#r7^NA@bdzyk}PZTKp<2&+%X+qot=7$ZO z=b8*0^qx0#-DSM=e?d--hzGBSE=R+crZWx9CEN)IH;KLo4PBrmtYF6z-g}ba>ExsY6w`1c-|8`!Tyr5G1Q=tM@oe=tVtn^ zY33(|R)<;49jg~g$n+>!DzL3|WK)S`xWv)5BTeC1+fI%nZC#1p0vci)4wyV#=(uhz z<0F>^3nwpl^{HWt$&}vdO2?RHFe)%xC(0ycehG0|W4Gw)#k))aWy?h#m@!LqhUja( kh`tdhWw!VidpZXL!wbH^UF$ALc7Vdi)78&qol`;+0Gy$RBme*a literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_off.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_off.png new file mode 100644 index 0000000000000000000000000000000000000000..cc151b3899ae0e3a9a9d8538abcc55102e25a548 GIT binary patch literal 489 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEZEbqC;$2*94Y> zpQZ1#o=y8!*1wvC{ok24`#1kjNq@KQ;*ZzUmc}g5=+gbP>w(0Xg90(>kzo&BOFpVj zV5^aK*pjtU`2vgbVjWk%gOU}-cT(>%sk^;k-Jg84<8}h)KF623W^WcY*c<)f{rhi& zG#WPwuMLJZ+yA-Zz}&I$vZ!#SH8Z)wB-@^!rKiI zmy}oSW9NCtaFKh1w1D_7-jomhY|sBJtbVj3P=P&E_xcoPbB|s7^iS|!`;z28alK)y zz?IDo`M<)Z{@ph%`Fm{qQ?}&i3#6?}l2-h+w)h!S!V|Yu#n$8wbmB`XUifr8o7 L)z4*}Q$iB}wKl*H literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_on.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_on.png new file mode 100644 index 0000000000000000000000000000000000000000..70beef3711ea51f5c5c038fb2ea154a7cc19e77d GIT binary patch literal 516 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEYH)$F~o!S z?UapP%#H$W#Yq#LLISv@xg9+wd(BQrPkzrF!C|(~$w&K%WDrN@CyA9?zA`TAH9Saj`i>`=VVRx)ib1Q$M>b>ZmqT8kHh?vvd zQZEvA2YsLMefQCo>{n`U&aUQMw}|PtHwiU&%<_aNViCO;9^^{g9) zt#^gb{<*)s<7lXu^n(cD3#*&dEErfnu)O;rx3fOj!s0>AsmbLtb=zW(N#Cm8U@iB5 zqu74;1cqNWFU4=l++y@Bl)bz?<#JRu`yH;2=6}4d6k9c$f8c)3v~2Ufl5cB3;q2+^ K=d#Wzp$P!}P`iZy literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_plus.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..960dd8915340f07be8cc15ad9fd8c5d5369a9500 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUt@m_s4DsN7 z8x+meVjz&6>Ug1EU$gq7ZG%FGY2!MUl~%036-yEd-lWL+K91RXs=-LWN#bSIw}_r& zx;4G`qNL5k6bj^b^q;$tV#(~o+rQuuv)_8Ja~pe~S>Ige99MVu(cbxA9~ikAUOmLV zRcfPWsp#^KRUT4iUV&e_A28nc5%P_193lIeLvzGFlW&t=8!h?>80EZ^|?l7 rGb0(kbaS=@@ISP)apaP=PY_N&q-S&J_E|Qbj+BH? z|ME9Udx&iP@l*Q5XB$@Y1h%XSHlorLT5InUEJ8WWfgbvzA@&k|p` zSgUpZ3q{WCwfc`2E&MZ~`_$I;N7f0Scxua{lDPJ3YK+Mgc}1php3<`qTy<_7uJ4Q} zb!Kr(D$@AFSaYfS*#3k6xoq}`uNFU?{$X{;LE#heg`zi#*`)X9{f)`p_KMA}E_WG= TZS^J@P;hv<`njxgN@xNAa+8RM literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_storageusage.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_storageusage.png new file mode 100644 index 0000000000000000000000000000000000000000..c4a0bf9ba456606405fa8d54be5c8ee6f691e848 GIT binary patch literal 560 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?h~sV~7Xu z+bIXNT>?egkBdky>eMhRGZPaN>zW#IL-SPABl!ta=T4oQ<8d=0@}!ej**CLOhn$2L z_K0$tCL1n%zI&(p^Vs+2s@LB$%@m=+_Cn!qPI^EY|aweQ?=INh*zwW8`PRmr3*gKQzU-3q@$jSm&B=$O2R zH+Eg;R=*oeoW&Cw3X2>!FZv>Wg;#LXeO0sPQ-8eo{wno`ZC>)z z+239X%4$Ab5&k0Qfn9q^iw7z5PFDq{7zqO{7^Of1^mA^X9tywYEW@f^QX*ri-4!6beT)k6u zq{iFq-HD>r6V@$jTgYC-^poXQE%VLn#?l+@_5Z(l$RDy1aeOo_iLEGU!MQ^sF^xwy zy*ZvHS*+$|{7PoeW^CiTu%5v-;QDeC+gr0&9kXGpE?{1tkXO&S i+h9&sM6AqLmO6%xM7DXZomTTevE}LN=d#Wzp$Pzp1mbxB literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_download.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_download.png new file mode 100644 index 0000000000000000000000000000000000000000..fd404abd4aa79caf1a8eb5a4f4e9ebc2b238aa00 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K$e_ISEDhFA!m zo#@DQ$Uwk#c2k*plekvNRqhIA|EIh*t=;c-U7X#~#2tI&ySLKPCCR&rA51=Z=J#Yx zT`uK4-`P((yb*i0IVEuE)iW>u-elOfeaf>i|F6qG2p042n9awzb>6NSB@9|eeuSv7OkRK>`8 z&86+z!~ZKOJzrC{aB(GrL^$iu4H`WxBHIoKTU>G%d$1%*`m2wLh#bSQb3C86Go3d% zEv>AVKh=It+MPXFuFR``njV}bTX4N}vCDdI_QNuZ*UdEh#W=bCfKz^&O#Py7YxgzJ v=iiZR1AWwL@`njxgN@xNA9^h&M literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_upload.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_upload.png new file mode 100644 index 0000000000000000000000000000000000000000..2f82a04d2c8916170856261f447928ceee13db12 GIT binary patch literal 376 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K$e9(lSrhFA!0 zooLH-$U(qOn6pWtDIxuNVvg&j=w||t3`Gv!<9^|5)9@{6s*~f9ANwY>Dz@C^u=;S~ z%^7q1-JOf-BLhV^brOGl<>}g0z;aW1(=}g#-ASU)3L49N1#Ug+`7F9^LGB@6fwyY~ z;(5&yq|d)Cwffdj-{>lH+* zu~E)y?~gUht|!aothwZ|de#Zww~zS~*DNrOtAASad8%8~RhuN$7t7qtPdwzYn>|71 uKnLUcPh3SDFYMgyqWuAYHs=hBC+VyBjaeC_G#=d#Wzp$Pz1mV?g# literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_premium_translate.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_premium_translate.png new file mode 100644 index 0000000000000000000000000000000000000000..32a3942ef84227ee92e072d3a96e1af2ee87495d GIT binary patch literal 583 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@?@(V~7Xu z+o|WZT>>TAV(o=}JA$02c}={bA?Qny>3y-mBN^cVMiuCX_+q6kgi97Oy zo97L|K#O_bt-hNT$DWy+W|?nWYk%(NzW4Wxms?j>TBbf`=`oZwnA;n-&^BWqLs0FD zHv36^+uaH^|EXQ6+NmOae0^JSMLUy5Q@DY_Ym0MS-`cq*8-2QJlhd%xwyDiy>Vm)g z3mCf=cba!O>qNM&6JGN5LDZ5NY~~w8b%OYod;@dXKQO7rDb|VC99lR1^o>g?LQCRI z4^BHMy2o+zS>DI;&R@1KT*12}^>)rbYm;QNK0*7NclH%cbp0s#qVss}V&yf}pEoQv zd(NAAGUdR8+(pILKmG`p_|G&iQDDhYAGV%=9}lNV7dPdG2z7y;C|9}4c+Q3Zq z5Ze@X^NHRKCd|y9Z!|i8HJN4}7ZE=!d#A~+Y+uK0hg;t!2g-K+zAHATHbOVMdVzPK z@V0;XeTUdC)H{dXNc*(bfc@Wd)tq>}=|xQOx8A+q^zCMNFenl|UHx3vIVCg!04`1A Az5oCK literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_smile_status.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_smile_status.png new file mode 100644 index 0000000000000000000000000000000000000000..0761be69793f48a5ab844361a1daf44347f79245 GIT binary patch literal 617 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?6RkeV~7Xu z(W!>s%#H%B#Yz$z1sny06!+F2JLT4GT`hh3hRW0@%a<5MEZx5KqFSqxS<-3&>w}-G z@10A_KRc5}NT%YOcN`0~e55%cbzj>_h8Owfky`~`3QzuO zdy`k>_emGaq*rZQ*cPp`+^2Uj<01FsF6ZYaC7eqmC06$yyzuN<=hg#Gx?fx$6WZC&?rNVaJpbN~?9jtF~9i7|ucE_KP9Z$04t+#jZ`R$GUSDbs>HKu#b qvu0tPMP<5AC;zmUuf2WJ=#P1e!W|L)Gluq{X!dmVb6Mw<&;$TzW&LIV literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_channel_create.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_channel_create.png new file mode 100644 index 0000000000000000000000000000000000000000..53b0a25c3c09f3831382751dced47b82f560209d GIT binary patch literal 1284 zcmV+f1^fDmP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGZb?KzRA>e5nMr6BK@f(0t_dm% zdJs?Q!95}>g2_c(z>61+3xeQ6Tu>AxiU{r?hz3Cs!3FW)h6o-L4{qR!3F<+kq8^l> zabHkepI^o4XW6f3(v$e|Mo7V*uCDsKs=8;UXI`gGn^tLEf!wS>I-MR44uCni$q*ft zyq!Q1CRnSlggQ z{jsK=lPf@u{@|vSOS(Hj2VEci?cxaJf$_D+Fr3bE(AgLr?Fx8$5C}HKz*4SWd%AbGo3{Xg#) z-lA_yWYwyutO?*73yK1cyrB~UTBQ`F)ZW12=K$pml_`~;{=tr zf26>1UV+AbfMnk_N` ztS16b8m=CnJ;1gQKn|g_H2RqV`H32^(!|6z9z0V%Q9lD&6sO>GUI8aL%t(+6z{u?| zp0PuGXvnl{j9ps#y}&tO%TWyW35oFMDdKw_%UdVFY!yUQ`4Jx~`0pzIdYg!^9oP(h zD4wXb;IDTN{Yr5Ja>0(})n~Ar-M=wWXys@yRPf(Y+$~{5I1@p=;)?nSRDeaG3TW97 z7OPP^QTC`v@6kJl4Zf{l&WhoRj2E1rw2Cwm#v}|QDvQeD8Q8$7*pyd^vW1vrraIvZ0A9FsD uDONrKdII@L`jqW1Y&-M`*UI@XR^S&@#j~N@Am32{00006gB0F2&*1?o7x#2=49Q@9 zJJUKt)KR3ZSap%3u&&M}mmYqREdm>jqkecTPhbgDVwrR)VwMKS%A;Y9jvOw5+7~Y! zIux_|2h-Lr{+b3)MZ*jgg_B>ccX6ky8_(YRdhbomX9v#DDSme5jQ#U>XU@IJ&EOC+ z5&**w@{$^%m$wD2G!d*9$YIYuz@jnTYiatFe_ThT53(BY=6vFMo~WPBurck!iDS1u zoK5DhFz58JHR#YwoA)hE$l&d!4YfV%#Y>tP4H&o79FEu>GT9^ch=8VZO21Mu>)!dU z(VewN);Le!v36tsC!-yU-|TtiFV$y!ujZ<(!y48zjS>46tl3i9QeQ6<(q7bK7k>Mg z=zXJb)_-5!{%XveQF^4``p?#a_sb^Bg}Y}87i|4_YQ9;czroe>_u}fjUMsuYnPzn^ zt7l((>|gzD9qySo7D~mt+D}dtj8}TME^B)D+=YqzTy>Nu6<#;HCu^ zKFKl3()dXSnMq#GDO$G$;H?vXPGyU-9#Uly&d=G%<3xipbLd(|cln)n)~HMV)_B3xsjc;mkB6u(>3MoyML}8r=y}er|2#YWcdM1I-BBW~>|At0!M?dx z?2oN=;I`)54&63>o7~o1%J}MbZpA}GpXa?AYxf44x8KeFu`6=T_aymW>|ZALXmkH@ zc`{vje~pGj&zqdq3GAB}#3?BKH|6Tsj z`>VdR%ra{uo!I(MDk$$d4`GQ+-J_VQnG&eTEdiJZduyP6xcE^5tJyndNCq4G+N z{NMbfIpq`AcFW~1xNbf3SOK5#q3sRR#3g2zT6`<~;LW~J{-R;)OM!{zAM%^$OsM6^ zW4L|$r{=#yeKy>aSZCHv2wlc;CH{}tm+%heAS2Gt(+$+W3LZb_#E~W`QuN85~`= zO~!obp@-~4%Ml`opouWGtOp~4nR=?1J`{>RNQ=CdmIVs-A%XP}F*!xw)|8fd`~A=C zHLN+a&pqePy-C6S!+-YLYp=ET+WYLY_da(@r50K<(3*k&^?wYMo0)yJTAfL}g>WvM z1KXi+01mEmfq9Tk1@=H2;PD>}oll4B;U93kkgsA)KdvL7 z!`tAG(Bm+bEpP?wgdK2dpyb=3;g|`b{DE@$zdi^$X@gIPPOTV3xC2g$C4jyRZ-k%1 zJoIDG7K_ucj(@;2;k&5}c2l1c3yxliFM)fZFa(w0E2`AMcG|QVG!F#S%=_du>sms) z(!HQl;@$9LDEtl|gR{&Q`EvLP%z_5dyeC00zigD)Jh%huCA`=1Ddf+fpu``Ar&;2@ zL_ZPU1&>0#69a)13HrVLxMf1=g*9mAmApE)M6JzAy?@M)z*F-&#byFj@|$E!so3hn z(AbMj6m6BZ+Z;l^By^;GKMPy(61R2&D8BHF(=DK`z69+~L&%=LzI&UbSGtZ&^4p5v*TAEjJwhh^)*4K9F$9aAlV8Oba&YY^|BR# z*6pGqyXsPM2+66na z41?ZY(1U3^o`Q6hpkGL=;)ff?i=g3t9~`B&zJIr@(Uq?w&xfbOC!w}eVJp1I$B>Nf zdiXUI-b}X#o0Y@O$=@4dHc=hsx{w(<(?&GRg0`e~BVQ4*ISc)>&PgWkVlz~f=_qU=a}q0>_kbo;FNQAGRs(C$Bbk+bkO4OjZUsGsMI?WOi6rRY0= zg@3-L4EmZ%q{rFFy?lN&h9V=kP992*y(QdJaxx-c2mNeQ z9fjOk!+LV?c+L`|ekrucQQvlBHIw>E0xXAyL4qV3Bo&)*+|; zeRVAH5L3I&hfv$Bp@LA~p_SD^T2Ej-3BR1ECdq$6nLg~!LHD@~fCf2|6tXr4?el)t zsaE@7b7ww1h%j?{v2Ax!$A5yB%~rS)>Pt$8*=(rf1uc~)pls}fMNFVr&3R#C3CDDF zs99VGvkp6&av@*EXl$#DC0JBP=k2fuZi9X;Q;kA4vRwrWZMC&>srfxy%Q4nQLi*|B zGN^4EcYX({~P%8ZcY2?4%F`r8L01E&B07*qoM6N<$ Ef|XGUX8-^I delta 1302 zcmV+x1?l?#4227jfPVzE?r8wER@RdX{3qkOaL>DTKU^4O5{=V)yHD7n%+kNlt z86VIGzOGZJ&ZDYsb=9eAwWc(kf$0qVuV;o z-TsR5zd>~RM({8=0jiR89|E)g+9(LV3A_OQ08L4@M}WRoBdWcG2qv3-371*a4*W;p z4R8`@*$C3tQc@>x27AFRz+<1K{up?I?ZU=`||r z)};41-U57`|9?sS5ZKT(plrbckguTQFk71XEVRR+X5Kr0mipa=$_<3_1@|ipQIK?^)vGS@ZWEynkZEe?qb2FsvU6W9{=nhvb3E zc5prkHCxx#_uR93Ymf!m9h4LA)%zk{n?hx&tRNVMPED)AV` zw)q$Q(0?I??49IX#hyw|O$nPj&Him`>aw(Hk`!BXe6T(0g)@i2HWXsp{E*{aDZwDU zVuIU@ugdN*#g~omvcy#8`f-x)qEA~B-&Yh401c(YL2m{#P`+>V-NsjCZ#6~tW#X2{ z_C95uvH>Wc4^m<_M9k0^2$xdBO+yOf1@VP{#(&qBCF-A>-20TpWdravU$lI}!S{*D zJ5)4OD6dL7qx^fD_bI!dbO1jlPs)`%703aK7<4a1eo1QksYoZud;o<9TG;?RC-=O4 zFjiH)QFeoEULO^^t5-Gv-Cu(WN1htjr*fHftc0u*CEd`!a)gmD8~+;Fq-+4L>`t;F z%YQ(#6M6d&xuH4}HiiC^8=pMyQ;t$L0PVp+x&{`}^$4#>4WAY%jFEko+LeuNFVXeb z-lwcyHh{&f(YwQ1HM4$reUhcsnGZ~LxAD&IwaQWB$Ft0erxHVZFzs)FpxeiL?AO3> zTq>a}Y@`y$`mHO}FxI!fL}tcspZs^@uM%P2Lh2_XrAwh zy1$3bq#ld80{E5kUg{^iZhJp@*6Mj)(ZrTeaiE{DwUr5!1D9M~?s%5URTA_w8vSH5!}IFW^|)^G3^ zT76Ph$=!K#q8r%#DYl6xV3`f=%X%>j(pOjjO;YJ@Pq5W)qd#msqri5KfuVC}g08Qa z;#g_39$=lc#m>$3FJKtR4A42DgQh9T_ArPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG-$_J4RA>e5nayuhWfaC|AYGtT z0-9)1H-;267&ReULm+iwVq%DKM=*g6HGCu;-KwPv6}n=fA+-GuWWknp)4{|LUCBp4 zLIQ;Zr2!O-3RFqP-!t6PoW67KoqKO@L6bSj)A!??^PKnVz8}*{r6ZjY=#0SsdIYLv zw!YD5tb%V7cowV%JwWmcxCX9*@2b`6Z>0YXq0y_sN1zVwgLWdDI;a8b;KT0>!B>C- z;0`D%@)gI5huQ-Ieh7XAUS=swfIXle^n&FPlvkZ}vXQNqn-m5Xy%PlK0^>e1`Dt#fgPj3az!7hwJaszs zOlqONZ5hvca_m`j5ds&RD+U_&l_yPKTXwPlfu_GLBCI zyO>R+8DrNC-UpMwWF+)K@vbRJWh|N7C$c_QMT__v97H9wTg*V!s1u&CZ0j z)cp|Ywuic;GWL6c$(A^~r1h%%yvaGsB&9^y0LIZT1)IU87~5Iu^j5I@)P@+Fu*%2I ze*VxHt#6awkkywl(sKLVj7hh8z0afD=Im~hU+MK>9{pNp-}0TvK4}K@nljOADotKT z=|A$fQ;fY%2b6r%#K(@^N|QR!NMj9j)0Dk^-10G(i-ClCAd4f7{9h)0CxY_X52A<^A3Gd%dZ+GKE$zUe4kWQx z3GaZ-5}@fG1vfyFTt^`r*(S|?lN!CQ^2M$aV!*iuOm_PQ`#c7(f|F*LBmGgnp3CRa z`R{Ph>wG?On}R?)fVRD5Kv#n`>>7WO&IvZ_DSQv?s;yt&P6F*NH^Co3qC3x1pclLb zo&l0SK_9$lo2BRvyy8>rr@>wD0yZtz6YA3iq65H0Tje}KaTxprJ^}0IDN_pAz6d@A z=fR=Sl)7PH@@1&cT!umGP|rGvo_T%Vnet=4TqGZIP<|6AmSka1N;L?QfhN_1KYAr) zzf|Sy5!}xMJ#tKT=A?)>hi%LlN%fK{y%TV%@n?X^Xnbo5)WWDM@Nr`%)lAG=P6cS^ zT;S5O@grZS+%;!VMg~G1ZoU&*r~384cA(s06gB0F2&*1?olkjwL49Q@9 zJ7Xj7Ap-%|WS7G{Jq#sRHVBGLF<{9#Ah9roL9CHWOJl-k-Ne(bI@Xh#OD}FOIb^B# zy#D=i&sAOBEFKMDl+eJkAX+G(r?C30;|8gvcC~8sINag`M2xjD9uv8%xNYJNBl3G z;gDT!ayDf15rORy>jT$3_`ct7&F|_+p}+|hhg)T@%(ZF#CRkOqQzrU1hwIC7J09m8 zfqzvGk}mEHJSnX(!+DCyfw{iwGF^wHtpaZ_l>eD9cf!ZGoV6K+PUq669uU}iw)RqgAyrNjttqT}Rp-_Ug2Kwv)z4*}Q$iB}CDxH( literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_bath.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_bath.png new file mode 100644 index 0000000000000000000000000000000000000000..d50924bd53452a04657c749fae73086f40dc79c0 GIT binary patch literal 1221 zcmV;$1UmbPP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGFG)l}RA>e5nN3JlK@`XJnUJOl z1!f;)enFoW6n(9PpoP({4oA;jYzPazcg$Mrc%$zgxKWFC7oqO-RtgKl{?+j$8D*X8Pcs{Wz zKq<&G;to)5&(6;7Gi;etB=J1Z0DgjKGKS+0SdclHt4v6$Ia<~h`xk7h6B$IHONeB4 zlFUPuP%rvA=msOoCaMe^1l3YOUV*JFsnKvPoj(kq#hB$y(Q=_pF1T;BJrS*~*Bm$5#%9RNF_|t~K_A2QWu>PEv1E{r{muB(gUK-zR*s*KeU+4ma>v zjJ9!It_Dz|BFV0HH*VC42J=vb;QI{QTbsGsMz6uHw?Jzki}5zIpH%X~>EsHK$Ssz` z3;5Pr61ADWVti_IBx-Xq013(87u9u1u`3{f)=r%33yzwWzjXJvmB$T6)(#uk7 zG3&Cojq2iGxg3DbLhnXeYkMHtX$Yt7D>K}LCAOYGzm?sO;u#}GbMS+N?!UFO2I4EB)I}}X}AYef_l|S zc92$84qBZiz%uX+Tm)^*e&Rb911SJnnjlJv5U@i9eH|}gv?Zkb4O957DoeF71$v2! z(H}2X%mHxO>ME{)et=SSAk6qNW7eA- zP)?(O`+&iJbDGmd1@g-(z%R7CDLNH6l+w@ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_busy.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_busy.png new file mode 100644 index 0000000000000000000000000000000000000000..9e5731cfdd9b1fc3b92f736b0c3355f733e8f70a GIT binary patch literal 1114 zcmV-g1f~0lP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NF#7RU!RA>e5nY(TiK@^5{-0CUfV(1BmJJso;jD9vvX$FwOU2h3{*4lU(Z0jOzT^%)+F-IfCFF}Oaak5un9K6 z(|W!BiE?WYMo)tqpb370UL>9-mV1Xu=NKvB|I$(R_b2PnJ@J_1kQXsm&& z;4C-{#sgGWpPq?Fyq-SLm>swiC>aBHyk_c~U=HlbYk+vc6`--6R%wjom6ODW;7Rbr zY5Pij0qjZ=nx%y|6}_rP7Tz10@^ymFVxqMwqrr+ieu5rGCb&tjy@h>E0)RI z@!%Kj2A7-r9sR!Pb$gpUPj?-o?uFP>G2YGbr-x_99beJvv46z zM;*utp$%uvQCA;!)$4wnTRCB&+t*f0WP5WvAVwT$0@0|B5<1HFJW6DRkbHQkA804I z(5?;lM>_3VX}09I0Pm;3D38`}14wI2pJs34w-rp;) z>6$l_CLx_09Vde>ini|JS4ycz$gCs<(k&@^s7g1rdjzr%0Sg_eywuHApa(&#k`_px zK1z22nKJ%W(4k_bfT{5z2-AlxeQYw)N|Y8($Wqw&nQzjz9Vl*8YA*tn+`JQdC-n88 z@MT|P!6LBFC{)||CoO5^bq3*D2_H^UsMXMi+T8bMc(pm`((Y%SW@`nMJM%H;P@)&x zb|0(71iR9By#iN`W5)iz01IWKI?;8-6DHH%BYk{#7#(pbspZ>x+M zn70q*Q(zvf1ART{MdA_fbxPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFp-DtRRA>e5nM-ICK@f&_;{z2z z1*515f?#}|G$M-PB?mo-Cs9NY1P>lOi6;>ha?xWB9z7^}P*G4+q9O^tf}ny21ByZ* zNDvWxAjU^BewD4B^zQa#b}~J?3R6&9)z#J2fAv()^vo6tIpr&muRy*6`3j_1fnqIV zgCLlO-)?vVyr`Bj34Gq;`wH$W7Kt;^mX4ky7t;udU^tij!R2?(o7&}>0 zr#0}9r90KQ1On%%apM$K|BRc`Y1~Sm5#fzS*~V3va1rAYh(lwpfVTv6!fut#$O$*I zuLOLSkYG0nh`wEZqR3YQzOO(pfQJ=yrU`i80|J_T@B{Hc6WGW;n4@}?@O1@zmyiH8 zWhDEoqYAkid?nz!gaqCl3v^@|rA;7{5)$B)Q9oi(lgKOqa~sW~gao@OqgM98N=>Fr zq`d+rfhkYpLZpSl0!t6ov;Jt*Hua$X@>Rj?%=vBQ;7yxBPtMSCrFB0?!ZF6UkE_qiLN|XR`WZo9o zbx@OsmK>u`!1G|C;5hn-gS_y^5`N9_+qi&M|2_1$N{ODA!3*JA zR=_BAn2x>CkxD({6BVGs{*(4G*xV?bp&AQ$p$pzcnCd5m-CF!Z1_Gv zX)xH1# literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_food.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_food.png index a95a9e3b765f4d9713791cc957bdf22b5b6bf323..10fedebf853e0fb4ab4d4e448dec5a2c780e0dd6 100644 GIT binary patch delta 921 zcmV;K17`e;3X2GkfPVvZNklmNkzgZfg^f@RnuvD%{xk10IrCnpGxNUF#Cwu|pYxpi zbDqo0w5=_tyaRa$@($!3XrKdy27D{7#bU9ONgwD2+kxi(*ndT2U%_Ya5j-js3Yxcu zD7pZKz!NYJ7E6C|m;j35Uu?RIBH?N91~iLa6X;aBReRA%bPd>!|6x7`hQSfA83Z~i znWvMDY###oI?|4eq`C+a+;!Q!ag=d)y-D%i0~Ev3oqFTN`jJ7Mck~O7pdaY@ ztPt~?z|n(>0tR6hkk2ZgTsz@N7dvp5tbI*9LG;Wy8udG&&}9_OfNf3>zYn|v)8M3$ ztN0&4H0I=PM0UTVDgPOC^14Uj=$#ko#RyzjWV2Fwbblr(5q9dlqZz+F3SDgXI!*ZX zi<%Rt6X-mO0^L$D- zpJzP9_zKvq^i-)1Ixfe+PA|(iFHqp~AZh_SaMA_VxD;rbB6?YXp3*7`U4Sgug$)cZ z!CuWQ!(BQCSCFAIh0 z-z0Cr#(-xwf^Vcb%q#RIDqZXjc#cCje~$`~qFluf#TBpIu{+?3^LF9_^P|9?PiNB1 vQD+HSu_w94eKKtymZ$m@f>Q|tC1%Jl<3JebqH-gFI-jU)C z(5Y?UXRyN8al8P$3l4z`;2yXOz5o+_?zqKtWD2+iWM8Qx_-WvCpw5=F^_6t`fl87q z%xxlnQq<-ldOM4_8!U**%=Hu80P~}QR;x(kC!|RlqnvNxvCdy2?gWqLa=F>~oxrTm zf;7ICcfjknaDT8kD(J;OPsh)@grzP%>*DbX88Xw|Aiv_`7k#fNZwCKF^;hv4dZ{hw z4j?ieg+<_DFa%C=MF;TZY-&{T6L|-Vl6G(`9@)3l-y8{R@Jq*E06&7;z?){3Zm{oYF>n$*0rU_SPk;9)3!UY9Xxq+k`U78`aRQydOjqq4 zVDtMZIc3Yh9$+so!bH{r1h<$d{-YpK8fxaz)FwL>Z9*VL4QBuPGE}5yzJtv!rz=wtBVW5xD)Vm z{hfkV*&JMVGX7$^;`le^MVC3##aV@Z+)peg8g~curDQh8f((7L(<-~tjXQx;5NJIk zdv3&K`un6)JLlr`A=B3{n#VBh8rYgWJwae5TG|k}4rG7F(Zt;Wwd;x+Yt_0kinDMp zA%9{^>hSdtXTL6g4Mu+UXVG(MAa}^=z8tIzNh9cw$h54O7fhD2AsSCddUB^h(kO{% zhCnMxvk&95tFJ}qOB2JtT{R;l`XAY1sGoTdG89-OWtUZ7xwtor48;l&^1A?}E%8Ed^-U;*)KTI)D~=V_}CODf`h69Gq&lY~_O0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG)k#D_RA>e5naz)lR~*M@)GS0X zUJ_I=K`;PBe}Zvv4_xZ)?R`Y~{~(ec1baaZ{0mxwTY~Zp{7iKAVdG3&rR_Fa zrK1fzi&QNpz}DU>$l!LxufeSqs)WHJct%$d7_2;8(CX6%5%Da1luNNJ>w9 zy1HDbaQ!+7>)KO2LIaj$VilagKAIj+AHX~>Citz=- z2SN5zLdV$IZFQLmB4t*VZD&m^_DlqyXN78~I-vW!(G9C4%KPwNIN2Rn&sM!mHnMF- zK6ZAX(soSOfiQI{R;D$lS3>MnE|2eG(NZ&@*OZZ7Q}2p=?C4giwH2d!jOlrd%zE0} zz#O0_;vYauM9)UGAA-j~)DIQ{eTZ5LD}dI&+E2kLo|(T>W~t?qH`M{(bIr!htY_M1 z!SV>-vtEWqYNkzhGnJ36;YvU1KBw0zsSfA?Zj|bPMpU#LXvS89PrzER2#B(YPr$nd zt^<9b+Ub4(=8NhZ)N(1OI-q4>w1&!*mGzq?$vTm=2%@*(&h>pdq;QNDYeoQCH!?*@S z(W?afPaD#yKYB%N1Suvuxg}$Rf@~SEr9-v8 z&14;wI2w_+K>8SyohTa!pGy8(h@s*{SzkFjoN0+@n>5l)M3+;}xD5urv~2vy*J$^( zVcNb54t2QsPH3HK-Isps%NFbhw&tle&Yxn3R=eH6xn{yICk51O=!e?51^nn+(LV1- zoo3_AsCMLINfAgNw(U*|EYhht3U-69!74B(Ky~pXla8IRR2w8;)qJqAgkwAcY7`Fw zJM5?yCfUkIa%YOgu9Qdc0WbtE0R4Kw3`g#p85aR!K-NEd6?*ZB}=A tdywcc;{VAvNxMtk5$KLUcLaKR{sZ8X2=^!iZ!rJ>002ovPDHLkV1lzEd7S_N literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_hi.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_hi.png new file mode 100644 index 0000000000000000000000000000000000000000..126e88cf536af91b317736e9c8ca08f92d6be6e0 GIT binary patch literal 1531 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHWl2OqRA>e5m}{t1RTRe^uMg0m zqD<4$EP4n%u!r6vq9mw@NU@+N*FF?MhS(>wQj9)`*D|a~rH2(=LO(=V6q#C7NcN!A z>O-2PqKLh_Wtlep{&V*l*6f+N=ggd$`Qj}2&sux^*IIj@J^Spl&lxbFE$taNvS%RI zjLXmG^XE`^6xfl=<+e4WkEYaQ;GN(*;N?vk|&S$Z^zz5Fvc&o=-)*pjem1+N;7`Z>fL*+| zum^!}1OG4jbjxjo9#}(>11|O`v$-+1V&83T^jI*%+VF?4=ZE$n^uxxrR5Npf!JaUa z2heBv0nlC^IH~;+HxS>J!2gFn*YmRRodKQ(irWda0o)6Q$FViFDUbs*!7spzwoc7x zL9mB{%`V^`6xt7*^{Ot$`3-FOlWXdze$vJ#hPcozynTT7xDxSR#%)fnCHO*u#vIro9?S{sAXM+y)Ur zwB}8;=1Vpe+8+jTx37`fCRsCXa+*)Xc^|Ng_%h-;;C>8=JrQ?t@OyQLh7N#5p{?hR zCP1>jNYrAGczYqe?`K||i+dihi&*Y?{5sf)6DCF68hl=!_q=S#t6jj{m`~NFz;VEC zu*2B5#fkVH1$GfLJdgh+AXydp&%2cG1g*b%TAYOM z1;<}zJU%UhH^5Eilcs$MFxl)mvmvz;Nwj@;m_L;!L685hK_$_QO^*xVdn*KMw>mTC zeH&iy2qv>UCmZ5;VE@poF`w8bxeJ(ljxiN11sc3W`VL=+ww|`10?8)Nc^htGA)@bR zqvyN0L9+O!UEULxA>dlOBx0KBhmLSe;fSTdKvuZ7oFP^Lwks^y?@2#!x^?%VI>F zfNu`4C8hJq=s2cQn>aljwK-f^h1WC0*8l2CF^N73=q7#-m~6)=yD{-i0@@`cYZ42m z2%yf0Lbbl1#VJxMhlE0!S(BeIid&>*;nR+>0^DrAESfqx+?g!QQcE|J-f8_)Q;+sr zG8Iiorv5l!(wz{VOjAi~@(HUL^n=Nn^+izsB-huH`l?jOqUda3H?8`34y4|FDwM3~ zqUHn@50d>K@V!t}XMKBNQ6Fo;(LN@tO})!iILMr=^~&-otet0{^?=r%J+>^cP6xGa zb+wywztMqS9lvoM={4|zI>%g+MxAA@?)Vb2kqtUI7Hn{x^+KIUcV(%S zDwmFQtaveWD5c|e?T4?>8@UguNRaze4Wbc2bhyBJ4f-*3$@^_mKg8>xcrfJaz}V2u zA*p{o^tylz05ks%7?YSt0CA^)?}16#n_rqbnPcdE3b3=02J;xt& zGY=$70Y;&3N&W+t2Bz7a3$#p*3DCu^0J?8X-o_~TM3ZGKb>}h&9X}ob_E`ioQC=aU z@KLMojvJlGfX0As@H?m`+aRXa+jsFhe!T_KAovfuy!002ovPDHLkV1jdW%@6

Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG5J^NqRA>e5ncIuaQ544=gWM)W zQzMr&YFv{j$t4NpX;LP+wIYwLjqn4xVijyB_!{ulNp>8$f4%|ntpZvtqbCTHK=K11Nxfx__#Sxg ze2X_f`iuZqqZnduzz#UR)0T8tkG&s?9MVRduQmjtQI?(Rq(a~I1R9ph+!FucjeSkc^sGwOo z6T23CbMl==)}=5$(QyILgJpCLVMP2$@p_PB4rsBY@av!=Runp{0`4)X2W>#CAVoNn zs~S84Mv|-Z3W?(u;O<2|V6l(Mypm;cB4-8A>>FuS=4R>A`6k?N-f#_~&N?9Lp0d^S zq&PW-T5RNjz`f0WMz1xyc-I#hhMDL$BI6hMTE3!=OUI_u;25Z+ZNA#NBYekTn-2PU zK5giY^ndELr>XQ;o;v(q$`Iw=hqzuk^c_@Vf7Gej501ltUhfaV9BUUxKMX{d+;(5a zz74oHPW5p~wtByxt7E?mnnBvV3Vk!suJ{hdxqZ513>o)2?Jt0++W}yk+3At{M@7u& zO6m#NGyu^>&!mae9V+b@PrHw^EbV@$82bFk_Y-^~c<=Qcf_?|+G@Az+KsK7-8>#Q1 z-nSH_HNKw9)vtIYc0^E>cpDCX%+5$!65W^o1UUg3?MvF{bF!8!BN~%jyRR) zwT1kEB+=*IWT2%FLE4JVY?+o2!AdboGfPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFy-7qtRA>e5nM+8NQ545#%-)fu zQS`u&=s`gXiztE?A*pR_5g8FKS`xb zojono>361k<;*wV_l@&C#u2^)|2gO0d+xdabMN_Hno1>->_D;u(|QNerC^`QWahBW zKClxk1pVMvI-MRwm$yKE6Bqza`9{ayvSts#S}^2fuG$~4YsxYSh*f|dMYbEe4pf1g zs(*jECU9Dj?8C0KM6v7D*g4xDL{|ivRA>(5*5Y&7`29k+alwwNd9#%*MZ1+8{4Xt);_|o+%US%jU4@V zjgR;)aPuj7A4FDwcZQg#170K;du#ljc=?pHA2OBTz9A**suuyq)+oOlUVbI*hfupB z^#FU87XikOD&NCiekJLLNE)0}gg#=|`Yq15t^aZCWq!Vs8OysvI47})Jb+Gs2CxCl z09F=bRGG#&x|v&Mw;goT#QRFW%n|=r4j<{0+iEZ9B-R_pcyUb@s|JriA(0oemO|0- zk!$5gpWp0&Y1QN)t_Vf zC6MFj(y%8GCWcGc|6QEIFqYjo&)1DGi`xWJ)M(_VKumc?$ZcBWMfTU_Crkpigd}X_ z2@rFS;`>n9IcAsyCQg8eaU{^BnBG%%ju}+~`stjrK#&IIBfRVh^m9GD^okQEfjCQO z3xwtNDdM^NG8iU-I7?_!r5CF5%Poq#6j zw!?9h&=pwDH%!}I89O@t642Sp-}RlM6L3q=>F?QQ=jVYA9F7^MA#|6qeU;xUfF$r5 ztOCbbKmzpvdotUwrBl9R8yR1RE>`599UH+xu-r`kj&7lRMoc@nf>aYIrO4OUuHcMa zW)e_#cQEEGJ`?{EkP|6Nd_U@KBm&E|A|Kn%KdV@mpjtj!o>DGSs)-~!knBLR1JiH^ Z{sECCQO4RP$6Wvb002ovPDHLkV1oE=Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NF&PhZ;RA>e5nEz|dQ5eT}XJ#_n z52R3?`!d3W>|XVelGc%ODLGKx0r9^sNJzz*mqh zT{H-Hc~Jbg+97TP-M~h!;UvG#FTtJ*ZrB9kBRLvOY?QWILJ)3%s1?X^5$OYM;3*gd z3&46%2aNP$Yy*;`1z;^jFoav#HL zmH6@!ywNbB@Ax_eG~$0;#U2ZA`>UCl6u7HmWogC}NLm$9tqTirQpj~6546)P;=c?S zX?Dq*@g-W8!idN6DAVC!5L*d+pO+{a;vRdshtVZL{>4EZv{wPyAw=%|R&Jl{A_L%y zTU5r|ePb93p zmQa&L?p(QSf~e9XI~$vn8K?nc-b}Q|CUOiU-$O6w547AF;tK@&-*|g`Cc8-T?eK~h zb<-{?#0!!-Fe+@w2cVC|A(8G~aLb9b2Z($JHSR1v5fB{_Mo*m2Ha?WTP4HhdNzg}q zo#He?RtjDy^8Imm!eZdwt@t~!r-%7F_dzHpM7j5h$b&6AMNR~+CXW-9mc!esoDgS| zK)h8lcp|s7wb?$d-{Dvd^sQ~DD~FRm$qoP`pD^@2*p;iE_J0PF*Mfo!)% znlTEq=1s9dn!;pvI%6vJ(K5hELGk}YI|a%MtzAIBLYIHqJs{^>Won{EO|jG9UheTf q=l#&&MCD3&lNm^6Aen)}&A?A9R*Va1Q*y=t0000vF`T( literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_neutral.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_neutral.png new file mode 100644 index 0000000000000000000000000000000000000000..f140e799bd89d319874714a9adf48d7188a05d4e GIT binary patch literal 1237 zcmV;`1SPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGKS@MERA>e5nK_J2Q5eT(Fbc-L zj-@5hs02YmV(XQZh$S&99V$yFQHT*yNOTHRGa(*{Mu|j1DYn=P5nJ;7{?Ga3b93&! z@7{N2EO}q@e`opDv!8QcPfwS+J<#oef4T>HQ%2uxHfLgQ9asn!fB_(S4qkw#;7)IE z?>o}Jg9v&7I0zcxJ18T`G{7LR29AAWa6S#30G~izlCEq_8`Boxa5s1hJbj@s4EBNb zUW#ojA2{bdlYasBfT`^UAX%^%NY~R4g}!#}RFcE+OmN$I z`%L~Ym|V$_6P9kUAzMbb$Y?W2M;KJk`{31cD^q#E)+*pfLybr`5*YK-<{srmse(5< zvI*`3qaovUlwwT_)=0gSJa`LGwt*js&K5Stv{l+}qj{Qa+E~!p6d#&SwkEVY)!$-K zJ_(EtXPu2!8HY#ADe3WAeo)j2YloDEwf1gPH30bnHkA}Z^%EN|5v=fhpNF>$ya%EuV7BLH^YBL`2z>+5!);tvDU{cejt}{3IWktgjm(lz&^kF_ zj7Ykdy6K^QG3kzojIT1^6R2F{8J5p$fS(EvO?VX2W{FMjJ9_@)H9(IMBRxin=rYX5 zLEt0l=>p+1@ID0o6VgisvSNAPKBi(d=Gz5Lyg>cM(mg%MO#&N1>2`rPu{#KRB!0A?mI905%n?svYgid zJ;06HpL?c}F7>`EH9%hvjFwsE52W7rvzY(r9Ank!(0B!O7K|`&x5ku_TTcBUP)89m)+L%Dqa!yV{cI?B`Z208HvCUwW0uTLZFr zB^aJax;^BxiS}`=7wtlIpdINVh>?8u1%|~ElZ)5U`T_7KuhTE_FH#Ki<58B>qIg0U z0*&Q^=BPO(JysHCJ{x7tLp|$6dgiUlmrldM$LipVq~*Kr2Jtf>jO>!7Kzb!bFI6eR z$M#}iQ%5d$rm(BK&XBAH(x;E)jliaYe-L~qIh!PS8Nrx7Z0Tc@kwzlfbi$UVjqmve zW!r($v;%|swCEe5HKDHuwIBP^1xJB>Mj_iee`chKI%5Un8VNt0U&?nJglIyFbYey{;71-j1*%BxO1$=C@?wneg)X2DvJ zWhoBTi^qW-c4RA)bY-Knt+FiGB0kOsz#zB@^!1>OBqP}apxz1V0*c;79luhRfOLyp z1GLTRE^iMK-R1qCeC^*VQS4H;2f97*ANRlyPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NH2}wjjRA>e5naPh-RTPK21Y96W zY(Q*qV1-0TAZ|dw*s{_M8xs?^L=ZG-ggx|%;ZLAVfSrj82(khr6a;o)B8Vi$jW}V# zq>M@f#rJ#MQ#t*(_q}@655%NS^5stFoIAcdRQ2`sq&EV+5%^z^K%>sqw_2@!{JjOU zVHOO4SOHz z6|R9x;N@Qu2jCMJgt;&!pt$l>CLQT|xkzI5Bku&2OoGpS&BV{cT6nJ021pmyfo#2u zkeJk|pGtZ-?uVnUwtt9kf@dl@a>}v|KIF^f2oY@t^$89&^1ksJxy5zWfUhOsXG5K+ zZzgc&m(3~CFV)p}^CO>d8cas4Y+NDU^ud~Fl-i9a-hdgf7?#1jvdW|rbY(Lgo-!Na z>V%((@qO4h(^hG_jn-+lYzWoxrLYT5!d18nKSOe9QKn9w1L^(^CtxQmfb38u)N-r9{YW@QH1YWbBy zjCI1=A*E@}b{j(N<$u97_!>6CLeNqwy_!fT=q@6Z?IE}hmtmC}NvPe)mXg{~{lvyd z*8`Ka!SQQkd>{CLaB`(li74Y^3VaA>;4Hin>e4`&tdE!$XJOe4);cw_LyB-B?0}`k z*40b#sqbJf%#<~u4!heRIb6vj2GhVUW(O)6*QiVz4uWJ9qK8|13(M8Job-f{w?9`l zCW+&jumYYQQ&5nQZm`KlyFk_Io`}w}m|m&_y3d=OwMags5p&4<0S>`F=v2N!Q8rrl zuND~jy4&ZE*H3joj}a3+MpE)I1=B*|do*TYO40Jsd4u@7Aw8XNjg>`0U$<{lTXno0 z$Zv1?bh{!K$?N3PPBnYUSvsnh>Ojk^O2QMae3bYpmrg~$qu`D!Jn7>3Xz96<>Okq# zg_?E}?uARRfw!*Sy@i6#?z2i_O$57DKASsmVI{jyGq&B>mR4yvOa9ePqp#7kU z*-$<#r4D6t%!lRSW7zrGV)>OroajlZXPrdPyd^0ol>H>74&}!JKX2lro+qU$!P#op zD7})Rmn!maIlW(qe*=2&3dNOYawFCO3SS0WI@0|prdK%+M9ktWg;Ev4ncP(tZQKMGUs$Uj?$ohl=bU@wpqPl t?Lnf)i2sxC3hAEoMxZwWy%Ff^yAO#qM7mWv?fC!z002ovPDHLkV1lE-op}HN literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_party.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_party.png new file mode 100644 index 0000000000000000000000000000000000000000..6e6eb41117ee62cf7208778aaa9986e1548e8c40 GIT binary patch literal 1735 zcmV;&1~~bNP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NIF-b&0RA>e5n0tuSRTRfvSIfjU zA6urO5lKc^8J1|K_FBtaYg<}G3ydCEYLP`t5@i4Ml#H~rT+qUeHlvcl$Z8=ZGNHui zWl^GK7WUf8N_$P8?{DuJ&iv;0o1JmiEn*LR=bZaJk9+6-?!CV|)1ybXbk9K7&p;-V zsRd7f)!?k85x`f0dqHiI|6k)6&{7bWW{BQ?P_(ZMLAyO~Hom@KDmctIui+~}131(3 zW!V%v519OIM$q~a71jav5U>u+H_mJL79eT%yxH(~N8a|23C5SDskOotorXOTeCfEE z9d$tLAg~1d74lw4%E7lL_@!nf#gxoZXq78EL2=kWoZi8y2i{bw_?~UMFdG3(2W)lw4PkO)#wsUhyB3zFaXWoKy{2h zIdD=d&ifJ+yFL__s z;dD}c7<`-1Ro-8=O~D#4&I)1cF7qpp`~ft$GQfzF&I12RvyMe?8)#{VrdxHlQ zkRXr3Rr>gjY~tqtE!FqI;T^>n^iyCSFxhAZI=jJDfc6pKC+F8bxu9V26eoGw7be-K zof4i-Q$aKPd8j095rM>~t?bUY#Hwr8Qn}Of>G^2qwqO?g42E&2~NB?2Eu31$H|B z4c;#s-xVM}(@N12d=cCg(2Q;aCW*hhZY@m~z~xum?MfKSWP z_QbM6^~&KcH(mDoW0|z;DKlw1@jV+O0sMy_55XrCkT!0S!K z*STZ|$lJ*A;>3&uw)rtLKZ2V;^io4#2266^(vUWBc|TL*{iL=jVwW<_P&M!;$-}9M z&Owf@6gnEcXacnUHOnT~SsKJ?MxtAcFG-WA6UAh)l4H9as-? zmYBsSYJw*NlZWC#IIaSI5Ug2kn3GW7`Uw0SHw5C?JN zz$YLsy1#FakvfK(z=?%w%14YQ=V_oHMK+n3$&;B=k08B-OwP%1CNv1tU49YJ6G)OD zAoX|o(Fy4VDROiRu!-0c4^I1m;eUI!#gh`+L*cZ^eV)R;01tvD{>9rX;s9hiImd;( zXN$_`8;=Gi3(}GZ7z>^Ob{(*scQJHzPMe^#l6gEeZ2zc_Q}Y6n2mPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHFiAu~RA>e5ncIt%RT#$iXd{G{ zXn~E{Ri-JG-f1~PLH+}lAa?7ilqRB!P!tbn-9=#JNc0zU5hdybx<{P?yE99REH6?= z(dsTT9k;*doAv7A+w1V{Jv%AbFFbo4-e7Wt97N@1Kl3@U-v*yCu`qmG-hIN zId~k*27N$s8H|F9V5Fy~=MTdFhEVC*;4M%Gw?IzBse=Jv4ZQ!2!TEIX9{3BiD=I4+ z)9-5waJU})4t%*m;s|&Hya?ujX%31jPdahL_2oK=b^m%JaMBA7_@0T6f{ozesud6y zybe^>mq8M}RqeFI!|+US-1GJ~@oivgONKnM$~qgeWim`en?dIUgX(#|^6I%Io$`RK zrNAEzHKKDPfiZvDoF+Y|Q3}xSQGV9w(@YE1zW+V4qKF$s|Xx5 z!XJr=Eo_WwtF+xl^E5ea&}-M(4`T8$ifO5apx1PgFNt=i_P1CHzb`9Jwq+dm!MkAO zMEEPZ#Ay3Fy@kaXyo4EVZAaZ1)*=^KQ}Lkj&@ zjypy;H|7A{Q$QTaP>iR1^g8VR5fM3-;x_3h@CdMr*^wqfDFf~`Ao-!BYD&U6TQD1q zt4+#M2D~B1y-656+$NREShAnUWS98DG83VV&~FKjsf=S~EI$;Q?*~vW3lU-s(0$(I ztVI%`?)sAF#)IUqajqm;<4WIm@cfB2K#vg$>8(tRu6*CO zU#C==Vgcy{HAx;kvIJ2luNJ#R>!E45$?FF?m?YvpldeT!_o0G4{_{zQuelYHMkq6u z#}n}kK6awt10Dq@NPkB74UoJ5G%_~gJ1FzL6d7sn$&2&d$Pq^nLs5 z;VwTmg)ZJ@)M^Wf4}0lkl*%22u#ldcOZcQC|3d!xWWlgfzD+J!Bpc#fudm7nS=L~i z1nS@)WHVYaL*Y7*Xve5>=(J=%N5-eF^4Y6IYz@f%=g!F#!q;59DZt4Tphx{tpe;1F zh{X|i1CZ^Q$Y-xpT3uq?=6sCzf#h`>{bFz)v@0sRsO+7*so;t;syf)=SEklti@3(3 z(|!CyO1ukX;BBxQ6oPIskr80;gxkcm`}_!EyNtHa1>k9*(bpo^^}8Q`r-_@qLu8gq ze1NXXwZqEZ3o)#DXs4&1c}t}w)U@$?{t#*Z{&desASNz23`~9|QcNep=Rs$ll&-St z%nPALWe(7sH#rojW2Gz%_>IuVgC~GZ9ob)7$xx1jp+Q-5qE8N(*XL~->A{=R9 z+wLUC5}leuU=w%==q9QAyr8)9q!Y(ZSfYiD|0dNfH>p@P$5%*1?19C#r-is&Vk_ze5$1Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGrAb6VRA>e5nahioRUF41OeuF?>LmX28efI_8+PL!{r8$pE(f&yJ=r0A%$ z>Efl=&-d~C^2ftD&+UCiG~OS4=iI)(%elPg^30@3ed&)te*~WE5g2GQ`fj&78+*&a z0x%y80?F^-I`|Eo9T*t6L;7q8LC*&}KnFYkWg<=o3C&@~TstIO2L4r?7FtJAsp_;DGl`{yNwUW>yVAT(AX5 z*UKn{sa5UN;$e6;IPJXsO@0JSuVu)Qr5kL>mdPnH+6>wg3~J|rNGaI zI?>)tV9YO@A1NGjQ)D1wsfGs7( zQ2)e6N!J6D&2@w5m5*Z`dM3lQ?V;HT+B!804=LKe0Dpk*KynYKO(*lWK-`01aw;&| zblBYkl9MT3v>t^yK$kAbi6|*l(!MHVJ^8aY#fP%<2`$U5PjOWbV=VCRlST(7H3ILV zKP4DH64F%iYOdk6T-g`%+R5{fF-RDhywoD@Zf%^Nd?YPV5v%alM z<5-@MD|_G3^G7|4i5?>+dWc(0k&ZJF&BEE{Y^{lrqH7E#9U3>m6fnm0uZ}6J4z4)Iz$%r4oFP3AZiMnY z(zk%l7ZV+jA7J}mtH`I=);9Y-cmQ68dpFNXmQn5iN#Rw3_H`NS@t?~ii&I8vTLP{; zre=TF7I1ZyZ+4ZCQIv`y6)?<7SlwPOd zTmzCrNn^PNxQ8>1Zue@gDJ#;Z>-3GlQ4Csw^##Q}!HAORgNFJcun)Xa)dSpl;Bzn( z)1iJBF!?mbsZ@srt;6wPNzc5cl@xm*;o}|9&XZDcU~D5W(JN_T5AhYMVtWy=r6Zpo z7b;Y3#L%d$1<|LE);obs1^-jX_yz0~@j-9Y%Gm))!ey|o~S&BoA z;%;Dv9ogCvUZ#g0$n?FrO?-dG7(4I?V#BS>w=2jMqPWYECJ~jtFH&z xW_6dh2Z`?T{-1o+ZPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NE;7LS5RA>e5mrqC)Q51(AvkVs^ zM75|^K|v8kibNPli`unl6D^9UHc8899k>b+T7(NF9_6Z{MG!3t5=o&JMo}2%rlick zY!MYm`uYyck%QbB=hc00t~3XJoOAzw_q_XN?$p&4R%D>aK#_qwGZ5vqc)48Oz}n~0 z<_rvP=~IfL=y!&`wdukJ`cNfy)kRkCs;p7ny9(FY=jxx^5fT{EzY~{qgbvVVvwoT* zG$`YOH#W8veKzN-6g;#70^NjO82Az5b=n@Z2Q)(W4E%fIjX^_OIAFUC{CDC#wms+= z*pmi+f%sU^z!nbJcJ#|^;IeHGItF?Rnl|t^g9f&6K+6+n%)pNlH`+eI#(>Hb=dOYO zK)k6^U@vcCfnnhRbQHPfEK~mmo#SmfjhDCZC0vihn6!7HS5k1;9OEV&^?s^=*^RPT zpRP#f*I5RbK386tVv0w{}jUwkOoccwyjbA}8XVSkD*}J%tVeJB;*Q@r3wJya9O`J>sb%cloARcw zPXTzE(k4yvAuh_*5|5Bjk>S0#b_byzp^uKXqN>P1k%1xu|4|1104!zjV9lCr00000 M07*qoM6N<$g2V2J761SM literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_stickers.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_stickers.png new file mode 100644 index 0000000000000000000000000000000000000000..050830b91215787a6089796063769ae1bc010c42 GIT binary patch literal 1273 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGV@X6oRA>e5ncIuaQ546|7?)A* z5AH9B@Pf(pfp}58V3fie50ZbugAy->XHh~#JW)o9QXZ7tnp`4xqFiezayvfXGkZ1r z{LXLxF6W$?@o-js&%UkoU2E^(-oM}8`xFWdX^cQ)1R5jIpCize*Lks69E!~>*E^A{C7=maJ|$m|2t^RvZUhzqm>ahu4e2CjO6K+~qf z7)c+1x&A<)n`tz zyyvW+WHzd^BL1Jb7&=4LNh@4mSjmghZ~y!}cWx(!+$VLwwg>v$_m}7cDY00(OWto% z2RyZKmPb4n+y`$#TUfKZ1)cRyS5tIOihka&dk-DtCTDtTD|0B_GDXrZ5d3=5Hqz;k zl;mb5V^0klXPw^Pp4#$UO-}&wLD0?fD2J1u>6N2dwMoaM6^?;ch)KuC)Rk4$)B!eI zzhL`V##ku4i z*_5EPIa>{u1AU~10AGet&=YO;E93Hg-T{K&Kp+Req_}|c*7a!z2wsbJcO=L^lz&F* zzEQpdbpBWb>?J`qqqw=JB)A4>TMV?}>I5s2sA<<1*q1{T7J}ejpSG*c;C&KzY@0Jw zlGK5No}L!mUZ8_|nNT+vyaXniMyZ1GV`p$TRXM6)o=DF|+pJ96IB?z5RrV`50XBgJ zK%=}Hm>e;d1Lep<3DiO<>~+3XSRu=>m? z#&)35-A}5ZKNjrr?8wH7zZVMfVtK{0o*YyRHDG+qBgl26#BM5B4Yq@A;2J1N$e&-2 z;!3BkByk4#c4c`C+dPu?vc{YRc+MDCnkjnPazAqVe@W-3*~GSE*aGTutpZP`4xrZz zE&`L2vB71nge7{hH7cvEuLnT`@!p!7d#yK{J}f~x?0rro{4Vfa;*oEV`G7J z#W|y0bKa&6+2RL~dKQS|s;Gk~?s8X`PBSW$V=B;_555D*RZ}6a_q<+}{@aFP>3p3z z_&nF^r*N(vq%Y4Y2)aG+_bWOmEd|<5YTDVs=?3}lKs!)ftNVK~*~`av4nDC@ini*7 zk5q;zpcQB|$AB!NQT_zPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGx=BPqRA>e5m}`htRTRf(d?hNT z;h6b|$c#`aA1L?;A6R~={NN+;!wf=XhEi67lA(wceo#m((6J)WsEnv^OdU{42Sbq_ zC@5JzQYg&_`Alu5-+y$?U3YWNoO|z_neoG2@SDBY-fOMB&OY~?z0Q=B6s5QW#T_W_ zKx^(mY1)g|)zx((<_wq&55iSA44X;*5EQI^5|mLUDnupPX}ZV7ZWyB2F%v_E_fUT&dOLa(?) zn0p3}fS2Pa&&TE`XQaD8qA!k+%(j^?<$x=fTTQ zC{N`b5C{Bv!26&(XQJohBY2>Yn2|mNn*qOrm(wV-p-rSy9)rXf4AtP}63Sw@Cy!9s zrZ|s*@Bvlew?OauRE3z&!LQ)u7|OJ~7Q*2X_yWA>Hm`@+2Q;rmVvLEepXwVBzIwl7 zY-o&IW*DP#xDH;bPzGhJn!m?-Wv~u(mY8T0UyNOy$w6?_tZ9FQNwE$sFv0qd!%pxr zEOKcqRyeCg^qc&EMlMvqAi2Eka(mB*@JaS`6B{YKYMtKN-EUk1Wv*Z1FW{h?*vu6t zKQzvvxw_<`!>!uIKj-?HE{2`p7?{-3*#r+~tXi(ex++&b1?AzTA~p-GdciJlO47~qA*CEz9F+c$Z#O(sAVs%)0`2|JeCgnMW z$GQ!uT=>I0@3eo?&V_b41xhd?j*7c^@E3SFfl>j=<7qH?At7Y;G+rHHA%umTj(vT| z6!cjtKbQ$e!Hd4=UWbM{i2itIFgH8HMl_t-+cf>|uoA9;m;ERc%`TS~`$=%X2cdrz z-hq292L1ZYp;cXG@`}wTws?$#4baz&)rSv2N4uA8C_~IHs%3r{?C?(X6{iv!J~8Rb zPTvRJ6o+;Mm@JHn9XW=F-8$|1C~t&55WWU4dgX0|{(-Fu#7`i6C4R}+V}WfsV^#y% z1w6r+$(!E3(LNq_0dkJ~?J=&~yGI62lxPj;J+6{GO#FMsvNpsLVO&L=iCus;%Ve3^ zs%`R{gp#9%IAe)Eh4yV22>R`ghENVMun3M;V(1iNEb|ReT_dq>6Qbgz zI>y2SK!;U$P^nxPVT;k92tR|D(P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHQb|NXRA>e5nOlfeRT#%Tk=ezv zEXkRSB0|Za%S%~d`C`2ky@+5pqSCxTQ_w>YCKPE8Jq9^ezVs0JWLG9Ik3r9YMv+EO zO`}CwP+q38)9=4$eTQ$p*?XU}&)G`B`QSfmeb@D^wb%8`tXTsZjKE+7{?{YWs5ARk zt2Li^%fS_37z_c?1UL-F!RL)e<0$2SgGhQ9JPn%QZ_tTk(*z^HI(X(gL*w(nHgFvD zO7c~Vd1tf-G`J4@0z6H^jDd|{1y~H`Ca5l%bh44Hr=MZgp7u`A$ZW8~w@m#oSPw4h zHUZg!4M4u0Mqy@m8>f;Tf#-wITx%z(Zw41s3gnFCn_?)I(LO5L4C*5SYUF+L8o68R zYJphGfd3lmM15a^V1C-{hhJ1z@)k!i!2w`2YP!BkqG`bzX_RVD-V#)7;J-wF3!7lt zDs8vXJgsfoSkkei4NWIo6WX16-(qoo1sH9Pjh!x@24Ap7DYy324vsou?U2%E?RmGU znt<8@HkFh^^%EN>T@Q@b$0SgE44wl$cTB!1#z#5vb?6z5M14md&t~%0sX612LUtqg z4IBZw*Uae{G#OxfF3OODuwN(nr_k(;1{LMioR)Xyfe~LPw$B2<0BW3hh zP`(TQX^@HC19k;@^bP9lA!IV2lgaW+KHEE`BJWz*+s?2aW{9Xe}@Y)y{M1HcZ) zKd4`2x>%yS5E#7~^@ThhZ@iHs_B;3e~- zjPo{&k9;*a3LdfstCsjaoMNoX^F_A=7`>Qhb9SB(nI7OqntO+gapghk*YiO4wocu- zitpQGr}Z*p*Gk@g-si5xqD8D<4~&*t#g{a`zn|nS7BMEk0pmmI+x{WwidjZQudmXB z480ccaWw-j#x9coKK?rDr% zi}DWeEYQN&8Zvs#CxlQ}`HokKqBWpcyTJ-@4tNl}4m?dd=345)6G^6{f1LWS-~`YB zXr7ndDo>*Kq&96JluI=tfgzx)tZ2q{8kyf}Go$oJU(BYTm#eP3R({5_T-yl$zw zB#M;7Leo_$aonZ|iKabhkZBG0X=HYq)0*455MBpv0oQ=+JfU0zB7Nu+L%GEnyzF(A z>IBg|)Cnunt#g?V0DluW1Uy~rZDJk6mEM^8F3?`U)NccJ!|m@$sm2Mm78q$NE%Hgh zp9lOCu-gu3I<==wYU@g5Hg%}BY)$zltJeuMs%VMy(?{&Yuqi3K?ZC8s9X}=irHiw@ zdZq;)1l2=ip9`)p(VkA!`|1Gxnl^sqoA9;+6=YRWOh6rOz7v|KnmXDsq%$hrF)+F} z8Gc78-z~uAJk?ecR6De~?F)hRCH!=P&9+$mQ2VK*yK zWN1VS+jb|a8J$YyJ9$2mp`Qc3N_M_bta=t~QR7iggW6)Z0z2%ewrNw2y}sU#w#8IM zzKYTNuWzxTsyvMkff2A5_!D>xejQi|o&ow%So9D00z3su*Gtu0`nD$_E#_B&Ju|6J zqY1cadw;);*7{#cONJ!%tH$HtcAy>Q2-pL5a`!(*IiSG^3`U@)5%?FQj_Vp?%m=3c O0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHa7jc#RA>e5nSE$iWfaGqW=Ym^ z(WZ-q`BJ{+DzY@vKLqVR*9#N`u_6lUABhlynvoD0{iD!}m9COxQqg)5=CD8PJqs$W z*^4I5p^1d%OR4E{eZF_k8E4mL_WSL3f7^l`_}p`z^PGF0bMNojbMJFEWXPZl-hqPd zKuJMob8<&V$0eu=D2KmbFYGTVDLIWEctXMF!W~c#tq_w#I2%B5=M0FeppY`CgWn(@ z`GsIzNWs5$>_+62l)-B_`6Z}KCHb57SI`W*;XrNKkB!vKNC%ITX{6N*7ZcN z7l1^o(NOcpwEE#YkZ3B6gJv}%@>DEGuD;k~{`zq84jwv3U7|6;-WPk%p)frZ$AeZU zJbkNwBavA^gT(RV)Q{kQ!a1G`4?aSO}9H?2~6!_B;DyY(3_{; zRQG^#f%qNx7p`kYg$2K+;{X5v07*qoM6N<$g102me*gdg literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_what.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_what.png new file mode 100644 index 0000000000000000000000000000000000000000..b6225d01b9580722089da6028f50900c9e3a573d GIT binary patch literal 1766 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NIP)S5VRA>e5nQLqnMHq%#v^FYQ z0TC(G5^F$fybz+6ASlL2Ad1nbAx2{~g`g&2h$cp@Bq}XYfAGT#RDT$a3W+gbNW}i& z;3ZHmD2fW+sIk~0*C2wWNRQ8Z*eTyR-Pzq!4pn2{c0d1 zci=yL2Z{^X`*b=zn0OOm1eC*YklLUfw!%ln#l^cx{~e;!hS4xEKzWs^PByZ&+R4St<30!)DS<}Y zGWm9x4W}pVfNbGjkgwGeE=rQd$;*zwgW-MCS_k<$I5n?8##p{V48?L~1;Y2{) zdE0s2xho3Q0qJZUjZ zhGpg);Rm%)`V46Hi2_!Mff z-RvsxsUUv?Tmp)F7!>;xXvTI2X%TicBx|4)c0m<&dr9*b!4`s3og#2i3eUkI*aXkR z9dH{w3Qf=oEuh_4J|kc)gsGFl6pWXxME-Gbsy|X1{?|JLc&qUr;bhnb=W!?YQ+@&Y zRnP>_QuZBXnuQDDLrB9Im;tKaOZ}PT7r_De4K#y_TM1{wXxIniu-}cnRyMV*x<5g) zprc4~5k$uWr`gVv0?oh-7@#uJO4tF?N@o|9VmC1G)qA8pp&F)GAFj3OInA|oiSl@+ z0&ne_-c5?S1%aJQE{snh<8_8-QKMzYTLVWiOG}6l?i>jF(MkexF)$Dsr!Ls*7yfBXcXg*G$(_ z!PF_y3K1*pd^aP@7rQqV6#W8PWxS$(j0^)k8D{8fG_!sO4sBtMxnuG})u_3e~j z1l9Oxd5)58JM`m6&sLbUmLC_y^_%9c}Lcz1%-QBOPfa)lzpS$*am6okHF% zdm7NRpiZBVi^(_OzcVO{N_6v_@*03$Np2;=EU<&sF0F&z=al~nhu{xb2kSxamUdfh zfMY?Mo60n>c`y_Ih4|N#k5aX%R6EH;aD9EbjZEhsNe8zlV7o3*8=Rqtq;_yU8lhf4 z08EADU}ZZP=4UsuK|Ktj3TP!|TOwZ}ds2M{x-I@LUkq&YL9g?DskPzyGFS@wj>xLZ zvD2VkJKAUR6VCeG#;SYGrtpQJ;&m65>)~)Wya6rXr0-oF%iYfITq0BK?O|?Cq;Xg! z0n{PAbWYtnAq9^Fgu}LYjF8WK8}nSO@hxw9GyyTG|lQP6fzedJDw-yqna07#ozq_C*~_vpx{ zHqs%kk^t{23TlkAb@kW|fXiV8IO);4#@U3W)T{Fwodc;hykiqV+})UvBog-eMEn`7 zbbVcvKlOTSTwC%@K}nQPqB?@?14$nuvBFMw->Her&EQ==sncpRAKWufHq-h1HZ5Pz z2P0_d(J|z8$uL z{>it8v>=KcfLfqq(@0i;dtY?+Ukkp8t=tgJ^%m!07*qo IM6N<$g5^anF8}}l literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_work.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_work.png new file mode 100644 index 0000000000000000000000000000000000000000..f296d094317127f3a2d15cbc9b3b246b4fc92d01 GIT binary patch literal 799 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*5QUVCwXAaSX{| zeLK@PTf|YIEnTG|kl#s3gKh7uIV~K|9%;sXQ4##ZUAMqqiStE#C!^?|ABCTuTJE8@c43{sb|ubE#ID=eyg|Sp!fNb@V)t^rSEgz=S)-e7WDwaAJauo>=w}P zN@APGS|BF#sh}?Xk7&ib=Rc$S^YFf9q@42e<8J{%Bb3kaVQwu}}R>s~LiOm0x9b^O>ic7aDPHzU}9J{s80oipv{n z63))M;p!0Gr&-JzkaAN)*doWv#`nodp_C&z)0y@}uYY1)V0lHjq14Xvim3s2pT^B>H%m{K#aVJa+J3+)B6X5{^ryFNj5xI90= zulmQWT39CERZKud>VcSmuVLkxbF2Yxb_sn6Saem7Rk%l@;a#fm@>&5O_Y3K&6~Z!i z0vUe2o^^Ox_okPIRx2If#~c*=<$JqmrH7gC0l!uD+JPUfe1KdHbKeDzZ2Dw>*D;-2 zI+6dpMChIe(L1-@*g7|P$`13XiRYZ;6DnV(zB-;Lck5-?m0y3RKC9Di;%mAPciE+K~^?FXxT*8KZl#agzdt3H1IkyTlq$G7NCzck_br2GTC zf5q-Bv3*haz9zz?@vm0Rd!dY5PW`4YB;Lk~JIeo6(OdqcI>GCw?)0vh%Z0x*?yWz_ z*<0oKo1^B^?|o7icQfg&Xn1k9XwJV?-w&IIJW|?lT{_0i{9>Gh-D4?#4!`E~i^2L` z%QNP!^2}UtdS@%!o*j)o=bnBFpR`x{?(0ie|IRO8oFn;Dc9Kr00uUyg(f%N9ExUp1 TTbKJHP~!A-^>bP0l+XkK!52^s literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_autodelete.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_autodelete.png new file mode 100644 index 0000000000000000000000000000000000000000..a0875f05d2b827228b3efe741e0a2049f92edf2c GIT binary patch literal 1246 zcmV<41R?v0P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGNJ&INRA>e5nOVq9Q547THP1pw zWGW$JK4o|yUJX%(DDpkXgJgQZ1IZX7FUatKLS9Iel%zZ%l%#m@p?o4!hRi;{m3zLs z@49=Rv-iE{;^D6Pb@tkOt^eBh4EyeLZzfZ<>KUk>fz;1HLqkIrdO;1eO}#+cf=seC z%!bo&A3j55^)&jWT{9IuCN=_2zz2x4t!6<2hr%^@2-~2mIbQL$6oiBD6MSr$IVlou zsifEVBh8qKwJ9_Y-l++=T)BM?KudE%_-`x;$IY0Ev?;pYQaI|8`~D2fhvCr9H3`P# zw$ZlV6<>Bgm72maT`}j&*<21CLJAQ-6K;aoZRin_9~6uDPN`zC{q%JS5>vtCw^Ci{ zx)hjenfO=w7N%P%uZH#_xB~mYc`N2K94(Ru!6z_H{E3c~vb)iqY!;(^wq#L~&nYo+ z=aww!k%;~(OU)@Bsf8hkjI#*sER0Iuqo!Q-AFB4D;7SNwRU%LD3)b^sQO^YG>{7K? zc&7ddBe}m45Vtl+BqkWGSx^VpA*(~_YXJ!U{0$F;3IiB#%Kf2EZjl z__;?~cnAe#2{UbPxJo_)A=#~NhA*Zl?V0(glv;?kg72!(-#41g>|4Z;aK% zq&E%`C(q1Ri0nw?psPWotPrN%amCvDNt6{t9(tFpvE|wN5Lm24p6R$Ix&vQd+E134 zxGvdM_HhJUrGJ-W%+{^HcZzOh+Xv9MOm~}dOy3*EY#;h9{R^_$?5~(yJyfqcl9ydB znY`zk_ECu>x+HHh1!&7cFe5Qh1(4GmE`!)dNZu0>)J>w5^;Fu4F8T5-orJ^S_0YOR z$(Nmh-wP9gS$GDfEpdte>;9r=fP1uoNnKDAo2LB#+vU_xHBUcnS&RGr%~?~gJ&b~) zl_zl?B+1_8J(zYhF)^h8ipoOrDpy>#@x6nkN!pkbhz_!nj0hGAOrVCWJoloax#RXg znM{Vn4iKG%Nbezyj=^F93Ft43iW$cZ0TTI81Xdd&QByW(MGt>ItGpK4YokKBqx|mF ztt3?vWnZJ;4Mg`Wv?)n6Aqm|+@Djx2ww;rZ5hHGg&k1#&o(7pF$xcXt?&q3Hr5m;s0Gx*QV4xv zGNm#_zls%%20Bb;6e&YM9%i8voMeZ4oMY9hXP|lpDsTpV1D$F&z>flfW&i*H07*qo IM6N<$g0OKaKmY&$ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_blocked.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_blocked.png new file mode 100644 index 0000000000000000000000000000000000000000..7cb4ed96f71e32e1a5588ffe25ee828fd065aec6 GIT binary patch literal 825 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*5QUU|Q_y;uw;_ z`gZ2oED=YM)^wBV(nPVw9hb`unyq^$aHuuqFZ8bE5bvDu{X%F*l90z74#jBJqjz<9 zQYJ6(KKjx6g6t&Et8ZtOgns3yedu%c%K4qo@2#4(?%lhRsBGg4X$#IeOqP6ctjJD= zFaN+-4jYEe3CkEJX=4|s8{pQ>c(k-)o zjSt>vRm6sGP5!fL$7Hsq=GPDQ9{f$$kY(5E^b8u|U2}-Lokvr?M z=P65Mm#Mv0)tB#CCxTY(;X81vd4;^wv<3eCuaByCfA6{)v1KpUi^;3Jm*yKYY}((m zspkJh@yiRcdn-2@GdH~d>3Z&s>3N<0d$tZwtZvIRYIZ9)-AU=`}uRk<}n^4i25r%d+dA1F6i^UCJZx~J9BHjLBwcy}-D-`HdOfj8pY zbhrF8r@03W`H!UDydJRca@~f%nqgzBJB>{%rU#rn5_Icvb?|qV+D-NAuRPLPo#v1nw}UNhRkh?%{>=;8{dVT6c2!JV z5Yr#}Wrgze+y@%>lBX(l#PDykQ~npV<;{H6rU=I+b2wA&dVd%R$YfY9y&Yqxl|NM;y+kWYOezgVeqWsF4bR#39_boFyt=akR{09!p_ ABme*a literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_calls.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_calls.png new file mode 100644 index 0000000000000000000000000000000000000000..207eedcbe014e858302e08d220a19cb480f1bc51 GIT binary patch literal 762 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*5QUU`p|HaSX{| zeLG`gwuqz1v3!0$r4=14-7j2SSOPr^ZrotWouniXa763it5qd}Q$$_{E&0elVaXOj z7v4EanLI0lGq^rVac{h+q{4De;_TY}jj|GLk>7IXq<&A3t2uLKcmA{A_jd2zyLatX zrxrdK{8GrSwDP+}U;e?p?0Qnwbw>H_fnV;O2+i;MX<5K>DQRcbI$?JUJNCMzmgb+X zpVC;QCm`Estnk2>!{VOiB&I5-tKLrY!e=dMc<*#{*@Wj))pQlaR`78HC1`n?l5cN0dd`c*T``=ytjnWAQ-SH=0bC@4sD>!O&vQ2kQQ37L0qh!`y z#_R`;d)IF;O-es#R&Z2&(&VT)KXX6abS-%@?aRJH?nnF^w;gWr+ne|)M!)58e8qEa z^YyF(!PBoVcPb9LHO0<8SLD9e64?cx?__;BpnOgDL-h0i#WoYS-j8OC>QD-sxjNlt zed)Rr7poah>A2RgzA}6w`@!>RpJaXC&hz)TJ=y(nLZR>%hj}~RobPO(TyT%2zwve4 zDZMwXE6gB0F2&*1?oJLc))7?Q#I zcE(;WW=E0M&7J#~w%*_r(=wZ;)Zrp<-?@f${()2HPMtaw=E%{+@rb+Q#!_LH;Mq=p zj?2gFf03|m;@mTD-l#Q|KiHsd{e52b`$l(HMx^_C7TZ2*0hdSfA9Gu z?7?2K^`CAo%J4OL=zN+*ztMf-7XI>|e^bnRG~Rii?$z^%V&PZ%$#8F{qDx}@FUtnW zq{b)JiUl0+&!0={o}}^0dq2B@^BLs=b(g*e%+oI2%;{{}_vJW4T8E`eUh4(J8iUz> z!XYk(@xQVejF0FznLFjEFDx=m*Vp&)cH)=gK5>_+49b*Tmf0H!I!s_qY4^uQKkcb*o~kVrt}j5w3CJz=IOo z#sqF=)-NnfygYvX#Z37JLvM5M*~b5~%fr~=YN(CExt(sa7|WQYial+geoa2BY7ol9 zuc~^XqU>yPtfJMtRfh9bxzopr0Oua*NB{r; literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_messages.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_messages.png new file mode 100644 index 0000000000000000000000000000000000000000..b8877f0fb8bb638cb431ab687cdeda9c56463c20 GIT binary patch literal 1003 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFRY^oaRA>e5nNLU+K^(_@_U}+> zL{XGPbtsH5QVH@>)S-k-Iz*Sc1RnApcnAriI&_SvLy|<74iOps^H>K-I!IuJlwFdt zND9;biT3%5`xu6qw~zOB-ZR)AeB9aJ%>4fC&hEUmq9T>F0%--(3ZxY%q5_#B<~pa& z%*@o$Q4eciEv$xd_ynWy7M^7?ncp1ehY)l#bioMZBNGgI0H$QLGe zz_OAhg0mWU3Q5Xmj5P;OLQX(c3n9}Oy#Nb>B!c0SASa>a9uAUC0)s6u6*_Xmepg~w z0iz8tX&5h6vokJ<*!KXDR$`Ln&I^G#?e6|%_oU}2Z9KkEDMQ~XSpX9s( zRDUrOM_`rDK#BARxC*^4UvXF9;5-OkaUXXDFI`*$$9xk@tZ(IRSmN>-mq3eaQWT0h5pKSJZIQ1k@ z4?gLkBO5U7Jz&4&jzos(tArb1$`B{nfN5)grTvgk&PVq0I%4IJ&l37wwh?r_#`pn8 z|3;%<&34Ba?Sp*MZI9P^t~D^>nlPtx{TTUUjF0Qr(0s-iCM$lJC$VkHu*Fvj^w&)T zoNt4l#(3RMP1cx;M!%ZA9Q7{B5P zTvtUOcnkSrr%#j$T)()&2@bY{x!dG)Rvz-VMxHsYhjw@b@8K8Nq9@C9I0sFT?B_#Y z32>yXZzQ8MuEI{=_(;!~l~4=%wWS?r;*xVW8hOKcBW?X7;vG+i50O4SrWHslkX9hA Zz&~VlJyhR#<}UyM002ovPDHLkV1lcgvT^_b literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_music.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_music.png new file mode 100644 index 0000000000000000000000000000000000000000..83f79b5a37af5aa11747a3695992ed722cb1ea7f GIT binary patch literal 892 zcmV-?1B3jDP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NE=1D|BRA>e5nY(V(Koo}8Kt%&l zI&LqJl8Rj+8juhm5qOJK2!wbCD3X-C2SgAN5GVXLgP~ zvnwPY>CZTxbN+L&ojEfZ40`D+&{v?Zz$`0}#d4nK`5atVzy)v;94o;vcwb_d@d;SV zvg|YC?1jLufoI?s2o>o*1&cGw0OupH4Z4arhEq!fX9vM**Qm$XuZTNoA~-k-*2g%H zb?dQwBuPTVU?*0j9v=CKn*@YXv7lGOA!>U_c15X=Efdr$Z zTv@e6YxL+}l&ys8d9c=kqi)i^oi2m0p8b5p`z>%A?A0S_alKho!t*0!OQ}Pr7`rP^ z7|y97i`^^dZ0H1))1lL}WjQpyiF!n?V-+2BOiLc&DBiJ(GK6qi2U~COb!1{y+bEPt zqe^MT(#% zt^=;XoA(JueZ97c=YjUH+6D^RjHsViORTO^jhX(%^o6mPz5;y(`U?E#75EFWD@+5) SV1U2?00006gB0F2&*5QUV4C9T;uw;_ z`gVq`e~6<<+s*|lc~?%k2=j6txWzd>PR16$RMq0t_x-I-6F^ zW5XW3fbWypMS-=J1?mb@4YVFLCkVwF$zan6H=7V!@IyQ4S!71&$tIVtC6N$sRrP6yi4yDxX=GA#F;zSuvhKSoLQ zmi+E5wS57y6Hn_cob;x&??UM8ZRgo$nKf?8%{ee@@p(Zl>*F!M3YmAF3U4T`VPX|A zoPH$Ircpj+&vfnV!#iK`t`YuiCc$3cYja9k>VM2r*?&$Cs;q;LZMJL5tvkQhU%Pr# ze#Je_a;w=KVxI~e{{GEux%OcG>9fzf*GyFWq?^39W9fS@mpY%w+pMd%rcPP^FYsu! zTjR8=QTH-=8<%^fM4t@~p3hrzz&rneVs_J}*+;f*JCb$OW9idf@3lWz=IQMe*d4R_ z&QtNFc44wo=avXesGb=v8+X+wZr7yme$C4j!n=#^hKK(4Snz0_Sn6^m4l#$B(|5DK zIPa}<|CQB!M%|VjdxVRk)y3nS6<%<2@4NZrl$+hMr<48SZY(|2$D6eADAy4%ob#Vc ZhOuaNwCt>B7aoGrsi&)-%Q~loCIJ37RB`|S literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_received.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_received.png new file mode 100644 index 0000000000000000000000000000000000000000..31f4cb8fed8a7ca812f7d41ebec0002364f9b65a GIT binary patch literal 560 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?oo8{@^7?Q#I zcDk*XbD%)$=bj8fgSi}09#OfQ7-L%_cCl>rOpX$NAm-A!`-E7Np2C9GgvAS*dhPZ{ zb38ouea>uaVWl$%6nEMeKRZ)tzcbUs<_=@|0oelfJB{^k92TzKt8=>4;&+1bqq>xu zIFX~lCi^3trFO7|7A{>|<~dtnpC51f-6-FvuajJvuU_Q|+r!8lJXzx}m&(o54L8>} zG_LfVQpY;!jnR!ga}J-ZT$ZM0|M%m1fl@aw^MeCeS*q#)cIJ>98`2%B+@)MaS*TPS_pRlW7yTnobJ)|pp zqC$qa4Tsf^^z(gTv7vG;xsAJLspUo94$)oZ+jhWAqRFDoXUo>tGe0Pnh~8_^Tsd@m9IcwAwQgYIMAPu%lnPF&*Q#hlEs zU3Cdp^)ZtR6F)35F}S{+gSTVLQkmt?e=b+Pre-p_XG4LE%m6mp;d c{BgN4pMCSqZt=2~t)STQboFyt=akR{0PTF(i~s-t literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_sent.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_sent.png new file mode 100644 index 0000000000000000000000000000000000000000..7ed2ebfffb6281be99e6be26cedbc0b77619b626 GIT binary patch literal 626 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?oyW{EN7?Q#I zcE(=6!v-R)(sk+!nzjlpEjAa>wzux!bgN*Ms9=lYjAK+|QTAsLezRe-LaDQX0^=j~ z8gbLmC(}+C`U!_#zZ95r{QI5a{<&JdE0_4n2C!dYEM2gIuO-n!S!2~cmspPbO!*H) zbJXsiqTBU-6 zTRRl5J3K0D=r4|GOP97VeLmkLX13a6HVIRs_r~iai!Xkd=VvUnWxafiev?9l$+ORr zK{tF4Meh2x_LaT+iS1(QcDe^nn)N&GVwO8wvgnd*!KSmx6W%qr8_!*_=|qcL`+wD7~lqc(Recrfn{knp_qbHsv{k7k{jdcdg;b$%F8-3TVe%XjPbQPPDP%6^}WiQ`SK2` spIF7Y{Yk{<FVdQ&MBb@03jsm%K!iX literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_videos.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_videos.png new file mode 100644 index 0000000000000000000000000000000000000000..94c7081855e08b51c0da7b5a54c9d5910c0fbf12 GIT binary patch literal 616 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?oyX5KO7?Q#I zcE)~v7Dtie<+4j3J#t?=F@TfxV(cPey^AmZsQzR6-`L`Ho{e+vq#%zMu1*Ul3(WZ{ z`7S9x-R<7F+?*rTC(U<%{#JW`&-b}ApFCUS;VT-z8p0Ur0HPZIuXfPMwe`L1n3R4{ zWrb(uk-d%C1!BiPCNsuWE)==X@_m8$?&duzYrAe38ZiG_B9k6teNy|p(VJG4;B%d~ z{PtZxz?Q+7eB5DA@R~al_rUh3%pHq6gN_vJ~&>HP+uh`gPTtz>I-gTH5HFx8! zhTv)OC1HD+-tYYuRmyB$zqc_~>cz{xfR|ha2X`)Q486b=%jwB{e&I>mJHBwy5~g$%nRYCb4a^@pQg>uIBCAEe@AT6W(2vH9i_& z!sh5-XPVb+loK4pAbhr&C8lZXe2YiB)jH3-|E4yB!S&x%1NJXmDl2M^1S5wvD9C>V aJz(bY-Q52?HtH}amOWklT-G@yGywqDG5GTU literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_voice.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_voice.png new file mode 100644 index 0000000000000000000000000000000000000000..f29be26a9be4d7af4160abd9c25ca527c061fe51 GIT binary patch literal 882 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*5QUV7lY!;uw;_ z`gVqOhG?Kb+h(;UwN}QX4YynbdOFvZb$O;LI|>{L(%I4_R@T+ql$5x-RboSkV{VSi zmX2FL7^E*AI+oEi<5)w7+V%W|aP`f*%g^7f=F_WSt2=k*&769<-#d11U#{*o#{mcr z?4RQxq*S^3>Z|s0rX2sD_cz)3OnOqCWnRAUho=Gmnlle) zIeA^#nzei@`#xNCC|%|txUtcpxpY}?`hm)jMyAJ-93~OzxBfro`JgwUVe$jD8;@<~ z@i9NVH~ZO)q_5xCGTjuMa8l`%Rjl;4gKrYpUw7p*f8%9(c<#xDbAiit$2r{=Imqy9 z#U|Ie#@o7o-el=bReM0<&eO!NSs_SM+REOpI3Eyix>1xUH<@&U_^J@IQH9cS8HBazD_T|UbOU?8a z=5H~Ky(wT9%IR`9mGk4tUJG4z?vDzW7NT zK3o@%-#%jhaL2Tjn{M2yyYc(rnsZHc%ghpY3HEJn`>ecedjH&*TmgCGlTY?p%;PR8 z+3=m^!uM$x1sk_E~lf=$0+ZU%aHa?j3P~fxKhwt1mAp)Fi2eK2MYWEc% zu;crGp&&=6H!@+XlE30l?@h`puj+PQoBUMlM);(+-2Wmc*uD;5oX;rjFwy2vWyk%t z)aLb9sl^hN(=8dk zH79Nm&Zunu$Y{gxeP_&`Jz5pn4&hq6&cyxJu<+2kKHW0bd-0bEygIA>rcZen%6qe+ zPVw@t>ugOi(}NVZ9}qbGa?7pLcbGn}l$&nR2!i{CfAHp)?$!}C=gbAAcTZP8mvv4F FO#n-6gB0F2&*1?oEAw=549Q@9 z8{wUI$Us1Kh4m@L8{b(9THi%=>XtuZC^&Ezn*P_AIhUt2u2>;FBeM zRm!~uamOB4o=^NF*_#p4z!ku#<-p3e#^Gw{+jBeJpVT$^KiL0)xh6LBD(C*x+4^#N zH@$C8ZGRQ;(`}X9jq*IE$9FiL_f@N|Z_|Ewwji8kR`@v)N2ZxAIdjuKSQn%(?c)pj zUi#ntOKmOx{``B;m?nS6>R(eUZ(msox-Ep_Nsac4+G#sdYN54^)KBJlOx? zMqR;%Ny`}Wh5w7HACEXIzdrMySyxN2&z!@r%O9E7Jg@1Wd^B0{pXf*VLLVExkK74g tw_i!Av6-F>44f4Vq6?Tp9_$yfU=BO{e)^oE!%IOi;pyt?KN%iaJ0 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_devices.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_devices.png new file mode 100644 index 0000000000000000000000000000000000000000..2aa5e71972219df93eb3c4b256654d181a1134b3 GIT binary patch literal 503 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?oOZ0Sc49Q@9 z8{wG6VgFdfuEXf6ds&x{`g4xQMXF{iDa7!Vb;g&MJJg>Ot{!m*6w|2qZ(nfi-PoaGhFo-T-3Q?HHv~pR=v{c;()*ZXl{2T8wS$keCS$Sfj zFLzdws(-QrlN7{w+3l{1=yueeykm%`@)nJ*>z|PsfOp!M% z=(o_anwKBGywRU+wKn_PY~~rBk{&MXOs&S=i<#4c*n}=NIy^jc=|#iLDUB{A3IP_I zO{@~so>~T$?fd%PgzwBBlV|F|nv0*gg)wK!2Tq*C{-|!E`Jvt%@frX3Uz)@Bfa(4b ziT54LttHc2?b-^S?!M9g{?Q-C2hoBumH#__H7D`!n{M&{KuP}V<5wrV7p!8d=*!qK zN$Jmax3gw)3)d&*K4-Axc<*?xhClG^cfsp&TaRbd32$Vdwu~vHfh&L!7$S4HWEjII W&;GC{;Q96gB0F2&*5QUU|Qkn;uw;_ z`gX?YED=YMw)7AY{ew9^4gr&Pg!vqJpyc#{Q$(<2rN9T)E9Mv0t}9t6u_%E>-~WNr z#i`RjGVW<;+GWaJ`p}?mzfb1!-*ZlVxp22IkiBlzt2?jf>HQEczxPGv@8CMVmj?$xM_*Zmk%25B@a|iT>klh^Ww$WbxX_q>;;U+8Q^Mz@#POshtFZjLK;e-2u)DOZ> zJok7fxE~Z?`y;7vUu@^}2~S`1^XuPZ6LHYrDxGkrh@qa#hN1DD@ywEv;}h?)Y!pv@ zD$UWk*5IP=_M4u0ayR!V-)?%NG@*a%ifz0t2l8jiY!=#D@j{OMebYyV#k(6fnQxrh zU-A2ZvQQ<@w`#8wd>-sSoeiG8ocb_)YoowtjmdnTam>4!CjXS!aqgGt1i#cRD~wqtIZc-hZ*uYFfb^@@*wyQxv$8FS};_;zNmiFz+$ z+>UEKTfU(rYuWc7^Ank^Vhl9P__zFO`&Ajql9d{~Bx1XRNu{dr+XfM)i@j^llv-Ul qa`DmZ8>zxYUdgK*;P60I_yhB1xtGV5@UZHD(yphgpUXO@geCwB{b4cy literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_off.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_off.png new file mode 100644 index 0000000000000000000000000000000000000000..cbc4928c23a6dcc08019554657f566bdc3475373 GIT binary patch literal 859 zcmV-h1ElPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NE#Ysd#RA>e5n7?aOK@i8^B^n{I z@Jtj^*+gt5m0DR?h?atlAlRgee}#f*n|~k>(})Nu3; z&%k@fW_&;9xwm&O_!hqG%+ActcXs!7UlK)it5@LvUV%o4^4sn9Vdgyz#=#c&0A4p5 zjW&IC8^kBU0@wn&eP!SdI8wO^AT@p zKzI(`f!$=#={J#2^tA{GG{J^LO2qGA3JfOXkjKD0&}}a9=}Qlrn~Kp6`q?Zp*k)4v zN3;Bck3(ij5t_+MitjLx+sJL#@?wf?14Rx6_6cQQQu-d1ciWlMTY3iNE19hi|O!4*2Hxj^FnMl>U2w7w8hpCa>+$e_Xyv;?6j+Z;+pY4Y0zo zTy$*R6Cr*GEV@r|06Ux5`mEW$`al zfZXwBe@pTlpB4plKF4$XqB6HougD8uGcU7a-YWFd=JgU65PyaJQS5VtUarsnwX~}u zXKW5z=M0Ms?&tXbWwKUkKG%}LIO#5aWBdp=U4O!x=kfo0z``@r$67#$Ba}%hgrTYhSg&mRHwUZtKEw)U%xTV5 zW(O8Bl7$%VelEGk!3(*K0=E_Bmp8-I%(sxt#>Da&ApeX#2jtVBn@wKoWiZbTB%dR7 lt5=|2fqDh%6$rlqe*g{9U9HPDK~(?%002ovPDHLkV1l>Ib|wG- literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_on.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_on.png new file mode 100644 index 0000000000000000000000000000000000000000..6bd2f3ef14d74da935d5e308a21ec5c8748987e9 GIT binary patch literal 832 zcmV-G1Hb%Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NEs!2paRA>e5n9oZUQ547DR46S1 zm5PLZ2yPVmL8bHuxM)|4plB_)mo^2hTlNox?%aec5dst2xXK{0C}>fkZVci<1!`fh z&ygW6M`z~TnYr&haSnW$d+t3yzUSUI_r5!|S|!yC9PSy2LX_WVH2R5q4fKLdum%>R zDEh^-Jq6McxDQsqezHa9b1=|$6+o&7%ma)3!Dzf~ihxWP_-J9SY@W155s-SJh`H)# zl)BrY+IL%81Y~Y2LZWVh2cTQX@sxLC0L%g{>vSA%SrH^(RE)OKuO|^=?5VOBbu`I7 zXg`ThgB@Yu$m6u6*mZ&rj=eNz(tNVUj$|36j9+9-`%k6V*Ek2Z8J|`*SCsChY63pa za!9#Shu{~tBcc6P^`B9?ms+HNPL=7W(v#F5YM?{uUTTp7yb^^nt_lb>v(~r=eg%$M zD-}ET>=7Pv@LU3?fGfR>e{wq#+Ivpk*iW|D6)?eWwvgbPzndhFz+VtrB*#N5Q`3cp zfL95)1ddt*7qr{Ke~6V>&WdAw2W}ClS>%PYBEL%@K3(6ZvdJ+RqJWJQ9^X>Nat(zjV2Gc~3C$+%OT6%Fd#fIz0QsEq48s5a zw8iZS`n#;etajFy*!RV|2Z0+9pNomyUgzUb$jg+|w7amI$j7HQK<>iL5V;!6gB0F2&*5QUU|R0!;uw;_ z`gX>7?@&jP<9nsNW+mh)9aRXv@P_@OlM}1Cr0y?nuQ&MxYbS7ruTv5@;;VgdLD5C0 zRx!O84VH!4%4=JEKCpK!QF`^-_>rhg+Pm31%iW^RH1dBxH`Dle&2x+Q`(A5naEMt6 zfZ>FN%zwzotPBm`X%NW1*jlFDk@$NeZQhf`jRx=#zf6V#r_0H>Z!q2=OMf|MtEK8AC zAH8O+LYdG*`yKyU-87iyc22ijy7SI~rcF+pKBs;9a`Vmk&DJlEJr$fat!TH5--}6> zHyPX=|ER{l?y~q$UoydYF4M=O9~f&QFSSSOp1RWgC`jV_(m8t`eLZykKbwkPyXJ>X zec#!cqV12oW_(>a=T2?dBA;f@8s29%UE;@=oet>_mFdiWFkAiO@h7sa(PoQ!>KPR_ z{xGO*lQv`R_{-(LfOX!%+8un4t|p7t9aQQ0c=?o2`1iISY7vbl*WSiWbafNyUViqy z$*IU*BfCg(pg3tKK~cy43F#jtXN#7{=*bwX#-Z?kk1@8evgY1n=5=N7?RO{+k-lWc>W8<|l*m!YeF`C-QLi>^pJe t0CUzAtygO<|J7`@-{Hg#gL+Gt|1&i1yV@KmvlpDmJzf1=);T3K0RVWaT6+Kh literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_plus.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..9f98d9a812e7504a8ebe1b379a34ccb29ddd5209 GIT binary patch literal 441 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?oQ}%Rm49Q@9 z8|KJ$$Uwm7DF2H{+ixqbKeDb_^!3r?J)O^gwO9#qDe7(U-n4WgXN%eGyQyj0ysug6 zX*sa2U=Urv6!O4d^u_OgZ^|crVffQ#yJnk)ki%a23GCV7w`RRyH0QSqU)HU9B`LLO zAG3pn9Lw~aYvHpuG7J1oFuR_$Oe?-d*kAS6*XBQOc~o~~IrN%d_16>l5d8E;!n4^w zRh({xUsM^eq-S`V~=?)Ub4CkBKMh95<8Nfg!MKRyb0)K=U(_g#>1pepG}}KfDz`snW8@!BJ!59r}#Vgfr8D`)z4*}Q$iB} DOkS4* literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_sdcard.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_sdcard.png new file mode 100644 index 0000000000000000000000000000000000000000..babdec449acfd8ebdc201517ef63571f84fff1d6 GIT binary patch literal 654 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*1?o`{C*07?Q#I zHe$CIbD+T4Rjmmwx-L1nJRDt0iySYw)jPcT%kY=^|H1kVf>SbHE*8?+(m8j5y@H@L z=d?prdT$P?oS9Vp%{AfqA;s_K&di%>X}-JqX4Kg>%>=F)Ov@THCp0r9N?dCUe!%*I z>C6j-9jrP}0=WDej~F{hpRlrXG&mY!aEK*)qlX3WZ{`iletO=vdDK56+sIU4WoduQ zYoAMu8@-wT*uJ~MyWoeX!Cgja+n$@^rEN-~%o_Jp3yxN`!mZx9FaZx$wjPCflEx z-d$VRxCC~6`0l`Hx_tSXJMkX3@3mbxpT2K~fc}|(mks}4IC4VW=D_@ib6LY&uSmXO zzZfNF%a>TLzc)X@`^fTHn|NEi#LCy)3xBhC!_LL+W+{tj-M<~Sv-&{v%uP(~h3s3{ zT^Gq6zTuFxan@m}3n7}9)2suQ-HOsHW3MxvG$%KNZ(HN`Io(%ZtdO~4ES@g$UG|IY zjLSyP6Mi$fD|0l-$LnRWDp#Yf WuWIKQ)Zab;r3Ft{KbLh*2~7aj(*kP% literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_storageusage.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_storageusage.png new file mode 100644 index 0000000000000000000000000000000000000000..17fe0ab309ae9d3bbc3a58394e097b5d75fe500f GIT binary patch literal 1056 zcmV+*1mF9KP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFib+I4RA>e5m`i9BK@f&_qam7u zM$N$&n&8EpgrH(XkOVX8NzHzp8t7cBUtjNiAK0bOq8CnAIy#C=}*_ zL*NPc3Lb(r=A?uJkATGVgTtWFjQeL}ir0hF;2SV4XEs7W&J1Ea22O!`Gd|HV1vi3M zz-29A69l!o0`U!jjxavaBZcJBPXm{Ue@WN~=gpu}&LlAh!<qkNhWpFDd2FD+YM|BlgC&4-z*{*fo9{7+a3Kya-p#eOlSq*E=3Zt1tG8$ zNTZtVvE^0EBfb}C_k~=Y<<;ty;z_;?G`m^~@^nIxYg!?=bFoX1{6P^Ng^3B8Br!tyBcZ z6fU4#6BtpF+7-?>wL%emuW$k7n!s}UOi0D~hGx<4Hbx#nV1xJ9kT^;h)cqmjXc!#6Q25=q#^TRyzh_4aImx#B(X2WKl zYn*jC%Y9UnPaJ(!Q~68b@Kd8uHkG0JINN z(5lJRyA9UY+EC=1xKbgSSxrnQkcZI*unfrlVH*4ZIWSPfQ*Ko4bscwV=?bJPkgmXN aT7f?UnPNOxPwK`100006gA}f5OZp5{R_N*C7!twx zcG^ZSW=DaxeAk0cK{qm!m4EPLEpFYq@~XRFPj7$H0h^As({4qs*c;JVQ72rM5|giA zy_%abKVegG_2={dpU1xw3Qu*5z0UVyVtc&R^H*mAD-BrYOprQW8N4b>QJf?1azbwI zw)E-y1r4gJoZR&nlrJbx*eCnIbi2;X4;JRzmONO@$8ay{)nb*eiOSBWmmSxLOEYx~ zVYs{d$*S|7;(}lJ4*K%cweN~HNO8C~Q7T^~-Y=m43)}0Ne#_-1U0SVZ%vNO|vzYJ0 z=U+~r?JD0pdaqgQ=b&=`PuG+<&V%oMMqcjypseK}#b~!tr87gZp3l=d-neEiPk-{6 zd2Lq~zRjN7d5b}yMd{wuxmT|#eaSx=8qv(LI5BFPvcEv!JR5<+?0x@uOQ*g4blyx` zVTyXj?dJ8BNp_pq{#IY;S3YoyHzrc^$r)|;uL5&ZlH3pEJbaN{C-Z|vH-3-N>Hkeuph)m^^>bP0l+XkKqsPPp literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_lock3.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_lock3.png new file mode 100644 index 0000000000000000000000000000000000000000..5841c6cdcef996252238448c1c164b7a08464a5f 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 zHgqr7Ap?QDsebG97A;;qdHsXcUu;FfYZ<~1{$hBg@k63(^R5?4J2Zm!H*b+K^t`>L zDTCjxsQ&(4Rg;yE|Lopj#xBs7$h$}Gg4iG1Yg=FMGEc0}b1atM!L(_@`Tr5=BHtUP z-U&?%?hF5+pkXy(R&Js{OIgsG_!kTs_Za2YoD`@s&2qAG*yo|KUHEA6dJVHat>oAj zTuR$gDwSj9zK8Efys%rxEOpnKPZG~hRBoJG)=+h(V2l#E0k{hGHBQoUdek}_{S?@i<@;Hx#VIqm(K7@ zSe$aha`W{=&LLNVYut37Do@!VZpiXCfX^XJ@f^>F?0FWkGe2mne_-mKJ?FlNN Ou=aHIb6Mw<&;$TO5V@ED literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_upload.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_upload.png new file mode 100644 index 0000000000000000000000000000000000000000..04c63878feed5f4166503994c955fc4e5cf23433 GIT binary patch literal 570 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZp5{w#3uLF(iWX z?G$S-7Ds`$^cqDDrH+$Hix%h|OJkcgYsW9y;mo(VK z&I$XVD6p~fwc{baM8W@;P918KJfyU)MXu$;+=_Sa1^7OS{h2Bd`*^4FpMN}#huc;g z?vY8@sd4>v(KJ&N_5h{6S-$rf`7&4d=PhM1lD?qy;n}r$5091J+2X90_|g8swnr9u z(MgtFd)!Zy7EI>8rZ}TYD5qI9T6Rw|!w(b+xs&Ai8N%I)oIPm^9 zL;d-ZV^IWFxBlT1#I+WbH3BL(MOvNyf6TqKXj%IhWNJ@E86 zyLof%pLGvv rg1$iB+s~dyO)VZh+IMx`zwfN~ca(jo^C+_X4~jQWS3j3^P6Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NF(@8`@RA>e5m`jLGVHn5fGYm08 znvq5lqDE2_VS}WUORfu)ELhCSrLi!vuo{U4DK;{Lm6WlQ`vSR55gS>^y%`k6Ach9o%5YJ-^@85qx00i_j#Y^|GfX_yz|bvd?h8BWjm1VK(+(_%?`A;w~qpA!RS7B zQ8YamyackhU}&GZ2pXQQ&W+73#s&0CP^8pb%b$DcWTyS|EyGT(BexL5y~vT?TDw@I z#f#;e{vvTLm&-NgBNP-zc#b&=#dH@G)F|Y9yF0wlg%aYAD0H1%SOHtEcsUx5B9EYjdqgI}iRL}WqQNg8P}%^dAc5AF%W*M(GfSCeX<2JCTo5+w$A8qkq( z))d7rN{&vpx^9B8DomJMf6(l4=Y(;K8lxfYs6Tg+bpaha7e#P67HY#E6wF&0*YE*;-Q}Z3YIRqc5^z2=4&^hgs3ZB!%HlRC)j#2DaU$}ZuS*wc@hd2nlGX=Mz_^Ib;<~eWph4jC|Zw;|N!Q@9H41Q*i|0jsv<2IXfPwE^!X(dtC>?82cA%_)Vr(&lvx= z*TnnnvLK>&O%u&s2oVA57MWVPt0U;?q!6`VZmSAWp;ph7+d!sQ7X36?TtigPgC$^Q vPn4-E2l{rN(3ASCCfk8*2eKVVe+Pa8#5k`kK$0rs00000NkvXXu0mjf=(+ha literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_smile_status.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_smile_status.png new file mode 100644 index 0000000000000000000000000000000000000000..92e38f865526aa64114001a0aef4fcf9e1235d89 GIT binary patch literal 1474 zcmV;z1wHzSP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHEJ;K`RA>e5n$L@sRT#(Tnv29B zYF23lGt|OOo1hG&8PTA!RV`XeXhG&qQ?rG-5FN@1S~%06P%f*rT8rAXD!zPEc0-#Pc3^WJyn&b7b?zP!&l=leX*dEfh-pEF})_vG$=fzB|(FDxv`&$D0~ zm;~z#sAHE6=g~h0-*h^i1)g_L==cj@9$W!!MK*I_>&V}LpwEG`U|4bnM;n*&BCS%0 zAWDxJ@MPVDQkAO$PCh#!G$tf!LkXjdVjmxT|^IO3+kjf=0PJn4} zUsDiqdfZu_mq99uG2FDm;XB|~66tr!`@ou}PM6wc+w&n`E`L+lRkCYUkE4&=b5Gac zE2Tjz|03gS9B48~|Zh*JliN~9icQ|L5I=*)T#c)~LFM$V5k)AeJDL+5V4(EIk zV+tr%5T#SQF@eD(@Byo@vf`Z&FGQ><;J<|WG7;JvpO8-hmlaE!QfCORbaMHu#9dU6 zg%&B7xkZE#7U;yhcLcq8v4i9*tfsf2%{Fb{o!FY4e2P6&^#NG}*X7-+!3Y}Z%zp0> z`j%o?8vQ5J3fs6y!FfO^IxRHx?A8{VW3~DKe8oN)8(o3a0luqjTtwi{fZIJBcYig# ztsVSX5JWH2zlWnT9lX;Gop>d9w5QGkRe_tcd%0$W&1Q=sRcDW`tO^QGcXE}oc9k`G zDbtv%OKCZd$4>bwt1sH=28kcaUqD;sAYZYiy&Vc8cveql^yLN1MMI8$UpJi5FHJuV58MFOdQp{KD^by4_Jr#!a&g1beZlW zSp~#jjeHS(!kVip+^4~Hv;U=L0I#@}h<1=Vz&CTVu`#2--3wfPqfniGY1f_59`Gj! zatG!0Oo&)TyWfoDH*;b`oC{uginu0v$tbjcVEmw-LpcbxfG5EQ@FF-0v_(&4cgA(B zf~@Vdf7twXS{4v>`{uGQdMYT84+GsCw3Qneyj5@;tKl3-9G4F?vVyFO)*w30jYn?< z1&(t1yI?fH^E8|%3hrVxoN?es%G0s2q+pN^=J^sgt;co~(5dcc;CD)YQT`F=4)v+j zu2hEm32=$$fRatO9*gu^WoOkO(})iZ*vG*-(8*A$RoJ`2b9^@D-L~S2WfJ&iPi;8;&&-%z)Qo zj}|Ms`q1rx4&d7IhJCyC^8QD@hbZSnyVAX!)`tH_K99zWXtDDZo8q!WEAwEBly_vg zIzhEz(*{s!)K+A35)7O!x&F3Fp_~KN(Fyr^25bY9Kq(WTORMlVW2II2SA%a!6}8=y c|MeI62Uf09wgD<_;Q#;t07*qoM6N<$f+otbJOBUy literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_channel_create.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_channel_create.png new file mode 100644 index 0000000000000000000000000000000000000000..fa7ce4bd0ef538057da39ae4d8fbd50efb27343e GIT binary patch literal 1811 zcmV+u2kiKXP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>eMv+?RCodHn_G+&RS<@EQSlN) z!SG_jLIg3!D4?Q74d8>C7!*+vjfrl=Tf_+Jn=i%}eNhZzygcZGCSDLPXox7F8=?dW z0-8tyA_@@_A*fsotX$Tw)}C;>sOfY1GP7fESMqP4s#En>oto{QGc(<7ZIx6Vs5($} zpz1)&cA!0^vYwuv4*XsRSAbPuW_x@4Hje)bp?+EC1aJX36YK@+z9e5ceG_`D33 zfx|${Aq=Bam#JAqPfgOm0LqyT_DEfIWFz)V-4f6zf`rB zIr^;}Qzj7};gii}Lj>+yz+a%A{KUlgkmMFYEDi@*Oe3W5%_Kz*1oJ$_E?|CeY>^3y z#T9eMVV~txfNftaQBH+=MuOD|b;&6;D{UH!FUEmGQ~raoUMq z8a$S-Ns5wRA-bBcDqbv#Fc*)n%OT`&6m<>S1($rMQ-~C?wzfh@GAxI@lZ@P58K~-p z82qtM3C%pk>K56`6IFveuTE%#{!u(ySJUNDLmRY0Em`Yox;$!VgJ!biWnh1F6unPY~4f4F!i49^CH2}!hl5a%EM1N1N@=eo}xxkgV&0Hmk zC%MU^aaWNw82qVr(w(Xpt*hzsslHQYh+4AN)pYq(UxUiG;*=|@8sur1uR*eNjtLjF zK`}$g6<>pP80$aJu$9*2YtSZR0OzP3pF$hL*Nv0LlXF3zeuEyr>GkWK|(0{M6EYmwjRA33hb zK!a7h8=CH72MDQ`z48zyJ|k6N8)EF4pHBA&{g171<0fc4K_w-YE6QjY-@G zxsKL2dbJi9bN3lGpXrd{FwnJ;?;~_+z#7-?j7KqE$$B4lY<)YVm@Cx_AnH+&>V|Cm zr%0d@>!XgG+H$YreC4av_b`~Z|JFLjyxc~t<#27jup=2Z=q%{Zrb&SRbq2@hNgVj! z2KE?nHPa>rQTWQ%<2xrt z4-a5?(Bi?qL_4D=z9<%t*9NKFkS%YwTBdq~BL@Pn(!uE8gv8?~r;0p-ktBA6!7>2*qXP2S!eJ3jKfmzK>LOX&@R>?UBn!@7BXL%BImp5Ry# z4F}fevpanx#B~5ITYYi9c?jk1+PlHqKu$e*2<8{C7~Bs|^>GwBPr}cDmhBkMN=n51 zg*ph``q3bXrtrC3A2sS!^PFLq3-wACoV2^X*N7{A(`F<|G6iqsl1SV+J})h&5nb3O zyLQH7fLsqg;3yv)Uz&F#m=3fo*M?H)G+_itdf<&|uk6HQNGTd(ErP|319I)j zDxDT@scdvc-qn6c*&*4JJOjL2gHkk$g$@EwgQQR0O!tbMR#RGO;Z1v$Sh(yrZU7U3 z+yEiEd@Z{hYysbb#a!gOIaX42pz1)?fvN*^;9qYAyx*{+;%fi^002ovPDHLkV1i_B BJ~{vZ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_download_settings.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_download_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..ef6e38bc2fa7470e5acdb85df4ce6b36285639fa GIT binary patch literal 1009 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==L6{JlfO6F{Fa= z?d*+tR~!V|iXGZrm?t)9c!X^6@Nj77>*SMq5v00@u{2IG=m__NYQ~I=%ohSp>@ft4MX+=qaU1n2dY1m8A$wja7({&M(Kn`h*y4hQ~QB0nkTJ{uWTp~U6QtX`jXfWJ*KuBO8nQ@L@R9xJM>zC=jNfV z@IKY~7w@LeEq=1ZH^e6UNi9S99GmJFIcKl5)GVE3zNIvzI#t4wX&#UA)Q<~z_isDl zx8&@!=P@SAKXY2=Ot;stdp5Q6x9yk5E>V|XiGR6r)njQW$ENe`dt@H0+yD90k-xlO z9xBe&Sgg18X03KmglN;A??{)UHNJ5QmiJ9p=we}!y_n^@cWN&h5X zge>mSSlS7W6NkM#SB$!^-d<9Xd1hW0=Z6=YzKWc1NWUIG@2;Zkk_^`QNnAx=cq5$p z$^^YmT(k@6lDTZW#b|<1zIw1BWAHXV8?^*xSbAZ~oaKvd`=$Pu7XC2j za__H2-U{jJPaiK|B5$=sG-QjesIY-nN|}fv{~{sl9`y6AjP)$@P`A0i3VaSsad{tdquW$ti(%H5xyjM%x4Iqz zI)ML^Qt+OL=B8T3rWdT%$M5Od)K+n2mz$_PkgK${wq36kAyUPDcHSa$v!8!?VrIXT z+A*&;at))>9jzB4M_G29Iisnl2@c3E&Vn0OZr9KM$SGFqxqki6ofSp(PLsYh$D}=* z66_!Kt(;?%u7~}=BC^ArFpvXXxfg%G%27msa8E9>Gx4XN$`_blD zFaeyH;3&$W2`E~ANw9%(O@j9*KW=Sp-A(!5B9hVurh-MF3sg(0D_{I5$CLH7e4U?XTWsSUNIS9jkh0-X##2U+wx$|Yb1m;^?H5nw<9@sdfm z9>kE^oV?Fwh=1T(!R(Bl{D^J=Xb1bpbOgJj!B3zPQVdOBd@}n(KtsUdlwSOXd=}6u z6-C&N0*`|2pc+yvL!ugMv=M=n!0MDoKqcSX#luIxC3a6;mm;?S|MX z0I($x?4Cq+cTB_B9s}k9KQS*O8z&!>{lSf38;B*vR)30#q3$*`tk)_ua#kY$0*GGA zY8d^o;0dr3SkeTp&14@!ekjl=+YMq!F*f&gqd`r`p*d$E@=Z9>Cei<^!7; zjk=e>nSHVn5MVbB=+%oM#oD}yo5n(`)k4<~^mhUObwSia?iG|k{EOfWS3kC-j((^= zfoM6n3V)0R`k{Q99qYFyJ6hE~$0xm3gXCBxSmzrAo?T*2t2Q8fYF=`5oAZM}F(@XV z8oN)TwSK_g1a3suvr@s|4r1v**Qshs8adcBG~N0@J`yN4ONza5J8qnJ*w)~8fwNp- z@MC}*^02v7Yl5`;Il9)x;Yt)|0mW#k!|Cf<(tpBW;Qu0XZ6oO4w2?&cwI)alfTK%n zERIJx*BK3lFwxk`heYLK%%1FM}1f6TzxxgjGmWmN5R!g1Mre+?`ZNR^> znB^R!I}m6|uas&{&=k{Pc|+-9vL!aNjGb8ZrGEEGIGZZ3hIH^83ibyR!E>M*sx?7c z)_)z1u}QH!2KoUNv!$ulCXL@OP2tI}@t!yH{0{gDECW}7YG@h}$Hoxye~=L>mLPFW z`!k9qp7Lt%xw=O>pryUbrap!LBSoGk{uF~L)kH@?t7F5&n99axSi=eD2(~mcuTHKWZ}Y52_!(K1(CZu)qNNCXHkHl?vSHv(V3%TbSQCGri5J<0;C~a~ z)AtBU&TpthKf|juFJxDd42K#qmL_F6z_35CR}s4UxG1ZRbl4mL9tQT1yOZa+Kzo^q z-~*6Ft5Bw1=c1eBRbHMKSFRq1>piEVvnpY$;qOSVQ|?4){b8>=qNjmNvPP5Ur&xO4 z`m;O^Mte@yTYXhL4*d<{h%86g4}Ua4+?r*ZrNhUmK$G`o<1dyCwo7GwEwQvUD+cNM z=NX{)FWY~~sZ+l8NNn;}mQ+`)N}r;_R#)a@ z64a+sj=-*Pf9BZ6sB?eifD>(BUI8)Nm_YS^L@^Hh5tEm7o1m&k&_5xz{C{BhO4v}} zc6bi_zIp1nS4>Vun3}`kvx2U7f~pxo3U?QH0IULEC(t#=I^d`-3EF_SlJiKZRqQMC z?6dnyf^KCVyVnNCyyS0D)VE9u4MV@eT2G)OMHba%k~R%wjaFmUi(Sdn{kyGv`C)oSjc^wz-0YlR2gyh&C z59R=!v0~{%41+s&kzMRNLN*F~1G4BXlqcA_JnJ=n6omc@q-0$W zt_F{Q&q0XhTc4K4Sl7e;waQd$QxlK#(51bC+yXuW>w$j3SlW)^ec&drI#5aHFTGyJ zhXO}_7`P0${{X;tUw;;|l?+{DFYS{?Iu%6&Ngw!hIMry4Is##5Pv=*K5`>MeN`3>D zIzzT0SyUiNMeRy&07n`}pTTRVD%uRb15?0xAeOo@ybCwtr)RZ@Y(ManXP5VQMm5pmbhvRm-S>g6d4Hdtlg?|&_a{lMP9tq_ zJS$1_K`d39ph2dATf7+bYAH5Liaoduuyt$VX<)K#G2vHI+9QTWl5Q3sPxN_3RS8l@ zaO}1ecesurQ{ohpPmTTiiwQs%Qa&wodRJngB+c~=1JAW2$W6eS$I68Ng@HC^JAK1T z8dt{`2ZB&wp?{GSTFPy8ZA4?vg?;))y{(C(hbT32Ldj9At$ivtQb2=4K&ayy+C6iU z0t1_XNSjD)6gL3(YQUCBdz!XNW2TOLiu8dX^jay#ijFyz#*k`H!zG~2qEDI}%iq8# zCm7}R&Ka@;zy;t-qkk2?qW|t-zc#7wUNz&c99zk?xqnwmqEV7UBS~8T%|C9U)}i$f zKS*T5fc>nqif3KQa- zx+pKru-DmY76^?Rxlk;7=e5cRT60ZkbyL8iU%>*<4(!gh>=Ic&FbBAV!j}JJK2!$q zI_azK0)OBiJQ4MfVrcG!oR*Z3oZz%i(uORHbaACW63hUTfX-CP~7yZ8dg>TuB0AZ3%iX=mc)B0$VqdPx-EB z)r*b2sdjXt4d@!<1<(bmCDoM=`Kox&R86OwK2e#`F}(`oz&YR~pxecxfF|SegiNUq zdcp>v&rbTX@;>;8E0Nul1r-@6GEiio$Uu>SA_GMRiVQS31AhSw0Eg>7)MY~e0000< KMNUMnLSTY<5QzBz delta 1894 zcmV-s2buW46VVTlfPV)&NklK!ObBK?p=knyJS!k&uF{DIG1bv7A2NJLlZlcg;Tg z?(^$^_nI>z^RSyBpQ+vS<5V8w2zRMhSDCBh0+DObWI0CY4o`xx~ zA3Ts(sQM&*#UZXNlZN5E{I&WcXcU~zP^^jdFxXU;2yrExSrfjrj8+w|6c0jnf?t5o zj#0U-RDeKdaRbHhnKbPTbg#cj0>D*|y35qPTEBwD2!DzN6w{it-JB#5SU)S@H|IC% zAM00g(m09=c+3SH0}{H=c)U!>eyL)#6IMSf6-H?HClZ}K&_B} zHGwrbK7RqeHucvjKU$xfMP_1b2RBUYZzxNXow%jFmKAqf4dhzVTWjB~sN4*$nZ{#% zNYLjd=HHaHL(t+=cQ@X0KS0;W}UszAM%v?`(IhX?NpBVq|j7#Yv{JK-Q_Hl?5 z$A2l;nd_4w|L8V|)&ct)-X9{s{{`ThZo}H&sl?#Y4a3??A#$AUuRvoeuL%<0tunZu zL!V(_=d2e)1IW_`_bb3PJ(LC?Z)n$klC|~{B@{d6Sxl!7u1&LR_p@7JuW7$V-HfT< zW6EWUyG-X9VqQ0OUByK6bXVo#$%?7!E`P=(NL!w+X`3|0P8p}&rd+0I6LdO~%xbq| zTSgO;p!TZN>8U;B82i>Z1%H;tw^wnqaj@T3)7&Xq?RIP($Mhm5L1U?N^7*4FXBB5n zLv`zpR%^ZC)`oqIoi$E&Y^J%@3MPmdO{bmq#549}^A8hEcf-=BC<%w%N{Q9QupAMP0;Ol`!=+KB%VfbSlxEuo^I_bpLX9EJN<2-PD2G3 zH#{7rzd;_(TB~{`C_Tt?MFcbMINC+n0&R0nd(lgA*yP(eDT~{u-8aTg|6qbxJIv!L zxMm0Lwz=1Kp12I39hmDMbq$9SeSgU~$7-^E^T`+u-BK}_pv3L`l6(6~$H6gnzj2D4 zCrmeQ(Q<9{dM&TC+U?ku^@vH3-p_HZ=i(}He#-5{wOxal=3K>d#(TRdXBDk>JGN#0 zViIHrws#qezru>1@w*kOwJYb?!$GUvjxE0!)(J%(R_~;r-JX3de{_EjxPSZhuy4-34e+?I6R1GYrA6xTf~Pzdu%Yu2VE}8{W&;Hk~HBF)ZW*n zehaY2J;zm|;ul?93`xt64mWB$hOqC>QDFw`$h6}zzEgP zEo)BF?fx+EzAlq;A97b2-;wO7-*YRJApeu$Oik*pY|KOGvR{#J207*qoM6N<$f?)lrIsgCw diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_angry.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_angry.png new file mode 100644 index 0000000000000000000000000000000000000000..b52eb874351e3cf14c43ff87902cb323e96c7a2a GIT binary patch literal 1972 zcmV;l2TS;gP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?9!W$&RCodHn@en0MHI%VwIHVA zg9X9Fq#-p*7sdzRMi(YZXktQlx^bZmTN6n)B^pU8y1^AOk&QKB2_|JhT=)#Sz=cFe zP*FlP8VO0kiU=ZN{e8{cGXKNe_oEN)Nxsh9nRC8#=KSxSduQ(LvSqEb8E7-mW}wYL zn}Ie1Z3b@640JU;?3tOFZhSrpo&*m%+(&tb1I4mG9e$zw-r)<%qg`EH*C>~kkdz*< z73>Gops2`J9OCL(^jTsME5Rt30#%DR#l3RTC5oWC!7%t0)GhKMU%GTFm&)fL0v#mE z-C!Ug+ROBP1U>_rV@`qJf#x2G=A*koKhQk&6nF+Coh{$eKf)aKA?3mo64M2CfjBu& z$2b@Qx91&!Y@F>lrMTimF;xD;=Z&{RpMZM7L`=kg(LM%rR#YP5a-8B0iDK!k#93Jq z0_g+C15y4<+g`A?tdBT*aXTOKWkoUd#o0E}t^mMU8yUx%I5#vB1Wx43`K0I&#n#tU z936getjj8N<{Y8DwzH-q2=72XfqYw0jLlwdIMjq3nsfHiew!C}qgD9^iouFvZEoVm zS?F%HuhDEII3vDLl6EDSRM&;`L10Cv_Pm`rc65pbgf2Hdqtz!k?FJ`+FPe}WpL5bi zshEI$l2`1tJaNy)1NkuUMYq?+?pA3@vHgk-*hhe2t5?Y}j8S68x}IVe+@)nlrx;zV6mv3a_2P~*-TI)_-pd)V+9P^{h2d-7@mv-C z6&!2=>wwl>e*i5;k74s0WnqE)7K|SO_kt*%pQs;!`)|q{1e-A$U-df9QD2MxRj;jh z6$jd&@Zr?}-qmvo|_GX#9mn9ASsAyELnD7ajgha$&D zYc~znCj0fck)gW|=w=X!Y{ik7)DRyw+D}sKzHAKX=4yj&yU$4dU@iiqjQtw$iN|@& zsLUOr^RA~Sn>BNt1uEDd^!QZWo<^fPLYk~M3fd+uEZjNHV!Ro=?MMa)^wt={XI;B= zH#^%H)lAJcc00CABppfwe^{yZWJ`xa#slni=la=UL}t{V2cLrATtK_dn&+JE4fYvb z&#A$+1^9A!uCr(bwn?9nx;D~t2{zjdhYq)8B`Iqk`GKcjjy;)-`U;njO?iZ>Mh|D1 zIk5?CtR2rvP}V;3qu7BjQ&C^x61FQoBlYEZ$*{R-ICOY1D^FSb$PYZr<=B%eQD0n{ zWs;7w&C`B5pd4xosLeKobVF@%_J!NCBq(~B7deStVnhmoa!18iD9Vfk0Qq|m(w7g+g>Mm5)-o;SMBwfjEKKoBnpC(DpeVfm6iJded>s|R`6&t(0 z3rLhK3Hr`3=tF|VDmM1i1f>p?({dy5rO;wE)ltm~44}|rHEs>$hkKL*?FioK8nvIR zwbX<=&Rr1fYK)!+j{~iTH1XdBRsqQcFb(usjLzV%z{jk`&QTT>#jMyP(U>&0^1^^} zZJ32T!qEe?_WB%L19?R@vK5E6fO82p?*m_|*)UTSu;$uwwUJ}5myJL8(Uq)=YtZ_M zJ4RQZ%hbB%s$bu($+QukD%kA=b;-`u08qgBmTddK6faxbsXXnr^G&|b@0-^cUJ5ApL$*# z$}2vGult#;CBAw_V-I)%_`hDq0E!-n({b;K7Xy(|rZZFYlGUsuQ#pxTC;smC#gL#3^on zm$0hPo8@5;+E3C-{s6EaP|=iGWGfDFW!ldvJJQPMptOJ(m@b9Kz!P9S&|Xi{zlCc% zL;KQSg0I=fS$h8#&cIq}Gtg$B%|M%hHUn)2+6*kT4Ezs^3C{SsMaSv@0000_H literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_back.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_back.png new file mode 100644 index 0000000000000000000000000000000000000000..ff83f9ecd9d04331618ee71a1b0cc93a4b8dee3c GIT binary patch literal 570 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==L6{Y>B6fV@L(# z+gpZSEQTV-KFWS%yLTW;$EIm&)8BdLi}VztJA0>2l{*l$VZ(-7ZZrPMozaPIdH$I7 zj>Ttwo3a@yDnHN8j^v13tHGhrz`%q;99YA$ODxQo=kUsBg{vh*X0Ll)7d0bXxLDxa z%tx+Ox}VviZ*TWm|LwJ&O>!`Fh)(aG&n) z1w3bsvS+f&Jm1;O+^75?WTNE*3no9&nV6ijw#BQ;M0nlH{JXlF9xi`(S9@FQuKl~d zE^MrN8&H?dzJ|5x!hvm}w~8vSKUufQ<0bEA!|JHx8`;a(Mcj5>wxrRh`R{SNOogRy zriG?yivP<=l`?s#iNQDgBKlSD$?MRx5NXyi>4S?8fbuWBHB=XO^V(Glsv_ y5W6;em#T{OmP+HYX9|^G6a7#E5FDNk9trIB@s1b0-}<+M;?2|5&t;ucLK6TNCeNt= literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_bath.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_bath.png new file mode 100644 index 0000000000000000000000000000000000000000..1fc7a789af6889e70a8cf13bc8a9819823362e17 GIT binary patch literal 1693 zcmV;O24eY%P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>2T4RhRCodHoLh)hRT#(TXi8<- z#VO3vnt`dbas&|)!Uv<5sEm?|qM)cAgkGwb-lD98B=Dt&h_IldBBR6*Cws9AMPUS8 z%m}S1yQragNl{O~|Fjo;u5;OYpS{jH7xoALS>L*Sx3kvTd#}Cr3=EW1Mxcy98G$ka zH4&&*t5d;4U=#Qa90v7h4~1L7DsW|upnfdC(dA$V$VJC%cQrmo;;U`l~&GpEhfsRu_AUt;V3+nizF}y1ziRL7SPB zj}d^g8`Sr1F;0yF-RW97NM;R~56*Pn!A}8mfYzvOz^65?t)J2`=m_%Vw=Iw1FM3}7 zO@25{A#Emsx4pi)eAm4Rq`db6gwb+xH?VYjT5w!Foz4Q|wln;4S8r3wg9a$p8gwB} z%rK4|gMZiLo3dQK_tC(=8jUvX6sYo)KyuQ=TiP4QM@Sl@yq*;09zWZ9BzUg9dPD z58m9>c8>xph%$l#+ZU;7=(fOj0;K=d|D6}_{ zwr(kPm86qW<)cyTHONlsM!cN2JBgO}>)IZu*a2$0L!lLv0ZNHz>;V01>}kZS$zjvZ z@_wCZ)*d!?fOIGA$nsxOsLQ*f*BwKur~X4pUTNlCfTU0FBwT{EFLYyqlYSh^bg91+ zEb={~YzXM(;E-SE=V=r4GVjap`F!XAo%AdAe0192KpCKvpt?KMhRqnVS5UbM^vZD( zy^$R;4jqL5(d5M*0qc3LTj`b8WU~b5YkFN()3ZMcZY4Xsgy;z6NBbk-peU&A&lT=%&-AeN?%mzWrh4!3|g6&K%ZQ+I^ z1qxUi4<|jmBn(|*jfEe}t0l`6vodwKz|y%k(}nywo=v)<<)T~xVo2)2(Z1t4jbCME zE{$;;4|(cxkN8{xN|b4FvovfoUB>$X+LqV85COV0uhNL^?G2;U+8u*TW`qb(SDpc6 z>dQBOgFp8O$`nQ02*uX`OF!HCZs9R-ku?%t-+N@bt+76|GJ-xqfKHP-nvLT5F4INn z^`0#oxX2VbPU6XHoFyRoV8qhe#;xPmV3@uX(ulEib2LlPdXv=*e-zA#W~ z?;rAYkL;z0YONY&I_vzEXT%or_FY$N!VC7o1|9y?DSb;%7ZjVnJKC373ljbX(vAfQ z-7~=Fi7hVKuk!pJ2Izs}51kbz{Q^Gvy%9R~+_lr#;n>HDxSIR2XO&^WAoKD%!V$i(0lKOvmGh(GPBYO5Jl# zQ*DK%wXIvv6nlgUeWc<@znsqZEChNJqMb->iA)9|No(3J@GIB>-UH8pJAfnYATB7f z201}3r37a>uqVUFR-bK2Sb$FGo(udBX0(8JhA`#t|Ety@_z#Lir|2T> zUp`keoORr{lk^12wH`U@+#4Bw9c{V31r7jxGC9>*)yWh)9t4{D`UeA}owTLYT}Ggc nKpBBD0%Zis2$T`%)d>6tX_p*OY@1DZ00000NkvXXu0mjf8NM8| literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_busy.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_busy.png new file mode 100644 index 0000000000000000000000000000000000000000..ce81d1660b463265d32af3b626b53a68db91c2d7 GIT binary patch literal 1396 zcmV-)1&jKLP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS<-bqA3RCodHo4acjK@`Swje-#$ zNGb&(h~T4CW2J?KV5+3E(JKFfP3lX!`~#^htV9b_Sws-j!bS_h7pP4{5PXZ;7~=1X z8=0Ja&AmIj_ukw&@UgF%bH4N4nc3ahxg#Udq5@HYs6bR8Di9Tj3Jj+Lt)|mnTU#3? z=1Fi497}MB?Vbc|Mt&q%Vf!+{1GZ0Et=1~rt!0R^15AUP;4A3XR98OaYsbK=L=t0Q z4txZmO+Mv&Y~X}~^eC7G??BzA7>cE?8{C4AK@gpS zG#>2-M}Wqu^WXv~YAw&Xew8um4%_}SglU0!kY}H{a1G3WU7cp2I!WDYY~?G@#3A?( z-zncsaBxFW*TF z#j++&6M1zTIWGd>gJs6C2F}xskRXU+B{A7-GI5(|ipQon1Xj1oYB`TMUt6o$M8Y{x zOrY4-#If1#MnDb7S!2$1&hK=1H@d6XKpd=zYjXoP!LsgF*Be!%AQ=3zM4B(C67CYg zr+_sz?Vhz9o1M6TtnQ{~wEB#oqu?2EO#^b{V@_F?;sorIytvo$#J$c3=d-{y-Ci5J zTa}4ouZtV7j{vi_T##b|>BZCjB8x$s*XRV!dKPm{ITXFJbjJp#b8Zy&^%UE8UCU-C zjtN&b|835et8|Q8&F9!Di*_Za4OWJG`@b~*c9cuF`6Qfag32|$ECzeGs#`0#?gjP* zciJcJHlIS2xnjyKF|DvMHDNCG-yvMT!)nPeyKIiTJ4AWi+P?zVX1ep%yIPQ+aT8!) zIaR;q4( zbliB*H0hw4e#LQBzBE$b)K@yUi_?*Y?zz^a*{`b4?TM-bRPtN8wB0pm!y| zg6}DIgRb+l}yPm2buHHQQorZYe)L zgS4ECJ2myi^OJL&yQ=||KChJ={W3_4yKAKaxrHAs^v0WO}Tohhx0gTU#1iy#m_!PA|X)xa9AXe zt|3zV^jsto0_m0?7cZ2E6qmmg38ZVZqPT#nNF)S`OYn*WN?K7|#OWbYTn6kZQr2?d zxR889JjNt-H!ZczGA*=f13MqQQN81>d?h~RJIlnS*|pJSSwLt@{+T8C;%bDNLd*pa z{|=Scst`#}+7^3j77eJ2T5h=FqSJ0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=Vo5|nRCodHn_I|LMHI(9erDwb z(jXAJkwq3{1sYUzK@f{F9}J>i3WCZodMNU#haw7kD74330u#aL!5}Ei3d@qrvir>< z5i3f|FS~pB`u%Bdoz_14?3r`+{?2&LEcml$&8(TV*8kfxd-k0DO_-1*F_0KY3?v2; z1BrpeKw=;Q+`%On%n=j$}IphDUZoE$Hrjuu%NyhG=(VJEu#KD;3rkFT-8MwRZ z`K&{lYL(I?K~YRGF~BtYfy)OD8_Ij3qn8$kf}kvW-9@f=twT)`6w?$FF?JpD+Auar zP&894yKOde)e&qivsi~N%$2h1&=ABrbN~`wHAKuedO;l;g0jrF7zSn=y`VNpP;6_E zlKWNW^;QDE z^hogk6<#!YK@BD7Q!|1-UMQ1jrWoWbCCF7K(2YFVzA<$L)h1CeFcmuEz1*q03+FS? zSA*}IdKJ$ydM&?d;BN}!>dvi-U3M1%Z3q_wS9A>ffLl>Znczmi7SN4srqh|d1VaBs zU{5#BO`m&uiKAm*9L)iv#-XqJJBBxPbWqYrKm88B+t*Qv-687lD{)a@HBR)wz=o0_ zs;UoS5d8ZTeNLzvxT1Y4?N^4f5cK(rJ2=kNSBc&Lv?fdkR%CMym}(mIPBf22@=H_S zQN^e1HC`^eDD240C44F6iZykh_Qdl9f0!6 zjvbDrMv_@(l9Re7BnRvln=$nB^56)`tu_ftz1ufKY^Q;L)X9<4eEUalM^gGE=0hhr z74?-`<*`Ga9JZU($&s7$wkEEjJL#TcV3GWT0ko_A)fs3q<#i;i4X2O1X^etDX)*od zQz2uia|h(b^*)hee0|;_yKeL8cg)$4+><6zsrObTg3V0eejKW&V=doASNR^-c9J>{ z*w>c7sJoyl5Nvh;S1zvV({1~>u0d{)tVi0&>9u2@Q-3_=XUSaaQYZPuG@fVl+SI-g zqzoWwCzm@+HgnM*Hg#6D$1aT#WF7ZK=Z>-aBfV5!Q5Fnsw*yz6DYNahzOQ$X6Z~?@ zdauewajk)Yvft15=7!nTcZ*=URjW}D#8ew4)Z2jjGN~Q%^N`f;3H86DU+hi-jYt#( zDKkjYk9v=rEU!j?1Cp)-Cxa27lR~>W)ak(B3&~FcuY*u|bnw~9GK85K;JpBb{=`=2 zQNtr7JQb|ScnQ1 z8nDQpNRuXA#E|@k`~Xu}1SDb;u~Z>oAsS30qE;s27rH*L+=SVayL0F6-rdY5bKoWO zdCq&@otZm#vweNZk^)JAq(D+2DUcLM3M2)R0!e|SK;;V5Du4Ib#9_T&AExU%I0sHT zI851Rn{<9~@S5_YTCKL~o75A15(UhIHBhz5r+iEJ-ZDrJfd%jfblMa{v4)~o36cX~ z2K)fsw(kT~?13tUs_YDc*dW9f!KEeyztR2}EP;36|GC0hqBEwc;a6wW)|qvh@-=W3 z90GavjK*8|{ePU-xhriXF#_I$JbOXoO>nR(a`Kh=lQr5^fMQw`H*Njy8-aBouUJOZXF-2iM$EYj zl+Y(I-NO8S<|(!{ajf*<4&p}8`<4my*`Ud05cAG}-+#v6Z8I#WDh|evsxv{8s~SW= z-E;IEuX0B;# z1!->Pqp7bo|VDCxuA#vIoL(nzg+6|vW1_poXK0oR! z>x=Qapt`nJ6r-(vBI#1-+9nn64VnI+b0dUUSzqD?#L>0RT^@-t^Pv45N8XmjxLZ&x6FWf8ksj->=@`gpck zvyYF^_62nRy~dJhul|ea$N9b}=(-WKf)M8lPW2^uuZtsTmBVV5lj>e8TtS(mCwM6w z>x~p&XB|potfZ$tYTl%?ZKaiS%IBnq`_|z;9J<|hukT3lRyQZc#%L2|Mg^L?uj$VXws0Q>FX;J=&hM>&(wRdYICqT zhUdhJ+4uJ#?^6kZ^n$vtZ_?f^mR-Ro5PzxRu^7GvqaLZ8CbArx67>qCSvb(k+!$C_ zeUF%ODSS~?uHG%?iji%%uWnlpmyZ^$oUPn~1=0jWYS?N7DK&p9Xt)2i!@F>cbvv2Z z;w6C!K9M9)5~x6dg6_0}Di-Lk>yM|y0k^Ht|0r{W?RA;^?ekEt zr4r2?&xJaVaNJxOaa!WfD$?(x9{~G1MVg{DaTVw8{p*}yqd;fUM-Zb};v{b3sG}iS wQXnai6i5mr1(E_ufuulEASsX(h!;hHe_?c~qe)wW>i_@%07*qoM6N<$f=EA0v;Y7A delta 1788 zcmV@eTCo?q8&rtd z0}OgVTR~wYgnv{P1yMw0)E}9#(M!@IB1kGB=%E#Ap;A%WxdWK#_qW1Aj#ZiVPg28K}vI zj)zY@_`15fx;=^;eZ~D8Fa{jgiGlns19Pz7!|%Z(47d(#1rq(%+0ju~4JLy3z(x=z zOK2Em?fbOOfM%G{&Tt1r+a%Ct`b4SIUHekY{Yo{=!0rg+bH7do27(u9n+HxeeWKLH zs7Bwm0lpn8*njU;V&5DQU)QQtK-ZyBPQQIlx#VJ=W>Bv|FmoQIGAKFUQ9lI?=VE*U z&}{h>xbnNJlv>X73_6NI-C+i{1AQ6^X)*OuN1D2WK0y~S;Qr2_b;{g8az1qG_7|CH zx?^2z>VGhL-&Pr93y6{@!bXVE^~P`y`p~fceX^bbMSmq|GwnwQ4UBp{8!ZQ}EDGvd zN?q#LAXuIOk*=p(-Ky6CT@RLUdTipi6nP`U_8}aeXPmxd^vbFvWhi(Iw1P0%O~WVP zPB7RqrY>p*T^Z27A2#=aeZZ9!DDJh(nwC$8h^F`bK&L<)*+l1OLHC0n<*)?(L))QU zqoP~`Zhr(n0xL?^Y%s2?f5m6XwW?iC#1w<@kPHg!A!6PBoQ5uR`4Xa z9oz+;2dhDl=myc_!1?fv)rSCsz#0=>7hIh}u>_kT;2y9N#F2J7KMhU^3P^o_AiqJ^ zs;NOXsnrp53b1l*k^nfgQ93?d8DA-9EOl`w&GBgLc|Zj_s(-25{E$tSet-LV*ak zxKSwU0j@lEh6E#m?^_ss1yMO#~wlBpv3DTyXD{Zcl^Kz@r0HDXLXDrx5nt9YMcZuHD0`z9*kWj)CneN z`Y){97Pb6fMPGR3S|D5twEF1ERlcO-%%CMW-Dw;*7(I`wW{>-jt1&FhgeZsLefKa( z&m>TaPT{!NaGsx{`<|`{q=j);_J5*`=-Dej8r;UaWIM|@WyX*IT2<6SnJdp_7BHb> zNNU5;mETYfN$57(oB(gR5h-i?CcB03XgZ;-a5@!e_0W~+p$2I+5KX%UR_;y9e_DPZ zINOlifnJ_(h6rRYe5^dxB2{R(gEb?CmUrj(-qaV90Gl zFYmh}0rfSzD>~ophfEm^KiVZ6u5(FsmLG|>%Al3N^}tT!rPNjI<0WG2qw_Z4itb#M zIsFOzy33@qJS~Ic;pLL}`pV5pvzKueonWGE;Xg53KJ5R#`BCoj2I?K9Qj+a6C_3uZ|3JUm5uz0J_l&aTF*-3fL8XDlmp2xbodg;Rxif7 z_%;A5E2*d_LECIYu5^+VbkU?bQ_%xrd0!`zWF4}%0eu8s4$%kZCnw<>W}Esc<_3ba zJ~V#;=yZw_{n_OUuyqFLqX?ZwBf)rJH~pyUmUWaK2Q8ddUi)0#mY#)76V%0lMAcDl z2BSbN(7VyMK-(`18JxPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?2uVaiRCodHo6Bn+RT#$eHMS;N zmEr}YmVTucdjSP)D?(j#Q6Z~l<;sHa{Q*KL#cU113hlaN6(Kv@MY8Zl7G0>c2nsEv z7ZlQxTC7&Bm&R+2zo(fgC+{~iXYNVrJn;0)oH_6NKIhGuGiT0x?dfUIWT44FlYu4! zO$M3_G#U7RW}sDfx98{Qdx`lxd>L*HxPkJafD}Ey2Ark581NIyFI%nFZOVHKBxN<+ z4^P0GFfU{)AM&+&#b=35^ur-|1C|Z>l<)o(mncN{!VbI&tA=7ImTukBQTiN&&;e8) zh1(O<{?4^2cnWHc`5OKNHTMXbkJiDbq2{T*a34$>E$6v@h&k#*%H;)W)w`%Yg4V)`7{#}!ABGwgr9i#{pYk0AX<1uJu%b>7 z(uU_ERQ^NVD15SLj5vGw4q_;lg*3I}Y-_2P0C?Rh<6INx&RRqeM6rUH6pJ8j?YeX< zibG)CR#7A84E2?bnnfa<6UBszZ6S^I-fjfcgd8>Jj8os|=&topv7t0rNNar)H^HKw zR^zp1BOw_2qLMU{U{c;Cf)79o4eccxIktDw0;6s>tO;~i zOFlI?9de^^tX1r?yR~fZq%qJ+aTi0jU7>T_YCp$rSqv9)TB9-Ahwr9l;Xr*UZ$AlV z+Msfwm&MZFt*XuyS|5h?1$Td%xU14MqRj!*Zjx<OMu>8h8X=3#j8Y-7TYQ z)E4HpN9!+mo;2QHGw1nE5vE7`P3U4Ui#H6_Ig2A{ePCF~UUBd-XauNF#UJ@N*=-!p zah_>EhxQsd7S}Q)sE~b-AnhkfyNg{u4QXz%J;uotLw3&8`A(yrc2RY4exlk&)y3KO z1e&#r=|W#t5|JiB+l&Wolde=)?Y3`S{YsOdXN;Bhkh9{02!r<{>f)-3+J}CvcH6hG zUHXz6cE-JFIo3w{iiEVAzRdVKl4bz}S@OJ8BNdlPhD zRhk*fyYc-JydVAnzk##xGEbE6C^G|}PhhkOJ_Xl9?LqwsPvi4*%F>Z0LCX50PGn{M z2j{%&kdC}b<=b5sf(owx#^DvHq>1u(3(i47>#PT%;wlm1Mi{%djL#vG7ixFha88fvuYw%7r+_Q?At z{WrE3;557nHL6~P!ea|X;=lHftG*>7O@c1r!Ci4~<@}>WuM6VUPI!Z%|Lwxzop&O= zr0SZIwFN#7)w!_bu;&K+-YLK0SV_5vufHhofDxh9beJF|%!g1@*v_tt!us?jA`Y5c z#J&}GIivl@j?J;I1|?Mx!j0OhX)Hw!O1S;)cdlkz{ch+&Rd1W1PWM@H*6*CKc2+u#s&PCVY-Cde<19@Y(2ks$q{~ZBM!)v}E7Ngc-Yz zz-AL|&ci+!g?TE^!gEmVG%^1Sg-4(!?(Oh7_$-Xmsvl$RKuhdn9xYn`T!HIgh(T<; z^J&;Pu_QpQO?&JP!>VyOQ9KtBQ0=C@1P~2swpdR_tric2AXhrJ< z?Y6*iXup?J<%MiytJSv`w9~C6Z7!s}*K1s)0RamC`~@GI;XCjw^g(UZc5_ODox+niLOWYfB?wpY* ztu>B9y@|&`Z{Sn#6x6n-_PDh}5bh3WwCT-Td&t@*-3#}@ei#Ss2rS?K4&|yQNxiTG z?Mjxa(xDiNRqYDd?O<8Qi0+3&P`?Q*8}cdNNu#Q)u2k!XPG~<#zjHhZ^~Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS@R7pfZRCodHnsCOTLjB&>NF*3HTSpMEZ$f%?2D=+bL^cV0*9|*cCL{UbJrq zwa6W|U&GfKaTjnE_`!`{uh2C>6So)0B4;%G#ApDFSc8A7jgh~GeTL(FPJ3Ul7U&OV z0xOGYtljXF#31grqpGp4g?U>$c-k9-A6@^;EvMn?3}#O^AT{+xdJ^dMO394aU?E@Z zI{Zv~!x*aQN zc&_7w=604F>KM-ngi84blnZ*W)P~L8A}@d2**?NAFy$PKhp94qTMUTU8!{>J;n`0pXQ#iq|uLaTs5aAxT|6N z)ba0$ajg!1PoSOpV_*)@)&SYFQWJV?gu8ue zU~n%3deTzzCx(kt{d3b3WIOP7DvOH#q*y>~TY&Ff-xm|yPVoFk;Nb-K4(GF4Q~S0S zN1&L`cIj}uGx)t)^os2#%FSaz&<_Llu&R3W$v}T7@Y2uv#dxMC)X+Y~`pB(L;5TXr z9w^hOME_FguMVV2`F<)%?C&`4(}9bAN3g`%wLv`%>;ZIWJ{^1otV|0&ax3wEw2e@y zYvCOPjsX635aqI10_e4dX#%YbPjL6Mq)NSczeW93XVX!o)z=Q)PLB6SELL4Q0*rS- zCRm5qv?^{BJws*Qdquxg~Ytovjx@&$2@B~u?7i&2*jr^mY>T3?PzImM<)@?VcrV|;i+ zfR()yJYDpA(bJPW%wpTrb6E`o{x_ zGI}^gzYWkI#>%*uzo3J7f+bUbHP~`1ak?$=>q>~LjpJUaVAwVUy7&sB`VO9tPG6eO zfF?cq^AGy|z)Opp$%x-{6_Xc*2aPgX(zwvMXR3L1+2iQeebUh^pSe~t8vxm#s)|RT%XDi_U7{gNh zpr?=DJDnSBxs(LZ!OzON-Z4h)W1a0 z^&_y-H^yzZ4$pdLt#nU0gQQzKea5Y5bGdq|Ppx`<_&?N$w))aX8%ryC(xbciwtOY+ zIDFbhpguN9#(-UyX$xGRH)*%}Vpa3wZS>cI9%LSsHYXjI z1f5dOv2_E_0V_JGw>sRWe0V*5HSyX=J_C04_E;O9e=X08@#@kMqzlkN)5{bTRX@?# zF9ddB)m7_ybtROcGqENCD@SJNUOSZty?_SiWjczguMYNoK-gqz5${oZ+@KpH^F*?FMt=V2d$0`))n?m!A0Oet1r4vJU>Ch3yn#@O~6dxMW51r3k}{5=j1fm zC3-|wH_3%I=BTNu=^OOA3x2}c*P;Cs$(-o)E4ul&OCa+RBhv&a7?boX#i77oG3c{< zCzEsq<;o)exI{9K*Y(fVWHQbJcK1xPS#(xgBb&GU+2ruZ|LH9M_vrkiwBeD^M*^MV zy}XQ~!#?S;G>NZ0la(PcUg0`27zh^HOe*!clv@^_Kq3IKKX5til%N)`CK2tGK6VMI zsbj~0;xlL&ftb2@(9TeEeyn6iQ)|Z6V z0R9eGdFsfK?_Erltci8Lf*P4vh2F6ylG5XSrAf|KZ>F(o(HRkAmJLdMRM9ar`zNWB zfPSIyqEmU-%nobpfNx#vT3JFP`d|HObXgpY#PmNi{H>mnp8;}D8lSp-m;f&ha+j==+Wv!58PoV1&FZ!P!$zNu(j0Zo5d*`%k z{?#N)tU|aX+ZFgL2#ra{m9d~pdjr#Vf8h5$AJ*fuy}8uYkAyn`e-( zv?yyKwxYdP)qAR}aXOSw@?(Ji1tbjc2`X*wzTs>HCV<$1xtRZ?*^#rv!1@C{H7U`5 zHNG4S23o^3Au108<3PB|rMg_SD39#OaTFSh!E^@KgV%9>usKd61J=(;dLo2DKvxyZz`tNI zcmX^MUgsKk31une43sla&OkW>R literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_home.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_home.png new file mode 100644 index 0000000000000000000000000000000000000000..9ade49edccd8de1b47529f90ac00ff820f7eb31e GIT binary patch literal 1689 zcmV;K24?w*P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>14%?dRCodHn`?+wRTRg)IzC2C zhAD-qNdwKuC@qnx{7@l*5@8McK_MBC5JHIjQeqJHr7s0N4N|B;0;7~tDy$DuRMwms^Pbn#UhwDa{oiY^{om`Jz0bMl+&f}~H=hBY0iOY% z0iOY%0iS{VGB7wexCFcfegt2D7r?aqMjR%QNkRvZ#JKEF$W_B+D%s0q@>9WAuFNRz zG3vGK6;wDP6P^QpR*49!zCz=e3Qs9JX-sq>IOWL32XNPcd%$T&`!2YS?37e65))hr z1{{-r6>gl7OnEN&)#3Lw+*ITDpE@$J^^OS(^#o|zW8kg;`+zoCn%Bok4t|${YA;O$ zjs`CSZRa6YhfS3BPVm0&NL`lb!l1sijREfhv18!2Am37XgiQkP0c~;#UmQmqeq+HF z9e}zl)s?Oo@GF%6XD+`|IRtitFO^WK9sxZ`#Nl59j{}!Is$=2wuyQ=CeM+q(ZZ`Ny ziInPoFg>j}`mP4DG_}11G1|nXT-^jA?sjkzX!{W2Vl#=fM`GLsWQl5%J!g`{Jl4Ya)mF?1PEn;g@RSUo_Nsy6u^cNwT&f)MoxaM_cPBhBQpIudg__|7q4Kio5l zFK-V*h+M{BRDz@`d&T`(CBzkn_?Li>fVQ)WC?`RPxCrc2Vx%g2M6YX7S#ylj4z_|Y zD?UM}k+m*sUfWTKo3c(sSUkoX37*nIta`BtV&H3mtaWV%Ag&CXOrC9wy#`#+qNvMN zwJp!Fhhj6(0&oIo`xs*KkYh;&G|1D*b6Onrx530*Wif!Jup54g4gx2a{Y{!LyN)L3hX%h4$nw(mCdBwi-8k*nJ*mIp>I}CC$bPgr zGH}5TXxa#FbPWrCE0B#^+ZLC914j@27~xsCrqd7ZZeTu%LQ2Iz3%dB;_#Ml$bk>IXj^U~){jXNv_thxQr*!c zHh>_gNsz?<9XMY)!jA*@f>mIw4%em$sn=??vo7A^n%-ksZGlAuOrUX*<#2@Zc5vR} z?4m5~JAt`4$euR=eP?W^7-d|y?5`#35x5~NE(y7h z_UGz8(pO@nd5sgeBI>c72V1PuA!Aa%<&1MCXdfLTV~LI7icV1D=)<7q6BO|w`2_g{ zMPwkN*`Gl^K@k~%6-m0xUd_=rK*pPp_;R;7MdV#3guOiOz`shH16Oi zh->{4Bd&86er4=It-OwIrEjWy6`ml@fNd!411AzF7T>;l-vr%ScP(^@8M#bUezUlh z`dlyr1bt8!XgdHtr%&{=8XU8>QW7MSs84toML}gP=##6g;G%{31Vv=rCn%=`4XC*7 zs$PYv)}%GZ(wO!PI;^74QS~ZRwI;1OKaE_XJAnQfOmBW8CX0-=USOMObw0FD7CC`8 z1M0UE^5$T1f)Kg5iUuHBY>WLiM2kxGc0z(My4>V_3UrKb;PwLjEEy_SlQ$;vFChKf zAGz6_$9>nHTt{~WCrNAVkEx>NwJz<2aU^9O2zz~8R^CL@y226>HV{I3z)s-$qX~4O zCK^ObqJIPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=Vo5|nRCodHnn{RNR}hB#IpLIr z8Uz=yg9ExSn1m=uKrtxBDF!2oZW`Q43=J9-vWiM{5m7XP3s*rD%uY8dEs7y%a0pId zZ~((j?d=0WD>wwMfhXVs*aapRD%q@)fq=Q-e-I_x80?vKZn?*!=oauAxX9|< z6V5UL7?}!QxiC|sGIcYM5sWzJrzjbJ{JXQt74Y)6GFzp?%NjbyagEh|^#`)hsX-t%jU)rcbLQ zv_kuu(HldBoMvzjXgPrry0n6-8Q-lPXfF!J8s2O6v)*^%Q=*ONs`8Xi=Ke?rX>E=+Lo$u zBsuY$1HJ*n!3V&K*o*|0h==rj!QJu&>ky?AQ|x8FK;#bkPN10M3-tehoMn5!QR208 zOkYTJC};!Kh`hoOViO5Iy{iePe2&wem?&s9#snD+>}6Wz5!rmqsD18oN&~+VxDh#f z{Ghz4T<#RG8Y3o`{lq>V#HZC^afHLi)x-^a@Sg_mbWB&%-yecGU5?Is5Gj4ngz{=a z%Py4d;HK`RJrk@^eXZ;Po0VQwlN|cuD0^Py11;lX_bHeLW&0=O^Tg;ExN3dZQA|hB9At9TR2enxCFTiw8(!lR4|&a4Qa0kHO#1!_$?+MQHQyN zPx8X-o#!P^(aRA5l?eLRFfh>Qp=w$L6>5ocEUNVTEQAS$<4uQv7{*`%GNs}YoFc?pYY z5tRE9WB-x&SN3OZ=lh@F6ibVsB3#8}bJly`X_nWmpm5h?BNMdHkdSzJiGNxI<+{XJ zUZbha{y@3M5ay(&MNr;LYz@`xpR_KqypA|AVvLdy^ho=bpK)}TZs$f2d2Jw(c{&-| z>y2K2mB6QfmX(#FU?e{kYjJuxRcSt#eu51K+jP)!Tk_VMwaawLZ3wc;1edSFRswli zeoyGvA6wS=`OIbx zd(WX-QgYsd2qXa)gKWODsimr>rpvfbtd$%|!I>a2Cg4F1Q@~Zx3n&lB=@;+`xt^*= ze$Gow2P-ePAL)~Ojp0DQ5Z9(@w}p_~-~>1T{(zWwuD0}f@eFtdJOiEq&wyvZGvFEU e40r}IXW$J#2QFp6EziIJ0000km_uTu(J@-84d7t;=Ip=-NfnV9da|PXK^=Et%*V7!MiC_qrJrWZ1e@Y>lJap;Fcq%QDpz%p2r0uGF@; zjaT4YHm5&Y?$k{ye>)l#ZT!C2r~z23E_!57N8pzvL1^qG$oQ(Lo>r1rQ>HebyhQ=! z++%C;Ua)Z}c0|+ujMl7XY*CpJ%S%ZPvz+ zy14f^Q!gNrl*V>TGHLn+A=mrSd0Z;K}+jGMOv#&GWH)QZ9R*ehRZ zQd0PYkr+>>61$ylg&CgSnsZLKvpHauB4%e)<+ea3?4;qh33-GvZNom4f`z1H&MvtS zu(d8iZ}Q>FfDVUgdHh8;`r7HIaO@?czA%`M!xEX@3BdzsM3n2eQOoErBhpm->1l8f znDGoga&%rnePqPxCtJVfre{$1%58j~vJMLRF&v$q2-xg7dAA`x*6ZYp55Ff3)wF~B z8TpiBgEZ0hNYt&kw6c`OlKv~#ayW)pmo~L>o;DcH!XKCYd5OVmwp+oahOX=#zFpbq z99-0Dh8OB@A%MsrK~v3zIyIw#Xv3E{{(}oN>7c_K2SVhH53mI9%LV60Ou z`kTW^^Yh0dr9H1qn3+xoe*{X(T=ryvV|tRv$;5T<>*8L=-c_{eulXS&?kpWthUdw* z|3-;bZJgLs%fEY%*1F|#=HEwDGuO!4`}985ippa_Ngu1gZ1%nSYPR!>-u~NW0|uEH z6N62Au@dpJ*=FOGxVi9%`0UE`fd-TNihaA(Q<2%4R0{ zUa0H~>n?lyJo=fQSz)aY*ZE^%uEEj@?d$xK_6W|REOSgFvJ?*n=kmX4dB`m;x6r1w z=5{^4xH`4Y#X(!rhY-Fwr5n2y^)47&59fAogiCYT!W2g1M;NUn%KzGYy{;H}Uwgl& z3^+9759ifyl76=1jeh^k^A6&W=;e1eD6Es(`cl2LWE&lyn#^eK&h!JBYm7sC%9X{t z_Qe$1O2JrE`MAY(A55F2ZesJKdgVO}tPODmJEUTb*fe|$?FX;>xZFHO9j{h#2iw6j zIoo+0dq&9QN+&(+&h{>jksS3wed&|kQhtA2x2)UvR5kN!1Y7`O5*2E0M5P8M5mi)4%rmF0+2UB9EsaK~0BI8?G6c%%8~ zP;`iNDy1&5Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=$4Nv%RCodHn@flsMHt6t+>InL z22IEzh&Ts94R}%GNe?;XkW&`Cnu~kz9t2s?)3^sAf)~M@a#*}19(GS2B6x_0Toe&} z1rO@_ATM2fL_-qR-(Pz|%{SFu)ic$dnN5B0r@N}Y$G^VmuCA`G>2$K>4CD;t4CD;t z4CD;t4BVX==(gSM&CSg@Vm<|)2agwcnB)BgICTCfu+H)80_Qk>+U<64aok!$QnrDk z;0)LR)$%3nuP{b^z;XJ7#B{+jD3f1l zI0Y8K&bmF2O<{YAqkNT#I3)k!>+&7ahtMvtTEh4*>ia-fMG}#(!l!)uL|k?y2{x${ zi1fhc9+o$$I|=qr8l%i!zKa-&WksBNWwx!epL{3{YhI{{ZYW_b_U(&57 z;YL#>BlRMhTr`MsJN}g~8H2R%>R9{>$J3xCGt>_toUEfQ>8a)8vnQoILA#<@_3` zwVs3i+s22Auf}!|-D4j6)3Nr_!(Qu2;_k}9IzGI*csuTTN_Km zJDs;Yb!AmP-81-JFEc2qx7=;tO3W&%xee?Dac_mXw+SDEr`XS&-;t-7h!J})aOH}Z zaGgrLU3Wcles3N7Y0?#U)0gWZelfRL$j6p$k4cc7F~>f6rZI7ryY1Tu=W!CGFP^h1 zmV1%}*(XKaxyLjm({i_c8{ryr1$|?z^sRhW#d5dvqLF^ZB_Lr&zsg0{>8CY2f*|pUUu@y^>ayuKSiUj2?c%fgLUnFnhj7U~ub<(XK+q00000NkvXXu0mjfins;z literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_omg.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_omg.png new file mode 100644 index 0000000000000000000000000000000000000000..e479479dfbace6e11bd9202e2cd7113e5f4f5fe9 GIT binary patch literal 2020 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?PDw;TRCodHo8OBTRT#&2T?IGR zFr`4q*b5;QiO8&r3Nj3}8~0z3Euo9LshhowMKUnR%e~rQZvrK}DoE{z7T85miJDlw zl?92KLgtUk?DO5uyqtMFGjryhnYZ1X2fohv^*qn_JbUJxGv~Yx47Aclpp8Hqfi?nd z1lkC+5x6}gFxc;I-@JKq2%isuC%|fll{}X?@EG{b;SA5O9ggt)d~k5^2G9SO5R^q= z8`ujjfnG(rvLRcG=6#gt#4wlu=Rw^fo3cGT?*awsAutYp0!@p2$d_K-+NJh62%=kI zxf`s_VSAOj1Ky}W!nv`!K4pzjqe-k&( zLaWtGU!#%Z41S>??aWchtSTK|E!W66f<>O7GS*Fpw0x2hJpQyO!+>jUkcs_ z$!H-tD>wL8x~ITF@B&Ev#eF+AP1}XwMIhU<@iUN3U*z*WV1qQ}HzF+_!`4UTJVqys zBkf|luNG-7`@ev{fkYkn4jck6f%TyBZWlQ}}K*Di2>(x#~=KGp)wbqb8+D%j=wBR{DMPt=!g5dF42 zr7@-hDqr-m*c}a|9|Ib?8sYeV$_p_d74njysR8Y$)Opv(!Frj2vJ$dc~B@`K;rtQ%qlU zvyv+@0n%rJFFGcT7XDV-!M6_EqZKn6RxgreO4dU`x z3jtm6J0GiW+f}uP{&ErUq>xL@9Ms(qI>O1-jO9Nc@|L^p+bw;F3D7M{B?`U>v<;O7 zngxqOx}mb5awCNd$11PbT$`jzzhZ?!B|shTomDb=l9qAW&zWUj+|>b3YMG>aUgis< z-{%Gdrt~r&GY6eA{a9`C^C@e&>vsXU5)+`4#==IEpHErKy)Zz9onu()oW+;h>SHw~ zK=bOjBdbIFg?l>gD162E3f6A|?dL%)r*V+h5yW#q2XY;tvtvPNm8q_-qm?leJe^9^ z^Ls}~<{r5k$5B~q?f`jLIaJSz+U$rjn$ZaTC7{tG*W5$<3|_%vh%Nwcg0do=!Vw>G zir%Dgrp<4ChxT%c!Q5+~5V24hc68g(tGpVrnOBCR=C6H307r!vhj~Pujdj?uH=SjI z^(T$j75VY&X+LEg==P=li$mAJapO##O~<9QJ5w+zUOSmsEgZUn3X3!@x)jnL6nL%Ny2H>6G@ zClnlUE&XFL&wcr%h=TSW1#dGx^$fGG*A2CNl{nCp|%ORHbY6&A*a2@Zm>2f3p}q< zc6w$ilwFc;yuq%O9xn!l&9lCG^=-Npi zs2_vRYC9&ySSxJ=+6c4}Xd}=@pp8Hqfi?o!5%>qduP7@_fv7+L0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS^@<~KNRCodHn+J?kMHt6DR4gE< zfQW(wi4rSzjY^DN5>YIH5RE-CqS(7w5DPYJ(I~NCZ&*<*A-UKw8pYnl7EnVVyp!w=Dhtot#c>1%3e`(tsTh>lCtq&gjILuH|F1vTbM8 z(O(0sn5CDyoS?nI9FRu;ARHD74!;-p%NUOe=_Ne$HUnRSC17I0kCo_j22TRf0x%+` z+a`Ph>NWE8w`b5^1a=N30e>iX6r2qjLOKZ#`6Iy6phOlbQ9RBnQ~v{W4(YZDk6>T8 z1g@jq1&jlWo$M>x6(xt=%HS+upEjCJo2PXQ`K3~Fv{sr;t}+7u>Vmh-4e$?hGBwAP zn*cVWz;`ls^aJe`()=Oc9M~V~`8569WdxrKENyIqAh^K_ss9MNTAf%Oy&m8h5Tiq4 zww90aU@!rk1X_MTtJ7w60^SEKO{LK?k5E@9f42(MGdqS(AMla0OPX3SN48m~@^nn1 z`zBeN@>m-KzJ5JRQ>;8xNBL=MP^fF7zY44ovT3(G684=bde4z-9Jc$+uAA@ z>Mv3bY`24umKcd^FZ5HPBP!1G`tW8+U}zVwleEz}-RP8wC>X4tj!CKLzOC3p|~jHAomtEEs)A**i=m;^mJCi}vup;5=;tOGP%Z@}CuDdV zgV3QBb~EYzNBg7hDIFe!++U-73U7ID18;W_qRC#j&D&)0vCHI19~AjCrxR;xdvFYB z*?n7I@P~jUz|!_sM|Fh#z&xu|sE_u#ZQdrZcF)NH@K@?v+Mu)>fOfqJN%wJ}!)1(K zK+xCvN$T(=vlP5DLSb8A2kGL(N6kwT*%RCkw(!B>?GG$1k`9bcU~kX}LZr?OxBh6a z1N=#TAFE^Q=xzhF>ps=;+f|+9-UOaDut_4+oZ(+p*=Qox9gYU`NZ@Y^^fabU@HS4n ztCPHL2SYU8CyUaGU>xvsjO_j7ES~5Z@28qJ{&d?Aod2rv8?`0as~|+`aPS@o{tjRk z$f74u$YleFpI%@_A>eGv9iyGfOF)p_3IUVCFY}khVqu_tkM=Dg(&_(9klQbfFI^2= zdOwz1ZhWFO+KANeaBa;W8-@bH*Jl~K@+GDZQ0W)4sfLHoN0I=Aa$Yt5GHnT>U9%;v zNZr75mPuVJOvz0GJU@5oYBqW$l9^D30=|a>OE+eiR3|3V^EMjwaq>vH3GlDlSRW0Y zBY>rgyiTZ%fhPK0z=hyZpda83pnN8QVIcS=1-_<)tASR_k{>M;uOc4Kw*!{+fv)9R zl=?YVNL?Qii@uT3?hZZxqHjU;wL;bvj06t@#mXW*%^Iwp6?L#$BLYu#8D4IEBGaBm zw}O`R3iWq-dKxwYCD*a=RsshCJtd*J3U(%GC%>(Y+2(ZuZsF4UlXfp37~TM&rQXuJ zG=fWiVvoEpxDEUU@}Q3s-!&=8c#6w9x{*UqyJx*#mNZuc=LmHG*?U$wQrA94E2icW z#n5qPKX3*35?GpFlYuEDuL)R3gM{?x_eo0t`Ito6lzMGKR~Vh)TmQzSx#L&D(EJzO zA0gB0Jr*nlOF-?;Xav(?)l#dLN(^qWMuqx4l%YWqKcP8Pw87gh?MDd7u+fcXO~1)+ zNI?B63F((Exu=OF+koy}iJ>X=Bo)1Gw56-pW+zZGfFb|wf=9BGfv4236*h4Umj{n| z2edUOb+Nj!I(plK`@ncmG_Wz7n(#?x0PvG7tfqU)NdSG#F^|j8(M;OwrTIdxW#6uf z|FNunQE3=*AC)F>w~ zzSL>GE}j%)99SjsM_o^z{SdH_cFA9|!qZ0vOH&gcxt2t@#zvvu{C7T-mpi^r??qoa z%1H#%C6ZZGz~EQs*p7&0jQNtO~xd0_u9z zdRH14TTR~D0c)^hq^HL|(b6kgBxnx+{}F)5|nfb-U?t8cn8EtuhLVX zbf_KVUAf)IVmQ%E!a0)(iDhQVk+P?A8W)n$jj(#6|QSEzMcE{-FZ?wke9j z{2EC+n~fuF)GY0lZ57wR(LrDq&^!_&%~6Mgk|RUhbL%De)e>*%vDRBVO}t!aJy9R# zR5F{`=)5!xyadvy5#i8GhgB%xzdz7<&CO))V#U7YiQ*U0sG91+)i>k&XZl zgPMG+BF=*@k?(0&evON<&R_O*m`{6MKNz-+T>GH2z-$mB{fak%k}C}BEAKk-{2X{_ z)iH4D&p|Wbm3$q5*B4w37JwLO_0ZD3Og;e<_hpk<=6){vEy<254z=%?3GAi#T-uWh z{8cFT2E##YV*Lu4{sZov{GW@3l*@$Zi*6FffTiGCa#@f|A~@D7QwhC^(Fjoad!9=V zYT$%U9tZq83@b>_!riq7X|=Bqbb1Jw29^R(n!xV@o3*d3E6=7?b5O`VgU}bg4vXD@ z=AgI0j1K>Qy69w`>LXAef%*v4N1#3e^%3Y0Bk&&z_^u%vmPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?AxT6*RCodHn@xyTRT#&eMA2q4 z!de&@vlz(S1ev(8$VH$C&cNiVcC)B(Cv9dWI0zB0#LcW`F}oB~S_IjLR0|0T3M>sl zX`&Ca5+)T>n|}ZC+;`4AbMJl6dGEPb&HKQg^YuLc=Q+=N@45G$d*5ZtT4^)TW}wYL zn}Ie1Z3fy5JeV2iYkJyqb92k_`5brwY;agl`G^C>vRQ{2%CioiQ-0mo*LR!p|0N`4 z1sDcLz!lJ|$W|QUT5;cJiAk&miaHH1ic)LfuBI#A|LXlQ#ZLJUxNsA z2T>jb8%v_S&e%!tDbN~o9{dHg_DHlIJqCt=)~RjaWl(mse8>1(tWh6O-g`n~`oIBD zB!4n61xCQbu``g3vz?+8SCJ@&Y+XaF29i1;e~6F^5r5)qf<6nCB|mVqSB zs*(`MAow;X%3JhJf^}7W6xoa0`H(LwifOROwvm1X0DiNP(bmHGd?P{NM82F)ibbN> z2AhgwksloEw8}ejPSao8QL`uruOXj6zO5+6W=}U9YC+ChbEfHE<;C4-Rlb2@u%cL- zTexwSceR>sG#e$(h%YZm2TDxR4dHwTu%bgd`pChiAG`|Q1?Rx5gX-$jSbuEv*yu>g zJKc1TR-fQ>IXDA+(SjVc=Af@r^mXtH=qA#UZqzA)zSbmrC$HFRx#OPCI^<)(7hPVX zu2$&ls5$171lDB}bu^)`tDC(A7^~$F!jT?4?JqJJ;|zN})t>^rifp5v;?bWp&NPRz zN0yi=E$BizZXD?@HulsyY&g{X2fPC|0o^(Xs;f_9Rt_&j)xCzXPBnYSJ>K0iLIVf- z;S`Cpy-5Dw<2wk(kHZ>4QugRKDn8 zG3wb0eY@^lqVI{0lY)wLfOLI1R-m5Sjo})gn0*<}Rqmw|)}uZ%^{E&h^tCWwHyop( z9N4{LY{eD3U{4v2Bcc9F^&r)y{fZ$UDK#>K*lsuW+5?Ib?9UpG?J)${ju?B*sp}>G zp#UeF(0SC;(`MI)UOS}vlu`Q3v_qQK#&UM!P|S)w6U|944@xB@L0b*ONp|h7nZ9n# zwMOBxX@@kejpZ!ma4~Ba(-*y2DV2}}J!2TOO&TkI7=y=6JEUoCEN2LZjor>|2}ekR zo;Fs|>j(Bf8jcrDJEUoCEN2LZjor>Igk!M|3)uy;xM?FjO0d7{S1|=l97AR<7osMT zrwpOJL5w>0GfsH!+I^50!&;LdyRK!b;U$DO4C%^n>jh0XQr$`47S{rEcn!OiW-d3v ztqU|EOp+kc!`1k+m_Mz$5|rc=a|vqvY2G9#`VK}_j(|Z z%}&SBgZaFPjor>|32#V(W{g$zRm`_%f>&vef;Ygg{#Zd>I?^3=wgqZI-8ObRwQ%+YZtsiY`B~WZ0$)zVv)mgN zOyYz;5$by@M+V7eLwb#N^v4I41F1-$n1N#VWphQ^`Ac)D|r(AVcOwQjlg zylGEhdPDIENG;;r6p|?P>fN+g5IBi`?Ssu8a1+!e;@(r1B*yE1?c)*@_2Q7g_JO8k zUr~|>VA2Fp&x=Esq%q?x_ti5xyNzDf{FurpcoKBoFwZ6}U1uX(apcMFOg}48YVOsu zOOOIRW1`b9vd#-i@1TA+I!CM{3VMUe+L$Pc52fuxQm^h zJC#G3UFs70L&n!d7sIsaSF@Q9s9XR=pWwZ30@G>GpE@xapSXcN)oct3={Tr-dS`xv zN*oS=ypK5P?#S^VvI>wp}jP zRQ}?4_~`~g(UEkDvCb7Pj=8(GxPg4+iDDY;&eDJef#`HAI@GT+HUXkOmnjQdT#i%R zd7@aF{WiKRV2u%w7Vf;OTQ&hbEKY$D5WSxy8)rL3X&*f4>WE@Uwjd`X$`VL$y4N@e zHfDV}rM|Lwu>KC^CxImCj(ZH)J6XDti+spey?4m|1XI-sS`WD6z`k3ftFnkw+^bW? zd)IiFg!YrP>2?%c0lkWB#UZYAA7PecCixmv;%k10iRo0(M%PxL?{oAC%6g!yTy~|? z3q4^5=(W@L;0y3ovTahxT4^)TW}wYLn}Ie1Z3fy5v>7PQz<;8ln;pEnlX3t6002ov JPDHLkV1ix}mnHxJ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sad.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sad.png new file mode 100644 index 0000000000000000000000000000000000000000..e01f1a23a9f48e3c7625bb038b2ac38f43ea3ca7 GIT binary patch literal 1871 zcmY*aX*3%M7fmd&hWbb?rD)UITGdkfJ}FYQ95kg7lp;ekmQ*#i(y@iu8cUTXA(+}3 zYe*YosbXTQu})F@h-EYt%V>x5o%1c{o%`;6@7>?`r8wGKgN5aU0RR9PZUb{VVVhG3 zf=>F~&0nlf2pHyMZ3(Dh$*-RbFke@=pPd~*{X`1_fJr|B_)aY+kUIeYz)JxFcuyF3 zx})&?=W0XY{jWYXW?r}21^_^9aF~Tl1aR|}16tv(RIg_m1X<$cV)PDcW^*Rk6;_e7&m5+Hi0Gs4K>sy4nj?rji8@zAmDWmip*)?x59NDRx|PuUXwCU_jWhERdXRB z0jpEGqnbQkQ#Te}C07@TnM%ptZTT2HYxnu%yp??Aso*fo>t#oz4TPom(vvy<3RmZ11BU z@Z=>XX}oeN-yFZw_^!|W5-SkL<6qqqH6lYe@77=6x!$Ol5MAxvGF$3vt&*Ou@v7zy zl0i)msl=yWbsH32ZnW@e9l|+(`JUeEgfbEGS9d%pPU`7@UHvBu;=T>s19ENd%+7d| zh7AHZXVo-twALsc*Q(|?zzCWsBaO%i9raEN{*aQ73ti0!fKK=FcnzKRo zh~f$!1O+9!Cx|^x^NuA^D)HH^M-8>)kikpg!}LxG&r9~`y@8Tv3 z_lUHb2th!`@_zVcfi}Br5t&Bqr#QmWz zG16Zm*t$LjbL$$69x6&HJukfZLt>imEEHX;SekD;Xipp2Ajfp-QRhNidWdtC$SgZLD7t9_hV8!Q$<7O`%$L$KuLm z18Y|z&XbunJ!zn*M&hUKnM@Gg_vHX(SLMtKk{e_sSHE>rd z^Bs^g>_{HVs(~Qq*6W)DWG0-q9F+>mH`psz<2roUVlqgDx8i?$-WZB1LD5->b{X=j zIvm4#eEa)shl7r-h42t}`VyhKXz6CsPnxeRvm1a7UzcIjtc`AS@&HM_t#^My78c-^7OZhc>tCeJ#-P5snKXV+e{JqU^O^aHK>-&z z{mwC!h+`HYTL(01U3e?yf<;iBXcamX!|qb=;R&}qs}d3@O{DIbN&u+Za9cpNML>Jk zhn7@{ifbujE0@b(L?^F>8i6evtQJMrNX|xnr7gS5QTvk GEB+tPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*ISED}K|vI?Xc0lRh>C(9iz4t32x=J`xoKg~T~T3Zgtci=5H~ES zu%~7%wA<%E!gLyc&V6`aGY7u-JLh+1?wrq^JNM4-_p_uVSRfDx1OkCTAP@)y0)apv zU?C8*#0nymNF?Sl(B)`S3IiUbO;0Qq`;Z>5vAl~&difTpcP~;3Sil4*rEW?+>pQw_xXh6mN zasgU}`jEDxevz?$_RWT4Iqb{ML?3zmT(*?>E1xDN+ zRPHAcqiP@=7aGdm;?FnI{5%B0Ml_<}4B;>HlZa6@5SF3=1xLQIwi{`F9s;2P#T6WJ z&-h8is2T{9&?BLttOGw|S1IJOLDr0cPvgZ_qUjDVnjq&Dmm;2zk$ai=3U%%&{$AQh z+l*MoNRKxf;LITB391_}SDlyNFgwkn>1ziu{oCd@u_Ndma9Gw^?n-=wjh1S;S;f1zsXQN5aiJn z+oHTWz)2)#0_P>t7VeQlL>A?nnhd_)mFLw&%GzFxs`nt-KWUo_q)r|D>wn|#Wwrwk z$2dRXVduRVMaZ)?2hpN&Mm50sPKvr`=F$E-{$?}gcq|*rI{NE#%+F041>Q%=*lu&A zG`yHhW0h;0d1m*yJ!Y_FNZ(dbHT>uHnxp1y4f^n3*7$+Hy@=|e7j$?cd*$9`lD>Y(ix$NY?^C9?*}HRS_np&EtUx!j~;;_jy~xv=H0 zF(b;6-22vc#a}8$7V=6_brLKM#R$+5$(O%W+*_iWeLZwf$S5-TeV|lfRP8X<=&RIHpecCI}IxBnhgF6REuP0 zjjE!!Nm#0*_-2%hy(YQd(pABQT<^^%`|!0~Iz3x(G%N#l1=MY68$u=lJ~GG9kmKj9 zXg*@jn^l1Y9ND4EKhs9p2%FT%CnlmAhjW2IAP@)y0)apv5C{YUfj~hJ_yflIGV(Hu R5WfHb002ovPDHLkV1hP9G5P=i literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_stickers.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_stickers.png new file mode 100644 index 0000000000000000000000000000000000000000..3448ec98f9bbb98471386046efb96b1a3062e40e GIT binary patch literal 1678 zcmV;9266d`P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=_(?=TRCodHn@xyTRT#(T9m0yr zJ|wUbMT4Yr(j?rJ8yB@`Ah6n*jr$g2L=@8|TE%RPHZ5JW?$ab;qL9Re1=0`%(g&4= zU{F+AnA7iX?eB&ztd^{oSg1ba9%*uXi_B&c|p* z9hk|gYm7swC_PuF3+XETh#g|J`bS_-fiJ<&;2>C)YEU}hH6Rb6 zSOpq1I>d-Ullc};AezIrd&)yaYU`W#whVoQ^sbcC&ZmE+K9p#bpperEm0w@QZ=(dU z*y+>Ek|!`d-k*EQLq%%q8xl)HA0fSV%6U8slHwJ`PE69oaYLaKWK#N3+P1D?^xb7% zOLgnZJU+WiP$~N@RYK5aP>>kcjm|+a0kqg=Ulm_hRZ;4a4v&PE@9Ropx`R5A^IS=r zVAYBv2tsb5H;;qIz*evpOtv3|flG#fS{K~vZTv;>E65@-otP~1F%i-RHgttXCxSa7 zRkAhfJVB77A#?()5A<43^dEsb75@fKgLi@Z`S}w0JYt{cSgYviV!;yl6X?^+##mjo zqrHweP5>)sDR=?g4WjR212 zcIa#$85sV4Hma-rYYe9lblU2Y{|CGYHkSoP{c7+FaOE8`mG*Av&ANt2zgOlzsm>Tq zA?QJLL#vKH-W>+}!2dqtQKr`uSI&{SDJgKLF}g3g#z?>6RM$<n#5fy7z)Fz&O!S z>T#esN4GNcq`C5PonBz5(ucz+pBVqzjg)ki$@UraGzV3c2cm-YG{WIJ<23rybL@E5 zbz4`~xtVck&TRe$uhZ^Mpe_Gb<8(arTB@tc9;0}Sc=BBrhJ8({uFM;U$ytou1Lnb} zK*P(5&aGY1J6Ez`;AUVa`~As=$`o+0*Nv2P_R9;{ycXOAE?@fOHy1&#V#}3Ulf9QG zthavs1)sGE!iH{`*#+i+x07`XakL0rY4idWj%pEv{;l9!H{fCZ>bhKb^)cS+6+HY^ zCJ5bC;25y-q_=aq3h~z3B~E-*A_zS_IX-gS7u8&p6z$-62H1Z+(55c?O;>Ct6QnqR z9aa=Ae*j{)G{sJ*=5RD8k4ALWHrtI?Y}t*Sjx2&gdoAT!t?YzM(dAwIjX~umDsZ|W z&mPf{#^^6tt|zBma@2X8PJ<9h3Qq4m+63+d8$s~G6?Fr! zeuy3X9t3uH>8MrbIXbeK1+pz4Wuo}n8CIbuf&et!?3`217iP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?a!Eu%RCodHn+c2*MHGfvZV(TI z6_hATKn_JfMIey`i7|=_20<_)5;ewfcwpr4zz`xvgNkT46p0anc#)t4#REjq#3*PG zH5?*GKtVxnL>64XA7?kUHC;VDJw3Ax^h-Xvt6sfVuio}lSJe#FswI+SAjv?Ifg}S- z29gXU8AvjaWWXZ>MILnpttu-kYe$E@pajl`eXs#m!=j?1q9a^SEg>mIFc6l5pKM1t z5sFWl3^CXq@GWE`duaR+)H-Ps#o*e&0?0+yVch$qN)iJqhN(~rUUH1eMQ|V71Vi9? z_yb(>35xb7bfOqQT^I{{!6k2_Xz4Xj>g&Kr*bQEClu9MOk(YgJ>j+pA@a?b#T=Er) zZb1e?yT&jbln^gb0w09<&rbw-6|4Z4{DPu?ki^(+uxk(cXt`t!itBB=Sd02W(2*wK!QeLme~G?p_TIx=&|e2w z3NHB>#dYC(2w+JEJz=FQ0_xX8zW}cC)`b51f?fnJ(R!b^dw7(k*Udxl=8AHeLGB8C?(kO_<1e|dI0UI!$reME#)@C%v zNZSEZW@R)wK^rj025`g}>>;nARJSVkTIB{-`D7|~W-#UoTOU8OoIX|>Xg6-lcq)QT zVCgPnS;KfVmHciEbX~?^G0;}xJIheT%`gP)CoZGUI5i;tmhc8>sbb55K(S(_r|56n zI#piH^@c!>V$_J3wdj2b%sGc*B^e($WX!sP{Ro=gKBo}qL@;otd1y$Cnuwo({g6o} zW)%Y78i5YawWV;$d=zc6a$JDM#8eB0fxcIB$yQ4-DO6}UX%4f&wYt{kPiHdch3X(e zBVy1TIsp83^jb~d2HIeoG9{-_@N@}$V0yIf4^q~*puzVwIYm_2n0~K@72pzmjdVZM zmL=DrR>NtPJ%%jdv$>|*9?AyaLnYxa3b1TE`rJWqZYd?jFn7PEb!vztqc*|MuR?B8xhH zKDUbIy$GZy*Jt1g%e+425h)b!5$^q#2M5tlhDrF=PxW$p1xZkOZw%}m?)AfhVX(El-sgG@ zoop_~b|`H3X`8L;Ck(b2MjspZ6}Q=b#12_5rYEdBK9BXFa}t#~xpx?_RKg=!pIX!Y1$%t(lq^G9Cq_6T7FN z6kM_hMW=iQhX2c9xhnwbzkwF{jKSA8owtU!z;)!Hdi~NY@ZQU}!;}(#T5Zn)*H%XJ zq)r(Mx{PtgP9XXPg`OCf=t-Li`p+t%1$(_D#(--_uWv1$gS3rw=uV?FB(UzFImji4 zQRs_+tp9TgHhp0OxMU%U3!@xQ-h2_L_FsOR&Hd;nK*oh8Z92eGaEW&8*W_(5`EpFq zTKMU>Vhy-t7m86(&yIt-VweH0c}BK6>&bREV0TruWd=|K?gA|+U9t_uXwb1o7tqtS z2fRe{nT}i=R_(|l?wtW?g4G$$4hSncTWS|^Xz_B#0Cl$fIJlk=RB57*=?V9nfSfYV zfOU}mG#mt%>_#yXYUR{f4#ri!!DR4_iGL9E0UdcLruFbX%;8w#0M|s43?vyyGLU2- m$v~2UBm+qXk_^Nv1OEYXTIBm*B_JdK0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS@6G=otRCodHn_Y-jMHt83Ov|#g zLdhsw%f2*7B8`$RjLeME?WPFoYA?DK>4WvImW8k&=+3$@6!gLbP1H!JAjB@J3(1cn z-As`TQ_IZEkL~w=nX}A3XXbpod)~8Z?*o5k=9%Yfo}DviX3o2#MzyJ(fp!Mk8E9vq zoq=`++8OwNW}u_)VGj%pjK=4K;4yHo!)=t;IZ%u`>2Q#8uftcA-*t3!oTt3Jh@^}G zi@`c@0yIm~l?~Y%bIE6kL5u@E;3%k?WK*`sU2=&c=+U4X90IK-`H(L?x|LJqYY>4h zB+7TejErbc)3*(L0kp>a1dao(JtD0~H-PCt>(o3jA7ssz-Sof88nu=3;v*8%0s26U zj?u9abb)KijzBt2cO|84#Yiz!{)aCc?+|$c8V@!^B0dGb7id;gLbBy-%65np%lJy1 z4c7>Pbb_6MD9^!L0j3PsM@(O~oe%l4q?kHmy0!2X061bJqpgMWp<05#iF`Sq6hla{ zb=DQf5I;E9V-=b?U&C+NtQiu7*N{&j-L@ zE!;Q@y{%T)nvD!+#1~3ZUxrF`T{vF|ENNPB_unYL41-bS$ zCvTLB3D}*yVsFWgyAcn@yMa%7z1H@&%1esvS8Tv;0lKYRC2bt(;A#IND=IPGLLC zsDkT2W-9O(^*?F91t#R_#`>k}Y{*tZ@-a20lkk!0N)%kFF%AEfkC8dXu>NX=?sJfv z3GCEXdl@KvK9a1{3E7&NBq6IrU-wDLjHBA1*;zV;`Y^N98B2Uu<8$ulGw5PC#qb8?=(-;exs;8VZf-&7rIc7vGtI<-#F zU*kvQ>fciqKEp{CNXOC|>o2Q~vbG049nF$2)Q7b*zD4R|3n?Om>;j{!gX7!as-iX$ zIq5iEd-z1?Py7Y zntH?tdby&9&VzSAY_ZKrNxECMoK4vlEl*3OImor-5$jh39_235$j$&-SbqSIq(iNS zBiqi0e9g$SicIN6y2xw(pmCg=AmsHEm1STSdzBqVzp|#YJka~W1N;p1I@T}3UIThPUs**8WXIW)UD=l(`FlNPpT5>ycgP{e%U+m;jux01 zI0?3aH-WBYb!U`y7L#v%#g&}or6+ya36Xwd6eNT{G75z*%rb*ZJYiVZlN*vYr2@H~ zx5!D4H&{h}KaFXFjO@x^bngSlz#l+u-4*F#?M85?Yg6P>KQY~5rHDt@!v}zVl$B5y zvZbzW62(-BgR+OUOHGlsj3Go7r1*B0<~?%8eR{bq3XrAFv6P(JJ%@apoDx`u&Q z-=}AnAieT;d4Z{_zesSf@FxNL287k1ppKW1R28jIf@D8+B@0ipQnC4@*rQjxDTmE4 zaG=+%CH>SSdRnJ%G5E$P4L3o1Wj8bi_&V(?CQH$;uOT~4^YGedJ=0#DWsv^6jm~fr z^kU4PVllqd?2E})&c|8lpWva>@&w^SGbfas4T`z)L}VGn;drnUSklx^%?@}iO^|$o z&|{?-3xA}{8guDB9Cv~vz>*fnA#XR@ElZGm0lOf>YQ)xAdSF#55QLHxnn~IMXb;ku zO_X}0`II^mr*w+ywATjzRgXXP@H-*G!#2wd3vvp@kFnAbm?M^ISx~ zX6C9vjdVpm;P!x{AVxpZ@o2~v{Au9Jh@x!Dc4mS@cFXW;c~%*O zPUKI6m%$T2mtj6#ps@vf4t@m_fs*zdxE3UIj>;!s71+Xs*V&}wvMEWH9=|zYE6BSG zLS&FWqgLn>^W~JRxeR*8U<$&OeXw5`sX^EBh~*8A1n75$&w{&ve)Dr28~~q!9Xv{U r1l!ckKsy8N474-Q&Okc@r84jz5kz3P(;shN00000NkvXXu0mjf#+@Zp literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_vacation.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_vacation.png new file mode 100644 index 0000000000000000000000000000000000000000..29484185426a79b1ad4469640e5389b5b6896021 GIT binary patch literal 2370 zcmV-I3BC4-P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS@tVu*cRCodHn+wd>Qy9nJHz{37 zx-1%67xywGWfc)2v4$mTiZQZmG}eUGG{c&SE=IN3GGZYaxr`!`?kS|pTfMr`MU-2w z&$s=4?Rn4t{C@xc`+xtpxBk!e-FeP)p68tBJpXgf@0|1d{Yy%URE$6|0>uavBT%pr zD9yHK6%`dNX`=;b9-t2CFJOyMT3Y%W>Cr<3qy@MYOaU7~GWr>XaiBXm=7^0Ho$C!g z00%+3v=zhQK%=bY6CJ4q?gXnqCTRne4Fa|D9i_C_Ae=t~=cj;6l5|3A%wkXuwu67c z$pJb9DT$XpK{|kSYKOP95QPM$6pR4-L8|mCilaaSw@=6}1Y^N^;G<0lFLvz;GLNGQ z&da`DAlnlmx8ikVdigqs{8(^5*a2Mn3&9YdUBSq3Q0vW9;L?8x^b~r-6sVI!!7?MW z?07P@eVs$z7)-Rv0k6e>u+OF-WH>j$mM^OL|k3P2S`g2Q+%@+CsMC zF6#*SlO;4X$d>zfbQL6bB;D`R4Q1%}0eT=$iEz#{idZusS*A@x*;h-{v}i&a=kjoo;zt9yw-JLEU+8+C~~`C>&hsP z7w*)V>T3W!9V0?|+@}*K!%$m*AHoVq^$=(dYJ-P>yH+8pM7mqb8hLlKL2DN}tuAu% z+W%-eoM_~m44)FqLG&N$c@X9I0t1bPao{x24aAWSzQf}bs#{i-04?=2rkg@bvA-sP z&|~>La5m6wKznck&}Q-XASEfe6-3=MXq{UO7J``sIB#pv>PiFIv*V?_jiVEF5Y=W+ zYlxmy>5vY&_kq>~r7#F*%1lo*loN>ZCPqhWf2&0PV(^6uszJ|T8~J3j?d6omDZBXY z^EHl6Enpwh!=#6-0eHzNBU>fX2=47`H8D{8w#s2lm&r0)Q& zHF30t!UurXEv+{p4#IB}sK0`=Fo}-p)EttoO1*@_giwieJJ7|ukG^z-I&jAQK;HIp zEsS$eLDAi@s41P%iCe$uRiHc2doKOj4M9lFLdK-?;2&W$d_^4^EqYHT(vzzTn6FHY zBRcaPur!>E-O$;xDE?In4*v-7(;dapH7+or!*oRVG}WOOFs`(hA%DA5;n!h%H7=zi z)11y!B|FB~VJc|pRHA*6Hi`vHhljt%!!nOdBJE@+fE7S%()pkx&?aspn9O=JhctnZ zYXM(QLHLBzy4DN4m7rYc0y;7P=t*PgGcsD7(MMDb};bX zHCM$?>gWwDt*eUt5wA;R>Vf?>Lhx-1wd2(u5moIN>(G8|+`UiiRclq-$fSPG0~9#_ zk<*F1pSc`=@|$H!b#kWIZt`(Y)ciV}>(&W|UP-%eOuOdVk5t;r%M@cB(*9|#<6uEf zv%CZ-2#gz`f?cScA2K&trdTUrNym=kbJKe2t>kS4G0nfddRibamot0K&=^D|XUIV)yWQJbp(>PtWWn_pa^O1I1fP27P5H-a&QWiJDlQoli zISma3K3atwg})N99=Q^A`c zq-m*Jr>RLxdLywjY%xd=kQU@2Q{BWjJzd@JoYIUy5;GdoD6ypZuKiAt2t*^GOD#(y zkA}#k`lK03FtjHLNnc-R|C2yOP*00G$<9mYHAL?gpf5wTuUP|TV7G@flCYD$Ms6#x z3w$cX?RBu}iH;s1O~J1~N0r&wh_61;z-(aYVPCB%bO4)yzB_y#92cRdJ=7N9(hdaO zeKwL&HWt|LkwW{AVG{OQ$n*xqF4m#GQu#O3L8Ge$?O9ItP6 z$)66~#U9aN`W;S(+e(D&$-^3cW;tT}L8$_&jcPKQT&baSGPLlg(@MgxrFzkEKTeRD zHgJbN#v;{=$R!{dtwZ6Y&{z18$qa(>1*DAvUsAP^Y0t2&v{EY2vLf`Gq^RNr1V1LFc&m?Zpz zAg+%IWz^CasFOn91O-Qcjy^)y9FL=Y6m|+t;WhQN1|_3up^Z|MF9Yt**{x%&wF&GV zLrLFZ&H@SlAaM0Fo~O}%KO3k%|#0 oMxYphVg!m2C`OPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS^&PhZ;RCodHn}4iVWgW-40xI|; z5^_mXFM2D*Kt$QfLLm@kjbOxVtv}3NYb@7lfPY-qbiruTny%J#s2gp}tww9Ga5kvb z+y+B49ef%XivXW;!g10Ag%c3)rLP<&2?sc=og<)jxSkPJDVu$OdK z!bZ|Rc64-{COx}^Nf{1vVKp3us-nKKAzQ=G_*r5QBcKNkLfs;pvOVIAn<#=F3f-^| z23zDqzI5x>F14>g1Uj22zYpUJqCH952KWtVjp>CWptVP$_2`4p1zM-3!);J>wfvd( zC9F};lD_wZiRpmlkSB*}SPAoBWZ4m@PttcKschwmVyOKOUpC&1J^@__YjPs~AN9*X zS4Ax%TZv8C4vAv9uoh>{8X=HQ*b#{GE$UXlWzG7?>o41h5Bc(>1 zHh9scow;&Uh9%Go{{%g8-he~!4_FUVq4o_PHsxC}dC?xNl$5&c@TS4+0J{m?Pk9O( zv;(PU^k$KN7_Ne%$NPV2{~O#&|5Ky`1X~wSc^$~swTZ&pr2m4Qu#dibNHan|t%KX( zBc?%{$%*I>&I>P2yTOVcubHP6W!+8(jM546daCU;>3_(-4U#uuCyX@%>CaL(A2x!n zz|-JG?_)25ZmEfZ{(8FkEkL)|tEG%1y?FX}s}W#l?`hD=2F(W<_HtdS$U;#OE>EW4(~q1Y{oPlz$4kGIX`v z4<9JhZo=#I1Z_3vgbHEdi*O^D?L`H={%M- z5M9nzmU+W8-VM5HCfGL0V_+?4z)Hv1_PjiL!{D4yJN1{qwJ;5q!UoW-dY9LyZW&n7 zSn4}Z!k7-ItZ1M`i*F`IboJM_vMHkwS-^nyU*nWUcIj6`|6)+gR_2zmQK*a6pIOV~ zR~B|Kjp*L&`liL3jatJjovsIM4RS}u!4Ev$aAoEK|_zW3Uw zO#bU7Z0J_&HGP#;c~}V>^IU(8so@?hcz-*mH&V8Xtq!}^JDs9pUJ%iP!?+I1u69mT zp6Tj}ii%mWr=l_G<3XXsOwebXg$-=9PPn?F;)^+rdG#T6ohpVT-8hEYGIdGJI>ody z)fPhem!mZ~XyGr{hq9g+ z+V(52bZ$~lHcHedBzg5AUDf&6{n+yQ<=3;2?RJY>SH5;}3wA2+VClQg#j&o~+rU=( zcR3ro2Wpk9!JywDjxK4U7Ioqn36F!`y_8lt_}6QWm4i(Ohcz8hSUI<8qwkUd263(( z2>CY}g%Yy{HL`J5x5w;7^fAxgR(i!aRApB9i^-oJ*eDhKlf z`W#rfLyA=B#qoCd7CZn8V8Gz18w>upfvQrXV+@^x+ta~dyhWAtzr%Tbu1G(s4TDcQ zqnZ#oddbzR_$u6I4O5=3hMMFQc76yKTOYA``YCoRPc-TqbBq1O8CgL2lMs5xQs560 zK_|Dwy-B|ftSr5%&> zC}}P6X+ib}W~nbdo!${Dzmzs4=`HUx7G%)X)$&mo52Nx_X}b=70>4l`PcKxD{*S@R z>X2TgI;{F5*VNIC)*zMVr432C*tVy6+OC3yphNyWU`3yIw!`dHzu6R9`U4E=k!$GC z9-n=mw!u@@t!CvRwNs%j{!DljLQg-cgL03xUp0^A!9BE32H6uB!e?#JwEGFtm9QSP z@v9PCV7YRBMp*anMX0{D%e@2>Uge6X@;fKo&S26SubYO$gZi}gI( zLos07KJJfD&OI)nO;^HzDz-Rih`Sf0R?z{}bibOpXSI!~5jbNacGP8^eqpWz(~xbPfws^!0AF z4Ezq6s(#U$Q_F1?b6}PR>#rE~eKTz=nR;6d&zl*r4%KFXzS4@k+wi-zeY>th|1uNg ze{7)hXMKgJB3HXk`hk<|9Z%{nBGm+R!8I@)ZiAv%1pR{b-TQYa1~3M!Oe3I5f{~fl zP?LEr&fQRI{i+mrqfP|TYX+moXQg$BeqS|qs%8(;u?LE-szyVqx1C^q;6{@<4~q4M zjbA!Du|>W8>vcy5cn#m{V&f^&D|H1B)Hsa24C&f+guD*EUx{55v7z-vUpG=4N68D- z3yIbuu@_zfeOcKAf56Y+{7N3a)t zpOMZUVPwPM89Txz^1q_5f8?L}lf|I4(bM6X&U>oLW;!-?ocf-hNd|Z&dz$KEbA4A!3+8h3=G|(_B(z`e-ZhWXf-!1myQ2hTvMZ6YhB|rp<9d2Znb@&)L_`i`$BNb zls%0PdzB7OH|sjEv&f?Hl9T+=upq<3998oC50_R7><_SSt84jZRvY(~EpG?^-Nt(+ z=I@o&_ZsCMUi+!jDfgVE>+QY!0xz>o*%q{LeG>of{4@W1+&64CshU#nRDC#8=3-c` z@buO*v;NJwo^9Eyx^2hQKS z^Ju+@!f(Y5xlVmP=WcDWQ#QL(?ZsFm+yAuf+)VkE6K}s2ev$kl_JvxB$0z24HLd3s zuAjI)=bV;(&9Xu%bB`n&VdFOxYM>h^6* zU#{&q*YZRs4`YX4cT7@tGF@18J*)3q?2EZNenwJ>KBYN57f*S*g-_;O^FD%q#r_7q zI`NdA(ltADIL&9;Fl}!4Ubec+KlMYwteeJRD`Gv{ee2(A_sn+;zWFw{XtDmnJooYU9c`rqB^UT9L&D;JijO}R)PQJnD^!SpYvqt&M;~Ae${Abc};HzX5 zQfP0ueD|ffh|2EtzPsL+WpDN7eA}Yx^5rrj zmF4XoC!Sq8Ve_TS(m$wy<%Hscl5AGa3C;&zUgH8Aw^mfefsb){w6;fs43ppXun7#7 zEOXwy;Chs}r1e4cM~(jlJ7yekP0aLLmLJ&5^vH8<$hOO;JWiRVSudY@xr1re?2GIX zt`|3^z4*1dbPfBl&2uNe%nNK~maYF-!FXw^jf3c~lT$x1bg(O|zazM(K!??!Ikf+0ip>w(OPk-h7NcoutX>#{?<`+Eub7=jH)`LfS&16-!CxnPI e3JM@0hQ|GsJNP$6PTtiB%1xfGelF{r5}E+pdYe7~ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_autodelete.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_autodelete.png new file mode 100644 index 0000000000000000000000000000000000000000..9cf64dfd8422aa42e4cd9ce51970428191be430f GIT binary patch literal 1875 zcmV-Z2dwysP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>y-7qtRCodHn}3KERTRf}*B`r@ zW~N(eKaA~{X38o`X_OYFf)SZm^y7~*F$=OSf`V$XEP^G9iYO~tvna5Fu%aK7yHrqN zYL?MfXr`oTzcg2KQ+s_*jBt1M-aB_@?!5PO=fIaYbM8Ig^Sx*1&CI>`ZAC?Hc?I$c zNMjZu_wU=dgY{slJs zl*XP%d~q0LHMj|^261h&u0W6+1D*h1gAc*Ypjy|rtbK@{1vY}DHak2(hiprDQ8Pk4g;#;49!>70tM7A-Zz?^ArGJw(t5umQN5 zJfRxEuq4Wfd(M(*T@udBVi0;E_`@RjP?LOZ9t5ZO5ChNE;5(q&-<+K1gWn4WVkUtO zRiWYd75pcANve>*Sp{Z*N5MicTxl-tA!3GsZNO%2G?vd_v{)r$(7l1&M{L$YMNq)uO-%FwxB;=e3?geK>h0$j!*bh{DH!9A#9oDN<=Fsu&&O{zMl6wevQPJ=t z$B~O=^qByf!3rSrK!2|xki7|X_A|~%aUSYYL7pC90oVyt`-hX#Jse0bk9L^^>g-7$ zgOB1MvCR3t)Cs`1C@MbFb_7f|2oravukG*;21|fxf&X*bysT#>E+PUz$a` z5(ux%(&q!)GK#z*pJt&cP7@-Q1D!3;LIH{7X1Yq3Fyy--i~O-U5oP-B-xr(A5W(**&pH?c7ALZnB5FFt>Bh<8b+9e;NxY0g z>`Ce#E#-XEBzFyY*CbxqOGIJ=0KmrI?!Zz8eHzWbSi@Nc!W z#c7&HXW0>Pu_ksaT3tF?`qUZP&NTQdYz3+@1>yJg!vfcJnbqWMwCHhdGA(f!f5c%c z&|XVc*T1@j;{PU>SA{+FyoRf1e-xQRdxxRVL4)6V1+^0-n|nGNs&gjr8Nd4qR|CcQ zUO7*5xZV)F*5J3hxtsm2yQAToZ;y0qg=Zl6#gIeXueve0^@8sx@PiO5CW~tIZVaJb z1b(IvsfQ1Qx+Xq_bQD;xk_X2x@!2;qu^|vn`J*&}7O)hIGIWi06TA%Q%;l>QognBz z0$Fpq96Su}1m`*jm$D;5?*KaMz*+Q#vQpH-_7oF6tp-u@^qFR8>ppI-5}8^5sk?;m zE$cp&u#A*KykIDhEO`vFgm#Z6iXe;LCVS*?r~=|=gOxyj-}n&d<4reYGHLw@=uDPl zPwk_CZ|HEbh9Z><&RQT#Bd>wS!KtYTvj|4iaG+c4!rjH*#xo1pHUlDM z5-(dtj{*7hzH059jEN*Db_YZa0J2l*YP;yz45ouvi~sbOulBdVWZ68v(-sxAy+E@` zb%bB;Rk9y1H~zbU@#aoj1F+eqv}4IM9_4d^>rSa@pzX|0ox$W72jul%wz7wS-Qab$nm^_zlJ)=q N002ovPDHLkV1hS>ZpHur literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_blocked.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_blocked.png new file mode 100644 index 0000000000000000000000000000000000000000..6fb2d134edeb3d11d0c38a1b45b19d0cddcbeea8 GIT binary patch literal 1103 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==L6{e5a?2V@L(# z+vweS!j2-noFXC(6C9=#a*1$7aZ5c~+Mv%-varX&%XOkwy`Z9$mYt%I<^qLx93CMi z4I+~!9dTmfQqeeLd95eqVeK93n_tiAefK)PdEW8bIh7T**4F0fNjwtF#~KV1VAK+W z3!W!en`E0vU3^x$;Qb}lCEN!pAILcTkHX%P)H-Z1eWu+Q4JO+}9A0 z82xI&x|!v9FZUi&X!w0VeL>DbzgKx`fdw{<_n1Ptb5)jp&kN;xm?K^hXsWIGD|2&n zXw1?VtwY0ip8W8; zwQ8zD#lcL`-E%T_vEFxX5Y=m2-(bA;ThPXj_A83m%OC6!4)+#tR9MdK{l39FtNW{o z#GxF171@ll^Dmhde4Ve5%Vk+IbKj-(tt;FG-29oe*I%9XD5F4naYp##t}cZMhksQ& z_$R9@+7%;~*P!yTuc55#ZnlBt8}%}sWP$DqmYo+5@140i>1|=yAD->gmMr!#ZkiVD zz_+_cwx(NL=%TwL4d&D+fwZe2Q6mpSjir+{qPukzELIW#KW;`)#u zv7jtQC${;Iuz#mt{PU&zXE;hFd5cV*vOw~P#Bxqe$C|KpQ+MBDQ(qyUq^+{7MBH%y zcjjjm+G3e6&;LAk<4f4cj`!!x*C zcd>n}@w@E;GS%_+4M&?rGpr^Z*x0vWUT%5H#HZhUw{1QpJ!8M_P41+aOPa@ao&R}J zNbtDQtR$7AzQ(t=oR?C}^TeFPqTg z*n1axy6b4ngu8!UaEdFgbQN>^(EdUFft!5Yvs<0hKO|3e^ks`W51zb-Ys6eLdCZ71uBE z2ep%y85vdoRbmBN7H|J&ef*Ak>0Ho>`nM7~wUQRRWX0*mO8V^04WJg0Z`ZuH1j6mtsLFxi3Y zpp%eGjtKW!mnj^UijGG$w4{!HHmQ@F_wd5)nRmDEynFlh_XpnJ(w?2&^Zn+{_|3DY zi5V*=u=F$t8ZfyX;E-U1a}?ZJrcIkxb&+M3>;GH)T=N!qXB78s_~SWsNqYci>qb_o zx2JhkCcSljYLK$()|m}^6~!lbl_i^DXA7mh{yg;RnV*ZtIN zJCh+W*X!rcKNnU^)D*b3FrCk1{|f84!>0DG3=$5XZdsmqa%_{iy-QXKSHnXEtErzX z|K+WIIBUKV!;W=XhddQb|M;xB{fYTxev*}q%iX@rk5hLA+nn&Ty7edA_5P-uYK~mT z`4{GN)ZP1JZtbQtH$!fxkKdieCw6aM!fVxSw>aus?;&xIYx9m>G`w=TMKv>(VQsI~123H!u2Pc~>=!Mz=v`2x^1Pxq^uCFzUGu8q6f@or zzqM|~#>TDBE%SL&BRt>n>Pg}Cd*gu|H?VmqpsU3K=NeKY0Guf3hgA9aAV6D c9+M8_mvltWTv9E)9h6-?UHx3vIVCg!0BSwUhyVZp literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_files.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_files.png new file mode 100644 index 0000000000000000000000000000000000000000..080957bf7b01e42b56d3286cc0334c7540d79548 GIT binary patch literal 798 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==Pq0fvLmO#WAFU z@$GDXZPrAQWA7twMDP40I)y(;ajCW{FK24*Vv&sjVop;weK5T7L#XVZNaxi3-g@hv zpSWV`H}`b)ySb9{w)+_u-}`R++|quz^u3)+h1fYKFrcG9>`Ysu*78KR%O0MWuwOR+ zMg`OD=FHc=5#D41orMEW;3C+DHviRI@?&P}a2|AAM8Psk-- z^JvSiV}c3coI$Pm8v-UM{P59Kxgx6Uz;Zi~iF3)qLk>+5nYHf)xfxhQJ#Kq_5dYD} z&FCrk{^2i%DGUw=cvV+8NO@j+@@*Bz_kvnRm7~fpW(oZe-FNZMp`Rk_UhtJ2jk?&e zYn6+bNAj&-F+W5O%IS$t5b1fK?Zx!-Y_*cO!zCq=jdJTO<}Uvy$vJJR3RC8)x>&t; zq6_8L-O%Fm6r1A0lzHja?Ms!eOWIGfsJJR!+%w7NpUz9()(c`%3r_w%-Fu{eQ3mJh zXF=JwKkk|FDfRn`KPG9@lBul%0as5< zJzBCs?L6PEGffQ>jUy(jFJN}g5xe|*p{H$s?GxK)$`S4>G?xD@ns==^dH#aK&fEE# zCTMfaD%3ise5OQ0hF|c0(gTJPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=aY;l$RCodHnr(;`RT#(bRVy@u z-qtqU@TP1ZP%S_G8+wU*CGI#EoIp@qwb7wB+fj=|nIp=vf|9j@lnR9NV5hO4W7zhjm z1_A?tfxtjuATSUZ2n-a?K(la<4h~zbmg3$3ZU zLDB=@WpE7q-=Y|bHQ|TTMcX z!QO5&6N#@}7MIIHLNpRt22MnhtIDl%T9%NulREcno&>a(`3Rih6tVn9{}A#nmIGQt zc}p&WAZL(>o5A$r&O3pU47BJRf}}5f<7FlYaxN#>XP{b>VKM`gRNV|oyONu9*5r8| zzJa^CkfWX}SLN&_nFwO^EGNn$uSnHsyl5(S=WM(mF#_m=awoXhIZCw}{z5ue@~G)U z*eY2@&}zKal^hYG+|>ss@ftyl9zDl!Ng!Y>aHk+u^K2L|B{}tsI9TjGUwNE|-9W%#h z)2c&hVyZuyW4;ZO&>~|A{SUO@hwC=-ENz>zxg%-S7bE^|LH!rKRaJg5>AD zG-oxdd)G#e`r|u-^zEW=re2WiAjsMmuMvbpeSE&(1MF;YAxHi68bLB(9@2r~7%+Yd zsZGU2`_URb-@D}LHGACW_tpQb+r?V21 zX%318gBguNop;ZR>ML}=mXY&N)_gKQVv&IQ^Hg7?T$NjWLOcVsk)K(7PBoH(3{sJM zBqlk}sGr1cIU{FdM*GudMG&;~w6|*9Y$c8RAxE$D+)~6Nc6aV9igBO?>fP;15UQj(^L@J3r2+~A{ zcTa%$iRoN)cY^1@7NCPen@rN+Q}7fR1f{(cG6f<*ebIjnW{a$t=v@9aFv475J-L)E z{?6s1zsBhxPf%WmfsUH?;O7snU6HJBvGd4Q2Z=gY+6{gH`jhrnIPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*ISLa(l@IwE zc;^Q16(s>C!AlU@^xYmN|{VtaX4Qag&;EmW-vp;n(^$Na|ms z92RjzSzN{0+q_2*qo+-j2i}qD(O`m6wBSRILHeuEQW4=B@g zSvZVH<$Mu9AiW%hvWGa@k*dM=R&Xbj^B#UC)0ja^0_x2?c=f&DOg7ghJm^juB_ewwM=5a}u;^c?de02xzGR)LxU2nBJ0NOy762JZ_x9JRE!3Y7k!XYpBj9YlIe zki+10fnfTf(rM0HtvqnMU83mvVCRgIQ-LH+v2&WP9)i~)cAl;t@Y~RJZKJD+bp*Nm zRC1mKpAq9_LQS@Hn8rB7m}oU8(AAweDO6r}q7aA(TNDp0AzxF6*iJyW#1 z(NEi?jVULqKw5%Q3qzRAU=}jBz@`GEOgXJH26%3)S86qcIY59rKxI)gk`9dJ9;ggejF}7d{tFGZ6BleeUxMG5+4AD9bXhkM`yflnlws*={Jf zJ=NJBMRWl!V@hR1UA9iIY$MY)31}3BT6g#hUl+md1Q#g3gECFrO*f`g5UEe0ZCuSn4zha4+2-qVk@vILgg?1gR0Ds7aw~Mec=`<8`yo5E|U_7kc6i z0Z#%gPO7_!}xH&^c|mPR1pBHPpHevQlNgljbvnQnDl;R>z4R_!8AbqO@$GGNQt zM5wrs+$9tuwLttULNB2ZXfKF=X6Yr8&LL78gnBK(RaaAtwu?_K&qG}AZt)LwuHH$6 zYEg#zOQwAF^%mgb+IfB;L9#)U#I*FJ1ypL4#VGiH|I|zJ(V_xTfv7-KASw_Qhzdjn bhD?D!>t)$Q_4;j900000NkvXXu0mjfo?tvF literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_photos.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_photos.png new file mode 100644 index 0000000000000000000000000000000000000000..3f4d9047abdb2335110b1816f819c6598c92a8ab GIT binary patch literal 1097 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==L6{e6y#EV@L(# z+u8fGMI1$rfA3-8Y|BVY6yfQZ4N_m97Qf= zB`0fkNjM7jieoypS-GSA-o1S@=k7dv_ufajnwhuFKi~WQw*2|CXWza}I&wzD zfYpaF_y7vE;5OHlQz|(oQom1zvp+xJXuwz2w06sUmH%vZ4Xz)Sgss-S9ClnFO~!`d z^@8harXIRQg;n_?M$BQ3SADW(y1=KcDyh4&^3~wL!%jSkEh@ z_18?PXL3H6vzPZqL!D9yw}5eT%KXduk4`L|IBV%Qg>FF)v&O$!2e%&QP_ceexAnoT zWR_LO_)Omkv0j(k>|y>WYqgt5cgY3I<7XCR&B>g;%AnE4X|{vf1b0UN?PnE)Pb_X& zemiXf=aaw#mvfCX99SmpZkm2TrQ)IG@}S+#+wLAZ^LIg9&D9;J%v+*0|J&U%Pna&# zeoLY5>V)6-w$FAdXo|0_U0S*4YVOta3qnjjil?%|IMhBV*NAVbyI&ZZe!-o~o^9E| z^821k{(kCS`A6!an%}MZnPsZAv2)$7EpV88f0>`@`G)Ju558xz)H6%oGEL?yQ)N_J z#!j!#+c$_>@0hKso^wvPN?m%f?BwSQ)x*8FPg`zM&prG916}8`Clep;avv&tv@?+a-_=>MmdhUfCFQl2eXMWI^d4Dm<#NP07g7IYS?*XR+XW36T zyZnn#V*}yKE*xH zanfAVV{(s5PM(=M!M{0D!Tj>-yr9Q9QN`uiscO7`nxDvOcX@mZXPMu%Nv*N*kFoa^ yrL~-G9-CNKF#oomqBiNLFM4(XWu84;e;6nF9@(j2nQ;-6jXhocT-G@yGywqqqS=N3 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_received.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_received.png new file mode 100644 index 0000000000000000000000000000000000000000..4e63b498fd62046df248a7a671d60b904f423203 GIT binary patch literal 747 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==Pq0fhp9}#WAFU z@$F1sKPE?kR>>q6u`cerf_w=#b`>3T+snj0fxCcDxIb}Evx*e|gJaSwynF4n6CVD^ zQdDeNmbPnGxW>elJ z1rghVz{pGX8mqq_YQ*~m!797Ol@s01#D1A?owMxSktc5pj%CRm`ogjHSCqw`y}RNcmNu=wxp{iI zq+i38ws{L~_&(FfQarTC<Q*Za;h zf7~Nnl*-_G&-?%9T45oT1S>2VtK*Z>=jG>w+0R*_A{wE@c(XoW<6#=k=Cp)pHu)B`Sv2N9U}!q))8q1h*+S)$=mZ_hue>^^H!3?s6*GA3U{p|w z_ON*1zUlh%{MV`_M?Lp6{74REDX{ciX*~>@4Gpicv#~4aMS&m zvWb~C)9wCW-`CQ#J;8j#bF-JbP3OFPxRRyy-Jy5$y_a3|KlY}|>HGawrtgXMQm*ZB zr*8cHH@QH|AyD*9vIehzeP^g;=C8_brzbt1j|Q)~s%rSVHq41JHeE(rr2I}u(U+oE z4m-+@6?SjEmu{<_8hL!h7u9>OB-dO~e9yHrE!T zimv#AWRAVQy4Qr?i`TTv?Y}uSwX;)7XR~R|n(8UFP5H+k=kMD0@LBBV#^S%sr(fTz zoc83K>m&_b$E<^!%(s{^?8z?OV!y|E&$)=V&X;V?Zas2oMRbD(%aT1TOiBu^4UeAj z5Txck=cx+VVtQAxcJ|{%>z{MJP;sdBxZkjW`;KV6L3C4X!{3%t(~q9>EBBpXUFMO= ztk#gZpVPX@_Q1MC_6<`jr|U>%=`Qlz(s}Icqg}6#{P?k4Rz&=fN{duwV4ii+uBZE3 znJTUGcAuMnb3S8J%CjA3YkUm;>#1?wTJq?*Wbv786${S?y?%6k`6o7x6($NkAI-ha z<-C*GdG@#K^{De&S e0~Hww{@|YR{m|tfZFIDx{$;P!BbLRF= zJ=JJ7$zQ=yu|>tV>&d6t6QqTV%&m>ztTF$^WAoWM=p{bw%BTmGj zdV!1g%h9jD|7IS0exXHQFDa+}#{IQnuMLvUy=Y~6#`$WYOm6oQ{fk>KMpw2f`}i;9 z%Ubkz(TT%c-uDup-FG;>qF1k?`L)E7j-8u)x5akp9;r${XA$N6JLAHczWM!UMP>Xy zu{V41%G}(R?}Q+lrMwXDTuttlUw( z{FiUJb~baWU~v3J-Ts~0^EMhgYc`~vOUd}wzTK=KY~y9u@YkEB7P+r~xIu`Y??TCniszhevqYAb&W-aQ|9ztXix7LEgt(})= zIH=pqEB-UB@oeEK5r@AqX-uEyRg0e0Gctc=_KM|9Kc6S#7xi6UwZe0@Hg0J@^ZAA7 zmhkwUTb?_{zcLY+c{*C!BmYFX_*bn@av?p-`9IGnesX`!qmN2a?(HY8)-4g{nBjRe z=-yfTL$8-LUkEy2blF)W;>>l~in*@(7s{`=_FoQ{vz(mt|Ic^Ft$S2ir|dK6z7xYG hjyoX;H2$A(Kyd2cZ@u%=r9sJ=!PC{xWt~$(696`kMH>JB literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_voice.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_voice.png new file mode 100644 index 0000000000000000000000000000000000000000..eddf2ee2d63e083331398a400e8829c440f1d0c1 GIT binary patch literal 1279 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==Pq0fhE(^#WAFU z@oluPw^*P=ZM<(c$DgJSk2lPhIYe5-951Xgo4Wd!blx3~+!)Ut9ZFH`*VfHda8t}< zDtxTAC`x2v;x(mc7RlNhmZppMeYX34uRQHt&5ZNR?K3Oi?R{?f-Qw=gs?{MTR~Snj zWCPgY)WOD86SP&fZroVN(#p?%G;P|$8Mw#b)xz+60 zYM5gV+9mJg)ZQhacALefV5icSVxQoPzl_)Sd-`!q&NnfgxbuJ#_kmW$2jz?NIR09c ztvF$s5+yx(wxF7$U15!*^fK6aV2RXAx&9u$Q*Dxj) z?7#nn;nuOkeRA6#PqW%sGPB}P&8+&Q>yDS?gjj!{nVEF=$^?b{$6c#WN7?l{9%p&x zs3^Y7uEknzo0*>H;fqU5FH3CE65-vymfLq~dXQ1#xnruCKW1$3TeZCM<@y_~UsKns zuyOwo`gA%d`pli81EJce+sKIfcujtHZTKp5#T|lFHpwILBndj4e{T z@|Rwg_>$JWEbYD5*}%64V`cWO@;z$xD57Y_qfHABF1dQ)uCvtgV)hTr9mf{+%FX@V zpnuVkSLUL8Oy`&$s?O?u#bm(D_uRaqAjaYTaR-wM=Sn7-PVtu-iEolS zX0t4baJ}^Wd0L=!Hp3d#qf0C_&Z~rMWuC8EdP0}+_vTB^?-sC`l{)&~mT%oO>EW~1 z2^Xy@qdQsO$Q5lq^4ig_;m$IN-s3Y8^EGnV?;3Wavf)rd1AzBx}|dFlzbtM*Q`FT11%K)t@&%FO!}tRG}%02 zHu!YA+2-($CHD8{={&Xbc@+HDWuP!+_JC~zUyA6HwBBi-tR4oi zeY8Cwk`NtnQAYcO>p401pK~wwocxgZiSNMwC6i1nrpa7uPn^H5B7TXqU_0lh>z@uE z&}`uTXz9?k+@t7Y9ivY&67|q}wUWWsmpo)JeZE#lTckz2r8lX3UW&#(RS6Ssv8A)|;`*FAyoeH(s*(z+V6H V{!PzSk1{}okEg4j%Q~loCIG=3CJ6ul literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_datausage.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_datausage.png new file mode 100644 index 0000000000000000000000000000000000000000..535b001b1114f0e1bdbbbaf73abf7d4482557af7 GIT binary patch literal 579 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==L6{Y^|q@V@L(# z+go@0niT}v67M#@J^J-h^|tcM^KQ&sqB1pNU*S^5ud0S!&Oa+vv}ee&2{CafG%%nL z8=?|sEn6*XZvC!o$&>4K?|1Dwr2O{)<0OxVHE}A=A0roCT6=YgM6~IgTc$I2$NpdT zr~PxX%<tx0%%PyDaOe!wDh44Yr87Jri4W5xzX+68SM;Z*9lpi%#e8+9 z<>uo?ruG%RXZ_0A|0)-5uj*=6>p%@)aCjGFG^+pa(@IHc R5xWD5Ku=dcmvv4FO#th7+ZX@< literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_devices.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_devices.png new file mode 100644 index 0000000000000000000000000000000000000000..3e75039f5b265c1b156af4b9ad8093cc45a78631 GIT binary patch literal 575 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==L6{Y^A4*V@L(# z+gpZyhaCi3A4+sGH%t)FP_=D;pyzQ%A>Cv0G~ohnK1bh)Y)p$za85WQeR64e{HAQl zgqaiGh(tzyXbTz|puZcls^;Th?z^u34d)6(x7k>-}2a_g9(q z%UJik{C1i-_}ISO^~~>QFZ-!s`(usC#?#TSOIKM0CS4IT6mq1;!d$=RgMYv}sD=5JT;&FA~)uue#1=TJ~iIOHSX;C7&8rb0tc1E;YggCwJH zS`&j2liC>;#uOHx8JtWfIA$0KvrG^)NL0hnaNRH9wtM zJu&|UvD`1sOBesvE?anH=c5+SFJ+?kOTxrFHradKSvD!Xpmw#~W9dmTkqh*)C!ewV zd%$4t%kqm}zk{pww5uZL{(J5X^iBf<6B^;n{fBYy=NWY;|IX0|MV_atpUXO@geCxC Ch03=8 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_email.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_email.png new file mode 100644 index 0000000000000000000000000000000000000000..75a5a6024236f9b1395ee71e81356d17f62c8155 GIT binary patch literal 1042 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==L6{yvEbTF{Fa= z?JV1DkwB5Q&1%Qgyf|(x+sNUvkuxev!hl8O;{FA$T%s4_6NOpqFa40uVYzrnenEm@ zPpfNJ$Rl=+WfwXk=ZmYQn9sESKIdlP$#u^UoIZEw_q_Gy6gnLweym%=RL^`lit*Re|g>A%qz`RhBKEZ+OBOodS-9Mz9jnq^{*QLPu>y!z&3}? z`+>!a<+Z9exhnY2HO_v(p|RO_Uy}Q2wXFV)?4dWeo;x6*e$eQ~s-mn6Kg%iEMgF|u zs~(jXN$*_ev2C7L!+D;HxQDl2Pf0o-@+970)#K+CIe*n8o8R(Ub67ttRB9{t+9+0Z z_CTaJ>$#u1o(FeI+-ED^*-&uoK<)?LE2cm1F(tRv6n_YbUitLT-Oo!S%h>IUcV=*M z<#XAv>~Fk!Wa{}ThR2m+u1+!WmJwHaKD9j4I`1VWB?aAww zsHPlc=(;+2YRkLa70a{A=GGTh%FBEXQ=We)+_1_l|DVqO=Uuy)YaV^GI@UFjwZ;u5axddLvj*?Yn&AlIgKu&kt2-pUs=PAXN)*~3G!~Axa{DOb9WejURfODubq41uQgkZ!>oQIr^WyU5e`j>v1_D`F=68kr-FIDY*FR9u$!+-ZN&Qtu4Ha)+1%OP$P%dD`b-lx4&kJtOkJ)g60 zx5)qgKP43_zHBwVA7-`HrmNbncqY@y{MB2&X`OwMP`&a;My1I2nrB9=x7GywTzX^k znOhdR{$V!D{~56sDGBTfp2<`j-1UFmjb@YSnip!d{C-DebiaKi)S*80%!1$tu|Yrc z*NJbq@BQxa(uEAar{^9piI%iq@TS?$^wX5W(tBs4CaG^eDYR(Q#%2CnjjqZ1$grLg zu;!Yg7?7A9u!%!n>3&|ov6&l>_-0F=s5N^zA>3_qLR)FR=GmP>(k$$aWm_D>kKdLy z;tNx9D-P;7VZCl?pZA2h0T#U`pU+n3S8e8Mv=g#p{4~wv$To(Rb^G%4YfeUrzYG*= z*Xqkqy3?|_eDk>l>r?K%o4ePT`S}b->zd$5)=BEEnr-?YWgfrcc=FfxqudMuo>-ZM znU69=HIB3Iw258pAUQu;Bx5Fr%I_(~3H42%WA=X6>)~CTnx8h;Chy_ZP1A*>C)gEl zUXdF0uyv=ZW%ASg?d%mi=a(N<+_R^=o~!Eeuh`rp-`8z^WttHq?B3=7>sV~7#^Lo@ zjdIo^Pai!NICg$%R^yZW{gG#ns%y8E*I#9lElqd_mN;7daZ(AZ&ZX`a%QI2R?rOTd zKmJO{H@us6PKNDK_4UZFJd+MB7kCs=ytgx#Yq#f|XFDq2@0~i;h4st=w)mTRKFu?a zD5T$RK5#_8Q`O)3y~RCd)yhUD(=5%WS%NEGt&h-b5|K3FnzArWWJOBj6W7=mXOCR8 zYJQ@d24ZMkaC!0S!1*H=f6bU)EOV3fJFC_dnO!Hl53|PCEt8z0BBxf_vAq6J<_)F3 z^(%BA-!M4!^1em|-@m3+v!00Y9a{Qy%BI!|6BpJ+Oo5F^*$u?a68XXZKku+@POjJ& PQ1bP0l+XkKNNe|t literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_on.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_on.png new file mode 100644 index 0000000000000000000000000000000000000000..a1fab57e59a38be62a74080be75cba2e6811d73e GIT binary patch literal 1166 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==L6{{D-HDV@L(# z+u6IbMFK^RZI+Vf)M|Rapmoub30Duf9n}+sBBDBTC4wjfDX?n15 zt11XhG-+}Ta5T(P;7ZalIkskh^X&H5cXpP)yK~c;`T2q4XXX{Zv%UYbOs+h=+}i3& z2xF*&XaH+S<0`EHZSIe5i#M|BSs&DyvF>VCaq2^{R`#YZP2CAHe^|708^wbYSa=$? z26`OR@Y?+QfUJVjj$6_~=Nm4`d~D5dZx%lw^I@wYTb_1H%o)$jRl;{Zg)U9K6CHOw z`J3<_Gv2#7nMUtV`}=ILwzw!EeCb3&oGH&^^$+EucY_y-+e+PVWnS-C?xk#eoNip5$+@&o@xq3OcjHUq)7@D-O_KgTIGj{;=$rJuthgsAm!Xgxh;guG_-1@|gE7%k)?1 zw>GlVNbPOO-Pxsf*Z+jB>y)c3TIjneP;brr$xLGR-%i=FGVGMV_JD~@UnMkbOn>CQ zOIP`0rZO{2^3vVAtsF;QZs6ovW_oIi_1>pGeO7|UOP;)qILEU)yu%^jjn6{M`9hmp zeUh)=VEc8fTj<1e|Ch&BI!xQ{!Wz`5!xeF;ie;sP7^}|1Ew?wOzSy65&F=Nb6J25Z z<{H#Fsh7>T^FF6GXKvyIo9A|(YZ&)6OkXp*PNL}c>$V8-9csSKn`RUU`Yk)UYO}{q zxfzZL_EXpN%39R~NwHd{U$!AoW@Dp+@0ni^Z+| zw{GfIZsKr%_$sxM#p-pa;W>r;b(MaGKly5%=hPX8&wVN~S)FI5Zofm3_u3xC3E}H2 z{WhNJnB2aCD<#k$>iUCr-I1?u9O70varjSX+9SbjpSBj4_7{X*T9`Abv(L0O@>U1G zhfasC@0`Npudk__wv--=@_ZRzcx@-MzbdQdM)v(R#k(vu=N%2ddi#&+WQ$8S8^7o1 zovzdAuI;lg%lI?V*)LIZBWu<33p2g@4x7{g*;Y>+ZmS+ol-fV#2GiWK1#c%kHt?Mt z+;pe<|G%(Z=UwJX)he8Rzp{6Wk7>@o8}1WyjO8v|6^N+1p#S^PWQh-PT{mWxcUFrp zZxndFV5&^2>EBf^Ee@EynEiY=pVnjt?W0`#-fIV3DA%kASDg{Sx@ixmRzM?D>pqX@ z70(g!ckn)W-GYpF~y56^Fm2)A)rFp;anTlObybvN-iaetcIK^~4z4<}XD_+)XjKfH8*-n*?`S_`;VFs*7p dP=D4Rkk^xOGOqf`)DJ2PJYD@<);T3K0RSPe`Qrcp literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_permissions.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_permissions.png new file mode 100644 index 0000000000000000000000000000000000000000..51324af25d9da1ac124410c125154b54d5f94189 GIT binary patch literal 1215 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==Pq0fko5P#WAFU z@$Kxh-XVb!$I^cpEz%cn73FAaa+?y;5hB3m_)v)>>IVB368fT-qM;HuavrAiRIroiByT*-}in0-7`mAF74U8=X;)8o}W{FZf^1W z6eF`W%-0xSHa7r_qZIy~V^Q9dt`cqm41`;3z61Bn6bX3sXxy1xEFv7CP8 z-uY+K>_6=Kz?`ggu=IoMkIuRiZx`e^?s7SP>Y%6r=bC8U3jFCl zxp-om2=nuz6LW;G>}Q#EFt0$2hru_*(Q2*YvO|eqaxTtc*PG*b>e*Tk8Exk6F|S0$ zzAn8~>AQG^P5g>0&woq)_&w*=!W>J9fM-)CK9S6vll1AZamE+Ja+}gsJ~vfT&F7rz z?ps}=k|l8ejggC)2@L5otf`n-v4 zj`J49aPS(P-!a8|;$xZ6knfp+Yg;S?3ai8F`DAC#M zh}D6vLoPLTho0wcSn^@V>EHMDQj1*^pEd7Pxn*9GBz`A6Y9D+4oKM#ic-}BfJ>dUk z^Q+v?s}_{r*6!c-r+eCp2Wy)a&&~fg-S69GTjh(vJ^48juJdg|Rh=u=XQ~A@e`=bS z*`j*j<)tk^7oTzT77Se{C}#Xz{pb9QTOMZ=&P;qgz52ldw}>-y{QSOa`bu}MNt&@) z$Z+lgPi3vNbMc?@k1i;mRhATg)F55g>B+Apfyx?;=X}>%E>gWF*kW1q^tZqj?_{=? zGq$A?CX22L-R3wn$G4+`C2MO^(zCM@_8;xHT%<16Y_PoRPJiQ`SwhbZ-2J|mFc)VX zG%(QATlU&(U#ZMW_WL|VZh7hRO^(V`{zy2ZP+WCUDDAtERlMLOmSenz&y}s7Bz8oE zXKbzJ$Yc{%IA!6sN$UdFu7>cs${aVj9abzU_pLW^JT*${Tl9o)!u^QAqZ*xB5rxar zg)jBx^o26tyeuYS-(=2Vf4s1m>EiMOCLLDmW?nws;8pO1VZ!W+!j@NMJ`OKWh8&(c z&ti_^@;hOCrMKMQI$U_$_coCGqx~uzlo_4js1qI`ESyO9yT)7i2bO-P*i?Dp5@;3Za=zdY3hwM>7sVqNV91yr8 z6{dcZTW=?aRnwDg>&>jZuFB-HKmRDlUjV@L(# z+glfX4;zTIK4klNgEgU{i_^;edLon93zc+V3ZWli0d3(p)TWfbDqz2vW zP5t-gJ=Zj&$`$P=?`@i^fAHZV9f@r*SC|4qoTun67dR8Lw_(9HHKm3#w;2Q++zuRB zqtMXP&>88-Ajv4axrxDuNiB_4a)JBg|JHuxPk%ixDX!H0WoL0B?larRlrL-V6<;r% zKRNTI-&}{P8>U}v-0y})uUh%f*<5tuynkD7_3h+dc6zRZk@(q@Q>J>LH%u=?E0 z-?v`7p4*sL^hU_xJ@5R=zqh^!?ta}}^360O!nWzu&sp`d&m{Nm%lw~w<$2ldU$e@u z?uyyKo?HC(!Ljvo^$U5Ub{|{ynK|VLBhv|v88bv#CI}iBYI7(kCnSYIe6T>8!OMJl zvF@p7$8>JpKg4Clo-UGlaD#PsiMIXM3-jd*`QC4C_#yeB;h;7Xhe87bD&Y{?C_iCJ V=ayG<&inwypQo#z%Q~loCIE_*-rWEI literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_sdcard.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_sdcard.png new file mode 100644 index 0000000000000000000000000000000000000000..58f8ad0d7c8f1c6a69c152e6a6c35d6c80dc25d5 GIT binary patch literal 942 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==L6{T*A}EF{Fa= z?d;uo!j2+sZ#$|PMKX7=3I;TEbWadaZQ>JAk-FC)7Zuka-l)dPDk~eY$5BXxQC1{` zLr~GNN8p)thH$U@YuVYhyYH#~pIDcjc5dcOcrk&zF^*6z4F1m5OlB-{w!5 z{2s<~%}b6c+%!J2$HhHpqu;;Up3f(e*PLQxOrPfxzc5*j)8F9OQ_dv!wy>%RY<;o~ z)fssyY*#J!6>iY0{_s9zTXRG4q^-Bl&191~yzjouh%dY-br@Cz1uGWWRNa>n&yJ)dRo8-Edf>$*MQ-pl)a@%a;OvX*?#&;0S2`KtH} zb*r9t3z=8kJZAWUTPpQiMDlHpS+3H7A3l{igdNx~b2MW9O@qE)K_bFo^{pHKM}7O% zd2_qvsknANz5n*X@%*ZRS+mUPgTDq(^*=fFa<+0Q$e#>7>`DLBnw?lVb^mHKc z{OA*(&~+!d19s}HdKvp=X|L_$|2!Ev9IlN_AujCm88`!)91g9ORdL{C;w+c7*2o9z zyj2(-bH3YCr@W~A-jd1vL3bWky*QUAE_T@Ll(XSX{k-TizuICS&$#fsNcM?Q$6bcj znXXUQ&c4cf>$^g=iIMoxh^_6{)-=Srn6DAI>HaF(e095q_}w*pJ4`kAGQMIES-WxD zD((fBTC$_xO;HnCz*4~oBpO?ytuxq}i!7b9+21~pof7e@BJb@27Im1MM}rWHP~Ljk zEi-4NOXW?UvxmX-4j1p~M7w^g@)kZ5*T3_K@X<@VPo%O> zJW(xF)$ogVL2`jy)q%ozZtIsiRZU?N{=QzO_uBZPR#n%z-TFSvU8qSEm}0MZJ>WlT WXi?(3blP%IUh#DGb6Mw<&;$Tb7=iBq literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_storageusage.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_storageusage.png new file mode 100644 index 0000000000000000000000000000000000000000..02e13ac4825219145b44b46d87edfe3d65090509 GIT binary patch literal 1586 zcmZ8hdo&XY7~jLnFtkwD<4&VVmdYfdvYBkPd5fVWbE!$O5F(pLlTnoc001x|0dFr+!X~A+ zNTSos3oD5L>GoDQK+${k?~(%V?Lz#EOa|i>v#<~!#b0%?4;COvx+@y(cOi+#VmJJTEyC&x~x!v zJW2ZJZhZY#L=0X?CL-kE$~iYDu}H&-oWprxy1U>H2)4SU;*=H2nDdxbw>@{nkv5((@X*hS6Dku#ih4d=Y+rwj zm39?*HBGP6*}B{FVkTFyS;`2}Ki?rOo;v4Z0{tA9cGa(1pvsf&x(+*vVlUTg6dP71 zeyU_P3!dm>=4zbu2i?Cw!}CHWG&BUHVj#IF%5p1*aNaEmO%E9FvTmYtZ@IoT;MRNb zG)p6@d&Z635cjxiFm5(G*f>(fU3hD0=PLtLL0CU-sP-Jt7+5Go#5pig#rM8mQRMq1 z+D6WLi^R!qX}z*L_<+LY8ZEw&+bZoGcLnm9YacS#k`wD`gPhKwxwLhSzM&^{qa|eelRXcYMO~Do-G&;R^DBtl$=MIF+dv(`w zoomBa{I^(P)82_%2sEmK3#^m{HWc@g$>a(%7+8qO*nO&uBJ73>$_mXt67{2*mQsDJcniDZ+uA*o z@J&b^$10CnYQU2LhgS6`t)_Qo{;d6_qh8t1x;=_`v{7I@dywedGU&>FrWZ8Jd-eQF zq+M`@9wX67blb#{A@BBR)bGWqh2{KQo1Pq*tL@*=KCJHey07ua?A&BIWPjyS^YI5D zseQ?G*K#F%6`Z8ivqR~bg5DbbQVr9vXjdi{Ecz^!kyz8}7 zsg^2r0O-4nB&F=$I}))PF|&YComRRzAW&OkMf}a|8~Hin-$0#dP3=)_4~UnZ4T+k1 z{8K@9@uxiW;(-$V^C?_%+DC{uD4M3Z0`j$A*5gxxkoTKqDK*~8p&2?;q2(o-kk6MyWu@)%8=D;(aWf({)1OaGk4R1He8*@TAWp@OMV#=87heo|V zTvA&yjjC=mfe0c_A3vaI20a0$6d7!DK@=V&3(T^;u30_pAU|xMdYwaPW6Y)Ygl0~a zFP_$LSbBycQX;}?tXtMPTQess)-msLwlX>ZJ`rV5KRsGW!m3A7;5u}ETM1OKj}_q3 zRG~N8)nB!nucAqdo7@*3FfXhboV%|DdKi$97~FjqWY~+Y@=RB_xUpLwe}qUy@}<$V z%!AxL!jL$d22OR#MZyo_ye|B~aghu)Q7ifc<{hm~*sYoet!z6f`Y`7c1H;Sc}- literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_download.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_download.png new file mode 100644 index 0000000000000000000000000000000000000000..2c059a820f955b1a9218024b3872e218276d0ace GIT binary patch literal 609 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?oJMHP>7?Q#I zHqz1Wuz^5MKs{r4h5J!gOQIJm8BBF}__vt~|D3+j|+{@1d{_rbDbLV2It*07vO z4t(&IiEGkwqpR8rCLLoESnuHYDP&m{YsjSthDV|r9`jCxtZ(p=;&w<2Wq5yl8T%B~ zA2*p8{&l(R-MnzWd$hR9I`gR!M|wU;dY@;QXSHBYZ|8v@Y`(YDj&k^^`0HdwvM+eU zrP5@d{H9?=xAw)ewhZkN+u9PUw@l&HVqD%W+HgMNnPl^6&+B?DZ#o;^FKMuhSfy3O z?9X}PXn?9*^HTu{;R(j(eW};ZD}3UR&y?}D&3$n_x+(2QastcTTP^CFgvx}zKm7Ln zB)ejQfvS?goLzDKdzw04Pu3R*{j^`X!Aa!ppEbzk}cYdouCdlg$?_Ys%hp^EdYA;aQo4i5M>*?y}vd$@?2>{rH?8N{8 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_lock3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_lock3.png new file mode 100644 index 0000000000000000000000000000000000000000..324436938a770ed8f20e8af9fa815dcbebd26351 GIT binary patch literal 644 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?od*|um7?Q#I zHo`makb!{ju2n9(^+m%UsO@zSI zOFdtv+>qP<)3R{RB7==QE~yK8X5BT~xk~Gk9pibw)b`i@k<+GT_kU(O{`>&f4aT4w z$2b0bv8O#)IDuEDaY8`*uE~KcOzvq1)C<-YoYTn`C}^1Z{!xvr&huxhS$c{!e>{<% zn}492`Tfo3lS`**9T2wLP;~bH!hFs<-pg-1KepnsND z^=nn`;VRA(;i}V5L_S-pe1-8zky7|_+n0V)0o!(Z`nJAflfJtCg>|;o++GO>`8)}gAMDw#(k}3PxR!!ykEq`G4rS5ob{8PqhD$< z8ci$9h>SV2O8Uya);QCY&e9OG&{U^a-wWO;ZfsWE#k?=3`M&!thE0FYJ2E)_-{P$? zWo^!5F^6qetPh7Vu69Ua%i(lYGpO3NjcMP0j*G{bS+r)~V%Wx*T+6dMCyV*SM|R7( zzBOm=eyePF&FpyRUFVv(2kV4v?$j_;D@>ixJ?HP-&esZWvLrX~M6gXtdmyh|es_`7 SGeaRz3h;FGb6Mw<&;$TqCk1=} literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_upload.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_upload.png new file mode 100644 index 0000000000000000000000000000000000000000..34cad727e3ed2e392ad7c301f4e411e7ad45532d GIT binary patch literal 766 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*5QUV9M}xaSX{| zeH*#k@34W0uV4pb%MmVVA!%pT8&TitocDLgGwfUNzcJ)SLnrGD#|@5+jHMdSJ+`IH zsTNi*oaL1K^3=!LdA|!bx=h-#dhLOt@CCu{zc$~@;jQcE?cLaKJ@?#}zKDypOf}*q z{6*sD@4h&gWX*CyF5{6>`M#6ykM>EPl|R^M^1-bCsE?AspCq-!1N9Lljn-dh%d0cT zNzGn4y`z5Fj+=!>50;)1zM(5<)t#<+G0lq6V9y4ric@+H?;b^No|!MC=&)e2SA%`I z;lh2R-IGGzWPENTt*J1_B4Rf{y zf+ymYDwy@m8|SFF*|ELdvxu|k$NUNW9}ev~b@8-_^l!!~FV^pCy;R&1=fk}t{hw&7 z%?f5Q!@rF&{|nta8U+%BOE_+AXxu7m)heX%>VEI;S8|*7UCi6|Q_XvM*P1o|Hqy?$U~908--lEvo4h>WLbJ!WLpO;$_VuRSI+)n*-dp<-AKlC#gA9{4*U?= zDChBPx5JAkCxgG8pJ!3KM&y1<-`ne4?^xFS_)}+k?GCqX|HAXIKU0p6R^O^3j}j#Jg$!WiN%PycgmHu6_Hnt#K<~#Lq+T>+KkGTjsT1 z;xAmyQl`6R;e*gaQ#$@DGY5RS?-1RzSS{i`$FAP$sjC)PIJtdX!@0!kOfjcT=~2Fb z2E8@OyIDRi-*B?D_d%`72i-;iYX{fl3&)>xW;orOBYwPXW9Ww?i_03EcAuI1ApVf- q>D86bTWhZzTlVb6+TTxC9pLxyR84s1lko?X_B>tvT-G@yGywp-$w6TN literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_premium_translate.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_premium_translate.png new file mode 100644 index 0000000000000000000000000000000000000000..6618705e2069d32e4c897e2e0a8b058c321be894 GIT binary patch literal 1712 zcmV;h22c5kP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>8c9S!RCodHn`@{QRTRfPzBRjQ zFSC%VNf2QPDV1q~32EG*z=FDnk)cq1@Pm*9WfF*1m!J>5AV{K@e&}(DETW>Ps1QOC z^!gBGBo#?%zRKHg#mr&5@7gna&Y3f_kL(S9X7Bad|FzDXJu~~v88ITZSbl#Ff=qYE+js|aG@}#gV(@6;5X1847m`9P>=y&wqp!>L*S-y7^w+6 zEL&v7AH(=^OBT$qjslHUve#saS@ohi3RHcTZOk~@$CowYH0*8w=lR&@*qp8CmodjV zioA&E7{cvPkE|8RYCakYnSm&i#r>B)(?zIot!vSfnMSZ<~wZ zG|Tu1<*{VCZ;YVqAU+D* z3*H8ggELzth;I-09oX%aR%6!gM<$P2+3akU6mcH3Vx>d-Ij+?ys`n#f>mCsw^RwwkZ5($L$pF9e!C!`d z+Wn+RoFHw1;EfVDV6w)G^<0=xmCE$b@S?x#0lQci%7XvxFw04)~6NC)5V}SgWW4BEj zL5$7lk?+^CK_-{zQCS4hzoGd4gzRNSF54v&vf|aMgWN+3X_x3r6q!E`pzj6p)v=qL ztykE>WPE3>MaY^Qf@gp~9mGwsoKZ8gVu=o$&8Ab*mmS7)6a5}V|9M{ATJ;citwm`r zvKB4KBZ-YXiu{^78ON7WUu3r%asG+)O%^R?X)?&&2eeNR@z7BqzkD2#L4l?f^+o*U%+heTBlaz&C0aBPgeHP* z4q_sf%l-cw_#EZyC-*&7x9^JPRf;`X&IGcCxY{o$E;A=%EI%@?0ivt2^_e_6-Y2uU zK)XLlla{@i*)AgJCV_Q89zk4RO;n||w_IF0B8PU?nez_%slF3qI}NM`uLF5v??k~4 z5?A}p&6lRX9TUmcgDZ&vbeRvHSu^2#A}7jlfJ|*^g;yoA0)o!;Tr~-H>U0KZ~8OQ4DcQh@}Ggizr{C$B^_eO6;Zp%e9pGb z8xvl1U>}gX=yyT8{{T8^TH?u$qujFzww$EwrUB$T zws;a-?v3i-JnNPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?heIc_AZ>y`g0fY$Nl086w78JyUG*2(#(yAbVO*nverRwB zZ4q^&Fa%A#eZG0-W#)OGnKNg8yuSDPKJaB`&NXF-}URqk(O2uCAG{B5v8(wrmoGvpc|9a0`q|WJ@-8jBTQDZXGxU{ss3-WLrM0 z>nc&5bkaDqABSeamKu)Tq0J@m1^6-GD#xs2=5)|u>(O~CU?0alU=4`LuQWJHhkh>B zu-AGLvlh&PnCKBW2M&Tqn>r=kz#*m~jj=^1^>g{x!`Z-YNk#oYYUnCpBmTZ=ZeBD)_wM9z|O@qZUPbfbRM&nE_ z4%rO0Ik+O9r*kUZpJG5xlqKgbb?^1M<-m zjoaD_%=F{aM~prnzo6^&N= z8ApsDq4FJgBks8*^N?uF<9!UK5hYn2O=IHn{_u*m{@94dnx(UHgM!|_t@=)rVgQQ8 z%E?-`(b62UH)1|fi(nZvB0kM9SW(RJIc^%wSWT{V3noulptBVm2b#apQ7am)L>z&u zF(>+(D)G9InW%FpYQ?}x^2{6rd%$moNY|PbY$RQB!leXTIURKjjmuVx>jP26Tm#zc zF}>vQs7U4UTRF$4Q|Sa<4nva63B$o57GgJMi(~Hf^!986bMsHHANq^C4hbr&ztq)GG zublTX`F|NsEC4IpOBE_AAQ|h|yj;h}?KW7h7xG~hR#vI}gUXHh2AprALt8XuwJzb) z8{rM`4EPqDfveT_l`c8qQml$OFN^rNDJ!rEx=F>uS!Fn`Md6kyTM?HeNU}Y^-kGJDe__~t2zGHUTlRN*gHrY zCashYoNUYGcdflgRth<=3DRy-D}|xAtt`9d4eH+P}$K5oSz2%?C@bKHHsHA<=pXbDG!ad<{DgaM~VpCw&4QNeL$S^*DN;Tf%UCljDmioV0H| z<=V-lJq~zFM`lx4l0Y#Y`*LxW(d5$e)7U0JW6&fNi=CBdaT~A z%!E^kPP>J}kf3c4sZ+Hw=h%!ELGlvt?n=vF_xfuZ?v5IE8lX4l7*VX=sM=u&MI}Uf zVg-uj+3=UD3Ge12CA# zDsj8A82$5(LG^K^+g~b&=O}7((J{yB`%EgGaLSX4;MZgF0?>@(W}pG-UGNvs?>96H z`6adr-$#@s3%0cB>mx_;WBA{7%Hu_lPPX91(nON>15YNKIJ4xDomnqKlr4Y`0O{HYyv-=y4mHZNc&d$R|$}L)w_9EGf1e;>nL$Y*OqsNtyuCRI7*wC+ zZFZn|AU8OB@P3k+{c#CC^+&x2&`FxU&1~r?T_6rkc6lGu6cy$>cllO zS@pJ~x|N7qHu@R()d{q18=Tj)>kQCp$z{-1#33$m+Lht9?hfg9(n$}oRumAFcAcri zRmZCicqiBZvW}V4L5Ho41eyy{N4_%u!4iQ@WRiggI0OFyChat archived. Chats archived. Hide the archive by swiping left on it. - UNDO + Undo Delete from cache Delete and exit Hide @@ -235,6 +235,10 @@ Delete chat Deleted Account Select Chat + Choose Bot + Choose User + Choose Group + Choose Channel Select Chats Forward to... My Groups @@ -266,6 +270,12 @@ Wrong layout? Send Sticker Send GIF + Send Emoji + Copy Emoji + Set as Status + Emoji status set. + Remove Status + Emoji status removed. View Pack Pin to top Sorry, you can only pin %1$s to the top in the main list. More chats can be pinned in Chat Folders. @@ -325,6 +335,14 @@ Message unpinned Tap on the pencil to start a new chat Create a New Group to Import + Create a New Channel For This + No such channels + You don\'t have channels that meet the requirements for this bot + Create a New Group For This + No such groups + You don\'t have groups that meet the requirements for this bot + No such users + No users found that meet the requirements for this bot Import Messages Import Error Invalid file format. @@ -606,8 +624,16 @@ What can this user do? Read Messages Send Messages + Send Polls + Send Text Messages Send Media Send Polls + Send Photos + Send Videos + Send Music + Send Files + Send Voice Messages + Send Video Messages Send Stickers & GIFs Embed Links Change Chat Info @@ -615,8 +641,15 @@ Add Users can\'t read can\'t send messages - no media + can\'t send text messages no polls + no media + no photos + no videos + no music + no files + no voice + no round no stickers & GIFs no embed links can\'t change Info @@ -667,6 +700,7 @@ Statistics Add Bot Add bot as admin + Add bot as admin? Add as admin Add bot as Member @@ -1199,21 +1233,43 @@ Are you sure you want to stop recording and discard your video message? Discard The admins of this group have restricted you from sending media here until %1$s + The admins of this group have restricted you from sending audio here until %1$s + The admins of this group have restricted you from sending photo here until %1$s + The admins of this group have restricted you from sending video messages here until %1$s + The admins of this group have restricted you from sending voice messages here until %1$s + The admins of this group have restricted you from sending video here until %1$s + The admins of this group have restricted you from sending documents here until %1$s The admins of this group have restricted you from sending inline content here until %1$s The admins of this group have restricted you from sending stickers here until %1$s The admins of this group have restricted you from sending GIFs here until %1$s + The admins of this group have restricted you from sending text message here until %1$s The admins of this group have restricted you from writing here until %1$s The admins of this group have restricted you from sending media here. + The admins of this group have restricted you from sending audio here. + The admins of this group have restricted you from sending documents here. + The admins of this group have restricted you from sending photo here. + The admins of this group have restricted you from sending video messages here. + The admins of this group have restricted you from sending voice messages here. + The admins of this group have restricted you from sending video here. The admins of this group have restricted you from sending inline content here The admins of this group have restricted you from sending stickers. The admins of this group have restricted you from sending GIFs. + The admins of this group have restricted you from sending text message. The admins of this group have restricted you from writing here. **%1$s** doesn\'t accept voice messages. **%1$s** doesn\'t accept video messages. + Sending plain text isn\'t allowed in this group. + Sending documents isn\'t allowed in this group. Sending media isn\'t allowed in this group. + Sending music isn\'t allowed in this group. + Sending photo isn\'t allowed in this group. + Sending video isn\'t allowed in this group. + Sending voice isn\'t allowed in this group. + Sending round video isn\'t allowed in this group. Inline bots aren\'t allowed in this group. Stickers aren\'t allowed in this group. GIFs aren\'t allowed in this group. + Text message aren\'t allowed in this group. Writing messages isn\'t allowed in this group. Message preview Preview message @@ -1724,6 +1780,11 @@ Add %1$d emoji Add %1$d emoji Add %1$d emoji + Add emoji pack + Add %1$d emoji packs + Add %1$d emoji packs + Add %1$d emoji packs + Add %1$d emoji packs Remove emoji Remove %1$d emoji Remove %1$d emoji @@ -1756,6 +1817,7 @@ More Stickers Delete from Favorites Delete from Recent + Remove from Recent Clear recent stickers Add to Masks Stickers not found @@ -2103,6 +2165,8 @@ Pinned Messages Translate Messages Show Translate Button + Translate Entire Chat + Subscribe to **Telegram Premium** to translate all chat messages at once. Do Not Translate %1$d Languages %1$d Language @@ -2200,6 +2264,10 @@ Voice messages are tiny, so they\'re always downloaded automatically. No media No GIFs + Auto-Download Settings + You can change your auto-download settings for media to reduce data usage when connected via mobile network. + You can change your auto-download settings for media to reduce data usage when connected to Wi-Fi. + You can change your auto-download settings for media to reduce data usage when roaming. Reset Auto-Download Settings Reset settings Are you sure you want to reset auto-download settings? @@ -2456,7 +2524,7 @@ Profile Photos Miscellaneous Photos - Voice/Video messages + Voice messages Videos Music GIFs @@ -3233,6 +3301,7 @@ All media will stay in the Telegram cloud and can be re-downloaded if you need it again. Data Usage Storage Path + All Mobile Wi-Fi Roaming @@ -3241,14 +3310,44 @@ Received Bytes sent Bytes received + Files sent + Files received + **%s** files sent + **%s** file sent + **%s** files sent + **%s** files sent + **%s** files sent + **%s** files sent + **%s** files received + **%s** file received + **%s** files received + **%s** files received + **%s** files received + **%s** files received Files Calls Outgoing calls Incoming calls + %1$d outgoing calls + %1$d outgoing call + %1$d outgoing calls + %1$d outgoing calls + %1$d outgoing calls + %1$d outgoing calls + %1$d incoming calls + %1$d incoming call + %1$d incoming calls + %1$d incoming calls + %1$d incoming calls + %1$d incoming calls Total time Total + Total network usage + Tap on each section for detailed view. Reset Statistics Network usage since %1$s + Your network usage since %1$s + No network usage since %1$s Reset statistics Do you want to reset your usage statistics? @@ -3674,10 +3773,22 @@ Sorry, you can\'t ban this user because they are an admin in this group and you are not allowed to demote them. Sorry, the admins of this group have restricted you from sending stickers. Sorry, the admins of this group have restricted you from sending media. + Sorry, the admins of this group have restricted you from sending photo. + Sorry, the admins of this group have restricted you from sending video. Sorry, the admins of this group have restricted you from sending polls. + Sorry, the admins of this group have restricted you from sending voice messages. + Sorry, the admins of this group have restricted you from sending video messages. + Sorry, the admins of this group have restricted you from sending documents. + Sorry, the admins of this group have restricted you from sending music. Sorry, sending stickers is not allowed in this group. + Sorry, sending photo is not allowed in this group. + Sorry, sending video is not allowed in this group. Sorry, sending media is not allowed in this group. Sorry, sending polls is not allowed in this group. + Sorry, sending voice messages is not allowed in this group. + Sorry, sending video messages is not allowed in this group. + Sorry, sending documents is not allowed in this group. + Sorry, sending music is not allowed in this group. Sorry, you can\'t send voice messages to this user because of their privacy settings. Sorry, you can\'t send video messages to this user because of their privacy settings. Unable to forward @@ -4983,6 +5094,8 @@ More options Switch to night theme Switch to day theme + Close Trending stickers + Close Trending emoji Play Pause Download @@ -5598,6 +5711,9 @@ Animated Profile Pictures Video avatars animated in chat lists and chats to allow for additional self-expression. Subscribe for %s per month + Subscribe for %s per year + Upgrade for %s per year + Upgrade for %s per year Subscribe Subscription not available **Official app needed** @@ -5750,6 +5866,8 @@ Infinite Reactions Emoji Status Add any of thousands emojis next to your name to display current activity. + Real-Time Translation + Real-time translation of channels and chats into other languages. Microphone for voice messages Built-In Headset @@ -5995,6 +6113,10 @@ Set as My Photo Invite To Telegram You allowed this bot to message you when you added it to your attachment menu. + You shared un1 with un2 + You shared a user with un2 + You shared a chat with un2 + You shared a channel with un2 Hide with spoiler Remove spoiler Update Public Photo @@ -6030,7 +6152,7 @@ View Photo View Video Chats - Media + Media Files Music Voice @@ -6049,4 +6171,87 @@ Delete All Proxies Are you sure you want to delete all proxies? Send as %1$s + Review the list of devices where you are logged into your Telegram account. + Photos + Videos + + Music + Files + Voice Messages + Video Messages + Embed Links + Polls + Use an emoji + Auto-switch proxies + You can configure the timeout for connecting to the nearest active proxy if the current one stops working. + %1$d sec. + Requirements + The user should have a Premium subscription. + The user should not have a Premium subscription. + The channel should be public. + The channel should be private. + The group should be public. + The group should be private. + Bot should be in the channel. + Bot should be in the group. + You should be the owner of the channel. + You should not be the owner of the channel. + You should be the owner of the group. + You should not be the owner of the group. + The group should have topics turned on. + The group should have topics turned off. + You should have these admin rights: + You should have admin rights to + Set Channel Photo + Set Group Photo + Photo Editor + Choose background + Send %1$s to %2$s? + Are you sure you want to send **%1$s** to **%2$s**? + This will also add **%1$s** to **%2$s**. + This will also add **%1$s** to **%2$s** with the following rights: %3$s. + Maximum video size + Automatically save all new media from private chats to your phone\'s gallery. + Automatically save all new media from groups to your phone\'s gallery. + Automatically save all new media from channels to your phone\'s gallery. + Automatically save all new media from this chat to your phone\'s gallery. + Photos + Videos + All videos in private chats less than the selected size will be saved to your gallery. + All videos in groups less than the selected size will be saved to your gallery. + All videos in channels less than the selected size will be saved to your gallery. + All videos from this chat less than the selected size will be saved to your gallery. + Add Exception + Exception + Off + Videos up to %s + The admins of this group only allow to send %s. + Text not allowed + Choose emoji or sticker + Up to %s + Save exception + Edit Exception + Translate To + Detected Language + Don\'t translate %s + Don\'t translate %s + Translate to %s + Translate to %s + Show Original + **%s** is added to the Do Not Translate list. + Translation bar is now hidden for this channel. + Translation bar is now hidden for this group. + Translation bar is now hidden for this chat. + No emoji or stickers found + An internal error occurred. Please try again later. + Upgrade to Premium with a discount of **%1$d%%** + Upgrade to the annual payment plan of Telegram Premium now to enjoy the discount. + Save on your subscription up to **%1$d%%** + Sign up for the annual payment plan for Telegram Premium now to get the discount. + Pause music while recording + Set Profile Photo + Status + Free up to **%s** + Clear storage space on your phone + your current plan diff --git a/gradle.properties b/gradle.properties index cb66d17ed..3061e15e9 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_NAME=9.3.3 -APP_VERSION_CODE=3026 +APP_VERSION_NAME=9.4.0 +APP_VERSION_CODE=3098 APP_PACKAGE=org.telegram.messenger RELEASE_KEY_PASSWORD=android RELEASE_KEY_ALIAS=androidkey