From 8bf056e27b51321c776e58c479cd616f92e3f844 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Wed, 14 Apr 2021 04:44:46 +0300 Subject: [PATCH] Update to 7.7.0 (2284) --- Dockerfile | 2 +- TMessagesProj/build.gradle | 28 +- .../release/AndroidManifest_standalone.xml | 67 + TMessagesProj/google-services.json | 39 +- TMessagesProj/jni/CMakeLists.txt | 2 +- TMessagesProj/jni/TgNetWrapper.cpp | 10 +- TMessagesProj/jni/tgnet/ApiScheme.cpp | 8 +- TMessagesProj/jni/tgnet/ApiScheme.h | 3 +- .../jni/tgnet/ConnectionsManager.cpp | 27 +- TMessagesProj/jni/tgnet/ConnectionsManager.h | 4 +- TMessagesProj/src/main/AndroidManifest.xml | 2 - .../telegram/messenger/AndroidUtilities.java | 40 +- .../org/telegram/messenger/BuildVars.java | 4 +- .../org/telegram/messenger/ChatObject.java | 29 +- .../messenger/DownloadController.java | 9 +- .../telegram/messenger/FileLoadOperation.java | 2 +- .../org/telegram/messenger/ImageLocation.java | 61 +- .../org/telegram/messenger/ImageReceiver.java | 4 + .../telegram/messenger/LocaleController.java | 137 +- .../telegram/messenger/MediaController.java | 2 +- .../messenger/MediaDataController.java | 64 +- .../org/telegram/messenger/MessageObject.java | 5 +- .../messenger/MessagesController.java | 55 +- .../telegram/messenger/MessagesStorage.java | 22 +- .../org/telegram/messenger/NativeLoader.java | 2 +- .../messenger/NotificationCenter.java | 1 - .../messenger/NotificationsController.java | 4 + .../messenger/SendMessagesHelper.java | 83 +- .../org/telegram/messenger/SvgHelper.java | 6 +- .../WearDataLayerListenerService.java | 2 +- .../messenger/voip/VoIPBaseService.java | 59 +- .../telegram/messenger/voip/VoIPService.java | 13 +- .../telegram/tgnet/ConnectionsManager.java | 13 +- .../main/java/org/telegram/tgnet/TLRPC.java | 1614 +++++++----- .../ui/ActionBar/ActionBarLayout.java | 42 +- .../telegram/ui/ActionBar/ActionBarMenu.java | 1 - .../ui/ActionBar/ActionBarMenuItem.java | 4 +- .../telegram/ui/ActionBar/AlertDialog.java | 31 +- .../telegram/ui/ActionBar/BaseFragment.java | 23 +- .../telegram/ui/ActionBar/BottomSheet.java | 7 + .../ui/ActionBar/DrawerLayoutContainer.java | 8 + .../telegram/ui/ActionBar/SimpleTextView.java | 82 +- .../java/org/telegram/ui/ActionBar/Theme.java | 2 + .../telegram/ui/Adapters/DialogsAdapter.java | 8 - .../ui/Adapters/DrawerLayoutAdapter.java | 2 +- .../org/telegram/ui/Adapters/FiltersView.java | 6 +- .../java/org/telegram/ui/ArticleViewer.java | 44 +- .../java/org/telegram/ui/AvatarPreviewer.java | 16 +- .../ui/CancelAccountDeletionActivity.java | 5 +- .../telegram/ui/Cells/AccountSelectCell.java | 6 +- .../telegram/ui/Cells/AdminedChannelCell.java | 2 +- .../telegram/ui/Cells/ChatMessageCell.java | 91 +- .../telegram/ui/Cells/CheckBoxUserCell.java | 2 +- .../org/telegram/ui/Cells/DialogCell.java | 12 +- .../telegram/ui/Cells/DialogMeUrlCell.java | 6 +- .../telegram/ui/Cells/DrawerProfileCell.java | 2 +- .../org/telegram/ui/Cells/DrawerUserCell.java | 2 +- .../ui/Cells/GroupCallInvitedCell.java | 2 +- .../telegram/ui/Cells/GroupCallUserCell.java | 159 +- .../ui/Cells/GroupCreateUserCell.java | 4 +- .../org/telegram/ui/Cells/HintDialogCell.java | 6 +- .../telegram/ui/Cells/JoinSheetUserCell.java | 2 +- .../telegram/ui/Cells/ManageChatUserCell.java | 4 +- .../org/telegram/ui/Cells/MentionCell.java | 6 +- .../telegram/ui/Cells/PaymentInfoCell.java | 55 +- .../telegram/ui/Cells/ProfileSearchCell.java | 4 +- .../org/telegram/ui/Cells/SessionCell.java | 2 +- .../telegram/ui/Cells/ShareDialogCell.java | 47 +- .../ui/Cells/SharingLiveLocationCell.java | 16 +- .../ui/Cells/StatisticPostInfoCell.java | 2 +- .../java/org/telegram/ui/Cells/UserCell.java | 4 +- .../java/org/telegram/ui/Cells/UserCell2.java | 4 +- .../org/telegram/ui/ChangePhoneActivity.java | 5 +- .../telegram/ui/ChannelAdminLogActivity.java | 2 +- .../telegram/ui/ChannelCreateActivity.java | 2 +- .../java/org/telegram/ui/ChatActivity.java | 210 +- .../org/telegram/ui/ChatEditActivity.java | 10 +- .../org/telegram/ui/ChatLinkActivity.java | 2 +- .../org/telegram/ui/ChatUsersActivity.java | 7 +- .../telegram/ui/Components/AlertsCreator.java | 388 ++- .../ui/Components/AvatarsImageView.java | 4 +- .../org/telegram/ui/Components/Bulletin.java | 3 + .../ui/Components/BulletinFactory.java | 2 + .../ui/Components/ChatActivityEnterView.java | 7 +- .../ui/Components/ChatAttachAlert.java | 50 +- .../ChatAttachAlertContactsLayout.java | 2 +- .../ChatAttachAlertPhotoLayout.java | 42 +- .../ui/Components/ChatAvatarContainer.java | 8 +- .../ui/Components/ChatGreetingsView.java | 35 +- .../ui/Components/ContextProgressView.java | 22 +- .../ui/Components/FilterTabsView.java | 8 + .../ui/Components/FragmentContextView.java | 146 +- .../FragmentContextViewWavesDrawable.java | 10 +- .../ui/Components/GroupCreateSpan.java | 4 +- .../org/telegram/ui/Components/HintView.java | 10 +- .../telegram/ui/Components/ImageUpdater.java | 12 +- .../telegram/ui/Components/JoinCallAlert.java | 397 ++- .../ui/Components/JoinCallByUrlAlert.java | 2 +- .../ui/Components/JoinGroupAlert.java | 2 +- .../telegram/ui/Components/NumberPicker.java | 1 + .../ui/Components/PhonebookShareAlert.java | 2 +- .../ui/Components/PollVotesAlert.java | 2 +- .../ui/Components/ProfileGalleryView.java | 459 ++-- .../ui/Components/PullForegroundDrawable.java | 2 +- .../ui/Components/RecyclerListView.java | 2 +- .../ui/Components/ScrollSlidingTabStrip.java | 2 +- .../telegram/ui/Components/ShareAlert.java | 6 +- .../ui/Components/SharedMediaLayout.java | 36 + .../org/telegram/ui/Components/UndoView.java | 50 +- .../ui/Components/VideoForwardDrawable.java | 124 +- .../ui/Components/VideoPlayerSeekBar.java | 61 +- .../ui/Components/voip/VoIPHelper.java | 21 +- .../ui/Components/voip/VoIPToggleButton.java | 23 +- .../org/telegram/ui/ContactAddActivity.java | 2 +- .../java/org/telegram/ui/DialogsActivity.java | 184 +- .../org/telegram/ui/GroupCallActivity.java | 2196 +++++++++++++---- .../telegram/ui/GroupCreateFinalActivity.java | 2 +- .../java/org/telegram/ui/LaunchActivity.java | 57 +- .../org/telegram/ui/LocationActivity.java | 2 +- .../java/org/telegram/ui/LoginActivity.java | 52 +- .../telegram/ui/MessageStatisticActivity.java | 2 +- .../org/telegram/ui/PassportActivity.java | 10 +- .../org/telegram/ui/PaymentFormActivity.java | 807 ++++-- .../java/org/telegram/ui/PhotoViewer.java | 270 +- .../org/telegram/ui/PinchToZoomHelper.java | 708 ++++++ .../ui/PopupNotificationActivity.java | 4 +- .../telegram/ui/PrivacySettingsActivity.java | 13 + .../java/org/telegram/ui/ProfileActivity.java | 188 +- .../java/org/telegram/ui/VoIPFragment.java | 22 +- .../src/main/res/drawable-hdpi/bot_card.png | Bin 0 -> 228 bytes .../src/main/res/drawable-hdpi/msg_addbio.png | Bin 0 -> 1050 bytes .../src/main/res/drawable-hdpi/msg_bio.png | Bin 0 -> 894 bytes .../msg_report_abuse.png | Bin .../msg_report_fake.png | Bin .../msg_report_other.png | Bin .../msg_report_spam.png | Bin .../msg_report_violence.png | Bin .../msg_report_xxx.png | Bin .../main/res/drawable-hdpi/msg_timeredit.png | Bin 0 -> 1086 bytes .../main/res/drawable-hdpi/msg_voiceshare.png | Bin 0 -> 678 bytes .../res/drawable-hdpi/payment_address.png | Bin 0 -> 930 bytes .../main/res/drawable-hdpi/payment_card.png | Bin 0 -> 451 bytes .../res/drawable-hdpi/payment_delivery.png | Bin 0 -> 842 bytes .../main/res/drawable-hdpi/payment_email.png | Bin 0 -> 1116 bytes .../main/res/drawable-hdpi/payment_name.png | Bin 0 -> 767 bytes .../main/res/drawable-hdpi/payment_phone.png | Bin 0 -> 778 bytes .../res/drawable-hdpi/payment_provider.png | Bin 0 -> 740 bytes .../src/main/res/drawable-mdpi/bot_card.png | Bin 0 -> 220 bytes .../src/main/res/drawable-mdpi/msg_addbio.png | Bin 0 -> 685 bytes .../src/main/res/drawable-mdpi/msg_bio.png | Bin 0 -> 599 bytes .../main/res/drawable-mdpi/msg_timeredit.png | Bin 0 -> 726 bytes .../main/res/drawable-mdpi/msg_voiceshare.png | Bin 0 -> 479 bytes .../res/drawable-mdpi/payment_address.png | Bin 0 -> 630 bytes .../main/res/drawable-mdpi/payment_card.png | Bin 0 -> 368 bytes .../res/drawable-mdpi/payment_delivery.png | Bin 0 -> 628 bytes .../main/res/drawable-mdpi/payment_email.png | Bin 0 -> 713 bytes .../main/res/drawable-mdpi/payment_name.png | Bin 0 -> 504 bytes .../main/res/drawable-mdpi/payment_phone.png | Bin 0 -> 528 bytes .../res/drawable-mdpi/payment_provider.png | Bin 0 -> 523 bytes .../src/main/res/drawable-xhdpi/bot_card.png | Bin 0 -> 259 bytes .../main/res/drawable-xhdpi/msg_addbio.png | Bin 0 -> 1324 bytes .../src/main/res/drawable-xhdpi/msg_bio.png | Bin 0 -> 1210 bytes .../main/res/drawable-xhdpi/msg_timeredit.png | Bin 0 -> 1437 bytes .../res/drawable-xhdpi/msg_voiceshare.png | Bin 0 -> 862 bytes .../res/drawable-xhdpi/payment_address.png | Bin 0 -> 1220 bytes .../main/res/drawable-xhdpi/payment_card.png | Bin 0 -> 569 bytes .../res/drawable-xhdpi/payment_delivery.png | Bin 0 -> 1164 bytes .../main/res/drawable-xhdpi/payment_email.png | Bin 0 -> 1471 bytes .../main/res/drawable-xhdpi/payment_name.png | Bin 0 -> 863 bytes .../main/res/drawable-xhdpi/payment_phone.png | Bin 0 -> 994 bytes .../res/drawable-xhdpi/payment_provider.png | Bin 0 -> 906 bytes .../src/main/res/drawable-xxhdpi/bot_card.png | Bin 0 -> 333 bytes .../main/res/drawable-xxhdpi/msg_addbio.png | Bin 0 -> 1986 bytes .../src/main/res/drawable-xxhdpi/msg_bio.png | Bin 0 -> 1715 bytes .../res/drawable-xxhdpi/msg_timeredit.png | Bin 0 -> 2185 bytes .../res/drawable-xxhdpi/msg_voiceshare.png | Bin 0 -> 1356 bytes .../res/drawable-xxhdpi/payment_address.png | Bin 0 -> 1855 bytes .../main/res/drawable-xxhdpi/payment_card.png | Bin 0 -> 692 bytes .../res/drawable-xxhdpi/payment_delivery.png | Bin 0 -> 1544 bytes .../res/drawable-xxhdpi/payment_email.png | Bin 0 -> 2144 bytes .../main/res/drawable-xxhdpi/payment_name.png | Bin 0 -> 1231 bytes .../res/drawable-xxhdpi/payment_phone.png | Bin 0 -> 1438 bytes .../res/drawable-xxhdpi/payment_provider.png | Bin 0 -> 1250 bytes .../res/mipmap-anydpi-v26/ic_launcher_sa.xml | 5 + .../main/res/mipmap-hdpi/ic_launcher_sa.png | Bin 0 -> 5750 bytes .../res/mipmap-hdpi/icon_background_sa.png | Bin 0 -> 11868 bytes .../res/mipmap-hdpi/icon_foreground_sa.png | Bin 0 -> 1857 bytes .../main/res/mipmap-mdpi/ic_launcher_sa.png | Bin 0 -> 3179 bytes .../res/mipmap-mdpi/icon_background_sa.png | Bin 0 -> 7015 bytes .../res/mipmap-mdpi/icon_foreground_sa.png | Bin 0 -> 1178 bytes .../main/res/mipmap-xhdpi/ic_launcher_sa.png | Bin 0 -> 8405 bytes .../res/mipmap-xhdpi/icon_background_sa.png | Bin 0 -> 17542 bytes .../res/mipmap-xhdpi/icon_foreground_sa.png | Bin 0 -> 2868 bytes .../main/res/mipmap-xxhdpi/ic_launcher_sa.png | Bin 0 -> 15490 bytes .../res/mipmap-xxhdpi/icon_background_sa.png | Bin 0 -> 33126 bytes .../res/mipmap-xxhdpi/icon_foreground_sa.png | Bin 0 -> 5036 bytes .../res/mipmap-xxxhdpi/ic_launcher_sa.png | Bin 0 -> 23169 bytes .../res/mipmap-xxxhdpi/icon_background_sa.png | Bin 0 -> 51199 bytes .../res/mipmap-xxxhdpi/icon_foreground_sa.png | Bin 0 -> 7553 bytes .../src/main/res/raw/contacts_sync_off.json | 1 + .../src/main/res/raw/contacts_sync_on.json | 1 + TMessagesProj/src/main/res/raw/folder_in.json | 1 + .../src/main/res/raw/folder_out.json | 1 + TMessagesProj/src/main/res/raw/hand_2.json | 1 + .../src/main/res/raw/payment_success.json | 1 + .../src/main/res/raw/utyan_schedule.tgs | 1 + .../src/main/res/raw/voip_filled.json | 1 + .../src/main/res/values-v21/styles.xml | 8 +- TMessagesProj/src/main/res/values/strings.xml | 85 + 209 files changed, 7674 insertions(+), 2278 deletions(-) create mode 100644 TMessagesProj/config/release/AndroidManifest_standalone.xml create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_card.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_addbio.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_bio.png rename TMessagesProj/src/main/res/{mipmap-mdpi => drawable-hdpi}/msg_report_abuse.png (100%) rename TMessagesProj/src/main/res/{mipmap-mdpi => drawable-hdpi}/msg_report_fake.png (100%) rename TMessagesProj/src/main/res/{mipmap-mdpi => drawable-hdpi}/msg_report_other.png (100%) rename TMessagesProj/src/main/res/{mipmap-mdpi => drawable-hdpi}/msg_report_spam.png (100%) rename TMessagesProj/src/main/res/{mipmap-mdpi => drawable-hdpi}/msg_report_violence.png (100%) rename TMessagesProj/src/main/res/{mipmap-mdpi => drawable-hdpi}/msg_report_xxx.png (100%) create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_timeredit.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_voiceshare.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/payment_address.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/payment_card.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/payment_delivery.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/payment_email.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/payment_name.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/payment_phone.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/payment_provider.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_card.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_addbio.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_bio.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_timeredit.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_voiceshare.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/payment_address.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/payment_card.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/payment_delivery.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/payment_email.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/payment_name.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/payment_phone.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/payment_provider.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_card.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_addbio.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_bio.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_timeredit.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_voiceshare.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/payment_address.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/payment_card.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/payment_delivery.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/payment_email.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/payment_name.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/payment_phone.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/payment_provider.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_card.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_addbio.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_bio.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_timeredit.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_voiceshare.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/payment_address.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/payment_card.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/payment_delivery.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/payment_email.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/payment_name.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/payment_phone.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/payment_provider.png create mode 100644 TMessagesProj/src/main/res/mipmap-anydpi-v26/ic_launcher_sa.xml create mode 100644 TMessagesProj/src/main/res/mipmap-hdpi/ic_launcher_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-hdpi/icon_background_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-hdpi/icon_foreground_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-mdpi/ic_launcher_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-mdpi/icon_background_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-mdpi/icon_foreground_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-xhdpi/ic_launcher_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-xhdpi/icon_background_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-xhdpi/icon_foreground_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-xxhdpi/ic_launcher_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-xxhdpi/icon_background_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-xxhdpi/icon_foreground_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-xxxhdpi/ic_launcher_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-xxxhdpi/icon_background_sa.png create mode 100644 TMessagesProj/src/main/res/mipmap-xxxhdpi/icon_foreground_sa.png create mode 100644 TMessagesProj/src/main/res/raw/contacts_sync_off.json create mode 100644 TMessagesProj/src/main/res/raw/contacts_sync_on.json create mode 100644 TMessagesProj/src/main/res/raw/folder_in.json create mode 100644 TMessagesProj/src/main/res/raw/folder_out.json create mode 100644 TMessagesProj/src/main/res/raw/hand_2.json create mode 100644 TMessagesProj/src/main/res/raw/payment_success.json create mode 100644 TMessagesProj/src/main/res/raw/utyan_schedule.tgs create mode 100644 TMessagesProj/src/main/res/raw/voip_filled.json diff --git a/Dockerfile b/Dockerfile index 011f3992919..7f0a37ea517 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,4 +24,4 @@ RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSIO ENV PATH ${ANDROID_NDK_HOME}:$PATH ENV PATH ${ANDROID_NDK_HOME}/prebuilt/linux-x86_64/bin/:$PATH -CMD mkdir -p /home/source/TMessagesProj/build/outputs/apk && mkdir -p /home/source/TMessagesProj/build/outputs/native-debug-symbols && cp -R /home/source/. /home/gradle && cd /home/gradle && gradle assembleRelease && cp -R /home/gradle/TMessagesProj/build/outputs/apk/. /home/source/TMessagesProj/build/outputs/apk && cp -R /home/gradle/TMessagesProj/build/outputs/native-debug-symbols/. /home/source/TMessagesProj/build/outputs/native-debug-symbols +CMD mkdir -p /home/source/TMessagesProj/build/outputs/apk && mkdir -p /home/source/TMessagesProj/build/outputs/native-debug-symbols && cp -R /home/source/. /home/gradle && cd /home/gradle && gradle assembleRelease && gradle assembleStandalone && cp -R /home/gradle/TMessagesProj/build/outputs/apk/. /home/source/TMessagesProj/build/outputs/apk && cp -R /home/gradle/TMessagesProj/build/outputs/native-debug-symbols/. /home/source/TMessagesProj/build/outputs/native-debug-symbols diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 68e83acd4e6..cf50a975a14 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -143,6 +143,17 @@ android { ndk.debugSymbolLevel = 'FULL' } + standalone { + debuggable false + jniDebuggable false + signingConfig signingConfigs.release + applicationIdSuffix ".web" + minifyEnabled true + multiDexEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + ndk.debugSymbolLevel = 'FULL' + } + release { debuggable false jniDebuggable false @@ -167,6 +178,10 @@ android { manifest.srcFile 'config/debug/AndroidManifest.xml' } + sourceSets.standalone { + manifest.srcFile 'config/release/AndroidManifest.xml' + } + sourceSets.release { manifest.srcFile 'config/release/AndroidManifest.xml' } @@ -243,9 +258,6 @@ android { sourceSets.debug { manifest.srcFile 'config/debug/AndroidManifest_SDK23.xml' } - /*sourceSets.debugAsan { - manifest.srcFile 'config/debug/AndroidManifest_SDK23.xml' - }*/ sourceSets.release { manifest.srcFile 'config/release/AndroidManifest_SDK23.xml' } @@ -276,19 +288,19 @@ android { sourceSets.debug { manifest.srcFile 'config/debug/AndroidManifest_SDK23.xml' } - /*sourceSets.debugAsan { - manifest.srcFile 'config/debug/AndroidManifest_SDK23.xml' - }*/ sourceSets.release { manifest.srcFile 'config/release/AndroidManifest_SDK23.xml' } + sourceSets.standalone { + manifest.srcFile 'config/release/AndroidManifest_standalone.xml' + } ext { abiVersionCode = 9 } } } - defaultConfig.versionCode = 2274 + defaultConfig.versionCode = 2284 applicationVariants.all { variant -> variant.outputs.all { output -> @@ -307,7 +319,7 @@ android { defaultConfig { minSdkVersion 16 targetSdkVersion 29 - versionName "7.6.1" + versionName "7.7.0" vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi'] diff --git a/TMessagesProj/config/release/AndroidManifest_standalone.xml b/TMessagesProj/config/release/AndroidManifest_standalone.xml new file mode 100644 index 00000000000..3c87a4403a6 --- /dev/null +++ b/TMessagesProj/config/release/AndroidManifest_standalone.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TMessagesProj/google-services.json b/TMessagesProj/google-services.json index 019c926bc17..640e841b2d2 100755 --- a/TMessagesProj/google-services.json +++ b/TMessagesProj/google-services.json @@ -6,6 +6,35 @@ "storage_bucket": "tmessages2.appspot.com" }, "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:760348033671:android:f6afd7b67eae3860", + "android_client_info": { + "package_name": "org.telegram.messenger" + } + }, + "oauth_client": [ + { + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyA-t0jLPjUt2FxrA8VPK2EiYHcYcboIR6k" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, { "client_info": { "mobilesdk_app_id": "1:760348033671:android:dc022572c167a16c", @@ -28,7 +57,7 @@ "appinvite_service": { "other_platform_oauth_client": [ { - "client_id": "760348033671-jiv412evc1r36rl4k7vhl1ba83atdmot.apps.googleusercontent.com", + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", "client_type": 3 } ] @@ -37,9 +66,9 @@ }, { "client_info": { - "mobilesdk_app_id": "1:760348033671:android:f6afd7b67eae3860", + "mobilesdk_app_id": "1:760348033671:android:7396e651423888c3f66e22", "android_client_info": { - "package_name": "org.telegram.messenger" + "package_name": "org.telegram.messenger.web" } }, "oauth_client": [ @@ -57,7 +86,7 @@ "appinvite_service": { "other_platform_oauth_client": [ { - "client_id": "760348033671-jiv412evc1r36rl4k7vhl1ba83atdmot.apps.googleusercontent.com", + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", "client_type": 3 } ] @@ -66,4 +95,4 @@ } ], "configuration_version": "1" -} +} \ No newline at end of file diff --git a/TMessagesProj/jni/CMakeLists.txt b/TMessagesProj/jni/CMakeLists.txt index 579b8ec233a..d955668c6cc 100644 --- a/TMessagesProj/jni/CMakeLists.txt +++ b/TMessagesProj/jni/CMakeLists.txt @@ -399,7 +399,7 @@ target_compile_definitions(sqlite PUBLIC #voip include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt) -set(NATIVE_LIB "tmessages.37") +set(NATIVE_LIB "tmessages.38") #tmessages add_library(${NATIVE_LIB} SHARED diff --git a/TMessagesProj/jni/TgNetWrapper.cpp b/TMessagesProj/jni/TgNetWrapper.cpp index 84f9bb4cdbb..aa7c4c933fd 100644 --- a/TMessagesProj/jni/TgNetWrapper.cpp +++ b/TMessagesProj/jni/TgNetWrapper.cpp @@ -371,7 +371,7 @@ void setSystemLangCode(JNIEnv *env, jclass c, jint instanceNum, jstring langCode } } -void init(JNIEnv *env, jclass c, jint instanceNum, jint version, jint layer, jint apiId, jstring deviceModel, jstring systemVersion, jstring appVersion, jstring langCode, jstring systemLangCode, jstring configPath, jstring logPath, jstring regId, jstring cFingerprint, jstring installerId, jint timezoneOffset, jint userId, jboolean enablePushConnection, jboolean hasNetwork, jint networkType) { +void init(JNIEnv *env, jclass c, jint instanceNum, jint version, jint layer, jint apiId, jstring deviceModel, jstring systemVersion, jstring appVersion, jstring langCode, jstring systemLangCode, jstring configPath, jstring logPath, jstring regId, jstring cFingerprint, jstring installerId, jstring packageId, jint timezoneOffset, jint userId, jboolean enablePushConnection, jboolean hasNetwork, jint networkType) { const char *deviceModelStr = env->GetStringUTFChars(deviceModel, 0); const char *systemVersionStr = env->GetStringUTFChars(systemVersion, 0); const char *appVersionStr = env->GetStringUTFChars(appVersion, 0); @@ -382,8 +382,9 @@ void init(JNIEnv *env, jclass c, jint instanceNum, jint version, jint layer, jin const char *regIdStr = env->GetStringUTFChars(regId, 0); const char *cFingerprintStr = env->GetStringUTFChars(cFingerprint, 0); const char *installerIdStr = env->GetStringUTFChars(installerId, 0); + const char *packageIdStr = env->GetStringUTFChars(packageId, 0); - ConnectionsManager::getInstance(instanceNum).init((uint32_t) version, layer, apiId, std::string(deviceModelStr), std::string(systemVersionStr), std::string(appVersionStr), std::string(langCodeStr), std::string(systemLangCodeStr), std::string(configPathStr), std::string(logPathStr), std::string(regIdStr), std::string(cFingerprintStr), std::string(installerIdStr), timezoneOffset, userId, true, enablePushConnection, hasNetwork, networkType); + ConnectionsManager::getInstance(instanceNum).init((uint32_t) version, layer, apiId, std::string(deviceModelStr), std::string(systemVersionStr), std::string(appVersionStr), std::string(langCodeStr), std::string(systemLangCodeStr), std::string(configPathStr), std::string(logPathStr), std::string(regIdStr), std::string(cFingerprintStr), std::string(installerIdStr), std::string(packageIdStr), timezoneOffset, userId, true, enablePushConnection, hasNetwork, networkType); if (deviceModelStr != 0) { env->ReleaseStringUTFChars(deviceModel, deviceModelStr); @@ -415,6 +416,9 @@ void init(JNIEnv *env, jclass c, jint instanceNum, jint version, jint layer, jin if (installerIdStr != 0) { env->ReleaseStringUTFChars(installerId, installerIdStr); } + if (packageIdStr != 0) { + env->ReleaseStringUTFChars(packageId, packageIdStr); + } } void setJava(JNIEnv *env, jclass c, jboolean useJavaByteBuffers) { @@ -440,7 +444,7 @@ static JNINativeMethod ConnectionsManagerMethods[] = { {"native_setProxySettings", "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", (void *) setProxySettings}, {"native_getConnectionState", "(I)I", (void *) getConnectionState}, {"native_setUserId", "(II)V", (void *) setUserId}, - {"native_init", "(IIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIZZI)V", (void *) init}, + {"native_init", "(IIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIZZI)V", (void *) init}, {"native_setLangCode", "(ILjava/lang/String;)V", (void *) setLangCode}, {"native_setRegId", "(ILjava/lang/String;)V", (void *) setRegId}, {"native_setSystemLangCode", "(ILjava/lang/String;)V", (void *) setSystemLangCode}, diff --git a/TMessagesProj/jni/tgnet/ApiScheme.cpp b/TMessagesProj/jni/tgnet/ApiScheme.cpp index 62c23955a85..e638324f997 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.cpp +++ b/TMessagesProj/jni/tgnet/ApiScheme.cpp @@ -1172,7 +1172,7 @@ UserProfilePhoto *UserProfilePhoto::TLdeserialize(NativeByteBuffer *stream, uint case 0x4f11bae1: result = new TL_userProfilePhotoEmpty(); break; - case 0x69d3ab26: + case 0xcc656077: result = new TL_userProfilePhoto(); break; default: @@ -1194,6 +1194,9 @@ void TL_userProfilePhoto::readParams(NativeByteBuffer *stream, int32_t instanceN photo_id = stream->readInt64(&error); photo_small = std::unique_ptr(FileLocation::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error)); photo_big = std::unique_ptr(FileLocation::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error)); + if ((flags & 2) != 0) { + stripped_thumb = std::unique_ptr(stream->readByteArray(&error)); + } dc_id = stream->readInt32(&error); } @@ -1204,6 +1207,9 @@ void TL_userProfilePhoto::serializeToStream(NativeByteBuffer *stream) { stream->writeInt64(photo_id); photo_small->serializeToStream(stream); photo_big->serializeToStream(stream); + if ((flags & 2) != 0) { + stream->writeByteArray(stripped_thumb.get()); + } stream->writeInt32(dc_id); } diff --git a/TMessagesProj/jni/tgnet/ApiScheme.h b/TMessagesProj/jni/tgnet/ApiScheme.h index 330579d37d6..132441805a6 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.h +++ b/TMessagesProj/jni/tgnet/ApiScheme.h @@ -257,6 +257,7 @@ class UserProfilePhoto : public TLObject { int64_t photo_id; std::unique_ptr photo_small; std::unique_ptr photo_big; + std::unique_ptr stripped_thumb; int32_t dc_id; static UserProfilePhoto *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error); @@ -273,7 +274,7 @@ class TL_userProfilePhotoEmpty : public UserProfilePhoto { class TL_userProfilePhoto : public UserProfilePhoto { public: - static const uint32_t constructor = 0x69d3ab26; + static const uint32_t constructor = 0xcc656077; void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error); void serializeToStream(NativeByteBuffer *stream); diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp index 5a8a92362c5..518c6d17f0e 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -2494,6 +2494,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t if (request->rawRequest->initFunc != nullptr) { request->rawRequest->initFunc(request->messageId); } + if (LOGS_ENABLED) DEBUG_D("messageId for token = %d, 0x%" PRIx64, request->requestToken, request->messageId); uint32_t requestLength = request->rpcRequest->getObjectSize(); if (request->requestFlags & RequestFlagCanCompress) { @@ -2593,8 +2594,8 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t Datacenter *datacenter = getDatacenterWithId(iter->first); if (datacenter != nullptr) { bool scannedPreviousRequests = false; - int64_t lastSentMessageRpcId = 0; bool needQuickAck = false; + int64_t lastSentMessageRpcId = 0; std::vector> &array = iter->second; size_t count = array.size(); for (uint32_t b = 0; b < count; b++) { @@ -2609,13 +2610,18 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t std::vector currentRequests; for (uint32_t a = 0; a < count; a++) { NetworkMessage *currentNetworkMessage = array[a].get(); - TL_message *currentMessage = currentNetworkMessage->message.get(); if (currentNetworkMessage->invokeAfter) { - currentRequests.push_back(currentMessage->msg_id); + currentRequests.push_back(currentNetworkMessage->message->msg_id); } } int64_t maxRequestId = 0; + if (lastInvokeAfterMessageId != 0) { + int64_t timeMessage = (int64_t) (lastInvokeAfterMessageId / 4294967296.0); + if (getCurrentTime() - timeMessage <= 30) { + maxRequestId = lastInvokeAfterMessageId; + } + } for (requestsIter iter2 = runningRequests.begin(); iter2 != runningRequests.end(); iter2++) { Request *request = iter2->get(); if (request->requestFlags & RequestFlagInvokeAfter) { @@ -2634,11 +2640,11 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t TL_invokeAfterMsg *request = new TL_invokeAfterMsg(); request->msg_id = lastSentMessageRpcId; if (message->outgoingBody != nullptr) { - if (LOGS_ENABLED) DEBUG_D("wrap outgoingBody(%p, %s) to TL_invokeAfterMsg", message->outgoingBody, typeid(*message->outgoingBody).name()); + if (LOGS_ENABLED) DEBUG_D("wrap outgoingBody(%p, %s) to TL_invokeAfterMsg, token = %d, after 0x%" PRIx64, message->outgoingBody, typeid(*message->outgoingBody).name(), networkMessage->requestId, request->msg_id); request->outgoingQuery = message->outgoingBody; message->outgoingBody = nullptr; } else { - if (LOGS_ENABLED) DEBUG_D("wrap body(%p, %s) to TL_invokeAfterMsg", message->body.get(), typeid(*(message->body.get())).name()); + if (LOGS_ENABLED) DEBUG_D("wrap body(%p, %s) to TL_invokeAfterMsg, token = %d, after 0x%" PRIx64, message->body.get(), typeid(*(message->body.get())).name(), networkMessage->requestId, request->msg_id); request->query = std::move(message->body); } message->body = std::unique_ptr(request); @@ -2646,6 +2652,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t } lastSentMessageRpcId = message->msg_id; + lastInvokeAfterMessageId = message->msg_id; } } @@ -2764,6 +2771,13 @@ std::unique_ptr ConnectionsManager::wrapInLayer(TLObject *object, Data objectValue->key = "installer"; objectValue->value = std::unique_ptr(jsonString); + objectValue = new TL_jsonObjectValue(); + jsonObject->value.push_back(std::unique_ptr(objectValue)); + jsonString = new TL_jsonString(); + jsonString->value = package; + objectValue->key = "package_id"; + objectValue->value = std::unique_ptr(jsonString); + objectValue = new TL_jsonObjectValue(); jsonObject->value.push_back(std::unique_ptr(objectValue)); @@ -3212,7 +3226,7 @@ void ConnectionsManager::applyDnsConfig(NativeByteBuffer *buffer, std::string ph }); } -void ConnectionsManager::init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string systemLangCode, std::string configPath, std::string logPath, std::string regId, std::string cFingerpting, std::string installerId, int32_t timezoneOffset, int32_t userId, bool isPaused, bool enablePushConnection, bool hasNetwork, int32_t networkType) { +void ConnectionsManager::init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string systemLangCode, std::string configPath, std::string logPath, std::string regId, std::string cFingerpting, std::string installerId, std::string packageId, int32_t timezoneOffset, int32_t userId, bool isPaused, bool enablePushConnection, bool hasNetwork, int32_t networkType) { currentVersion = version; currentLayer = layer; currentApiId = apiId; @@ -3224,6 +3238,7 @@ void ConnectionsManager::init(uint32_t version, int32_t layer, int32_t apiId, st currentRegId = regId; certFingerprint = cFingerpting; installer = installerId; + package = packageId; currentDeviceTimezone = timezoneOffset; currentSystemLangCode = systemLangCode; currentUserId = userId; diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.h b/TMessagesProj/jni/tgnet/ConnectionsManager.h index d44a9d589bc..740e868301c 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.h +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.h @@ -63,7 +63,7 @@ class ConnectionsManager { void pauseNetwork(); void setNetworkAvailable(bool value, int32_t type, bool slow); void setIpStrategy(uint8_t value); - void init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string systemLangCode, std::string configPath, std::string logPath, std::string regId, std::string cFingerprint, std::string installerId, int32_t timezoneOffset, int32_t userId, bool isPaused, bool enablePushConnection, bool hasNetwork, int32_t networkType); + void init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string systemLangCode, std::string configPath, std::string logPath, std::string regId, std::string cFingerprint, std::string installerId, std::string packageId, int32_t timezoneOffset, int32_t userId, bool isPaused, bool enablePushConnection, bool hasNetwork, int32_t networkType); void setProxySettings(std::string address, uint16_t port, std::string username, std::string password, std::string secret); void setLangCode(std::string langCode); void setRegId(std::string regId); @@ -206,6 +206,7 @@ class ConnectionsManager { requestsList runningRequests; std::vector requestingSaltsForDc; int32_t lastPingId = 0; + int64_t lastInvokeAfterMessageId = 0; int32_t currentNetworkType = NETWORK_TYPE_WIFI; uint32_t currentVersion = 1; @@ -218,6 +219,7 @@ class ConnectionsManager { std::string currentRegId; std::string certFingerprint; std::string installer; + std::string package; int32_t currentDeviceTimezone = 0; std::string currentSystemLangCode; std::string currentConfigPath; diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index f0903989223..a25e951b0e2 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -75,8 +75,6 @@ android:name="org.telegram.messenger.ApplicationLoader" android:allowBackup="false" android:hardwareAccelerated="@bool/useHardwareAcceleration" - android:icon="@mipmap/ic_launcher" - android:roundIcon="@mipmap/ic_launcher_round" android:largeHeap="true" android:theme="@style/Theme.TMessages.Start" android:manageSpaceActivity="org.telegram.ui.ExternalActionActivity" diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index d4038df6a55..1b80d906b85 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -49,6 +49,7 @@ import android.provider.Settings; import androidx.core.content.FileProvider; +import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager.widget.ViewPager; @@ -185,6 +186,8 @@ public class AndroidUtilities { private static Paint roundPaint; private static RectF bitmapRect; + public static final RectF rectTmp = new RectF(); + public static Pattern WEB_URL = null; static { @@ -365,6 +368,22 @@ private static class LinkSpec { int end; } + private static Boolean standaloneApp; + public static boolean isStandaloneApp() { + if (standaloneApp == null) { + standaloneApp = "org.telegram.messenger.web".equals(ApplicationLoader.applicationContext.getPackageName()); + } + return standaloneApp; + } + + private static Boolean betaApp; + public static boolean isBetaApp() { + if (betaApp == null) { + betaApp = "org.telegram.messenger.beta".equals(ApplicationLoader.applicationContext.getPackageName()); + } + return betaApp; + } + private static String makeUrl(String url, String[] prefixes, Matcher matcher) { boolean hasPrefix = false; for (int i = 0; i < prefixes.length; i++) { @@ -2477,6 +2496,17 @@ public static String formatDuration(int duration, boolean isLong) { } } + public static String formatFullDuration(int duration) { + int h = duration / 3600; + int m = duration / 60 % 60; + int s = duration % 60; + if (duration < 0) { + return String.format(Locale.US, "-%02d:%02d:%02d", Math.abs(h), Math.abs(m), Math.abs(s)); + } else { + return String.format(Locale.US, "%02d:%02d:%02d", h, m, s); + } + } + public static String formatDurationNoHours(int duration, boolean isLong) { int m = duration / 60; int s = duration % 60; @@ -3666,10 +3696,9 @@ public static void updateViewVisibilityAnimated(View view, boolean show, float s view.setScaleY(1f); } view.setTag(1); - } else { + } else if (!show && view.getTag() != null){ view.animate().setListener(null).cancel(); if (animated) { - view.animate().alpha(1f).scaleY(1f).scaleX(1f).setDuration(150).start(); view.animate().alpha(0).scaleY(scaleFactor).scaleX(scaleFactor).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -3680,6 +3709,13 @@ public void onAnimationEnd(Animator animation) { view.setVisibility(View.GONE); } view.setTag(null); + } else if (!animated) { + view.animate().setListener(null).cancel(); + view.setVisibility(show ? View.VISIBLE : View.GONE); + view.setTag(show ? 1 : null); + view.setAlpha(1f); + view.setScaleX(1f); + view.setScaleY(1f); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index fc2b16a0776..e34e8528fee 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -18,8 +18,8 @@ public class BuildVars { public static boolean LOGS_ENABLED = false; public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; - public static int BUILD_VERSION = 2274; - public static String BUILD_VERSION_STRING = "7.6.0"; + public static int BUILD_VERSION = 2284; + public static String BUILD_VERSION_STRING = "7.7.0"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; public static String APPCENTER_HASH = "a5b5c4f5-51da-dedc-9918-d9766a22ca7c"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index 43512c885f9..571a75a6dee 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -100,7 +100,7 @@ public void setCall(AccountInstance account, int chatId, TLRPC.TL_phone_groupCal loadMembers(true); } - public void addSelfDummyParticipant() { + public void addSelfDummyParticipant(boolean notify) { int selfId = getSelfId(); if (participants.indexOfKey(selfId) >= 0) { return; @@ -109,16 +109,29 @@ public void addSelfDummyParticipant() { selfDummyParticipant.peer = selfPeer; selfDummyParticipant.muted = true; selfDummyParticipant.self = true; - selfDummyParticipant.can_self_unmute = !call.join_muted; - selfDummyParticipant.date = currentAccount.getConnectionsManager().getCurrentTime(); TLRPC.Chat chat = currentAccount.getMessagesController().getChat(chatId); + selfDummyParticipant.can_self_unmute = !call.join_muted || ChatObject.canManageCalls(chat); + selfDummyParticipant.date = currentAccount.getConnectionsManager().getCurrentTime(); if (ChatObject.canManageCalls(chat) || !ChatObject.isChannel(chat) || chat.megagroup || selfDummyParticipant.can_self_unmute) { selfDummyParticipant.active_date = currentAccount.getConnectionsManager().getCurrentTime(); } + if (selfId > 0) { + TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount.getCurrentAccount()).getUserFull(selfId); + if (userFull != null) { + selfDummyParticipant.about = userFull.about; + } + } else { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount.getCurrentAccount()).getChatFull(-selfId); + if (chatFull != null) { + selfDummyParticipant.about = chatFull.about; + } + } participants.put(selfId, selfDummyParticipant); sortedParticipants.add(selfDummyParticipant); sortParticipants(); - currentAccount.getNotificationCenter().postNotificationName(NotificationCenter.groupCallUpdated, chatId, call.id, false); + if (notify) { + currentAccount.getNotificationCenter().postNotificationName(NotificationCenter.groupCallUpdated, chatId, call.id, false); + } } public void migrateToChat(TLRPC.Chat chat) { @@ -129,6 +142,14 @@ public void migrateToChat(TLRPC.Chat chat) { } } + public boolean shouldShowPanel() { + return call.participants_count > 0 || isScheduled(); + } + + public boolean isScheduled() { + return (call.flags & 128) != 0; + } + private int getSelfId() { int selfId; if (selfPeer != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java index 56dc589c400..dbbf415c743 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java @@ -400,7 +400,7 @@ public static int typeToIndex(int type) { if (type == AUTODOWNLOAD_TYPE_PHOTO) { return PRESET_SIZE_NUM_PHOTO; } else if (type == AUTODOWNLOAD_TYPE_AUDIO) { - return PRESET_SIZE_NUM_AUDIO; + return PRESET_SIZE_NUM_DOCUMENT; } else if (type == AUTODOWNLOAD_TYPE_VIDEO) { return PRESET_SIZE_NUM_VIDEO; } else if (type == AUTODOWNLOAD_TYPE_DOCUMENT) { @@ -663,7 +663,12 @@ public int canDownloadMedia(TLRPC.Message message) { preset = getCurrentMobilePreset(); } int mask = preset.mask[index]; - int maxSize = preset.sizes[typeToIndex(type)]; + int maxSize; + if (type == AUTODOWNLOAD_TYPE_AUDIO) { + maxSize = Math.max(512 * 1024, preset.sizes[typeToIndex(type)]); + } else { + maxSize = preset.sizes[typeToIndex(type)]; + } int size = MessageObject.getMessageSize(message); if (isVideo && preset.preloadVideo && size > maxSize && maxSize > 2 * 1024 * 1024) { return (mask & type) != 0 ? 2 : 0; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index 47696f88259..62edaffb845 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -196,7 +196,7 @@ public FileLoadOperation(ImageLocation imageLocation, Object parent, String exte location.id = imageLocation.location.volume_id; location.volume_id = imageLocation.location.volume_id; location.local_id = imageLocation.location.local_id; - location.big = imageLocation.photoPeerBig; + location.big = imageLocation.photoPeerType == ImageLocation.TYPE_BIG; location.peer = imageLocation.photoPeer; } else if (imageLocation.stickerSet != null) { location = new TLRPC.TL_inputStickerSetThumb(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java index 2b42979fc45..e89e5593c60 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java @@ -23,7 +23,7 @@ public class ImageLocation { public TLRPC.PhotoSize photoSize; public TLRPC.Photo photo; - public boolean photoPeerBig; + public int photoPeerType; public TLRPC.InputPeer photoPeer; public TLRPC.InputStickerSet stickerSet; public int imageType; @@ -99,14 +99,37 @@ public static ImageLocation getForPhoto(TLRPC.PhotoSize photoSize, TLRPC.Photo p } else { dc_id = photoSize.location.dc_id; } - return getForPhoto(photoSize.location, photoSize.size, photo, null, null, false, dc_id, null, photoSize.type); + return getForPhoto(photoSize.location, photoSize.size, photo, null, null, TYPE_SMALL, dc_id, null, photoSize.type); } - public static ImageLocation getForUser(TLRPC.User user, boolean big) { + public static final int TYPE_BIG = 0; + public static final int TYPE_SMALL = 1; + public static final int TYPE_STRIPPED = 2; + + public static ImageLocation getForUserOrChat(TLObject object, int type) { + if (object instanceof TLRPC.User) { + return getForUser((TLRPC.User) object, type); + } else if (object instanceof TLRPC.Chat) { + return getForChat((TLRPC.Chat) object, type); + } + return null; + } + + public static ImageLocation getForUser(TLRPC.User user, int type) { if (user == null || user.access_hash == 0 || user.photo == null) { return null; } - TLRPC.FileLocation fileLocation = big ? user.photo.photo_big : user.photo.photo_small; + if (type == TYPE_STRIPPED) { + if (user.photo.stripped_thumb == null) { + return null; + } + ImageLocation imageLocation = new ImageLocation(); + imageLocation.photoSize = new TLRPC.TL_photoStrippedSize(); + imageLocation.photoSize.type = "s"; + imageLocation.photoSize.bytes = user.photo.stripped_thumb; + return imageLocation; + } + TLRPC.FileLocation fileLocation = type == TYPE_BIG ? user.photo.photo_big : user.photo.photo_small; if (fileLocation == null) { return null; } @@ -119,14 +142,24 @@ public static ImageLocation getForUser(TLRPC.User user, boolean big) { } else { dc_id = fileLocation.dc_id; } - return getForPhoto(fileLocation, 0, null, null, inputPeer, big, dc_id, null, null); + return getForPhoto(fileLocation, 0, null, null, inputPeer, type, dc_id, null, null); } - public static ImageLocation getForChat(TLRPC.Chat chat, boolean big) { + public static ImageLocation getForChat(TLRPC.Chat chat, int type) { if (chat == null || chat.photo == null) { return null; } - TLRPC.FileLocation fileLocation = big ? chat.photo.photo_big : chat.photo.photo_small; + if (type == TYPE_STRIPPED) { + if (chat.photo.stripped_thumb == null) { + return null; + } + ImageLocation imageLocation = new ImageLocation(); + imageLocation.photoSize = new TLRPC.TL_photoStrippedSize(); + imageLocation.photoSize.type = "s"; + imageLocation.photoSize.bytes = chat.photo.stripped_thumb; + return imageLocation; + } + TLRPC.FileLocation fileLocation = type == TYPE_BIG ? chat.photo.photo_big : chat.photo.photo_small; if (fileLocation == null) { return null; } @@ -148,7 +181,7 @@ public static ImageLocation getForChat(TLRPC.Chat chat, boolean big) { } else { dc_id = fileLocation.dc_id; } - return getForPhoto(fileLocation, 0, null, null, inputPeer, big, dc_id, null, null); + return getForPhoto(fileLocation, 0, null, null, inputPeer, type, dc_id, null, null); } public static ImageLocation getForSticker(TLRPC.PhotoSize photoSize, TLRPC.Document sticker) { @@ -163,7 +196,7 @@ public static ImageLocation getForSticker(TLRPC.PhotoSize photoSize, TLRPC.Docum if (stickerSet == null) { return null; } - ImageLocation imageLocation = getForPhoto(photoSize.location, photoSize.size, null, null, null, false, sticker.dc_id, stickerSet, photoSize.type); + ImageLocation imageLocation = getForPhoto(photoSize.location, photoSize.size, null, null, null, TYPE_SMALL, sticker.dc_id, stickerSet, photoSize.type); if (MessageObject.isAnimatedStickerDocument(sticker, true)) { imageLocation.imageType = FileLoader.IMAGE_TYPE_LOTTIE; } @@ -174,7 +207,7 @@ public static ImageLocation getForDocument(TLRPC.VideoSize videoSize, TLRPC.Docu if (videoSize == null || document == null) { return null; } - ImageLocation location = getForPhoto(videoSize.location, videoSize.size, null, document, null, false, document.dc_id, null, videoSize.type); + ImageLocation location = getForPhoto(videoSize.location, videoSize.size, null, document, null, TYPE_SMALL, document.dc_id, null, videoSize.type); location.imageType = FileLoader.IMAGE_TYPE_ANIMATION; return location; } @@ -183,7 +216,7 @@ public static ImageLocation getForPhoto(TLRPC.VideoSize videoSize, TLRPC.Photo p if (videoSize == null || photo == null) { return null; } - ImageLocation location = getForPhoto(videoSize.location, videoSize.size, photo, null, null, false, photo.dc_id, null, videoSize.type); + ImageLocation location = getForPhoto(videoSize.location, videoSize.size, photo, null, null, TYPE_SMALL, photo.dc_id, null, videoSize.type); location.imageType = FileLoader.IMAGE_TYPE_ANIMATION; if ((videoSize.flags & 1) != 0) { location.videoSeekTo = (int) (videoSize.video_start_ts * 1000); @@ -199,7 +232,7 @@ public static ImageLocation getForDocument(TLRPC.PhotoSize photoSize, TLRPC.Docu } else if (photoSize == null || document == null) { return null; } - return getForPhoto(photoSize.location, photoSize.size, null, document, null, false, document.dc_id, null, photoSize.type); + return getForPhoto(photoSize.location, photoSize.size, null, document, null, TYPE_SMALL, document.dc_id, null, photoSize.type); } public static ImageLocation getForLocal(TLRPC.FileLocation location) { @@ -215,7 +248,7 @@ public static ImageLocation getForLocal(TLRPC.FileLocation location) { return imageLocation; } - private static ImageLocation getForPhoto(TLRPC.FileLocation location, int size, TLRPC.Photo photo, TLRPC.Document document, TLRPC.InputPeer photoPeer, boolean photoPeerBig, int dc_id, TLRPC.InputStickerSet stickerSet, String thumbSize) { + private static ImageLocation getForPhoto(TLRPC.FileLocation location, int size, TLRPC.Photo photo, TLRPC.Document document, TLRPC.InputPeer photoPeer, int photoPeerType, int dc_id, TLRPC.InputStickerSet stickerSet, String thumbSize) { if (location == null || photo == null && photoPeer == null && stickerSet == null && document == null) { return null; } @@ -224,7 +257,7 @@ private static ImageLocation getForPhoto(TLRPC.FileLocation location, int size, imageLocation.photo = photo; imageLocation.currentSize = size; imageLocation.photoPeer = photoPeer; - imageLocation.photoPeerBig = photoPeerBig; + imageLocation.photoPeerType = photoPeerType; imageLocation.stickerSet = stickerSet; if (location instanceof TLRPC.TL_fileLocationToBeDeprecated) { imageLocation.location = (TLRPC.TL_fileLocationToBeDeprecated) location; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index c5ce9f6dbce..bee51b37fad 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -313,6 +313,10 @@ public void setImage(ImageLocation imageLocation, String imageFilter, ImageLocat setImage(imageLocation, imageFilter, thumbLocation, thumbFilter, null, size, ext, parentObject, cacheType); } + public void setImage(ImageLocation fileLocation, String fileFilter, ImageLocation thumbLocation, String thumbFilter, Drawable thumb, Object parentObject, int cacheType) { + setImage(null, null, fileLocation, fileFilter, thumbLocation, thumbFilter, thumb, 0, null, parentObject, cacheType); + } + public void setImage(ImageLocation fileLocation, String fileFilter, ImageLocation thumbLocation, String thumbFilter, Drawable thumb, int size, String ext, Object parentObject, int cacheType) { setImage(null, null, fileLocation, fileFilter, thumbLocation, thumbFilter, thumb, size, ext, parentObject, cacheType); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index 3add96e88d3..c59af7456c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -65,7 +65,7 @@ public class LocaleController { public FastDateFormat formatterScheduleDay; public FastDateFormat formatterScheduleYear; public FastDateFormat formatterMonthYear; - public FastDateFormat[] formatterScheduleSend = new FastDateFormat[6]; + public FastDateFormat[] formatterScheduleSend = new FastDateFormat[15]; private HashMap allRules = new HashMap<>(); @@ -1087,7 +1087,53 @@ public static String formatTTLString(int ttl) { } } + private static char[] defaultNumbers = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + private static char[][] otherNumbers = new char[][]{ + {'٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'}, + {'۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'}, + {'०', '१', '२', '३', '४', '५', '६', '७', '८', '९'}, + {'૦', '૧', '૨', '૩', '૪', '૫', '૬', '૭', '૮', '૯'}, + {'੦', '੧', '੨', '੩', '੪', '੫', '੬', '੭', '੮', '੯'}, + {'০', '১', '২', '৩', '৪', '৫', '৬', '৭', '৮', '৯'}, + {'೦', '೧', '೨', '೩', '೪', '೫', '೬', '೭', '೮', '೯'}, + {'୦', '୧', '୨', '୩', '୪', '୫', '୬', '୭', '୮', '୯'}, + {'൦', '൧', '൨', '൩', '൪', '൫', '൬', '൭', '൮', '൯'}, + {'௦', '௧', '௨', '௩', '௪', '௫', '௬', '௭', '௮', '௯'}, + {'౦', '౧', '౨', '౩', '౪', '౫', '౬', '౭', '౮', '౯'}, + {'၀', '၁', '၂', '၃', '၄', '၅', '၆', '၇', '၈', '၉'}, + {'༠', '༡', '༢', '༣', '༤', '༥', '༦', '༧', '༨', '༩'}, + {'᠐', '᠑', '᠒', '᠓', '᠔', '᠕', '᠖', '᠗', '᠘', '᠙'}, + {'០', '១', '២', '៣', '៤', '៥', '៦', '៧', '៨', '៩'}, + {'๐', '๑', '๒', '๓', '๔', '๕', '๖', '๗', '๘', '๙'}, + {'໐', '໑', '໒', '໓', '໔', '໕', '໖', '໗', '໘', '໙'}, + {'꧐', '꧑', '꧒', '꧓', '꧔', '꧕', '꧖', '꧗', '꧘', '꧙'} + }; + + public static String fixNumbers(CharSequence numbers) { + StringBuilder builder = new StringBuilder(numbers); + for (int c = 0, N = builder.length(); c < N; c++) { + char ch = builder.charAt(c); + if (ch >= '0' && ch <= '9' || ch == '.' || ch == ',') { + continue; + } + for (int a = 0; a < otherNumbers.length; a++) { + for (int b = 0; b < otherNumbers[a].length; b++) { + if (ch == otherNumbers[a][b]) { + builder.setCharAt(c, defaultNumbers[b]); + a = otherNumbers.length; + break; + } + } + } + } + return builder.toString(); + } + public String formatCurrencyString(long amount, String type) { + return formatCurrencyString(amount, true, type); + } + + public String formatCurrencyString(long amount, boolean fixAnything, String type) { type = type.toUpperCase(); String customFormat; double doubleAmount; @@ -1102,7 +1148,7 @@ public String formatCurrencyString(long amount, String type) { case "IRR": doubleAmount = amount / 100.0f; - if (amount % 100 == 0) { + if (fixAnything && amount % 100 == 0) { customFormat = " %.0f"; } else { customFormat = " %.2f"; @@ -1158,7 +1204,7 @@ public String formatCurrencyString(long amount, String type) { if (currency != null) { NumberFormat format = NumberFormat.getCurrencyInstance(currentLocale != null ? currentLocale : systemDefaultLocale); format.setCurrency(currency); - if (type.equals("IRR")) { + if (fixAnything && type.equals("IRR")) { format.setMaximumFractionDigits(0); } return (discount ? "-" : "") + format.format(doubleAmount); @@ -1166,6 +1212,46 @@ public String formatCurrencyString(long amount, String type) { return (discount ? "-" : "") + String.format(Locale.US, type + customFormat, doubleAmount); } + public static int getCurrencyExpDivider(String type) { + switch (type) { + case "CLF": + return 10000; + case "BHD": + case "IQD": + case "JOD": + case "KWD": + case "LYD": + case "OMR": + case "TND": + return 1000; + case "BIF": + case "BYR": + case "CLP": + case "CVE": + case "DJF": + case "GNF": + case "ISK": + case "JPY": + case "KMF": + case "KRW": + case "MGA": + case "PYG": + case "RWF": + case "UGX": + case "UYI": + case "VND": + case "VUV": + case "XAF": + case "XOF": + case "XPF": + return 1; + case "MRO": + return 10; + default: + return 100; + } + } + public String formatCurrencyDecimalString(long amount, String type, boolean inludeType) { type = type.toUpperCase(); String customFormat; @@ -1559,12 +1645,57 @@ public void recreateFormatters() { formatterScheduleSend[3] = createFormatter(locale, getStringInternal("RemindTodayAt", R.string.RemindTodayAt), "'Remind today at' HH:mm"); formatterScheduleSend[4] = createFormatter(locale, getStringInternal("RemindDayAt", R.string.RemindDayAt), "'Remind on' MMM d 'at' HH:mm"); formatterScheduleSend[5] = createFormatter(locale, getStringInternal("RemindDayYearAt", R.string.RemindDayYearAt), "'Remind on' MMM d yyyy 'at' HH:mm"); + formatterScheduleSend[6] = createFormatter(locale, getStringInternal("StartTodayAt", R.string.StartTodayAt), "'Start today at' HH:mm"); + formatterScheduleSend[7] = createFormatter(locale, getStringInternal("StartDayAt", R.string.StartDayAt), "'Start on' MMM d 'at' HH:mm"); + formatterScheduleSend[8] = createFormatter(locale, getStringInternal("StartDayYearAt", R.string.StartDayYearAt), "'Start on' MMM d yyyy 'at' HH:mm"); + formatterScheduleSend[9] = createFormatter(locale, getStringInternal("StartShortTodayAt", R.string.StartShortTodayAt), "'Today,' HH:mm"); + formatterScheduleSend[10] = createFormatter(locale, getStringInternal("StartShortDayAt", R.string.StartShortDayAt), "MMM d',' HH:mm"); + formatterScheduleSend[11] = createFormatter(locale, getStringInternal("StartShortDayYearAt", R.string.StartShortDayYearAt), "MMM d yyyy, HH:mm"); + formatterScheduleSend[12] = createFormatter(locale, getStringInternal("StartsTodayAt", R.string.StartsTodayAt), "'Starts today at' HH:mm"); + formatterScheduleSend[13] = createFormatter(locale, getStringInternal("StartsDayAt", R.string.StartsDayAt), "'Starts on' MMM d 'at' HH:mm"); + formatterScheduleSend[14] = createFormatter(locale, getStringInternal("StartsDayYearAt", R.string.StartsDayYearAt), "'Starts on' MMM d yyyy 'at' HH:mm"); } public static boolean isRTLCharacter(char ch) { return Character.getDirectionality(ch) == Character.DIRECTIONALITY_RIGHT_TO_LEFT || Character.getDirectionality(ch) == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC || Character.getDirectionality(ch) == Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING || Character.getDirectionality(ch) == Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE; } + public static String formatStartsTime(long date, int type) { + return formatStartsTime(date, type, true); + } + + public static String formatStartsTime(long date, int type, boolean needToday) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + int currentYear = calendar.get(Calendar.YEAR); + int currentDay = calendar.get(Calendar.DAY_OF_YEAR); + + calendar.setTimeInMillis(date * 1000); + int selectedYear = calendar.get(Calendar.YEAR); + int selectedDay = calendar.get(Calendar.DAY_OF_YEAR); + + int num; + if (currentYear == selectedYear) { + if (needToday && selectedDay == currentDay) { + num = 0; + } else { + num = 1; + } + } else { + num = 2; + } + if (type == 1) { + num += 3; + } else if (type == 2) { + num += 6; + } else if (type == 3) { + num += 9; + } else if (type == 4) { + num += 12; + } + return LocaleController.getInstance().formatterScheduleSend[num].format(calendar.getTimeInMillis()); + } + public static String formatSectionDate(long date) { try { date *= 1000; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index acd7aa99c03..b7ebe403238 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -883,7 +883,7 @@ public MediaController() { } proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); PowerManager powerManager = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); - proximityWakeLock = powerManager.newWakeLock(0x00000020, "proximity"); + proximityWakeLock = powerManager.newWakeLock(0x00000020, "telegram:proximity_lock"); } catch (Exception e) { FileLog.e(e); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 4dfe444a5ec..f164f841e08 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -144,6 +144,8 @@ public MediaDataController(int num) { public static final int TYPE_FEATURED = 3; public static final int TYPE_EMOJI = 4; + public static final int TYPE_GREETINGS = 3; + private ArrayList[] stickerSets = new ArrayList[]{new ArrayList<>(), new ArrayList<>(), new ArrayList<>(0), new ArrayList<>(), new ArrayList<>()}; private LongSparseArray[] stickersByIds = new LongSparseArray[]{new LongSparseArray<>(), new LongSparseArray<>(), new LongSparseArray<>(), new LongSparseArray<>(), new LongSparseArray<>()}; private LongSparseArray stickerSetsById = new LongSparseArray<>(); @@ -168,9 +170,9 @@ public MediaDataController(int num) { private HashMap> allStickers = new HashMap<>(); private HashMap> allStickersFeatured = new HashMap<>(); - private ArrayList[] recentStickers = new ArrayList[]{new ArrayList<>(), new ArrayList<>(), new ArrayList<>()}; - private boolean[] loadingRecentStickers = new boolean[3]; - private boolean[] recentStickersLoaded = new boolean[3]; + private ArrayList[] recentStickers = new ArrayList[]{new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()}; + private boolean[] loadingRecentStickers = new boolean[4]; + private boolean[] recentStickersLoaded = new boolean[4]; private ArrayList recentGifs = new ArrayList<>(); private boolean loadingRecentGifs; @@ -185,8 +187,10 @@ public MediaDataController(int num) { private boolean loadingFeaturedStickers; private boolean featuredStickersLoaded; + private TLRPC.Document greetingsSticker; + public void cleanup() { - for (int a = 0; a < 3; a++) { + for (int a = 0; a < recentStickers.length; a++) { recentStickers[a].clear(); loadingRecentStickers[a] = false; recentStickersLoaded[a] = false; @@ -283,7 +287,7 @@ public boolean isStickerInFavorites(TLRPC.Document document) { } public void addRecentSticker(final int type, Object parentObject, TLRPC.Document document, int date, boolean remove) { - if (!MessageObject.isStickerDocument(document) && !MessageObject.isAnimatedStickerDocument(document, true)) { + if (type == TYPE_GREETINGS || !MessageObject.isStickerDocument(document) && !MessageObject.isAnimatedStickerDocument(document, true)) { return; } boolean found = false; @@ -749,6 +753,8 @@ public void loadRecents(final int type, final boolean gif, boolean cache, boolea cacheType = 3; } else if (type == TYPE_MASK) { cacheType = 4; + } else if (type == TYPE_GREETINGS) { + cacheType = 6; } else { cacheType = 5; } @@ -777,6 +783,9 @@ public void loadRecents(final int type, final boolean gif, boolean cache, boolea loadingRecentStickers[type] = false; recentStickersLoaded[type] = true; } + if (type == TYPE_GREETINGS) { + preloadNextGreetingsSticker(); + } getNotificationCenter().postNotificationName(NotificationCenter.recentDocumentsDidLoad, gif, type); loadRecents(type, gif, false, false); }); @@ -794,6 +803,8 @@ public void loadRecents(final int type, final boolean gif, boolean cache, boolea lastLoadTime = preferences.getLong("lastStickersLoadTime", 0); } else if (type == TYPE_MASK) { lastLoadTime = preferences.getLong("lastStickersLoadTimeMask", 0); + } else if (type == TYPE_GREETINGS) { + lastLoadTime = preferences.getLong("lastStickersLoadTimeGreet", 0); } else { lastLoadTime = preferences.getLong("lastStickersLoadTimeFavs", 0); } @@ -823,6 +834,11 @@ public void loadRecents(final int type, final boolean gif, boolean cache, boolea TLRPC.TL_messages_getFavedStickers req = new TLRPC.TL_messages_getFavedStickers(); req.hash = calcDocumentsHash(recentStickers[type]); request = req; + } else if (type == TYPE_GREETINGS) { + TLRPC.TL_messages_getStickers req = new TLRPC.TL_messages_getStickers(); + req.emoticon = "\uD83D\uDC4B" + Emoji.fixEmoji("⭐"); + req.hash = calcDocumentsHash(recentStickers[type]); + request = req; } else { TLRPC.TL_messages_getRecentStickers req = new TLRPC.TL_messages_getRecentStickers(); req.hash = calcDocumentsHash(recentStickers[type]); @@ -831,7 +847,12 @@ public void loadRecents(final int type, final boolean gif, boolean cache, boolea } getConnectionsManager().sendRequest(request, (response, error) -> { ArrayList arrayList = null; - if (type == TYPE_FAVE) { + if (type == TYPE_GREETINGS) { + if (response instanceof TLRPC.TL_messages_stickers) { + TLRPC.TL_messages_stickers res = (TLRPC.TL_messages_stickers) response; + arrayList = res.stickers; + } + } else if (type == TYPE_FAVE) { if (response instanceof TLRPC.TL_messages_favedStickers) { TLRPC.TL_messages_favedStickers res = (TLRPC.TL_messages_favedStickers) response; arrayList = res.stickers; @@ -842,12 +863,26 @@ public void loadRecents(final int type, final boolean gif, boolean cache, boolea arrayList = res.stickers; } } - processLoadedRecentDocuments(type, arrayList, gif, 0, true); + processLoadedRecentDocuments(type, arrayList, false, 0, true); }); } } } + private void preloadNextGreetingsSticker() { + if (recentStickers[TYPE_GREETINGS].isEmpty()) { + return; + } + greetingsSticker = recentStickers[TYPE_GREETINGS].get(Utilities.random.nextInt(recentStickers[TYPE_GREETINGS].size())); + getFileLoader().loadFile(ImageLocation.getForDocument(greetingsSticker), greetingsSticker, null, 0, 1); + } + + public TLRPC.Document getGreetingsSticker() { + TLRPC.Document result = greetingsSticker; + preloadNextGreetingsSticker(); + return result; + } + protected void processLoadedRecentDocuments(final int type, final ArrayList documents, final boolean gif, final int date, boolean replace) { if (documents != null) { getMessagesStorage().getStorageQueue().postRunnable(() -> { @@ -857,7 +892,9 @@ protected void processLoadedRecentDocuments(final int type, final ArrayList users, AbstractM if (messageOwner instanceof TLRPC.TL_messageService) { if (messageOwner.action != null) { - if (messageOwner.action instanceof TLRPC.TL_messageActionGroupCall) { + if (messageOwner.action instanceof TLRPC.TL_messageActionGroupCallScheduled) { + TLRPC.TL_messageActionGroupCallScheduled action = (TLRPC.TL_messageActionGroupCallScheduled) messageOwner.action; + messageText = LocaleController.formatString("ActionGroupCallScheduled", R.string.ActionGroupCallScheduled, LocaleController.formatStartsTime(action.schedule_date, 3, false)); + } else if (messageOwner.action instanceof TLRPC.TL_messageActionGroupCall) { if (messageOwner.action.duration != 0) { String time; int days = messageOwner.action.duration / (3600 * 24); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 2850da41d41..3f5acd00885 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -313,9 +313,6 @@ public class MessagesController extends BaseController implements NotificationCe public volatile boolean ignoreSetOnline; - private ArrayList preloadedStickers = new ArrayList<>(); - private boolean preloadingSticker; - public static class FaqSearchResult { public String title; @@ -2390,7 +2387,7 @@ public void cleanup() { editor = emojiPreferences.edit(); editor.putLong("lastGifLoadTime", 0).putLong("lastStickersLoadTime", 0).putLong("lastStickersLoadTimeMask", 0).putLong("lastStickersLoadTimeFavs", 0).commit(); editor = mainPreferences.edit(); - editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("soundHint").remove("dcDomainName2").remove("webFileDatacenterId").remove("themehint").remove("showFiltersTooltip").commit(); + editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("reminderhint").remove("soundHint").remove("dcDomainName2").remove("webFileDatacenterId").remove("themehint").remove("showFiltersTooltip").commit(); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("shortcut_widget", Activity.MODE_PRIVATE); SharedPreferences.Editor widgetEditor = null; @@ -3006,6 +3003,9 @@ public ChatObject.Call getGroupCall(int chatId, boolean load, Runnable onLoad) { })); } } + if (result != null && result.call instanceof TLRPC.TL_groupCallDiscarded) { + return null; + } return result; } @@ -8885,14 +8885,11 @@ public void toogleChannelInvitesHistory(int chat_id, boolean enabled) { } public void updateChatAbout(int chat_id, final String about, final TLRPC.ChatFull info) { - if (info == null) { - return; - } TLRPC.TL_messages_editChatAbout req = new TLRPC.TL_messages_editChatAbout(); req.peer = getInputPeer(-chat_id); req.about = about; getConnectionsManager().sendRequest(req, (response, error) -> { - if (response instanceof TLRPC.TL_boolTrue) { + if (response instanceof TLRPC.TL_boolTrue && info != null) { AndroidUtilities.runOnUIThread(() -> { info.about = about; getMessagesStorage().updateChatInfo(info, false); @@ -9141,7 +9138,7 @@ public void changeChatTitle(int chat_id, String title) { } } - public void changeChatAvatar(int chat_id, TLRPC.TL_inputChatPhoto oldPhoto, TLRPC.InputFile inputPhoto, final TLRPC.InputFile inputVideo, double videoStartTimestamp, String videoPath, TLRPC.FileLocation smallSize, TLRPC.FileLocation bigSize) { + public void changeChatAvatar(int chat_id, TLRPC.TL_inputChatPhoto oldPhoto, TLRPC.InputFile inputPhoto, final TLRPC.InputFile inputVideo, double videoStartTimestamp, String videoPath, TLRPC.FileLocation smallSize, TLRPC.FileLocation bigSize, Runnable callback) { TLObject request; TLRPC.InputChatPhoto inputChatPhoto; if (oldPhoto != null) { @@ -9221,7 +9218,12 @@ public void changeChatAvatar(int chat_id, TLRPC.TL_inputChatPhoto oldPhoto, TLRP } } processUpdates(updates, false); - AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_AVATAR)); + AndroidUtilities.runOnUIThread(() -> { + if (callback != null) { + callback.run(); + } + getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_AVATAR); + }); }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -13977,7 +13979,7 @@ public static String getRestrictionReason(ArrayList } for (int a = 0, N = reasons.size(); a < N; a++) { TLRPC.TL_restrictionReason reason = reasons.get(a); - if ("all".equals(reason.platform) || "android".equals(reason.platform)) { + if ("all".equals(reason.platform) || !AndroidUtilities.isStandaloneApp() && !AndroidUtilities.isBetaApp() && "android".equals(reason.platform)) { return reason.text; } } @@ -14238,9 +14240,6 @@ public void didReceivedNotification(int id, int account, Object... args) { if (callback != null) { callback.onMessagesLoaded(isCache); } - if (lower_part > 0 && size == 0) { - preloadGreetingsSticker(); - } } } else if (id == NotificationCenter.loadingMessagesFailed && (Integer) args[0] == classGuid) { getNotificationCenter().removeObserver(this, NotificationCenter.messagesDidLoadWithoutProcess); @@ -14263,34 +14262,6 @@ public void didReceivedNotification(int id, int account, Object... args) { } } - public void preloadGreetingsSticker() { - if (preloadingSticker) { - return; - } - preloadingSticker = true; - TLRPC.TL_messages_getStickers req = new TLRPC.TL_messages_getStickers(); - req.emoticon = "\uD83D\uDC4B" + Emoji.fixEmoji("⭐"); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - if (response instanceof TLRPC.TL_messages_stickers) { - ArrayList list = ((TLRPC.TL_messages_stickers) response).stickers; - if (!list.isEmpty()) { - AndroidUtilities.runOnUIThread(() -> { - for (int i = 0; i < list.size(); i++) { - TLRPC.Document sticker = list.get(i); - FileLoader.getInstance(currentAccount).loadFile(ImageLocation.getForDocument(sticker), sticker, null, 0, 1); - preloadedStickers.add(sticker); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.greetingsStickerLoaded); - }); - } - } - }); - } - - public TLRPC.Document getPreloadedSticker() { - return !preloadedStickers.isEmpty() ? preloadedStickers.get(Utilities.random.nextInt(preloadedStickers.size())) : null; - } - public interface MessagesLoadedCallback { void onMessagesLoaded(boolean fromCache); void onError(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index 027d952bcd6..effd951142c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -6562,6 +6562,7 @@ public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count } int minId = Integer.MAX_VALUE; int maxId = Integer.MIN_VALUE; + ArrayList messageIdsToFix = null; if (cursor != null) { while (cursor.next()) { messagesCount++; @@ -6572,7 +6573,14 @@ public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count if (data != null) { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); message.send_state = cursor.intValue(2); - message.id = cursor.intValue(3); + long fullMid = cursor.longValue(3); + message.id = (int) fullMid; + if ((fullMid & 0xffffffff00000000L) == 0xffffffff00000000L && message.id > 0) { + if (messageIdsToFix == null) { + messageIdsToFix = new ArrayList<>(); + } + messageIdsToFix.add(fullMid); + } if (message.id > 0 && message.send_state != 0 && message.send_state != 3) { message.send_state = 0; } @@ -6678,6 +6686,18 @@ public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count } cursor.dispose(); } + if (messageIdsToFix != null) { //TODO remove later + SQLitePreparedStatement state = database.executeFast("UPDATE messages SET mid = ? WHERE mid = ?"); + for (int a = 0, N = messageIdsToFix.size(); a < N; a++) { + long id = messageIdsToFix.get(a); + state.requery(); + state.bindLong(1, (int) id); + state.bindLong(2, id); + state.step(); + } + state.dispose(); + } + Collections.sort(res.messages, (lhs, rhs) -> { if (lhs.id > 0 && rhs.id > 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java index 80cba148684..03c91b1ad27 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java @@ -22,7 +22,7 @@ public class NativeLoader { - private final static int LIB_VERSION = 37; + private final static int LIB_VERSION = 38; private final static String LIB_NAME = "tmessages." + LIB_VERSION; private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so"; private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 0327aa6f2d2..436821059b3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -213,7 +213,6 @@ public class NotificationCenter { public static final int webRtcMicAmplitudeEvent = totalEvents++; public static final int webRtcSpeakerAmplitudeEvent = totalEvents++; public static final int showBulletin = totalEvents++; - public static final int greetingsStickerLoaded = totalEvents++; private SparseArray> observers = new SparseArray<>(); private SparseArray> removeAfterBroadcast = new SparseArray<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index 036581e2ac1..dface0ef338 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -1404,6 +1404,8 @@ private String getShortStringForMessage(MessageObject messageObject, String[] us } } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGroupCall) { return LocaleController.formatString("NotificationGroupCreatedCall", R.string.NotificationGroupCreatedCall, name, chat.title); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGroupCallScheduled) { + return messageObject.messageText.toString(); } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionInviteToGroupCall) { int singleUserId = messageObject.messageOwner.action.user_id; if (singleUserId == 0 && messageObject.messageOwner.action.users.size() == 1) { @@ -2023,6 +2025,8 @@ private String getStringForMessage(MessageObject messageObject, boolean shortMes } } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGroupCall) { msg = LocaleController.formatString("NotificationGroupCreatedCall", R.string.NotificationGroupCreatedCall, name, chat.title); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGroupCallScheduled) { + msg = messageObject.messageText.toString(); } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionInviteToGroupCall) { int singleUserId = messageObject.messageOwner.action.user_id; if (singleUserId == 0 && messageObject.messageOwner.action.users.size() == 1) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 28ba3386803..cd34b18f645 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -42,6 +42,7 @@ import androidx.annotation.UiThread; import androidx.core.view.inputmethod.InputContentInfoCompat; +import org.json.JSONObject; import org.telegram.messenger.audioinfo.AudioInfo; import org.telegram.messenger.support.SparseLongArray; import org.telegram.tgnet.ConnectionsManager; @@ -1616,7 +1617,7 @@ public int sendMessage(ArrayList messages, final long peer, boole TLRPC.TL_keyboardButtonRow newRow = null; for (int c = 0, N2 = oldRow.buttons.size(); c < N2; c++) { TLRPC.KeyboardButton button = oldRow.buttons.get(c); - if (button instanceof TLRPC.TL_keyboardButtonUrlAuth || button instanceof TLRPC.TL_keyboardButtonUrl || button instanceof TLRPC.TL_keyboardButtonSwitchInline) { + if (button instanceof TLRPC.TL_keyboardButtonUrlAuth || button instanceof TLRPC.TL_keyboardButtonUrl || button instanceof TLRPC.TL_keyboardButtonSwitchInline || button instanceof TLRPC.TL_keyboardButtonBuy) { if (button instanceof TLRPC.TL_keyboardButtonUrlAuth) { TLRPC.TL_keyboardButtonUrlAuth auth = new TLRPC.TL_keyboardButtonUrlAuth(); auth.flags = button.flags; @@ -2541,9 +2542,9 @@ public void sendCallback(final boolean cache, final MessageObject messageObject, if (response instanceof TLRPC.TL_payments_paymentForm) { final TLRPC.TL_payments_paymentForm form = (TLRPC.TL_payments_paymentForm) response; getMessagesController().putUsers(form.users, false); - parentFragment.presentFragment(new PaymentFormActivity(form, messageObject)); + parentFragment.presentFragment(new PaymentFormActivity(form, messageObject, parentFragment)); } else if (response instanceof TLRPC.TL_payments_paymentReceipt) { - parentFragment.presentFragment(new PaymentFormActivity(messageObject, (TLRPC.TL_payments_paymentReceipt) response)); + parentFragment.presentFragment(new PaymentFormActivity((TLRPC.TL_payments_paymentReceipt) response)); } } else { TLRPC.TL_messages_botCallbackAnswer res = (TLRPC.TL_messages_botCallbackAnswer) response; @@ -2730,10 +2731,26 @@ public void sendCallback(final boolean cache, final MessageObject messageObject, if ((messageObject.messageOwner.media.flags & 4) == 0) { TLRPC.TL_payments_getPaymentForm req = new TLRPC.TL_payments_getPaymentForm(); req.msg_id = messageObject.getId(); + req.peer = getMessagesController().getInputPeer(messageObject.messageOwner.peer_id); + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("bg_color", Theme.getColor(Theme.key_windowBackgroundWhite)); + jsonObject.put("text_color", Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + jsonObject.put("hint_color", Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); + jsonObject.put("link_color", Theme.getColor(Theme.key_windowBackgroundWhiteLinkText)); + jsonObject.put("button_color", Theme.getColor(Theme.key_featuredStickers_addButton)); + jsonObject.put("button_text_color", Theme.getColor(Theme.key_featuredStickers_buttonText)); + req.theme_params = new TLRPC.TL_dataJSON(); + req.theme_params.data = jsonObject.toString(); + req.flags |= 1; + } catch (Exception e) { + FileLog.e(e); + } getConnectionsManager().sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors); } else { TLRPC.TL_payments_getPaymentReceipt req = new TLRPC.TL_payments_getPaymentReceipt(); req.msg_id = messageObject.messageOwner.media.receipt_msg_id; + req.peer = getMessagesController().getInputPeer(messageObject.messageOwner.peer_id); getConnectionsManager().sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors); } } else { @@ -2815,38 +2832,42 @@ public void sendGame(TLRPC.InputPeer peer, TLRPC.TL_inputMediaGame game, long ra } public void sendMessage(MessageObject retryMessageObject) { - sendMessage(null, null, null, null, null, null, null, null, null, retryMessageObject.getDialogId(), retryMessageObject.messageOwner.attachPath, null, null, null, true, retryMessageObject, null, retryMessageObject.messageOwner.reply_markup, retryMessageObject.messageOwner.params, !retryMessageObject.messageOwner.silent, retryMessageObject.scheduled ? retryMessageObject.messageOwner.date : 0, 0, null); + sendMessage(null, null, null, null, null, null, null, null, null, null, retryMessageObject.getDialogId(), retryMessageObject.messageOwner.attachPath, null, null, null, true, retryMessageObject, null, retryMessageObject.messageOwner.reply_markup, retryMessageObject.messageOwner.params, !retryMessageObject.messageOwner.silent, retryMessageObject.scheduled ? retryMessageObject.messageOwner.date : 0, 0, null); } public void sendMessage(TLRPC.User user, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate) { - sendMessage(null, null, null, null, null, user, null, null, null, peer, null, replyToMsg, replyToTopMsg, null, true, null, null, replyMarkup, params, notify, scheduleDate, 0, null); + sendMessage(null, null, null, null, null, user, null, null, null, null, peer, null, replyToMsg, replyToTopMsg, null, true, null, null, replyMarkup, params, notify, scheduleDate, 0, null); + } + + public void sendMessage(TLRPC.TL_messageMediaInvoice invoice, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate) { + sendMessage(null, null, null, null, null, null, null, null, null, invoice, peer, null, replyToMsg, replyToTopMsg, null, true, null, null, replyMarkup, params, notify, scheduleDate, 0, null); } public void sendMessage(TLRPC.TL_document document, VideoEditedInfo videoEditedInfo, String path, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, String caption, ArrayList entities, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate, int ttl, Object parentObject) { - sendMessage(null, caption, null, null, videoEditedInfo, null, document, null, null, peer, path, replyToMsg, replyToTopMsg, null, true, null, entities, replyMarkup, params, notify, scheduleDate, ttl, parentObject); + sendMessage(null, caption, null, null, videoEditedInfo, null, document, null, null, null, peer, path, replyToMsg, replyToTopMsg, null, true, null, entities, replyMarkup, params, notify, scheduleDate, ttl, parentObject); } public void sendMessage(String message, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, TLRPC.WebPage webPage, boolean searchLinks, ArrayList entities, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate) { - sendMessage(message, null, null, null, null, null, null, null, null, peer, null, replyToMsg, replyToTopMsg, webPage, searchLinks, null, entities, replyMarkup, params, notify, scheduleDate, 0, null); + sendMessage(message, null, null, null, null, null, null, null, null, null, peer, null, replyToMsg, replyToTopMsg, webPage, searchLinks, null, entities, replyMarkup, params, notify, scheduleDate, 0, null); } public void sendMessage(TLRPC.MessageMedia location, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate) { - sendMessage(null, null, location, null, null, null, null, null, null, peer, null, replyToMsg, replyToTopMsg, null, true, null, null, replyMarkup, params, notify, scheduleDate, 0, null); + sendMessage(null, null, location, null, null, null, null, null, null, null, peer, null, replyToMsg, replyToTopMsg, null, true, null, null, replyMarkup, params, notify, scheduleDate, 0, null); } public void sendMessage(TLRPC.TL_messageMediaPoll poll, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate) { - sendMessage(null, null, null, null, null, null, null, null, poll, peer, null, replyToMsg, replyToTopMsg, null, true, null, null, replyMarkup, params, notify, scheduleDate, 0, null); + sendMessage(null, null, null, null, null, null, null, null, poll, null, peer, null, replyToMsg, replyToTopMsg, null, true, null, null, replyMarkup, params, notify, scheduleDate, 0, null); } public void sendMessage(TLRPC.TL_game game, long peer, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate) { - sendMessage(null, null, null, null, null, null, null, game, null, peer, null, null, null, null, true, null, null, replyMarkup, params, notify, scheduleDate, 0, null); + sendMessage(null, null, null, null, null, null, null, game, null, null, peer, null, null, null, null, true, null, null, replyMarkup, params, notify, scheduleDate, 0, null); } public void sendMessage(TLRPC.TL_photo photo, String path, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, String caption, ArrayList entities, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate, int ttl, Object parentObject) { - sendMessage(null, caption, null, photo, null, null, null, null, null, peer, path, replyToMsg, replyToTopMsg, null, true, null, entities, replyMarkup, params, notify, scheduleDate, ttl, parentObject); + sendMessage(null, caption, null, photo, null, null, null, null, null, null, peer, path, replyToMsg, replyToTopMsg, null, true, null, entities, replyMarkup, params, notify, scheduleDate, ttl, parentObject); } - private void sendMessage(String message, String caption, TLRPC.MessageMedia location, TLRPC.TL_photo photo, VideoEditedInfo videoEditedInfo, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_game game, TLRPC.TL_messageMediaPoll poll, long peer, String path, MessageObject replyToMsg, MessageObject replyToTopMsg, TLRPC.WebPage webPage, boolean searchLinks, MessageObject retryMessageObject, ArrayList entities, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate, int ttl, Object parentObject) { + private void sendMessage(String message, String caption, TLRPC.MessageMedia location, TLRPC.TL_photo photo, VideoEditedInfo videoEditedInfo, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_game game, TLRPC.TL_messageMediaPoll poll, TLRPC.TL_messageMediaInvoice invoice, long peer, String path, MessageObject replyToMsg, MessageObject replyToTopMsg, TLRPC.WebPage webPage, boolean searchLinks, MessageObject retryMessageObject, ArrayList entities, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate, int ttl, Object parentObject) { if (user != null && user.phone == null) { return; } @@ -3053,6 +3074,12 @@ private void sendMessage(String message, String caption, TLRPC.MessageMedia loca if (params != null && params.containsKey("query_id")) { type = 9; } + } else if (invoice != null) { + newMsg = new TLRPC.TL_message(); + newMsg.media = invoice; + if (params != null && params.containsKey("query_id")) { + type = 9; + } } else if (user != null) { if (encryptedChat != null) { newMsg = new TLRPC.TL_message_secret(); @@ -5040,7 +5067,7 @@ protected void performSendMessageRequest(final TLObject req, final MessageObject newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; ImageLoader.saveMessageThumbs(newMsgObj); } - if (res.media instanceof TLRPC.TL_messageMediaGame && !TextUtils.isEmpty(res.message)) { + if ((res.media instanceof TLRPC.TL_messageMediaGame || res.media instanceof TLRPC.TL_messageMediaInvoice) && !TextUtils.isEmpty(res.message)) { newMsgObj.message = res.message; } if (!newMsgObj.entities.isEmpty()) { @@ -5207,7 +5234,6 @@ protected void performSendMessageRequest(final TLObject req, final MessageObject getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByAck, msg_id); }); }, ConnectionsManager.RequestFlagCanCompress | ConnectionsManager.RequestFlagInvokeAfter | (req instanceof TLRPC.TL_messages_sendMessage ? ConnectionsManager.RequestFlagNeedQuickAck : 0)); - if (parentMessage != null) { parentMessage.sendDelayedRequests(); } @@ -5435,12 +5461,16 @@ private void updateMediaPaths(MessageObject newMsgObj, TLRPC.Message sentMessage } else if (sentMessage.media instanceof TLRPC.TL_messageMediaGeo) { sentMessage.media.geo.lat = newMsg.media.geo.lat; sentMessage.media.geo._long = newMsg.media.geo._long; - } else if (sentMessage.media instanceof TLRPC.TL_messageMediaGame) { + } else if (sentMessage.media instanceof TLRPC.TL_messageMediaGame || sentMessage.media instanceof TLRPC.TL_messageMediaInvoice) { newMsg.media = sentMessage.media; - if (newMsg.media instanceof TLRPC.TL_messageMediaGame && !TextUtils.isEmpty(sentMessage.message)) { + if (!TextUtils.isEmpty(sentMessage.message)) { newMsg.entities = sentMessage.entities; newMsg.message = sentMessage.message; } + if (sentMessage.reply_markup != null) { + newMsg.reply_markup = sentMessage.reply_markup; + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MARKUP; + } } else if (sentMessage.media instanceof TLRPC.TL_messageMediaPoll) { newMsg.media = sentMessage.media; } @@ -6438,6 +6468,24 @@ public static void prepareSendingBotContextResult(AccountInstance accountInstanc reason.reason = ""; user.restriction_reason.add(reason); accountInstance.getSendMessagesHelper().sendMessage(user, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); + } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaInvoice) { + if (DialogObject.isSecretDialogId(dialogId)) { + return; //doesn't work in secret chats for now + } + TLRPC.TL_botInlineMessageMediaInvoice invoice = (TLRPC.TL_botInlineMessageMediaInvoice) result.send_message; + TLRPC.TL_messageMediaInvoice messageMediaInvoice = new TLRPC.TL_messageMediaInvoice(); + messageMediaInvoice.shipping_address_requested = invoice.shipping_address_requested; + messageMediaInvoice.test = invoice.test; + messageMediaInvoice.title = invoice.title; + messageMediaInvoice.description = invoice.description; + if (invoice.photo != null) { + messageMediaInvoice.photo = invoice.photo; + messageMediaInvoice.flags |= 1; + } + messageMediaInvoice.currency = invoice.currency; + messageMediaInvoice.total_amount = invoice.total_amount; + messageMediaInvoice.start_param = ""; + accountInstance.getSendMessagesHelper().sendMessage(messageMediaInvoice, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); } } @@ -7360,6 +7408,9 @@ public static Bitmap createVideoThumbnailAtTime(String filePath, long time, int[ orientation[0] = fileDrawable.getOrientation(); } fileDrawable.recycle(); + if (bitmap == null) { + return createVideoThumbnailAtTime(filePath, time, orientation, false); + } } else { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java index 87917f7e460..3cf989a8456 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java @@ -260,7 +260,11 @@ public void setupGradient(String colorKey, float alpha) { placeholderMatrix = new Matrix(); placeholderGradient.setLocalMatrix(placeholderMatrix); for (Paint paint : paints.values()) { - paint.setShader(new ComposeShader(placeholderGradient, backgroundGradient, PorterDuff.Mode.ADD)); + if (Build.VERSION.SDK_INT <= 22) { + paint.setShader(backgroundGradient); + } else { + paint.setShader(new ComposeShader(placeholderGradient, backgroundGradient, PorterDuff.Mode.ADD)); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/WearDataLayerListenerService.java b/TMessagesProj/src/main/java/org/telegram/messenger/WearDataLayerListenerService.java index 4f7ab88a579..6f9adebb62c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/WearDataLayerListenerService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/WearDataLayerListenerService.java @@ -96,7 +96,7 @@ public void onChannelOpened(final Channel ch) { }; AndroidUtilities.runOnUIThread(() -> { NotificationCenter.getInstance(currentAccount).addObserver(listener, NotificationCenter.fileDidLoad); - FileLoader.getInstance(currentAccount).loadFile(ImageLocation.getForUser(user, false), user, null, 1, 1); + FileLoader.getInstance(currentAccount).loadFile(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), user, null, 1, 1); }); try { barrier.await(10, TimeUnit.SECONDS); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java index e3d56498e65..fc8f5edde06 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java @@ -195,6 +195,7 @@ public abstract class VoIPBaseService extends Service implements SensorEventList protected int mySource; protected String myJson; protected boolean createGroupCall; + protected int scheduleDate; protected TLRPC.InputPeer groupCallPeer; public boolean hasFewPeers; protected String joinHash; @@ -1281,38 +1282,42 @@ protected void callFailed() { protected Bitmap getRoundAvatarBitmap(TLObject userOrChat) { Bitmap bitmap = null; - if (userOrChat instanceof TLRPC.User) { - TLRPC.User user = (TLRPC.User) userOrChat; - if (user.photo != null && user.photo.photo_small != null) { - BitmapDrawable img = ImageLoader.getInstance().getImageFromMemory(user.photo.photo_small, null, "50_50"); - if (img != null) { - bitmap = img.getBitmap().copy(Bitmap.Config.ARGB_8888, true); - } else { - try { - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inMutable = true; - bitmap = BitmapFactory.decodeFile(FileLoader.getPathToAttach(user.photo.photo_small, true).toString(), opts); - } catch (Throwable e) { - FileLog.e(e); + try { + if (userOrChat instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) userOrChat; + if (user.photo != null && user.photo.photo_small != null) { + BitmapDrawable img = ImageLoader.getInstance().getImageFromMemory(user.photo.photo_small, null, "50_50"); + if (img != null) { + bitmap = img.getBitmap().copy(Bitmap.Config.ARGB_8888, true); + } else { + try { + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inMutable = true; + bitmap = BitmapFactory.decodeFile(FileLoader.getPathToAttach(user.photo.photo_small, true).toString(), opts); + } catch (Throwable e) { + FileLog.e(e); + } } } - } - } else { - TLRPC.Chat chat = (TLRPC.Chat) userOrChat; - if (chat.photo != null && chat.photo.photo_small != null) { - BitmapDrawable img = ImageLoader.getInstance().getImageFromMemory(chat.photo.photo_small, null, "50_50"); - if (img != null) { - bitmap = img.getBitmap().copy(Bitmap.Config.ARGB_8888, true); - } else { - try { - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inMutable = true; - bitmap = BitmapFactory.decodeFile(FileLoader.getPathToAttach(chat.photo.photo_small, true).toString(), opts); - } catch (Throwable e) { - FileLog.e(e); + } else { + TLRPC.Chat chat = (TLRPC.Chat) userOrChat; + if (chat.photo != null && chat.photo.photo_small != null) { + BitmapDrawable img = ImageLoader.getInstance().getImageFromMemory(chat.photo.photo_small, null, "50_50"); + if (img != null) { + bitmap = img.getBitmap().copy(Bitmap.Config.ARGB_8888, true); + } else { + try { + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inMutable = true; + bitmap = BitmapFactory.decodeFile(FileLoader.getPathToAttach(chat.photo.photo_small, true).toString(), opts); + } catch (Throwable e) { + FileLog.e(e); + } } } } + } catch (Throwable e) { + FileLog.e(e); } if (bitmap == null) { Theme.createDialogsResources(this); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java index f9b4b203d51..bd26486d95f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java @@ -237,6 +237,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { groupCallPeer.user_id = peerUserId; groupCallPeer.access_hash = intent.getLongExtra("peerAccessHash", 0); } + scheduleDate = intent.getIntExtra("scheduleDate", 0); isOutgoing = intent.getBooleanExtra("is_outgoing", false); videoCall = intent.getBooleanExtra("video_call", false); @@ -1328,6 +1329,10 @@ private void startGroupCall(int ssrc, String json, boolean create) { TLRPC.TL_phone_createGroupCall req = new TLRPC.TL_phone_createGroupCall(); req.peer = MessagesController.getInputPeer(chat); req.random_id = Utilities.random.nextInt(); + if (scheduleDate != 0) { + req.schedule_date = scheduleDate; + req.flags |= 2; + } ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (response != null) { TLRPC.Updates updates = (TLRPC.Updates) response; @@ -1673,8 +1678,7 @@ private void updateConnectionState(int state, boolean inTransition) { connectingSoundRunnable = null; } } else { - Utilities.globalQueue.postRunnable(() -> soundPool.play(spVoiceChatStartId, 1.0f, 1.0f, 0, 0, 1)); - playedConnectedSound = true; + playConnectedSound(); } if (!wasConnected) { wasConnected = true; @@ -1866,6 +1870,11 @@ protected void showNotification() { } } + public void playConnectedSound() { + Utilities.globalQueue.postRunnable(() -> soundPool.play(spVoiceChatStartId, 1.0f, 1.0f, 0, 0, 1)); + playedConnectedSound = true; + } + private void startConnectingSound() { Utilities.globalQueue.postRunnable(() -> { if (spPlayId != 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java index 2893c40b0dd..1d3c0a9a6b2 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java @@ -376,8 +376,17 @@ public void init(int version, int layer, int apiId, String deviceModel, String s if (installer == null) { installer = ""; } + String packageId = ""; + try { + packageId = ApplicationLoader.applicationContext.getPackageName(); + } catch (Throwable ignore) { + + } + if (packageId == null) { + packageId = ""; + } - native_init(currentAccount, version, layer, apiId, deviceModel, systemVersion, appVersion, langCode, systemLangCode, configPath, logPath, regId, cFingerprint, installer, timezoneOffset, userId, enablePushConnection, ApplicationLoader.isNetworkOnline(), ApplicationLoader.getCurrentNetworkType()); + native_init(currentAccount, version, layer, apiId, deviceModel, systemVersion, appVersion, langCode, systemLangCode, configPath, logPath, regId, cFingerprint, installer, packageId, timezoneOffset, userId, enablePushConnection, ApplicationLoader.isNetworkOnline(), ApplicationLoader.getCurrentNetworkType()); checkConnection(); } @@ -688,7 +697,7 @@ public static void setProxySettings(boolean enabled, String address, int port, S public static native void native_applyDatacenterAddress(int currentAccount, int datacenterId, String ipAddress, int port); public static native int native_getConnectionState(int currentAccount); public static native void native_setUserId(int currentAccount, int id); - public static native void native_init(int currentAccount, int version, int layer, int apiId, String deviceModel, String systemVersion, String appVersion, String langCode, String systemLangCode, String configPath, String logPath, String regId, String cFingerprint, String installer, int timezoneOffset, int userId, boolean enablePushConnection, boolean hasNetwork, int networkType); + public static native void native_init(int currentAccount, int version, int layer, int apiId, String deviceModel, String systemVersion, String appVersion, String langCode, String systemLangCode, String configPath, String logPath, String regId, String cFingerprint, String installer, String packageId, int timezoneOffset, int userId, boolean enablePushConnection, boolean hasNetwork, int networkType); public static native void native_setProxySettings(int currentAccount, String address, int port, String username, String password, String secret); public static native void native_setLangCode(int currentAccount, String langCode); public static native void native_setRegId(int currentAccount, String regId); diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index 82cad21d82d..7a20689c2a2 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -62,7 +62,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 = 126; + public static final int LAYER = 127; public static class TL_stats_megagroupStats extends TLObject { public static int constructor = 0xef7ff916; @@ -400,6 +400,7 @@ public static abstract class ChatPhoto extends TLObject { public boolean has_video; public FileLocation photo_small; public FileLocation photo_big; + public byte[] stripped_thumb; public int dc_id; public static ChatPhoto TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -415,6 +416,9 @@ public static ChatPhoto TLdeserialize(AbstractSerializedData stream, int constru result = new TL_chatPhoto_layer97(); break; case 0xd20b9f3c: + result = new TL_chatPhoto_layer126(); + break; + case 0x4790ee05: result = new TL_chatPhoto(); break; } @@ -471,7 +475,7 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_chatPhoto extends ChatPhoto { + public static class TL_chatPhoto_layer126 extends TL_chatPhoto { public static int constructor = 0xd20b9f3c; @@ -493,6 +497,34 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_chatPhoto extends ChatPhoto { + public static int constructor = 0x4790ee05; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + has_video = (flags & 1) != 0; + photo_small = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + photo_big = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 2) != 0) { + stripped_thumb = stream.readByteArray(exception); + } + dc_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = has_video ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + photo_small.serializeToStream(stream); + photo_big.serializeToStream(stream); + if ((flags & 2) != 0) { + stream.writeByteArray(stripped_thumb); + } + stream.writeInt32(dc_id); + } + } + public static class TL_help_termsOfService extends TLObject { public static int constructor = 0x780a0310; @@ -559,90 +591,110 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_payments_paymentReceipt extends TLObject { - public static int constructor = 0x500911e1; + public static class TL_payments_paymentReceipt extends TLObject { + public static int constructor = 0x10b555d0; - public int flags; - public int date; - public int bot_id; - public TL_invoice invoice; - public int provider_id; - public TL_paymentRequestedInfo info; - public TL_shippingOption shipping; - public String currency; - public long total_amount; - public String credentials_title; - public ArrayList users = new ArrayList<>(); + public int flags; + public int date; + public int bot_id; + public int provider_id; + public String title; + public String description; + public WebDocument photo; + public TL_invoice invoice; + public TL_paymentRequestedInfo info; + public TL_shippingOption shipping; + public long tip_amount; + public String currency; + public long total_amount; + public String credentials_title; + public ArrayList users = new ArrayList<>(); - public static TL_payments_paymentReceipt TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_payments_paymentReceipt.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_payments_paymentReceipt", constructor)); - } else { - return null; - } - } - TL_payments_paymentReceipt result = new TL_payments_paymentReceipt(); - result.readParams(stream, exception); - return result; - } + public static TL_payments_paymentReceipt TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_payments_paymentReceipt.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_payments_paymentReceipt", constructor)); + } else { + return null; + } + } + TL_payments_paymentReceipt result = new TL_payments_paymentReceipt(); + result.readParams(stream, exception); + return result; + } - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - date = stream.readInt32(exception); - bot_id = stream.readInt32(exception); - invoice = TL_invoice.TLdeserialize(stream, stream.readInt32(exception), exception); - provider_id = stream.readInt32(exception); - if ((flags & 1) != 0) { - info = TL_paymentRequestedInfo.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 2) != 0) { - shipping = TL_shippingOption.TLdeserialize(stream, stream.readInt32(exception), exception); - } - currency = stream.readString(exception); - total_amount = stream.readInt64(exception); - credentials_title = 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++) { - User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - users.add(object); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + date = stream.readInt32(exception); + bot_id = stream.readInt32(exception); + provider_id = stream.readInt32(exception); + title = stream.readString(exception); + description = stream.readString(exception); + if ((flags & 4) != 0) { + photo = WebDocument.TLdeserialize(stream, stream.readInt32(exception), exception); + } + invoice = TL_invoice.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 1) != 0) { + info = TL_paymentRequestedInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2) != 0) { + shipping = TL_shippingOption.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 8) != 0) { + tip_amount = stream.readInt64(exception); + } + currency = stream.readString(exception); + total_amount = stream.readInt64(exception); + credentials_title = 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++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - stream.writeInt32(date); - stream.writeInt32(bot_id); - invoice.serializeToStream(stream); - stream.writeInt32(provider_id); - if ((flags & 1) != 0) { - info.serializeToStream(stream); - } - if ((flags & 2) != 0) { - shipping.serializeToStream(stream); - } - stream.writeString(currency); - stream.writeInt64(total_amount); - stream.writeString(credentials_title); - stream.writeInt32(0x1cb5c415); - int count = users.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - users.get(a).serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(date); + stream.writeInt32(bot_id); + stream.writeInt32(provider_id); + stream.writeString(title); + stream.writeString(description); + if ((flags & 4) != 0) { + photo.serializeToStream(stream); + } + invoice.serializeToStream(stream); + if ((flags & 1) != 0) { + info.serializeToStream(stream); + } + if ((flags & 2) != 0) { + shipping.serializeToStream(stream); + } + if ((flags & 8) != 0) { + stream.writeInt64(tip_amount); + } + stream.writeString(currency); + stream.writeInt64(total_amount); + stream.writeString(credentials_title); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } public static abstract class NotifyPeer extends TLObject { @@ -1876,15 +1928,17 @@ public static abstract class GroupCall extends TLObject { public boolean join_muted; public boolean can_change_join_muted; public boolean join_date_asc; + public boolean schedule_start_subscribed; public long id; public long access_hash; - public int duration; public int participants_count; public TL_dataJSON params; public String title; public int stream_dc_id; public int record_start_date; + public int schedule_date; public int version; + public int duration; public static GroupCall TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { GroupCall result = null; @@ -1892,7 +1946,7 @@ public static GroupCall TLdeserialize(AbstractSerializedData stream, int constru case 0x7780bcb4: result = new TL_groupCallDiscarded(); break; - case 0xc0c2052e: + case 0xc95c6654: result = new TL_groupCall(); break; } @@ -1925,7 +1979,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_groupCall extends GroupCall { - public static int constructor = 0xc0c2052e; + public static int constructor = 0xc95c6654; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -1933,6 +1987,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { join_muted = (flags & 2) != 0; can_change_join_muted = (flags & 4) != 0; join_date_asc = (flags & 64) != 0; + schedule_start_subscribed = (flags & 256) != 0; id = stream.readInt64(exception); access_hash = stream.readInt64(exception); participants_count = stream.readInt32(exception); @@ -1948,6 +2003,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 32) != 0) { record_start_date = stream.readInt32(exception); } + if ((flags & 128) != 0) { + schedule_date = stream.readInt32(exception); + } version = stream.readInt32(exception); } @@ -1956,6 +2014,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = join_muted ? (flags | 2) : (flags &~ 2); flags = can_change_join_muted ? (flags | 4) : (flags &~ 4); flags = join_date_asc ? (flags | 64) : (flags &~ 64); + flags = schedule_start_subscribed ? (flags | 256) : (flags &~ 256); stream.writeInt32(flags); stream.writeInt64(id); stream.writeInt64(access_hash); @@ -1972,6 +2031,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 32) != 0) { stream.writeInt32(record_start_date); } + if ((flags & 128) != 0) { + stream.writeInt32(schedule_date); + } stream.writeInt32(version); } } @@ -2873,101 +2935,104 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_payments_paymentForm extends TLObject { - public static int constructor = 0x3f56aea3; + public static class TL_payments_paymentForm extends TLObject { + public static int constructor = 0x8d0b2415; - public int flags; - public boolean can_save_credentials; - public boolean password_missing; - public int bot_id; - public TL_invoice invoice; - public int provider_id; - public String url; - public String native_provider; - public TL_dataJSON native_params; - public TL_paymentRequestedInfo saved_info; - public TL_paymentSavedCredentialsCard saved_credentials; - public ArrayList users = new ArrayList<>(); + public int flags; + public boolean can_save_credentials; + public boolean password_missing; + public long form_id; + public int bot_id; + public TL_invoice invoice; + public int provider_id; + public String url; + public String native_provider; + public TL_dataJSON native_params; + public TL_paymentRequestedInfo saved_info; + public TL_paymentSavedCredentialsCard saved_credentials; + public ArrayList users = new ArrayList<>(); - public static TL_payments_paymentForm TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_payments_paymentForm.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_payments_paymentForm", constructor)); - } else { - return null; - } - } - TL_payments_paymentForm result = new TL_payments_paymentForm(); - result.readParams(stream, exception); - return result; - } + public static TL_payments_paymentForm TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_payments_paymentForm.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_payments_paymentForm", constructor)); + } else { + return null; + } + } + TL_payments_paymentForm result = new TL_payments_paymentForm(); + result.readParams(stream, exception); + return result; + } - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - can_save_credentials = (flags & 4) != 0; - password_missing = (flags & 8) != 0; - bot_id = stream.readInt32(exception); - invoice = TL_invoice.TLdeserialize(stream, stream.readInt32(exception), exception); - provider_id = stream.readInt32(exception); - url = stream.readString(exception); - if ((flags & 16) != 0) { - native_provider = stream.readString(exception); - } - if ((flags & 16) != 0) { - native_params = TL_dataJSON.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 1) != 0) { - saved_info = TL_paymentRequestedInfo.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 2) != 0) { - saved_credentials = TL_paymentSavedCredentialsCard.TLdeserialize(stream, stream.readInt32(exception), exception); - } - int magic = stream.readInt32(exception); - if (magic != 0x1cb5c415) { - if (exception) { - throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); - } - return; - } - int count = stream.readInt32(exception); - for (int a = 0; a < count; a++) { - User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - users.add(object); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_save_credentials = (flags & 4) != 0; + password_missing = (flags & 8) != 0; + form_id = stream.readInt64(exception); + bot_id = stream.readInt32(exception); + invoice = TL_invoice.TLdeserialize(stream, stream.readInt32(exception), exception); + provider_id = stream.readInt32(exception); + url = stream.readString(exception); + if ((flags & 16) != 0) { + native_provider = stream.readString(exception); + } + if ((flags & 16) != 0) { + native_params = TL_dataJSON.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 1) != 0) { + saved_info = TL_paymentRequestedInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2) != 0) { + saved_credentials = TL_paymentSavedCredentialsCard.TLdeserialize(stream, stream.readInt32(exception), exception); + } + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = can_save_credentials ? (flags | 4) : (flags &~ 4); - flags = password_missing ? (flags | 8) : (flags &~ 8); - stream.writeInt32(flags); - stream.writeInt32(bot_id); - invoice.serializeToStream(stream); - stream.writeInt32(provider_id); - stream.writeString(url); - if ((flags & 16) != 0) { - stream.writeString(native_provider); - } - if ((flags & 16) != 0) { - native_params.serializeToStream(stream); - } - if ((flags & 1) != 0) { - saved_info.serializeToStream(stream); - } - if ((flags & 2) != 0) { - saved_credentials.serializeToStream(stream); - } - stream.writeInt32(0x1cb5c415); - int count = users.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - users.get(a).serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_save_credentials ? (flags | 4) : (flags &~ 4); + flags = password_missing ? (flags | 8) : (flags &~ 8); + stream.writeInt32(flags); + stream.writeInt64(form_id); + stream.writeInt32(bot_id); + invoice.serializeToStream(stream); + stream.writeInt32(provider_id); + stream.writeString(url); + if ((flags & 16) != 0) { + stream.writeString(native_provider); + } + if ((flags & 16) != 0) { + native_params.serializeToStream(stream); + } + if ((flags & 1) != 0) { + saved_info.serializeToStream(stream); + } + if ((flags & 2) != 0) { + saved_credentials.serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } public static abstract class ContactLink_layer101 extends TLObject { @@ -13981,323 +14046,326 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static abstract class BotInlineMessage extends TLObject { - public int flags; - public GeoPoint geo; - public String title; - public String address; - public String provider; - public String venue_id; - public String venue_type; - public ReplyMarkup reply_markup; - public String message; - public ArrayList entities = new ArrayList<>(); - public String phone_number; - public String first_name; - public String last_name; - public String vcard; - public boolean no_webpage; - public int period; + public static abstract class BotInlineMessage extends TLObject { + public int flags; + public GeoPoint geo; + public String title; + public String address; + public String provider; + public String venue_id; + public String venue_type; + public ReplyMarkup reply_markup; + public String message; + public ArrayList entities = new ArrayList<>(); + public String phone_number; + public String first_name; + public String last_name; + public String vcard; + public boolean no_webpage; + public int period; public int heading; public int proximity_notification_radius; - public static BotInlineMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - BotInlineMessage result = null; - switch (constructor) { - case 0x4366232e: - result = new TL_botInlineMessageMediaVenue_layer77(); - break; - case 0x8a86659c: - result = new TL_botInlineMessageMediaVenue(); - break; - case 0x3a8fd8b8: - result = new TL_botInlineMessageMediaGeo_layer71(); - break; - case 0x764cf810: - result = new TL_botInlineMessageMediaAuto(); - break; - case 0xa74b15b: - result = new TL_botInlineMessageMediaAuto_layer74(); - break; - case 0x35edb4d4: - result = new TL_botInlineMessageMediaContact_layer81(); - break; - case 0x18d1cdc2: - result = new TL_botInlineMessageMediaContact(); - break; - case 0x8c7f65e2: - result = new TL_botInlineMessageText(); - break; - case 0xb722de65: - result = new TL_botInlineMessageMediaGeo_layer119(); - break; + public static BotInlineMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + BotInlineMessage result = null; + switch (constructor) { + case 0x4366232e: + result = new TL_botInlineMessageMediaVenue_layer77(); + break; + case 0x8a86659c: + result = new TL_botInlineMessageMediaVenue(); + break; + case 0x3a8fd8b8: + result = new TL_botInlineMessageMediaGeo_layer71(); + break; + case 0x764cf810: + result = new TL_botInlineMessageMediaAuto(); + break; + case 0xa74b15b: + result = new TL_botInlineMessageMediaAuto_layer74(); + break; + case 0x35edb4d4: + result = new TL_botInlineMessageMediaContact_layer81(); + break; + case 0x18d1cdc2: + result = new TL_botInlineMessageMediaContact(); + break; + case 0x8c7f65e2: + result = new TL_botInlineMessageText(); + break; + case 0xb722de65: + result = new TL_botInlineMessageMediaGeo_layer119(); + break; case 0x51846fd: result = new TL_botInlineMessageMediaGeo(); break; - } - if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in BotInlineMessage", constructor)); - } - if (result != null) { - result.readParams(stream, exception); - } - return result; - } - } + case 0x354a9b09: + result = new TL_botInlineMessageMediaInvoice(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in BotInlineMessage", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } - public static class TL_botInlineMessageMediaVenue_layer77 extends TL_botInlineMessageMediaVenue { - public static int constructor = 0x4366232e; + public static class TL_botInlineMessageMediaVenue_layer77 extends TL_botInlineMessageMediaVenue { + public static int constructor = 0x4366232e; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); - title = stream.readString(exception); - address = stream.readString(exception); - provider = stream.readString(exception); - venue_id = stream.readString(exception); - if ((flags & 4) != 0) { - reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + title = stream.readString(exception); + address = stream.readString(exception); + provider = stream.readString(exception); + venue_id = stream.readString(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - geo.serializeToStream(stream); - stream.writeString(title); - stream.writeString(address); - stream.writeString(provider); - stream.writeString(venue_id); - if ((flags & 4) != 0) { - reply_markup.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + geo.serializeToStream(stream); + stream.writeString(title); + stream.writeString(address); + stream.writeString(provider); + stream.writeString(venue_id); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } - public static class TL_botInlineMessageMediaVenue extends BotInlineMessage { - public static int constructor = 0x8a86659c; + public static class TL_botInlineMessageMediaVenue extends BotInlineMessage { + public static int constructor = 0x8a86659c; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); - title = stream.readString(exception); - address = stream.readString(exception); - provider = stream.readString(exception); - venue_id = stream.readString(exception); - venue_type = stream.readString(exception); - if ((flags & 4) != 0) { - reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + title = stream.readString(exception); + address = stream.readString(exception); + provider = stream.readString(exception); + venue_id = stream.readString(exception); + venue_type = stream.readString(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - geo.serializeToStream(stream); - stream.writeString(title); - stream.writeString(address); - stream.writeString(provider); - stream.writeString(venue_id); - stream.writeString(venue_type); - if ((flags & 4) != 0) { - reply_markup.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + geo.serializeToStream(stream); + stream.writeString(title); + stream.writeString(address); + stream.writeString(provider); + stream.writeString(venue_id); + stream.writeString(venue_type); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } - public static class TL_botInlineMessageMediaGeo_layer71 extends TL_botInlineMessageMediaGeo { - public static int constructor = 0x3a8fd8b8; + public static class TL_botInlineMessageMediaGeo_layer71 extends TL_botInlineMessageMediaGeo { + public static int constructor = 0x3a8fd8b8; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); - if ((flags & 4) != 0) { - reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - geo.serializeToStream(stream); - if ((flags & 4) != 0) { - reply_markup.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + geo.serializeToStream(stream); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } - public static class TL_botInlineMessageMediaAuto extends BotInlineMessage { - public static int constructor = 0x764cf810; + public static class TL_botInlineMessageMediaAuto extends BotInlineMessage { + public static int constructor = 0x764cf810; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - message = stream.readString(exception); - if ((flags & 2) != 0) { - int magic = stream.readInt32(exception); - if (magic != 0x1cb5c415) { - if (exception) { - throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); - } - return; - } - int count = stream.readInt32(exception); - for (int a = 0; a < count; a++) { - MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - entities.add(object); - } - } - if ((flags & 4) != 0) { - reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 2) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - stream.writeString(message); - if ((flags & 2) != 0) { - stream.writeInt32(0x1cb5c415); - int count = entities.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - entities.get(a).serializeToStream(stream); - } - } - if ((flags & 4) != 0) { - reply_markup.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(message); + if ((flags & 2) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } - public static class TL_botInlineMessageMediaAuto_layer74 extends TL_botInlineMessageMediaAuto { - public static int constructor = 0xa74b15b; + public static class TL_botInlineMessageMediaAuto_layer74 extends TL_botInlineMessageMediaAuto { + public static int constructor = 0xa74b15b; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - message = stream.readString(exception); - if ((flags & 4) != 0) { - reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - stream.writeString(message); - if ((flags & 4) != 0) { - reply_markup.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(message); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } - public static class TL_botInlineMessageMediaContact_layer81 extends TL_botInlineMessageMediaContact { - public static int constructor = 0x35edb4d4; + public static class TL_botInlineMessageMediaContact_layer81 extends TL_botInlineMessageMediaContact { + public static int constructor = 0x35edb4d4; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - phone_number = stream.readString(exception); - first_name = stream.readString(exception); - last_name = stream.readString(exception); - if ((flags & 4) != 0) { - reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + phone_number = stream.readString(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - stream.writeString(phone_number); - stream.writeString(first_name); - stream.writeString(last_name); - if ((flags & 4) != 0) { - reply_markup.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(phone_number); + stream.writeString(first_name); + stream.writeString(last_name); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } - public static class TL_botInlineMessageMediaContact extends BotInlineMessage { - public static int constructor = 0x18d1cdc2; + public static class TL_botInlineMessageMediaContact extends BotInlineMessage { + public static int constructor = 0x18d1cdc2; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - phone_number = stream.readString(exception); - first_name = stream.readString(exception); - last_name = stream.readString(exception); - vcard = stream.readString(exception); - if ((flags & 4) != 0) { - reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + phone_number = stream.readString(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + vcard = stream.readString(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - stream.writeString(phone_number); - stream.writeString(first_name); - stream.writeString(last_name); - stream.writeString(vcard); - if ((flags & 4) != 0) { - reply_markup.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(phone_number); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(vcard); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } - public static class TL_botInlineMessageText extends BotInlineMessage { - public static int constructor = 0x8c7f65e2; + public static class TL_botInlineMessageText extends BotInlineMessage { + public static int constructor = 0x8c7f65e2; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - no_webpage = (flags & 1) != 0; - message = stream.readString(exception); - if ((flags & 2) != 0) { - int magic = stream.readInt32(exception); - if (magic != 0x1cb5c415) { - if (exception) { - throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); - } - return; - } - int count = stream.readInt32(exception); - for (int a = 0; a < count; a++) { - MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - entities.add(object); - } - } - if ((flags & 4) != 0) { - reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + no_webpage = (flags & 1) != 0; + message = stream.readString(exception); + if ((flags & 2) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = no_webpage ? (flags | 1) : (flags &~ 1); - stream.writeInt32(flags); - stream.writeString(message); - if ((flags & 2) != 0) { - stream.writeInt32(0x1cb5c415); - int count = entities.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - entities.get(a).serializeToStream(stream); - } - } - if ((flags & 4) != 0) { - reply_markup.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = no_webpage ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeString(message); + if ((flags & 2) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } public static class TL_botInlineMessageMediaGeo extends BotInlineMessage { public static int constructor = 0x51846fd; @@ -14339,29 +14407,73 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_botInlineMessageMediaGeo_layer119 extends TL_botInlineMessageMediaGeo { - public static int constructor = 0xb722de65; + public static class TL_botInlineMessageMediaGeo_layer119 extends TL_botInlineMessageMediaGeo { + public static int constructor = 0xb722de65; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); - period = stream.readInt32(exception); - if ((flags & 4) != 0) { - reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + period = stream.readInt32(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - geo.serializeToStream(stream); - stream.writeInt32(period); - if ((flags & 4) != 0) { - reply_markup.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + geo.serializeToStream(stream); + stream.writeInt32(period); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } + + public static class TL_botInlineMessageMediaInvoice extends BotInlineMessage { + public static int constructor = 0x354a9b09; + + public boolean shipping_address_requested; + public boolean test; + public String description; + public WebDocument photo; + public String currency; + public long total_amount; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + shipping_address_requested = (flags & 2) != 0; + test = (flags & 8) != 0; + title = stream.readString(exception); + description = stream.readString(exception); + if ((flags & 1) != 0) { + photo = WebDocument.TLdeserialize(stream, stream.readInt32(exception), exception); + } + currency = stream.readString(exception); + total_amount = stream.readInt64(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = shipping_address_requested ? (flags | 2) : (flags &~ 2); + flags = test ? (flags | 8) : (flags &~ 8); + stream.writeInt32(flags); + stream.writeString(title); + stream.writeString(description); + if ((flags & 1) != 0) { + photo.serializeToStream(stream); + } + stream.writeString(currency); + stream.writeInt64(total_amount); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } public static class TL_keyboardButtonRow extends TLObject { public static int constructor = 0x77608b83; @@ -18367,6 +18479,9 @@ public static MessageAction TLdeserialize(AbstractSerializedData stream, int con case 0x92a72876: result = new TL_messageActionGameScore(); break; + case 0xb3a07661: + result = new TL_messageActionGroupCallScheduled(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in MessageAction", constructor)); @@ -18896,6 +19011,23 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_messageActionGroupCallScheduled extends MessageAction { + public static int constructor = 0xb3a07661; + + public int schedule_date; + + public void readParams(AbstractSerializedData stream, boolean exception) { + call = TL_inputGroupCall.TLdeserialize(stream, stream.readInt32(exception), exception); + schedule_date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + call.serializeToStream(stream); + stream.writeInt32(schedule_date); + } + } + public static abstract class ReportReason extends TLObject { public static ReportReason TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -19411,82 +19543,111 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_invoice extends TLObject { - public static int constructor = 0xc30aa358; + public static class TL_invoice extends TLObject { + public static int constructor = 0xcd886e0; - public int flags; - public boolean test; - public boolean name_requested; - public boolean phone_requested; - public boolean email_requested; - public boolean shipping_address_requested; - public boolean flexible; - public boolean phone_to_provider; - public boolean email_to_provider; - public String currency; - public ArrayList prices = new ArrayList<>(); - - public static TL_invoice TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_invoice.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_invoice", constructor)); - } else { - return null; - } - } - TL_invoice result = new TL_invoice(); - result.readParams(stream, exception); - return result; - } + public int flags; + public boolean test; + public boolean name_requested; + public boolean phone_requested; + public boolean email_requested; + public boolean shipping_address_requested; + public boolean flexible; + public boolean phone_to_provider; + public boolean email_to_provider; + public String currency; + public ArrayList prices = new ArrayList<>(); + public long max_tip_amount; + public ArrayList suggested_tip_amounts = new ArrayList<>(); + + public static TL_invoice TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_invoice.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_invoice", constructor)); + } else { + return null; + } + } + TL_invoice result = new TL_invoice(); + result.readParams(stream, exception); + return result; + } - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - test = (flags & 1) != 0; - name_requested = (flags & 2) != 0; - phone_requested = (flags & 4) != 0; - email_requested = (flags & 8) != 0; - shipping_address_requested = (flags & 16) != 0; - flexible = (flags & 32) != 0; - phone_to_provider = (flags & 64) != 0; - email_to_provider = (flags & 128) != 0; - currency = 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_labeledPrice object = TL_labeledPrice.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - prices.add(object); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + test = (flags & 1) != 0; + name_requested = (flags & 2) != 0; + phone_requested = (flags & 4) != 0; + email_requested = (flags & 8) != 0; + shipping_address_requested = (flags & 16) != 0; + flexible = (flags & 32) != 0; + phone_to_provider = (flags & 64) != 0; + email_to_provider = (flags & 128) != 0; + currency = 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_labeledPrice object = TL_labeledPrice.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + prices.add(object); + } + if ((flags & 256) != 0) { + max_tip_amount = stream.readInt64(exception); + } + if ((flags & 256) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + suggested_tip_amounts.add(stream.readInt64(exception)); + } + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = test ? (flags | 1) : (flags &~ 1); - flags = name_requested ? (flags | 2) : (flags &~ 2); - flags = phone_requested ? (flags | 4) : (flags &~ 4); - flags = email_requested ? (flags | 8) : (flags &~ 8); - flags = shipping_address_requested ? (flags | 16) : (flags &~ 16); - flags = flexible ? (flags | 32) : (flags &~ 32); - flags = phone_to_provider ? (flags | 64) : (flags &~ 64); - flags = email_to_provider ? (flags | 128) : (flags &~ 128); - stream.writeInt32(flags); - stream.writeString(currency); - stream.writeInt32(0x1cb5c415); - int count = prices.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - prices.get(a).serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = test ? (flags | 1) : (flags &~ 1); + flags = name_requested ? (flags | 2) : (flags &~ 2); + flags = phone_requested ? (flags | 4) : (flags &~ 4); + flags = email_requested ? (flags | 8) : (flags &~ 8); + flags = shipping_address_requested ? (flags | 16) : (flags &~ 16); + flags = flexible ? (flags | 32) : (flags &~ 32); + flags = phone_to_provider ? (flags | 64) : (flags &~ 64); + flags = email_to_provider ? (flags | 128) : (flags &~ 128); + stream.writeInt32(flags); + stream.writeString(currency); + stream.writeInt32(0x1cb5c415); + int count = prices.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + prices.get(a).serializeToStream(stream); + } + if ((flags & 256) != 0) { + stream.writeInt64(max_tip_amount); + } + if ((flags & 256) != 0) { + stream.writeInt32(0x1cb5c415); + count = suggested_tip_amounts.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(suggested_tip_amounts.get(a)); + } + } + } + } public static abstract class account_WallPapers extends TLObject { @@ -26695,13 +26856,14 @@ public static abstract class UserProfilePhoto extends TLObject { public long photo_id; public FileLocation photo_small; public FileLocation photo_big; + public byte[] stripped_thumb; public int dc_id; public static UserProfilePhoto TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { UserProfilePhoto result = null; switch (constructor) { case 0x69d3ab26: - result = new TL_userProfilePhoto(); + result = new TL_userProfilePhoto_layer126(); break; case 0xecd75d8c: result = new TL_userProfilePhoto_layer115(); @@ -26715,6 +26877,9 @@ public static UserProfilePhoto TLdeserialize(AbstractSerializedData stream, int case 0x990d1493: result = new TL_userProfilePhoto_old(); break; + case 0xcc656077: + result = new TL_userProfilePhoto(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in UserProfilePhoto", constructor)); @@ -26726,7 +26891,7 @@ public static UserProfilePhoto TLdeserialize(AbstractSerializedData stream, int } } - public static class TL_userProfilePhoto extends UserProfilePhoto { + public static class TL_userProfilePhoto_layer126 extends TL_userProfilePhoto { public static int constructor = 0x69d3ab26; @@ -26750,6 +26915,36 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_userProfilePhoto extends UserProfilePhoto { + public static int constructor = 0xcc656077; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + has_video = (flags & 1) != 0; + photo_id = stream.readInt64(exception); + photo_small = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + photo_big = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 2) != 0) { + stripped_thumb = stream.readByteArray(exception); + } + dc_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = has_video ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt64(photo_id); + photo_small.serializeToStream(stream); + photo_big.serializeToStream(stream); + if ((flags & 2) != 0) { + stream.writeByteArray(stripped_thumb); + } + stream.writeInt32(dc_id); + } + } + public static class TL_userProfilePhoto_layer115 extends TL_userProfilePhoto { public static int constructor = 0xecd75d8c; @@ -34359,6 +34554,7 @@ public static abstract class StickerSet extends TLObject { public int installed_date; public ArrayList thumbs = new ArrayList<>(); public int thumb_dc_id; + public int thumb_version; public static StickerSet TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { StickerSet result = null; @@ -34376,11 +34572,14 @@ public static StickerSet TLdeserialize(AbstractSerializedData stream, int constr result = new TL_stickerSet_layer121(); break; case 0x40e237a8: - result = new TL_stickerSet(); + result = new TL_stickerSet_layer126(); break; case 0xcd303b41: result = new TL_stickerSet_layer75(); break; + case 0xd7df217a: + result = new TL_stickerSet(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in StickerSet", constructor)); @@ -34412,6 +34611,83 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_stickerSet extends StickerSet { + public static int constructor = 0xd7df217a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + archived = (flags & 2) != 0; + official = (flags & 4) != 0; + masks = (flags & 8) != 0; + animated = (flags & 32) != 0; + if ((flags & 1) != 0) { + installed_date = stream.readInt32(exception); + } + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + title = stream.readString(exception); + short_name = stream.readString(exception); + if ((flags & 16) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + thumbs.add(object); + } + } + if ((flags & 16) != 0) { + thumb_dc_id = stream.readInt32(exception); + } + if ((flags & 16) != 0) { + thumb_version = stream.readInt32(exception); + } + count = stream.readInt32(exception); + hash = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = archived ? (flags | 2) : (flags &~ 2); + flags = official ? (flags | 4) : (flags &~ 4); + flags = masks ? (flags | 8) : (flags &~ 8); + flags = animated ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeInt32(installed_date); + } + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeString(title); + stream.writeString(short_name); + if ((flags & 16) != 0) { + stream.writeInt32(0x1cb5c415); + int count = thumbs.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + thumbs.get(a).serializeToStream(stream); + } + } + if ((flags & 16) != 0) { + stream.writeInt32(thumb_dc_id); + } + if ((flags & 16) != 0) { + stream.writeInt32(thumb_version); + } + stream.writeInt32(count); + stream.writeInt32(hash); + } + } + public static class TL_stickerSet_layer96 extends TL_stickerSet { public static int constructor = 0x5585a139; @@ -34497,7 +34773,7 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_stickerSet extends StickerSet { + public static class TL_stickerSet_layer126 extends TL_stickerSet { public static int constructor = 0x40e237a8; @@ -38310,7 +38586,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_groupCallParticipant extends TLObject { - public static int constructor = 0x19adba89; + public static int constructor = 0xb96b25ee; public int flags; public boolean muted; @@ -38329,6 +38605,7 @@ public static class TL_groupCallParticipant extends TLObject { public int volume; public String about; public long raise_hand_rating; + public TL_dataJSON params; public long lastSpeakTime; //custom; public float amplitude; //custom; public boolean hasVoice; //custom; @@ -38378,6 +38655,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 8192) != 0) { raise_hand_rating = stream.readInt64(exception); } + if ((flags & 64) != 0) { + params = TL_dataJSON.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -38407,6 +38687,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 8192) != 0) { stream.writeInt64(raise_hand_rating); } + if ((flags & 64) != 0) { + params.serializeToStream(stream); + } } } @@ -45165,10 +45448,13 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_phone_createGroupCall extends TLObject { - public static int constructor = 0xbd3dabe0; + public static int constructor = 0x48cdc6d8; + public int flags; public InputPeer peer; public int random_id; + public String title; + public int schedule_date; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -45176,8 +45462,15 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + stream.writeInt32(flags); peer.serializeToStream(stream); stream.writeInt32(random_id); + if ((flags & 1) != 0) { + stream.writeString(title); + } + if ((flags & 2) != 0) { + stream.writeInt32(schedule_date); + } } } @@ -45453,35 +45746,152 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_payments_getPaymentForm extends TLObject { - public static int constructor = 0x99f09745; + public static class TL_phone_toggleGroupCallStartSubscription extends TLObject { + public static int constructor = 0x219c34e6; - public int msg_id; + public TL_inputGroupCall call; + public boolean subscribed; - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_payments_paymentForm.TLdeserialize(stream, constructor, exception); - } + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(msg_id); - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + call.serializeToStream(stream); + stream.writeBool(subscribed); + } + } - public static class TL_payments_getPaymentReceipt extends TLObject { - public static int constructor = 0xa092a980; + public static class TL_phone_startScheduledGroupCall extends TLObject { + public static int constructor = 0x5680e342; - public int msg_id; + public TL_inputGroupCall call; - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_payments_paymentReceipt.TLdeserialize(stream, constructor, exception); - } + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(msg_id); - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + call.serializeToStream(stream); + } + } + + public static class TL_phone_saveDefaultGroupCallJoinAs extends TLObject { + public static int constructor = 0x575e1f8c; + + public InputPeer peer; + public InputPeer join_as; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + join_as.serializeToStream(stream); + } + } + + public static class TL_payments_getPaymentForm extends TLObject { + public static int constructor = 0x8a333c8d; + + public int flags; + public InputPeer peer; + public int msg_id; + public TL_dataJSON theme_params; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_payments_paymentForm.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(msg_id); + if ((flags & 1) != 0) { + theme_params.serializeToStream(stream); + } + } + } + + public static class TL_payments_getPaymentReceipt extends TLObject { + public static int constructor = 0x2478d1cc; + + public InputPeer peer; + public int msg_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_payments_paymentReceipt.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(msg_id); + } + } + + public static class TL_payments_validateRequestedInfo extends TLObject { + public static int constructor = 0xdb103170; + + public int flags; + public boolean save; + public InputPeer peer; + public int msg_id; + public TL_paymentRequestedInfo info; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_payments_validatedRequestedInfo.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = save ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(msg_id); + info.serializeToStream(stream); + } + } + + public static class TL_payments_sendPaymentForm extends TLObject { + public static int constructor = 0x30c3bc9d; + + public int flags; + public long form_id; + public InputPeer peer; + public int msg_id; + public String requested_info_id; + public String shipping_option_id; + public InputPaymentCredentials credentials; + public long tip_amount; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return payments_PaymentResult.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt64(form_id); + peer.serializeToStream(stream); + stream.writeInt32(msg_id); + if ((flags & 1) != 0) { + stream.writeString(requested_info_id); + } + if ((flags & 2) != 0) { + stream.writeString(shipping_option_id); + } + credentials.serializeToStream(stream); + if ((flags & 4) != 0) { + stream.writeInt64(tip_amount); + } + } + } public static class TL_help_supportName extends TLObject { public static int constructor = 0x8c05f1c9; @@ -45573,54 +45983,6 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_payments_validateRequestedInfo extends TLObject { - public static int constructor = 0x770a8e74; - - public int flags; - public boolean save; - public int msg_id; - public TL_paymentRequestedInfo info; - - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_payments_validatedRequestedInfo.TLdeserialize(stream, constructor, exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = save ? (flags | 1) : (flags &~ 1); - stream.writeInt32(flags); - stream.writeInt32(msg_id); - info.serializeToStream(stream); - } - } - - public static class TL_payments_sendPaymentForm extends TLObject { - public static int constructor = 0x2b8879b3; - - public int flags; - public int msg_id; - public String requested_info_id; - public String shipping_option_id; - public InputPaymentCredentials credentials; - - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return payments_PaymentResult.TLdeserialize(stream, constructor, exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - stream.writeInt32(msg_id); - if ((flags & 1) != 0) { - stream.writeString(requested_info_id); - } - if ((flags & 2) != 0) { - stream.writeString(shipping_option_id); - } - credentials.serializeToStream(stream); - } - } - public static class TL_payments_getSavedInfo extends TLObject { public static int constructor = 0x227d824b; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index 4635886494f..d8c9627de12 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -353,6 +353,11 @@ public void drawHeaderShadow(Canvas canvas, int alpha, int y) { public void setInnerTranslationX(float value) { innerTranslationX = value; invalidate(); + + if (fragmentsStack.size() >= 2) { + BaseFragment prevFragment = fragmentsStack.get(fragmentsStack.size() - 2); + prevFragment.onSlideProgress(false, value / containerView.getMeasuredWidth()); + } } @Keep @@ -528,9 +533,11 @@ private void onSlideAnimationEnd(final boolean backAnimation) { return; } BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 1); + lastFragment.prepareFragmentToSlide(true, false); lastFragment.onPause(); lastFragment.onFragmentDestroy(); lastFragment.setParentLayout(null); + fragmentsStack.remove(fragmentsStack.size() - 1); LayoutContainer temp = containerView; @@ -542,11 +549,16 @@ private void onSlideAnimationEnd(final boolean backAnimation) { currentActionBar = lastFragment.actionBar; lastFragment.onResume(); lastFragment.onBecomeFullyVisible(); + lastFragment.prepareFragmentToSlide(false, false); layoutToIgnore = containerView; } else { if (fragmentsStack.size() >= 2) { - BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 2); + BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 1); + lastFragment.prepareFragmentToSlide(true, false); + + lastFragment = fragmentsStack.get(fragmentsStack.size() - 2); + lastFragment.prepareFragmentToSlide(false, false); lastFragment.onPause(); if (lastFragment.fragmentView != null) { ViewGroup parent = (ViewGroup) lastFragment.fragmentView.getParent(); @@ -614,6 +626,10 @@ private void prepareForMoving(MotionEvent ev) { if (themeAnimatorSet != null) { presentingFragmentDescriptions = lastFragment.getThemeDescriptions(); } + + BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1); + currentFragment.prepareFragmentToSlide(true, true); + lastFragment.prepareFragmentToSlide(false, true); } public boolean onTouchEvent(MotionEvent ev) { @@ -685,19 +701,33 @@ public boolean onTouchEvent(MotionEvent ev) { float distToMove; if (!backAnimation) { distToMove = containerView.getMeasuredWidth() - x; + int duration = Math.max((int) (200.0f / containerView.getMeasuredWidth() * distToMove), 50); animatorSet.playTogether( - ObjectAnimator.ofFloat(containerView, View.TRANSLATION_X, containerView.getMeasuredWidth()), - ObjectAnimator.ofFloat(this, "innerTranslationX", (float) containerView.getMeasuredWidth()) + ObjectAnimator.ofFloat(containerView, View.TRANSLATION_X, containerView.getMeasuredWidth()).setDuration(duration), + ObjectAnimator.ofFloat(this, "innerTranslationX", (float) containerView.getMeasuredWidth()).setDuration(duration) ); } else { distToMove = x; + int duration = Math.max((int) (200.0f / containerView.getMeasuredWidth() * distToMove), 50); animatorSet.playTogether( - ObjectAnimator.ofFloat(containerView, View.TRANSLATION_X, 0), - ObjectAnimator.ofFloat(this, "innerTranslationX", 0.0f) + ObjectAnimator.ofFloat(containerView, View.TRANSLATION_X, 0).setDuration(duration), + ObjectAnimator.ofFloat(this, "innerTranslationX", 0.0f).setDuration(duration) ); } - animatorSet.setDuration(Math.max((int) (200.0f / containerView.getMeasuredWidth() * distToMove), 50)); + Animator customTransition = currentFragment.getCustomSlideTransition(false, backAnimation, distToMove); + if (customTransition != null) { + animatorSet.playTogether(customTransition); + } + + BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 2); + if (lastFragment != null) { + customTransition = lastFragment.getCustomSlideTransition(false, backAnimation, distToMove); + if (customTransition != null) { + animatorSet.playTogether(customTransition); + } + } + animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java index 90da7b0fcef..d3b548c6ef0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java @@ -17,7 +17,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.ui.Adapters.FiltersView; import org.telegram.ui.Components.RLottieDrawable; -import org.telegram.ui.Components.RLottieImageView; public class ActionBarMenu extends LinearLayout { 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 7798d4de225..15018c51851 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -1685,12 +1685,12 @@ public void setData(FiltersView.MediaFilterData data) { avatarImageView.setImageDrawable(combinedDrawable); } else { avatarImageView.getImageReceiver().setRoundRadius(AndroidUtilities.dp(16)); - avatarImageView.getImageReceiver().setImage(ImageLocation.getForUser(user, false), "50_50", thumbDrawable, null, user, 0); + avatarImageView.getImageReceiver().setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", thumbDrawable, user, 0); } } else if (data.chat instanceof TLRPC.Chat) { TLRPC.Chat chat = (TLRPC.Chat) data.chat; avatarImageView.getImageReceiver().setRoundRadius(AndroidUtilities.dp(16)); - avatarImageView.getImageReceiver().setImage(ImageLocation.getForChat(chat, false), "50_50",thumbDrawable, null, chat, 0); + avatarImageView.getImageReceiver().setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", thumbDrawable, chat, 0); } } else if (data.filterType == FiltersView.FILTER_TYPE_ARCHIVE) { CombinedDrawable combinedDrawable = Theme.createCircleDrawableWithIcon(AndroidUtilities.dp(32), R.drawable.chats_archive); 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 f4d4b70f596..7775c20fcb1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -68,6 +68,8 @@ public class AlertDialog extends Dialog implements Drawable.Callback { private AnimatorSet[] shadowAnimation = new AnimatorSet[2]; private int customViewOffset = 20; + private String dialogButtonColorKey = Theme.key_dialogButton; + private OnCancelListener onCancelListener; private AlertDialog cancelDialog; @@ -728,13 +730,13 @@ public void setTextColor(int color) { textView.setMinWidth(AndroidUtilities.dp(64)); textView.setTag(Dialog.BUTTON_POSITIVE); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - textView.setTextColor(getThemeColor(Theme.key_dialogButton)); + textView.setTextColor(getThemeColor(dialogButtonColorKey)); textView.setGravity(Gravity.CENTER); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); // textView.setLines(1); // textView.setSingleLine(true); //TODO textView.setText(positiveButtonText.toString().toUpperCase()); - textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable(getThemeColor(Theme.key_dialogButton))); + textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable(getThemeColor(dialogButtonColorKey))); textView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); if (verticalButtons) { buttonsLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 36, LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)); @@ -768,13 +770,13 @@ public void setTextColor(int color) { textView.setMinWidth(AndroidUtilities.dp(64)); textView.setTag(Dialog.BUTTON_NEGATIVE); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - textView.setTextColor(getThemeColor(Theme.key_dialogButton)); + textView.setTextColor(getThemeColor(dialogButtonColorKey)); textView.setGravity(Gravity.CENTER); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); textView.setEllipsize(TextUtils.TruncateAt.END); textView.setSingleLine(true); textView.setText(negativeButtonText.toString().toUpperCase()); - textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable(getThemeColor(Theme.key_dialogButton))); + textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable(getThemeColor(dialogButtonColorKey))); textView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); if (verticalButtons) { buttonsLayout.addView(textView, 0, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 36, LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)); @@ -808,13 +810,13 @@ public void setTextColor(int color) { textView.setMinWidth(AndroidUtilities.dp(64)); textView.setTag(Dialog.BUTTON_NEUTRAL); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - textView.setTextColor(getThemeColor(Theme.key_dialogButton)); + textView.setTextColor(getThemeColor(dialogButtonColorKey)); textView.setGravity(Gravity.CENTER); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); textView.setEllipsize(TextUtils.TruncateAt.END); textView.setSingleLine(true); textView.setText(neutralButtonText.toString().toUpperCase()); - textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable(getThemeColor(Theme.key_dialogButton))); + textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable(getThemeColor(dialogButtonColorKey))); textView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); if (verticalButtons) { buttonsLayout.addView(textView, 1, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 36, LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)); @@ -1015,6 +1017,9 @@ private boolean canTextInput(View v) { @Override public void dismiss() { + if (onDismissListener != null) { + onDismissListener.onDismiss(this); + } if (cancelDialog != null) { cancelDialog.dismiss(); } @@ -1176,8 +1181,8 @@ public static class Builder { private AlertDialog alertDialog; - protected Builder(AlertDialog alert){ - alertDialog=alert; + protected Builder(AlertDialog alert) { + alertDialog = alert; } public Builder(Context context) { @@ -1241,6 +1246,11 @@ public Builder setTopView(View view) { return this; } + public Builder setDialogButtonColorKey(String key) { + alertDialog.dialogButtonColorKey = key; + return this; + } + public Builder setTopAnimation(int resId, int backgroundColor) { alertDialog.topAnimationId = resId; alertDialog.topBackgroundColor = backgroundColor; @@ -1329,5 +1339,10 @@ public void notDrawBackgroundOnTopView(boolean b) { public void setButtonsVertical(boolean vertical) { alertDialog.verticalButtons = vertical; } + + public Builder setOnPreDismissListener(OnDismissListener onDismissListener) { + alertDialog.onDismissListener = onDismissListener; + return this; + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java index 54dea6608f3..448d01bac3f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -8,6 +8,7 @@ package org.telegram.ui.ActionBar; +import android.animation.Animator; import android.animation.AnimatorSet; import android.app.Activity; import android.app.Dialog; @@ -46,7 +47,7 @@ import java.util.ArrayList; -public class BaseFragment { +public abstract class BaseFragment { private boolean isFinished; private boolean finishing; @@ -327,6 +328,10 @@ public void restoreSelfArgs(Bundle args) { } + public boolean isLastFragment() { + return parentLayout != null && !parentLayout.fragmentsStack.isEmpty() && parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1) == this; + } + public ActionBarLayout getParentLayout() { return parentLayout; } @@ -411,6 +416,10 @@ public void onBeginSlide() { } } + protected void onSlideProgress(boolean isOpen, float progress) { + + } + protected void onTransitionAnimationProgress(boolean isOpen, float progress) { } @@ -597,4 +606,16 @@ public void setFragmentPanTranslationOffset(int offset) { public void saveKeyboardPositionBeforeTransition() { } + + protected Animator getCustomSlideTransition(boolean topFragment, boolean backAnimation, float distanceToMove) { + return null; + } + + protected void prepareFragmentToSlide(boolean topFragment, boolean beginSlide) { + + } + + public void setProgressToDrawerOpened(float v) { + + } } 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 214b3558947..7ee17860225 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -58,6 +58,7 @@ import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.LaunchActivity; import java.util.ArrayList; @@ -107,6 +108,8 @@ public class BottomSheet extends Dialog { private boolean allowCustomAnimation = true; private boolean showWithoutAnimation; + protected int statusBarHeight = AndroidUtilities.statusBarHeight; + protected boolean calcMandatoryInsets; private int touchSlop; @@ -766,6 +769,10 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { if (Build.VERSION.SDK_INT >= 21) { container.setFitsSystemWindows(true); container.setOnApplyWindowInsetsListener((v, insets) -> { + int newTopInset = insets.getSystemWindowInsetTop(); + if ((newTopInset != 0 || AndroidUtilities.isInMultiwindow) && statusBarHeight != 0 && statusBarHeight != newTopInset) { + statusBarHeight = newTopInset; + } lastInsets = insets; v.requestLayout(); if (Build.VERSION.SDK_INT >= 30) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java index 7989b68331f..38d0ce579d7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java @@ -193,6 +193,14 @@ public void setDrawerPosition(float value) { if (drawerLayout.getVisibility() != newVisibility) { drawerLayout.setVisibility(newVisibility); } + BaseFragment currentFragment = parentActionBarLayout.fragmentsStack.get(0); + if (drawerPosition == drawerLayout.getMeasuredWidth()) { + currentFragment.setProgressToDrawerOpened(1f); + } else if (drawerPosition == 0){ + currentFragment.setProgressToDrawerOpened(0); + } else { + currentFragment.setProgressToDrawerOpened(drawerPosition / drawerLayout.getMeasuredWidth()); + } setScrimOpacity(drawerPosition / (float) drawerLayout.getMeasuredWidth()); } 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 bd8f3e4dbc2..a6387e11f84 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -27,6 +27,8 @@ import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.ui.Components.EmptyStubSpan; @@ -79,7 +81,7 @@ public class SimpleTextView extends View implements Drawable.Callback { private static final int SCROLL_SLOWDOWN_PX = 100; private int fullLayoutAdditionalWidth; private int fullLayoutLeftOffset; - private boolean crosfadeFullLayout; + private float fullLayoutLeftCharactersOffset; public SimpleTextView(Context context) { super(context); @@ -186,19 +188,15 @@ private void calcOffset(int width) { } if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.CENTER_HORIZONTAL) { - offsetX = (width - textWidth) / 2; + offsetX = (width - textWidth) / 2 - (int) layout.getLineLeft(0); } else if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT) { - if (crosfadeFullLayout) { - offsetX = 0; - } else if (firstLineLayout != null) { + if (firstLineLayout != null) { offsetX = -(int) firstLineLayout.getLineLeft(0); } else { offsetX = -(int) layout.getLineLeft(0); } } else if (layout.getLineLeft(0) == 0) { - if (crosfadeFullLayout) { - offsetX = 0; - } else if (firstLineLayout != null) { + if (firstLineLayout != null) { offsetX = (int) (width - firstLineLayout.getLineWidth(0)); } else { offsetX = width - textWidth; @@ -208,6 +206,10 @@ private void calcOffset(int width) { } offsetX += getPaddingLeft(); textDoesNotFit = textWidth > width; + + if (fullLayout != null && fullLayoutAdditionalWidth > 0) { + fullLayoutLeftCharactersOffset = fullLayout.getPrimaryHorizontal(0) - firstLineLayout.getPrimaryHorizontal(0); + } } } @@ -223,38 +225,30 @@ protected boolean createLayout(int width) { width -= dw; width -= drawablePadding; } - crosfadeFullLayout = false; if (buildFullLayout) { CharSequence string = TextUtils.ellipsize(text, textPaint, width, TextUtils.TruncateAt.END); if (!string.equals(text)) { fullLayout = StaticLayoutEx.createStaticLayout(text, 0, text.length(), textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, 3, false); if (fullLayout != null) { - if (LocaleController.isRTL || fullLayout.isRtlCharAt(0) && fullLayoutAdditionalWidth != 0) { - layout = StaticLayoutEx.createStaticLayout(text, 0, text.length(), textPaint, width + AndroidUtilities.dp(8), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, maxLines, false); - fullLayout = StaticLayoutEx.createStaticLayout(text, 0, text.length(), textPaint, width + fullLayoutAdditionalWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width + fullLayoutAdditionalWidth, 3, false); - partLayout = null; - firstLineLayout = null; - crosfadeFullLayout = true; + + int end = fullLayout.getLineEnd(0); + int start = fullLayout.getLineStart(1); + CharSequence substr = text.subSequence(0, end); + SpannableStringBuilder full = SpannableStringBuilder.valueOf(text); + full.setSpan(new EmptyStubSpan(), 0, start, 0); + CharSequence part; + if (end < string.length()) { + part = string.subSequence(end, string.length()); } else { - int end = fullLayout.getLineEnd(0); - int start = fullLayout.getLineStart(1); - CharSequence substr = text.subSequence(0, end); - SpannableStringBuilder full = SpannableStringBuilder.valueOf(text); - full.setSpan(new EmptyStubSpan(), 0, start, 0); - CharSequence part; - if (end < string.length()) { - part = string.subSequence(end, string.length()); - } else { - part = "…"; - } - firstLineLayout = new StaticLayout(string, 0, string.length(), textPaint, scrollNonFitText ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - layout = new StaticLayout(substr, 0, substr.length(), textPaint, scrollNonFitText ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - if (layout.getLineLeft(0) != 0) { - part = "\u200F" + part; - } - partLayout = new StaticLayout(part, 0, part.length(), textPaint, scrollNonFitText ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - fullLayout = StaticLayoutEx.createStaticLayout(full, 0, full.length(), textPaint, width + fullLayoutAdditionalWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width + fullLayoutAdditionalWidth, 3, false); + part = "…"; + } + firstLineLayout = new StaticLayout(string, 0, string.length(), textPaint, scrollNonFitText ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + layout = new StaticLayout(substr, 0, substr.length(), textPaint, scrollNonFitText ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (layout.getLineLeft(0) != 0) { + part = "\u200F" + part; } + partLayout = new StaticLayout(part, 0, part.length(), textPaint, scrollNonFitText ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + fullLayout = StaticLayoutEx.createStaticLayout(full, 0, full.length(), textPaint, width + AndroidUtilities.dp(8) + fullLayoutAdditionalWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width + fullLayoutAdditionalWidth, 3, false); } } else { layout = new StaticLayout(string, 0, string.length(), textPaint, scrollNonFitText ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); @@ -579,7 +573,7 @@ protected void onDraw(Canvas canvas) { } else { canvas.translate(layout.getLineWidth(0) - (partLayout.getText().length() == 1 ? AndroidUtilities.dp(4) : 0), 0); } - canvas.translate(-fullLayoutLeftOffset * fullAlpha, 0); + canvas.translate(-fullLayoutLeftOffset * fullAlpha + fullLayoutLeftCharactersOffset * fullAlpha, 0); partLayout.draw(canvas); canvas.restore(); textPaint.setAlpha(prevAlpha); @@ -588,10 +582,7 @@ protected void onDraw(Canvas canvas) { int prevAlpha = textPaint.getAlpha(); textPaint.setAlpha((int) (255 * fullAlpha)); - if (layout.getLineLeft(0) != 0) { - canvas.translate(-offsetX, 0); - } - canvas.translate(-fullLayoutLeftOffset * fullAlpha, 0); + canvas.translate(-fullLayoutLeftOffset * fullAlpha + fullLayoutLeftCharactersOffset * fullAlpha - fullLayoutLeftCharactersOffset, 0); fullLayout.draw(canvas); textPaint.setAlpha(prevAlpha); } @@ -625,17 +616,9 @@ protected void onDraw(Canvas canvas) { } private void drawLayout(Canvas canvas) { - if (crosfadeFullLayout && fullAlpha > 0) { - int prevAlpha = textPaint.getAlpha(); - textPaint.setAlpha((int) (255 * (1f - fullAlpha))); + if (fullAlpha > 0 && fullLayoutLeftOffset != 0) { canvas.save(); - canvas.translate(-fullLayoutLeftOffset * fullAlpha, 0); - layout.draw(canvas); - textPaint.setAlpha(prevAlpha); - canvas.restore(); - } else if (fullAlpha > 0 && fullLayoutLeftOffset != 0) { - canvas.save(); - canvas.translate(-fullLayoutLeftOffset * fullAlpha, 0); + canvas.translate(-fullLayoutLeftOffset * fullAlpha + fullLayoutLeftCharactersOffset * fullAlpha, 0); layout.draw(canvas); canvas.restore(); } else { @@ -703,6 +686,9 @@ public void setFullLayoutAdditionalWidth(int fullLayoutAdditionalWidth, int full this.fullLayoutLeftOffset = fullLayoutLeftOffset; createLayout(getMeasuredWidth()); } + } + public int getTextColor() { + return textPaint.getColor(); } } 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 367cafc4071..3f21352f7e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -2172,6 +2172,7 @@ public void run() { public static Drawable chat_replyIconDrawable; public static Drawable chat_goIconDrawable; public static Drawable chat_botLinkDrawalbe; + public static Drawable chat_botCardDrawalbe; public static Drawable chat_botInlineDrawable; public static Drawable chat_systemDrawable; public static Drawable chat_commentDrawable; @@ -7202,6 +7203,7 @@ public static void createChatResources(Context context, boolean fontsOnly) { chat_botLinkDrawalbe = resources.getDrawable(R.drawable.bot_link); chat_botInlineDrawable = resources.getDrawable(R.drawable.bot_lines); + chat_botCardDrawalbe = resources.getDrawable(R.drawable.bot_card); chat_commentDrawable = resources.getDrawable(R.drawable.msg_msgbubble); chat_commentStickerDrawable = resources.getDrawable(R.drawable.msg_msgbubble2); 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 d958a19c8a0..28b4661cba5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -204,8 +204,6 @@ public int getItemCount() { if (folderId == 0 && onlineContacts != null) { if (!hasContacts) { onlineContacts = null; - } else { - MessagesController.getInstance(currentAccount).preloadGreetingsSticker(); } } if (folderId == 1 && showArchiveHint) { @@ -508,12 +506,6 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { } cell.setChecked(selectedDialogs.contains(dialog.id), false); cell.setDialog(dialog, dialogsType, folderId); - if ((int) dialog.id > 0) { - MessageObject message = MessagesController.getInstance(currentAccount).dialogMessage.get(dialog.id); - if (MessageObject.isSystemSignUp(message)) { - MessagesController.getInstance(currentAccount).preloadGreetingsSticker(); - } - } if (preloader != null && i < 10) { preloader.add(dialog.id); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java index 79ecc9a1609..ef6bc038cea 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java @@ -304,7 +304,7 @@ private void resetItems() { items.add(new Item(8, LocaleController.getString("Settings", R.string.Settings), settingsIcon)); items.add(null); // divider items.add(new Item(7, LocaleController.getString("InviteFriends", R.string.InviteFriends), inviteIcon)); - items.add(new Item(9, LocaleController.getString("TelegramFAQ", R.string.TelegramFAQ), helpIcon)); + items.add(new Item(13, LocaleController.getString("TelegramFeatures", R.string.TelegramFeatures), helpIcon)); } public int getId(int position) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java index cbbf4cff19f..4e4b52869da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java @@ -40,7 +40,6 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; -import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; @@ -49,7 +48,6 @@ import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Calendar; -import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.regex.Matcher; @@ -730,12 +728,12 @@ public void setData(MediaFilterData data) { avatarImageView.setImageDrawable(combinedDrawable); } else { avatarImageView.getImageReceiver().setRoundRadius(AndroidUtilities.dp(16)); - avatarImageView.getImageReceiver().setImage(ImageLocation.getForUser(user, false), "50_50", thumbDrawable, null, user, 0); + avatarImageView.getImageReceiver().setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", thumbDrawable, user, 0); } } else if (data.chat instanceof TLRPC.Chat) { TLRPC.Chat chat = (TLRPC.Chat) data.chat; avatarImageView.getImageReceiver().setRoundRadius(AndroidUtilities.dp(16)); - avatarImageView.getImageReceiver().setImage(ImageLocation.getForChat(chat, false), "50_50", thumbDrawable, null, chat, 0); + avatarImageView.getImageReceiver().setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", thumbDrawable, chat, 0); } } else { avatarImageView.setImageDrawable(thumbDrawable); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index 9a975dd7d8d..f3464151a1f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -290,6 +290,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg TextSelectionHelper.ArticleTextSelectionHelper textSelectionHelper; TextSelectionHelper.ArticleTextSelectionHelper textSelectionHelperBottomSheet; + PinchToZoomHelper pinchToZoomHelper; + private int allowAnimationIndex = -1; private final String BOTTOM_SHEET_VIEW_TAG = "bottomSheet"; @@ -707,6 +709,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override public boolean dispatchTouchEvent(MotionEvent ev) { + if (pinchToZoomHelper.isInOverlayMode()) { + ev.offsetLocation(-containerView.getX(), -containerView.getY()); + return pinchToZoomHelper.onTouchEvent(ev); + } TextSelectionHelper.TextSelectionOverlay selectionOverlay = textSelectionHelper.getOverlayView(getContext()); MotionEvent textSelectionEv = MotionEvent.obtain(ev); textSelectionEv.offsetLocation(-containerView.getX(), -containerView.getY()); @@ -3657,6 +3663,22 @@ public void onTextCopied() { }); containerView.addView(textSelectionHelper.getOverlayView(activity)); + pinchToZoomHelper = new PinchToZoomHelper(containerView); + pinchToZoomHelper.setClipBoundsListener(new PinchToZoomHelper.ClipBoundsListener() { + @Override + public void getClipTopBottom(float[] topBottom) { + topBottom[0] = currentHeaderHeight; + topBottom[1] = listView[0].getMeasuredHeight(); + } + }); + pinchToZoomHelper.setCallback(new PinchToZoomHelper.Callback() { + @Override + public void onZoomStarted(MessageObject messageObject) { + if (listView[0] != null) { + listView[0].cancelClickRunnables(true); + } + } + }); updatePaintColors(); } @@ -5952,6 +5974,9 @@ public View getChannelCell() { @Override public boolean onTouchEvent(MotionEvent event) { + if (pinchToZoomHelper.checkPinchToZoom(event, this, imageView, null)) { + return true; + } float x = event.getX(); float y = event.getY(); if (channelCell.getVisibility() == VISIBLE && y > channelCell.getTranslationY() && y < channelCell.getTranslationY() + AndroidUtilities.dp(39)) { @@ -6118,9 +6143,11 @@ protected void onDraw(Canvas canvas) { if (!imageView.hasBitmapImage() || imageView.getCurrentAlpha() != 1.0f) { canvas.drawRect(imageView.getDrawRegion(), photoBackgroundPaint); } - imageView.draw(canvas); - if (imageView.getVisible()) { - radialProgress.draw(canvas); + if (!pinchToZoomHelper.isInOverlayModeFor(this)) { + imageView.draw(canvas); + if (imageView.getVisible()) { + radialProgress.draw(canvas); + } } int count = 0; if (captionLayout != null) { @@ -9831,6 +9858,9 @@ public View getChannelCell() { @Override public boolean onTouchEvent(MotionEvent event) { + if (pinchToZoomHelper.checkPinchToZoom(event, this, imageView, null)) { + return true; + } float x = event.getX(); float y = event.getY(); if (channelCell.getVisibility() == VISIBLE && y > channelCell.getTranslationY() && y < channelCell.getTranslationY() + AndroidUtilities.dp(39)) { @@ -9992,9 +10022,11 @@ protected void onDraw(Canvas canvas) { if (!imageView.hasBitmapImage() || imageView.getCurrentAlpha() != 1.0f) { canvas.drawRect(imageView.getImageX(), imageView.getImageY(), imageView.getImageX2(), imageView.getImageY2(), photoBackgroundPaint); } - imageView.draw(canvas); - if (imageView.getVisible()) { - radialProgress.draw(canvas); + if (!pinchToZoomHelper.isInOverlayModeFor(this)) { + imageView.draw(canvas); + if (imageView.getVisible()) { + radialProgress.draw(canvas); + } } if (!TextUtils.isEmpty(currentBlock.url)) { int x = getMeasuredWidth() - AndroidUtilities.dp(11 + 24); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/AvatarPreviewer.java b/TMessagesProj/src/main/java/org/telegram/ui/AvatarPreviewer.java index 67fd91bb797..3d9eceb181d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/AvatarPreviewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/AvatarPreviewer.java @@ -163,15 +163,15 @@ public static enum MenuItem { public static class Data { public static Data of(TLRPC.User user, int classGuid, MenuItem... menuItems) { - final ImageLocation imageLocation = ImageLocation.getForUser(user, true); - final ImageLocation thumbImageLocation = ImageLocation.getForUser(user, false); + final ImageLocation imageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_BIG); + final ImageLocation thumbImageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL); final String thumbFilter = thumbImageLocation != null && thumbImageLocation.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; return new Data(imageLocation, thumbImageLocation, null, null, thumbFilter, null, null, user, menuItems, new UserInfoLoadTask(user, classGuid)); } public static Data of(TLRPC.UserFull userFull, MenuItem... menuItems) { - final ImageLocation imageLocation = ImageLocation.getForUser(userFull.user, true); - final ImageLocation thumbImageLocation = ImageLocation.getForUser(userFull.user, false); + final ImageLocation imageLocation = ImageLocation.getForUserOrChat(userFull.user, ImageLocation.TYPE_BIG); + final ImageLocation thumbImageLocation = ImageLocation.getForUserOrChat(userFull.user, ImageLocation.TYPE_SMALL); final String thumbFilter = thumbImageLocation != null && thumbImageLocation.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; final ImageLocation videoLocation; final String videoFileName; @@ -188,15 +188,15 @@ public static Data of(TLRPC.UserFull userFull, MenuItem... menuItems) { } public static Data of(TLRPC.Chat chat, int classGuid, MenuItem... menuItems) { - final ImageLocation imageLocation = ImageLocation.getForChat(chat, true); - final ImageLocation thumbImageLocation = ImageLocation.getForChat(chat, false); + final ImageLocation imageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_BIG); + final ImageLocation thumbImageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL); final String thumbFilter = thumbImageLocation != null && thumbImageLocation.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; return new Data(imageLocation, thumbImageLocation, null, null, thumbFilter, null, null, chat, menuItems, new ChatInfoLoadTask(chat, classGuid)); } public static Data of(TLRPC.Chat chat, TLRPC.ChatFull chatFull, MenuItem... menuItems) { - final ImageLocation imageLocation = ImageLocation.getForChat(chat, true); - final ImageLocation thumbImageLocation = ImageLocation.getForChat(chat, false); + final ImageLocation imageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_BIG); + final ImageLocation thumbImageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL); final String thumbFilter = thumbImageLocation != null && thumbImageLocation.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; final ImageLocation videoLocation; final String videoFileName; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java index 5ca7406f51e..8daa702c2f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java @@ -25,6 +25,7 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.telephony.PhoneNumberUtils; @@ -553,8 +554,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); - Intent mailer = new Intent(Intent.ACTION_SEND); - mailer.setType("message/rfc822"); + Intent mailer = new Intent(Intent.ACTION_SENDTO); + mailer.setData(Uri.parse("mailto:")); mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"}); mailer.putExtra(Intent.EXTRA_SUBJECT, "Android cancel account deletion issue " + version + " " + phone); mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + phone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java index 6dc5efb735b..b770c86e7ce 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java @@ -110,12 +110,12 @@ public void setObject(TLObject object) { TLRPC.User user = (TLRPC.User) object; avatarDrawable.setInfo(user); infoTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } else { TLRPC.Chat chat = (TLRPC.Chat) object; avatarDrawable.setInfo(chat); infoTextView.setText(chat.title); - imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + imageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } } @@ -125,7 +125,7 @@ public void setAccount(int account, boolean check) { avatarDrawable.setInfo(user); textView.setText(ContactsController.formatName(user.first_name, user.last_name)); imageView.getImageReceiver().setCurrentAccount(account); - imageView.setImage(ImageLocation.getForUser(user,false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user,ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); checkImageView.setVisibility(check && account == UserConfig.selectedAccount ? VISIBLE : INVISIBLE); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java index 833781d5d91..f5fc04de19d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java @@ -81,7 +81,7 @@ public void setChannel(TLRPC.Chat channel, boolean last) { SpannableStringBuilder stringBuilder = new SpannableStringBuilder(url + channel.username); stringBuilder.setSpan(new URLSpanNoUnderline(""), url.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); statusTextView.setText(stringBuilder); - avatarImageView.setImage(ImageLocation.getForChat(channel, false), "50_50", avatarDrawable, currentChannel); + avatarImageView.setImage(ImageLocation.getForUserOrChat(channel, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(channel, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentChannel); isLast = last; } 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 a94138042e5..a53acbce7fb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -126,6 +126,7 @@ import org.telegram.ui.Components.URLSpanMono; import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.PhotoViewer; +import org.telegram.ui.PinchToZoomHelper; import org.telegram.ui.SecretMediaViewer; import java.io.File; @@ -257,6 +258,11 @@ default void onDiceFinished() { default boolean shouldDrawThreadProgress(ChatMessageCell cell) { return false; } + + default PinchToZoomHelper getPinchToZoomHelper() { + return null; + } + } private final static int DOCUMENT_ATTACH_TYPE_NONE = 0; @@ -775,6 +781,7 @@ public void run() { }; private SparseArray accessibilityVirtualViewBounds = new SparseArray<>(); private int currentFocusedVirtualView = -1; + public boolean drawFromPinchToZoom; public ChatMessageCell(Context context) { super(context); @@ -1930,6 +1937,9 @@ public boolean onTouchEvent(MotionEvent event) { boolean result = checkTextBlockMotionEvent(event); + if (!result) { + result = checkPinchToZoom(event); + } if (!result) { result = checkDateMotionEvent(event); } @@ -2196,6 +2206,17 @@ public boolean onTouchEvent(MotionEvent event) { return result; } + + private boolean checkPinchToZoom(MotionEvent ev) { + PinchToZoomHelper pinchToZoomHelper = delegate == null ? null : delegate.getPinchToZoomHelper(); + if (currentMessageObject == null || !photoImage.hasNotThumb() || pinchToZoomHelper == null || currentMessageObject.isSticker() || + currentMessageObject.isAnimatedEmoji() || (currentMessageObject.isVideo() && !autoPlayingMedia) || + currentMessageObject.isRoundVideo() || currentMessageObject.isAnimatedSticker() || (currentMessageObject.isDocument() && !currentMessageObject.isGif()) || currentMessageObject.needDrawBluredPreview()) { + return false; + } + return pinchToZoomHelper.checkPinchToZoom(ev, this, photoImage, currentMessageObject); + } + private boolean checkTextSelection(MotionEvent event) { TextSelectionHelper.ChatListTextSelectionHelper textSelectionHelper = delegate.getTextSelectionHelper(); if (textSelectionHelper == null) { @@ -3144,10 +3165,10 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } if (user != null) { commentAvatarDrawables[a].setInfo(user); - commentAvatarImages[a].setImage(ImageLocation.getForUser(user, false), "50_50", commentAvatarDrawables[a], null, user, 0); + commentAvatarImages[a].setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", commentAvatarDrawables[a], user, 0); } else if (chat != null) { commentAvatarDrawables[a].setInfo(chat); - commentAvatarImages[a].setImage(ImageLocation.getForChat(chat, false), "50_50", commentAvatarDrawables[a], null, chat, 0); + commentAvatarImages[a].setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", commentAvatarDrawables[a], chat, 0); } else { commentAvatarDrawables[a].setInfo(id, "", ""); } @@ -3236,9 +3257,9 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe hasInvoicePreview = messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice; hasLinkPreview = !messageObject.isRestrictedMessage && messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage; drawInstantView = hasLinkPreview && messageObject.messageOwner.media.webpage.cached_page != null; - hasEmbed = hasLinkPreview && !TextUtils.isEmpty(messageObject.messageOwner.media.webpage.embed_url) && !messageObject.isGif(); - boolean slideshow = false; String siteName = hasLinkPreview ? messageObject.messageOwner.media.webpage.site_name : null; + hasEmbed = hasLinkPreview && !TextUtils.isEmpty(messageObject.messageOwner.media.webpage.embed_url) && !messageObject.isGif() && !"instangram".equalsIgnoreCase(siteName); + boolean slideshow = false; String webpageType = hasLinkPreview ? messageObject.messageOwner.media.webpage.type : null; TLRPC.Document androidThemeDocument = null; TLRPC.TL_themeSettings androidThemeSettings = null; @@ -3908,8 +3929,21 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe width = height = maxPhotoWidth; } else { if (hasGamePreview || hasInvoicePreview) { - width = 640; - height = 360; + if (hasInvoicePreview) { + width = 640; + height = 360; + for (int a = 0, N = webDocument.attributes.size(); a < N; a++) { + TLRPC.DocumentAttribute attribute = webDocument.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { + width = attribute.w; + height = attribute.h; + break; + } + } + } else { + width = 640; + height = 360; + } float scale = width / (float) (maxPhotoWidth - AndroidUtilities.dp(2)); width /= scale; height /= scale; @@ -4202,7 +4236,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } else { hasName = false; } - photoImage.setImage(ImageLocation.getForUser(user, false), "50_50", hasName ? contactAvatarDrawable : Theme.chat_contactDrawable[messageObject.isOutOwner() ? 1 : 0], null, messageObject, 0); + photoImage.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", hasName ? contactAvatarDrawable : Theme.chat_contactDrawable[messageObject.isOutOwner() ? 1 : 0], messageObject, 0); CharSequence phone; if (!TextUtils.isEmpty(messageObject.vCardData)) { @@ -4394,7 +4428,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(id); if (user != null) { pollAvatarDrawables[a].setInfo(user); - pollAvatarImages[a].setImage(ImageLocation.getForUser(user, false), "50_50", pollAvatarDrawables[a], null, user, 0); + pollAvatarImages[a].setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", pollAvatarDrawables[a], user, 0); } else { pollAvatarDrawables[a].setInfo(id, "", ""); } @@ -4728,13 +4762,13 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe updateCurrentUserAndChat(); if (currentUser != null) { contactAvatarDrawable.setInfo(currentUser); - locationImageReceiver.setImage(ImageLocation.getForUser(currentUser, false), "50_50", contactAvatarDrawable, null, currentUser, 0); + locationImageReceiver.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", contactAvatarDrawable, currentUser, 0); } else if (currentChat != null) { if (currentChat.photo != null) { currentPhoto = currentChat.photo.photo_small; } contactAvatarDrawable.setInfo(currentChat); - locationImageReceiver.setImage(ImageLocation.getForChat(currentChat, false), "50_50", contactAvatarDrawable, null, currentChat, 0); + locationImageReceiver.setImage(ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_STRIPPED), "50_50", contactAvatarDrawable, currentChat, 0); } else { locationImageReceiver.setImage(null, null, contactAvatarDrawable, null, null, 0); } @@ -4809,7 +4843,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } else if (currentMapProvider == 2) { if (currentWebFile != null) { ImageLocation lastLocation = lastWebFile == null ? null : ImageLocation.getForWebFile(lastWebFile); - photoImage.setImage(ImageLocation.getForWebFile(currentWebFile), null, lastLocation, null, null, messageObject, 0); + photoImage.setImage(ImageLocation.getForWebFile(currentWebFile), null, lastLocation, null, (Drawable) null, messageObject, 0); } } else { if (currentMapProvider == 3 || currentMapProvider == 4) { @@ -7097,7 +7131,9 @@ private void drawContent(Canvas canvas) { buttonY = this.buttonY = (int) (photoImage.getImageY() + (photoImage.getImageHeight() - size) / 2.0f); radialProgress.setProgressRect((int) buttonX, (int ) buttonY, (int) buttonX + size, (int) buttonY + size); } - imageDrawn = photoImage.draw(canvas); + if (delegate == null || delegate.getPinchToZoomHelper() == null || !delegate.getPinchToZoomHelper().isInOverlayModeFor(this)) { + imageDrawn = photoImage.draw(canvas); + } } linkPreviewY += photoImage.getImageHeight() + AndroidUtilities.dp(6); } @@ -7180,7 +7216,9 @@ private void drawContent(Canvas canvas) { imageDrawn = true; drawTime = true; } else { - imageDrawn = photoImage.draw(canvas); + if (delegate == null || delegate.getPinchToZoomHelper() == null || !delegate.getPinchToZoomHelper().isInOverlayModeFor(this)) { + imageDrawn = photoImage.draw(canvas); + } } } if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { @@ -7330,7 +7368,9 @@ private void drawContent(Canvas canvas) { } else { photoImage.setSideClip(0); } - imageDrawn = photoImage.draw(canvas); + if (delegate == null || delegate.getPinchToZoomHelper() == null || !delegate.getPinchToZoomHelper().isInOverlayModeFor(this)) { + imageDrawn = photoImage.draw(canvas); + } boolean drawTimeOld = drawTime; drawTime = photoImage.getVisible(); if (currentPosition != null && drawTimeOld != drawTime) { @@ -7796,11 +7836,19 @@ private void drawBotButtons(Canvas canvas, ArrayList botButtons, floa setDrawableBounds(Theme.chat_botInlineDrawable, x, y + AndroidUtilities.dp(3)); Theme.chat_botInlineDrawable.draw(canvas); } else if (button.button instanceof TLRPC.TL_keyboardButtonCallback || button.button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation || button.button instanceof TLRPC.TL_keyboardButtonGame || button.button instanceof TLRPC.TL_keyboardButtonBuy || button.button instanceof TLRPC.TL_keyboardButtonUrlAuth) { + if (button.button instanceof TLRPC.TL_keyboardButtonBuy) { + int x = button.x + button.width - AndroidUtilities.dp(5) - Theme.chat_botCardDrawalbe.getIntrinsicWidth() + addX; + setDrawableBounds(Theme.chat_botCardDrawalbe, x, y + AndroidUtilities.dp(4)); + Theme.chat_botCardDrawalbe.draw(canvas); + } boolean drawProgress = (button.button instanceof TLRPC.TL_keyboardButtonCallback || button.button instanceof TLRPC.TL_keyboardButtonGame || button.button instanceof TLRPC.TL_keyboardButtonBuy || button.button instanceof TLRPC.TL_keyboardButtonUrlAuth) && SendMessagesHelper.getInstance(currentAccount).isSendingCallback(currentMessageObject, button.button) || button.button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation && SendMessagesHelper.getInstance(currentAccount).isSendingCurrentLocation(currentMessageObject, button.button); if (drawProgress || button.progressAlpha != 0) { Theme.chat_botProgressPaint.setAlpha(Math.min(255, (int) (button.progressAlpha * 255))); int x = button.x + button.width - AndroidUtilities.dp(9 + 3) + addX; + if (button.button instanceof TLRPC.TL_keyboardButtonBuy) { + y += AndroidUtilities.dp(26); + } rect.set(x, y + AndroidUtilities.dp(4), x + AndroidUtilities.dp(8), y + AndroidUtilities.dp(8 + 4)); canvas.drawArc(rect, button.angle, 220, false, Theme.chat_botProgressPaint); invalidate(); @@ -9150,7 +9198,7 @@ private void setMessageObjectInternal(MessageObject messageObject) { currentPhoto = null; } avatarDrawable.setInfo(currentUser); - avatarImage.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, null, currentUser, 0); + avatarImage.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser, 0); } else if (currentChat != null) { if (currentChat.photo != null) { currentPhoto = currentChat.photo.photo_small; @@ -9158,7 +9206,7 @@ private void setMessageObjectInternal(MessageObject messageObject) { currentPhoto = null; } avatarDrawable.setInfo(currentChat); - avatarImage.setImage(ImageLocation.getForChat(currentChat, false), "50_50", avatarDrawable, null, currentChat, 0); + avatarImage.setImage(ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentChat, 0); } else { currentPhoto = null; avatarDrawable.setInfo(messageObject.getFromChatId(), null, null); @@ -11020,7 +11068,7 @@ public boolean needDrawTime() { return !forceNotDrawTime; } - private boolean shouldDrawTimeOnMedia() { + public boolean shouldDrawTimeOnMedia() { if (overideShouldDrawTimeOnMedia != 0) { return overideShouldDrawTimeOnMedia == 1; } @@ -11028,6 +11076,9 @@ private boolean shouldDrawTimeOnMedia() { } public void drawTime(Canvas canvas, float alpha, boolean fromParent) { + if (!drawFromPinchToZoom && delegate != null && delegate.getPinchToZoomHelper() != null && delegate.getPinchToZoomHelper().isInOverlayModeFor(this) && shouldDrawTimeOnMedia()) { + return; + } for (int i = 0; i < 2; i++) { float curentAplha = alpha; if (i == 0 && isDrawSelectionBackground() && currentSelectedBackgroundAlpha == 1f && !shouldDrawTimeOnMedia()) { @@ -11828,6 +11879,9 @@ private void drawStatusDrawable(Canvas canvas, boolean drawCheck1, boolean drawC } public void drawOverlays(Canvas canvas) { + if (!drawFromPinchToZoom && delegate != null && delegate.getPinchToZoomHelper() != null && delegate.getPinchToZoomHelper().isInOverlayModeFor(this)) { + return; + } long newAnimationTime = SystemClock.elapsedRealtime(); long animationDt = newAnimationTime - lastAnimationTime; if (animationDt > 17) { @@ -13127,6 +13181,9 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { info.setParent(ChatMessageCell.this); info.setPackageName(getContext().getPackageName()); if (virtualViewId >= LINK_IDS_START) { + if (!(currentMessageObject.messageText instanceof Spannable)) { + return null; + } Spannable buffer = (Spannable) currentMessageObject.messageText; ClickableSpan link = getLinkById(virtualViewId); if (link == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxUserCell.java index 040e158e915..490c179fea1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxUserCell.java @@ -77,7 +77,7 @@ public void setUser(TLRPC.User user, boolean checked, boolean divider) { textView.setText(ContactsController.formatName(user.first_name, user.last_name)); checkBox.setChecked(checked, false); avatarDrawable.setInfo(user); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); needDivider = divider; setWillNotDraw(!divider); } 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 0b46bad2acc..ef3c8af61cb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -981,7 +981,7 @@ public void buildLayout() { } thumbImage.setImage(ImageLocation.getForObject(bigThumb, message.photoThumbsObject), "20_20", ImageLocation.getForObject(smallThumb, message.photoThumbsObject), "20_20", size, null, message, 0); } else { - thumbImage.setImage(null, null, ImageLocation.getForObject(smallThumb, message.photoThumbsObject), "20_20", null, message, 0); + thumbImage.setImage(null, null, ImageLocation.getForObject(smallThumb, message.photoThumbsObject), "20_20", (Drawable) null, message, 0); } needEmoji = false; } @@ -2113,11 +2113,11 @@ public void update(int mask, boolean animated) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); avatarImage.setImage(null, null, avatarDrawable, null, user, 0); } else { - avatarImage.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, null, user, 0); + avatarImage.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user, 0); } } else if (chat != null) { avatarDrawable.setInfo(chat); - avatarImage.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, null, chat, 0); + avatarImage.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat, 0); } } @@ -2236,7 +2236,10 @@ protected void onDraw(Canvas canvas) { boolean needInvalidate = false; if (currentDialogFolderId != 0 && archivedChatsDrawable != null && archivedChatsDrawable.outProgress == 0.0f && translationX == 0.0f) { + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); archivedChatsDrawable.draw(canvas); + canvas.restore(); return; } @@ -2892,7 +2895,10 @@ protected void onDraw(Canvas canvas) { canvas.restore(); } if (currentDialogFolderId != 0 && translationX == 0 && archivedChatsDrawable != null) { + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); archivedChatsDrawable.draw(canvas); + canvas.restore(); } if (useSeparator) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java index 9d6db96b2ea..d4226ea9598 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java @@ -129,7 +129,7 @@ public void buildLayout() { } nameString = chat.title; avatarDrawable.setInfo(chat); - avatarImage.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, null, recentMeUrl, 0); + avatarImage.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, recentMeUrl, 0); } else if (recentMeUrl instanceof TLRPC.TL_recentMeUrlUser) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(recentMeUrl.user_id); if (!LocaleController.isRTL) { @@ -153,7 +153,7 @@ public void buildLayout() { } nameString = UserObject.getUserName(user); avatarDrawable.setInfo(user); - avatarImage.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, null, recentMeUrl, 0); + avatarImage.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, recentMeUrl, 0); } else if (recentMeUrl instanceof TLRPC.TL_recentMeUrlStickerSet) { if (!LocaleController.isRTL) { nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); @@ -180,7 +180,7 @@ public void buildLayout() { nameLockTop = AndroidUtilities.dp(17.5f); } drawVerified = recentMeUrl.chat_invite.chat.verified; - avatarImage.setImage(ImageLocation.getForChat(recentMeUrl.chat_invite.chat, false), "50_50", avatarDrawable, null, recentMeUrl, 0); + avatarImage.setImage(ImageLocation.getForUserOrChat(recentMeUrl.chat_invite.chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(recentMeUrl.chat_invite.chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, recentMeUrl, 0); } else { nameString = recentMeUrl.chat_invite.title; avatarDrawable.setInfo(5, recentMeUrl.chat_invite.title, null); 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 112a8d31521..c24c458dcf6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java @@ -351,7 +351,7 @@ public void setUser(TLRPC.User user, boolean accounts) { phoneTextView.setText(PhoneFormat.getInstance().format("+" + user.phone)); AvatarDrawable avatarDrawable = new AvatarDrawable(user); avatarDrawable.setColor(Theme.getColor(Theme.key_avatar_backgroundInProfileBlue)); - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); applyBackground(true); } 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 7b7650656f4..53a9857bd46 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java @@ -91,7 +91,7 @@ public void setAccount(int account) { avatarDrawable.setInfo(user); textView.setText(ContactsController.formatName(user.first_name, user.last_name)); imageView.getImageReceiver().setCurrentAccount(account); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); checkBox.setVisibility(account == UserConfig.selectedAccount ? VISIBLE : INVISIBLE); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java index e7a5e73ecd9..9d33cfb42b9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java @@ -91,7 +91,7 @@ public void setData(int account, Integer uid) { nameTextView.setText(lastName); avatarImageView.getImageReceiver().setCurrentAccount(account); - avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser); } public void setDrawDivider(boolean draw) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java index bbfd123fa1d..2e5d92d719e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java @@ -45,8 +45,8 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; +import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.WaveDrawable; -import org.telegram.ui.ProfileActivity; import java.util.ArrayList; @@ -57,10 +57,13 @@ public class GroupCallUserCell extends FrameLayout { private BackupImageView avatarImageView; private SimpleTextView nameTextView; private SimpleTextView[] statusTextView = new SimpleTextView[5]; + private SimpleTextView fullAboutTextView; private RLottieImageView muteButton; private RLottieDrawable muteDrawable; private RLottieDrawable shakeHandDrawable; + private RadialProgressView avatarProgressView; + private AvatarDrawable avatarDrawable; private ChatObject.Call currentCall; @@ -81,7 +84,6 @@ public class GroupCallUserCell extends FrameLayout { private int currentStatus; private int selfId; - private Runnable shakeHandCallback = () -> { shakeHandDrawable.setOnFinishCallback(null, 0); muteDrawable.setOnFinishCallback(null, 0); @@ -132,6 +134,7 @@ public class GroupCallUserCell extends FrameLayout { private boolean updateRunnableScheduled; private boolean updateVoiceRunnableScheduled; private boolean isSpeaking; + private boolean hasAvatar; private Drawable speakingDrawable; @@ -142,17 +145,29 @@ public class GroupCallUserCell extends FrameLayout { public void setProgressToAvatarPreview(float progressToAvatarPreview) { this.progressToAvatarPreview = progressToAvatarPreview; nameTextView.setTranslationX((LocaleController.isRTL ? AndroidUtilities.dp(53) : -AndroidUtilities.dp(53)) * progressToAvatarPreview); - for (int i = 0; i < statusTextView.length; i++) { - if (!TextUtils.isEmpty(statusTextView[4].getText()) && statusTextView[4].getLineCount() > 1) { - statusTextView[i].setFullLayoutAdditionalWidth(AndroidUtilities.dp(92), LocaleController.isRTL ? AndroidUtilities.dp(48) : AndroidUtilities.dp(53)); - statusTextView[i].setFullAlpha(progressToAvatarPreview); - statusTextView[i].setTranslationX(0); - statusTextView[i].invalidate(); - } else { - statusTextView[i].setTranslationX((LocaleController.isRTL ? AndroidUtilities.dp(53) : -AndroidUtilities.dp(53)) * progressToAvatarPreview); - statusTextView[i].setFullLayoutAdditionalWidth(0, 0); + + if (isSelfUser() && progressToAvatarPreview > 0) { + fullAboutTextView.setTranslationX((LocaleController.isRTL ? -AndroidUtilities.dp(53) : AndroidUtilities.dp(53)) * (1f - progressToAvatarPreview)); + fullAboutTextView.setVisibility(View.VISIBLE); + fullAboutTextView.setAlpha(progressToAvatarPreview); + statusTextView[4].setAlpha(1f - progressToAvatarPreview); + statusTextView[4].setTranslationX((LocaleController.isRTL ? AndroidUtilities.dp(53) : -AndroidUtilities.dp(53)) * progressToAvatarPreview); + } else { + fullAboutTextView.setVisibility(View.GONE); + + for (int i = 0; i < statusTextView.length; i++) { + if (!TextUtils.isEmpty(statusTextView[4].getText()) && statusTextView[4].getLineCount() > 1) { + statusTextView[i].setFullLayoutAdditionalWidth(AndroidUtilities.dp(92), LocaleController.isRTL ? AndroidUtilities.dp(48) : AndroidUtilities.dp(53)); + statusTextView[i].setFullAlpha(progressToAvatarPreview); + statusTextView[i].setTranslationX(0); + statusTextView[i].invalidate(); + } else { + statusTextView[i].setTranslationX((LocaleController.isRTL ? AndroidUtilities.dp(53) : -AndroidUtilities.dp(53)) * progressToAvatarPreview); + statusTextView[i].setFullLayoutAdditionalWidth(0, 0); + } } } + avatarImageView.setAlpha(progressToAvatarPreview == 0 ? 1f : 0); avatarWavesDrawable.setShowWaves(isSpeaking && progressToAvatarPreview == 0, this); @@ -160,6 +175,8 @@ public void setProgressToAvatarPreview(float progressToAvatarPreview) { muteButton.setAlpha(1f - progressToAvatarPreview); muteButton.setScaleX(0.6f + 0.4f * (1f - progressToAvatarPreview)); muteButton.setScaleY(0.6f + 0.4f * (1f - progressToAvatarPreview)); + + invalidate(); } @@ -167,6 +184,15 @@ public AvatarWavesDrawable getAvatarWavesDrawable() { return avatarWavesDrawable; } + public void setUploadProgress(float progress, boolean animated) { + avatarProgressView.setProgress(progress); + if (progress < 1f) { + AndroidUtilities.updateViewVisibilityAnimated(avatarProgressView, true, 1f, animated); + } else { + AndroidUtilities.updateViewVisibilityAnimated(avatarProgressView, false, 1f, animated); + } + } + private static class VerifiedDrawable extends Drawable { private Drawable[] drawables = new Drawable[2]; @@ -227,6 +253,28 @@ public GroupCallUserCell(Context context) { avatarImageView.setRoundRadius(AndroidUtilities.dp(24)); addView(avatarImageView, LayoutHelper.createFrame(46, 46, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 11, 6, LocaleController.isRTL ? 11 : 0, 0)); + avatarProgressView = new RadialProgressView(context) { + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + { + paint.setColor(0x55000000); + } + + @Override + protected void onDraw(Canvas canvas) { + if (avatarImageView.getImageReceiver().hasNotThumb() && avatarImageView.getAlpha() > 0) { + paint.setAlpha((int) (0x55 * avatarImageView.getImageReceiver().getCurrentAlpha() * avatarImageView.getAlpha())); + canvas.drawCircle(getMeasuredWidth() / 2.0f, getMeasuredHeight() / 2.0f, getMeasuredWidth() / 2.0f, paint); + } + avatarProgressView.setProgressColor(ColorUtils.setAlphaComponent(0xffffffff, (int) (255 * avatarImageView.getImageReceiver().getCurrentAlpha() * avatarImageView.getAlpha()))); + super.onDraw(canvas); + } + }; + avatarProgressView.setSize(AndroidUtilities.dp(26)); + avatarProgressView.setProgressColor(0xffffffff); + avatarProgressView.setNoProgress(false); + addView(avatarProgressView, LayoutHelper.createFrame(46, 46, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 11, 6, LocaleController.isRTL ? 11 : 0, 0)); + AndroidUtilities.updateViewVisibilityAnimated(avatarProgressView, false, 1f, false); + nameTextView = new SimpleTextView(context); nameTextView.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -247,15 +295,18 @@ public GroupCallUserCell(Context context) { @Override public void setAlpha(float alpha) { originalAlpha = alpha; + float alphaOverride; if (num == 4) { - float alphaOverride = statusTextView[4].getFullAlpha(); - if (alphaOverride > 0) { + alphaOverride = statusTextView[4].getFullAlpha(); + if (isSelfUser() && progressToAvatarPreview > 0) { + super.setAlpha(1f - progressToAvatarPreview); + } else if (alphaOverride > 0) { super.setAlpha(Math.max(alpha, alphaOverride)); } else { super.setAlpha(alpha); } } else { - float alphaOverride = 1.0f - statusTextView[4].getFullAlpha(); + alphaOverride = 1.0f - statusTextView[4].getFullAlpha(); super.setAlpha(alpha * alphaOverride); } } @@ -306,6 +357,13 @@ public void setFullAlpha(float value) { } } + fullAboutTextView = new SimpleTextView(context); + fullAboutTextView.setMaxLines(3); + fullAboutTextView.setTextSize(15); + fullAboutTextView.setTextColor(Theme.getColor(Theme.key_voipgroup_mutedIcon)); + fullAboutTextView.setVisibility(View.GONE); + addView(fullAboutTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20 * 3, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 14, 32, 14, 0)); + muteDrawable = new RLottieDrawable(R.raw.voice_outlined2, "" + R.raw.voice_outlined2, AndroidUtilities.dp(34), AndroidUtilities.dp(32), true, null); shakeHandDrawable = new RLottieDrawable(R.raw.hand_1, "" + R.raw.hand_1, AndroidUtilities.dp(34), AndroidUtilities.dp(32), true, null); @@ -333,10 +391,16 @@ protected void onMuteClick(GroupCallUserCell cell) { } public int getClipHeight() { - int lineCount = statusTextView[4].getLineCount(); + SimpleTextView aboutTextView; + if (!TextUtils.isEmpty(fullAboutTextView.getText()) && hasAvatar) { + aboutTextView = fullAboutTextView; + } else { + aboutTextView = statusTextView[4]; + } + int lineCount = aboutTextView.getLineCount(); if (lineCount > 1) { - int h = statusTextView[4].getTextHeight(); - return statusTextView[4].getTop() + h + AndroidUtilities.dp(8); + int h = aboutTextView.getTextHeight(); + return aboutTextView.getTop() + h + AndroidUtilities.dp(8); } return getMeasuredHeight(); } @@ -377,7 +441,7 @@ public boolean hasAvatarSet() { return avatarImageView.getImageReceiver().hasNotThumb(); } - public void setData(AccountInstance account, TLRPC.TL_groupCallParticipant groupCallParticipant, ChatObject.Call call, int self) { + public void setData(AccountInstance account, TLRPC.TL_groupCallParticipant groupCallParticipant, ChatObject.Call call, int self, TLRPC.FileLocation uploadingAvatar) { currentCall = call; accountInstance = account; selfId = self; @@ -393,7 +457,14 @@ public void setData(AccountInstance account, TLRPC.TL_groupCallParticipant group nameTextView.setText(UserObject.getUserName(currentUser)); nameTextView.setRightDrawable(currentUser != null && currentUser.verified ? new VerifiedDrawable(getContext()) : null); avatarImageView.getImageReceiver().setCurrentAccount(account.getCurrentAccount()); - avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + if (uploadingAvatar != null) { + hasAvatar = true; + avatarImageView.setImage(ImageLocation.getForLocal(uploadingAvatar), "50_50", avatarDrawable, null); + } else { + ImageLocation imageLocation = ImageLocation.getForUser(currentUser, ImageLocation.TYPE_SMALL); + hasAvatar = imageLocation != null; + avatarImageView.setImage(imageLocation, "50_50", avatarDrawable, currentUser); + } } else { currentChat = accountInstance.getMessagesController().getChat(-id); currentUser = null; @@ -403,9 +474,17 @@ public void setData(AccountInstance account, TLRPC.TL_groupCallParticipant group nameTextView.setText(currentChat.title); nameTextView.setRightDrawable(currentChat.verified ? new VerifiedDrawable(getContext()) : null); avatarImageView.getImageReceiver().setCurrentAccount(account.getCurrentAccount()); - avatarImageView.setImage(ImageLocation.getForChat(currentChat, false), "50_50", avatarDrawable, currentChat); + if (uploadingAvatar != null) { + hasAvatar = true; + avatarImageView.setImage(ImageLocation.getForLocal(uploadingAvatar), "50_50", avatarDrawable, null); + } else { + ImageLocation imageLocation = ImageLocation.getForChat(currentChat, ImageLocation.TYPE_SMALL); + hasAvatar = imageLocation != null; + avatarImageView.setImage(imageLocation, "50_50", avatarDrawable, currentChat); + } } } + applyParticipantChanges(false); } public void setDrawDivider(boolean draw) { @@ -578,18 +657,45 @@ private void applyParticipantChanges(boolean animated, boolean internal) { } } - if (isSelfUser()) { - statusTextView[4].setTextColor(Theme.getColor(Theme.key_voipgroup_listeningText)); - } else { + if (!isSelfUser()) { statusTextView[4].setTextColor(Theme.getColor(grayIconColor)); } if (isSelfUser()) { - statusTextView[4].setText(LocaleController.getString("ThisIsYou", R.string.ThisIsYou)); + if (!hasAbout && !hasAvatar) { + if (currentUser != null) { + statusTextView[4].setText(LocaleController.getString("TapToAddPhotoOrBio", R.string.TapToAddPhotoOrBio)); + } else { + statusTextView[4].setText(LocaleController.getString("TapToAddPhotoOrDescription", R.string.TapToAddPhotoOrDescription)); + } + statusTextView[4].setTextColor(Theme.getColor(grayIconColor)); + } else if (!hasAbout ){ + if (currentUser != null) { + statusTextView[4].setText(LocaleController.getString("TapToAddBio", R.string.TapToAddBio)); + } else { + statusTextView[4].setText(LocaleController.getString("TapToAddDescription", R.string.TapToAddDescription)); + } + statusTextView[4].setTextColor(Theme.getColor(grayIconColor)); + } else if (!hasAvatar) { + statusTextView[4].setText(LocaleController.getString("TapToAddPhoto", R.string.TapToAddPhoto)); + statusTextView[4].setTextColor(Theme.getColor(grayIconColor)); + } else { + statusTextView[4].setText(LocaleController.getString("ThisIsYou", R.string.ThisIsYou)); + statusTextView[4].setTextColor(Theme.getColor(Theme.key_voipgroup_listeningText)); + } + if (hasAbout) { + fullAboutTextView.setText(AndroidUtilities.replaceNewLines(participant.about)); + fullAboutTextView.setTextColor(Theme.getColor(Theme.key_voipgroup_mutedIcon)); + } else { + fullAboutTextView.setText(statusTextView[newStatus].getText()); + fullAboutTextView.setTextColor(statusTextView[newStatus].getTextColor()); + } } else if (hasAbout) { statusTextView[4].setText(AndroidUtilities.replaceNewLines(participant.about)); + fullAboutTextView.setText(""); } else { statusTextView[4].setText(""); + fullAboutTextView.setText(""); } boolean somethingChanged = false; if (animatorSet != null) { @@ -626,7 +732,7 @@ private void applyParticipantChanges(boolean animated, boolean internal) { int volume = vol / 100; if (volume != 100) { statusTextView[1].setLeftDrawable(speakingDrawable); - statusTextView[1].setText((vol < 100 ? 1 : volume) + "% " + LocaleController.getString("Speaking", R.string.Speaking)); + statusTextView[1].setText(LocaleController.formatString("SpeakingWithVolume", R.string.SpeakingWithVolume, vol < 100 ? 1 : volume)); } else { statusTextView[1].setLeftDrawable(null); statusTextView[1].setText(LocaleController.getString("Speaking", R.string.Speaking)); @@ -766,6 +872,8 @@ protected void dispatchDraw(Canvas canvas) { avatarImageView.setScaleX(avatarWavesDrawable.getAvatarScale()); avatarImageView.setScaleY(avatarWavesDrawable.getAvatarScale()); + avatarProgressView.setScaleX(avatarWavesDrawable.getAvatarScale()); + avatarProgressView.setScaleY(avatarWavesDrawable.getAvatarScale()); super.dispatchDraw(canvas); } @@ -913,6 +1021,7 @@ public BackupImageView getAvatarImageView() { return avatarImageView; } + @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java index c3004876f39..78dad291a0e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java @@ -330,7 +330,7 @@ public void update(int mask) { } } - avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser); } else { TLRPC.Chat currentChat = (TLRPC.Chat) currentObject; if (currentChat.photo != null) { @@ -390,7 +390,7 @@ public void update(int mask) { } } - avatarImageView.setImage(ImageLocation.getForChat(currentChat, false), "50_50", avatarDrawable, currentChat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentChat); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java index 801e0415656..d18cddd942b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java @@ -11,8 +11,6 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.RectF; -import android.text.Layout; -import android.text.StaticLayout; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; @@ -130,7 +128,7 @@ public void setDialog(int uid, boolean counter, CharSequence name) { nameTextView.setText(""); } avatarDrawable.setInfo(currentUser); - imageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + imageView.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-uid); if (name != null) { @@ -142,7 +140,7 @@ public void setDialog(int uid, boolean counter, CharSequence name) { } avatarDrawable.setInfo(chat); currentUser = null; - imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + imageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } if (counter) { update(0); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java index a134e6922ca..1c21246f4ed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java @@ -58,7 +58,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { public void setUser(TLRPC.User user) { nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); avatarDrawable.setInfo(user); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } public void setCount(int count) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java index c0885773097..22fcc3a8754 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java @@ -260,7 +260,7 @@ public void update(int mask) { } } lastAvatar = photo; - avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser); } else if (currentObject instanceof TLRPC.Chat) { TLRPC.Chat currentChat = (TLRPC.Chat) currentObject; @@ -317,7 +317,7 @@ public void update(int mask) { } } lastAvatar = photo; - avatarImageView.setImage(ImageLocation.getForChat(currentChat, false), "50_50", avatarDrawable, currentChat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentChat); } else if (currentObject instanceof Integer) { nameTextView.setText(currentName); statusTextView.setTextColor(statusColor); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java index 0152ee1a024..a3bc21010d2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java @@ -76,7 +76,7 @@ public void setUser(TLRPC.User user) { } avatarDrawable.setInfo(user); if (user.photo != null && user.photo.photo_small != null) { - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } else { imageView.setImageDrawable(avatarDrawable); } @@ -99,7 +99,7 @@ public void setChat(TLRPC.Chat chat) { } avatarDrawable.setInfo(chat); if (chat.photo != null && chat.photo.photo_small != null) { - imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + imageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } else { imageView.setImageDrawable(avatarDrawable); } @@ -140,7 +140,7 @@ public void setBotCommand(String command, String help, TLRPC.User user) { imageView.setVisibility(VISIBLE); avatarDrawable.setInfo(user); if (user.photo != null && user.photo.photo_small != null) { - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } else { imageView.setImageDrawable(avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PaymentInfoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PaymentInfoCell.java index da858bba3e5..66fb5899123 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PaymentInfoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PaymentInfoCell.java @@ -60,25 +60,27 @@ public PaymentInfoCell(Context context) { detailExTextView = new TextView(context); detailExTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); - detailExTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + detailExTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); detailExTextView.setLines(1); detailExTextView.setMaxLines(1); detailExTextView.setSingleLine(true); detailExTextView.setEllipsize(TextUtils.TruncateAt.END); detailExTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); - addView(detailExTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 10 : 123, 90, LocaleController.isRTL ? 123 : 10, 0)); + addView(detailExTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 10 : 123, 90, LocaleController.isRTL ? 123 : 10, 9)); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(120), MeasureSpec.EXACTLY)); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - top = detailTextView.getBottom() + AndroidUtilities.dp(3); - detailExTextView.layout(detailExTextView.getLeft(), top, detailExTextView.getRight(), top + detailExTextView.getMeasuredHeight()); + int h; + if (imageView.getVisibility() != GONE) { + h = MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(120), MeasureSpec.EXACTLY); + } else { + h = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + measureChildWithMargins(detailTextView, widthMeasureSpec, 0, heightMeasureSpec, 0); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) detailExTextView.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.dp(33) + detailTextView.getMeasuredHeight() + AndroidUtilities.dp(3); + } + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), h); } public void setInvoice(TLRPC.TL_messageMediaInvoice invoice, String botname) { @@ -107,7 +109,38 @@ public void setInvoice(TLRPC.TL_messageMediaInvoice invoice, String botname) { } else { nameTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 9, 17, 0)); detailTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 33, 17, 0)); - detailExTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 90, 17, 0)); + detailExTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 90, 17, 9)); + imageView.setVisibility(GONE); + } + } + + public void setReceipt(TLRPC.TL_payments_paymentReceipt receipt, String botname) { + nameTextView.setText(receipt.title); + detailTextView.setText(receipt.description); + detailExTextView.setText(botname); + + int maxPhotoWidth; + if (AndroidUtilities.isTablet()) { + maxPhotoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); + } else { + maxPhotoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); + } + int width = 640; + int height = 360; + float scale = width / (float) (maxPhotoWidth - AndroidUtilities.dp(2)); + width /= scale; + height /= scale; + if (receipt.photo != null && receipt.photo.mime_type.startsWith("image/")) { + nameTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 10 : 123, 9, LocaleController.isRTL ? 123 : 10, 0)); + detailTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 10 : 123, 33, LocaleController.isRTL ? 123 : 10, 0)); + detailExTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 10 : 123, 90, LocaleController.isRTL ? 123 : 10, 0)); + imageView.setVisibility(VISIBLE); + String filter = String.format(Locale.US, "%d_%d", width, height); + imageView.getImageReceiver().setImage(ImageLocation.getForWebFile(WebFile.createWithWebDocument(receipt.photo)), filter, null, null, -1, null, receipt, 1); + } else { + nameTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 9, 17, 0)); + detailTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 33, 17, 0)); + detailExTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 90, 17, 9)); imageView.setVisibility(GONE); } } 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 1e1381fdf95..0b6a00721d1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java @@ -501,14 +501,14 @@ public void update(int mask) { if (user.photo != null) { photo = user.photo.photo_small; } - avatarImage.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, null, user, 0); + avatarImage.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user, 0); } } else if (chat != null) { if (chat.photo != null) { photo = chat.photo.photo_small; } avatarDrawable.setInfo(chat); - avatarImage.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, null, chat, 0); + avatarImage.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat, 0); } else { avatarDrawable.setInfo(0, null, null); avatarImage.setImage(null, null, avatarDrawable, null, null, 0); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java index f45fbb68187..1793545f6ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java @@ -183,7 +183,7 @@ public void setSession(TLObject object, boolean divider) { if (user != null) { avatarDrawable.setInfo(user); name = UserObject.getFirstName(user); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } else { name = ""; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java index 43b396b3f5c..90557001c34 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java @@ -41,58 +41,68 @@ public class ShareDialogCell extends FrameLayout { private CheckBox2 checkBox; private AvatarDrawable avatarDrawable = new AvatarDrawable(); private TLRPC.User user; - private boolean darkTheme; + private int currentType; private float onlineProgress; private long lastUpdateTime; + private long currentDialog; private int currentAccount = UserConfig.selectedAccount; - public ShareDialogCell(Context context, boolean forCall) { + public static final int TYPE_SHARE = 0; + public static final int TYPE_CALL = 1; + public static final int TYPE_CREATE = 2; + + public ShareDialogCell(Context context, int type) { super(context); setWillNotDraw(false); - darkTheme = forCall; + currentType = type; imageView = new BackupImageView(context); imageView.setRoundRadius(AndroidUtilities.dp(28)); - addView(imageView, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 7, 0, 0)); + if (type == TYPE_CREATE) { + addView(imageView, LayoutHelper.createFrame(48, 48, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 7, 0, 0)); + } else { + addView(imageView, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 7, 0, 0)); + } nameTextView = new TextView(context); - nameTextView.setTextColor(Theme.getColor(forCall ? Theme.key_voipgroup_nameText : Theme.key_dialogTextBlack)); + nameTextView.setTextColor(Theme.getColor(type == TYPE_CALL ? Theme.key_voipgroup_nameText : Theme.key_dialogTextBlack)); nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); nameTextView.setMaxLines(2); nameTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); nameTextView.setLines(2); nameTextView.setEllipsize(TextUtils.TruncateAt.END); - addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 6, 66, 6, 0)); + addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 6, currentType == TYPE_CREATE ? 58 : 66, 6, 0)); checkBox = new CheckBox2(context, 21); - checkBox.setColor(Theme.key_dialogRoundCheckBox, forCall ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_dialogBackground, Theme.key_dialogRoundCheckBoxCheck); + checkBox.setColor(Theme.key_dialogRoundCheckBox, type == TYPE_CALL ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_dialogBackground, Theme.key_dialogRoundCheckBoxCheck); checkBox.setDrawUnchecked(false); checkBox.setDrawBackgroundAsArc(4); checkBox.setProgressDelegate(progress -> { float scale = 1.0f - (1.0f - 0.857f) * checkBox.getProgress(); imageView.setScaleX(scale); imageView.setScaleY(scale); + invalidate(); }); - addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 19, 42, 0, 0)); + addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 19, currentType == TYPE_CREATE ? -40 : 42, 0, 0)); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(103), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(currentType == TYPE_CREATE ? 95 : 103), MeasureSpec.EXACTLY)); } public void setDialog(int uid, boolean checked, CharSequence name) { if (uid > 0) { user = MessagesController.getInstance(currentAccount).getUser(uid); avatarDrawable.setInfo(user); - if (UserObject.isReplyUser(user)) { + if (currentType != TYPE_CREATE && UserObject.isReplyUser(user)) { nameTextView.setText(LocaleController.getString("RepliesTitle", R.string.RepliesTitle)); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); imageView.setImage(null, null, avatarDrawable, user); - } else if (UserObject.isUserSelf(user)) { + } else if (currentType != TYPE_CREATE && UserObject.isUserSelf(user)) { nameTextView.setText(LocaleController.getString("SavedMessages", R.string.SavedMessages)); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); imageView.setImage(null, null, avatarDrawable, user); @@ -104,7 +114,7 @@ public void setDialog(int uid, boolean checked, CharSequence name) { } else { nameTextView.setText(""); } - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } else { user = null; @@ -117,11 +127,16 @@ public void setDialog(int uid, boolean checked, CharSequence name) { nameTextView.setText(""); } avatarDrawable.setInfo(chat); - imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + imageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } + currentDialog = uid; checkBox.setChecked(checked, false); } + public long getCurrentDialog() { + return currentDialog; + } + public void setChecked(boolean checked, boolean animated) { checkBox.setChecked(checked, animated); } @@ -129,7 +144,7 @@ public void setChecked(boolean checked, boolean animated) { @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean result = super.drawChild(canvas, child, drawingTime); - if (child == imageView) { + if (child == imageView && currentType != TYPE_CREATE) { if (user != null && !MessagesController.isSupportUser(user)) { long newTime = SystemClock.elapsedRealtime(); long dt = newTime - lastUpdateTime; @@ -142,7 +157,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (isOnline || onlineProgress != 0) { int top = imageView.getBottom() - AndroidUtilities.dp(6); int left = imageView.getRight() - AndroidUtilities.dp(10); - Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(darkTheme ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_windowBackgroundWhite)); + Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(currentType == TYPE_CALL ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_windowBackgroundWhite)); canvas.drawCircle(left, top, AndroidUtilities.dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_chats_onlineCircle)); canvas.drawCircle(left, top, AndroidUtilities.dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); @@ -177,6 +192,6 @@ protected void onDraw(Canvas canvas) { int cy = imageView.getTop() + imageView.getMeasuredHeight() / 2; Theme.checkboxSquare_checkPaint.setColor(Theme.getColor(Theme.key_dialogRoundCheckBox)); Theme.checkboxSquare_checkPaint.setAlpha((int) (checkBox.getProgress() * 255)); - canvas.drawCircle(cx, cy, AndroidUtilities.dp(28), Theme.checkboxSquare_checkPaint); + canvas.drawCircle(cx, cy, AndroidUtilities.dp(24), Theme.checkboxSquare_checkPaint); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java index acaa813a007..aabcfacc433 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java @@ -124,14 +124,14 @@ public void setDialog(long dialogId, TLRPC.TL_channelLocation chatLocation) { if (user != null) { avatarDrawable = new AvatarDrawable(user); name = UserObject.getUserName(user); - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lowerId); if (chat != null) { avatarDrawable = new AvatarDrawable(chat); name = chat.title; - avatarImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } } nameTextView.setText(name); @@ -177,14 +177,14 @@ public void setDialog(MessageObject messageObject, Location userLocation) { if (user != null) { avatarDrawable = new AvatarDrawable(user); name = UserObject.getUserName(user); - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId); if (chat != null) { avatarDrawable = new AvatarDrawable(chat); name = chat.title; - avatarImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } } } @@ -216,14 +216,14 @@ public void setDialog(LocationActivity.LiveLocation info, Location userLocation) if (user != null) { avatarDrawable.setInfo(user); nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_id); if (chat != null) { avatarDrawable.setInfo(chat); nameTextView.setText(chat.title); - avatarImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } } @@ -249,14 +249,14 @@ public void setDialog(LocationController.SharingLocationInfo info) { if (user != null) { avatarDrawable.setInfo(user); nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_id); if (chat != null) { avatarDrawable.setInfo(chat); nameTextView.setText(chat.title); - avatarImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java index e66fd18879b..cbc76b726ea 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java @@ -113,7 +113,7 @@ public void setData(StatisticActivity.RecentPostInfo postInfo) { public void setData(StatisticActivity.MemberData memberData) { avatarDrawable.setInfo(memberData.user); - imageView.setImage(ImageLocation.getForUser(memberData.user, false), "50_50", avatarDrawable, memberData.user); + imageView.setImage(ImageLocation.getForUserOrChat(memberData.user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(memberData.user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, memberData.user); imageView.setRoundRadius(AndroidUtilities.dp(46) >> 1); message.setText(memberData.user.first_name); date.setText(memberData.description); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java index 7fe3538c9a6..68f59d26bcd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java @@ -493,9 +493,9 @@ public void update(int mask) { lastAvatar = photo; if (currentUser != null) { - avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser); } else if (currentChat != null) { - avatarImageView.setImage(ImageLocation.getForChat(currentChat, false), "50_50", avatarDrawable, currentChat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentChat); } else { avatarImageView.setImageDrawable(avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java index 86c747fd11e..8bfb329a0f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java @@ -260,7 +260,7 @@ public void update(int mask) { statusTextView.setText(LocaleController.formatUserStatus(currentAccount, currentUser)); } } - avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser); } else if (currentChat != null) { statusTextView.setTextColor(statusColor); if (ChatObject.isChannel(currentChat) && !currentChat.megagroup) { @@ -282,7 +282,7 @@ public void update(int mask) { statusTextView.setText(LocaleController.getString("MegaPublic", R.string.MegaPublic)); } } - avatarImageView.setImage(ImageLocation.getForChat(currentChat, false), "50_50", avatarDrawable, currentObject); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentObject); } else { avatarImageView.setImageDrawable(avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java index b8733a762cd..37584792906 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java @@ -27,6 +27,7 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.telephony.PhoneNumberUtils; @@ -981,8 +982,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); - Intent mailer = new Intent(Intent.ACTION_SEND); - mailer.setType("message/rfc822"); + Intent mailer = new Intent(Intent.ACTION_SENDTO); + mailer.setData(Uri.parse("mailto:")); mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"}); mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + emailPhone); mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + requestPhone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java index 0ed2568ea09..085368ecf0b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java @@ -2754,7 +2754,7 @@ public ArrayList getThemeDescriptions() { themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{ChatActionCell.class}, Theme.chat_actionTextPaint, null, null, Theme.key_chat_serviceText)); themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_LINKCOLOR, new Class[]{ChatActionCell.class}, Theme.chat_actionTextPaint, null, null, Theme.key_chat_serviceLink)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_shareIconDrawable, Theme.chat_botInlineDrawable, Theme.chat_botLinkDrawalbe, Theme.chat_goIconDrawable, Theme.chat_commentStickerDrawable}, null, Theme.key_chat_serviceIcon)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_botCardDrawalbe, Theme.chat_shareIconDrawable, Theme.chat_botInlineDrawable, Theme.chat_botLinkDrawalbe, Theme.chat_goIconDrawable, Theme.chat_commentStickerDrawable}, null, Theme.key_chat_serviceIcon)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class, ChatActionCell.class}, null, null, null, Theme.key_chat_serviceBackground)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class, ChatActionCell.class}, null, null, null, Theme.key_chat_serviceBackgroundSelected)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java index 203d005f364..470a6c1095b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java @@ -1003,7 +1003,7 @@ public void didReceivedNotification(int id, int account, Object... args) { bundle.putInt("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); + MessagesController.getInstance(currentAccount).changeChatAvatar(chat_id, null, inputPhoto, inputVideo, videoTimestamp, inputVideoPath, avatar, avatarBig, null); } presentFragment(new ChannelCreateActivity(bundle), true); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 1fe23d464e6..e5f01c9fc34 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -737,6 +737,8 @@ public boolean needPostpone(int id, int currentAccount, Object[] args) { private boolean invalidateMessagesVisiblePart; private boolean scrollByTouch; + private PinchToZoomHelper pinchToZoomHelper; + public float getChatListViewPadding() { return chatListViewPaddingTop; } @@ -1666,6 +1668,9 @@ public void onFragmentDestroy() { if (chatListItemAnimator != null) { chatListItemAnimator.onDestroy(); } + if (pinchToZoomHelper != null) { + pinchToZoomHelper.clear(); + } } @Override @@ -1824,7 +1829,19 @@ public void onItemClick(final int id) { alert.setDelegate(new ClearHistoryAlert.ClearHistoryAlertDelegate() { @Override public void onClearHistory(boolean revoke) { - performHistoryClear(revoke); + if (revoke && currentUser != null) { + getMessagesStorage().getMessagesCount(currentUser.id, (count) -> { + if (count >= 50) { + AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, true, false, true, null, currentUser, false, false, (param) -> { + performHistoryClear(true); + }); + } else { + performHistoryClear(true); + } + }); + } else { + performHistoryClear(revoke); + } } @Override @@ -1960,6 +1977,7 @@ public void onAutoDeleteHistory(int ttl, int action) { avatarContainer.onDestroy(); } avatarContainer = new ChatAvatarContainer(context, this, currentEncryptedChat != null); + AndroidUtilities.updateViewVisibilityAnimated(avatarContainer, true, 1f, false); if (inPreviewMode || inBubbleMode) { avatarContainer.setOccupyStatusBar(false); } @@ -2401,6 +2419,10 @@ public boolean dispatchTouchEvent(MotionEvent ev) { } } + if (pinchToZoomHelper.isInOverlayMode()) { + return pinchToZoomHelper.onTouchEvent(ev); + } + if (AvatarPreviewer.hasVisibleInstance()) { AvatarPreviewer.getInstance().onTouchEvent(ev); return true; @@ -5566,6 +5588,26 @@ public void onContextClick(TLRPC.BotInlineResult result) { return; } TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) object; + if (currentEncryptedChat != null) { + int error = 0; + if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaAuto && "game".equals(result.type)) { + error = 1; + } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaInvoice) { + error = 2; + } + if (error != 0) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("SendMessageTitle", R.string.SendMessageTitle)); + if (error == 1) { + builder.setMessage(LocaleController.getString("GameCantSendSecretChat", R.string.GameCantSendSecretChat)); + } else { + builder.setMessage(LocaleController.getString("InvoiceCantSendSecretChat", R.string.InvoiceCantSendSecretChat)); + } + builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + return; + } + } if ((result.type.equals("photo") && (result.photo != null || result.content != null) || result.type.equals("gif") && (result.document != null || result.content != null) || result.type.equals("video") && (result.document != null/* || result.content_url != null*/))) { @@ -5743,7 +5785,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } }); - topUndoView = new UndoView(context, true) { + topUndoView = new UndoView(context, this, true) { @Override public void didPressUrl(CharacterStyle span) { didPressMessageUrl(span, false, null, null); @@ -6362,10 +6404,15 @@ public void setVisibility(int visibility) { replyLayout.setOnClickListener(v -> { if (forwardingMessages != null && !forwardingMessages.isEmpty()) { int hasPoll = 0; + boolean hasInvoice = false; for (int a = 0, N = forwardingMessages.size(); a < N; a++) { MessageObject messageObject = forwardingMessages.get(a); - if (hasPoll != 2 && messageObject.isPoll()) { - hasPoll = messageObject.isPublicPoll() ? 2 : 1; + if (messageObject.isPoll()) { + if (hasPoll != 2) { + hasPoll = messageObject.isPublicPoll() ? 2 : 1; + } + } else if (messageObject.isInvoice()) { + hasInvoice = true; } selectedMessagesIds[0].put(messageObject.getId(), messageObject); } @@ -6373,6 +6420,7 @@ public void setVisibility(int visibility) { args.putBoolean("onlySelect", true); args.putInt("dialogsType", 3); args.putInt("hasPoll", hasPoll); + args.putBoolean("hasInvoice", hasInvoice); args.putInt("messagesCount", forwardingMessages.size()); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate(ChatActivity.this); @@ -6422,10 +6470,15 @@ public void setVisibility(int visibility) { builder.setNegativeButton(LocaleController.getString("SelectOtherChat", R.string.SelectOtherChat), (dialogInterface, i) -> { if (forwardingMessages != null && !forwardingMessages.isEmpty()) { int hasPoll = 0; + boolean hasInvoice = false; for (int a = 0, N = forwardingMessages.size(); a < N; a++) { MessageObject messageObject = forwardingMessages.get(a); - if (hasPoll != 2 && messageObject.isPoll()) { - hasPoll = messageObject.isPublicPoll() ? 2 : 1; + if (messageObject.isPoll()) { + if (hasPoll != 2) { + hasPoll = messageObject.isPublicPoll() ? 2 : 1; + } + } else if (messageObject.isInvoice()) { + hasInvoice = true; } selectedMessagesIds[0].put(messageObject.getId(), messageObject); } @@ -6433,6 +6486,7 @@ public void setVisibility(int visibility) { args.putBoolean("onlySelect", true); args.putInt("dialogsType", 3); args.putInt("hasPoll", hasPoll); + args.putBoolean("hasInvoice", hasInvoice); args.putInt("messagesCount", forwardingMessages.size()); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate(ChatActivity.this); @@ -6911,7 +6965,7 @@ protected void onSend(int type, String message) { contentView.addView(searchContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.BOTTOM)); - undoView = new UndoView(context); + undoView = new UndoView(context, this); undoView.setAdditionalTranslationY(AndroidUtilities.dp(51)); contentView.addView(undoView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 8, 0, 8, 8)); @@ -7006,6 +7060,109 @@ public void onTextCopied() { if (replyingMessageObject != null) { chatActivityEnterView.setReplyingMessageObject(replyingMessageObject); } + + ViewGroup decorView; + if (Build.VERSION.SDK_INT >= 21) { + decorView = (ViewGroup) getParentActivity().getWindow().getDecorView(); + } else { + decorView = contentView; + } + pinchToZoomHelper = new PinchToZoomHelper(decorView) { + @Override + protected void drawOverlays(Canvas canvas, float alpha, float parentOffsetX, float parentOffsetY, float clipTop, float clipBottom) { + if (alpha > 0) { + View view = getChild(); + if (view instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) view; + + int top = (int) Math.max(clipTop, parentOffsetY); + int bottom = (int) Math.min(clipBottom, parentOffsetY + cell.getMeasuredHeight()); + AndroidUtilities.rectTmp.set(parentOffsetX, top, parentOffsetX + cell.getMeasuredWidth(), bottom); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (255 * alpha), Canvas.ALL_SAVE_FLAG); + canvas.translate(parentOffsetX, parentOffsetY); + cell.drawFromPinchToZoom = true; + cell.drawOverlays(canvas); + if (cell.shouldDrawTimeOnMedia() && cell.getCurrentMessagesGroup() == null) { + cell.drawTime(canvas, 1f, false); + } + cell.drawFromPinchToZoom = false; + canvas.restore(); + } + } + } + }; + pinchToZoomHelper.setCallback(new PinchToZoomHelper.Callback() { + + @Override + public TextureView getCurrentTextureView() { + return videoTextureView; + } + + @Override + public void onZoomStarted(MessageObject messageObject) { + chatListView.cancelClickRunnables(true); + chatListView.stopScroll(); + if (MediaController.getInstance().isPlayingMessage(messageObject)) { + contentView.removeView(videoPlayerContainer); + videoPlayerContainer = null; + videoTextureView = null; + aspectRatioFrameLayout = null; + } + + for (int i = 0; i < chatListView.getChildCount(); i++) { + if (chatListView.getChildAt(i) instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) chatListView.getChildAt(i); + if (cell.getMessageObject().getId() == messageObject.getId()) { + cell.getPhotoImage().setVisible(false, true); + } + } + } + } + + @Override + public void onZoomFinished(MessageObject messageObject) { + if (messageObject == null) { + return; + } + if (MediaController.getInstance().isPlayingMessage(messageObject)) { + for (int i = 0; i < chatListView.getChildCount(); i++) { + if (chatListView.getChildAt(i) instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) chatListView.getChildAt(i); + if (cell.getMessageObject().getId() == messageObject.getId()) { + AnimatedFileDrawable animation = cell.getPhotoImage().getAnimation(); + if (animation.isRunning()) { + animation.stop(); + } + if (animation != null) { + Bitmap bitmap = animation.getAnimatedBitmap(); + if (bitmap != null) { + try { + Bitmap src = pinchToZoomHelper.getVideoBitmap(bitmap.getWidth(), bitmap.getHeight()); + Canvas canvas = new Canvas(bitmap); + canvas.drawBitmap(src, 0, 0, null); + src.recycle(); + } catch (Throwable e) { + FileLog.e(e); + } + } + } + } + } + } + createTextureView(true); + MediaController.getInstance().setTextureView(videoTextureView, aspectRatioFrameLayout, videoPlayerContainer, true); + } + chatListView.invalidate(); + } + + }); + pinchToZoomHelper.setClipBoundsListener(new PinchToZoomHelper.ClipBoundsListener() { + @Override + public void getClipTopBottom(float[] topBottom) { + topBottom[1] = chatListView.getBottom(); + topBottom[0] = chatListView.getTop() + chatListViewPaddingTop - AndroidUtilities.dp(4); + } + }); return fragmentView; } @@ -7597,6 +7754,7 @@ private void destroyTextureView() { private void openForward() { int hasPoll = 0; + boolean hasInvoice = false; for (int a = 0; a < 2; a++) { for (int b = 0; b < selectedMessagesIds[a].size(); b++) { MessageObject messageObject = selectedMessagesIds[a].valueAt(b); @@ -7605,6 +7763,8 @@ private void openForward() { if (hasPoll == 2) { break; } + } else if (messageObject.isInvoice()) { + hasInvoice = true; } } if (hasPoll == 2) { @@ -7616,6 +7776,7 @@ private void openForward() { args.putInt("dialogsType", 3); args.putInt("messagesCount", canForwardMessagesCount); args.putInt("hasPoll", hasPoll); + args.putBoolean("hasInvoice", hasInvoice); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate(ChatActivity.this); presentFragment(fragment); @@ -7851,7 +8012,7 @@ private void createChatAttachView() { return; } if (chatAttachAlert == null) { - chatAttachAlert = new ChatAttachAlert(getParentActivity(), this) { + chatAttachAlert = new ChatAttachAlert(getParentActivity(), this, false) { @Override public void dismissInternal() { if (chatAttachAlert.isShowing()) { @@ -9805,7 +9966,7 @@ public void showFieldPanel(boolean show, MessageObject messageObjectToReply, Mes } private void moveScrollToLastMessage() { - if (chatListView != null && !messages.isEmpty()) { + if (chatListView != null && !messages.isEmpty() && !pinchToZoomHelper.isInOverlayMode()) { chatLayoutManager.scrollToPositionWithOffset(0, 0); chatListView.stopScroll(); } @@ -18050,11 +18211,13 @@ private void createMenu(View v, boolean single, boolean listView, float x, float return; } - MessageObject message = null; + MessageObject message; if (v instanceof ChatMessageCell) { message = ((ChatMessageCell) v).getMessageObject(); } else if (v instanceof ChatActionCell) { message = ((ChatActionCell) v).getMessageObject(); + } else { + message = null; } if (message == null) { return; @@ -18072,7 +18235,17 @@ private void createMenu(View v, boolean single, boolean listView, float x, float if (avatarContainer.openSetTimer()) { return; } - } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionGroupCall || message.messageOwner.action instanceof TLRPC.TL_messageActionInviteToGroupCall) { + } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent && message.replyMessageObject != null && message.replyMessageObject.isInvoice()) { + TLRPC.TL_payments_getPaymentReceipt req = new TLRPC.TL_payments_getPaymentReceipt(); + req.msg_id = message.getId(); + req.peer = getMessagesController().getInputPeer(message.messageOwner.peer_id); + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_payments_paymentReceipt) { + presentFragment(new PaymentFormActivity((TLRPC.TL_payments_paymentReceipt) response)); + } + }), ConnectionsManager.RequestFlagFailOnServerErrors); + return; + } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionGroupCall || message.messageOwner.action instanceof TLRPC.TL_messageActionInviteToGroupCall || message.messageOwner.action instanceof TLRPC.TL_messageActionGroupCallScheduled) { if (getParentActivity() == null) { return; } @@ -18080,7 +18253,7 @@ private void createMenu(View v, boolean single, boolean listView, float x, float if (sharedInstance != null) { if (sharedInstance.groupCall != null && message.messageOwner.action.call.id == sharedInstance.groupCall.call.id) { if (getParentActivity() instanceof LaunchActivity) { - GroupCallActivity.create((LaunchActivity) getParentActivity(), AccountInstance.getInstance(currentAccount)); + GroupCallActivity.create((LaunchActivity) getParentActivity(), AccountInstance.getInstance(currentAccount), null, null, false, null); } else { Intent intent = new Intent(getParentActivity(), LaunchActivity.class).setAction("voip_chat"); intent.putExtra("currentAccount", VoIPService.getSharedInstance().getAccount()); @@ -18093,7 +18266,7 @@ private void createMenu(View v, boolean single, boolean listView, float x, float return; } else if (fragmentContextView != null && getGroupCall() != null) { if (VoIPService.getSharedInstance() != null) { - GroupCallActivity.create((LaunchActivity) getParentActivity(), AccountInstance.getInstance(VoIPService.getSharedInstance().getAccount())); + GroupCallActivity.create((LaunchActivity) getParentActivity(), AccountInstance.getInstance(VoIPService.getSharedInstance().getAccount()), null, null, false, null); } else { ChatObject.Call call = getGroupCall(); if (call == null) { @@ -19077,6 +19250,7 @@ private void processSelectedOption(int option) { args.putInt("dialogsType", 3); args.putInt("messagesCount", forwardingMessageGroup == null ? 1 : forwardingMessageGroup.messages.size()); args.putInt("hasPoll", forwardingMessage.isPoll() ? (forwardingMessage.isPublicPoll() ? 2 : 1) : 0); + args.putBoolean("hasInvoice", forwardingMessage.isInvoice()); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate(this); presentFragment(fragment); @@ -21550,6 +21724,11 @@ public void onDiceFinished() { fireworksOverlay.start(); fireworksOverlay.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } + + @Override + public PinchToZoomHelper getPinchToZoomHelper() { + return pinchToZoomHelper; + } }); if (currentEncryptedChat == null) { chatMessageCell.setAllowAssistant(true); @@ -22406,6 +22585,9 @@ public class ChatScrollCallback extends RecyclerAnimationScrollHelper.AnimationC public void onStartAnimation() { super.onStartAnimation(); scrollCallbackAnimationIndex = getNotificationCenter().setAnimationInProgress(scrollCallbackAnimationIndex, allowedNotificationsDuringChatListAnimations); + if (pinchToZoomHelper.isInOverlayMode()) { + pinchToZoomHelper.finishZoom(); + } } @Override @@ -22562,7 +22744,7 @@ public ArrayList getThemeDescriptions() { themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{ChatActionCell.class}, Theme.chat_actionTextPaint, null, null, Theme.key_chat_serviceText)); themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_LINKCOLOR, new Class[]{ChatActionCell.class}, Theme.chat_actionTextPaint, null, null, Theme.key_chat_serviceLink)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_shareIconDrawable, Theme.chat_replyIconDrawable, Theme.chat_botInlineDrawable, Theme.chat_botLinkDrawalbe, Theme.chat_goIconDrawable, Theme.chat_commentStickerDrawable}, null, Theme.key_chat_serviceIcon)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_botCardDrawalbe, Theme.chat_shareIconDrawable, Theme.chat_replyIconDrawable, Theme.chat_botInlineDrawable, Theme.chat_botLinkDrawalbe, Theme.chat_goIconDrawable, Theme.chat_commentStickerDrawable}, null, Theme.key_chat_serviceIcon)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class, ChatActionCell.class}, null, null, null, Theme.key_chat_serviceBackground)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class, ChatActionCell.class}, null, null, null, Theme.key_chat_serviceBackgroundSelected)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index 9e065c7d6c3..490ef9351da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -584,7 +584,7 @@ protected void onDraw(Canvas canvas) { setAvatarCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); setAvatarCell.setOnClickListener(v -> imageUpdater.openMenu(avatar != null, () -> { avatar = null; - MessagesController.getInstance(currentAccount).changeChatAvatar(chatId, null, null, null, 0, null, null, null); + MessagesController.getInstance(currentAccount).changeChatAvatar(chatId, null, null, null, 0, null, null, null, null); showAvatarProgress(false, true); avatarImage.setImage(null, null, avatarDrawable, currentChat); }, null)); @@ -775,7 +775,7 @@ public void afterTextChanged(Editable editable) { blockCell = new TextCell(context); blockCell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - blockCell.setVisibility(ChatObject.isChannel(currentChat) || currentChat.creator ? View.VISIBLE : View.GONE); + blockCell.setVisibility(ChatObject.isChannel(currentChat) || currentChat.creator || ChatObject.hasAdminRights(currentChat) && ChatObject.canChangeChatInfo(currentChat) ? View.VISIBLE : View.GONE); blockCell.setOnClickListener(v -> { Bundle args = new Bundle(); args.putInt("chat_id", chatId); @@ -937,8 +937,8 @@ private void setAvatar() { boolean hasPhoto; if (currentChat.photo != null) { avatar = currentChat.photo.photo_small; - ImageLocation location = ImageLocation.getForChat(currentChat, false); - avatarImage.setImage(location, "50_50", avatarDrawable, currentChat); + ImageLocation location = ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL); + avatarImage.setImage(location, "50_50", ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentChat); hasPhoto = location != null; } else { avatarImage.setImageDrawable(avatarDrawable); @@ -1001,7 +1001,7 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi AndroidUtilities.runOnUIThread(() -> { avatar = smallSize.location; if (photo != null || video != null) { - MessagesController.getInstance(currentAccount).changeChatAvatar(chatId, null, photo, video, videoStartTimestamp, videoPath, smallSize.location, bigSize.location); + MessagesController.getInstance(currentAccount).changeChatAvatar(chatId, null, photo, video, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, null); if (createAfterUpload) { try { if (progressDialog != null && progressDialog.isShowing()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java index 9ade21d3ac4..08f7c6873c4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java @@ -499,7 +499,7 @@ private void showLinkAlert(TLRPC.Chat chat, boolean query) { frameLayout2.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, (LocaleController.isRTL ? 21 : 76), 11, (LocaleController.isRTL ? 76 : 21), 0)); frameLayout2.addView(messageTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 24, 57, 24, 9)); avatarDrawable.setInfo(chat); - imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + imageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); builder.setPositiveButton(LocaleController.getString("DiscussionLinkGroup", R.string.DiscussionLinkGroup), (dialogInterface, i) -> { if (chatFull.hidden_prehistory) { MessagesController.getInstance(currentAccount).toogleChannelInvitesHistory(chat.id, false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index 18584bfffc6..02243691da6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -514,7 +514,7 @@ private void updateRows() { if (slowmodeInfoRow == -1 && gigaHeaderRow == -1 || removedUsersRow != -1) { participantsDividerRow = rowCount++; } - if (ChatObject.canBlockUsers(currentChat)) { + if (ChatObject.canBlockUsers(currentChat) && (ChatObject.isChannel(currentChat) || currentChat.creator)) { addNewRow = rowCount++; } @@ -726,6 +726,9 @@ public void onTextChanged(EditText editText) { } else { searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); } + if (!(ChatObject.isChannel(currentChat) || currentChat.creator)) { + searchItem.setVisibility(View.GONE); + } if (type == TYPE_KICKED) { doneItem = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); @@ -2109,7 +2112,7 @@ private void processDone() { if (type != TYPE_KICKED) { return; } - if (!ChatObject.isChannel(currentChat) && selectedSlowmode != initialSlowmode && info != null) { + if (currentChat.creator && !ChatObject.isChannel(currentChat) && selectedSlowmode != initialSlowmode && info != null) { MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, this, param -> { if (param != 0) { chatId = param; 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 a573767a1ba..08a786a049e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -28,22 +28,28 @@ import android.os.Bundle; import android.os.Vibrator; import android.provider.Settings; +import android.text.Editable; import android.text.Html; +import android.text.InputFilter; import android.text.InputType; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextUtils; +import android.text.TextWatcher; import android.text.style.URLSpan; import android.util.Base64; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; +import android.view.KeyEvent; import android.view.View; import android.view.ViewOutlineProvider; import android.view.inputmethod.EditorInfo; import android.widget.Button; +import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; @@ -89,6 +95,7 @@ import org.telegram.ui.Components.voip.VoIPHelper; import org.telegram.ui.LanguageSelectActivity; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.LoginActivity; import org.telegram.ui.NotificationsCustomSettingsActivity; import org.telegram.ui.NotificationsSettingsActivity; import org.telegram.ui.ProfileNotificationsActivity; @@ -285,7 +292,7 @@ public static Dialog processError(int currentAccount, TLRPC.TL_error error, Base } } else if (request instanceof TLRPC.TL_account_sendChangePhoneCode) { if (error.text.contains("PHONE_NUMBER_INVALID")) { - showSimpleAlert(fragment, LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); + LoginActivity.needShowInvalidAlert(fragment, (String) args[0], false); } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { showSimpleAlert(fragment, LocaleController.getString("InvalidCode", R.string.InvalidCode)); } else if (error.text.contains("PHONE_CODE_EXPIRED")) { @@ -294,6 +301,8 @@ public static Dialog processError(int currentAccount, TLRPC.TL_error error, Base showSimpleAlert(fragment, LocaleController.getString("FloodWait", R.string.FloodWait)); } else if (error.text.startsWith("PHONE_NUMBER_OCCUPIED")) { showSimpleAlert(fragment, LocaleController.formatString("ChangePhoneNumberOccupied", R.string.ChangePhoneNumberOccupied, args[0])); + } else if (error.text.startsWith("PHONE_NUMBER_BANNED")) { + LoginActivity.needShowInvalidAlert(fragment, (String) args[0], true); } else { showSimpleAlert(fragment, LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); } @@ -837,10 +846,26 @@ public static void showCustomNotificationsDialog(BaseFragment parentFragment, lo } } } + if (callback != null) { callback.run(i); } builder.getDismissRunnable().run(); + int setting = -1; + if (i == 0) { + setting = NotificationsController.SETTING_MUTE_UNMUTE; + } else if (i == 1) { + setting = NotificationsController.SETTING_MUTE_HOUR; + } else if (i == 2) { + setting = NotificationsController.SETTING_MUTE_2_DAYS; + } else if (i == 4){ + setting = NotificationsController.SETTING_MUTE_FOREVER; + } + if (setting >= 0) { + if (BulletinFactory.canShowBulletin(parentFragment)) { + BulletinFactory.createMuteBulletin(parentFragment, setting).show(); + } + } }); } builder.setTitle(LocaleController.getString("Notifications", R.string.Notifications)); @@ -1136,11 +1161,11 @@ public static void createImportDialogAlert(BaseFragment fragment, String title, } else { avatarDrawable.setSmallSize(false); avatarDrawable.setInfo(user); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } else { avatarDrawable.setInfo(chat); - imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + imageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } messageTextView.setText(AndroidUtilities.replaceTags(message)); @@ -1304,11 +1329,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } else { avatarDrawable.setSmallSize(false); avatarDrawable.setInfo(user); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } else { avatarDrawable.setInfo(chat); - imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + imageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } if (second) { @@ -1474,7 +1499,7 @@ public static void createCallDialogAlert(BaseFragment fragment, TLRPC.User user, BackupImageView imageView = new BackupImageView(context); imageView.setRoundRadius(AndroidUtilities.dp(20)); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); frameLayout.addView(imageView, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 22, 5, 22, 0)); TextView textView = new TextView(context); @@ -1500,6 +1525,292 @@ public static void createCallDialogAlert(BaseFragment fragment, TLRPC.User user, fragment.showDialog(dialog); } + public static void createChangeBioAlert(String currentBio, int peerId, Context context, int currentAccount) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(peerId > 0 ? LocaleController.getString("UserBio", R.string.UserBio) : LocaleController.getString("DescriptionPlaceholder", R.string.DescriptionPlaceholder)); + builder.setMessage(peerId > 0 ? LocaleController.getString("VoipGroupBioEditAlertText", R.string.VoipGroupBioEditAlertText) : LocaleController.getString("DescriptionInfo", R.string.DescriptionInfo)); + FrameLayout dialogView = new FrameLayout(context); + dialogView.setClipChildren(false); + + if (peerId < 0) { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-peerId); + if (chatFull == null) { + MessagesController.getInstance(currentAccount).loadFullChat(-peerId, ConnectionsManager.generateClassGuid(), true); + } + } + + NumberTextView checkTextView = new NumberTextView(context); + EditText editTextView = new EditText(context); + editTextView.setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); + editTextView.setHint(peerId > 0 ? LocaleController.getString("UserBio", R.string.UserBio) : LocaleController.getString("DescriptionPlaceholder", R.string.DescriptionPlaceholder)); + editTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + editTextView.setBackground(Theme.createEditTextDrawable(context, true)); + + editTextView.setMaxLines(4); + editTextView.setRawInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE); + editTextView.setImeOptions(EditorInfo.IME_ACTION_DONE); + + InputFilter[] inputFilters = new InputFilter[1]; + int maxSymbolsCount = peerId > 0 ? 70 : 255; + inputFilters[0] = new CodepointsLengthInputFilter(maxSymbolsCount) { + @Override + public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { + CharSequence result = super.filter(source, start, end, dest, dstart, dend); + if (result != null && source != null && result.length() != source.length()) { + Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + if (v != null) { + v.vibrate(200); + } + AndroidUtilities.shakeView(checkTextView, 2, 0); + } + return result; + } + }; + editTextView.setFilters(inputFilters); + + checkTextView.setCenterAlign(true); + checkTextView.setTextSize(15); + checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + checkTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + dialogView.addView(checkTextView, LayoutHelper.createFrame(20, 20, LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT, 0, 14, 21, 0)); + editTextView.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(24) : 0, AndroidUtilities.dp(8), LocaleController.isRTL ? 0 : AndroidUtilities.dp(24), AndroidUtilities.dp(8)); + editTextView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + + } + + @Override + public void afterTextChanged(Editable s) { + int count = maxSymbolsCount - Character.codePointCount(s, 0, s.length()); + if (count < 30) { + checkTextView.setNumber(count, checkTextView.getVisibility() == View.VISIBLE); + AndroidUtilities.updateViewVisibilityAnimated(checkTextView, true); + } else { + AndroidUtilities.updateViewVisibilityAnimated(checkTextView, false); + } + } + }); + AndroidUtilities.updateViewVisibilityAnimated(checkTextView, false, 0, false); + editTextView.setText(currentBio); + editTextView.setSelection(editTextView.getText().toString().length()); + + builder.setView(dialogView); + DialogInterface.OnClickListener onDoneListener = (dialogInterface, i) -> { + if (peerId > 0) { + final TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(UserConfig.getInstance(currentAccount).getClientUserId()); + final String newName = editTextView.getText().toString().replace("\n", " ").replaceAll(" +", " ").trim(); + if (userFull != null) { + String currentName = userFull.about; + if (currentName == null) { + currentName = ""; + } + if (currentName.equals(newName)) { + AndroidUtilities.hideKeyboard(editTextView); + dialogInterface.dismiss(); + return; + } + userFull.about = newName; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, peerId, userFull); + } + + final TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile(); + req.about = newName; + req.flags |= 4; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_BIO_CHANGED, peerId); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } else { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-peerId); + final String newAbout = editTextView.getText().toString(); + if (chatFull != null) { + String currentName = chatFull.about; + if (currentName == null) { + currentName = ""; + } + if (currentName.equals(newAbout)) { + AndroidUtilities.hideKeyboard(editTextView); + dialogInterface.dismiss(); + return; + } + chatFull.about = newAbout; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, chatFull, 0, false, false); + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_BIO_CHANGED, peerId); + MessagesController.getInstance(currentAccount).updateChatAbout(-peerId, newAbout, chatFull); + } + dialogInterface.dismiss(); + }; + builder.setPositiveButton(LocaleController.getString("Save", R.string.Save), onDoneListener); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setOnPreDismissListener(dialogInterface -> AndroidUtilities.hideKeyboard(editTextView)); + dialogView.addView(editTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 23, 12, 23, 21)); + editTextView.requestFocus(); + AndroidUtilities.showKeyboard(editTextView); + + AlertDialog dialog = builder.create(); + editTextView.setOnEditorActionListener((textView, i, keyEvent) -> { + if ((i == EditorInfo.IME_ACTION_DONE || (peerId > 0 && keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER)) && dialog.isShowing()) { + onDoneListener.onClick(dialog, 0); + return true; + } + return false; + }); + + dialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_dialogBackground)); + dialog.show(); + dialog.setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); + + } + + public static void createChangeNameAlert(int peerId, Context context, int currentAccount) { + String currentName; + String currentLastName = null; + if (peerId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(peerId); + currentName = user.first_name; + currentLastName = user.last_name; + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-peerId); + currentName = chat.title; + } + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(peerId > 0 ? LocaleController.getString("VoipEditName", R.string.VoipEditName) : LocaleController.getString("VoipEditTitle", R.string.VoipEditTitle)); + LinearLayout dialogView = new LinearLayout(context); + dialogView.setOrientation(LinearLayout.VERTICAL); + + EditText firstNameEditTextView = new EditText(context); + firstNameEditTextView.setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); + firstNameEditTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + firstNameEditTextView.setMaxLines(1); + firstNameEditTextView.setLines(1); + firstNameEditTextView.setSingleLine(true); + firstNameEditTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + firstNameEditTextView.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + firstNameEditTextView.setImeOptions(peerId > 0 ? EditorInfo.IME_ACTION_NEXT : EditorInfo.IME_ACTION_DONE); + firstNameEditTextView.setHint(peerId > 0 ? LocaleController.getString("FirstName", R.string.FirstName) : LocaleController.getString("VoipEditTitleHint", R.string.VoipEditTitleHint)); + firstNameEditTextView.setBackground(Theme.createEditTextDrawable(context, true)); + firstNameEditTextView.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + firstNameEditTextView.requestFocus(); + + EditText lastNameEditTextView = null; + if (peerId > 0) { + lastNameEditTextView = new EditText(context); + lastNameEditTextView.setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); + lastNameEditTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + lastNameEditTextView.setMaxLines(1); + lastNameEditTextView.setLines(1); + lastNameEditTextView.setSingleLine(true); + lastNameEditTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + lastNameEditTextView.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + lastNameEditTextView.setImeOptions(EditorInfo.IME_ACTION_DONE); + lastNameEditTextView.setHint(LocaleController.getString("LastName", R.string.LastName)); + lastNameEditTextView.setBackground(Theme.createEditTextDrawable(context, true)); + lastNameEditTextView.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + } + + AndroidUtilities.showKeyboard(firstNameEditTextView); + + dialogView.addView(firstNameEditTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 23, 12, 23, 21)); + if (lastNameEditTextView != null) { + dialogView.addView(lastNameEditTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 23, 12, 23, 21)); + } + + firstNameEditTextView.setText(currentName); + firstNameEditTextView.setSelection(firstNameEditTextView.getText().toString().length()); + + if (lastNameEditTextView != null) { + lastNameEditTextView.setText(currentLastName); + lastNameEditTextView.setSelection(lastNameEditTextView.getText().toString().length()); + } + + + builder.setView(dialogView); + EditText finalLastNameEditTextView = lastNameEditTextView; + DialogInterface.OnClickListener onDoneListener = (dialogInterface, i) -> { + if (firstNameEditTextView.getText() == null) { + return; + } + if (peerId > 0) { + TLRPC.User currentUser = MessagesController.getInstance(currentAccount).getUser(peerId); + + String newFirst = firstNameEditTextView.getText().toString(); + String newLast = finalLastNameEditTextView.getText().toString(); + String oldFirst = currentUser.first_name; + String oldLast = currentUser.last_name; + if (oldFirst == null) { + oldFirst = ""; + } + if (oldLast == null) { + oldLast = ""; + } + if (oldFirst.equals(newFirst) && oldLast.equals(newLast)) { + dialogInterface.dismiss(); + return; + } + TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile(); + req.flags = 3; + currentUser.first_name = req.first_name = newFirst; + currentUser.last_name = req.last_name = newLast; + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + if (user != null) { + user.first_name = req.first_name; + user.last_name = req.last_name; + } + UserConfig.getInstance(currentAccount).saveConfig(true); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_NAME); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + + }); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_NAME_CHANGED, peerId); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-peerId); + String newFirst = firstNameEditTextView.getText().toString(); + if (chat.title != null && chat.title.equals(newFirst)) { + dialogInterface.dismiss(); + return; + } + chat.title = newFirst; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_CHAT_NAME); + MessagesController.getInstance(currentAccount).changeChatTitle(-peerId, newFirst); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_NAME_CHANGED, peerId); + } + dialogInterface.dismiss(); + }; + builder.setPositiveButton(LocaleController.getString("Save", R.string.Save), onDoneListener); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setOnPreDismissListener(dialogInterface -> { + AndroidUtilities.hideKeyboard(firstNameEditTextView); + AndroidUtilities.hideKeyboard(finalLastNameEditTextView); + }); + AlertDialog dialog = builder.create(); + + dialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_dialogBackground)); + dialog.show(); + dialog.setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); + + TextView.OnEditorActionListener actionListener = (textView, i, keyEvent) -> { + if ((i == EditorInfo.IME_ACTION_DONE || keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER) && dialog.isShowing()) { + onDoneListener.onClick(dialog, 0); + return true; + } + return false; + }; + if (lastNameEditTextView != null) { + lastNameEditTextView.setOnEditorActionListener(actionListener); + } else { + firstNameEditTextView.setOnEditorActionListener(actionListener); + } + + } + public interface BlockDialogCallback { void run(boolean report, boolean delete); } @@ -1640,16 +1951,28 @@ public static AlertDialog.Builder createDatePickerDialog(Context context, int mi return builder; } - private static boolean checkScheduleDate(TextView button, boolean reminder, NumberPicker dayPicker, NumberPicker hourPicker, NumberPicker minutePicker) { + public static boolean checkScheduleDate(TextView button, TextView infoText, int type, NumberPicker dayPicker, NumberPicker hourPicker, NumberPicker minutePicker) { + return checkScheduleDate(button, infoText, 0, type, dayPicker, hourPicker, minutePicker); + } + + public static boolean checkScheduleDate(TextView button, TextView infoText, long maxDate, int type, NumberPicker dayPicker, NumberPicker hourPicker, NumberPicker minutePicker) { int day = dayPicker.getValue(); int hour = hourPicker.getValue(); int minute = minutePicker.getValue(); - Calendar calendar = Calendar.getInstance(); + long systemTime = System.currentTimeMillis(); calendar.setTimeInMillis(systemTime); int currentYear = calendar.get(Calendar.YEAR); int currentDay = calendar.get(Calendar.DAY_OF_YEAR); + if (maxDate > 0) { + maxDate *= 1000; + calendar.setTimeInMillis(systemTime + maxDate); + calendar.set(Calendar.HOUR_OF_DAY, 23); + calendar.set(Calendar.MINUTE, 59); + calendar.set(Calendar.SECOND, 59); + maxDate = calendar.getTimeInMillis(); + } calendar.setTimeInMillis(System.currentTimeMillis() + (long) day * 24 * 3600 * 1000); calendar.set(Calendar.HOUR_OF_DAY, hour); @@ -1658,11 +1981,18 @@ private static boolean checkScheduleDate(TextView button, boolean reminder, Numb if (currentTime <= systemTime + 60000L) { calendar.setTimeInMillis(systemTime + 60000L); + if (currentDay != calendar.get(Calendar.DAY_OF_YEAR)) { dayPicker.setValue(day = 1); } hourPicker.setValue(hour = calendar.get(Calendar.HOUR_OF_DAY)); minutePicker.setValue(minute = calendar.get(Calendar.MINUTE)); + } else if (maxDate > 0 && currentTime > maxDate) { + calendar.setTimeInMillis(maxDate); + + dayPicker.setValue(day = 7); + hourPicker.setValue(hour = calendar.get(Calendar.HOUR_OF_DAY)); + minutePicker.setValue(minute = calendar.get(Calendar.MINUTE)); } int selectedYear = calendar.get(Calendar.YEAR); @@ -1670,8 +2000,8 @@ private static boolean checkScheduleDate(TextView button, boolean reminder, Numb calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); + long time = calendar.getTimeInMillis(); if (button != null) { - long time = calendar.getTimeInMillis(); int num; if (day == 0) { num = 0; @@ -1680,11 +2010,33 @@ private static boolean checkScheduleDate(TextView button, boolean reminder, Numb } else { num = 2; } - if (reminder) { + if (type == 1) { num += 3; + } else if (type == 2) { + num += 6; + } else if (type == 3) { + num += 9; } button.setText(LocaleController.getInstance().formatterScheduleSend[num].format(time)); } + if (infoText != null) { + int diff = (int) ((time - systemTime) / 1000); + String t; + if (diff > 24 * 60 * 60) { + t = LocaleController.formatPluralString("DaysSchedule", diff / (24 * 60 * 60)); + } else if (diff >= 60 * 60) { + t = LocaleController.formatPluralString("HoursSchedule", diff / (60 * 60)); + } else if (diff >= 60) { + t = LocaleController.formatPluralString("MinutesSchedule", diff / 60); + } else { + t = LocaleController.formatPluralString("SecondsSchedule", diff); + } + if (infoText.getTag() != null) { + infoText.setText(LocaleController.formatString("VoipGroupScheduleInfo", R.string.VoipGroupScheduleInfo, t)); + } else { + infoText.setText(LocaleController.formatString("VoipChannelScheduleInfo", R.string.VoipChannelScheduleInfo, t)); + } + } return currentTime - systemTime > 60000L; } @@ -1892,7 +2244,7 @@ public CharSequence getAccessibilityClassName() { } catch (Exception ignore) { } - checkScheduleDate(buttonTextView, selfUserId == dialogId, dayPicker, hourPicker, minutePicker); + checkScheduleDate(buttonTextView, null, selfUserId == dialogId ? 1 : 0, dayPicker, hourPicker, minutePicker); }; dayPicker.setOnValueChangedListener(onValueChangeListener); @@ -1926,7 +2278,7 @@ public CharSequence getAccessibilityClassName() { } final boolean[] canceled = {true}; - checkScheduleDate(buttonTextView, selfUserId == dialogId, dayPicker, hourPicker, minutePicker); + checkScheduleDate(buttonTextView, null, selfUserId == dialogId ? 1 : 0, dayPicker, hourPicker, minutePicker); buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); buttonTextView.setGravity(Gravity.CENTER); @@ -1937,7 +2289,7 @@ public CharSequence getAccessibilityClassName() { container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { canceled[0] = false; - boolean setSeconds = checkScheduleDate(null, selfUserId == dialogId, dayPicker, hourPicker, minutePicker); + boolean setSeconds = checkScheduleDate(null, null, selfUserId == dialogId ? 1 : 0, dayPicker, hourPicker, minutePicker); calendar.setTimeInMillis(System.currentTimeMillis() + (long) dayPicker.getValue() * 24 * 3600 * 1000); calendar.set(Calendar.HOUR_OF_DAY, hourPicker.getValue()); calendar.set(Calendar.MINUTE, minutePicker.getValue()); @@ -2078,7 +2430,7 @@ public CharSequence getAccessibilityClassName() { } catch (Exception ignore) { } - checkScheduleDate(null, false, dayPicker, hourPicker, minutePicker); + checkScheduleDate(null, null, 0, dayPicker, hourPicker, minutePicker); }; dayPicker.setOnValueChangedListener(onValueChangeListener); @@ -2110,9 +2462,8 @@ public CharSequence getAccessibilityClassName() { dayPicker.setValue(days); } } - final boolean[] canceled = {true}; - checkScheduleDate(null, false, dayPicker, hourPicker, minutePicker); + checkScheduleDate(null, null, 0, dayPicker, hourPicker, minutePicker); buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); buttonTextView.setGravity(Gravity.CENTER); @@ -2123,8 +2474,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setText(LocaleController.getString("SetTimeLimit", R.string.SetTimeLimit)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { - canceled[0] = false; - boolean setSeconds = checkScheduleDate(null, false, dayPicker, hourPicker, minutePicker); + boolean setSeconds = checkScheduleDate(null, null, 0, dayPicker, hourPicker, minutePicker); calendar.setTimeInMillis(System.currentTimeMillis() + (long) dayPicker.getValue() * 24 * 3600 * 1000); calendar.set(Calendar.HOUR_OF_DAY, hourPicker.getValue()); calendar.set(Calendar.MINUTE, minutePicker.getValue()); @@ -3011,7 +3361,7 @@ public void getOutline(View view, Outline outline) { BackupImageView imageView = new BackupImageView(activity); imageView.setRoundRadius(AndroidUtilities.dp(26)); - imageView.setImage(ImageLocation.getForUser(selfUser, false), "50_50", (Drawable) null, selfUser); + imageView.setImage(ImageLocation.getForUserOrChat(selfUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(selfUser, ImageLocation.TYPE_STRIPPED), "50_50", (Drawable) null, selfUser); frameLayout.addView(imageView, LayoutHelper.createFrame(52, 52, Gravity.CENTER, 0, 0, 0, 11)); builder.setTopView(frameLayout); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsImageView.java index 56357b3fbdb..12e8addb4e7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsImageView.java @@ -234,9 +234,9 @@ public void setObject(int index, int account, TLObject object) { animatingStates[index].id = -currentChat.id; } if (currentUser != null) { - animatingStates[index].imageReceiver.setImage(ImageLocation.getForUser(currentUser, false), "50_50", animatingStates[index].avatarDrawable, null, currentUser, 0); + animatingStates[index].imageReceiver.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", animatingStates[index].avatarDrawable, currentUser, 0); } else { - animatingStates[index].imageReceiver.setImage(ImageLocation.getForChat(currentChat, false), "50_50", animatingStates[index].avatarDrawable, null, currentChat, 0); + animatingStates[index].imageReceiver.setImage(ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_STRIPPED), "50_50", animatingStates[index].avatarDrawable, currentChat, 0); } animatingStates[index].imageReceiver.setRoundRadius(AndroidUtilities.dp(currentStyle == 4 ? 16 : 12)); int size = AndroidUtilities.dp(currentStyle == 4 ? 32 : 24); 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 a18de5f1461..7750c3e3fe1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -61,6 +61,8 @@ public final class Bulletin { public static final int TYPE_STICKER = 0; public static final int TYPE_ERROR = 1; + public static final int TYPE_BIO_CHANGED = 2; + public static final int TYPE_NAME_CHANGED = 3; public static Bulletin make(@NonNull FrameLayout containerLayout, @NonNull Layout contentLayout, int duration) { return new Bulletin(containerLayout, contentLayout, duration); @@ -1031,6 +1033,7 @@ public LottieLayout(@NonNull Context context, @ColorInt int backgroundColor, @Co textView.setTypeface(Typeface.SANS_SERIF); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); addView(textView, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 56, 0, 16, 0)); } 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 04948ecc3fa..d07641a57c0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -116,6 +116,8 @@ public Bulletin createSimpleBulletin(int iconRawId, String text) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext()); layout.setAnimation(iconRawId, 36, 36); layout.textView.setText(text); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(2); return create(layout, Bulletin.DURATION_SHORT); } 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 6fdfd9ca331..f45b25c311d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -49,6 +49,7 @@ import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ImageSpan; +import android.util.Log; import android.util.Property; import android.util.TypedValue; import android.view.ActionMode; @@ -3457,7 +3458,9 @@ public void onPause() { showKeyboardOnResume = true; } AndroidUtilities.runOnUIThread(hideKeyboardRunnable = () -> { - closeKeyboard(); + if (parentFragment == null || parentFragment.isLastFragment()) { + closeKeyboard(); + } hideKeyboardRunnable = null; }, 500); } @@ -4819,7 +4822,7 @@ public void onAnimationEnd(Animator animator) { slideText.setTranslationX(0); recordCircle.showTooltipIfNeed(); - messageEditText.setVisibility(View.GONE); + messageEditText.setAlpha(0f); } }); runningAnimationAudio.setInterpolator(new DecelerateInterpolator()); 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 c079cedd710..7f94da8cb7f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -391,6 +391,7 @@ boolean onBackPressed() { private Paint attachButtonPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private float bottomPannelTranslation; + private boolean forceDarkTheme; private class AttachButton extends FrameLayout { @@ -552,7 +553,7 @@ public void setUser(TLRPC.User user) { currentUser = user; nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); avatarDrawable.setInfo(user); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); requestLayout(); } } @@ -563,8 +564,9 @@ public void setUser(TLRPC.User user) { float currentPanTranslationY; @SuppressLint("ClickableViewAccessibility") - public ChatAttachAlert(Context context, final BaseFragment parentFragment) { + public ChatAttachAlert(Context context, final BaseFragment parentFragment, boolean forceDarkTheme) { super(context, false); + this.forceDarkTheme = forceDarkTheme; drawNavigationBar = true; inBubbleMode = parentFragment instanceof ChatActivity && parentFragment.isInBubbleMode(); openInterpolator = new OvershootInterpolator(0.7f); @@ -896,8 +898,9 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { shadowDrawable.setAlpha(viewAlpha); shadowDrawable.setBounds(0, top, getMeasuredWidth(), height); shadowDrawable.draw(canvas); + int backgroundColor = Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground); if (actionBarType == 2) { - Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_dialogBackground)); + Theme.dialogs_onlineCirclePaint.setColor(backgroundColor); Theme.dialogs_onlineCirclePaint.setAlpha(viewAlpha); rect.set(backgroundPaddingLeft, backgroundPaddingTop + top, getMeasuredWidth() - backgroundPaddingLeft, backgroundPaddingTop + top + AndroidUtilities.dp(24)); canvas.save(); @@ -909,7 +912,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean result = super.drawChild(canvas, child, drawingTime); if (rad != 1.0f && actionBarType != 2) { - Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_dialogBackground)); + Theme.dialogs_onlineCirclePaint.setColor(backgroundColor); Theme.dialogs_onlineCirclePaint.setAlpha(viewAlpha); rect.set(backgroundPaddingLeft, backgroundPaddingTop + top, getMeasuredWidth() - backgroundPaddingLeft, backgroundPaddingTop + top + AndroidUtilities.dp(24)); canvas.save(); @@ -946,7 +949,7 @@ protected void onDraw(Canvas canvas) { if (inBubbleMode) { return; } - int color1 = Theme.getColor(Theme.key_dialogBackground); + int color1 = Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground); int finalColor = Color.argb((int) (255 * actionBar.getAlpha()), (int) (Color.red(color1) * 0.8f), (int) (Color.green(color1) * 0.8f), (int) (Color.blue(color1) * 0.8f)); Theme.dialogs_onlineCirclePaint.setColor(finalColor); canvas.drawRect(backgroundPaddingLeft, currentPanTranslationY, getMeasuredWidth() - backgroundPaddingLeft, AndroidUtilities.statusBarHeight + currentPanTranslationY, Theme.dialogs_onlineCirclePaint); @@ -1162,7 +1165,7 @@ public void setTranslationY(float translationY) { selectedTextView.setVisibility(View.INVISIBLE); selectedTextView.setAlpha(0.0f); - layouts[0] = photoLayout = new ChatAttachAlertPhotoLayout(this, context); + layouts[0] = photoLayout = new ChatAttachAlertPhotoLayout(this, context, forceDarkTheme); currentAttachLayout = photoLayout; selectedId = 1; containerView.addView(photoLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -1309,7 +1312,7 @@ protected void onDraw(Canvas canvas) { float alphaOffset = (frameLayout2.getMeasuredHeight() - AndroidUtilities.dp(84)) * (1f - getAlpha()); shadow.setTranslationY(-(frameLayout2.getMeasuredHeight() - AndroidUtilities.dp(84)) + captionEditTextTopOffset + currentPanTranslationY + bottomPannelTranslation + alphaOffset); - int newColor = Theme.getColor(Theme.key_dialogBackground); + int newColor = Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground); if (color != newColor) { color = newColor; p.setColor(color); @@ -1688,6 +1691,11 @@ protected void onDraw(Canvas canvas) { selectedCountView.setScaleX(0.2f); selectedCountView.setScaleY(0.2f); containerView.addView(selectedCountView, LayoutHelper.createFrame(42, 24, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, -8, 9)); + + if (forceDarkTheme) { + checkColors(); + navBarColorKey = null; + } } @Override @@ -2130,18 +2138,18 @@ public void checkColors() { for (int a = 0; a < count; a++) { applyAttachButtonColors(buttonsRecyclerView.getChildAt(a)); } - selectedTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + selectedTextView.setTextColor(forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBarItems) : Theme.getColor(Theme.key_dialogTextBlack)); doneItem.getTextView().setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader)); - selectedMenuItem.setIconColor(Theme.getColor(Theme.key_dialogTextBlack)); - Theme.setDrawableColor(selectedMenuItem.getBackground(), Theme.getColor(Theme.key_dialogButtonSelector)); + selectedMenuItem.setIconColor(forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBarItems) : Theme.getColor(Theme.key_dialogTextBlack)); + Theme.setDrawableColor(selectedMenuItem.getBackground(), forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBarItemsSelector) : Theme.getColor(Theme.key_dialogButtonSelector)); selectedMenuItem.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), false); selectedMenuItem.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), true); selectedMenuItem.redrawPopup(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground)); - searchItem.setIconColor(Theme.getColor(Theme.key_dialogTextBlack)); - Theme.setDrawableColor(searchItem.getBackground(), Theme.getColor(Theme.key_dialogButtonSelector)); + searchItem.setIconColor(forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBarItems) : Theme.getColor(Theme.key_dialogTextBlack)); + Theme.setDrawableColor(searchItem.getBackground(), forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBarItemsSelector) : Theme.getColor(Theme.key_dialogButtonSelector)); commentTextView.updateColors(); @@ -2149,7 +2157,7 @@ public void checkColors() { for (int a = 0; a < itemCells.length; a++) { if (itemCells[a] != null) { itemCells[a].setColors(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon)); - itemCells[a].setSelectorColor(Theme.getColor(Theme.key_dialogButtonSelector)); + itemCells[a].setSelectorColor(forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBarItemsSelector) : Theme.getColor(Theme.key_dialogButtonSelector)); } } sendPopupLayout.setBackgroundColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground)); @@ -2165,18 +2173,18 @@ public void checkColors() { actionBarShadow.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); buttonsRecyclerView.setGlowColor(Theme.getColor(Theme.key_dialogScrollGlow)); - buttonsRecyclerView.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + buttonsRecyclerView.setBackgroundColor(Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground)); - frameLayout2.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + frameLayout2.setBackgroundColor(Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground)); selectedCountView.invalidate(); - actionBar.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); - actionBar.setItemsColor(Theme.getColor(Theme.key_dialogTextBlack), false); - actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_dialogButtonSelector), false); - actionBar.setTitleColor(Theme.getColor(Theme.key_dialogTextBlack)); + actionBar.setBackgroundColor(forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBar) : Theme.getColor(Theme.key_dialogBackground)); + actionBar.setItemsColor(forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBarItems) : Theme.getColor(Theme.key_dialogTextBlack), false); + actionBar.setItemsBackgroundColor(forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBarItemsSelector) : Theme.getColor(Theme.key_dialogButtonSelector), false); + actionBar.setTitleColor(forceDarkTheme ? Theme.getColor(Theme.key_voipgroup_actionBarItems) : Theme.getColor(Theme.key_dialogTextBlack)); - Theme.setDrawableColor(shadowDrawable, Theme.getColor(Theme.key_dialogBackground)); + Theme.setDrawableColor(shadowDrawable, Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground)); containerView.invalidate(); @@ -2489,7 +2497,7 @@ public void init() { if (baseFragment == null) { return; } - if (baseFragment instanceof ChatActivity) { + if (baseFragment instanceof ChatActivity && avatarPicker != 2) { TLRPC.Chat chat = ((ChatActivity) baseFragment).getCurrentChat(); TLRPC.User user = ((ChatActivity) baseFragment).getCurrentUser(); if (chat != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java index 5fab1da19af..be2606fc875 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java @@ -208,7 +208,7 @@ public void update(int mask) { lastAvatar = photo; if (currentUser != null) { - avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser); } else { avatarImageView.setImageDrawable(avatarDrawable); } 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 f2f33559aed..4ee7645909a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -190,6 +190,8 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou private final static int compress = 1; private final static int open_in = 2; + boolean forceDarkTheme; + private class BasePhotoProvider extends PhotoViewer.EmptyPhotoViewerProvider { @Override public boolean isPhotoChecked(int index) { @@ -433,8 +435,9 @@ private ArrayList getAllPhotosArray() { return arrayList; } - public ChatAttachAlertPhotoLayout(ChatAttachAlert alert, Context context) { + public ChatAttachAlertPhotoLayout(ChatAttachAlert alert, Context context, boolean forceDarkTheme) { super(alert, context); + this.forceDarkTheme = forceDarkTheme; NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.albumsDidLoad); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.cameraInitied); FrameLayout container = alert.getContainer(); @@ -596,16 +599,15 @@ public int getSpanSize(int position) { PhotoViewer.getInstance().setMaxSelectedPhotos(parentAlert.maxSelectedPhotos, parentAlert.allowOrder); ChatActivity chatActivity; int type; - if (parentAlert.baseFragment instanceof ChatActivity) { + if (parentAlert.avatarPicker != 0) { + chatActivity = null; + type = PhotoViewer.SELECT_TYPE_AVATAR; + } else if (parentAlert.baseFragment instanceof ChatActivity) { chatActivity = (ChatActivity) parentAlert.baseFragment; type = 0; } else { chatActivity = null; - if (parentAlert.avatarPicker != 0) { - type = PhotoViewer.SELECT_TYPE_AVATAR; - } else { - type = 4; - } + type = 4; } AndroidUtilities.hideKeyboard(parentAlert.baseFragment.getFragmentView().findFocus()); AndroidUtilities.hideKeyboard(parentAlert.getContainer().findFocus()); @@ -1247,16 +1249,15 @@ private void openPhotoViewer(MediaController.PhotoEntry entry, final boolean sam ChatActivity chatActivity; int type; - if (parentAlert.baseFragment instanceof ChatActivity) { + if (parentAlert.avatarPicker != 0) { + type = PhotoViewer.SELECT_TYPE_AVATAR; + chatActivity = null; + } else if (parentAlert.baseFragment instanceof ChatActivity) { chatActivity = (ChatActivity) parentAlert.baseFragment; type = 2; } else { chatActivity = null; - if (parentAlert.avatarPicker != 0) { - type = PhotoViewer.SELECT_TYPE_AVATAR; - } else { - type = 5; - } + type = 5; } ArrayList arrayList; int index; @@ -1490,7 +1491,7 @@ private void setCameraFlashModeIcon(ImageView imageView, String mode) { } public void checkCamera(boolean request) { - if (parentAlert.baseFragment == null) { + if (parentAlert.baseFragment == null || parentAlert.baseFragment.getParentActivity() == null) { return; } boolean old = deviceHasGoodCamera; @@ -2363,6 +2364,7 @@ void checkColors() { if (cameraIcon != null) { cameraIcon.invalidate(); } + String textColor = forceDarkTheme ? Theme.key_voipgroup_actionBarItems : Theme.key_dialogTextBlack; Theme.setDrawableColor(cameraDrawable, Theme.getColor(Theme.key_dialogCameraIcon)); progressView.setTextColor(Theme.getColor(Theme.key_emptyListPlaceholder)); gridView.setGlowColor(Theme.getColor(Theme.key_dialogScrollGlow)); @@ -2371,11 +2373,11 @@ void checkColors() { ((PhotoAttachCameraCell) holder.itemView).getImageView().setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogCameraIcon), PorterDuff.Mode.MULTIPLY)); } - dropDown.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - dropDownContainer.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), false); - dropDownContainer.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), true); - dropDownContainer.redrawPopup(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground)); - Theme.setDrawableColor(dropDownDrawable, Theme.getColor(Theme.key_dialogTextBlack)); + dropDown.setTextColor(Theme.getColor(textColor)); + dropDownContainer.setPopupItemsColor(Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_actionBarItems : Theme.key_actionBarDefaultSubmenuItem), false); + dropDownContainer.setPopupItemsColor(Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_actionBarItems :Theme.key_actionBarDefaultSubmenuItem), true); + dropDownContainer.redrawPopup(Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_actionBarUnscrolled : Theme.key_actionBarDefaultSubmenuBackground)); + Theme.setDrawableColor(dropDownDrawable, Theme.getColor(textColor)); } @Override @@ -2389,7 +2391,7 @@ void onInit(boolean hasMedia) { cameraIcon.setAlpha(mediaEnabled ? 1.0f : 0.2f); cameraIcon.setEnabled(mediaEnabled); } - if (parentAlert.baseFragment instanceof ChatActivity) { + if (parentAlert.baseFragment instanceof ChatActivity && parentAlert.avatarPicker == 0) { galleryAlbumEntry = MediaController.allMediaAlbumEntry; if (mediaEnabled) { progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); 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 c803d239ed7..6a1ec32a677 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -589,7 +589,7 @@ public void onAnimationEnd(Animator animation) { public void setChatAvatar(TLRPC.Chat chat) { avatarDrawable.setInfo(chat); if (avatarImageView != null) { - avatarImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } } @@ -615,7 +615,7 @@ public void setUserAvatar(TLRPC.User user, boolean showSelf) { } else { avatarDrawable.setSmallSize(false); if (avatarImageView != null) { - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } } @@ -643,13 +643,13 @@ public void checkAndUpdateAvatar() { } else { avatarDrawable.setSmallSize(false); if (avatarImageView != null) { - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } } else if (chat != null) { avatarDrawable.setInfo(chat); if (avatarImageView != null) { - avatarImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java index 682995d1404..d4acc5cfe1e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java @@ -9,25 +9,20 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DocumentObject; -import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLocation; 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.SvgHelper; -import org.telegram.messenger.UserConfig; -import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; -import java.util.ArrayList; import java.util.Locale; -import java.util.Random; -public class ChatGreetingsView extends LinearLayout implements NotificationCenter.NotificationCenterDelegate { +public class ChatGreetingsView extends LinearLayout { private TLRPC.Document preloadedGreetingsSticker; private TextView titleView; @@ -39,7 +34,7 @@ public class ChatGreetingsView extends LinearLayout implements NotificationCente public BackupImageView stickerToSendView; - public ChatGreetingsView(Context context, TLRPC.User user, int distance, int currentAccount, TLRPC.Document preloadedGreetingsSticker) { + public ChatGreetingsView(Context context, TLRPC.User user, int distance, int currentAccount, TLRPC.Document sticker) { super(context); setOrientation(VERTICAL); this.currentAccount = currentAccount; @@ -70,16 +65,17 @@ public ChatGreetingsView(Context context, TLRPC.User user, int distance, int cur descriptionView.setText(LocaleController.getString("NearbyPeopleGreetingsDescription", R.string.NearbyPeopleGreetingsDescription)); } - this.preloadedGreetingsSticker = preloadedGreetingsSticker; - + preloadedGreetingsSticker = sticker; if (preloadedGreetingsSticker == null) { - MessagesController.getInstance(currentAccount).preloadGreetingsSticker(); - } else { - setSticker(preloadedGreetingsSticker); + preloadedGreetingsSticker = MediaDataController.getInstance(currentAccount).getGreetingsSticker(); } + setSticker(preloadedGreetingsSticker); } private void setSticker(TLRPC.Document sticker) { + if (sticker == null) { + return; + } SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(sticker, Theme.key_chat_serviceBackground, 1.0f); if (svgThumb != null) { stickerToSendView.setImage(ImageLocation.getForDocument(sticker), createFilter(sticker), svgThumb, 0, sticker); @@ -177,26 +173,17 @@ public void requestLayout() { protected void onAttachedToWindow() { super.onAttachedToWindow(); fetchSticker(); - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.greetingsStickerLoaded); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.greetingsStickerLoaded); } private void fetchSticker() { if (preloadedGreetingsSticker == null) { - preloadedGreetingsSticker = MessagesController.getInstance(currentAccount).getPreloadedSticker(); - if (preloadedGreetingsSticker != null) { - setSticker(preloadedGreetingsSticker); - } + preloadedGreetingsSticker = MediaDataController.getInstance(currentAccount).getGreetingsSticker(); + setSticker(preloadedGreetingsSticker); } } - - @Override - public void didReceivedNotification(int id, int account, Object... args) { - fetchSticker(); - } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ContextProgressView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ContextProgressView.java index 361dad03dcb..15952d2b16b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ContextProgressView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ContextProgressView.java @@ -27,6 +27,8 @@ public class ContextProgressView extends View { private int currentColorType; private String innerKey; private String outerKey; + private int innerColor; + private int outerColor; public ContextProgressView(Context context, int colorType) { super(context); @@ -51,9 +53,25 @@ public ContextProgressView(Context context, int colorType) { updateColors(); } + public void setColors(int innerColor, int outerColor) { + innerKey = null; + outerKey = null; + this.innerColor = innerColor; + this.outerColor = outerColor; + updateColors(); + } + public void updateColors() { - innerPaint.setColor(Theme.getColor(innerKey)); - outerPaint.setColor(Theme.getColor(outerKey)); + if (innerKey != null) { + innerPaint.setColor(Theme.getColor(innerKey)); + } else { + innerPaint.setColor(innerColor); + } + if (outerKey != null) { + outerPaint.setColor(Theme.getColor(outerKey)); + } else { + outerPaint.setColor(outerColor); + } invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java index 38c3110a985..c2c649252a3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java @@ -1134,8 +1134,12 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } } if (indicatorWidth != 0) { + canvas.save(); + canvas.translate(listView.getTranslationX(), 0); + canvas.scale(listView.getScaleX(), 1f, listView.getPivotX() + listView.getX(), listView.getPivotY()); selectorDrawable.setBounds((int) indicatorX, height - AndroidUtilities.dpr(4), (int) (indicatorX + indicatorWidth), height); selectorDrawable.draw(canvas); + canvas.restore(); } } long newTime = SystemClock.elapsedRealtime(); @@ -1525,4 +1529,8 @@ public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHol viewHolder.itemView.setBackground(null); } } + + public RecyclerListView getListView() { + return listView; + } } 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 8dccba7212a..cb8f5d3835f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java @@ -17,8 +17,13 @@ import android.content.DialogInterface; import android.content.Intent; import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.Typeface; import android.os.Build; import android.os.Bundle; @@ -26,8 +31,11 @@ import androidx.annotation.Keep; import android.os.SystemClock; +import android.text.Layout; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.StaticLayout; +import android.text.TextPaint; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; @@ -104,6 +112,42 @@ public class FragmentContextView extends FrameLayout implements NotificationCent private boolean supportsCalls = true; private AvatarsImageView avatars; + private Paint gradientPaint; + private LinearGradient linearGradient; + private Matrix matrix; + private int gradientWidth; + private TextPaint gradientTextPaint; + private StaticLayout timeLayout; + private RectF rect = new RectF(); + private boolean scheduleRunnableScheduled; + private Runnable updateScheduleTimeRunnable = new Runnable() { + @Override + public void run() { + if (gradientTextPaint == null || !(fragment instanceof ChatActivity)) { + scheduleRunnableScheduled = false; + return; + } + ChatObject.Call call = ((ChatActivity) fragment).getGroupCall(); + if (call == null || !call.isScheduled()) { + timeLayout = null; + scheduleRunnableScheduled = false; + return; + } + int currentTime = fragment.getConnectionsManager().getCurrentTime(); + int diff = call.call.schedule_date - currentTime; + String str; + if (diff >= 24 * 60 * 60) { + str = LocaleController.formatPluralString("Days", Math.round(diff / (24 * 60 * 60.0f))); + } else { + str = AndroidUtilities.formatFullDuration(call.call.schedule_date - currentTime); + } + int width = (int) Math.ceil(gradientTextPaint.measureText(str)); + timeLayout = new StaticLayout(str, gradientTextPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + AndroidUtilities.runOnUIThread(updateScheduleTimeRunnable, 1000); + frameLayout.invalidate(); + } + }; + private final int account = UserConfig.selectedAccount; private boolean isLocation; @@ -173,6 +217,44 @@ public void invalidate() { avatars.invalidate(); } } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (currentStyle == 4 && timeLayout != null) { + int width = (int) Math.ceil(timeLayout.getLineWidth(0)) + AndroidUtilities.dp(24); + if (width != gradientWidth) { + linearGradient = new LinearGradient(0, 0, width * 1.7f, 0, new int[]{0xff648CF4, 0xff8C69CF, 0xffD45979, 0xffD45979}, new float[]{0.0f, 0.294f, 0.588f, 1.0f}, Shader.TileMode.CLAMP); + gradientPaint.setShader(linearGradient); + gradientWidth = width; + } + ChatObject.Call call = ((ChatActivity) fragment).getGroupCall(); + float moveProgress = 0.0f; + if (fragment != null && call != null && call.isScheduled()) { + long diff = ((long) call.call.schedule_date) * 1000 - fragment.getConnectionsManager().getCurrentTimeMillis(); + if (diff < 0) { + moveProgress = 1.0f; + } else if (diff < 5000) { + moveProgress = 1.0f - diff / 5000.0f; + } + if (diff < 6000) { + invalidate(); + } + } + matrix.reset(); + matrix.postTranslate(-gradientWidth * 0.7f * moveProgress, 0); + linearGradient.setLocalMatrix(matrix); + int x = getMeasuredWidth() - width - AndroidUtilities.dp(10); + int y = AndroidUtilities.dp(12); + rect.set(0, 0, width, AndroidUtilities.dp(24)); + canvas.save(); + canvas.translate(x, y); + canvas.drawRoundRect(rect, AndroidUtilities.dp(12), AndroidUtilities.dp(12), gradientPaint); + canvas.translate(AndroidUtilities.dp(12), AndroidUtilities.dp(4)); + timeLayout.draw(canvas); + canvas.restore(); + } + } }; addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); @@ -528,7 +610,7 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { } } else if (currentStyle == 3) { if (VoIPService.getSharedInstance() != null && getContext() instanceof LaunchActivity) { - GroupCallActivity.create((LaunchActivity) getContext(), AccountInstance.getInstance(VoIPService.getSharedInstance().getAccount())); + GroupCallActivity.create((LaunchActivity) getContext(), AccountInstance.getInstance(VoIPService.getSharedInstance().getAccount()), null, null, false, null); } } else if (currentStyle == 4) { if (fragment.getParentActivity() == null) { @@ -614,7 +696,7 @@ private void checkVisibility() { show = true; } else if (fragment instanceof ChatActivity && fragment.getSendMessagesHelper().getImportingHistory(((ChatActivity) fragment).getDialogId()) != null && !isPlayingVoice()) { show = true; - } else if (fragment instanceof ChatActivity && ((ChatActivity) fragment).getGroupCall() != null && ((ChatActivity) fragment).getGroupCall().call.participants_count > 0 && !GroupCallPip.isShowing() && !isPlayingVoice()) { + } else if (fragment instanceof ChatActivity && ((ChatActivity) fragment).getGroupCall() != null && ((ChatActivity) fragment).getGroupCall().shouldShowPanel() && !GroupCallPip.isShowing() && !isPlayingVoice()) { show = true; } else { MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); @@ -656,6 +738,10 @@ private void updateStyle(int style) { } } currentStyle = style; + frameLayout.setWillNotDraw(currentStyle != 4); + if (style != 4) { + timeLayout = null; + } if (avatars != null) { avatars.setStyle(currentStyle); @@ -738,9 +824,7 @@ private void updateStyle(int style) { frameLayout.setBackgroundColor(Theme.getColor(Theme.key_inappPlayerBackground)); frameLayout.setTag(Theme.key_inappPlayerBackground); muteButton.setVisibility(GONE); - subtitleTextView.setVisibility(VISIBLE); - joinButton.setVisibility(VISIBLE); for (int i = 0; i < 2; i++) { TextView textView = i == 0 ? titleTextView.getTextView() : titleTextView.getNextTextView(); @@ -754,7 +838,6 @@ private void updateStyle(int style) { } titleTextView.setTag(Theme.key_inappPlayerPerformer); titleTextView.setPadding(0, 0, 0, 0); - titleTextView.setText(LocaleController.getString("VoipGroupVoiceChat", R.string.VoipGroupVoiceChat), false); importingImageView.setVisibility(GONE); importingImageView.stopAnimation(); @@ -820,6 +903,10 @@ protected void onDetachedFromWindow() { animatorSet.cancel(); animatorSet = null; } + if (scheduleRunnableScheduled) { + AndroidUtilities.cancelRunOnUIThread(updateScheduleTimeRunnable); + scheduleRunnableScheduled = false; + } visible = false; NotificationCenter.getInstance(account).onAnimationFinish(animationIndex); topPadding = 0; @@ -885,7 +972,7 @@ protected void onAttachedToWindow() { checkCall(true); } else if (fragment instanceof ChatActivity && fragment.getSendMessagesHelper().getImportingHistory(((ChatActivity) fragment).getDialogId()) != null && !isPlayingVoice()) { checkImport(true); - } else if (fragment instanceof ChatActivity && ((ChatActivity) fragment).getGroupCall() != null && ((ChatActivity) fragment).getGroupCall().call.participants_count > 0 && !GroupCallPip.isShowing() && !isPlayingVoice()) { + } else if (fragment instanceof ChatActivity && ((ChatActivity) fragment).getGroupCall() != null && ((ChatActivity) fragment).getGroupCall().shouldShowPanel() && !GroupCallPip.isShowing() && !isPlayingVoice()) { checkCall(true); } else { checkPlayer(true); @@ -905,6 +992,11 @@ protected void onAttachedToWindow() { muteDrawable.setCurrentFrame(muteDrawable.getCustomEndFrame() - 1, false, true); muteButton.invalidate(); } + } else if (currentStyle == 4) { + if (!scheduleRunnableScheduled) { + scheduleRunnableScheduled = true; + updateScheduleTimeRunnable.run(); + } } if (visible && topPadding == 0) { @@ -963,7 +1055,9 @@ public void didReceivedNotification(int id, int account, Object... args) { if (visible && currentStyle == 4) { ChatObject.Call call = ((ChatActivity) fragment).getGroupCall(); if (call != null) { - if (call.call.participants_count == 0) { + if (call.isScheduled()) { + subtitleTextView.setText(LocaleController.formatStartsTime(call.call.schedule_date, 4), false); + } else if (call.call.participants_count == 0) { subtitleTextView.setText(LocaleController.getString("MembersTalkingNobody", R.string.MembersTalkingNobody), false); } else { subtitleTextView.setText(LocaleController.formatPluralString("Participants", call.call.participants_count), false); @@ -1226,7 +1320,7 @@ private void checkPlayer(boolean create) { boolean callAvailable = supportsCalls && VoIPService.getSharedInstance() != null && !VoIPService.getSharedInstance().isHangingUp() && VoIPService.getSharedInstance().getCallState() != VoIPService.STATE_WAITING_INCOMING && !GroupCallPip.isShowing(); if (!isPlayingVoice() && !callAvailable && fragment instanceof ChatActivity && !GroupCallPip.isShowing()) { ChatObject.Call call = ((ChatActivity) fragment).getGroupCall(); - callAvailable = call != null && call.call.participants_count > 0; + callAvailable = call != null && call.shouldShowPanel(); } if (callAvailable) { checkCall(false); @@ -1558,7 +1652,7 @@ public void checkCall(boolean create) { groupActive = false; if (!isPlayingVoice() && !GroupCallActivity.groupCallUiVisible && supportsCalls && !callAvailable && fragment instanceof ChatActivity) { ChatObject.Call call = ((ChatActivity) fragment).getGroupCall(); - if (call != null && call.call.participants_count > 0) { + if (call != null && call.shouldShowPanel()) { callAvailable = true; groupActive = true; } @@ -1614,7 +1708,7 @@ public void onAnimationEnd(Animator animation) { int newStyle; if (groupActive) { newStyle = 4; - } else if (voIPService != null && voIPService.groupCall != null) { + } else if (voIPService.groupCall != null) { newStyle = 3; } else { newStyle = 1; @@ -1653,11 +1747,37 @@ public void onAnimationEnd(Animator animation) { updateStyle(4); ChatObject.Call call = ((ChatActivity) fragment).getGroupCall(); + if (call.isScheduled()) { + if (gradientPaint == null) { + gradientTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + gradientTextPaint.setColor(0xffffffff); + gradientTextPaint.setTextSize(AndroidUtilities.dp(14)); + gradientTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - if (call.call.participants_count == 0) { - subtitleTextView.setText(LocaleController.getString("MembersTalkingNobody", R.string.MembersTalkingNobody), false); + gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + gradientPaint.setColor(0xffffffff); + + matrix = new Matrix(); + } + joinButton.setVisibility(GONE); + if (!TextUtils.isEmpty(call.call.title)) { + titleTextView.setText(call.call.title, false); + } else { + titleTextView.setText(LocaleController.getString("VoipGroupScheduledVoiceChat", R.string.VoipGroupScheduledVoiceChat), false); + } + subtitleTextView.setText(LocaleController.formatStartsTime(call.call.schedule_date, 2), false); + if (!scheduleRunnableScheduled) { + scheduleRunnableScheduled = true; + updateScheduleTimeRunnable.run(); + } } else { - subtitleTextView.setText(LocaleController.formatPluralString("Participants", call.call.participants_count), false); + joinButton.setVisibility(VISIBLE); + titleTextView.setText(LocaleController.getString("VoipGroupVoiceChat", R.string.VoipGroupVoiceChat), false); + if (call.call.participants_count == 0) { + subtitleTextView.setText(LocaleController.getString("MembersTalkingNobody", R.string.MembersTalkingNobody), false); + } else { + subtitleTextView.setText(LocaleController.formatPluralString("Participants", call.call.participants_count), false); + } } updateAvatars(avatars.wasDraw && updateAnimated); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextViewWavesDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextViewWavesDrawable.java index 1434d1ff606..aaa17915d68 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextViewWavesDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextViewWavesDrawable.java @@ -10,6 +10,8 @@ import android.os.SystemClock; import android.view.View; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.Utilities; @@ -78,7 +80,11 @@ public void draw(float left, float top, float right, float bottom, Canvas canvas if (dt > 20) { dt = 17; } - + if (dt < 3) { + update = false; + } + } + if (update) { if (animateToAmplitude != amplitude) { amplitude += animateAmplitudeDiff * dt; if (animateAmplitudeDiff > 0) { @@ -145,7 +151,7 @@ public void draw(float left, float top, float right, float bottom, Canvas canvas lineBlobDrawable2.minRadius = AndroidUtilities.dp(0); lineBlobDrawable2.maxRadius = AndroidUtilities.dp(3) + AndroidUtilities.dp(9) * amplitude; - if (i == 1) { + if (i == 1 && update) { lineBlobDrawable.update(amplitude, 0.3f); lineBlobDrawable1.update(amplitude, 0.7f); lineBlobDrawable2.update(amplitude, 0.7f); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java index 2c9d4bc5941..8a2fb3ef868 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java @@ -143,7 +143,7 @@ public GroupCreateSpan(Context context, Object object, ContactsController.Contac } else { avatarDrawable.setInfo(user); firstName = UserObject.getFirstName(user); - imageLocation = ImageLocation.getForUser(user, false); + imageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL); imageParent = user; } } else if (object instanceof TLRPC.Chat) { @@ -151,7 +151,7 @@ public GroupCreateSpan(Context context, Object object, ContactsController.Contac avatarDrawable.setInfo(chat); uid = -chat.id; firstName = chat.title; - imageLocation = ImageLocation.getForChat(chat, false); + imageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL); imageParent = chat; } else { avatarDrawable.setInfo(0, contact.first_name, contact.last_name); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java index 41bcba6e6ac..0ce4f090dde 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java @@ -331,12 +331,14 @@ private void updatePosition(View view) { top += AndroidUtilities.dp(4); } else if (currentType == 6) { top += view.getMeasuredHeight() + getMeasuredHeight() + AndroidUtilities.dp(10); - } else if (currentType == 7 || currentType == 8) { + } else if (currentType == 7 || currentType == 8 && isTopArrow) { top += view.getMeasuredHeight() + getMeasuredHeight() + AndroidUtilities.dp(8); + } else if (currentType == 8) { + top -= AndroidUtilities.dp(10); } int centerX; - if (currentType == 8) { + if (currentType == 8 && isTopArrow) { if (view instanceof SimpleTextView) { SimpleTextView textView = (SimpleTextView) view; Drawable drawable = textView.getRightDrawable(); @@ -374,7 +376,9 @@ private void updatePosition(View view) { leftMargin = ((MarginLayoutParams) getLayoutParams()).leftMargin; rightMargin = ((MarginLayoutParams) getLayoutParams()).rightMargin; } - if (centerX > parentView.getMeasuredWidth() / 2) { + if (currentType == 8 && !isTopArrow) { + offset = (parentWidth - leftMargin - rightMargin - getMeasuredWidth()) / 2; + } else if (centerX > parentView.getMeasuredWidth() / 2) { if (currentType == TYPE_SEARCH_AS_LIST) { offset = (int) (parentWidth - getMeasuredWidth() * 1.5f); } else { 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 31eb257ca14..e400484c7dc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java @@ -88,6 +88,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega private double videoTimestamp; private boolean canSelectVideo; + private boolean forceDarkTheme; private final static int attach_photo = 0; @@ -208,6 +209,11 @@ public void setSearchAvailable(boolean value) { useAttachMenu = searchAvailable = value; } + public void setSearchAvailable(boolean value, boolean useAttachMenu) { + this.useAttachMenu = useAttachMenu; + searchAvailable = value; + } + public void setUploadAfterSelect(boolean value) { uploadAfterSelect = value; } @@ -319,7 +325,7 @@ private void createChatAttachView() { return; } if (chatAttachAlert == null) { - chatAttachAlert = new ChatAttachAlert(parentFragment.getParentActivity(), parentFragment); + chatAttachAlert = new ChatAttachAlert(parentFragment.getParentActivity(), parentFragment, forceDarkTheme); chatAttachAlert.setAvatarPicker(canSelectVideo ? 2 : 1, searchAvailable); chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { @@ -882,4 +888,8 @@ public void didReceivedNotification(int id, int account, Object... args) { parentFragment.getFileLoader().uploadFile(uploadingVideo, false, false, (int) convertingVideo.videoEditedInfo.estimatedSize, ConnectionsManager.FileTypeVideo, false); } } + + public void setForceDarkTheme(boolean forceDarkTheme) { + this.forceDarkTheme = forceDarkTheme; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinCallAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinCallAlert.java index 4022e16992c..a3292eedb22 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinCallAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinCallAlert.java @@ -39,7 +39,7 @@ import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.GroupCreateUserCell; -import org.telegram.ui.ContentPreviewViewer; +import org.telegram.ui.Cells.ShareDialogCell; import java.util.ArrayList; @@ -67,6 +67,7 @@ public class JoinCallAlert extends BottomSheet { private TLRPC.Peer selectedPeer; private TLRPC.Peer currentPeer; private TLRPC.InputPeer selectAfterDismiss; + private boolean schedule; private boolean animationInProgress; @@ -101,21 +102,26 @@ public static void processDeletedChat(int account, long did) { } public interface JoinCallAlertDelegate { - void didSelectChat(TLRPC.InputPeer peer, boolean hasFewPeers); + void didSelectChat(TLRPC.InputPeer peer, boolean hasFewPeers, boolean schedule); } public class BottomSheetCell extends FrameLayout { private View background; private TextView[] textView = new TextView[2]; - private LinearLayout linearLayout; + private boolean hasBackground; - public BottomSheetCell(Context context) { + public BottomSheetCell(Context context, boolean withoutBackground) { super(context); + hasBackground = !withoutBackground; + setBackground(null); + background = new View(context); - background.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); - addView(background, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 16, 16, 16, 16)); + if (hasBackground) { + background.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); + } + addView(background, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 16, withoutBackground ? 0 : 16, 16, 16)); for (int a = 0; a < 2; a++) { textView[a] = new TextView(context); @@ -124,9 +130,14 @@ public BottomSheetCell(Context context) { textView[a].setGravity(Gravity.CENTER_HORIZONTAL); textView[a].setEllipsize(TextUtils.TruncateAt.END); textView[a].setGravity(Gravity.CENTER); - textView[a].setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + if (hasBackground) { + textView[a].setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + textView[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + } else { + textView[a].setTextColor(Theme.getColor(Theme.key_featuredStickers_addButton)); + } textView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - textView[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView[a].setPadding(0, 0, 0, hasBackground ? 0 : AndroidUtilities.dp(13)); addView(textView[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); if (a == 1) { textView[a].setAlpha(0.0f); @@ -136,7 +147,7 @@ public BottomSheetCell(Context context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(hasBackground ? 80 : 50), MeasureSpec.EXACTLY)); } public void setText(CharSequence text, boolean animated) { @@ -201,16 +212,16 @@ public static void checkFewUsers(Context context, int did, AccountInstance accou } } - public static void open(Context context, int did, AccountInstance accountInstance, BaseFragment fragment, int type, JoinCallAlertDelegate delegate) { + public static void open(Context context, int did, AccountInstance accountInstance, BaseFragment fragment, int type, TLRPC.Peer scheduledPeer, JoinCallAlertDelegate delegate) { if (context == null || delegate == null) { return; } if (lastCachedAccount == accountInstance.getCurrentAccount() && lastCacheDid == did && cachedChats != null && SystemClock.elapsedRealtime() - lastCacheTime < 5 * 60 * 1000) { - if (cachedChats.size() == 1) { + if (cachedChats.size() == 1 && type != TYPE_CREATE) { TLRPC.InputPeer peer = accountInstance.getMessagesController().getInputPeer(MessageObject.getPeerId(cachedChats.get(0))); - delegate.didSelectChat(peer, false); + delegate.didSelectChat(peer, false, false); } else { - showAlert(context, cachedChats, fragment, type, delegate); + showAlert(context, did, cachedChats, fragment, type, scheduledPeer, delegate); } } else { final AlertDialog progressDialog = new AlertDialog(context, 3); @@ -226,7 +237,7 @@ public static void open(Context context, int did, AccountInstance accountInstanc TLRPC.TL_phone_joinAsPeers res = (TLRPC.TL_phone_joinAsPeers) response; if (res.peers.size() == 1) { TLRPC.InputPeer peer = accountInstance.getMessagesController().getInputPeer(MessageObject.getPeerId(res.peers.get(0))); - delegate.didSelectChat(peer, false); + delegate.didSelectChat(peer, false, false); return; } cachedChats = res.peers; @@ -235,7 +246,7 @@ public static void open(Context context, int did, AccountInstance accountInstanc lastCachedAccount = accountInstance.getCurrentAccount(); accountInstance.getMessagesController().putChats(res.chats, false); accountInstance.getMessagesController().putUsers(res.users, false); - showAlert(context, res.peers, fragment, type, delegate); + showAlert(context, did, res.peers, fragment, type, scheduledPeer, delegate); } })); progressDialog.setOnCancelListener(dialog -> accountInstance.getConnectionsManager().cancelRequest(reqId, true)); @@ -247,8 +258,8 @@ public static void open(Context context, int did, AccountInstance accountInstanc } } - private static void showAlert(Context context, ArrayList peers, BaseFragment fragment, int type, JoinCallAlertDelegate delegate) { - JoinCallAlert alert = new JoinCallAlert(context, peers, type, delegate); + private static void showAlert(Context context, long dialogId, ArrayList peers, BaseFragment fragment, int type, TLRPC.Peer scheduledPeer, JoinCallAlertDelegate delegate) { + JoinCallAlert alert = new JoinCallAlert(context, dialogId, peers, type, scheduledPeer, delegate); if (fragment != null) { if (fragment.getParentActivity() != null) { fragment.showDialog(alert); @@ -258,14 +269,13 @@ private static void showAlert(Context context, ArrayList peers, Base } } - private JoinCallAlert(Context context, ArrayList chats, int type, JoinCallAlertDelegate delegate) { + private JoinCallAlert(Context context, long dialogId, ArrayList arrayList, int type, TLRPC.Peer scheduledPeer, JoinCallAlertDelegate delegate) { super(context, false); setApplyBottomPadding(false); - this.chats = chats; + chats = new ArrayList<>(arrayList); this.delegate = delegate; currentType = type; - shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow_round).mutate(); if (type == TYPE_DISPLAY) { if (VoIPService.getSharedInstance() != null) { @@ -277,6 +287,15 @@ private JoinCallAlert(Context context, ArrayList chats, int type, Jo break; } } + } else if (scheduledPeer != null) { + long did = MessageObject.getPeerId(scheduledPeer); + for (int a = 0, N = chats.size(); a < N; a++) { + TLRPC.Peer p = chats.get(a); + if (MessageObject.getPeerId(p) == did) { + selectedPeer = currentPeer = p; + break; + } + } } else { selectedPeer = chats.get(0); } @@ -286,77 +305,119 @@ private JoinCallAlert(Context context, ArrayList chats, int type, Jo selectedPeer = chats.get(0); } - containerView = new FrameLayout(context) { - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_DOWN && scrollOffsetY != 0 && ev.getY() < scrollOffsetY) { - dismiss(); - return true; + ViewGroup internalLayout; + if (currentType == TYPE_CREATE) { + LinearLayout linearLayout = new LinearLayout(context) { + + boolean sorted; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (currentType == TYPE_CREATE) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int totalWidth = chats.size() * AndroidUtilities.dp(95); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) listView.getLayoutParams(); + if (totalWidth > width) { + layoutParams.width = LayoutHelper.MATCH_PARENT; + layoutParams.gravity = Gravity.TOP | Gravity.LEFT; + if (!sorted) { + if (selectedPeer != null) { + chats.remove(selectedPeer); + chats.add(0, selectedPeer); + } + sorted = true; + } + } else { + layoutParams.width = LayoutHelper.WRAP_CONTENT; + layoutParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + if (!sorted) { + if (selectedPeer != null) { + int idx; + if (chats.size() % 2 == 0) { + idx = Math.max(0, chats.size() / 2 - 1); + } else { + idx = chats.size() / 2; + } + chats.remove(selectedPeer); + chats.add(idx, selectedPeer); + } + sorted = true; + } + } + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - return super.onInterceptTouchEvent(ev); - } - - @Override - public boolean onTouchEvent(MotionEvent e) { - return !isDismissed() && super.onTouchEvent(e); - } + }; + linearLayout.setOrientation(LinearLayout.VERTICAL); + setCustomView(internalLayout = linearLayout); + } else { + containerView = new FrameLayout(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int height = MeasureSpec.getSize(heightMeasureSpec); - if (Build.VERSION.SDK_INT >= 21) { - height -= AndroidUtilities.statusBarHeight; + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN && scrollOffsetY != 0 && ev.getY() < scrollOffsetY) { + dismiss(); + return true; + } + return super.onInterceptTouchEvent(ev); } - measureChildWithMargins(messageTextView, widthMeasureSpec, 0, heightMeasureSpec, 0); - int h = messageTextView.getMeasuredHeight(); - ((LayoutParams) listView.getLayoutParams()).topMargin = AndroidUtilities.dp(65) + h; - int measuredWidth = getMeasuredWidth(); - int padding; - int contentSize = AndroidUtilities.dp(80) + chats.size() * AndroidUtilities.dp(58) + backgroundPaddingTop + AndroidUtilities.dp(55) + h; - if (contentSize < height / 5 * 3) { - padding = height - contentSize; - } else { - padding = height / 5 * 2; + + @Override + public boolean onTouchEvent(MotionEvent e) { + return !isDismissed() && super.onTouchEvent(e); } - if (listView.getPaddingTop() != padding) { - ignoreLayout = true; - listView.setPadding(0, padding, 0, 0); - ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = MeasureSpec.getSize(heightMeasureSpec); + if (Build.VERSION.SDK_INT >= 21) { + height -= AndroidUtilities.statusBarHeight; + } + measureChildWithMargins(messageTextView, widthMeasureSpec, 0, heightMeasureSpec, 0); + int h = messageTextView.getMeasuredHeight(); + ((LayoutParams) listView.getLayoutParams()).topMargin = AndroidUtilities.dp(65) + h; + int measuredWidth = getMeasuredWidth(); + int padding; + int contentSize = AndroidUtilities.dp(80) + chats.size() * AndroidUtilities.dp(58) + backgroundPaddingTop + AndroidUtilities.dp(55) + h; + if (contentSize < height / 5 * 3) { + padding = height - contentSize; + } else { + padding = height / 5 * 2; + } + if (listView.getPaddingTop() != padding) { + ignoreLayout = true; + listView.setPadding(0, padding, 0, 0); + ignoreLayout = false; + } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); } - super.onMeasure(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); - updateLayout(); - } + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + updateLayout(); + } - @Override - public void requestLayout() { - if (ignoreLayout) { - return; + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); } - super.requestLayout(); - } - @Override - protected void onDraw(Canvas canvas) { - shadowDrawable.setBounds(0, scrollOffsetY - backgroundPaddingTop, getMeasuredWidth(), getMeasuredHeight()); - shadowDrawable.draw(canvas); - } - }; - containerView.setWillNotDraw(false); - containerView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, 0); + @Override + protected void onDraw(Canvas canvas) { + shadowDrawable.setBounds(0, scrollOffsetY - backgroundPaddingTop, getMeasuredWidth(), getMeasuredHeight()); + shadowDrawable.draw(canvas); + } + }; + internalLayout = containerView; + containerView.setWillNotDraw(false); + containerView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, 0); + } listView = new RecyclerListView(context) { - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - boolean result = ContentPreviewViewer.getInstance().onInterceptTouchEvent(event, listView, 0, null); - return super.onInterceptTouchEvent(event) || result; - } - @Override public void requestLayout() { if (ignoreLayout) { @@ -365,7 +426,7 @@ public void requestLayout() { super.requestLayout(); } }; - listView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); + listView.setLayoutManager(new LinearLayoutManager(getContext(), currentType == TYPE_CREATE ? LinearLayoutManager.HORIZONTAL : LinearLayoutManager.VERTICAL, false)); listView.setAdapter(new ListAdapter(context)); listView.setVerticalScrollBarEnabled(false); listView.setClipToPadding(false); @@ -381,18 +442,41 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (animationInProgress || chats.get(position) == selectedPeer) { return; } - GroupCreateUserCell cell = (GroupCreateUserCell) view; selectedPeer = chats.get(position); - cell.setChecked(true, true); + if (view instanceof GroupCreateUserCell) { + ((GroupCreateUserCell) view).setChecked(true, true); + } else if (view instanceof ShareDialogCell) { + ((ShareDialogCell) view).setChecked(true, true); + view.invalidate(); + } for (int a = 0, N = listView.getChildCount(); a < N; a++) { - GroupCreateUserCell child = (GroupCreateUserCell) listView.getChildAt(a); - if (child != cell) { - child.setChecked(false, true); + View child = listView.getChildAt(a); + if (child != view) { + if (view instanceof GroupCreateUserCell) { + ((GroupCreateUserCell) child).setChecked(false, true); + } else if (view instanceof ShareDialogCell) { + ((ShareDialogCell) child).setChecked(false, true); + } } } - updateDoneButton(true); + if (currentType != TYPE_CREATE) { + updateDoneButton(true); + } }); - containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 100, 0, 80)); + if (type != TYPE_CREATE) { + internalLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 100, 0, 80)); + } else { + listView.setSelectorDrawableColor(0); + listView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); + } + + if (type == TYPE_CREATE) { + RLottieImageView imageView = new RLottieImageView(context); + imageView.setAutoRepeat(true); + imageView.setAnimation(R.raw.utyan_schedule, 120, 120); + imageView.playAnimation(); + internalLayout.addView(imageView, LayoutHelper.createLinear(160, 160, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 17, 8, 17, 0)); + } textView = new TextView(context); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -402,16 +486,19 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } else { textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); } - if (type == TYPE_DISPLAY) { - textView.setText(LocaleController.getString("VoipGroupDisplayAs", R.string.VoipGroupDisplayAs)); - } else if (type == TYPE_CREATE) { - textView.setText(LocaleController.getString("VoipGroupStartAs", R.string.VoipGroupStartAs)); - } else { - textView.setText(LocaleController.getString("VoipGroupJoinAs", R.string.VoipGroupJoinAs)); - } textView.setSingleLine(true); textView.setEllipsize(TextUtils.TruncateAt.END); - containerView.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 23, 0, 23, 0)); + if (type == TYPE_CREATE) { + textView.setText(LocaleController.getString("StartVoipChatTitle", R.string.StartVoipChatTitle)); + internalLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 23, 16, 23, 0)); + } else { + if (type == TYPE_DISPLAY) { + textView.setText(LocaleController.getString("VoipGroupDisplayAs", R.string.VoipGroupDisplayAs)); + } else { + textView.setText(LocaleController.getString("VoipGroupJoinAs", R.string.VoipGroupJoinAs)); + } + internalLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 23, 8, 23, 0)); + } messageTextView = new TextView(getContext()); if (type == TYPE_DISPLAY) { @@ -431,45 +518,86 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } } } - if (hasGroup) { - messageTextView.setText(LocaleController.getString("VoipGroupStartAsInfoGroup", R.string.VoipGroupStartAsInfoGroup)); - } else { - messageTextView.setText(LocaleController.getString("VoipGroupStartAsInfo", R.string.VoipGroupStartAsInfo)); - } messageTextView.setMovementMethod(new AndroidUtilities.LinkMovementMethodMy()); messageTextView.setLinkTextColor(Theme.getColor(Theme.key_dialogTextLink)); - messageTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); - containerView.addView(messageTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 23, 0, 23, 5)); + if (type == TYPE_CREATE) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat((int) -dialogId); + StringBuilder builder = new StringBuilder(); + if (ChatObject.isChannel(chat) && !chat.megagroup) { + builder.append(LocaleController.getString("VoipChannelStart2", R.string.VoipChannelStart2)); + } else { + builder.append(LocaleController.getString("VoipGroupStart2", R.string.VoipGroupStart2)); + } + if (chats.size() > 1) { + builder.append("\n\n").append(LocaleController.getString("VoipChatDisplayedAs", R.string.VoipChatDisplayedAs)); + } else { + listView.setVisibility(View.GONE); + } + messageTextView.setText(builder); + messageTextView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP); + internalLayout.addView(messageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 23, 0, 23, 5)); + } else { + if (hasGroup) { + messageTextView.setText(LocaleController.getString("VoipGroupStartAsInfoGroup", R.string.VoipGroupStartAsInfoGroup)); + } else { + messageTextView.setText(LocaleController.getString("VoipGroupStartAsInfo", R.string.VoipGroupStartAsInfo)); + } + messageTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); + internalLayout.addView(messageTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 23, 0, 23, 5)); + } - doneButton = new BottomSheetCell(context); - doneButton.setBackground(null); + if (type == TYPE_CREATE) { + internalLayout.addView(listView, LayoutHelper.createLinear(chats.size() < 5 ? LayoutHelper.WRAP_CONTENT : LayoutHelper.MATCH_PARENT, 95, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 6, 0, 0)); + } + + doneButton = new BottomSheetCell(context, false); doneButton.background.setOnClickListener(v -> { TLRPC.InputPeer peer = MessagesController.getInstance(currentAccount).getInputPeer(MessageObject.getPeerId(selectedPeer)); if (currentType == TYPE_DISPLAY) { if (selectedPeer != currentPeer) { - delegate.didSelectChat(peer, chats.size() > 1); + delegate.didSelectChat(peer, chats.size() > 1, false); } } else { selectAfterDismiss = peer; } dismiss(); }); - containerView.addView(doneButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 0)); + if (currentType == TYPE_CREATE) { + internalLayout.addView(doneButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0)); + + BottomSheetCell scheduleButton = new BottomSheetCell(context, true); + scheduleButton.setText(LocaleController.getString("VoipGroupScheduleVoiceChat", R.string.VoipGroupScheduleVoiceChat), false); + scheduleButton.background.setOnClickListener(v -> { + selectAfterDismiss = MessagesController.getInstance(currentAccount).getInputPeer(MessageObject.getPeerId(selectedPeer)); + schedule = true; + dismiss(); + }); + internalLayout.addView(scheduleButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0)); + } else { + internalLayout.addView(doneButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 0)); + } updateDoneButton(false); } private void updateDoneButton(boolean animated) { - int did = MessageObject.getPeerId(selectedPeer); - if (did > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); - doneButton.setText(LocaleController.formatString("VoipGroupContinueAs", R.string.VoipGroupContinueAs, UserObject.getFirstName(user)), animated); + if (currentType == TYPE_CREATE) { + doneButton.setText(LocaleController.formatString("VoipGroupStartVoiceChat", R.string.VoipGroupStartVoiceChat), animated); } else { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); - doneButton.setText(LocaleController.formatString("VoipGroupContinueAs", R.string.VoipGroupContinueAs, chat != null ? chat.title : ""), animated); + int did = MessageObject.getPeerId(selectedPeer); + if (did > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); + doneButton.setText(LocaleController.formatString("VoipGroupContinueAs", R.string.VoipGroupContinueAs, UserObject.getFirstName(user)), animated); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); + doneButton.setText(LocaleController.formatString("VoipGroupContinueAs", R.string.VoipGroupContinueAs, chat != null ? chat.title : ""), animated); + } } } private void updateLayout() { + if (currentType == TYPE_CREATE) { + return; + } if (listView.getChildCount() <= 0) { listView.setTopGlowOffset(scrollOffsetY = listView.getPaddingTop()); containerView.invalidate(); @@ -491,7 +619,7 @@ private void updateLayout() { public void dismissInternal() { super.dismissInternal(); if (selectAfterDismiss != null) { - delegate.didSelectChat(selectAfterDismiss, chats.size() > 1); + delegate.didSelectChat(selectAfterDismiss, chats.size() > 1, schedule); } } @@ -525,30 +653,41 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = new GroupCreateUserCell(context, 2, 0, false, currentType == TYPE_DISPLAY); + View view; + if (currentType == TYPE_CREATE) { + view = new ShareDialogCell(context, ShareDialogCell.TYPE_CREATE); + view.setLayoutParams(new RecyclerView.LayoutParams(AndroidUtilities.dp(80), AndroidUtilities.dp(100))); + } else { + view = new GroupCreateUserCell(context, 2, 0, false, currentType == TYPE_DISPLAY); + } return new RecyclerListView.Holder(view); } @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { int position = holder.getAdapterPosition(); - GroupCreateUserCell cell = (GroupCreateUserCell) holder.itemView; - Object object = cell.getObject(); - if (object != null) { - int did = MessageObject.getPeerId(selectedPeer); - int id; - if (object instanceof TLRPC.Chat) { - id = -((TLRPC.Chat) object).id; - } else { - id = ((TLRPC.User) object).id; + long did = MessageObject.getPeerId(selectedPeer); + if (holder.itemView instanceof GroupCreateUserCell) { + GroupCreateUserCell cell = (GroupCreateUserCell) holder.itemView; + Object object = cell.getObject(); + long id = 0; + if (object != null) { + if (object instanceof TLRPC.Chat) { + id = -((TLRPC.Chat) object).id; + } else { + id = ((TLRPC.User) object).id; + } } cell.setChecked(did == id, false); + } else { + ShareDialogCell cell = (ShareDialogCell) holder.itemView; + long id = cell.getCurrentDialog(); + cell.setChecked(did == id, false); } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - GroupCreateUserCell cell = (GroupCreateUserCell) holder.itemView; int did = MessageObject.getPeerId(chats.get(position)); TLObject object; String status; @@ -559,7 +698,13 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { object = MessagesController.getInstance(currentAccount).getChat(-did); status = null; } - cell.setObject(object, null, status, position != getItemCount() - 1); + if (currentType == TYPE_CREATE) { + ShareDialogCell cell = (ShareDialogCell) holder.itemView; + cell.setDialog(did, did == MessageObject.getPeerId(selectedPeer), null); + } else { + GroupCreateUserCell cell = (GroupCreateUserCell) holder.itemView; + cell.setObject(object, null, status, position != getItemCount() - 1); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinCallByUrlAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinCallByUrlAlert.java index 669b20453dd..7596f5f7d5e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinCallByUrlAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinCallByUrlAlert.java @@ -80,7 +80,7 @@ public JoinCallByUrlAlert(final Context context, TLRPC.Chat chat) { linearLayout.addView(avatarImageView, LayoutHelper.createLinear(90, 90, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 29, 0, 0)); AvatarDrawable avatarDrawable = new AvatarDrawable(chat); - avatarImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); TextView percentTextView = new TextView(context); percentTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinGroupAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinGroupAlert.java index 6f9813fd7f5..1ca621e0bb7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinGroupAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/JoinGroupAlert.java @@ -68,7 +68,7 @@ public JoinGroupAlert(final Context context, TLRPC.ChatInvite invite, String gro avatarDrawable = new AvatarDrawable(invite.chat); title = invite.chat.title; participants_count = invite.chat.participants_count; - avatarImageView.setImage(ImageLocation.getForChat(invite.chat, false), "50_50", avatarDrawable, invite); + avatarImageView.setImage(ImageLocation.getForUserOrChat(invite.chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(invite.chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, invite); } else { avatarDrawable = new AvatarDrawable(); avatarDrawable.setInfo(0, invite.title, null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java index ecad7aa3805..e10abe87c7c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java @@ -232,6 +232,7 @@ public void setSelectorColor(int color) { public NumberPicker(Context context) { this(context, 18); } + public NumberPicker(Context context, int textSize) { super(context); mTextSize = AndroidUtilities.dp(textSize); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java index 4e0aeca48ce..114f7a971fc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java @@ -117,7 +117,7 @@ public UserCell(Context context) { BackupImageView avatarImageView = new BackupImageView(context); avatarImageView.setRoundRadius(AndroidUtilities.dp(40)); - avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser); addView(avatarImageView, LayoutHelper.createLinear(80, 80, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 32, 0, 0)); TextView textView = new TextView(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java index 3e995aac7af..8d4955509c7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java @@ -375,7 +375,7 @@ public void update(int mask) { lastAvatar = photo; if (currentUser != null) { - avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, currentUser); } else { avatarImageView.setImageDrawable(avatarDrawable); } 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 0686f3e09cb..a716ee0fb01 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java @@ -13,7 +13,6 @@ import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.text.TextUtils; -import android.util.Log; import android.util.SparseArray; import android.view.MotionEvent; import android.view.View; @@ -31,6 +30,7 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.PinchToZoomHelper; import org.telegram.ui.ProfileActivity; import java.util.ArrayList; @@ -55,6 +55,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio private boolean scrolledByUser; private boolean isDownReleased; private final boolean isProfileFragment; + private ImageLocation uploadingImageLocation; private int currentAccount = UserConfig.selectedAccount; @@ -70,21 +71,29 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio private ArrayList imagesLocations = new ArrayList<>(); private ArrayList thumbsLocations = new ArrayList<>(); private ArrayList imagesLocationsSizes = new ArrayList<>(); + private ArrayList imagesUploadProgress = new ArrayList<>(); private int settingMainPhoto; private final SparseArray radialProgresses = new SparseArray<>(); - private OnPageChangeListener onPageChangeListener; + private boolean createThumbFromParent = true; + private boolean forceResetPosition; + private boolean invalidateWithParent; + + PinchToZoomHelper pinchToZoomHelper; private static class Item { - private BackupImageView imageView; + private AvatarImageView imageView; } public interface Callback { void onDown(boolean left); + void onRelease(); + void onPhotosLoaded(); + void onVideoSet(); } @@ -238,7 +247,6 @@ public void onPageScrollStateChanged(int state) { MessagesController.getInstance(currentAccount).loadDialogPhotos((int) dialogId, 80, 0, true, parentClassGuid); } - public void onDestroy() { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.dialogPhotosLoaded); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileDidLoad); @@ -302,8 +310,21 @@ public boolean onTouchEvent(MotionEvent ev) { cancelEvent.recycle(); return false; } - final int action = ev.getAction(); + + if (pinchToZoomHelper != null) { + if (action != MotionEvent.ACTION_DOWN && isDownReleased && !pinchToZoomHelper.isInOverlayMode()) { + pinchToZoomHelper.checkPinchToZoom(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0), this, getCurrentItemView().getImageReceiver(), null); + } else if (pinchToZoomHelper.checkPinchToZoom(ev, this, getCurrentItemView().getImageReceiver(), null)) { + if (!isDownReleased) { + isDownReleased = true; + callback.onRelease(); + } + return true; + } + } + + if (action == MotionEvent.ACTION_DOWN) { isScrollingListView = true; isSwipingViewPager = true; @@ -393,6 +414,7 @@ public void setChatInfo(TLRPC.ChatFull chatFull) { videoLocations.set(0, null); videoFileNames.add(0, null); } + imagesUploadProgress.set(0, null); adapter.notifyDataSetChanged(); } } @@ -402,8 +424,13 @@ public boolean initIfEmpty(ImageLocation imageLocation, ImageLocation thumbLocat return false; } if (prevImageLocation == null || prevImageLocation.location.local_id != imageLocation.location.local_id) { - imagesLocations.clear(); - MessagesController.getInstance(currentAccount).loadDialogPhotos((int) dialogId, 80, 0, true, parentClassGuid); + if (!imagesLocations.isEmpty()) { + prevImageLocation = imageLocation; + MessagesController.getInstance(currentAccount).loadDialogPhotos((int) dialogId, 80, 0, true, parentClassGuid); + return true; + } else { + MessagesController.getInstance(currentAccount).loadDialogPhotos((int) dialogId, 80, 0, true, parentClassGuid); + } } if (!imagesLocations.isEmpty()) { return false; @@ -416,11 +443,39 @@ public boolean initIfEmpty(ImageLocation imageLocation, ImageLocation thumbLocat videoLocations.add(null); photos.add(null); imagesLocationsSizes.add(-1); + imagesUploadProgress.add(null); getAdapter().notifyDataSetChanged(); - resetCurrentItem(); + // resetCurrentItem(); return true; } + ImageLocation currentUploadingImageLocation; + ImageLocation curreantUploadingThumbLocation; + + public void addUploadingImage(ImageLocation imageLocation, ImageLocation thumbLocation) { + prevImageLocation = imageLocation; + thumbsFileNames.add(0, null); + videoFileNames.add(0, null); + imagesLocations.add(0, imageLocation); + thumbsLocations.add(0, thumbLocation); + videoLocations.add(0, null); + photos.add(0, null); + imagesLocationsSizes.add(0, -1); + imagesUploadProgress.add(0, 0f); + adapter.notifyDataSetChanged(); + resetCurrentItem(); + + currentUploadingImageLocation = imageLocation; + curreantUploadingThumbLocation = thumbLocation; + + } + + public void removeUploadingImage(ImageLocation imageLocation) { + uploadingImageLocation = imageLocation; + currentUploadingImageLocation = null; + curreantUploadingThumbLocation = null; + } + public ImageLocation getImageLocation(int index) { if (index < 0 || index >= imagesLocations.size()) { return null; @@ -576,6 +631,10 @@ public void startMovePhotoToBegin(int index) { imagesLocationsSizes.remove(index); imagesLocationsSizes.add(0, size); + Float uploadProgress = imagesUploadProgress.get(index); + imagesUploadProgress.remove(index); + imagesUploadProgress.add(0, uploadProgress); + prevImageLocation = imagesLocations.get(0); } @@ -596,6 +655,7 @@ public boolean removePhotoAtIndex(int index) { thumbsLocations.remove(index); imagesLocationsSizes.remove(index); radialProgresses.delete(index); + imagesUploadProgress.remove(index); if (index == 0 && !imagesLocations.isEmpty()) { prevImageLocation = imagesLocations.get(0); } @@ -640,13 +700,14 @@ public void didReceivedNotification(int id, int account, Object... args) { thumbsLocations.clear(); photos.clear(); imagesLocationsSizes.clear(); + imagesUploadProgress.clear(); ImageLocation currentImageLocation = null; if (did < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); - currentImageLocation = ImageLocation.getForChat(chat, true); + currentImageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_BIG); if (currentImageLocation != null) { imagesLocations.add(currentImageLocation); - thumbsLocations.add(ImageLocation.getForChat(chat, false)); + thumbsLocations.add(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL)); thumbsFileNames.add(null); if (chatInfo != null && FileLoader.isSamePhoto(currentImageLocation.location, chatInfo.chat_photo)) { photos.add(chatInfo.chat_photo); @@ -664,6 +725,7 @@ public void didReceivedNotification(int id, int account, Object... args) { videoLocations.add(null); } imagesLocationsSizes.add(-1); + imagesUploadProgress.add(null); } } for (int a = 0; a < arrayList.size(); a++) { @@ -717,20 +779,24 @@ public void didReceivedNotification(int id, int account, Object... args) { } photos.add(photo); imagesLocationsSizes.add(sizeFull.size); + imagesUploadProgress.add(null); } } } loadNeighboringThumbs(); getAdapter().notifyDataSetChanged(); if (isProfileFragment) { - if (!scrolledByUser) { + if (!scrolledByUser || forceResetPosition) { resetCurrentItem(); } } else { - resetCurrentItem(); - getAdapter().notifyDataSetChanged(); + if (!scrolledByUser || forceResetPosition) { + resetCurrentItem(); + getAdapter().notifyDataSetChanged(); + } } + forceResetPosition = false; if (fromCache) { MessagesController.getInstance(currentAccount).loadDialogPhotos(did, 80, 0, false, parentClassGuid); @@ -738,6 +804,9 @@ public void didReceivedNotification(int id, int account, Object... args) { if (callback != null) { callback.onPhotosLoaded(); } + if (currentUploadingImageLocation != null) { + addUploadingImage(currentUploadingImageLocation, curreantUploadingThumbLocation); + } } } else if (id == NotificationCenter.fileDidLoad) { final String fileName = (String) args[0]; @@ -817,147 +886,7 @@ public Item instantiateItem(ViewGroup container, int position) { final Item item = objects.get(position); if (item.imageView == null) { - item.imageView = new BackupImageView(context) { - - private final int radialProgressSize = AndroidUtilities.dp(64f); - - private RadialProgress2 radialProgress; - private ValueAnimator radialProgressHideAnimator; - private float radialProgressHideAnimatorStartValue; - private long firstDrawTime = -1; - private boolean isVideo; - - { - getImageReceiver().setAllowDecodeSingleFrame(true); - final int realPosition = getRealPosition(position); - boolean needProgress = false; - if (realPosition == 0) { - Drawable drawable = parentAvatarImageView == null ? null : parentAvatarImageView.getImageReceiver().getDrawable(); - if (drawable instanceof AnimatedFileDrawable && ((AnimatedFileDrawable) drawable).hasBitmap()) { - AnimatedFileDrawable animatedFileDrawable = (AnimatedFileDrawable) drawable; - setImageDrawable(drawable); - animatedFileDrawable.addSecondParentView(this); - animatedFileDrawable.setInvalidateParentViewWithSecond(true); - } else { - ImageLocation videoLocation = videoLocations.get(realPosition); - isVideo = videoLocation != null; - needProgress = true; - String filter; - if (isProfileFragment && videoLocation != null && videoLocation.imageType == FileLoader.IMAGE_TYPE_ANIMATION) { - filter = ImageLoader.AUTOPLAY_FILTER; - } else { - filter = null; - } - Bitmap thumb = parentAvatarImageView == null ? null : parentAvatarImageView.getImageReceiver().getBitmap(); - setImageMedia(videoLocations.get(realPosition), filter, imagesLocations.get(realPosition), null, thumb, imagesLocationsSizes.get(realPosition), 1, "avatar_" + dialogId); - } - } else { - final ImageLocation videoLocation = videoLocations.get(realPosition); - isVideo = videoLocation != null; - needProgress = true; - ImageLocation location = thumbsLocations.get(realPosition); - String filter = location.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; - setImageMedia(videoLocation, null, imagesLocations.get(realPosition), null, thumbsLocations.get(realPosition), filter, null, imagesLocationsSizes.get(realPosition), 1, location); - } - if (needProgress) { - radialProgress = radialProgresses.get(realPosition); - if (radialProgress == null) { - radialProgress = new RadialProgress2(this); - radialProgress.setOverrideAlpha(0.0f); - radialProgress.setIcon(MediaActionDrawable.ICON_EMPTY, false, false); - radialProgress.setColors(0x42000000, 0x42000000, Color.WHITE, Color.WHITE); - radialProgresses.append(realPosition, radialProgress); - } - postInvalidateOnAnimation(); - } - getImageReceiver().setDelegate(new ImageReceiver.ImageReceiverDelegate() { - @Override - public void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb, boolean memCache) { - - } - - @Override - public void onAnimationReady(ImageReceiver imageReceiver) { - callback.onVideoSet(); - } - }); - getImageReceiver().setCrossfadeAlpha((byte) 2); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - if (radialProgress != null) { - int paddingTop = (parentActionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight(); - int paddingBottom = AndroidUtilities.dp2(80f); - radialProgress.setProgressRect((w - radialProgressSize) / 2, paddingTop + (h - paddingTop - paddingBottom - radialProgressSize) / 2, (w + radialProgressSize) / 2, paddingTop + (h - paddingTop - paddingBottom + radialProgressSize) / 2); - } - } - - @Override - protected void onDraw(Canvas canvas) { - if (radialProgress != null) { - final Drawable drawable = getImageReceiver().getDrawable(); - if (drawable != null && (!isVideo || (drawable instanceof AnimatedFileDrawable && ((AnimatedFileDrawable) drawable).getDurationMs() > 0))) { - if (radialProgressHideAnimator == null) { - long startDelay = 0; - if (radialProgress.getProgress() < 1f) { - radialProgress.setProgress(1f, true); - startDelay = 100; - } - radialProgressHideAnimatorStartValue = radialProgress.getOverrideAlpha(); - radialProgressHideAnimator = ValueAnimator.ofFloat(0f, 1f); - radialProgressHideAnimator.setStartDelay(startDelay); - radialProgressHideAnimator.setDuration((long) (radialProgressHideAnimatorStartValue * 250f)); - radialProgressHideAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); - radialProgressHideAnimator.addUpdateListener(anim -> radialProgress.setOverrideAlpha(AndroidUtilities.lerp(radialProgressHideAnimatorStartValue, 0f, anim.getAnimatedFraction()))); - radialProgressHideAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - radialProgress = null; - radialProgresses.delete(getRealPosition(position)); - } - }); - radialProgressHideAnimator.start(); - } - } else { - if (firstDrawTime < 0) { - firstDrawTime = System.currentTimeMillis(); - } else { - final long elapsedTime = System.currentTimeMillis() - firstDrawTime; - final long startDelay = isVideo ? 250 : 750; - final long duration = 250; - if (elapsedTime <= startDelay + duration) { - if (elapsedTime > startDelay) { - radialProgress.setOverrideAlpha(CubicBezierInterpolator.DEFAULT.getInterpolation((elapsedTime - startDelay) / (float) duration)); - } - } - } - postInvalidateOnAnimation(); - } - if (roundTopRadius == 0 && roundBottomRadius == 0) { - canvas.drawRect(0, 0, getWidth(), getHeight(), placeholderPaint); - } else if (roundTopRadius == roundBottomRadius) { - rect.set(0, 0, getWidth(), getHeight()); - canvas.drawRoundRect(rect, roundTopRadius, roundTopRadius, placeholderPaint); - } else { - path.reset(); - rect.set(0, 0, getWidth(), getHeight()); - for (int i = 0; i < 4; i++) { - radii[i] = roundTopRadius; - radii[4 + i] = roundBottomRadius; - } - path.addRoundRect(rect, radii, Path.Direction.CW); - canvas.drawPath(path, placeholderPaint); - } - } - super.onDraw(canvas); - - if (radialProgress != null && radialProgress.getOverrideAlpha() > 0f) { - radialProgress.draw(canvas); - } - } - }; + item.imageView = new AvatarImageView(context, position, placeholderPaint); imageViews.set(position, item.imageView); } @@ -965,6 +894,76 @@ public void onAnimationEnd(Animator animation) { container.addView(item.imageView); } + item.imageView.getImageReceiver().setAllowDecodeSingleFrame(true); + final int realPosition = getRealPosition(position); + boolean needProgress = false; + if (realPosition == 0) { + Drawable drawable = parentAvatarImageView == null ? null : parentAvatarImageView.getImageReceiver().getDrawable(); + if (drawable instanceof AnimatedFileDrawable && ((AnimatedFileDrawable) drawable).hasBitmap()) { + AnimatedFileDrawable animatedFileDrawable = (AnimatedFileDrawable) drawable; + item.imageView.setImageDrawable(drawable); + animatedFileDrawable.addSecondParentView(item.imageView); + animatedFileDrawable.setInvalidateParentViewWithSecond(true); + } else { + ImageLocation videoLocation = videoLocations.get(realPosition); + item.imageView.isVideo = videoLocation != null; + needProgress = true; + String filter; + if (isProfileFragment && videoLocation != null && videoLocation.imageType == FileLoader.IMAGE_TYPE_ANIMATION) { + filter = ImageLoader.AUTOPLAY_FILTER; + } else { + filter = null; + } + ImageLocation location = thumbsLocations.get(realPosition); + Bitmap thumb = (parentAvatarImageView == null || !createThumbFromParent) ? null : parentAvatarImageView.getImageReceiver().getBitmap(); + if (thumb != null) { + item.imageView.setImageMedia(videoLocations.get(realPosition), filter, imagesLocations.get(realPosition), null, thumb, imagesLocationsSizes.get(realPosition), 1, location); + } else if (uploadingImageLocation != null) { + item.imageView.setImageMedia(videoLocations.get(realPosition), filter, imagesLocations.get(realPosition), null, uploadingImageLocation, null, null, imagesLocationsSizes.get(realPosition), 1, location); + } else { + String thumbFilter = location.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; + item.imageView.setImageMedia(videoLocation, null, imagesLocations.get(realPosition), null, thumbsLocations.get(realPosition), thumbFilter, null, imagesLocationsSizes.get(realPosition), 1, location); + } + } + } else { + final ImageLocation videoLocation = videoLocations.get(realPosition); + item.imageView.isVideo = videoLocation != null; + needProgress = true; + ImageLocation location = thumbsLocations.get(realPosition); + String filter = location.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; + item.imageView.setImageMedia(videoLocation, null, imagesLocations.get(realPosition), null, thumbsLocations.get(realPosition), filter, null, imagesLocationsSizes.get(realPosition), 1, location); + } + if (imagesUploadProgress.get(realPosition) != null) { + needProgress = true; + } + if (needProgress) { + item.imageView.radialProgress = radialProgresses.get(realPosition); + if (item.imageView.radialProgress == null) { + item.imageView.radialProgress = new RadialProgress2(item.imageView); + item.imageView.radialProgress.setOverrideAlpha(0.0f); + item.imageView.radialProgress.setIcon(MediaActionDrawable.ICON_EMPTY, false, false); + item.imageView.radialProgress.setColors(0x42000000, 0x42000000, Color.WHITE, Color.WHITE); + radialProgresses.append(realPosition, item.imageView.radialProgress); + } + if (invalidateWithParent) { + invalidate(); + } else { + postInvalidateOnAnimation(); + } + } + item.imageView.getImageReceiver().setDelegate(new ImageReceiver.ImageReceiverDelegate() { + @Override + public void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb, boolean memCache) { + + } + + @Override + public void onAnimationReady(ImageReceiver imageReceiver) { + callback.onVideoSet(); + } + }); + item.imageView.getImageReceiver().setCrossfadeAlpha((byte) 2); + item.imageView.setRoundRadius(roundTopRadius, roundTopRadius, roundBottomRadius, roundBottomRadius); return item; @@ -981,6 +980,7 @@ public void destroyItem(ViewGroup container, int position, Object object) { } imageView.setRoundRadius(0); container.removeView(imageView); + imageView.getImageReceiver().cancelLoadImage(); } @Nullable @@ -1021,6 +1021,8 @@ public void setData(long dialogId) { resetCurrentItem(); return; } + forceResetPosition = true; + adapter.notifyDataSetChanged(); reset(); this.dialogId = dialogId; MessagesController.getInstance(currentAccount).loadDialogPhotos((int) dialogId, 80, 0, true, parentClassGuid); @@ -1034,8 +1036,9 @@ private void reset() { imagesLocations.clear(); thumbsLocations.clear(); imagesLocationsSizes.clear(); + imagesUploadProgress.clear(); adapter.notifyDataSetChanged(); - resetCurrentItem(); + uploadingImageLocation = null; } public void setRoundRadius(int topRadius, int bottomRadius) { @@ -1055,4 +1058,150 @@ public void setParentAvatarImage(BackupImageView parentImageView) { adapter.parentAvatarImageView = parentImageView; } } + + public void setUploadProgress(ImageLocation imageLocation, float p) { + if (imageLocation == null) { + return; + } + for (int i = 0; i < imagesLocations.size(); i++) { + if (imagesLocations.get(i) == imageLocation) { + imagesUploadProgress.set(i, p); + if (radialProgresses.get(i) != null) { + radialProgresses.get(i).setProgress(p, true); + } + break; + } + } + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).invalidate(); + } + } + + public void setCreateThumbFromParent(boolean createThumbFromParent) { + this.createThumbFromParent = createThumbFromParent; + } + + private class AvatarImageView extends BackupImageView { + + private final int radialProgressSize = AndroidUtilities.dp(64f); + + private RadialProgress2 radialProgress; + private ValueAnimator radialProgressHideAnimator; + private float radialProgressHideAnimatorStartValue; + private long firstDrawTime = -1; + public boolean isVideo; + private final int position; + private final Paint placeholderPaint; + + public AvatarImageView(Context context, int position, Paint placeholderPaint) { + super(context); + this.position = position; + this.placeholderPaint = placeholderPaint; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (radialProgress != null) { + int paddingTop = (parentActionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight(); + int paddingBottom = AndroidUtilities.dp2(80f); + radialProgress.setProgressRect((w - radialProgressSize) / 2, paddingTop + (h - paddingTop - paddingBottom - radialProgressSize) / 2, (w + radialProgressSize) / 2, paddingTop + (h - paddingTop - paddingBottom + radialProgressSize) / 2); + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (pinchToZoomHelper != null && pinchToZoomHelper.isInOverlayMode()) { + return; + } + if (radialProgress != null) { + final int realPosition = getRealPosition(position); + final Drawable drawable = getImageReceiver().getDrawable(); + boolean hideProgress; + if (realPosition < imagesUploadProgress.size() && imagesUploadProgress.get(realPosition) != null) { + hideProgress = imagesUploadProgress.get(realPosition) >= 1f; + } else { + hideProgress = drawable != null && (!isVideo || (drawable instanceof AnimatedFileDrawable && ((AnimatedFileDrawable) drawable).getDurationMs() > 0)); + } + if (hideProgress) { + if (radialProgressHideAnimator == null) { + long startDelay = 0; + if (radialProgress.getProgress() < 1f) { + radialProgress.setProgress(1f, true); + startDelay = 100; + } + radialProgressHideAnimatorStartValue = radialProgress.getOverrideAlpha(); + radialProgressHideAnimator = ValueAnimator.ofFloat(0f, 1f); + radialProgressHideAnimator.setStartDelay(startDelay); + radialProgressHideAnimator.setDuration((long) (radialProgressHideAnimatorStartValue * 250f)); + radialProgressHideAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + radialProgressHideAnimator.addUpdateListener(anim -> radialProgress.setOverrideAlpha(AndroidUtilities.lerp(radialProgressHideAnimatorStartValue, 0f, anim.getAnimatedFraction()))); + radialProgressHideAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + radialProgress = null; + radialProgresses.delete(getRealPosition(position)); + } + }); + radialProgressHideAnimator.start(); + } + } else { + if (firstDrawTime < 0) { + firstDrawTime = System.currentTimeMillis(); + } else { + final long elapsedTime = System.currentTimeMillis() - firstDrawTime; + final long startDelay = isVideo ? 250 : 750; + final long duration = 250; + if (elapsedTime <= startDelay + duration) { + if (elapsedTime > startDelay) { + radialProgress.setOverrideAlpha(CubicBezierInterpolator.DEFAULT.getInterpolation((elapsedTime - startDelay) / (float) duration)); + } + } + } + if (invalidateWithParent) { + invalidate(); + } else { + postInvalidateOnAnimation(); + } + invalidate(); + } + if (roundTopRadius == 0 && roundBottomRadius == 0) { + canvas.drawRect(0, 0, getWidth(), getHeight(), placeholderPaint); + } else if (roundTopRadius == roundBottomRadius) { + rect.set(0, 0, getWidth(), getHeight()); + canvas.drawRoundRect(rect, roundTopRadius, roundTopRadius, placeholderPaint); + } else { + path.reset(); + rect.set(0, 0, getWidth(), getHeight()); + for (int i = 0; i < 4; i++) { + radii[i] = roundTopRadius; + radii[4 + i] = roundBottomRadius; + } + path.addRoundRect(rect, radii, Path.Direction.CW); + canvas.drawPath(path, placeholderPaint); + } + } + super.onDraw(canvas); + + if (radialProgress != null && radialProgress.getOverrideAlpha() > 0f) { + radialProgress.draw(canvas); + } + } + + @Override + public void invalidate() { + super.invalidate(); + if (invalidateWithParent) { + ProfileGalleryView.this.invalidate(); + } + } + } + + public void setPinchToZoomHelper(PinchToZoomHelper pinchToZoomHelper) { + this.pinchToZoomHelper = pinchToZoomHelper; + } + + public void setInvalidateWithParent(boolean invalidateWithParent) { + this.invalidateWithParent = invalidateWithParent; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PullForegroundDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PullForegroundDrawable.java index a79fa42935c..72b695a1a7e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PullForegroundDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PullForegroundDrawable.java @@ -468,7 +468,7 @@ private void textIn() { } public void startOutAnimation() { - if (animateOut) { + if (animateOut || listView == null) { return; } if (outAnimator != null) { 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 b3814a03371..23657cddabf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java @@ -773,7 +773,7 @@ protected View getPressedChildView() { } protected void onChildPressed(View child, float x, float y, boolean pressed) { - if (disableHighlightState) { + if (disableHighlightState || child == null) { return; } child.setPressed(pressed); 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 9c3585cb2a6..cc2a12055f7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java @@ -284,7 +284,7 @@ public void addStickerTab(TLRPC.Chat chat) { BackupImageView imageView = new BackupImageView(getContext()); imageView.setLayerNum(1); imageView.setRoundRadius(AndroidUtilities.dp(15)); - imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + imageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); imageView.setAspectFit(true); tab.addView(imageView, LayoutHelper.createFrame(30, 30, Gravity.CENTER)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java index 2baca1604f5..d2a65baad21 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java @@ -1601,7 +1601,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType View view; switch (viewType) { case 0: { - view = new ShareDialogCell(context, darkTheme); + view = new ShareDialogCell(context, darkTheme ? ShareDialogCell.TYPE_CALL : ShareDialogCell.TYPE_SHARE); view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(100))); break; } @@ -1901,8 +1901,8 @@ private void updateSearchResults(final ArrayList result, final int searc if (becomeEmpty) { topBeforeSwitch = getCurrentTop(); } - searchAdapterHelper.mergeResults(searchResult); searchResult = result; + searchAdapterHelper.mergeResults(searchResult); notifyDataSetChanged(); if (!isEmpty && !becomeEmpty && topBeforeSwitch > 0) { layoutManager.scrollToPositionWithOffset(0, -topBeforeSwitch); @@ -1995,7 +1995,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType View view; switch (viewType) { case 0: { - view = new ShareDialogCell(context, darkTheme); + view = new ShareDialogCell(context, darkTheme ? ShareDialogCell.TYPE_CALL : ShareDialogCell.TYPE_SHARE); view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(100))); break; } 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 bea492f20c4..d0b28c3d239 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -485,8 +485,28 @@ public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObj return null; } final RecyclerListView listView = mediaPages[0].listView; + int firstVisiblePosition = -1; + int lastVisiblePosition = -1; for (int a = 0, count = listView.getChildCount(); a < count; a++) { View view = listView.getChildAt(a); + int visibleHeight = mediaPages[0].listView.getMeasuredHeight(); + View parent = (View) getParent(); + if (parent != null) { + if (getY() + getMeasuredHeight() > parent.getMeasuredHeight()) { + visibleHeight -= getBottom() - parent.getMeasuredHeight(); + } + } + + if (view.getTop() >= visibleHeight) { + continue; + } + int adapterPosition = listView.getChildAdapterPosition(view); + if (adapterPosition < firstVisiblePosition || firstVisiblePosition == -1) { + firstVisiblePosition = adapterPosition; + } + if (adapterPosition > lastVisiblePosition || lastVisiblePosition == -1) { + lastVisiblePosition = adapterPosition; + } int[] coords = new int[2]; ImageReceiver imageReceiver = null; if (view instanceof SharedPhotoVideoCell) { @@ -564,6 +584,18 @@ public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObj return object; } } + if (mediaPages[0].selectedType == 0 && firstVisiblePosition >= 0 && lastVisiblePosition >= 0) { + int position = photoVideoAdapter.getPositionForIndex(index); + + if (position <= firstVisiblePosition) { + mediaPages[0].layoutManager.scrollToPositionWithOffset(position, 0); + profileActivity.scrollToSharedMedia(); + } else if (position >= lastVisiblePosition && lastVisiblePosition >= 0) { + mediaPages[0].layoutManager.scrollToPositionWithOffset(position, 0, true); + profileActivity.scrollToSharedMedia(); + } + } + return null; } }; @@ -3487,6 +3519,10 @@ public SharedPhotoVideoAdapter(Context context) { mContext = context; } + public int getPositionForIndex(int i) { + return i / columnsCount; + } + @Override public int getItemCount() { if (sharedMediaData[0].messages.size() == 0 && !sharedMediaData[0].loading) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java index 845862e0277..7c3ed9c4b70 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -44,8 +44,11 @@ import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; +import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.PaymentFormActivity; @SuppressWarnings("FieldCanBeLocal") public class UndoView extends FrameLayout { @@ -59,6 +62,8 @@ public class UndoView extends FrameLayout { private LinearLayout undoButton; private int undoViewHeight; + private BaseFragment parentFragment; + private Object currentInfoObject; private int currentAccount = UserConfig.selectedAccount; @@ -149,6 +154,8 @@ public class UndoView extends FrameLayout { public final static int ACTION_GIGAGROUP_CANCEL = 75; public final static int ACTION_GIGAGROUP_SUCCESS = 76; + public final static int ACTION_PAYMENT_SUCCESS = 77; + private CharSequence infoText; public class LinkMovementMethodMy extends LinkMovementMethod { @@ -175,11 +182,16 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event } public UndoView(Context context) { - this(context, false); + this(context, null, false); } - public UndoView(Context context, boolean top) { + public UndoView(Context context, BaseFragment parent) { + this(context, parent, false); + } + + public UndoView(Context context, BaseFragment parent, boolean top) { super(context); + parentFragment = parent; fromTop = top; infoTextView = new TextView(context); @@ -280,7 +292,7 @@ private boolean isTooltipAction() { currentAction == ACTION_CHAT_UNARCHIVED || currentAction == ACTION_VOIP_MUTED || currentAction == ACTION_VOIP_UNMUTED || currentAction == ACTION_VOIP_REMOVED || currentAction == ACTION_VOIP_LINK_COPIED || currentAction == ACTION_VOIP_INVITED || currentAction == ACTION_VOIP_MUTED_FOR_YOU || currentAction == ACTION_VOIP_UNMUTED_FOR_YOU || currentAction == ACTION_REPORT_SENT || currentAction == ACTION_VOIP_USER_CHANGED || currentAction == ACTION_VOIP_CAN_NOW_SPEAK || currentAction == ACTION_VOIP_RECORDING_STARTED || - currentAction == ACTION_VOIP_RECORDING_FINISHED || currentAction == ACTION_VOIP_SOUND_MUTED || currentAction == ACTION_VOIP_SOUND_UNMUTED; + currentAction == ACTION_VOIP_RECORDING_FINISHED || currentAction == ACTION_VOIP_SOUND_MUTED || currentAction == ACTION_VOIP_SOUND_UNMUTED || currentAction == ACTION_PAYMENT_SUCCESS; } private boolean hasSubInfo() { @@ -412,6 +424,9 @@ public void showWithAction(long did, int action, Object infoObject, Object infoO boolean infoOnly = false; boolean reversedPlay = false; int reversedPlayEndFrame = 0; + setOnClickListener(null); + setOnTouchListener((v, event) -> true); + infoTextView.setMovementMethod(new LinkMovementMethodMy()); if (isTooltipAction()) { CharSequence infoText; @@ -434,7 +449,7 @@ public void showWithAction(long did, int action, Object infoObject, Object infoO AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(12)); avatarDrawable.setInfo(user); - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); avatarImageView.setVisibility(VISIBLE); timeLeft = 3000; } else if (action == ACTION_VOIP_USER_CHANGED) { @@ -444,12 +459,12 @@ public void showWithAction(long did, int action, Object infoObject, Object infoO if (infoObject instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) infoObject; avatarDrawable.setInfo(user); - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); name = ContactsController.formatName(user.first_name, user.last_name); } else { TLRPC.Chat chat = (TLRPC.Chat) infoObject; avatarDrawable.setInfo(chat); - avatarImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); name = chat.title; } infoText = AndroidUtilities.replaceTags(LocaleController.formatString("VoipGroupUserChanged", R.string.VoipGroupUserChanged, name)); @@ -462,6 +477,27 @@ public void showWithAction(long did, int action, Object infoObject, Object infoO subInfoText = null; icon = R.raw.voip_invite; timeLeft = 3000; + } else if (action == ACTION_PAYMENT_SUCCESS) { + infoText = (CharSequence) infoObject; + subInfoText = null; + icon = R.raw.payment_success; + timeLeft = 5000; + if (parentFragment != null && infoObject2 instanceof TLRPC.Message) { + TLRPC.Message message = (TLRPC.Message) infoObject2; + setOnTouchListener(null); + infoTextView.setMovementMethod(null); + setOnClickListener(v -> { + hide(true, 1); + TLRPC.TL_payments_getPaymentReceipt req = new TLRPC.TL_payments_getPaymentReceipt(); + req.msg_id = message.id; + req.peer = parentFragment.getMessagesController().getInputPeer(message.peer_id); + parentFragment.getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_payments_paymentReceipt) { + parentFragment.presentFragment(new PaymentFormActivity((TLRPC.TL_payments_paymentReceipt) response)); + } + }), ConnectionsManager.RequestFlagFailOnServerErrors); + }); + } } else if (action == ACTION_VOIP_MUTED) { String name; if (infoObject instanceof TLRPC.User) { @@ -670,7 +706,7 @@ public void showWithAction(long did, int action, Object infoObject, Object infoO } } subInfoText = null; - icon = R.raw.contact_check; + icon = action == ACTION_ADDED_TO_FOLDER ? R.raw.folder_in : R.raw.folder_out; } else if (action == ACTION_CACHE_WAS_CLEARED) { infoText = this.infoText; subInfoText = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoForwardDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoForwardDrawable.java index 4b9539dd858..4dbc7859324 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoForwardDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoForwardDrawable.java @@ -21,13 +21,25 @@ public class VideoForwardDrawable extends Drawable { private final static int[] playPath = new int[] {10, 7, 26, 16, 10, 25}; private float animationProgress; + private float enterAnimationProgress; private boolean animating; + private boolean isOneShootAnimation; + private boolean showing; private long lastAnimationTime; private VideoForwardDrawableDelegate delegate; - long time; - String timeStr; + private long time; + private String timeStr; + + public void setTime(long dt) { + time = dt; + if (time >= 1000) { + timeStr = LocaleController.formatPluralString("Seconds", (int) (time / 1000)); + } else { + timeStr = null; + } + } public interface VideoForwardDrawableDelegate { void onAnimationEnd(); @@ -61,8 +73,17 @@ public void startAnimation() { invalidateSelf(); } + public void setOneShootAnimation(boolean isOneShootAnimation) { + if (this.isOneShootAnimation != isOneShootAnimation) { + this.isOneShootAnimation = isOneShootAnimation; + timeStr = null; + time = 0; + animationProgress = 0f; + } + } + public void setLeftSide(boolean value) { - if (leftSide == value && animationProgress >= 1.0f) { + if (leftSide == value && animationProgress >= 1.0f && isOneShootAnimation) { return; } if (leftSide != value) { @@ -111,12 +132,17 @@ public void draw(Canvas canvas) { canvas.save(); canvas.clipRect(rect.left, rect.top, rect.right, rect.bottom); - if (animationProgress <= 0.7f) { - paint.setAlpha((int) (80 * Math.min(1.0f, animationProgress / 0.3f))); - textPaint.setAlpha((int) (255 * Math.min(1.0f, animationProgress / 0.3f))); + if (!isOneShootAnimation) { + paint.setAlpha((int) (80 * enterAnimationProgress)); + textPaint.setAlpha((int) (255 * enterAnimationProgress)); } else { - paint.setAlpha((int) (80 * (1.0f - (animationProgress - 0.7f) / 0.3f))); - textPaint.setAlpha((int) (255 * (1.0f - (animationProgress - 0.7f) / 0.3f))); + if (animationProgress <= 0.7f) { + paint.setAlpha((int) (80 * Math.min(1.0f, animationProgress / 0.3f))); + textPaint.setAlpha((int) (255 * Math.min(1.0f, animationProgress / 0.3f))); + } else { + paint.setAlpha((int) (80 * (1.0f - (animationProgress - 0.7f) / 0.3f))); + textPaint.setAlpha((int) (255 * (1.0f - (animationProgress - 0.7f) / 0.3f))); + } } canvas.drawCircle(x + Math.max(rect.width(), rect.height()) / 4 * (leftSide ? -1 : 1), y + AndroidUtilities.dp(16), Math.max(rect.width(), rect.height()) / 2, paint); canvas.restore(); @@ -131,31 +157,46 @@ public void draw(Canvas canvas) { } canvas.translate(x, y); if (animationProgress <= 0.6f) { + int a; if (animationProgress < 0.4f) { - paint.setAlpha(Math.min(255, (int) (255 * animationProgress / 0.2f))); + a = Math.min(255, (int) (255 * animationProgress / 0.2f)); } else { - paint.setAlpha((int) (255 * (1.0f - (animationProgress - 0.4f) / 0.2f))); + a = (int) (255 * (1.0f - (animationProgress - 0.4f) / 0.2f)); + } + if (!isOneShootAnimation) { + a = (int) (a * enterAnimationProgress); } + paint.setAlpha(a); canvas.drawPath(path1, paint); } canvas.translate(AndroidUtilities.dp(18), 0); if (animationProgress >= 0.2f && animationProgress <= 0.8f) { float progress = animationProgress - 0.2f; + int a; if (progress < 0.4f) { - paint.setAlpha(Math.min(255, (int) (255 * progress / 0.2f))); + a = Math.min(255, (int) (255 * progress / 0.2f)); } else { - paint.setAlpha((int) (255 * (1.0f - (progress - 0.4f) / 0.2f))); + a = (int) (255 * (1.0f - (progress - 0.4f) / 0.2f)); } + if (!isOneShootAnimation) { + a = (int) (a * enterAnimationProgress); + } + paint.setAlpha(a); canvas.drawPath(path1, paint); } canvas.translate(AndroidUtilities.dp(18), 0); if (animationProgress >= 0.4f && animationProgress <= 1.0f) { float progress = animationProgress - 0.4f; + int a; if (progress < 0.4f) { - paint.setAlpha(Math.min(255, (int) (255 * progress / 0.2f))); + a = Math.min(255, (int) (255 * progress / 0.2f)); } else { - paint.setAlpha((int) (255 * (1.0f - (progress - 0.4f) / 0.2f))); + a = (int) (255 * (1.0f - (progress - 0.4f) / 0.2f)); + } + if (!isOneShootAnimation) { + a = (int) (a * enterAnimationProgress); } + paint.setAlpha(a); canvas.drawPath(path1, paint); } canvas.restore(); @@ -169,24 +210,57 @@ public void draw(Canvas canvas) { lastAnimationTime = newTime; if (animationProgress < 1.0f) { animationProgress += dt / 800.0f; - if (animationProgress >= 1.0f) { - animationProgress = 0.0f; - animating = false; - time = 0; - timeStr = null; - if (delegate != null) { - delegate.onAnimationEnd(); + if (!isOneShootAnimation) { + if (animationProgress >= 1.0f) { + if (showing) { + animationProgress = 0f; + } else { + animationProgress = 1f; + } } - } - if (delegate != null) { - delegate.invalidate(); } else { - invalidateSelf(); + if (animationProgress >= 1.0f) { + animationProgress = 0.0f; + animating = false; + time = 0; + timeStr = null; + if (delegate != null) { + delegate.onAnimationEnd(); + } + } + } + invalidate(); + } + if (!isOneShootAnimation) { + if (showing && enterAnimationProgress != 1f) { + enterAnimationProgress += 16 / 150f; + invalidate(); + } else if (!showing && enterAnimationProgress != 0) { + enterAnimationProgress -= 16 / 150f; + invalidate(); + } + if (enterAnimationProgress < 0) { + enterAnimationProgress = 0f; + } else if (enterAnimationProgress > 1f) { + enterAnimationProgress = 1f; } } } } + public void setShowing(boolean showing) { + this.showing = showing; + invalidate(); + } + + private void invalidate() { + if (delegate != null) { + delegate.invalidate(); + } else { + invalidateSelf(); + } + } + @Override public int getIntrinsicWidth() { return AndroidUtilities.dp(32); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayerSeekBar.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayerSeekBar.java index 67fd64bb631..6f893a0213d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayerSeekBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayerSeekBar.java @@ -11,6 +11,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.RectF; import android.os.SystemClock; import android.view.MotionEvent; @@ -18,6 +19,8 @@ import androidx.core.graphics.ColorUtils; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; public class VideoPlayerSeekBar { @@ -45,6 +48,9 @@ default void onSeekBarContinuousDrag(float progress) { private int backgroundSelectedColor; private RectF rect = new RectF(); private boolean selected; + private float animateFromBufferedProgress; + private boolean animateResetBuffering; + private float bufferedAnimationValue = 1f; private float bufferedProgress; private float currentRadius; private long lastUpdateTime; @@ -133,11 +139,20 @@ public void setColors(int background, int cache, int progress, int circle, int s } public void setProgress(float progress, boolean animated) { + int newThumb = (int) Math.ceil((width - thumbWidth) * progress); + if (animated) { - animateThumbProgress = 0; - fromThumbX = thumbX; + if (Math.abs(newThumb - thumbX) > AndroidUtilities.dp(10)) { + float progressInterpolated = CubicBezierInterpolator.DEFAULT.getInterpolation(animateThumbProgress); + fromThumbX = (int) (thumbX * progressInterpolated + fromThumbX * (1f - progressInterpolated)); + animateThumbProgress = 0; + } else if (animateThumbProgress == 1f) { + animateThumbProgress = 0; + fromThumbX = thumbX; + } } - thumbX = (int) Math.ceil((width - thumbWidth) * progress); + thumbX = newThumb; + if (thumbX < 0) { thumbX = 0; } else if (thumbX > width - thumbWidth) { @@ -150,7 +165,12 @@ public void setProgress(float progress) { } public void setBufferedProgress(float value) { - bufferedProgress = value; + if (value != bufferedProgress) { + animateFromBufferedProgress = bufferedProgress; + animateResetBuffering = value < bufferedProgress; + bufferedProgress = value; + bufferedAnimationValue = 0; + } } public float getProgress() { @@ -206,7 +226,7 @@ public void draw(Canvas canvas, View view) { float currentThumbX = thumbX; if (animateThumbProgress != 1f) { - animateThumbProgress += 16 / 150f; + animateThumbProgress += 16 / 220f; if (animateThumbProgress >= 1f) { animateThumbProgress = 1f; } else { @@ -220,11 +240,34 @@ public void draw(Canvas canvas, View view) { setPaintColor(selected ? backgroundSelectedColor : backgroundColor, 1f - transitionProgress); canvas.drawRoundRect(rect, radius, radius, paint); + if (bufferedAnimationValue != 1f) { + bufferedAnimationValue += 16 / 100f; + if (bufferedAnimationValue > 1) { + bufferedAnimationValue = 1f; + } else { + parentView.invalidate(); + } + } + // buffered - if (bufferedProgress > 0) { - rect.right = horizontalPadding + AndroidUtilities.lerp(thumbWidth / 2f + bufferedProgress * (width - thumbWidth), parentView.getWidth() - horizontalPadding * 2f, transitionProgress); - setPaintColor(selected ? backgroundSelectedColor : cacheColor, 1f - transitionProgress); - canvas.drawRoundRect(rect, radius, radius, paint); + if (animateResetBuffering) { + if (animateFromBufferedProgress > 0) { + rect.right = horizontalPadding + AndroidUtilities.lerp(thumbWidth / 2f + animateFromBufferedProgress * (width - thumbWidth), parentView.getWidth() - horizontalPadding * 2f, transitionProgress); + setPaintColor(selected ? backgroundSelectedColor : cacheColor, (1f - transitionProgress) * (1f - bufferedAnimationValue)); + canvas.drawRoundRect(rect, radius, radius, paint); + } + if (bufferedProgress > 0) { + rect.right = horizontalPadding + AndroidUtilities.lerp(thumbWidth / 2f + bufferedProgress * (width - thumbWidth), parentView.getWidth() - horizontalPadding * 2f, transitionProgress); + setPaintColor(selected ? backgroundSelectedColor : cacheColor, 1f - transitionProgress); + canvas.drawRoundRect(rect, radius, radius, paint); + } + } else { + float currentBufferedProgress = animateFromBufferedProgress * (1f - bufferedAnimationValue) + bufferedProgress * bufferedAnimationValue; + if (currentBufferedProgress > 0) { + rect.right = horizontalPadding + AndroidUtilities.lerp(thumbWidth / 2f + currentBufferedProgress * (width - thumbWidth), parentView.getWidth() - horizontalPadding * 2f, transitionProgress); + setPaintColor(selected ? backgroundSelectedColor : cacheColor, 1f - transitionProgress); + canvas.drawRoundRect(rect, radius, radius, paint); + } } // progress diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java index 9396b7ba5f0..bdab37c21b4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java @@ -217,7 +217,7 @@ private static void initiateCall(TLRPC.User user, TLRPC.Chat chat, String hash, if (!TextUtils.isEmpty(hash)) { voIPService.setGroupCallHash(hash); } - GroupCallActivity.create((LaunchActivity) activity, AccountInstance.getInstance(UserConfig.selectedAccount)); + GroupCallActivity.create((LaunchActivity) activity, AccountInstance.getInstance(UserConfig.selectedAccount), null, null, false, null); } } } else if (VoIPService.callIShouldHavePutIntoIntent == null) { @@ -256,8 +256,10 @@ protected void onJoin() { } } if (checkJoiner && chat != null) { - JoinCallAlert.open(activity, -chat.id, accountInstance, fragment, createCall ? JoinCallAlert.TYPE_CREATE : JoinCallAlert.TYPE_JOIN, (selectedPeer, hasFew) -> { - if (!hasFew && hash != null) { + JoinCallAlert.open(activity, -chat.id, accountInstance, fragment, createCall ? JoinCallAlert.TYPE_CREATE : JoinCallAlert.TYPE_JOIN, null, (selectedPeer, hasFew, schedule) -> { + if (createCall && schedule) { + GroupCallActivity.create((LaunchActivity) activity, accountInstance, chat, selectedPeer, hasFew, hash); + } else if (!hasFew && hash != null) { JoinCallByUrlAlert alert = new JoinCallByUrlAlert(activity, chat) { @Override protected void onJoin() { @@ -302,6 +304,13 @@ protected void onJoin() { } } } + if (chat != null && !createCall) { + ChatObject.Call call = accountInstance.getMessagesController().getGroupCall(chat.id, false); + if (call != null && call.isScheduled()) { + GroupCallActivity.create((LaunchActivity) activity, accountInstance, chat, peer, hasFewPeers, hash); + return; + } + } lastCallTime = SystemClock.elapsedRealtime(); Intent intent = new Intent(activity, VoIPService.class); @@ -715,7 +724,7 @@ public static void showGroupCallAlert(BaseFragment fragment, TLRPC.Chat currentC return; } JoinCallAlert.checkFewUsers(fragment.getParentActivity(), -currentChat.id, accountInstance, param -> { - if (param) { + /*if (param) { if (fragment.getParentActivity() == null) { return; } @@ -740,9 +749,9 @@ public static void showGroupCallAlert(BaseFragment fragment, TLRPC.Chat currentC }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); fragment.showDialog(builder.create()); - } else { + } else {*/ startCall(currentChat, peer, null, true, fragment.getParentActivity(), fragment, accountInstance); - } + //} }); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java index 9c68940ecad..6d3a9b6ddda 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java @@ -5,7 +5,6 @@ import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; -import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -27,6 +26,7 @@ import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; @@ -35,6 +35,7 @@ public class VoIPToggleButton extends FrameLayout { Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private boolean drawBackground = true; + private boolean animateBackground; Drawable[] icon = new Drawable[2]; TextView[] textView = new TextView[2]; @@ -116,7 +117,7 @@ public void setDrawBackground(boolean value) { @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { - if (replaceProgress != 0) { + if (animateBackground && replaceProgress != 0) { circlePaint.setColor(ColorUtils.blendARGB(backgroundColor, animateToBackgroundColor, replaceProgress)); } else { circlePaint.setColor(backgroundColor); @@ -231,6 +232,16 @@ public void setData(int iconRes, int iconColor, int backgroundColor, String text setData(iconRes, iconColor, backgroundColor, 1.0f, true, text, cross, animated); } + public void setEnabled(boolean enabled, boolean animated) { + super.setEnabled(enabled); + if (animated) { + animate().alpha(enabled ? 1.0f : 0.5f).setDuration(180).start(); + } else { + clearAnimation(); + setAlpha(enabled ? 1.0f : 0.5f); + } + } + public void setData(int iconRes, int iconColor, int backgroundColor, float selectorAlpha, boolean recreateRipple, String text, boolean cross, boolean animated) { if (getVisibility() != View.VISIBLE) { animated = false; @@ -254,6 +265,7 @@ public void setData(int iconRes, int iconColor, int backgroundColor, float selec if (replaceAnimator != null) { replaceAnimator.cancel(); } + animateBackground = currentBackgroundColor != backgroundColor; iconChangeColor = currentIconRes == iconRes; if (iconChangeColor) { @@ -372,8 +384,11 @@ public void setCheckable(boolean checkable) { this.checkable = checkable; } - public void setChecked(boolean checked, boolean animated) { - this.checked = checked; + public void setChecked(boolean value, boolean animated) { + if (checked == value) { + return; + } + checked = value; if (checkable) { if (animated) { if (checkAnimator != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java index 45dcaab083a..cfcbc8b1487 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java @@ -277,7 +277,7 @@ private void updateAvatarLayout() { } } onlineTextView.setText(LocaleController.formatUserStatus(currentAccount, user)); - avatarImage.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable = new AvatarDrawable(user), user); + avatarImage.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable = new AvatarDrawable(user), user); } public void didReceivedNotification(int id, int account, Object... args) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 895d8db23e1..a270276feca 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -73,6 +73,8 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager.widget.ViewPager; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; @@ -249,6 +251,7 @@ public boolean isDefaultDialogType() { private int messagesCount; private int hasPoll; + private boolean hasInvoice; private PacmanAnimation pacmanAnimation; @@ -524,6 +527,19 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == viewPages[0] || (viewPages.length > 1 && child == viewPages[1]) || child == fragmentContextView || child == fragmentLocationContextView || child == searchViewPager) { canvas.save(); canvas.clipRect(0, -getY() + actionBar.getY() + getActionBarFullHeight(), getMeasuredWidth(), getMeasuredHeight()); + if (slideFragmentProgress != 1f) { + float s = 1f - 0.05f * (1f - slideFragmentProgress); + canvas.translate((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress), 0); + canvas.scale(s, s, isDrawerTransition ? getMeasuredWidth() : 0, -getY() + actionBar.getY() + getActionBarFullHeight()); + } + + result = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + } else if (child == actionBar && slideFragmentProgress != 1f) { + canvas.save(); + float s = 1f - 0.05f * (1f - slideFragmentProgress); + canvas.translate((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress), 0); + canvas.scale(s, s, isDrawerTransition ? getMeasuredWidth() : 0, (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight() / 2f); result = super.drawChild(canvas, child, drawingTime); canvas.restore(); } else { @@ -633,6 +649,11 @@ protected void dispatchDraw(Canvas canvas) { if (fragmentContextView != null && fragmentContextView.isCallStyle()) { canvas.save(); canvas.translate(fragmentContextView.getX(), fragmentContextView.getY()); + if (slideFragmentProgress != 1f) { + float s = 1f - 0.05f * (1f - slideFragmentProgress); + canvas.translate((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress), 0); + canvas.scale(s, 1f, isDrawerTransition ? getMeasuredWidth() : 0, fragmentContextView.getY()); + } fragmentContextView.setDrawOverlay(true); fragmentContextView.draw(canvas); fragmentContextView.setDrawOverlay(false); @@ -729,6 +750,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } else { child.setTranslationY(0); } + int transitionPadding = (isSlideBackTransition || isDrawerTransition) ? (int) (h * 0.05f) : 0; + h += transitionPadding; + child.setPadding(child.getPaddingLeft(), child.getPaddingTop(), child.getPaddingRight(), transitionPadding); child.measure(contentWidthSpec, View.MeasureSpec.makeMeasureSpec(Math.max(AndroidUtilities.dp(10), h), View.MeasureSpec.EXACTLY)); child.setPivotX(child.getMeasuredWidth() / 2); } else if (child == searchViewPager) { @@ -867,7 +891,7 @@ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { @Override public boolean onTouchEvent(MotionEvent ev) { - if (filterTabsView != null && !filterTabsView.isEditing() && !searching && + if (parentLayout != null && filterTabsView != null && !filterTabsView.isEditing() && !searching && !parentLayout.checkTransitionAnimation() && !parentLayout.isInPreviewMode() && !parentLayout.isPreviewOpenAnimationInProgress() && !parentLayout.getDrawerLayoutContainer().isDrawerOpened() && (ev == null || startedTracking || ev.getY() > actionBar.getMeasuredHeight() + actionBar.getTranslationY()) && SharedConfig.getChatSwipeAction(currentAccount) == SwipeGestureSettingsView.SWIPE_GESTURE_FOLDERS) { if (ev != null) { @@ -1087,7 +1111,7 @@ public class DialogsRecyclerView extends RecyclerListView { private boolean firstLayout = true; private boolean ignoreLayout; - private ViewPage parentPage; + private final ViewPage parentPage; private int appliedPaddingTop; private int lastTop; private int lastListPadding; @@ -1202,7 +1226,9 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - parentPage.recyclerItemsEnterAnimator.onDetached(); + if (parentPage != null && parentPage.recyclerItemsEnterAnimator != null) { + parentPage.recyclerItemsEnterAnimator.onDetached(); + } } @Override @@ -1750,6 +1776,7 @@ public boolean onFragmentCreate() { resetDelegate = arguments.getBoolean("resetDelegate", true); messagesCount = arguments.getInt("messagesCount", 0); hasPoll = arguments.getInt("hasPoll", 0); + hasInvoice = arguments.getBoolean("hasInvoice", false); } if (initialDialogsType == 0) { @@ -1808,6 +1835,7 @@ public static void loadDialogs(AccountInstance accountInstance) { messagesController.loadUserInfo(accountInstance.getUserConfig().getCurrentUser(), false, 0); accountInstance.getContactsController().checkInviteText(); accountInstance.getMediaDataController().loadRecents(MediaDataController.TYPE_FAVE, false, true, false); + accountInstance.getMediaDataController().loadRecents(MediaDataController.TYPE_GREETINGS, false, true, false); accountInstance.getMediaDataController().checkFeaturedStickers(); for (String emoji : messagesController.diceEmojies) { accountInstance.getMediaDataController().loadStickersByEmojiOrName(emoji, true, true); @@ -2423,7 +2451,7 @@ public void onDeletePressed(int id) { TLRPC.User user = getUserConfig().getCurrentUser(); avatarDrawable.setInfo(user); imageView.getImageReceiver().setCurrentAccount(currentAccount); - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { TLRPC.User u = AccountInstance.getInstance(a).getUserConfig().getCurrentUser(); @@ -4661,7 +4689,7 @@ private void onItemClick(View view, int position, RecyclerListView.Adapter adapt if (getMessagesController().checkCanOpenChat(args, DialogsActivity.this)) { ChatActivity chatActivity = new ChatActivity(args); if (adapter instanceof DialogsAdapter && lower_part > 0 && (getMessagesController().dialogs_dict.get(dialogId) == null)) { - TLRPC.Document sticker = getMessagesController().getPreloadedSticker(); + TLRPC.Document sticker = getMediaDataController().getGreetingsSticker(); if (sticker != null) { chatActivity.setPreloadedSticker(sticker, true); } @@ -5504,6 +5532,10 @@ private void pinDialog(long selectedDialog, boolean pin, MessagesController.Dial private void scrollToTop() { int scrollDistance = viewPages[0].layoutManager.findFirstVisibleItemPosition() * AndroidUtilities.dp(SharedConfig.useThreeLinesLayout ? 78 : 72); int position = viewPages[0].dialogsType == 0 && hasHiddenArchive() ? 1 : 0; + RecyclerView.ItemAnimator animator = viewPages[0].listView.getItemAnimator(); +// if (animator != null) { +// animator.endAnimations(); +// } if (scrollDistance >= viewPages[0].listView.getMeasuredHeight() * 1.2f) { viewPages[0].scrollHelper.setScrollDirection(RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP); viewPages[0].scrollHelper.scrollToPosition(position, 0, false, true); @@ -6560,10 +6592,14 @@ private void didSelectResult(final long dialog_id, boolean useAlert, final boole showDialog(builder.create()); return; } - } else if (lowerId == 0 && hasPoll != 0) { + } else if (lowerId == 0 && (hasPoll != 0 || hasInvoice)) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("SendMessageTitle", R.string.SendMessageTitle)); - builder.setMessage(LocaleController.getString("PollCantForwardSecretChat", R.string.PollCantForwardSecretChat)); + if (hasPoll != 0) { + builder.setMessage(LocaleController.getString("PollCantForwardSecretChat", R.string.PollCantForwardSecretChat)); + } else { + builder.setMessage(LocaleController.getString("InvoiceCantForwardSecretChat", R.string.InvoiceCantForwardSecretChat)); + } builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), null); showDialog(builder.create()); return; @@ -7199,4 +7235,138 @@ public ArrayList getThemeDescriptions() { return arrayList; } + + float slideFragmentProgress = 1f; + boolean isSlideBackTransition; + boolean isDrawerTransition; + ValueAnimator slideBackTransitionAnimator; + + @Override + protected Animator getCustomSlideTransition(boolean topFragment, boolean backAnimation, float distanceToMove) { + if (backAnimation) { + slideBackTransitionAnimator = ValueAnimator.ofFloat(slideFragmentProgress, 1f); + return slideBackTransitionAnimator; + } + int duration = (int) (Math.max((int) (200.0f / getLayoutContainer().getMeasuredWidth() * distanceToMove), 80) * 1.2f); + slideBackTransitionAnimator = ValueAnimator.ofFloat(slideFragmentProgress, 1f); + slideBackTransitionAnimator.addUpdateListener(valueAnimator -> setSlideTransitionProgress((float) valueAnimator.getAnimatedValue())); + slideBackTransitionAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); + slideBackTransitionAnimator.setDuration(duration); + slideBackTransitionAnimator.start(); + return slideBackTransitionAnimator; + } + + @Override + protected void prepareFragmentToSlide(boolean topFragment, boolean beginSlide) { + if (!topFragment && beginSlide) { + isSlideBackTransition = true; + setFragmentIsSliding(true); + } else { + slideBackTransitionAnimator = null; + isSlideBackTransition = false; + setFragmentIsSliding(false); + setSlideTransitionProgress(1f); + } + } + + private void setFragmentIsSliding(boolean sliding) { + if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW) { + return; + } + if (sliding) { + if (viewPages != null && viewPages[0] != null) { + viewPages[0].setLayerType(View.LAYER_TYPE_HARDWARE, null); + viewPages[0].setClipChildren(false); + viewPages[0].setClipToPadding(false); + viewPages[0].listView.setClipChildren(false); + } + + if (actionBar != null) { + actionBar.setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + if (filterTabsView != null) { + filterTabsView.getListView().setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + if (fragmentView != null) { + ((ViewGroup) fragmentView).setClipChildren(false); + fragmentView.requestLayout(); + } + } else { + + for (int i = 0; i < viewPages.length; i++) { + ViewPage page = viewPages[i]; + if (page != null) { + page.setLayerType(View.LAYER_TYPE_NONE, null); + page.setClipChildren(true); + page.setClipToPadding(true); + page.listView.setClipChildren(true); + } + } + + if (actionBar != null) { + actionBar.setLayerType(View.LAYER_TYPE_NONE, null); + } + + if (filterTabsView != null) { + filterTabsView.getListView().setLayerType(View.LAYER_TYPE_NONE, null); + } + if (fragmentView != null) { + ((ViewGroup) fragmentView).setClipChildren(true); + fragmentView.requestLayout(); + } + } + } + + @Override + protected void onSlideProgress(boolean isOpen, float progress) { + if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW) { + return; + } + if (isSlideBackTransition && slideBackTransitionAnimator == null) { + setSlideTransitionProgress(progress); + } + } + + private void setSlideTransitionProgress(float progress) { + if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW) { + return; + } + slideFragmentProgress = progress; + if (fragmentView != null) { + fragmentView.invalidate(); + } + + if (filterTabsView != null) { + float s = 1f - 0.05f * (1f - slideFragmentProgress); + filterTabsView.getListView().setScaleX(s); + filterTabsView.getListView().setScaleY(s); + filterTabsView.getListView().setTranslationX((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress)); + filterTabsView.getListView().setPivotX(isDrawerTransition ? filterTabsView.getMeasuredWidth() : 0); + filterTabsView.getListView().setPivotY(0); + filterTabsView.invalidate(); + } + } + + @Override + public void setProgressToDrawerOpened(float progress) { + if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW) { + return; + } + boolean drawerTransition = progress > 0; + if (searchIsShowed) { + drawerTransition = false; + progress = 0; + } + if (drawerTransition != isDrawerTransition) { + isDrawerTransition = drawerTransition; + if (isDrawerTransition) { + setFragmentIsSliding(true); + } else { + setFragmentIsSliding(false); + } + fragmentView.requestLayout(); + } + setSlideTransitionProgress(1f - progress); + } } + diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java index b3fea49573b..2bc2c8943c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java @@ -8,6 +8,8 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -67,7 +69,9 @@ import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; +import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; @@ -78,6 +82,7 @@ import org.telegram.messenger.Utilities; import org.telegram.messenger.voip.VoIPBaseService; import org.telegram.messenger.voip.VoIPService; +import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -108,8 +113,10 @@ import org.telegram.ui.Components.GroupCallPip; import org.telegram.ui.Components.GroupVoipInviteAlert; import org.telegram.ui.Components.HintView; +import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.JoinCallAlert; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.NumberPicker; import org.telegram.ui.Components.ProfileGalleryView; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; @@ -120,7 +127,9 @@ import org.telegram.ui.Components.WaveDrawable; import org.telegram.ui.Components.voip.VoIPToggleButton; +import java.io.File; import java.util.ArrayList; +import java.util.Calendar; import java.util.Locale; public class GroupCallActivity extends BottomSheet implements NotificationCenter.NotificationCenterDelegate, VoIPBaseService.StateListener { @@ -140,6 +149,9 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter private static final int MUTE_BUTTON_STATE_MUTED_BY_ADMIN = 2; private static final int MUTE_BUTTON_STATE_CONNECTING = 3; private static final int MUTE_BUTTON_STATE_RAISED_HAND = 4; + private static final int MUTE_BUTTON_STATE_START_NOW = 5; + private static final int MUTE_BUTTON_STATE_SET_REMINDER = 6; + private static final int MUTE_BUTTON_STATE_CANCEL_REMINDER = 7; public static GroupCallActivity groupCallInstance; public static boolean groupCallUiVisible; @@ -151,6 +163,12 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter private ActionBar actionBar; private ListAdapter listAdapter; private RecyclerListView listView; + private LinearLayout scheduleTimerContainer; + private TextView scheduleInfoTextView; + private TextView scheduleButtonTextView; + private SimpleTextView scheduleStartInTextView; + private SimpleTextView scheduleTimeTextView; + private SimpleTextView scheduleStartAtTextView; private DefaultItemAnimator itemAnimator; private FillLastLinearLayoutManager layoutManager; private VoIPToggleButton soundButton; @@ -171,11 +189,15 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter private View accountGap; private boolean changingPermissions; private HintView recordHintView; + private HintView reminderHintView; private ShareAlert shareAlert; private boolean delayedGroupCallUpdated; + private long creatingServiceTime; + private boolean callInitied; + private RectF rect = new RectF(); private boolean enterEventSent; @@ -209,10 +231,18 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter private final Matrix radialMatrix; private final Paint radialPaint; + private float switchToButtonProgress; + private float switchToButtonInt2; + private float scheduleButtonsScale; + private ValueAnimator scheduleAnimator; + private ValueAnimator muteButtonAnimator; + private TLRPC.InputPeer schedulePeer; public TLRPC.Chat currentChat; public ChatObject.Call call; + private boolean scheduleHasFewPeers; + private String scheduledHash; private RecordCallDrawable recordCallDrawable; private AudioPlayerAlert.ClippingTextViewSwitcher titleTextView; @@ -233,10 +263,12 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter private int muteButtonState = MUTE_BUTTON_STATE_UNMUTE; + private boolean startingGroupCall; + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG); private Paint paintTmp = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG); private Paint leaveBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private WeavingState[] states = new WeavingState[5]; + private WeavingState[] states = new WeavingState[8]; private float switchProgress = 1.0f; private WeavingState prevState; private WeavingState currentState; @@ -256,12 +288,49 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter private final int[] colorsTmp = new int[3]; View blurredView; + PinchToZoomHelper pinchToZoomHelper; private float progressToAvatarPreview; private View scrimPopupLayout; private boolean avatarsPreviewShowed; + ImageUpdater currentAvatarUpdater; + AvatarUpdaterDelegate avatarUpdaterDelegate; + + private int scheduleStartAt; + private boolean contentFullyOverlayed; + + private Runnable updateSchedeulRunnable = new Runnable() { + @Override + public void run() { + if (scheduleTimeTextView == null || isDismissed()) { + return; + } + int time; + if (call != null) { + time = call.call.schedule_date; + } else { + time = scheduleStartAt; + } + if (time == 0) { + return; + } + int diff = time - accountInstance.getConnectionsManager().getCurrentTime(); + if (diff >= 24 * 60 * 60) { + scheduleTimeTextView.setText(LocaleController.formatPluralString("Days", Math.round(diff / (24 * 60 * 60.0f)))); + } else { + scheduleTimeTextView.setText(AndroidUtilities.formatFullDuration(Math.abs(diff))); + if (diff < 0 && scheduleStartInTextView.getTag() == null) { + scheduleStartInTextView.setTag(1); + scheduleStartInTextView.setText(LocaleController.getString("VoipChatLateBy", R.string.VoipChatLateBy)); + } + } + scheduleStartAtTextView.setText(LocaleController.formatStartsTime(time, 3)); + AndroidUtilities.runOnUIThread(updateSchedeulRunnable, 1000); + } + }; + private Runnable unmuteRunnable = () -> { if (VoIPService.getSharedInstance() == null) { return; @@ -270,7 +339,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter }; private Runnable pressRunnable = () -> { - if (!scheduled || VoIPService.getSharedInstance() == null) { + if (call == null || !scheduled || VoIPService.getSharedInstance() == null) { return; } muteButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); @@ -293,6 +362,7 @@ public Float get(GroupCallActivity object) { }; private final FrameLayout avatarPreviewContainer; private final AvatarPreviewPagerIndicator avatarPagerIndicator; + private ViewGroup currentOptionsLayout; private static class SmallRecordCallDrawable extends Drawable { @@ -638,9 +708,9 @@ private void onSeekBarDrag(double progress, boolean finalMove) { int id = MessageObject.getPeerId(currentParticipant.peer); TLObject object; if (id > 0) { - object = MessagesController.getInstance(currentAccount).getUser(id); + object = accountInstance.getMessagesController().getUser(id); } else { - object = MessagesController.getInstance(currentAccount).getChat(-id); + object = accountInstance.getMessagesController().getChat(-id); } if (currentParticipant.volume == 0) { if (scrimPopupWindow != null) { @@ -787,7 +857,7 @@ public void update(int top, int left, int size, long dt) { float y = top + size * (startY + (targetY - startY) * interpolation) - 200; float s; - if (currentState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || currentState == MUTE_BUTTON_STATE_RAISED_HAND) { + if (isGradientState(currentState)) { s = 1f; } else { s = currentState == MUTE_BUTTON_STATE_MUTE ? 4 : 2.5f; @@ -801,7 +871,7 @@ public void update(int top, int left, int size, long dt) { } private void setTarget() { - if (currentState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || currentState == MUTE_BUTTON_STATE_RAISED_HAND) { + if (isGradientState(currentState)) { targetX = 0.85f + 0.20f * Utilities.random.nextInt(100) / 100f; targetY = 1f; } else if (currentState == MUTE_BUTTON_STATE_MUTE) { @@ -814,6 +884,10 @@ private void setTarget() { } } + private static boolean isGradientState(int state) { + return state == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || state == MUTE_BUTTON_STATE_RAISED_HAND || state == MUTE_BUTTON_STATE_START_NOW || state == MUTE_BUTTON_STATE_SET_REMINDER || state == MUTE_BUTTON_STATE_CANCEL_REMINDER; + } + @SuppressWarnings("FieldCanBeLocal") private static class LabeledButton extends FrameLayout { @@ -901,11 +975,18 @@ public void dismiss() { accountInstance.getNotificationCenter().removeObserver(this, NotificationCenter.chatInfoDidLoad); accountInstance.getNotificationCenter().removeObserver(this, NotificationCenter.didLoadChatAdmins); accountInstance.getNotificationCenter().removeObserver(this, NotificationCenter.applyGroupCallVisibleParticipants); + accountInstance.getNotificationCenter().removeObserver(this, NotificationCenter.userInfoDidLoad); + accountInstance.getNotificationCenter().removeObserver(this, NotificationCenter.mainUserInfoChanged); + accountInstance.getNotificationCenter().removeObserver(this, NotificationCenter.updateInterfaces); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.webRtcMicAmplitudeEvent); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didEndCall); super.dismiss(); } + private boolean isStillConnecting() { + return currentCallState == VoIPService.STATE_WAIT_INIT || currentCallState == VoIPService.STATE_WAIT_INIT_ACK || currentCallState == VoIPService.STATE_CREATING || currentCallState == VoIPService.STATE_RECONNECTING; + } + @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.groupCallUpdated) { @@ -914,6 +995,38 @@ public void didReceivedNotification(int id, int account, Object... args) { if (call.call instanceof TLRPC.TL_groupCallDiscarded) { dismiss(); } else { + if (creatingServiceTime == 0 && (muteButtonState == MUTE_BUTTON_STATE_CANCEL_REMINDER || muteButtonState == MUTE_BUTTON_STATE_START_NOW || muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) && !call.isScheduled()) { + try { + Intent intent = new Intent(parentActivity, VoIPService.class); + intent.putExtra("chat_id", currentChat.id); + intent.putExtra("createGroupCall", false); + intent.putExtra("hasFewPeers", scheduleHasFewPeers); + intent.putExtra("peerChannelId", schedulePeer.channel_id); + intent.putExtra("peerChatId", schedulePeer.chat_id); + intent.putExtra("peerUserId", schedulePeer.user_id); + intent.putExtra("hash", scheduledHash); + intent.putExtra("peerAccessHash", schedulePeer.access_hash); + intent.putExtra("is_outgoing", true); + intent.putExtra("start_incall_activity", false); + intent.putExtra("account", accountInstance.getCurrentAccount()); + intent.putExtra("scheduleDate", scheduleStartAt); + parentActivity.startService(intent); + } catch (Throwable e) { + FileLog.e(e); + } + creatingServiceTime = SystemClock.elapsedRealtime(); + AndroidUtilities.runOnUIThread(() -> { + if (!isStillConnecting()) { + return; + } + updateState(true, false); + }, 3000); + } + if (!callInitied && VoIPService.getSharedInstance() != null) { + call.addSelfDummyParticipant(false); + initCreatedGroupCall(); + VoIPService.getSharedInstance().playConnectedSound(); + } updateItems(); for (int a = 0, N = listView.getChildCount(); a < N; a++) { View child = listView.getChildAt(a); @@ -946,7 +1059,7 @@ public void didReceivedNotification(int id, int account, Object... args) { } else if (id == NotificationCenter.webRtcMicAmplitudeEvent) { float amplitude = (float) args[0]; setAmplitude(amplitude * 4000.0f); - if (listView != null) { + if (call != null && listView != null) { TLRPC.TL_groupCallParticipant participant = call.participants.get(MessageObject.getPeerId(selfPeer)); if (participant != null) { ArrayList array = delayedGroupCallUpdated ? oldParticipants : call.sortedParticipants; @@ -957,7 +1070,9 @@ public void didReceivedNotification(int id, int account, Object... args) { GroupCallUserCell cell = (GroupCallUserCell) holder.itemView; cell.setAmplitude(amplitude * 15.0f); if (holder.itemView == scrimView) { - containerView.invalidate(); + if (!contentFullyOverlayed) { + containerView.invalidate(); + } } } } @@ -994,6 +1109,27 @@ public void didReceivedNotification(int id, int account, Object... args) { updateItems(); updateState(isShowing(), false); } + int selfId = MessageObject.getPeerId(selfPeer); + if (call != null && chatFull.id == -selfId) { + TLRPC.TL_groupCallParticipant participant = call.participants.get(selfId); + if (participant != null) { + participant.about = chatFull.about; + applyCallParticipantUpdates(); + AndroidUtilities.updateVisibleRows(listView); + + if (currentOptionsLayout != null) { + for (int i = 0; i < currentOptionsLayout.getChildCount(); i++) { + View child = currentOptionsLayout.getChildAt(i); + if (child instanceof ActionBarMenuSubItem && child.getTag() != null && (Integer) child.getTag() == 10) { + ((ActionBarMenuSubItem) child).setTextAndIcon( + TextUtils.isEmpty(participant.about) ? LocaleController.getString("VoipAddDescription", R.string.VoipAddDescription) : LocaleController.getString("VoipEditDescription", R.string.VoipEditDescription), + TextUtils.isEmpty(participant.about) ? R.drawable.msg_addbio : R.drawable.msg_bio + ); + } + } + } + } + } } else if (id == NotificationCenter.didLoadChatAdmins) { int chatId = (Integer) args[0]; if (chatId == currentChat.id) { @@ -1011,11 +1147,42 @@ public void didReceivedNotification(int id, int account, Object... args) { cell.getParticipant().lastVisibleDate = time; } } + } else if (id == NotificationCenter.userInfoDidLoad) { + Integer uid = (Integer) args[0]; + int selfId = MessageObject.getPeerId(selfPeer); + if (call != null && selfId == uid) { + TLRPC.TL_groupCallParticipant participant = call.participants.get(selfId); + TLRPC.UserFull userInfo = (TLRPC.UserFull) args[1]; + participant.about = userInfo.about; + applyCallParticipantUpdates(); + AndroidUtilities.updateVisibleRows(listView); + + if (currentOptionsLayout != null) { + for (int i = 0; i < currentOptionsLayout.getChildCount(); i++) { + View child = currentOptionsLayout.getChildAt(i); + if (child instanceof ActionBarMenuSubItem && child.getTag() != null && (Integer) child.getTag() == 10) { + ((ActionBarMenuSubItem) child).setTextAndIcon( + TextUtils.isEmpty(participant.about) ? LocaleController.getString("VoipAddBio", R.string.VoipAddBio) : LocaleController.getString("VoipEditBio", R.string.VoipEditBio), + TextUtils.isEmpty(participant.about) ? R.drawable.msg_addbio : R.drawable.msg_bio + ); + } + } + } + } + } else if (id == NotificationCenter.mainUserInfoChanged) { + applyCallParticipantUpdates(); + AndroidUtilities.updateVisibleRows(listView); + } else if (id == NotificationCenter.updateInterfaces) { + int mask = (int) args[0]; + if ((mask & MessagesController.UPDATE_MASK_CHAT_NAME) != 0) { + applyCallParticipantUpdates(); + AndroidUtilities.updateVisibleRows(listView); + } } } private void applyCallParticipantUpdates() { - if (delayedGroupCallUpdated) { + if (call == null || delayedGroupCallUpdated) { return; } int self = MessageObject.getPeerId(call.selfPeer); @@ -1070,6 +1237,9 @@ private void applyCallParticipantUpdates() { } private void updateRecordCallText() { + if (call == null) { + return; + } int time = accountInstance.getConnectionsManager().getCurrentTime() - call.call.record_start_date; if (call.recording) { recordItem.setSubtext(AndroidUtilities.formatDuration(time, false)); @@ -1079,6 +1249,14 @@ private void updateRecordCallText() { } private void updateItems() { + if (call == null || call.isScheduled()) { + pipItem.setVisibility(View.INVISIBLE); + if (call == null) { + otherItem.setVisibility(View.GONE); + accountSwitchImageView.setVisibility(View.GONE); + return; + } + } if (changingPermissions) { return; } @@ -1096,7 +1274,11 @@ private void updateItems() { if (ChatObject.canManageCalls(currentChat)) { leaveItem.setVisibility(View.VISIBLE); editTitleItem.setVisibility(View.VISIBLE); - recordItem.setVisibility(View.VISIBLE); + if (call.isScheduled()) { + recordItem.setVisibility(View.GONE); + } else { + recordItem.setVisibility(View.VISIBLE); + } anyVisible = true; recordCallDrawable.setRecording(call.recording); if (call.recording) { @@ -1129,7 +1311,7 @@ private void updateItems() { otherItem.setVisibility(anyVisible ? View.VISIBLE : View.GONE); int margin = 48; - if (VoIPService.getSharedInstance() != null && VoIPService.getSharedInstance().hasFewPeers) { + if (VoIPService.getSharedInstance() != null && VoIPService.getSharedInstance().hasFewPeers || scheduleHasFewPeers) { if (!anyVisible) { anyVisible = true; accountSwitchImageView.getImageReceiver().setCurrentAccount(currentAccount); @@ -1137,11 +1319,11 @@ private void updateItems() { if (peerId > 0) { TLRPC.User user = accountInstance.getMessagesController().getUser(peerId); accountSwitchAvatarDrawable.setInfo(user); - accountSwitchImageView.setImage(ImageLocation.getForUser(user, false), "50_50", accountSwitchAvatarDrawable, user); + accountSwitchImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", accountSwitchAvatarDrawable, user); } else { TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-peerId); accountSwitchAvatarDrawable.setInfo(chat); - accountSwitchImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", accountSwitchAvatarDrawable, chat); + accountSwitchImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", accountSwitchAvatarDrawable, chat); } accountSelectCell.setVisibility(View.GONE); accountGap.setVisibility(View.GONE); @@ -1220,30 +1402,56 @@ protected void makeFocusable(BottomSheet bottomSheet, AlertDialog alertDialog, E } } - public static void create(LaunchActivity activity, AccountInstance account) { - if (groupCallInstance != null || VoIPService.getSharedInstance() == null) { + public static void create(LaunchActivity activity, AccountInstance account, TLRPC.Chat scheduleChat, TLRPC.InputPeer schedulePeer, boolean hasFewPeers, String scheduledHash) { + if (groupCallInstance != null || schedulePeer == null && VoIPService.getSharedInstance() == null) { return; } - ChatObject.Call call = VoIPService.getSharedInstance().groupCall; - if (call == null) { - return; - } - TLRPC.Chat chat = account.getMessagesController().getChat(call.chatId); - if (chat == null) { - return; + if (schedulePeer != null) { + ChatObject.Call call = account.getMessagesController().getGroupCall(scheduleChat.id, false); + groupCallInstance = new GroupCallActivity(activity, account, call, scheduleChat, schedulePeer, hasFewPeers, scheduledHash); + } else { + ChatObject.Call call = VoIPService.getSharedInstance().groupCall; + if (call == null) { + return; + } + TLRPC.Chat chat = account.getMessagesController().getChat(call.chatId); + if (chat == null) { + return; + } + call.addSelfDummyParticipant(true); + groupCallInstance = new GroupCallActivity(activity, account, call, chat, null, hasFewPeers, scheduledHash); } - call.addSelfDummyParticipant(); - groupCallInstance = new GroupCallActivity(activity, account, call, chat); groupCallInstance.parentActivity = activity; groupCallInstance.show(); } - private GroupCallActivity(Context context, AccountInstance account, ChatObject.Call call, TLRPC.Chat chat) { + private GroupCallActivity(Context context, AccountInstance account, ChatObject.Call groupCall, TLRPC.Chat chat, TLRPC.InputPeer schedulePeer, boolean scheduleHasFewPeers, String scheduledHash) { super(context, false); this.accountInstance = account; - this.call = call; + this.call = groupCall; + this.schedulePeer = schedulePeer; this.currentChat = chat; + this.scheduledHash = scheduledHash; this.currentAccount = account.getCurrentAccount(); + this.scheduleHasFewPeers = scheduleHasFewPeers; + setDelegate(new BottomSheetDelegateInterface() { + @Override + public void onOpenAnimationStart() { + + } + + @Override + public void onOpenAnimationEnd() { + if (muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) { + showReminderHint(); + } + } + + @Override + public boolean canDismiss() { + return true; + } + }); drawNavigationBar = true; if (Build.VERSION.SDK_INT >= 30) { getWindow().setNavigationBarColor(0xff000000); @@ -1271,88 +1479,347 @@ public void setAlpha(int a) { setDimBehindAlpha(75); - oldParticipants.addAll(call.sortedParticipants); - oldInvited.addAll(call.invitedUsers); + listAdapter = new ListAdapter(context); - TLRPC.InputPeer peer = VoIPService.getSharedInstance().getGroupCallPeer(); - if (peer == null) { - selfPeer = new TLRPC.TL_peerUser(); - selfPeer.user_id = accountInstance.getUserConfig().getClientUserId(); - } else if (peer instanceof TLRPC.TL_inputPeerChannel) { - selfPeer = new TLRPC.TL_peerChannel(); - selfPeer.channel_id = peer.channel_id; - } else if (peer instanceof TLRPC.TL_inputPeerUser) { - selfPeer = new TLRPC.TL_peerUser(); - selfPeer.user_id = peer.user_id; - } else if (peer instanceof TLRPC.TL_inputPeerChat) { - selfPeer = new TLRPC.TL_peerChat(); - selfPeer.chat_id = peer.chat_id; - } + actionBar = new ActionBar(context) { + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + containerView.invalidate(); + } + }; + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setOccupyStatusBar(false); + actionBar.setAllowOverlayTitle(false); + actionBar.setItemsColor(Theme.getColor(Theme.key_voipgroup_actionBarItems), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), false); + actionBar.setTitleColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); + actionBar.setSubtitleColor(Theme.getColor(Theme.key_voipgroup_lastSeenTextUnscrolled)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + dismiss(); + } else if (id == eveyone_can_speak_item) { + call.call.join_muted = false; + toggleAdminSpeak(); + } else if (id == admin_can_speak_item) { + call.call.join_muted = true; + toggleAdminSpeak(); + } else if (id == share_invite_link_item) { + getLink(false); + } else if (id == leave_item) { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - currentCallState = VoIPService.getSharedInstance().getCallState(); + builder.setTitle(LocaleController.getString("VoipGroupEndAlertTitle", R.string.VoipGroupEndAlertTitle)); + builder.setMessage(LocaleController.getString("VoipGroupEndAlertText", R.string.VoipGroupEndAlertText)); + builder.setDialogButtonColorKey(Theme.key_voipgroup_listeningText); - VoIPService.audioLevelsCallback = (uids, levels, voice) -> { - for (int a = 0; a < uids.length; a++) { - TLRPC.TL_groupCallParticipant participant = call.participantsBySources.get(uids[a]); - if (participant != null) { - ArrayList array = delayedGroupCallUpdated ? oldParticipants : call.sortedParticipants; - int idx = array.indexOf(participant); - if (idx >= 0) { - RecyclerView.ViewHolder holder = listView.findViewHolderForAdapterPosition(idx + listAdapter.usersStartRow); - if (holder != null && holder.itemView instanceof GroupCallUserCell) { - GroupCallUserCell cell = (GroupCallUserCell) holder.itemView; - cell.setAmplitude(levels[a] * 15.0f); - if (holder.itemView == scrimView) { - containerView.invalidate(); + builder.setPositiveButton(LocaleController.getString("VoipGroupEnd", R.string.VoipGroupEnd), (dialogInterface, i) -> { + if (call.isScheduled()) { + TLRPC.ChatFull chatFull = accountInstance.getMessagesController().getChatFull(currentChat.id); + if (chatFull != null) { + chatFull.flags &=~ 2097152; + chatFull.call = null; + accountInstance.getNotificationCenter().postNotificationName(NotificationCenter.groupCallUpdated, currentChat.id, call.call.id, false); } + TLRPC.TL_phone_discardGroupCall req = new TLRPC.TL_phone_discardGroupCall(); + req.call = call.getInputGroupCall(); + accountInstance.getConnectionsManager().sendRequest(req, (response, error) -> { + if (response instanceof TLRPC.TL_updates) { + TLRPC.TL_updates updates = (TLRPC.TL_updates) response; + accountInstance.getMessagesController().processUpdates(updates, false); + } + }); + } else if (VoIPService.getSharedInstance() != null) { + VoIPService.getSharedInstance().hangUp(1); } + dismiss(); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didStartedCall); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + AlertDialog dialog = builder.create(); + + dialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_dialogBackground)); + dialog.show(); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_voipgroup_leaveCallMenu)); } - } - } - }; + dialog.setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); + } else if (id == start_record_item) { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setDialogButtonColorKey(Theme.key_voipgroup_listeningText); + EditTextBoldCursor editText; + if (call.recording) { + builder.setTitle(LocaleController.getString("VoipGroupStopRecordingTitle", R.string.VoipGroupStopRecordingTitle)); + builder.setMessage(LocaleController.getString("VoipGroupStopRecordingText", R.string.VoipGroupStopRecordingText)); + editText = null; + } else { + enterEventSent = false; + builder.setTitle(LocaleController.getString("VoipGroupStartRecordingTitle", R.string.VoipGroupStartRecordingTitle)); + builder.setMessage(LocaleController.getString("VoipGroupStartRecordingText", R.string.VoipGroupStartRecordingText)); + builder.setCheckFocusable(false); - accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.groupCallUpdated); - accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.needShowAlert); - accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.chatInfoDidLoad); - accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.didLoadChatAdmins); - accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.applyGroupCallVisibleParticipants); - NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.webRtcMicAmplitudeEvent); - NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didEndCall); + editText = new EditTextBoldCursor(getContext()); + editText.setBackgroundDrawable(Theme.createEditTextDrawable(getContext(), true)); - shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow_round).mutate(); + LinearLayout linearLayout = new LinearLayout(getContext()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + builder.setView(linearLayout); - bigMicDrawable = new RLottieDrawable(R.raw.voice_outlined2, "" + R.raw.voice_outlined2, AndroidUtilities.dp(57), AndroidUtilities.dp(55), true, null); - handDrawables = new RLottieDrawable(R.raw.hand_1, "" + R.raw.hand_1, AndroidUtilities.dp(57), AndroidUtilities.dp(55), true, null); + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + editText.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); + editText.setMaxLines(1); + editText.setLines(1); + editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); + editText.setGravity(Gravity.LEFT | Gravity.TOP); + editText.setSingleLine(true); + editText.setHint(LocaleController.getString("VoipGroupSaveFileHint", R.string.VoipGroupSaveFileHint)); + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + editText.setHintTextColor(Theme.getColor(Theme.key_voipgroup_lastSeenText)); + editText.setCursorColor(Theme.getColor(Theme.key_voipgroup_nameText)); + editText.setCursorSize(AndroidUtilities.dp(20)); + editText.setCursorWidth(1.5f); + editText.setPadding(0, AndroidUtilities.dp(4), 0, 0); + linearLayout.addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.LEFT, 24, 0, 24, 12)); + editText.setOnEditorActionListener((textView, i2, keyEvent) -> { + AndroidUtilities.hideKeyboard(textView); + builder.create().getButton(AlertDialog.BUTTON_POSITIVE).callOnClick(); + return false; + }); - containerView = new FrameLayout(context) { + final AlertDialog alertDialog = builder.create(); + alertDialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_inviteMembersBackground)); + alertDialog.setOnShowListener(dialog -> makeFocusable(null, alertDialog, editText, true)); + alertDialog.setOnDismissListener(dialog -> AndroidUtilities.hideKeyboard(editText)); + } - private boolean ignoreLayout = false; - private RectF rect = new RectF(); - private int lastSize; + builder.setPositiveButton(call.recording ? LocaleController.getString("Stop", R.string.Stop) : LocaleController.getString("Start", R.string.Start), (dialogInterface, i) -> { + if (editText == null) { + call.toggleRecord(null); + getUndoView().showWithAction(0, UndoView.ACTION_VOIP_RECORDING_FINISHED, null); + } else { + call.toggleRecord(editText.getText().toString()); + AndroidUtilities.hideKeyboard(editText); + getUndoView().showWithAction(0, UndoView.ACTION_VOIP_RECORDING_STARTED, null); + if (VoIPService.getSharedInstance() != null) { + VoIPService.getSharedInstance().playStartRecordSound(); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> AndroidUtilities.hideKeyboard(editText)); + AlertDialog dialog = builder.create(); + dialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_dialogBackground)); + dialog.show(); + dialog.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); + if (editText != null) { + editText.requestFocus(); + } + } else if (id == permission_item) { + changingPermissions = true; + everyoneItem.setVisibility(View.VISIBLE); + adminItem.setVisibility(View.VISIBLE); - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int totalHeight = MeasureSpec.getSize(heightMeasureSpec); - if (Build.VERSION.SDK_INT >= 21) { - ignoreLayout = true; - setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); - ignoreLayout = false; - } - int availableHeight = totalHeight - getPaddingTop() - AndroidUtilities.dp(14 + 231); + accountGap.setVisibility(View.GONE); + inviteItem.setVisibility(View.GONE); + leaveItem.setVisibility(View.GONE); + permissionItem.setVisibility(View.GONE); + editTitleItem.setVisibility(View.GONE); + recordItem.setVisibility(View.GONE); + accountSelectCell.setVisibility(View.GONE); + otherItem.forceUpdatePopupPosition(); + } else if (id == edit_item) { + enterEventSent = false; + final EditTextBoldCursor editText = new EditTextBoldCursor(getContext()); + editText.setBackgroundDrawable(Theme.createEditTextDrawable(getContext(), true)); - LayoutParams layoutParams = (LayoutParams) listView.getLayoutParams(); - layoutParams.topMargin = ActionBar.getCurrentActionBarHeight() + AndroidUtilities.dp(14); + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setDialogButtonColorKey(Theme.key_voipgroup_listeningText); + builder.setTitle(LocaleController.getString("VoipGroupTitle", R.string.VoipGroupTitle)); + builder.setCheckFocusable(false); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> AndroidUtilities.hideKeyboard(editText)); - layoutParams = (LayoutParams) actionBarShadow.getLayoutParams(); + LinearLayout linearLayout = new LinearLayout(getContext()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + builder.setView(linearLayout); + + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + editText.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); + editText.setMaxLines(1); + editText.setLines(1); + editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); + editText.setGravity(Gravity.LEFT | Gravity.TOP); + editText.setSingleLine(true); + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + editText.setHint(currentChat.title); + editText.setHintTextColor(Theme.getColor(Theme.key_voipgroup_lastSeenText)); + editText.setCursorColor(Theme.getColor(Theme.key_voipgroup_nameText)); + editText.setCursorSize(AndroidUtilities.dp(20)); + editText.setCursorWidth(1.5f); + editText.setPadding(0, AndroidUtilities.dp(4), 0, 0); + linearLayout.addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.LEFT, 24, 6, 24, 0)); + editText.setOnEditorActionListener((textView, i, keyEvent) -> { + AndroidUtilities.hideKeyboard(textView); + builder.create().getButton(AlertDialog.BUTTON_POSITIVE).callOnClick(); + return false; + }); + editText.addTextChangedListener(new TextWatcher() { + + boolean ignoreTextChange; + + @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) { + if (ignoreTextChange) { + return; + } + if (s.length() > 40) { + ignoreTextChange = true; + s.delete(40, s.length()); + AndroidUtilities.shakeView(editText, 2, 0); + editText.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + ignoreTextChange = false; + } + } + }); + if (!TextUtils.isEmpty(call.call.title)) { + editText.setText(call.call.title); + editText.setSelection(editText.length()); + } + builder.setPositiveButton(LocaleController.getString("Save", R.string.Save), (dialog, which) -> { + AndroidUtilities.hideKeyboard(editText); + call.setTitle(editText.getText().toString()); + builder.getDismissRunnable().run(); + }); + + final AlertDialog alertDialog = builder.create(); + alertDialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_inviteMembersBackground)); + alertDialog.setOnShowListener(dialog -> makeFocusable(null, alertDialog, editText, true)); + alertDialog.setOnDismissListener(dialog -> AndroidUtilities.hideKeyboard(editText)); + alertDialog.show(); + alertDialog.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); + editText.requestFocus(); + } else if (id == user_item) { + accountSwitchImageView.callOnClick(); + } + } + }); + + TLRPC.InputPeer peer; + if (schedulePeer != null) { + peer = schedulePeer; + } else { + peer = VoIPService.getSharedInstance().getGroupCallPeer(); + } + if (peer == null) { + selfPeer = new TLRPC.TL_peerUser(); + selfPeer.user_id = accountInstance.getUserConfig().getClientUserId(); + } else if (peer instanceof TLRPC.TL_inputPeerChannel) { + selfPeer = new TLRPC.TL_peerChannel(); + selfPeer.channel_id = peer.channel_id; + } else if (peer instanceof TLRPC.TL_inputPeerUser) { + selfPeer = new TLRPC.TL_peerUser(); + selfPeer.user_id = peer.user_id; + } else if (peer instanceof TLRPC.TL_inputPeerChat) { + selfPeer = new TLRPC.TL_peerChat(); + selfPeer.chat_id = peer.chat_id; + } + + VoIPService.audioLevelsCallback = (uids, levels, voice) -> { + for (int a = 0; a < uids.length; a++) { + TLRPC.TL_groupCallParticipant participant = call.participantsBySources.get(uids[a]); + if (participant != null) { + ArrayList array = delayedGroupCallUpdated ? oldParticipants : call.sortedParticipants; + int idx = array.indexOf(participant); + if (idx >= 0) { + RecyclerView.ViewHolder holder = listView.findViewHolderForAdapterPosition(idx + listAdapter.usersStartRow); + if (holder != null && holder.itemView instanceof GroupCallUserCell) { + GroupCallUserCell cell = (GroupCallUserCell) holder.itemView; + cell.setAmplitude(levels[a] * 15.0f); + if (holder.itemView == scrimView) { + containerView.invalidate(); + } + } + } + } + } + }; + + accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.groupCallUpdated); + accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.needShowAlert); + accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.chatInfoDidLoad); + accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.didLoadChatAdmins); + accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.applyGroupCallVisibleParticipants); + accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.userInfoDidLoad); + accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.mainUserInfoChanged); + accountInstance.getNotificationCenter().addObserver(this, NotificationCenter.updateInterfaces); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.webRtcMicAmplitudeEvent); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didEndCall); + + shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow_round).mutate(); + + bigMicDrawable = new RLottieDrawable(R.raw.voip_filled, "" + R.raw.voip_filled, AndroidUtilities.dp(72), AndroidUtilities.dp(72), true, null); + handDrawables = new RLottieDrawable(R.raw.hand_2, "" + R.raw.hand_2, AndroidUtilities.dp(72), AndroidUtilities.dp(72), true, null); + + containerView = new FrameLayout(context) { + + private boolean ignoreLayout = false; + private RectF rect = new RectF(); + private int lastSize; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int totalHeight = MeasureSpec.getSize(heightMeasureSpec); + if (Build.VERSION.SDK_INT >= 21) { + ignoreLayout = true; + setPadding(backgroundPaddingLeft, statusBarHeight, backgroundPaddingLeft, 0); + ignoreLayout = false; + } + int availableHeight = totalHeight - getPaddingTop() - AndroidUtilities.dp(14 + 231); + + LayoutParams layoutParams = (LayoutParams) listView.getLayoutParams(); + layoutParams.topMargin = ActionBar.getCurrentActionBarHeight() + AndroidUtilities.dp(14); + + layoutParams = (LayoutParams) actionBarShadow.getLayoutParams(); layoutParams.topMargin = ActionBar.getCurrentActionBarHeight(); int contentSize = Math.max(AndroidUtilities.dp(64 + 50 + 58 * 2.5f), availableHeight / 5 * 3); int padding = Math.max(0, availableHeight - contentSize + AndroidUtilities.dp(8)); + ignoreLayout = true; if (listView.getPaddingTop() != padding) { - ignoreLayout = true; listView.setPadding(0, padding, 0, 0); - ignoreLayout = false; } + if (scheduleStartAtTextView != null) { + int y = padding + (availableHeight - padding + AndroidUtilities.dp(60)) / 2; + FrameLayout.LayoutParams layoutParams1 = (FrameLayout.LayoutParams) scheduleStartInTextView.getLayoutParams(); + layoutParams1.topMargin = y - AndroidUtilities.dp(30); + + FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) scheduleStartAtTextView.getLayoutParams(); + layoutParams2.topMargin = y + AndroidUtilities.dp(80); + + FrameLayout.LayoutParams layoutParams3 = (FrameLayout.LayoutParams) scheduleTimeTextView.getLayoutParams(); + + if (layoutParams1.topMargin < ActionBar.getCurrentActionBarHeight() || layoutParams2.topMargin + AndroidUtilities.dp(20) > totalHeight - AndroidUtilities.dp(231)) { + scheduleStartInTextView.setVisibility(INVISIBLE); + scheduleStartAtTextView.setVisibility(INVISIBLE); + layoutParams3.topMargin = y - AndroidUtilities.dp(20); + } else { + scheduleStartInTextView.setVisibility(VISIBLE); + scheduleStartAtTextView.setVisibility(VISIBLE); + layoutParams3.topMargin = y; + } + } + ignoreLayout = false; super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(totalHeight, MeasureSpec.EXACTLY)); int currentSize = getMeasuredHeight() + (getMeasuredWidth() << 16); if (currentSize != lastSize) { @@ -1386,7 +1853,7 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { return true; } } - if (ev.getAction() == MotionEvent.ACTION_DOWN && scrollOffsetY != 0 && ev.getY() < scrollOffsetY - AndroidUtilities.dp(37) && actionBar.getAlpha() == 0.0f) { + if (ev.getAction() == MotionEvent.ACTION_DOWN && scrollOffsetY != 0 && ev.getY() < scrollOffsetY - AndroidUtilities.dp(37) && actionBar.getAlpha() == 0.0f && !avatarsPreviewShowed) { dismiss(); return true; } @@ -1437,7 +1904,7 @@ protected void onDraw(Canvas canvas) { int finalColor = Color.argb((int) (255 * actionBar.getAlpha()), (int) (Color.red(backgroundColor) * 0.8f), (int) (Color.green(backgroundColor) * 0.8f), (int) (Color.blue(backgroundColor) * 0.8f)); Theme.dialogs_onlineCirclePaint.setColor(finalColor); - canvas.drawRect(backgroundPaddingLeft, 0, getMeasuredWidth() - backgroundPaddingLeft, AndroidUtilities.statusBarHeight, Theme.dialogs_onlineCirclePaint); + canvas.drawRect(backgroundPaddingLeft, 0, getMeasuredWidth() - backgroundPaddingLeft, statusBarHeight, Theme.dialogs_onlineCirclePaint); } @Override @@ -1451,7 +1918,6 @@ protected void dispatchDraw(Canvas canvas) { Path roundPath = new Path(); int count = listView.getChildCount(); - float viewClipTop = listTop; float viewClipBottom = listView.getY() + listView.getMeasuredHeight(); for (int num = 0; num < count; num++) { @@ -1461,10 +1927,9 @@ protected void dispatchDraw(Canvas canvas) { } - if (viewClipTop < viewClipBottom) { -// + if (listTop < viewClipBottom) { canvas.save(); - canvas.clipRect(0, viewClipTop * (1f - progressToAvatarPreview), getMeasuredWidth(), viewClipBottom * (1f - progressToAvatarPreview) + getMeasuredHeight() * progressToAvatarPreview); + canvas.clipRect(0, listTop * (1f - progressToAvatarPreview), getMeasuredWidth(), viewClipBottom * (1f - progressToAvatarPreview) + getMeasuredHeight() * progressToAvatarPreview); float childY = (listView.getY() + child.getY()) * (1f - progressToAvatarPreview) + (avatarPreviewContainer.getTop() + avatarPreviewContainer.getMeasuredWidth()) * progressToAvatarPreview; float childX = (listView.getLeft() + child.getX()) * (1f - progressToAvatarPreview) + avatarPreviewContainer.getLeft() * progressToAvatarPreview; @@ -1473,7 +1938,6 @@ protected void dispatchDraw(Canvas canvas) { float pr = 1.0f - CubicBezierInterpolator.EASE_OUT.getInterpolation(1.0f - progress); int h = (int) (scrimView.getMeasuredHeight() + (scrimView.getClipHeight() - scrimView.getMeasuredHeight()) * pr); rect.set(0, 0, child.getMeasuredWidth(), h); - //scrimView.setAboutVisibleProgress(listViewBackgroundPaint.getColor(), progressToAvatarPreview); scrimView.setProgressToAvatarPreview(progressToAvatarPreview); for (int i = 0; i < 4; i++) { radii[i] = AndroidUtilities.dp(13) * (1f - progressToAvatarPreview); @@ -1507,12 +1971,14 @@ protected void dispatchDraw(Canvas canvas) { } } - canvas.save(); - canvas.clipRect(0, viewClipTop * (1f - progressToAvatarPreview), getMeasuredWidth(), viewClipBottom * (1f - progressToAvatarPreview) + getMeasuredHeight() * progressToAvatarPreview); - canvas.scale(avatarPreviewContainer.getScaleX(), avatarPreviewContainer.getScaleY(), avatarPreviewContainer.getX(), avatarPreviewContainer.getY()); - canvas.translate(avatarPreviewContainer.getX(), avatarPreviewContainer.getY()); - avatarPreviewContainer.draw(canvas); - canvas.restore(); + if (!pinchToZoomHelper.isInOverlayMode()) { + canvas.save(); + canvas.clipRect(0, listTop * (1f - progressToAvatarPreview), getMeasuredWidth(), viewClipBottom * (1f - progressToAvatarPreview) + getMeasuredHeight() * progressToAvatarPreview); + canvas.scale(avatarPreviewContainer.getScaleX(), avatarPreviewContainer.getScaleY(), avatarPreviewContainer.getX(), avatarPreviewContainer.getY()); + canvas.translate(avatarPreviewContainer.getX(), avatarPreviewContainer.getY()); + avatarPreviewContainer.draw(canvas); + canvas.restore(); + } } } else { if (scrimView != null) { @@ -1561,6 +2027,11 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == avatarPreviewContainer || child == scrimPopupLayout) { return true; } + if (contentFullyOverlayed) { + if (child == listView || child == buttonsContainer) { + return true; + } + } return super.drawChild(canvas, child, drawingTime); } @@ -1580,6 +2051,102 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { containerView.setKeepScreenOn(true); containerView.setClipChildren(false); + if (schedulePeer != null) { + scheduleStartInTextView = new SimpleTextView(context); + scheduleStartInTextView.setGravity(Gravity.CENTER); + scheduleStartInTextView.setTextColor(0xffffffff); + scheduleStartInTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + scheduleStartInTextView.setTextSize(18); + scheduleStartInTextView.setText(LocaleController.getString("VoipChatStartsIn", R.string.VoipChatStartsIn)); + containerView.addView(scheduleStartInTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 21, 0, 21, 231 + 80)); //-80 + + scheduleTimeTextView = new SimpleTextView(context) { + + private LinearGradient linearGradient; + private int lastTextWidth; + private Matrix matrix = new Matrix(); + private float targetX = -1f; + private float startX; + private float duration; + private float time; + private float gradientWidth; + private long lastUpdateTime; + + private void setTarget() { + targetX = 0.20f * (Utilities.random.nextInt(100) - 50) / 50.0f; + } + + @Override + protected boolean createLayout(int width) { + boolean result = super.createLayout(width); + int w = getTextWidth(); + if (w != lastTextWidth) { + gradientWidth = w * 1.3f; + linearGradient = new LinearGradient(0, getTextHeight(), w * 2.0f, 0, new int[]{Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient), Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient3), Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient2), Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient2)}, new float[]{0.0f, 0.38f, 0.76f, 1.0f}, Shader.TileMode.CLAMP); + getPaint().setShader(linearGradient); + lastTextWidth = w; + } + return result; + } + + @Override + protected void onDraw(Canvas canvas) { + float moveProgress = 0.0f; + if (linearGradient != null) { + if (call != null && call.isScheduled()) { + long diff = ((long) call.call.schedule_date) * 1000 - accountInstance.getConnectionsManager().getCurrentTimeMillis(); + if (diff < 0) { + moveProgress = 1.0f; + } else if (diff < 5000) { + moveProgress = 1.0f - diff / 5000.0f; + } + } + matrix.reset(); + matrix.postTranslate(-lastTextWidth * 0.7f * moveProgress, 0); + + long newTime = SystemClock.elapsedRealtime(); + long dt = newTime - lastUpdateTime; + if (dt > 20) { + dt = 17; + } + lastUpdateTime = newTime; + if (duration == 0 || time >= duration) { + duration = Utilities.random.nextInt(200) + 1500; + time = 0; + if (targetX == -1f) { + setTarget(); + } + startX = targetX; + setTarget(); + } + time += dt * (0.5f + BlobDrawable.GRADIENT_SPEED_MIN) + dt * (BlobDrawable.GRADIENT_SPEED_MAX * 2) * amplitude; + if (time > duration) { + time = duration; + } + float interpolation = CubicBezierInterpolator.EASE_OUT.getInterpolation(time / duration); + float x = gradientWidth * (startX + (targetX - startX) * interpolation) - gradientWidth / 2; + matrix.postTranslate(x, 0); + + linearGradient.setLocalMatrix(matrix); + invalidate(); + } + super.onDraw(canvas); + } + }; + scheduleTimeTextView.setGravity(Gravity.CENTER); + scheduleTimeTextView.setTextColor(0xffffffff); + scheduleTimeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + scheduleTimeTextView.setTextSize(60); + containerView.addView(scheduleTimeTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 21, 0, 21, 231)); + + scheduleStartAtTextView = new SimpleTextView(context); + scheduleStartAtTextView.setGravity(Gravity.CENTER); + scheduleStartAtTextView.setTextColor(0xffffffff); + scheduleStartAtTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + scheduleStartAtTextView.setTextSize(18); + containerView.addView(scheduleStartAtTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 21, 0, 21, 231 - 30)); //+ 30 + } + listView = new RecyclerListView(context) { @Override @@ -1607,6 +2174,7 @@ protected void dispatchDraw(Canvas canvas) { minTop = Math.min(minTop, Math.max(0, child.getY())); } } + rect.set(0, minTop, getMeasuredWidth(), Math.min(getMeasuredHeight(), maxBottom)); canvas.drawRoundRect(rect, AndroidUtilities.dp(13), AndroidUtilities.dp(13), listViewBackgroundPaint); @@ -1630,7 +2198,7 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - if (listView.getChildCount() <= 0) { + if (listView.getChildCount() <= 0 || call == null) { return; } if (!call.loadingMembers && !call.membersLoadEndReached && layoutManager.findLastVisibleItemPosition() > listAdapter.getItemCount() - 5) { @@ -1655,6 +2223,9 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (recordHintView != null) { recordHintView.hide(); } + if (reminderHintView != null) { + reminderHintView.hide(); + } } scrolling = newState == RecyclerView.SCROLL_STATE_DRAGGING; } @@ -1664,15 +2235,12 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { listView.setLayoutManager(layoutManager = new FillLastLinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false, 0, listView)); layoutManager.setBind(false); containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 14, 14, 14, 231)); - listView.setAdapter(listAdapter = new ListAdapter(context)); + listView.setAdapter(listAdapter); listView.setTopBottomSelectorRadius(13); listView.setSelectorDrawableColor(Theme.getColor(Theme.key_voipgroup_listSelector)); listView.setOnItemClickListener((view, position, x, y) -> { if (view instanceof GroupCallUserCell) { GroupCallUserCell cell = (GroupCallUserCell) view; - if (cell.isSelfUser() && !cell.isHandRaised()) { - return; - } showMenuForCell(cell); } else if (view instanceof GroupCallInvitedCell) { GroupCallInvitedCell cell = (GroupCallInvitedCell) view; @@ -1768,6 +2336,9 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto @SuppressLint("DrawAllocation") @Override protected void dispatchDraw(Canvas canvas) { + if (contentFullyOverlayed) { + return; + } int offset = (getMeasuredWidth() - getMeasuredHeight()) / 2; long newTime = SystemClock.elapsedRealtime(); @@ -1861,7 +2432,7 @@ protected void dispatchDraw(Canvas canvas) { boolean showWaves = false; boolean showLighting = false; if (currentState != null) { - showWaves = currentState.currentState == MUTE_BUTTON_STATE_MUTE || currentState.currentState == MUTE_BUTTON_STATE_UNMUTE || currentState.currentState == MUTE_BUTTON_STATE_RAISED_HAND || currentState.currentState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN; + showWaves = currentState.currentState == MUTE_BUTTON_STATE_MUTE || currentState.currentState == MUTE_BUTTON_STATE_UNMUTE || isGradientState(currentState.currentState); showLighting = currentState.currentState != MUTE_BUTTON_STATE_CONNECTING; } @@ -1928,8 +2499,10 @@ protected void dispatchDraw(Canvas canvas) { paint.setAlpha(76); - float radius = AndroidUtilities.dp(52) / 2f; - canvas.drawCircle(leaveButton.getX() + leaveButton.getMeasuredWidth() / 2f, leaveButton.getY() + radius, radius, leaveBackgroundPaint); + if (call != null) { + float radius = AndroidUtilities.dp(52) / 2f; + canvas.drawCircle(leaveButton.getX() + leaveButton.getMeasuredWidth() / 2f, leaveButton.getY() + radius, radius, leaveBackgroundPaint); + } canvas.save(); canvas.scale(BlobDrawable.GLOBAL_SCALE, BlobDrawable.GLOBAL_SCALE, cx, cy); @@ -1943,19 +2516,21 @@ protected void dispatchDraw(Canvas canvas) { canvas.scale(scaleLight, scaleLight, cx, cy); canvas.drawCircle(cx, cy, AndroidUtilities.dp(160), radialPaint); canvas.restore(); - - canvas.restore(); - canvas.save(); - scale = BlobDrawable.SCALE_BIG_MIN + BlobDrawable.SCALE_BIG * amplitude; - canvas.scale(scale * showWavesProgressInterpolated, scale * showWavesProgressInterpolated, cx, cy); - bigWaveDrawable.draw(cx, cy, canvas, paint); canvas.restore(); - canvas.save(); - scale = BlobDrawable.SCALE_SMALL_MIN + BlobDrawable.SCALE_SMALL * amplitude; - canvas.scale(scale * showWavesProgressInterpolated, scale * showWavesProgressInterpolated, cx, cy); - tinyWaveDrawable.draw(cx, cy, canvas, paint); - canvas.restore(); + if (call != null) { + canvas.save(); + scale = BlobDrawable.SCALE_BIG_MIN + BlobDrawable.SCALE_BIG * amplitude * scheduleButtonsScale; + canvas.scale(scale * showWavesProgressInterpolated, scale * showWavesProgressInterpolated, cx, cy); + bigWaveDrawable.draw(cx, cy, canvas, paint); + canvas.restore(); + + canvas.save(); + scale = BlobDrawable.SCALE_SMALL_MIN + BlobDrawable.SCALE_SMALL * amplitude * scheduleButtonsScale; + canvas.scale(scale * showWavesProgressInterpolated, scale * showWavesProgressInterpolated, cx, cy); + tinyWaveDrawable.draw(cx, cy, canvas, paint); + canvas.restore(); + } paint.setAlpha(255); @@ -2002,43 +2577,63 @@ protected void dispatchDraw(Canvas canvas) { radialMatrix.setTranslate(cx, cy); radialGradient.setLocalMatrix(radialMatrix); - paint.setAlpha((int) (76 * alpha)); - if (i == 1) { - float radius = AndroidUtilities.dp(52) / 2f; - canvas.drawCircle(leaveButton.getX() + leaveButton.getMeasuredWidth() / 2, leaveButton.getY() + radius, radius, leaveBackgroundPaint); + paint.setAlpha((int) (76 * alpha * switchToButtonProgress)); + if (switchToButtonProgress > 0) { + if (i == 1) { + int a = leaveBackgroundPaint.getAlpha(); + leaveBackgroundPaint.setAlpha((int) (a * switchToButtonProgress)); + float radius = AndroidUtilities.dp(52) / 2f; + canvas.drawCircle(leaveButton.getX() + leaveButton.getMeasuredWidth() / 2, leaveButton.getY() + radius, radius, leaveBackgroundPaint); + leaveBackgroundPaint.setAlpha(a); + } } canvas.save(); canvas.scale(BlobDrawable.GLOBAL_SCALE, BlobDrawable.GLOBAL_SCALE, cx, cy); canvas.save(); + float translation = AndroidUtilities.dp(89) * (1.0f - switchToButtonInt2); + cy += translation; float scale = BlobDrawable.SCALE_BIG_MIN + BlobDrawable.SCALE_BIG * amplitude * 0.5f; canvas.scale(scale * showLightingProgress, scale * showLightingProgress, cx, cy); if (i == 1) { - float scaleLight = 0.7f + BlobDrawable.LIGHT_GRADIENT_SIZE; + float scaleLight = 0.7f + BlobDrawable.LIGHT_GRADIENT_SIZE * scheduleButtonsScale; canvas.save(); canvas.scale(scaleLight, scaleLight, cx, cy); + int a = radialPaint.getAlpha(); + radialPaint.setAlpha((int) (a * switchToButtonProgress)); canvas.drawCircle(cx, cy, AndroidUtilities.dp(160), radialPaint); + radialPaint.setAlpha(a); canvas.restore(); } canvas.restore(); - canvas.save(); - scale = BlobDrawable.SCALE_BIG_MIN + BlobDrawable.SCALE_BIG * amplitude; - canvas.scale(scale * showWavesProgressInterpolated, scale * showWavesProgressInterpolated, cx, cy); - bigWaveDrawable.draw(cx, cy, canvas, paint); - canvas.restore(); + if (switchToButtonProgress > 0) { + canvas.save(); + scale = BlobDrawable.SCALE_BIG_MIN + BlobDrawable.SCALE_BIG * amplitude * showWavesProgressInterpolated * scheduleButtonsScale; + canvas.scale(scale, scale, cx, cy); + bigWaveDrawable.draw(cx, cy, canvas, paint); + canvas.restore(); - canvas.save(); - scale = BlobDrawable.SCALE_SMALL_MIN + BlobDrawable.SCALE_SMALL * amplitude; - canvas.scale(scale * showWavesProgressInterpolated, scale * showWavesProgressInterpolated, cx, cy); - tinyWaveDrawable.draw(cx, cy, canvas, paint); - canvas.restore(); + canvas.save(); + scale = BlobDrawable.SCALE_SMALL_MIN + BlobDrawable.SCALE_SMALL * amplitude * showWavesProgressInterpolated * scheduleButtonsScale; + canvas.scale(scale, scale, cx, cy); + tinyWaveDrawable.draw(cx, cy, canvas, paint); + canvas.restore(); + } if (i == 0) { paint.setAlpha(255); } else { paint.setAlpha((int) (255 * alpha)); } - canvas.drawCircle(cx, cy, buttonRadius, paint); + + muteButton.setTranslationY(translation); + float startX = getMeasuredWidth() / 2 - AndroidUtilities.dp(21); + float startY = AndroidUtilities.dp(24); + float w = (startX + (buttonRadius - startX) * switchToButtonInt2) * scheduleButtonsScale; + float h = (startY + (buttonRadius - startY) * switchToButtonInt2) * scheduleButtonsScale; + rect.set(cx - w, cy - h, cx + w, cy + h); + float rad = AndroidUtilities.dp(4) + (buttonRadius - AndroidUtilities.dp(4)) * switchToButtonInt2; + canvas.drawRoundRect(rect, rad, rad, paint); canvas.restore(); @@ -2055,6 +2650,212 @@ protected void dispatchDraw(Canvas canvas) { buttonsContainer.setWillNotDraw(false); containerView.addView(buttonsContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 231, Gravity.LEFT | Gravity.BOTTOM)); + if (schedulePeer != null) { + scheduleInfoTextView = new TextView(context); + scheduleInfoTextView.setGravity(Gravity.CENTER); + scheduleInfoTextView.setTextColor(0xff7B8389); + scheduleInfoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + if (ChatObject.isChannel(currentChat) && !currentChat.megagroup) { + scheduleInfoTextView.setTag(1); + } + containerView.addView(scheduleInfoTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 21, 0, 21, 100)); + + final NumberPicker dayPicker = new NumberPicker(context); + dayPicker.setTextColor(0xffffffff); + dayPicker.setSelectorColor(0xff6D89ED); + dayPicker.setTextOffset(AndroidUtilities.dp(10)); + dayPicker.setItemCount(5); + final NumberPicker hourPicker = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int value) { + return LocaleController.formatPluralString("Hours", value); + } + }; + hourPicker.setItemCount(5); + hourPicker.setTextColor(0xffffffff); + hourPicker.setSelectorColor(0xff6D89ED); + hourPicker.setTextOffset(-AndroidUtilities.dp(10)); + final NumberPicker minutePicker = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int value) { + return LocaleController.formatPluralString("Minutes", value); + } + }; + minutePicker.setItemCount(5); + minutePicker.setTextColor(0xffffffff); + minutePicker.setSelectorColor(0xff6D89ED); + minutePicker.setTextOffset(-AndroidUtilities.dp(34)); + + scheduleButtonTextView = new TextView(context); + scheduleButtonTextView.setLines(1); + scheduleButtonTextView.setSingleLine(true); + scheduleButtonTextView.setEllipsize(TextUtils.TruncateAt.END); + scheduleButtonTextView.setGravity(Gravity.CENTER); + scheduleButtonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), 0, 0x3f000000)); + scheduleButtonTextView.setTextColor(0xffffffff); + scheduleButtonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + scheduleButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + containerView.addView(scheduleButtonTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 21, 0, 21, 20.5f)); + scheduleButtonTextView.setOnClickListener(v -> { + scheduleAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); + scheduleAnimator.setDuration(600); + scheduleAnimator.addUpdateListener(a -> { + switchToButtonProgress = (float) a.getAnimatedValue(); + updateScheduleUI(true); + + buttonsContainer.invalidate(); + listView.invalidate(); + }); + scheduleAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + scheduleAnimator = null; + } + }); + scheduleAnimator.start(); + titleTextView.setText(LocaleController.getString("VoipGroupVoiceChat", R.string.VoipGroupVoiceChat), true); + Calendar calendar = Calendar.getInstance(); + boolean setSeconds = AlertsCreator.checkScheduleDate(null, null, 7 * 24 * 60 * 60, 3, dayPicker, hourPicker, minutePicker); + calendar.setTimeInMillis(System.currentTimeMillis() + (long) dayPicker.getValue() * 24 * 3600 * 1000); + calendar.set(Calendar.HOUR_OF_DAY, hourPicker.getValue()); + calendar.set(Calendar.MINUTE, minutePicker.getValue()); + if (setSeconds) { + calendar.set(Calendar.SECOND, 0); + } + scheduleStartAt = (int) (calendar.getTimeInMillis() / 1000); + updateScheduleUI(false); + + TLRPC.TL_phone_createGroupCall req = new TLRPC.TL_phone_createGroupCall(); + req.peer = MessagesController.getInputPeer(chat); + req.random_id = Utilities.random.nextInt(); + req.schedule_date = scheduleStartAt; + req.flags |= 2; + account.getConnectionsManager().sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.Updates updates = (TLRPC.Updates) response; + for (int a = 0; a < updates.updates.size(); a++) { + TLRPC.Update update = updates.updates.get(a); + if (update instanceof TLRPC.TL_updateGroupCall) { + TLRPC.TL_updateGroupCall updateGroupCall = (TLRPC.TL_updateGroupCall) update; + AndroidUtilities.runOnUIThread(() -> { + call = new ChatObject.Call(); + call.call = new TLRPC.TL_groupCall(); + call.call.participants_count = 0; + call.call.version = 1; + call.call.can_change_join_muted = true; + call.chatId = chat.id; + call.call.schedule_date = scheduleStartAt; + call.call.flags |= 128; + call.currentAccount = accountInstance; + call.setSelfPeer(peer); + call.call.access_hash = updateGroupCall.call.access_hash; + call.call.id = updateGroupCall.call.id; + accountInstance.getMessagesController().putGroupCall(call.chatId, call); + }); + break; + } + } + accountInstance.getMessagesController().processUpdates(updates, false); + } else { + AndroidUtilities.runOnUIThread(() -> { + accountInstance.getNotificationCenter().postNotificationName(NotificationCenter.needShowAlert, 6, error.text); + dismiss(); + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + }); + + scheduleTimerContainer = new LinearLayout(context) { + + boolean ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + int count = 5; + dayPicker.setItemCount(count); + hourPicker.setItemCount(count); + minutePicker.setItemCount(count); + dayPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; + hourPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; + minutePicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; + ignoreLayout = false; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + scheduleTimerContainer.setWeightSum(1.0f); + scheduleTimerContainer.setOrientation(LinearLayout.HORIZONTAL); + containerView.addView(scheduleTimerContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 54 * 5, Gravity.TOP | Gravity.LEFT, 0, 50, 0, 0)); + + long currentTime = System.currentTimeMillis(); + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(currentTime); + int currentYear = calendar.get(Calendar.YEAR); + int currentDay = calendar.get(Calendar.DAY_OF_YEAR); + + scheduleTimerContainer.addView(dayPicker, LayoutHelper.createLinear(0, 54 * 5, 0.5f)); + dayPicker.setMinValue(0); + dayPicker.setMaxValue(365); + dayPicker.setWrapSelectorWheel(false); + dayPicker.setFormatter(value -> { + if (value == 0) { + return LocaleController.getString("MessageScheduleToday", R.string.MessageScheduleToday); + } else { + long date = currentTime + (long) value * 86400000L; + calendar.setTimeInMillis(date); + int year = calendar.get(Calendar.YEAR); + if (year == currentYear) { + return LocaleController.getInstance().formatterScheduleDay.format(date); + } else { + return LocaleController.getInstance().formatterScheduleYear.format(date); + } + } + }); + final NumberPicker.OnValueChangeListener onValueChangeListener = (picker, oldVal, newVal) -> { + try { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + + } + AlertsCreator.checkScheduleDate(scheduleButtonTextView, scheduleInfoTextView, 7 * 24 * 60 * 60, 2, dayPicker, hourPicker, minutePicker); + }; + dayPicker.setOnValueChangedListener(onValueChangeListener); + + hourPicker.setMinValue(0); + hourPicker.setMaxValue(23); + scheduleTimerContainer.addView(hourPicker, LayoutHelper.createLinear(0, 54 * 5, 0.2f)); + hourPicker.setFormatter(value -> String.format("%02d", value)); + hourPicker.setOnValueChangedListener(onValueChangeListener); + + minutePicker.setMinValue(0); + minutePicker.setMaxValue(59); + minutePicker.setValue(0); + minutePicker.setFormatter(value -> String.format("%02d", value)); + scheduleTimerContainer.addView(minutePicker, LayoutHelper.createLinear(0, 54 * 5, 0.3f)); + minutePicker.setOnValueChangedListener(onValueChangeListener); + + calendar.setTimeInMillis(currentTime + 3 * 60 * 60 * 1000); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + int nextDay = calendar.get(Calendar.DAY_OF_YEAR); + int minute = calendar.get(Calendar.MINUTE); + int hour = calendar.get(Calendar.HOUR_OF_DAY); + dayPicker.setValue(currentDay != nextDay ? 1 : 0); + minutePicker.setValue(minute); + hourPicker.setValue(hour); + + AlertsCreator.checkScheduleDate(scheduleButtonTextView, scheduleInfoTextView, 7 * 24 * 60 * 60, 2, dayPicker, hourPicker, minutePicker); + } + int color = Theme.getColor(Theme.key_voipgroup_unmuteButton2); int r = Color.red(color); int g = Color.green(color); @@ -2083,6 +2884,10 @@ protected void dispatchDraw(Canvas canvas) { soundButton.setTextSize(12); buttonsContainer.addView(soundButton, LayoutHelper.createFrame(68, 90)); soundButton.setOnClickListener(v -> { + if (call == null || call.isScheduled()) { + getLink(false); + return; + } if (VoIPService.getSharedInstance() == null) { return; } @@ -2095,6 +2900,10 @@ protected void dispatchDraw(Canvas canvas) { leaveButton.setData(R.drawable.calls_decline, 0xffffffff, Theme.getColor(Theme.key_voipgroup_leaveButton), 0.3f, false, LocaleController.getString("VoipGroupLeave", R.string.VoipGroupLeave), false, false); buttonsContainer.addView(leaveButton, LayoutHelper.createFrame(68, 80)); leaveButton.setOnClickListener(v -> { + if (call == null || call.isScheduled()) { + dismiss(); + return; + } updateItems(); onLeaveClick(context, this::dismiss, false); }); @@ -2103,7 +2912,7 @@ protected void dispatchDraw(Canvas canvas) { @Override public boolean onTouchEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN && muteButtonState == MUTE_BUTTON_STATE_UNMUTE) { + if (event.getAction() == MotionEvent.ACTION_DOWN && muteButtonState == MUTE_BUTTON_STATE_UNMUTE && call != null) { AndroidUtilities.runOnUIThread(pressRunnable, 300); scheduled = true; } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { @@ -2154,306 +2963,123 @@ public void run() { @Override public void onClick(View v) { - if (VoIPService.getSharedInstance() == null || muteButtonState == MUTE_BUTTON_STATE_CONNECTING) { + if (call == null || muteButtonState == MUTE_BUTTON_STATE_CONNECTING) { return; } - if (muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND) { - if (playingHandAnimation) { + if (muteButtonState == MUTE_BUTTON_STATE_START_NOW) { + if (startingGroupCall) { return; } - playingHandAnimation = true; - AndroidUtilities.shakeView(muteLabel[0], 2, 0); - AndroidUtilities.shakeView(muteSubLabel[0], 2, 0); v.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - int num = Utilities.random.nextInt(100); - int endFrame; - int startFrame; - if (num < 32) { - startFrame = 0; - endFrame = 120; - } else if (num < 64) { - startFrame = 120; - endFrame = 240; - } else if (num < 97) { - startFrame = 240; - endFrame = 420; - } else if (num == 98) { - startFrame = 420; - endFrame = 540; - } else { - startFrame = 540; - endFrame = 720; - } - handDrawables.setCustomEndFrame(endFrame); - handDrawables.setOnFinishCallback(finishRunnable, endFrame - 1); - muteButton.setAnimation(handDrawables); - handDrawables.setCurrentFrame(startFrame); - muteButton.playAnimation(); - if (muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN) { - TLRPC.TL_groupCallParticipant participant = call.participants.get(MessageObject.getPeerId(selfPeer)); - TLObject object; - int peerId = MessageObject.getPeerId(participant.peer); - if (peerId > 0) { - object = accountInstance.getMessagesController().getUser(peerId); - } else { - object = accountInstance.getMessagesController().getChat(-peerId); - } - VoIPService.getSharedInstance().editCallMember(object, true, -1, true); - updateMuteButton(MUTE_BUTTON_STATE_RAISED_HAND, true); - } - } else if (muteButtonState == MUTE_BUTTON_STATE_UNMUTE) { - updateMuteButton(MUTE_BUTTON_STATE_MUTE, true); - VoIPService.getSharedInstance().setMicMute(false, false, true); - muteButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } else { - updateMuteButton(MUTE_BUTTON_STATE_UNMUTE, true); - VoIPService.getSharedInstance().setMicMute(true, false, true); - muteButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } - } - }); - - radialProgressView = new RadialProgressView(context); - radialProgressView.setSize(AndroidUtilities.dp(110)); - radialProgressView.setStrokeWidth(4); - radialProgressView.setProgressColor(Theme.getColor(Theme.key_voipgroup_connectingProgress)); - //buttonsContainer.addView(radialProgressView, LayoutHelper.createFrame(126, 126, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); - - for (int a = 0; a < 2; a++) { - muteLabel[a] = new TextView(context); - muteLabel[a].setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); - muteLabel[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - muteLabel[a].setGravity(Gravity.CENTER_HORIZONTAL); - buttonsContainer.addView(muteLabel[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 26)); - - muteSubLabel[a] = new TextView(context); - muteSubLabel[a].setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); - muteSubLabel[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); - muteSubLabel[a].setGravity(Gravity.CENTER_HORIZONTAL); - buttonsContainer.addView(muteSubLabel[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 10)); - if (a == 1) { - muteLabel[a].setVisibility(View.INVISIBLE); - muteSubLabel[a].setVisibility(View.INVISIBLE); - } - } - - actionBar = new ActionBar(context) { - @Override - public void setAlpha(float alpha) { - super.setAlpha(alpha); - containerView.invalidate(); - } - }; - actionBar.setBackButtonImage(R.drawable.ic_ab_back); - actionBar.setOccupyStatusBar(false); - actionBar.setAllowOverlayTitle(false); - actionBar.setItemsColor(Theme.getColor(Theme.key_voipgroup_actionBarItems), false); - actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), false); - actionBar.setTitleColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); - actionBar.setSubtitleColor(Theme.getColor(Theme.key_voipgroup_lastSeenTextUnscrolled)); - actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { - @Override - public void onItemClick(int id) { - if (id == -1) { - dismiss(); - } else if (id == eveyone_can_speak_item) { - call.call.join_muted = false; - toggleAdminSpeak(); - } else if (id == admin_can_speak_item) { - call.call.join_muted = true; - toggleAdminSpeak(); - } else if (id == share_invite_link_item) { - getLink(false); - } else if (id == leave_item) { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - - builder.setTitle(LocaleController.getString("VoipGroupEndAlertTitle", R.string.VoipGroupEndAlertTitle)); - builder.setMessage(LocaleController.getString("VoipGroupEndAlertText", R.string.VoipGroupEndAlertText)); - - builder.setPositiveButton(LocaleController.getString("VoipGroupEnd", R.string.VoipGroupEnd), (dialogInterface, i) -> { - if (VoIPService.getSharedInstance() != null) { - VoIPService.getSharedInstance().hangUp(1); + startingGroupCall = true; + TLRPC.TL_phone_startScheduledGroupCall req = new TLRPC.TL_phone_startScheduledGroupCall(); + req.call = call.getInputGroupCall(); + accountInstance.getConnectionsManager().sendRequest(req, (response, error) -> { + if (response != null) { + accountInstance.getMessagesController().processUpdates((TLRPC.Updates) response, false); } - dismiss(); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didStartedCall); }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - AlertDialog dialog = builder.create(); - - dialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_dialogBackground)); - dialog.show(); - TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); - if (button != null) { - button.setTextColor(Theme.getColor(Theme.key_voipgroup_leaveCallMenu)); - } - dialog.setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); - } else if (id == start_record_item) { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - - EditTextBoldCursor editText; - if (call.recording) { - builder.setTitle(LocaleController.getString("VoipGroupStopRecordingTitle", R.string.VoipGroupStopRecordingTitle)); - builder.setMessage(LocaleController.getString("VoipGroupStopRecordingText", R.string.VoipGroupStopRecordingText)); - editText = null; - } else { - enterEventSent = false; - builder.setTitle(LocaleController.getString("VoipGroupStartRecordingTitle", R.string.VoipGroupStartRecordingTitle)); - builder.setMessage(LocaleController.getString("VoipGroupStartRecordingText", R.string.VoipGroupStartRecordingText)); - builder.setCheckFocusable(false); - - editText = new EditTextBoldCursor(getContext()); - editText.setBackgroundDrawable(Theme.createEditTextDrawable(getContext(), true)); - - LinearLayout linearLayout = new LinearLayout(getContext()); - linearLayout.setOrientation(LinearLayout.VERTICAL); - builder.setView(linearLayout); - - editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - editText.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); - editText.setMaxLines(1); - editText.setLines(1); - editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); - editText.setGravity(Gravity.LEFT | Gravity.TOP); - editText.setSingleLine(true); - editText.setHint(LocaleController.getString("VoipGroupSaveFileHint", R.string.VoipGroupSaveFileHint)); - editText.setImeOptions(EditorInfo.IME_ACTION_DONE); - editText.setHintTextColor(Theme.getColor(Theme.key_voipgroup_lastSeenText)); - editText.setCursorColor(Theme.getColor(Theme.key_voipgroup_nameText)); - editText.setCursorSize(AndroidUtilities.dp(20)); - editText.setCursorWidth(1.5f); - editText.setPadding(0, AndroidUtilities.dp(4), 0, 0); - linearLayout.addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.LEFT, 24, 0, 24, 12)); - editText.setOnEditorActionListener((textView, i2, keyEvent) -> { - AndroidUtilities.hideKeyboard(textView); - builder.create().getButton(AlertDialog.BUTTON_POSITIVE).callOnClick(); - return false; - }); - - final AlertDialog alertDialog = builder.create(); - alertDialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_inviteMembersBackground)); - alertDialog.setOnShowListener(dialog -> makeFocusable(null, alertDialog, editText, true)); - alertDialog.setOnDismissListener(dialog -> AndroidUtilities.hideKeyboard(editText)); + } else if (muteButtonState == MUTE_BUTTON_STATE_CANCEL_REMINDER || muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) { + if (muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) { + if (reminderHintView != null) { + reminderHintView.hide(); + } } - - builder.setPositiveButton(call.recording ? LocaleController.getString("Stop", R.string.Stop) : LocaleController.getString("Start", R.string.Start), (dialogInterface, i) -> { - if (editText == null) { - call.toggleRecord(null); - getUndoView().showWithAction(0, UndoView.ACTION_VOIP_RECORDING_FINISHED, null); - } else { - call.toggleRecord(editText.getText().toString()); - AndroidUtilities.hideKeyboard(editText); - getUndoView().showWithAction(0, UndoView.ACTION_VOIP_RECORDING_STARTED, null); - if (VoIPService.getSharedInstance() != null) { - VoIPService.getSharedInstance().playStartRecordSound(); - } + TLRPC.TL_phone_toggleGroupCallStartSubscription req = new TLRPC.TL_phone_toggleGroupCallStartSubscription(); + req.call = call.getInputGroupCall(); + call.call.schedule_start_subscribed = !call.call.schedule_start_subscribed; + req.subscribed = call.call.schedule_start_subscribed; + accountInstance.getConnectionsManager().sendRequest(req, (response, error) -> { + if (response != null) { + accountInstance.getMessagesController().processUpdates((TLRPC.Updates) response, false); } }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> AndroidUtilities.hideKeyboard(editText)); - AlertDialog dialog = builder.create(); - dialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_dialogBackground)); - dialog.show(); - dialog.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); - if (editText != null) { - editText.requestFocus(); + updateMuteButton(call.call.schedule_start_subscribed ? MUTE_BUTTON_STATE_CANCEL_REMINDER : MUTE_BUTTON_STATE_SET_REMINDER, true); + } else { + if (VoIPService.getSharedInstance() == null || isStillConnecting()) { + return; } - } else if (id == permission_item) { - changingPermissions = true; - everyoneItem.setVisibility(View.VISIBLE); - adminItem.setVisibility(View.VISIBLE); - - accountGap.setVisibility(View.GONE); - inviteItem.setVisibility(View.GONE); - leaveItem.setVisibility(View.GONE); - permissionItem.setVisibility(View.GONE); - editTitleItem.setVisibility(View.GONE); - recordItem.setVisibility(View.GONE); - accountSelectCell.setVisibility(View.GONE); - otherItem.forceUpdatePopupPosition(); - } else if (id == edit_item) { - enterEventSent = false; - final EditTextBoldCursor editText = new EditTextBoldCursor(getContext()); - editText.setBackgroundDrawable(Theme.createEditTextDrawable(getContext(), true)); - - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(LocaleController.getString("VoipGroupTitle", R.string.VoipGroupTitle)); - builder.setCheckFocusable(false); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> AndroidUtilities.hideKeyboard(editText)); - - LinearLayout linearLayout = new LinearLayout(getContext()); - linearLayout.setOrientation(LinearLayout.VERTICAL); - builder.setView(linearLayout); - - editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - editText.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); - editText.setMaxLines(1); - editText.setLines(1); - editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); - editText.setGravity(Gravity.LEFT | Gravity.TOP); - editText.setSingleLine(true); - editText.setImeOptions(EditorInfo.IME_ACTION_DONE); - editText.setHint(currentChat.title); - editText.setHintTextColor(Theme.getColor(Theme.key_voipgroup_lastSeenText)); - editText.setCursorColor(Theme.getColor(Theme.key_voipgroup_nameText)); - editText.setCursorSize(AndroidUtilities.dp(20)); - editText.setCursorWidth(1.5f); - editText.setPadding(0, AndroidUtilities.dp(4), 0, 0); - linearLayout.addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.LEFT, 24, 6, 24, 0)); - editText.setOnEditorActionListener((textView, i, keyEvent) -> { - AndroidUtilities.hideKeyboard(textView); - builder.create().getButton(AlertDialog.BUTTON_POSITIVE).callOnClick(); - return false; - }); - editText.addTextChangedListener(new TextWatcher() { - - boolean ignoreTextChange; - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - + if (muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND) { + if (playingHandAnimation) { + return; } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - + playingHandAnimation = true; + AndroidUtilities.shakeView(muteLabel[0], 2, 0); + AndroidUtilities.shakeView(muteSubLabel[0], 2, 0); + v.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + int num = Utilities.random.nextInt(100); + int endFrame; + int startFrame; + if (num < 32) { + startFrame = 0; + endFrame = 120; + } else if (num < 64) { + startFrame = 120; + endFrame = 240; + } else if (num < 97) { + startFrame = 240; + endFrame = 420; + } else if (num == 98) { + startFrame = 420; + endFrame = 540; + } else { + startFrame = 540; + endFrame = 720; } - - @Override - public void afterTextChanged(Editable s) { - if (ignoreTextChange) { - return; - } - if (s.length() > 40) { - ignoreTextChange = true; - s.delete(40, s.length()); - AndroidUtilities.shakeView(editText, 2, 0); - editText.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - ignoreTextChange = false; + handDrawables.setCustomEndFrame(endFrame); + handDrawables.setOnFinishCallback(finishRunnable, endFrame - 1); + muteButton.setAnimation(handDrawables); + handDrawables.setCurrentFrame(startFrame); + muteButton.playAnimation(); + if (muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN) { + TLRPC.TL_groupCallParticipant participant = call.participants.get(MessageObject.getPeerId(selfPeer)); + TLObject object; + int peerId = MessageObject.getPeerId(participant.peer); + if (peerId > 0) { + object = accountInstance.getMessagesController().getUser(peerId); + } else { + object = accountInstance.getMessagesController().getChat(-peerId); } + VoIPService.getSharedInstance().editCallMember(object, true, -1, true); + updateMuteButton(MUTE_BUTTON_STATE_RAISED_HAND, true); } - }); - if (!TextUtils.isEmpty(call.call.title)) { - editText.setText(call.call.title); - editText.setSelection(editText.length()); - } - builder.setPositiveButton(LocaleController.getString("Save", R.string.Save), (dialog, which) -> { - AndroidUtilities.hideKeyboard(editText); - call.setTitle(editText.getText().toString()); - builder.getDismissRunnable().run(); - }); - - final AlertDialog alertDialog = builder.create(); - alertDialog.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_inviteMembersBackground)); - alertDialog.setOnShowListener(dialog -> makeFocusable(null, alertDialog, editText, true)); - alertDialog.setOnDismissListener(dialog -> AndroidUtilities.hideKeyboard(editText)); - alertDialog.show(); - alertDialog.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); - editText.requestFocus(); - } else if (id == user_item) { - accountSwitchImageView.callOnClick(); + } else if (muteButtonState == MUTE_BUTTON_STATE_UNMUTE) { + updateMuteButton(MUTE_BUTTON_STATE_MUTE, true); + VoIPService.getSharedInstance().setMicMute(false, false, true); + muteButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } else { + updateMuteButton(MUTE_BUTTON_STATE_UNMUTE, true); + VoIPService.getSharedInstance().setMicMute(true, false, true); + muteButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } } } }); + radialProgressView = new RadialProgressView(context); + radialProgressView.setSize(AndroidUtilities.dp(110)); + radialProgressView.setStrokeWidth(4); + radialProgressView.setProgressColor(Theme.getColor(Theme.key_voipgroup_connectingProgress)); + //buttonsContainer.addView(radialProgressView, LayoutHelper.createFrame(126, 126, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); + + for (int a = 0; a < 2; a++) { + muteLabel[a] = new TextView(context); + muteLabel[a].setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); + muteLabel[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + muteLabel[a].setGravity(Gravity.CENTER_HORIZONTAL); + buttonsContainer.addView(muteLabel[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 26)); + + muteSubLabel[a] = new TextView(context); + muteSubLabel[a].setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); + muteSubLabel[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + muteSubLabel[a].setGravity(Gravity.CENTER_HORIZONTAL); + buttonsContainer.addView(muteSubLabel[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 10)); + if (a == 1) { + muteLabel[a].setVisibility(View.INVISIBLE); + muteSubLabel[a].setVisibility(View.INVISIBLE); + } + } + actionBar.setAlpha(0.0f); actionBar.getBackButton().setScaleX(0.9f); actionBar.getBackButton().setScaleY(0.9f); @@ -2466,18 +3092,54 @@ public void afterTextChanged(Editable s) { accountSwitchAvatarDrawable.setTextSize(AndroidUtilities.dp(12)); accountSwitchImageView = new BackupImageView(context); accountSwitchImageView.setRoundRadius(AndroidUtilities.dp(16)); - accountSwitchImageView.setOnClickListener(v -> JoinCallAlert.open(getContext(), -chat.id, accountInstance, null, JoinCallAlert.TYPE_DISPLAY, (peer1, hasFewPeers) -> { - if (VoIPService.getSharedInstance() == null || !hasFewPeers) { + accountSwitchImageView.setOnClickListener(v -> JoinCallAlert.open(getContext(), -currentChat.id, accountInstance, null, JoinCallAlert.TYPE_DISPLAY, selfPeer, (peer1, hasFewPeers, schedule) -> { + if (call == null) { return; } - TLRPC.TL_groupCallParticipant participant = call.participants.get(MessageObject.getPeerId(selfPeer)); - VoIPService.getSharedInstance().setGroupCallPeer(peer1); + TLObject object; if (peer1 instanceof TLRPC.TL_inputPeerUser) { - userSwitchObject = accountInstance.getMessagesController().getUser(peer1.user_id); + object = accountInstance.getMessagesController().getUser(peer1.user_id); } else if (peer1 instanceof TLRPC.TL_inputPeerChat) { - userSwitchObject = accountInstance.getMessagesController().getChat(peer1.chat_id); + object = accountInstance.getMessagesController().getChat(peer1.chat_id); + } else { + object = accountInstance.getMessagesController().getChat(peer1.channel_id); + } + if (call.isScheduled()) { + getUndoView().showWithAction(0, UndoView.ACTION_VOIP_USER_CHANGED, object); + if (peer1 instanceof TLRPC.TL_inputPeerChannel) { + selfPeer = new TLRPC.TL_peerChannel(); + selfPeer.channel_id = peer1.channel_id; + } else if (peer1 instanceof TLRPC.TL_inputPeerUser) { + selfPeer = new TLRPC.TL_peerUser(); + selfPeer.user_id = peer1.user_id; + } else if (peer1 instanceof TLRPC.TL_inputPeerChat) { + selfPeer = new TLRPC.TL_peerChat(); + selfPeer.chat_id = peer1.chat_id; + } + this.schedulePeer = peer1; + TLRPC.ChatFull chatFull = accountInstance.getMessagesController().getChatFull(currentChat.id); + if (chatFull != null) { + chatFull.groupcall_default_join_as = selfPeer; + if (chatFull instanceof TLRPC.TL_chatFull) { + chatFull.flags |= 32768; + } else { + chatFull.flags |= 67108864; + } + } + TLRPC.TL_phone_saveDefaultGroupCallJoinAs req = new TLRPC.TL_phone_saveDefaultGroupCallJoinAs(); + req.peer = MessagesController.getInputPeer(currentChat); + req.join_as = peer1; + accountInstance.getConnectionsManager().sendRequest(req, (response, error) -> { + + }); + updateItems(); } else { - userSwitchObject = accountInstance.getMessagesController().getChat(peer1.channel_id); + if (VoIPService.getSharedInstance() == null || !hasFewPeers) { + return; + } + TLRPC.TL_groupCallParticipant participant = call.participants.get(MessageObject.getPeerId(selfPeer)); + VoIPService.getSharedInstance().setGroupCallPeer(peer1); + userSwitchObject = object; } })); @@ -2489,6 +3151,9 @@ public void afterTextChanged(Editable s) { otherItem.setDelegate(id -> actionBar.getActionBarMenuOnItemClick().onItemClick(id)); otherItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_voipgroup_actionBarItemsSelector), 6)); otherItem.setOnClickListener(v -> { + if (call == null) { + return; + } if (call.call.join_muted) { everyoneItem.setColors(Theme.getColor(Theme.key_voipgroup_actionBarItems), Theme.getColor(Theme.key_voipgroup_actionBarItems)); everyoneItem.setChecked(false); @@ -2534,7 +3199,7 @@ protected TextView createTextView() { textView.setSingleLine(true); textView.setEllipsize(TextUtils.TruncateAt.END); textView.setOnClickListener(v -> { - if (call.recording) { + if (call != null && call.recording) { showRecordHint(textView); } }); @@ -2606,31 +3271,38 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { permissionItem.setColors(Theme.getColor(Theme.key_voipgroup_actionBarItems), Theme.getColor(Theme.key_voipgroup_actionBarItems)); recordItem.setColors(Theme.getColor(Theme.key_voipgroup_actionBarItems), Theme.getColor(Theme.key_voipgroup_actionBarItems)); + if (call != null) { + initCreatedGroupCall(); + } + listAdapter.notifyDataSetChanged(); oldCount = listAdapter.getItemCount(); - actionBar.setSubtitle(LocaleController.formatPluralString("Participants", call.call.participants_count + (listAdapter.addSelfToCounter() ? 1 : 0))); - actionBar.setTitleRightMargin(AndroidUtilities.dp(48) * 2); - - call.saveActiveDates(); - VoIPService.getSharedInstance().registerStateListener(this); updateItems(); updateSpeakerPhoneIcon(false); updateState(false, false); + updateScheduleUI(false); setColorProgress(0.0f); leaveBackgroundPaint.setColor(Theme.getColor(Theme.key_voipgroup_leaveButton)); updateTitle(false); actionBar.getTitleTextView().setOnClickListener(v -> { - if (call.recording) { + if (call != null && call.recording) { showRecordHint(actionBar.getTitleTextView()); } }); avatarPagerIndicator = new AvatarPreviewPagerIndicator(context); - avatarsViewPager = new ProfileGalleryView(context, actionBar, listView, avatarPagerIndicator); + avatarsViewPager = new ProfileGalleryView(context, actionBar, listView, avatarPagerIndicator) { + @Override + public void invalidate() { + super.invalidate(); + containerView.invalidate(); + } + }; + avatarsViewPager.setInvalidateWithParent(true); avatarPagerIndicator.setProfileGalleryView(avatarsViewPager); avatarPreviewContainer = new FrameLayout(context) { @@ -2661,8 +3333,8 @@ protected void dispatchDraw(Canvas canvas) { scrimView.getAvatarImageView().setRoundRadius(scrimView.getAvatarImageView().getMeasuredHeight() / 2); canvas.restore(); } - avatarsViewPager.setAlpha(progressToAvatarPreview); } + avatarsViewPager.setAlpha(progressToAvatarPreview); path.reset(); rectF.set(0, 0, getMeasuredHeight(), getMeasuredWidth()); @@ -2672,6 +3344,12 @@ protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); canvas.restore(); } + + @Override + public void invalidate() { + super.invalidate(); + containerView.invalidate(); + } }; avatarPreviewContainer.setVisibility(View.GONE); @@ -2695,12 +3373,193 @@ public void onPageScrollStateChanged(int state) { } }); - blurredView = new View(context); + blurredView = new View(context) { + @Override + public void setAlpha(float alpha) { + if (getAlpha() != alpha) { + super.setAlpha(alpha); + checkContentOverlayed(); + } + } + }; containerView.addView(blurredView); avatarPreviewContainer.addView(avatarsViewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); avatarPreviewContainer.addView(avatarPagerIndicator, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 0, 0, 0, 0)); containerView.addView(avatarPreviewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 14, 14, 14, 14)); + + ViewGroup decorView; + if (Build.VERSION.SDK_INT >= 21) { + decorView = (ViewGroup) getWindow().getDecorView(); + } else { + decorView = containerView; + } + pinchToZoomHelper = new PinchToZoomHelper(decorView) { + @Override + protected void invalidateViews() { + super.invalidateViews(); + for (int i = 0; i < avatarsViewPager.getChildCount(); i++) { + avatarsViewPager.getChildAt(i).invalidate(); + } + } + + @Override + protected void drawOverlays(Canvas canvas, float alpha, float parentOffsetX, float parentOffsetY, float clipTop, float clipBottom) { + if (alpha > 0) { + float x = avatarPreviewContainer.getX() + containerView.getX(); + float y = avatarPreviewContainer.getY() + containerView.getY(); + AndroidUtilities.rectTmp.set(x, y, x + avatarsViewPager.getMeasuredWidth(), y + avatarsViewPager.getMeasuredHeight()); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (255 * alpha), Canvas.ALL_SAVE_FLAG); + + canvas.translate(x, y); + avatarPreviewContainer.draw(canvas); + + canvas.restore(); + } + } + }; + pinchToZoomHelper.setCallback(new PinchToZoomHelper.Callback() { + + @Override + public void onZoomStarted(MessageObject messageObject) { + listView.cancelClickRunnables(true); + pinchToZoomHelper.getPhotoImage().setRoundRadius(AndroidUtilities.dp(13), AndroidUtilities.dp(13), 0, 0); + containerView.invalidate(); + } + + @Override + public void onZoomFinished(MessageObject messageObject) { + containerView.invalidate(); + } + }); + avatarsViewPager.setPinchToZoomHelper(pinchToZoomHelper); + } + + private void checkContentOverlayed() { + boolean overlayed = !avatarPriviewTransitionInProgress && blurredView.getVisibility() == View.VISIBLE && blurredView.getAlpha() == 1f;; + if (contentFullyOverlayed != overlayed) { + contentFullyOverlayed = overlayed; + buttonsContainer.invalidate(); + containerView.invalidate(); + listView.invalidate(); + } + }; + + private void updateScheduleUI(boolean animation) { + if ((scheduleTimerContainer == null || call != null) && scheduleAnimator == null) { + scheduleButtonsScale = 1.0f; + switchToButtonInt2 = 1.0f; + switchToButtonProgress = 1.0f; + if (scheduleTimerContainer == null) { + return; + } + } + if (!animation) { + AndroidUtilities.cancelRunOnUIThread(updateSchedeulRunnable); + updateSchedeulRunnable.run(); + if (call == null || call.isScheduled()) { + listView.setVisibility(View.INVISIBLE); + } else { + listView.setVisibility(View.VISIBLE); + } + leaveItem.setText(LocaleController.getString("VoipGroupCancelChat", R.string.VoipGroupCancelChat)); + } + float scheduleButtonsScale2; + float alpha; + if (switchToButtonProgress > 0.6f) { + scheduleButtonsScale = scheduleButtonsScale2 = 1.05f - CubicBezierInterpolator.DEFAULT.getInterpolation((switchToButtonProgress - 0.6f) / 0.4f) * 0.05f; + switchToButtonInt2 = 1.0f; + alpha = 1.0f; + } else { + scheduleButtonsScale = 1.0f + CubicBezierInterpolator.DEFAULT.getInterpolation(switchToButtonProgress / 0.6f) * 0.05f; + switchToButtonInt2 = CubicBezierInterpolator.DEFAULT.getInterpolation(switchToButtonProgress / 0.6f); + scheduleButtonsScale2 = 1.05f * CubicBezierInterpolator.DEFAULT.getInterpolation(switchToButtonProgress / 0.6f); + alpha = switchToButtonProgress / 0.6f; + } + + float reversedAlpha = 1.0f - alpha; + leaveButton.setAlpha(alpha); + soundButton.setAlpha(alpha * (soundButton.isEnabled() ? 1.0f : 0.5f)); + muteButton.setAlpha(alpha); + scheduleTimerContainer.setAlpha(reversedAlpha); + scheduleStartInTextView.setAlpha(alpha); + scheduleStartAtTextView.setAlpha(alpha); + scheduleTimeTextView.setAlpha(alpha); + muteLabel[0].setAlpha(alpha); + muteSubLabel[0].setAlpha(alpha); + scheduleTimeTextView.setScaleX(scheduleButtonsScale2); + scheduleTimeTextView.setScaleY(scheduleButtonsScale2); + leaveButton.setScaleX(scheduleButtonsScale2); + leaveButton.setScaleY(scheduleButtonsScale2); + soundButton.setScaleX(scheduleButtonsScale2); + soundButton.setScaleY(scheduleButtonsScale2); + muteButton.setScaleX(scheduleButtonsScale2); + muteButton.setScaleY(scheduleButtonsScale2); + scheduleButtonTextView.setScaleX(reversedAlpha); + scheduleButtonTextView.setScaleY(reversedAlpha); + scheduleButtonTextView.setAlpha(reversedAlpha); + scheduleInfoTextView.setAlpha(reversedAlpha); + otherItem.setAlpha(alpha); + int newVisibility = reversedAlpha == 0.0f ? View.INVISIBLE : View.VISIBLE; + if (newVisibility != scheduleTimerContainer.getVisibility()) { + scheduleTimerContainer.setVisibility(newVisibility); + scheduleButtonTextView.setVisibility(newVisibility); + } + } + + private void initCreatedGroupCall() { + if (callInitied) { + return; + } + VoIPService service = VoIPService.getSharedInstance(); + if (service == null) { + return; + } + callInitied = true; + oldParticipants.addAll(call.sortedParticipants); + oldInvited.addAll(call.invitedUsers); + currentCallState = service.getCallState(); + if (call == null) { + call = service.groupCall; + } + actionBar.setSubtitle(LocaleController.formatPluralString("Participants", call.call.participants_count + (listAdapter.addSelfToCounter() ? 1 : 0))); + actionBar.setTitleRightMargin(AndroidUtilities.dp(48) * 2); + call.saveActiveDates(); + VoIPService.getSharedInstance().registerStateListener(this); + if (scheduleTimeTextView != null && scheduleTimeTextView.getVisibility() == View.VISIBLE) { + leaveButton.setData(R.drawable.calls_decline, 0xffffffff, Theme.getColor(Theme.key_voipgroup_leaveButton), 0.3f, false, LocaleController.getString("VoipGroupLeave", R.string.VoipGroupLeave), false, true); + updateSpeakerPhoneIcon(true); + leaveItem.setText(LocaleController.getString("VoipGroupEndChat", R.string.VoipGroupEndChat)); + listView.setVisibility(View.VISIBLE); + pipItem.setVisibility(View.VISIBLE); + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(listView, View.ALPHA, 0.0f, 1.0f), + ObjectAnimator.ofFloat(listView, View.TRANSLATION_Y, AndroidUtilities.dp(200), 0.0f), + ObjectAnimator.ofFloat(scheduleTimeTextView, View.SCALE_X, 0.0f), + ObjectAnimator.ofFloat(scheduleTimeTextView, View.SCALE_Y, 0.0f), + ObjectAnimator.ofFloat(scheduleTimeTextView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(scheduleStartInTextView, View.SCALE_X, 0.0f), + ObjectAnimator.ofFloat(scheduleStartInTextView, View.SCALE_Y, 0.0f), + ObjectAnimator.ofFloat(scheduleStartInTextView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(scheduleStartAtTextView, View.SCALE_X, 0.0f), + ObjectAnimator.ofFloat(scheduleStartAtTextView, View.SCALE_Y, 0.0f), + ObjectAnimator.ofFloat(scheduleStartAtTextView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(pipItem, View.SCALE_X, 0.0f, 1.0f), + ObjectAnimator.ofFloat(pipItem, View.SCALE_Y, 0.0f, 1.0f), + ObjectAnimator.ofFloat(pipItem, View.ALPHA, 0.0f, 1.0f)); + animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + scheduleTimeTextView.setVisibility(View.INVISIBLE); + scheduleStartAtTextView.setVisibility(View.INVISIBLE); + scheduleStartInTextView.setVisibility(View.INVISIBLE); + } + }); + animatorSet.setDuration(300); + animatorSet.start(); + } } @Override @@ -2748,11 +3607,19 @@ private float getColorProgress() { } private void updateTitle(boolean animated) { + if (call == null) { + titleTextView.setText(LocaleController.getString("VoipGroupScheduleVoiceChat", R.string.VoipGroupScheduleVoiceChat), animated); + return; + } if (!TextUtils.isEmpty(call.call.title)) { if (!call.call.title.equals(actionBar.getTitle())) { if (animated) { actionBar.setTitleAnimated(call.call.title, true, 180); - actionBar.getTitleTextView().setOnClickListener(v -> showRecordHint(actionBar.getTitleTextView())); + actionBar.getTitleTextView().setOnClickListener(v -> { + if (call != null && call.recording) { + showRecordHint(actionBar.getTitleTextView()); + } + }); } else { actionBar.setTitle(call.call.title); } @@ -2762,7 +3629,11 @@ private void updateTitle(boolean animated) { if (!currentChat.title.equals(actionBar.getTitle())) { if (animated) { actionBar.setTitleAnimated(currentChat.title, true, 180); - actionBar.getTitleTextView().setOnClickListener(v -> showRecordHint(actionBar.getTitleTextView())); + actionBar.getTitleTextView().setOnClickListener(v -> { + if (call != null && call.recording) { + showRecordHint(actionBar.getTitleTextView()); + } + }); } else { actionBar.setTitle(currentChat.title); } @@ -2799,7 +3670,7 @@ private void setColorProgress(float progress) { listViewBackgroundPaint.setColor(color); listView.setGlowColor(color); - if (muteButtonState == MUTE_BUTTON_STATE_CONNECTING || muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND) { + if (muteButtonState == MUTE_BUTTON_STATE_CONNECTING || isGradientState(muteButtonState)) { muteButton.invalidate(); } @@ -2855,6 +3726,9 @@ private void getLink(boolean copy) { openShareAlert(true, null, url, copy); } } else { + if (call == null) { + return; + } for (int a = 0; a < 2; a++) { int num = a; TLRPC.TL_phone_exportGroupCallInvite req = new TLRPC.TL_phone_exportGroupCallInvite(); @@ -2877,7 +3751,11 @@ private void getLink(boolean copy) { if (ChatObject.canManageCalls(currentChat) && !call.call.join_muted) { invites[0] = null; } - openShareAlert(false, invites[0], invites[1], copy); + if (invites[0] == null && invites[1] == null && !TextUtils.isEmpty(currentChat.username)) { + openShareAlert(true, null, accountInstance.getMessagesController().linkPrefix + "/" + currentChat.username, copy); + } else { + openShareAlert(false, invites[0], invites[1], copy); + } })); } } @@ -2935,6 +3813,9 @@ public boolean didCopy() { } private void inviteUserToCall(int id, boolean shouldAdd) { + if (call == null) { + return; + } TLRPC.User user = accountInstance.getMessagesController().getUser(id); if (user == null) { return; @@ -2994,18 +3875,14 @@ private void inviteUserToCall(int id, boolean shouldAdd) { } private void updateLayout(boolean animated) { - if (listView.getChildCount() <= 0) { - listView.setTopGlowOffset((int) (scrollOffsetY = listView.getPaddingTop())); - containerView.invalidate(); - return; - } float minY = Integer.MAX_VALUE; - for (int a = 0, N = listView.getChildCount(); a < N; a++) { + int N = listView.getChildCount(); + for (int a = 0; a < N; a++) { View child = listView.getChildAt(a); minY = Math.min(minY, itemAnimator.getTargetY(child)); } if (minY < 0 || minY == Integer.MAX_VALUE) { - minY = 0; + minY = N != 0 ? 0 : listView.getPaddingTop(); } boolean show = minY <= ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(14); @@ -3083,6 +3960,9 @@ public void onAnimationEnd(Animator animation) { menuItemsContainer.setTranslationY(Math.max(AndroidUtilities.dp(4), scrollOffsetY - AndroidUtilities.dp(53) - diff)); titleTextView.setTranslationY(Math.max(AndroidUtilities.dp(4), scrollOffsetY - AndroidUtilities.dp(44) - diff)); + if (scheduleTimerContainer != null) { + scheduleTimerContainer.setTranslationY(Math.max(AndroidUtilities.dp(4), scrollOffsetY - AndroidUtilities.dp(44) - diff)); + } containerView.invalidate(); } } @@ -3101,11 +3981,23 @@ private void cancelMutePress() { } private void updateState(boolean animated, boolean selfUpdated) { + if (call == null || call.isScheduled()) { + int state; + if (ChatObject.canManageCalls(currentChat)) { + state = MUTE_BUTTON_STATE_START_NOW; + } else { + state = call.call.schedule_start_subscribed ? MUTE_BUTTON_STATE_CANCEL_REMINDER : MUTE_BUTTON_STATE_SET_REMINDER; + } + updateMuteButton(state, animated); + leaveButton.setData(R.drawable.calls_decline, 0xffffffff, Theme.getColor(Theme.key_voipgroup_leaveButton), 0.3f, false, LocaleController.getString("Close", R.string.Close), false, false); + updateScheduleUI(false); + return; + } VoIPService voIPService = VoIPService.getSharedInstance(); if (voIPService == null) { return; } - if (!voIPService.isSwitchingStream() && (currentCallState == VoIPService.STATE_WAIT_INIT || currentCallState == VoIPService.STATE_WAIT_INIT_ACK || currentCallState == VoIPService.STATE_CREATING || currentCallState == VoIPService.STATE_RECONNECTING)) { + if (!voIPService.isSwitchingStream() && (creatingServiceTime == 0 || Math.abs(SystemClock.elapsedRealtime() - creatingServiceTime) > 3000) && (currentCallState == VoIPService.STATE_WAIT_INIT || currentCallState == VoIPService.STATE_WAIT_INIT_ACK || currentCallState == VoIPService.STATE_CREATING || currentCallState == VoIPService.STATE_RECONNECTING)) { cancelMutePress(); updateMuteButton(MUTE_BUTTON_STATE_CONNECTING, animated); } else { @@ -3155,7 +4047,12 @@ private void updateSpeakerPhoneIcon(boolean animated) { } VoIPService service = VoIPService.getSharedInstance(); if (service == null) { + soundButton.setData(R.drawable.msg_voiceshare, Color.WHITE, 0, 0.3f, true, LocaleController.getString("VoipChatShare", R.string.VoipChatShare), false, animated); + soundButton.setEnabled(!TextUtils.isEmpty(currentChat.username) || ChatObject.hasAdminRights(currentChat) && ChatObject.canAddUsers(currentChat), false); + soundButton.setChecked(true, false); return; + } else { + soundButton.setEnabled(true, animated); } boolean bluetooth = service.isBluetoothOn() || service.isBluetoothWillOn(); @@ -3189,24 +4086,71 @@ private void updateMuteButton(int state, boolean animated) { boolean changed; boolean mutedByAdmin = false; - if (state == MUTE_BUTTON_STATE_UNMUTE) { + if (state == MUTE_BUTTON_STATE_CANCEL_REMINDER) { + newText = LocaleController.getString("VoipGroupCancelReminder", R.string.VoipGroupCancelReminder); + newSubtext = ""; + changed = bigMicDrawable.setCustomEndFrame(202); + } else if (state == MUTE_BUTTON_STATE_SET_REMINDER) { + newText = LocaleController.getString("VoipGroupSetReminder", R.string.VoipGroupSetReminder); + newSubtext = ""; + changed = bigMicDrawable.setCustomEndFrame(344); + } else if (state == MUTE_BUTTON_STATE_START_NOW) { + newText = LocaleController.getString("VoipGroupStartNow", R.string.VoipGroupStartNow); + newSubtext = ""; + changed = bigMicDrawable.setCustomEndFrame(377); + } else if (state == MUTE_BUTTON_STATE_UNMUTE) { newText = LocaleController.getString("VoipGroupUnmute", R.string.VoipGroupUnmute); newSubtext = LocaleController.getString("VoipHoldAndTalk", R.string.VoipHoldAndTalk); - changed = bigMicDrawable.setCustomEndFrame(muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN ? 21 : 64); + if (muteButtonState == MUTE_BUTTON_STATE_CONNECTING) { + int endFrame = bigMicDrawable.getCustomEndFrame(); + if (endFrame == 136 || endFrame == 173 || endFrame == 274 || endFrame == 311) { + changed = bigMicDrawable.setCustomEndFrame(99); + } else { + changed = false; + } + } else if (muteButtonState == MUTE_BUTTON_STATE_START_NOW) { + changed = bigMicDrawable.setCustomEndFrame(404); + } else if (muteButtonState == MUTE_BUTTON_STATE_CANCEL_REMINDER) { + changed = bigMicDrawable.setCustomEndFrame(376); + } else if (muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) { + changed = bigMicDrawable.setCustomEndFrame(237); + } else if (muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN) { + changed = bigMicDrawable.setCustomEndFrame(36); + } else { + changed = bigMicDrawable.setCustomEndFrame(99); + } } else if (state == MUTE_BUTTON_STATE_MUTE) { newText = LocaleController.getString("VoipTapToMute", R.string.VoipTapToMute); newSubtext = ""; - changed = bigMicDrawable.setCustomEndFrame(muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND ? 64 : 42); + changed = bigMicDrawable.setCustomEndFrame(muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND ? 99 : 69); } else if (state == MUTE_BUTTON_STATE_RAISED_HAND) { newText = LocaleController.getString("VoipMutedTapedForSpeak", R.string.VoipMutedTapedForSpeak); newSubtext = LocaleController.getString("VoipMutedTapedForSpeakInfo", R.string.VoipMutedTapedForSpeakInfo); - changed = bigMicDrawable.setCustomEndFrame(84); + changed = bigMicDrawable.setCustomEndFrame(136); } else { TLRPC.TL_groupCallParticipant participant = call.participants.get(MessageObject.getPeerId(selfPeer)); if (mutedByAdmin = participant != null && !participant.can_self_unmute && participant.muted && !ChatObject.canManageCalls(currentChat)) { - changed = bigMicDrawable.setCustomEndFrame(84); + if (muteButtonState == MUTE_BUTTON_STATE_CANCEL_REMINDER) { + changed = bigMicDrawable.setCustomEndFrame(311); + } else if (muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) { + changed = bigMicDrawable.setCustomEndFrame(274); + } else if (muteButtonState == MUTE_BUTTON_STATE_MUTE) { + changed = bigMicDrawable.setCustomEndFrame(173); + } else { + changed = bigMicDrawable.setCustomEndFrame(136); + } } else { - changed = bigMicDrawable.setCustomEndFrame(muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND ? 21 : 64); + if (muteButtonState == MUTE_BUTTON_STATE_START_NOW) { + changed = bigMicDrawable.setCustomEndFrame(404); + } else if (muteButtonState == MUTE_BUTTON_STATE_CANCEL_REMINDER) { + changed = bigMicDrawable.setCustomEndFrame(376); + } else if (muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) { + changed = bigMicDrawable.setCustomEndFrame(237); + } else if (muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND) { + changed = bigMicDrawable.setCustomEndFrame(36); + } else { + changed = bigMicDrawable.setCustomEndFrame(99); + } } if (state == MUTE_BUTTON_STATE_CONNECTING) { newText = LocaleController.getString("Connecting", R.string.Connecting); @@ -3227,17 +4171,51 @@ private void updateMuteButton(int state, boolean animated) { if (animated) { if (changed) { - if (state == MUTE_BUTTON_STATE_UNMUTE) { - bigMicDrawable.setCurrentFrame(muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN ? 0 : 42); + if (state == MUTE_BUTTON_STATE_START_NOW) { + bigMicDrawable.setCurrentFrame(376); + } else if (state == MUTE_BUTTON_STATE_CANCEL_REMINDER) { + bigMicDrawable.setCurrentFrame(173); + } else if (state == MUTE_BUTTON_STATE_SET_REMINDER) { + bigMicDrawable.setCurrentFrame(311); + } else if (state == MUTE_BUTTON_STATE_UNMUTE) { + if (muteButtonState == MUTE_BUTTON_STATE_START_NOW) { + bigMicDrawable.setCurrentFrame(376); + } else if (muteButtonState == MUTE_BUTTON_STATE_CANCEL_REMINDER) { + bigMicDrawable.setCurrentFrame(344); + } else if (muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) { + bigMicDrawable.setCurrentFrame(202); + } else if (muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN) { + bigMicDrawable.setCurrentFrame(0); + } else { + bigMicDrawable.setCurrentFrame(69); + } } else if (state == MUTE_BUTTON_STATE_MUTE) { - bigMicDrawable.setCurrentFrame(muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND ? 42 : 21); + bigMicDrawable.setCurrentFrame(muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND ? 69 : 36); } else if (state == MUTE_BUTTON_STATE_RAISED_HAND) { - bigMicDrawable.setCurrentFrame(63); + bigMicDrawable.setCurrentFrame(99); } else { if (mutedByAdmin) { - bigMicDrawable.setCurrentFrame(63); + if (muteButtonState == MUTE_BUTTON_STATE_CANCEL_REMINDER) { + bigMicDrawable.setCurrentFrame(274); + } else if (muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) { + bigMicDrawable.setCurrentFrame(237); + } else if (muteButtonState == MUTE_BUTTON_STATE_MUTE) { + bigMicDrawable.setCurrentFrame(136); + } else { + bigMicDrawable.setCurrentFrame(99); + } } else { - bigMicDrawable.setCurrentFrame(muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND ? 0 : 42); + if (muteButtonState == MUTE_BUTTON_STATE_START_NOW) { + bigMicDrawable.setCurrentFrame(376); + } else if (muteButtonState == MUTE_BUTTON_STATE_CANCEL_REMINDER) { + bigMicDrawable.setCurrentFrame(344); + } else if (muteButtonState == MUTE_BUTTON_STATE_SET_REMINDER) { + bigMicDrawable.setCurrentFrame(202); + } else if (muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND) { + bigMicDrawable.setCurrentFrame(0); + } else { + bigMicDrawable.setCurrentFrame(69); + } } } } @@ -3302,7 +4280,7 @@ private void fillColors(int state, int[] colorsToSet) { colorsToSet[0] = Theme.getColor(Theme.key_voipgroup_muteButton2); colorsToSet[1] = AndroidUtilities.getOffsetColor(Theme.getColor(Theme.key_voipgroup_soundButtonActive2), Theme.getColor(Theme.key_voipgroup_soundButtonActive2Scrolled), colorProgress, 1.0f); colorsToSet[2] = Theme.getColor(Theme.key_voipgroup_soundButton2); - } else if (state == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || state == MUTE_BUTTON_STATE_RAISED_HAND) { + } else if (isGradientState(state)) { colorsToSet[0] = Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient3); colorsToSet[1] = Theme.getColor(Theme.key_voipgroup_mutedByAdminMuteButton); colorsToSet[2] = Theme.getColor(Theme.key_voipgroup_mutedByAdminMuteButtonDisabled); @@ -3327,6 +4305,25 @@ private void showRecordHint(View view) { recordHintView.showForView(view, true); } + private void showReminderHint() { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + if (preferences.getBoolean("reminderhint", false)) { + return; + } + preferences.edit().putBoolean("reminderhint", true).commit(); + if (reminderHintView == null) { + reminderHintView = new HintView(getContext(), 8); + reminderHintView.setAlpha(0.0f); + reminderHintView.setVisibility(View.INVISIBLE); + reminderHintView.setShowingDuration(4000); + containerView.addView(reminderHintView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 19, 0, 19, 0)); + reminderHintView.setText(LocaleController.getString("VoipChatReminderHint", R.string.VoipChatReminderHint)); + reminderHintView.setBackgroundColor(0xea272f38, 0xffffffff); + } + reminderHintView.setExtraTranslationY(-AndroidUtilities.statusBarHeight); + reminderHintView.showForView(muteButton, true); + } + private void updateMuteButtonState(boolean animated) { muteButton.invalidate(); @@ -3335,7 +4332,7 @@ private void updateMuteButtonState(boolean animated) { if (muteButtonState == MUTE_BUTTON_STATE_CONNECTING) { states[muteButtonState].shader = null; } else { - if (muteButtonState == MUTE_BUTTON_STATE_MUTED_BY_ADMIN || muteButtonState == MUTE_BUTTON_STATE_RAISED_HAND) { + if (isGradientState(muteButtonState)) { states[muteButtonState].shader = new LinearGradient(0, 400, 400, 0, new int[]{Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient), Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient3), Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient2)}, null, Shader.TileMode.CLAMP); } else if (muteButtonState == MUTE_BUTTON_STATE_MUTE) { states[muteButtonState].shader = new RadialGradient(200, 200, 200, new int[]{Theme.getColor(Theme.key_voipgroup_muteButton), Theme.getColor(Theme.key_voipgroup_muteButton3)}, null, Shader.TileMode.CLAMP); @@ -3433,7 +4430,7 @@ public static void onLeaveClick(Context context, Runnable onLeave, boolean fromO 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)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); if (fromOverlayWindow) { @@ -3489,6 +4486,7 @@ private void processSelectedOption(TLRPC.TL_groupCallParticipant participant, in return; } AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setDialogButtonColorKey(Theme.key_voipgroup_listeningText); TextView messageTextView = new TextView(getContext()); messageTextView.setTextColor(Theme.getColor(Theme.key_voipgroup_actionBarItems)); @@ -3509,11 +4507,11 @@ private void processSelectedOption(TLRPC.TL_groupCallParticipant participant, in String name; if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; - imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); name = UserObject.getFirstName(user); } else { TLRPC.Chat chat = (TLRPC.Chat) object; - imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + imageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); name = chat.title; } @@ -3594,6 +4592,25 @@ private void processSelectedOption(TLRPC.TL_groupCallParticipant participant, in } else if (option == 7) { voIPService.editCallMember(object, true, -1, false); updateMuteButton(MUTE_BUTTON_STATE_MUTED_BY_ADMIN, true); + } else if (option == 9) { + if (currentAvatarUpdater != null && currentAvatarUpdater.isUploadingImage()) { + return; + } + currentAvatarUpdater = new ImageUpdater(true); + currentAvatarUpdater.setOpenWithFrontfaceCamera(true); + currentAvatarUpdater.setForceDarkTheme(true); + currentAvatarUpdater.setSearchAvailable(false, true); + 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 -> { + + }); + } else if (option == 10) { + AlertsCreator.createChangeBioAlert(participant.about, peerId, getContext(), currentAccount); + } else if (option == 11) { + AlertsCreator.createChangeNameAlert(peerId, getContext(), currentAccount); } else { if (option == 5) { voIPService.editCallMember(object, true, -1, null); @@ -3666,7 +4683,7 @@ public boolean onTouch(View v, MotionEvent event) { LinearLayout buttonsLayout = new LinearLayout(getContext()); LinearLayout volumeLayout = !participant.muted_by_you ? new LinearLayout(getContext()) : null; - + currentOptionsLayout = buttonsLayout; LinearLayout linearLayout = new LinearLayout(getContext()) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -3685,7 +4702,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { VolumeSlider volumeSlider = null; int color = AndroidUtilities.getOffsetColor(Theme.getColor(Theme.key_voipgroup_listViewBackgroundUnscrolled), Theme.getColor(Theme.key_voipgroup_listViewBackground), colorProgress, 1.0f); - if (!participant.muted_by_you && (!participant.muted || participant.can_self_unmute)) { + if (volumeLayout != null && !view.isSelfUser() && !participant.muted_by_you && (!participant.muted || participant.can_self_unmute)) { Drawable shadowDrawable = getContext().getResources().getDrawable(R.drawable.popup_fixed_alert).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); volumeLayout.setBackgroundDrawable(shadowDrawable); @@ -3743,10 +4760,27 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { isAdmin = peerId == -currentChat.id; } if (view.isSelfUser()) { - items.add(LocaleController.getString("VoipGroupCancelRaiseHand", R.string.VoipGroupCancelRaiseHand)); - icons.add(R.drawable.msg_handdown); - options.add(7); - showWithAvatarPreview = false; + if (view.isHandRaised()) { + items.add(LocaleController.getString("VoipGroupCancelRaiseHand", R.string.VoipGroupCancelRaiseHand)); + icons.add(R.drawable.msg_handdown); + options.add(7); + } + + items.add(view.hasAvatarSet() ? LocaleController.getString("VoipAddPhoto", R.string.VoipAddPhoto) : LocaleController.getString("VoipSetNewPhoto", R.string.VoipSetNewPhoto)); + icons.add(R.drawable.msg_addphoto); + options.add(9); + + if (peerId > 0) { + items.add(TextUtils.isEmpty(participant.about) ? LocaleController.getString("VoipAddBio", R.string.VoipAddBio) : LocaleController.getString("VoipEditBio", R.string.VoipEditBio)); + } else { + items.add(TextUtils.isEmpty(participant.about) ? LocaleController.getString("VoipAddDescription", R.string.VoipAddDescription) : LocaleController.getString("VoipEditDescription", R.string.VoipEditDescription)); + } + icons.add(TextUtils.isEmpty(participant.about) ? R.drawable.msg_addbio : R.drawable.msg_bio); + options.add(10); + + items.add(peerId > 0 ? LocaleController.getString("VoipEditName", R.string.VoipEditName) : LocaleController.getString("VoipEditTitle", R.string.VoipEditTitle)); + icons.add(R.drawable.msg_edit); + options.add(11); } else if (ChatObject.canManageCalls(currentChat)) { if (!isAdmin || !participant.muted) { if (!participant.muted || participant.can_self_unmute) { @@ -3798,7 +4832,6 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } - ActionBarMenuSubItem[] scrimPopupWindowItems = new ActionBarMenuSubItem[items.size()]; for (int a = 0, N = items.size(); a < N; a++) { ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getContext(), a == 0, a == N - 1); if (options.get(a) != 2) { @@ -3810,15 +4843,22 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { cell.setTextAndIcon(items.get(a), icons.get(a)); buttonsLayout.addView(cell); final int i = a; + cell.setTag(options.get(a)); cell.setOnClickListener(v1 -> { if (i >= options.size()) { return; } - processSelectedOption(participant, MessageObject.getPeerId(participant.peer), options.get(i)); + TLRPC.TL_groupCallParticipant participant1 = call.participants.get(MessageObject.getPeerId(participant.peer)); + if (participant1 == null) { + participant1 = participant; + } + processSelectedOption(participant1, MessageObject.getPeerId(participant1.peer), options.get(i)); if (scrimPopupWindow != null) { scrimPopupWindow.dismiss(); } else { - dismissAvatarPreview(true); + if (options.get(i) != 9 && options.get(i) != 10 && options.get(i) != 11) { + dismissAvatarPreview(true); + } } }); } @@ -3840,12 +4880,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final ImageLocation thumbLocation; if (peerId > 0) { TLRPC.User currentUser = accountInstance.getMessagesController().getUser(peerId); - imageLocation = ImageLocation.getForUser(currentUser, true); - thumbLocation = ImageLocation.getForUser(currentUser, false); + imageLocation = ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_BIG); + thumbLocation = ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL); } else { TLRPC.Chat currentChat = accountInstance.getMessagesController().getChat(-peerId); - imageLocation = ImageLocation.getForChat(currentChat, true); - thumbLocation = ImageLocation.getForChat(currentChat, false); + imageLocation = ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_BIG); + thumbLocation = ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL); } if (imageLocation == null) { @@ -3853,7 +4893,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } else { avatarsViewPager.setParentAvatarImage(scrimView.getAvatarImageView()); avatarsViewPager.setData(peerId); + avatarsViewPager.setCreateThumbFromParent(true); avatarsViewPager.initIfEmpty(imageLocation, thumbLocation); + if (MessageObject.getPeerId(selfPeer) == peerId && currentAvatarUpdater != null && avatarUpdaterDelegate != null && avatarUpdaterDelegate.avatar != null) { + avatarsViewPager.addUploadingImage(avatarUpdaterDelegate.uploadingImageLocation, ImageLocation.getForLocal(avatarUpdaterDelegate.avatar)); + } } if (showWithAvatarPreview) { @@ -3977,11 +5021,11 @@ private void runAvatarPreviewTransition(boolean enter, GroupCallUserCell view) { containerView.invalidate(); avatarsViewPager.setRoundRadius((int) (fromRadius * (1f - progressToAvatarPreview)), (int) (fromRadius * (1f - progressToAvatarPreview))); }); - popupAnimationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(popupAnimationIndex, new int[]{NotificationCenter.dialogPhotosLoaded, NotificationCenter.fileDidLoad, NotificationCenter.messagesDidLoad}); + popupAnimationIndex = accountInstance.getNotificationCenter().setAnimationInProgress(popupAnimationIndex, new int[]{NotificationCenter.dialogPhotosLoaded, NotificationCenter.fileDidLoad, NotificationCenter.messagesDidLoad}); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - NotificationCenter.getInstance(currentAccount).onAnimationFinish(popupAnimationIndex); + accountInstance.getNotificationCenter().onAnimationFinish(popupAnimationIndex); avatarPriviewTransitionInProgress = false; progressToAvatarPreview = enter ? 1f : 0f; if (!enter) { @@ -4012,6 +5056,7 @@ public void onAnimationEnd(Animator animation) { avatarPreviewContainer.setTranslationX(1f); avatarPreviewContainer.setTranslationY(1f); } + checkContentOverlayed(); containerView.invalidate(); avatarsViewPager.invalidate(); listView.invalidate(); @@ -4020,6 +5065,8 @@ public void onAnimationEnd(Animator animation) { valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); valueAnimator.setDuration(220); valueAnimator.start(); + + checkContentOverlayed(); } private void dismissAvatarPreview(boolean animated) { @@ -4048,6 +5095,7 @@ private void dismissAvatarPreview(boolean animated) { delayedGroupCallUpdated = false; applyCallParticipantUpdates(); } + checkContentOverlayed(); } } @@ -4081,7 +5129,7 @@ public int getItemCount() { } private void updateRows() { - if (delayedGroupCallUpdated) { + if (call == null || call.isScheduled() || delayedGroupCallUpdated) { return; } rowsCount = 0; @@ -4188,7 +5236,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { GroupCallTextCell textCell = (GroupCallTextCell) holder.itemView; int color = AndroidUtilities.getOffsetColor(Theme.getColor(Theme.key_voipgroup_lastSeenTextUnscrolled), Theme.getColor(Theme.key_voipgroup_lastSeenText), actionBar.getTag() != null ? 1.0f : 0.0f, 1.0f); textCell.setColors(color, color); - textCell.setTextAndIcon(LocaleController.getString("VoipGroupInviteMember", R.string.VoipGroupInviteMember), R.drawable.actions_addmember2, true); + if (ChatObject.isChannel(currentChat) && !currentChat.megagroup && !TextUtils.isEmpty(currentChat.username)) { + textCell.setTextAndIcon(LocaleController.getString("VoipGroupShareLink", R.string.VoipGroupShareLink), R.drawable.msg_link, true); + } else { + textCell.setTextAndIcon(LocaleController.getString("VoipGroupInviteMember", R.string.VoipGroupInviteMember), R.drawable.actions_addmember2, true); + } break; case 1: { GroupCallUserCell userCell = (GroupCallUserCell) holder.itemView; @@ -4208,7 +5260,13 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } } if (participant != null) { - userCell.setData(accountInstance, participant, call, MessageObject.getPeerId(selfPeer)); + int peerId = MessageObject.getPeerId(participant.peer); + int selfPeerId = MessageObject.getPeerId(selfPeer); + TLRPC.FileLocation uploadingAvatar = (peerId == selfPeerId && avatarUpdaterDelegate != null) ? avatarUpdaterDelegate.avatar : null; + float uploadingProgress = (uploadingAvatar != null) ? avatarUpdaterDelegate.uploadingProgress : 1f; + boolean animated = userCell.getParticipant() != null && MessageObject.getPeerId(userCell.getParticipant().peer) == peerId; + userCell.setData(accountInstance, participant, call, selfPeerId, uploadingAvatar); + userCell.setUploadProgress(uploadingProgress, animated); } break; } @@ -4241,8 +5299,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { public boolean isEnabled(RecyclerView.ViewHolder holder) { int type = holder.getItemViewType(); if (type == 1) { - GroupCallUserCell userCell = (GroupCallUserCell) holder.itemView; - return !userCell.isSelfUser() || userCell.isHandRaised(); + return true; } else if (type == 3) { return false; } @@ -4406,4 +5463,177 @@ public void onBackPressed() { } super.onBackPressed(); } + + private class AvatarUpdaterDelegate implements ImageUpdater.ImageUpdaterDelegate { + + public float uploadingProgress; + private TLRPC.FileLocation avatarBig; + private TLRPC.FileLocation avatar; + private ImageLocation uploadingImageLocation; + + private final int peerId; + + private AvatarUpdaterDelegate(int peerId) { + this.peerId = peerId; + } + + @Override + public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize) { + AndroidUtilities.runOnUIThread(() -> { + if (photo != null || video != null) { + if (peerId > 0) { + TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); + if (photo != null) { + req.file = photo; + req.flags |= 1; + } + if (video != null) { + req.video = video; + req.flags |= 2; + req.video_start_ts = videoStartTimestamp; + req.flags |= 4; + } + + accountInstance.getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (uploadingImageLocation != null) { + avatarsViewPager.removeUploadingImage(uploadingImageLocation); + uploadingImageLocation = null; + } + if (error == null) { + TLRPC.User user = accountInstance.getMessagesController().getUser(accountInstance.getUserConfig().getClientUserId()); + if (user == null) { + user = accountInstance.getUserConfig().getCurrentUser(); + if (user == null) { + return; + } + accountInstance.getMessagesController().putUser(user, false); + } else { + accountInstance.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); + + user.photo = new TLRPC.TL_userProfilePhoto(); + user.photo.photo_id = photos_photo.photo.id; + if (small != null) { + user.photo.photo_small = small.location; + } + if (big != null) { + user.photo.photo_big = big.location; + } + + if (small != null && avatar != null) { + File destFile = FileLoader.getPathToAttach(small, true); + File src = FileLoader.getPathToAttach(avatar, true); + src.renameTo(destFile); + String oldKey = avatar.volume_id + "_" + avatar.local_id + "@50_50"; + String newKey = small.location.volume_id + "_" + small.location.local_id + "@50_50"; + ImageLoader.getInstance().replaceImageInCache(oldKey, newKey, ImageLocation.getForUser(user, ImageLocation.TYPE_SMALL), false); + } + + if (big != null && avatarBig != null) { + File destFile = FileLoader.getPathToAttach(big, true); + File src = FileLoader.getPathToAttach(avatarBig, true); + src.renameTo(destFile); + } + if (videoSize != null && videoPath != null) { + File destFile = FileLoader.getPathToAttach(videoSize, "mp4", true); + File src = new File(videoPath); + src.renameTo(destFile); + } + + accountInstance.getMessagesStorage().clearUserPhotos(user.id); + ArrayList users = new ArrayList<>(); + users.add(user); + accountInstance.getMessagesStorage().putUsersAndChats(users, null, false, true); + + final ImageLocation imageLocation; + final ImageLocation thumbLocation; + TLRPC.User currentUser = accountInstance.getMessagesController().getUser(peerId); + imageLocation = ImageLocation.getForUser(currentUser, ImageLocation.TYPE_BIG); + thumbLocation = ImageLocation.getForUser(currentUser, ImageLocation.TYPE_SMALL); + ImageLocation thumb = ImageLocation.getForLocal(avatarBig); + if (thumb == null) { + thumb = ImageLocation.getForLocal(avatar); + } else { + thumb = thumbLocation; + } + avatarsViewPager.setCreateThumbFromParent(false); + avatarsViewPager.initIfEmpty(imageLocation, thumb); + avatar = null; + avatarBig = null; + AndroidUtilities.updateVisibleRows(listView); + updateAvatarUploadingProgress(1f); + } + + accountInstance.getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_ALL); + accountInstance.getNotificationCenter().postNotificationName(NotificationCenter.mainUserInfoChanged); + accountInstance.getUserConfig().saveConfig(true); + })); + } else { + accountInstance.getMessagesController().changeChatAvatar(-peerId, null, photo, video, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, () -> { + if (uploadingImageLocation != null) { + avatarsViewPager.removeUploadingImage(uploadingImageLocation); + uploadingImageLocation = null; + } + + TLRPC.Chat currentChat = accountInstance.getMessagesController().getChat(-peerId); + ImageLocation imageLocation = ImageLocation.getForChat(currentChat, ImageLocation.TYPE_BIG); + ImageLocation thumbLocation = ImageLocation.getForChat(currentChat, ImageLocation.TYPE_SMALL); + ImageLocation thumb = ImageLocation.getForLocal(avatarBig); + if (thumb == null) { + thumb = ImageLocation.getForLocal(avatar); + } else { + thumb = thumbLocation; + } + avatarsViewPager.setCreateThumbFromParent(false); + avatarsViewPager.initIfEmpty(imageLocation, thumb); + avatar = null; + avatarBig = null; + AndroidUtilities.updateVisibleRows(listView); + updateAvatarUploadingProgress(1f); + }); + } + } else { + avatar = smallSize.location; + avatarBig = bigSize.location; + uploadingImageLocation = ImageLocation.getForLocal(avatarBig); + avatarsViewPager.addUploadingImage(uploadingImageLocation, ImageLocation.getForLocal(avatar)); + AndroidUtilities.updateVisibleRows(listView); + } + }); + } + + @Override + public void didStartUpload(boolean isVideo) { + + } + + @Override + public void onUploadProgressChanged(float progress) { + avatarsViewPager.setUploadProgress(uploadingImageLocation, progress); + updateAvatarUploadingProgress(progress); + } + + public void updateAvatarUploadingProgress(float progress) { + uploadingProgress = progress; + if (listView == null) { + return; + } + for (int i = 0; i < listView.getChildCount(); i++) { + View child = listView.getChildAt(i); + if (child instanceof GroupCallUserCell) { + GroupCallUserCell cell = ((GroupCallUserCell) child); + if (cell.isSelfUser()) { + cell.setUploadProgress(progress, true); + } + } + } + } + } + + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java index e167d58084f..efc3e1523eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java @@ -803,7 +803,7 @@ public void didReceivedNotification(int id, int account, Object... args) { presentFragment(new ChatActivity(args2), true); } if (inputPhoto != null || inputVideo != null) { - getMessagesController().changeChatAvatar(chat_id, null, inputPhoto, inputVideo, videoTimestamp, inputVideoPath, avatar, avatarBig); + getMessagesController().changeChatAvatar(chat_id, null, inputPhoto, inputVideo, videoTimestamp, inputVideoPath, avatar, avatarBig, null); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 3fdbf462640..1fb88257949 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -183,7 +183,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa private FrameLayout shadowTabletSide; private View backgroundTablet; private FrameLayout frameLayout; - protected DrawerLayoutContainer drawerLayoutContainer; + public DrawerLayoutContainer drawerLayoutContainer; private DrawerLayoutAdapter drawerLayoutAdapter; private PasscodeView passcodeView; private TermsOfServiceView termsOfServiceView; @@ -584,6 +584,9 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { presentFragment(new ActionIntroActivity(ActionIntroActivity.ACTION_TYPE_NEARBY_LOCATION_ENABLED)); } drawerLayoutContainer.closeDrawer(false); + } else if (id == 13) { + Browser.openUrl(LaunchActivity.this, LocaleController.getString("TelegramFeaturesUrl", R.string.TelegramFeaturesUrl)); + drawerLayoutContainer.closeDrawer(false); } } }); @@ -2279,7 +2282,7 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool } pushOpened = true; } else if (showGroupVoip) { - GroupCallActivity.create(this, AccountInstance.getInstance(currentAccount)); + GroupCallActivity.create(this, AccountInstance.getInstance(currentAccount), null, null, false, null); if (GroupCallActivity.groupCallInstance != null) { GroupCallActivity.groupCallUiVisible = true; } @@ -4230,6 +4233,8 @@ public void didReceivedNotification(int id, final int account, Object... args) { } Bitmap bitmap = Bitmap.createBitmap(drawerLayoutContainer.getMeasuredWidth(), drawerLayoutContainer.getMeasuredHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); + HashMap viewLayerTypes = new HashMap<>(); + invalidateCachedViews(drawerLayoutContainer); drawerLayoutContainer.draw(canvas); frameLayout.removeView(themeSwitchImageView); if (toDark) { @@ -4390,12 +4395,39 @@ public void onAnimationEnd(Animator animation) { } else if (id == NotificationCenter.showBulletin) { if (!mainFragmentsStack.isEmpty()) { int type = (int) args[0]; - BaseFragment fragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); - if (type == Bulletin.TYPE_STICKER) { + + FrameLayout container = null; + BaseFragment fragment = null; + if (GroupCallActivity.groupCallUiVisible && GroupCallActivity.groupCallInstance != null) { + container = GroupCallActivity.groupCallInstance.getContainer(); + } + + if (container == null) { + fragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); + } + + if (type == Bulletin.TYPE_NAME_CHANGED) { + int peerId = (int) args[1]; + String text = peerId > 0 ? LocaleController.getString("YourNameChanged", R.string.YourNameChanged) : LocaleController.getString("CannelTitleChanged", R.string.ChannelTitleChanged); + (container != null ? BulletinFactory.of(container) : BulletinFactory.of(fragment)).createErrorBulletin(text).show(); + } else if (type == Bulletin.TYPE_BIO_CHANGED) { + int peerId = (int) args[1]; + String text = peerId > 0 ? LocaleController.getString("YourBioChanged", R.string.YourBioChanged) : LocaleController.getString("CannelDescriptionChanged", R.string.ChannelDescriptionChanged); + (container != null ? BulletinFactory.of(container) : BulletinFactory.of(fragment)).createErrorBulletin(text).show(); + } else if (type == Bulletin.TYPE_STICKER) { TLRPC.Document sticker = (TLRPC.Document) args[1]; - Bulletin.make(fragment, new StickerSetBulletinLayout(this, null, (int) args[2], sticker), Bulletin.DURATION_SHORT).show(); + StickerSetBulletinLayout layout = new StickerSetBulletinLayout(this, null, (int) args[2], sticker); + if (fragment != null) { + Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT).show(); + } else { + Bulletin.make(container, layout, Bulletin.DURATION_SHORT).show(); + } } else if (type == Bulletin.TYPE_ERROR) { - BulletinFactory.of(fragment).createErrorBulletin((String)args[1]).show(); + if (fragment != null) { + BulletinFactory.of(fragment).createErrorBulletin((String) args[1]).show(); + } else { + BulletinFactory.of(container).createErrorBulletin((String) args[1]).show(); + } } } } else if (id == NotificationCenter.groupCallUpdated) { @@ -4403,6 +4435,19 @@ public void onAnimationEnd(Animator animation) { } } + private void invalidateCachedViews(View parent) { + int layerType = parent.getLayerType(); + if (layerType != View.LAYER_TYPE_NONE) { + parent.invalidate(); + } + if (parent instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) parent; + for (int i = 0; i < viewGroup.getChildCount(); i++) { + invalidateCachedViews(viewGroup.getChildAt(i)); + } + } + } + private void checkWasMutedByAdmin(boolean checkOnly) { VoIPService voIPService = VoIPService.getSharedInstance(); if (voIPService != null && voIPService.groupCall != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index 0d163880ef5..e8762679f64 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -1208,7 +1208,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto BackupImageView backupImageView = new BackupImageView(context); backupImageView.setRoundRadius(AndroidUtilities.dp(26)); - backupImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", new AvatarDrawable(chat), chat); + backupImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", new AvatarDrawable(chat), chat); frameLayout1.addView(backupImageView, LayoutHelper.createFrame(52, 52, Gravity.LEFT | Gravity.TOP, 5, 5, 0, 0)); markerImageView = frameLayout1; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index 03dbc43b58c..acab2160aeb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -32,6 +32,7 @@ import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Vibrator; @@ -96,6 +97,8 @@ import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.ContextProgressView; import org.telegram.ui.Components.EditTextBoldCursor; @@ -279,7 +282,20 @@ public void onItemClick(int id) { doneItem.setContentDescription(LocaleController.getString("Done", R.string.Done)); doneItem.setVisibility(doneButtonVisible[DONE_TYPE_ACTION] ? View.VISIBLE : View.GONE); - FrameLayout container = new FrameLayout(context); + FrameLayout container = new FrameLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + MarginLayoutParams marginLayoutParams = (MarginLayoutParams) floatingButtonContainer.getLayoutParams(); + if (Bulletin.getVisibleBulletin() != null && Bulletin.getVisibleBulletin().isShowing()) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + marginLayoutParams.bottomMargin = AndroidUtilities.dp(14) + Bulletin.getVisibleBulletin().getLayout().getMeasuredHeight() - AndroidUtilities.dp(10); + } else { + marginLayoutParams.bottomMargin = AndroidUtilities.dp(14); + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + }; fragmentView = container; ScrollView scrollView = new ScrollView(context) { @@ -614,11 +630,11 @@ private void onFieldError(View view) { AndroidUtilities.shakeView(view, 2, 0); } - private void needShowInvalidAlert(final String phoneNumber, final boolean banned) { - if (getParentActivity() == null) { + public static void needShowInvalidAlert(BaseFragment fragment, final String phoneNumber, final boolean banned) { + if (fragment == null || fragment.getParentActivity() == null) { return; } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); if (banned) { builder.setMessage(LocaleController.getString("BannedPhoneNumber", R.string.BannedPhoneNumber)); @@ -630,8 +646,8 @@ private void needShowInvalidAlert(final String phoneNumber, final boolean banned PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); - Intent mailer = new Intent(Intent.ACTION_SEND); - mailer.setType("message/rfc822"); + Intent mailer = new Intent(Intent.ACTION_SENDTO); + mailer.setData(Uri.parse("mailto:")); mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"login@stel.com"}); if (banned) { mailer.putExtra(Intent.EXTRA_SUBJECT, "Banned phone number: " + phoneNumber); @@ -640,13 +656,17 @@ private void needShowInvalidAlert(final String phoneNumber, final boolean banned mailer.putExtra(Intent.EXTRA_SUBJECT, "Invalid phone number: " + phoneNumber); mailer.putExtra(Intent.EXTRA_TEXT, "I'm trying to use my mobile phone number: " + phoneNumber + "\nBut Telegram says it's invalid. Please help.\n\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault()); } - getParentActivity().startActivity(Intent.createChooser(mailer, "Send email...")); + fragment.getParentActivity().startActivity(Intent.createChooser(mailer, "Send email...")); } catch (Exception e) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); + AlertDialog.Builder builder2 = new AlertDialog.Builder(fragment.getParentActivity()); + builder2.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder2.setMessage(LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); + builder2.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + fragment.showDialog(builder2.create()); } }); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - showDialog(builder.create()); + fragment.showDialog(builder.create()); } private void showDoneButton(boolean show, boolean animated) { @@ -1389,11 +1409,9 @@ public void onClick(View v) { FileLog.e(e); } if (syncContacts) { - visibleToast = Toast.makeText(getParentActivity(), LocaleController.getString("SyncContactsOn", R.string.SyncContactsOn), Toast.LENGTH_SHORT); - visibleToast.show(); + BulletinFactory.of((FrameLayout) fragmentView).createSimpleBulletin(R.raw.contacts_sync_on, LocaleController.getString("SyncContactsOn", R.string.SyncContactsOn)).show(); } else { - visibleToast = Toast.makeText(getParentActivity(), LocaleController.getString("SyncContactsOff", R.string.SyncContactsOff), Toast.LENGTH_SHORT); - visibleToast.show(); + BulletinFactory.of((FrameLayout) fragmentView).createSimpleBulletin(R.raw.contacts_sync_off, LocaleController.getString("SyncContactsOff", R.string.SyncContactsOff)).show(); } } }); @@ -1657,13 +1675,13 @@ public void onNextPressed() { } else { if (error.text != null) { if (error.text.contains("PHONE_NUMBER_INVALID")) { - needShowInvalidAlert(req.phone_number, false); + needShowInvalidAlert(LoginActivity.this, req.phone_number, false); } else if (error.text.contains("PHONE_PASSWORD_FLOOD")) { needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); } else if (error.text.contains("PHONE_NUMBER_FLOOD")) { needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("PhoneNumberFlood", R.string.PhoneNumberFlood)); } else if (error.text.contains("PHONE_NUMBER_BANNED")) { - needShowInvalidAlert(req.phone_number, true); + needShowInvalidAlert(LoginActivity.this, req.phone_number, true); } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); } else if (error.text.contains("PHONE_CODE_EXPIRED")) { @@ -1961,8 +1979,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); - Intent mailer = new Intent(Intent.ACTION_SEND); - mailer.setType("message/rfc822"); + Intent mailer = new Intent(Intent.ACTION_SENDTO); + mailer.setData(Uri.parse("mailto:")); mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"}); mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + emailPhone); mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + requestPhone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java index 961f9c33500..e015407c733 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java @@ -391,7 +391,7 @@ protected void onDetachedFromWindow() { } thumbImage.setImage(ImageLocation.getForObject(bigThumb, messageObject.photoThumbsObject), "20_20", ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "20_20", size, null, messageObject, 0); } else { - thumbImage.setImage(null, null, ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "20_20", null, messageObject, 0); + thumbImage.setImage(null, null, ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "20_20", (Drawable) null, messageObject, 0); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java index 34792936519..0ac36701d98 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java @@ -1526,7 +1526,7 @@ private void createPasswordInterface(Context context) { passwordAvatarContainer.addView(avatarImageView, LayoutHelper.createFrame(64, 64, Gravity.CENTER, 0, 8, 0, 0)); AvatarDrawable avatarDrawable = new AvatarDrawable(botUser); - avatarImageView.setImage(ImageLocation.getForUser(botUser, false), "50_50", avatarDrawable, botUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(botUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(botUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, botUser); passwordRequestTextView = new TextInfoPrivacyCell(context); passwordRequestTextView.getTextView().setGravity(Gravity.CENTER_HORIZONTAL); @@ -2001,7 +2001,7 @@ private void createRequestInterface(Context context) { avatarContainer.addView(avatarImageView, LayoutHelper.createFrame(64, 64, Gravity.CENTER, 0, 8, 0, 0)); AvatarDrawable avatarDrawable = new AvatarDrawable(botUser); - avatarImageView.setImage(ImageLocation.getForUser(botUser, false), "50_50", avatarDrawable, botUser); + avatarImageView.setImage(ImageLocation.getForUserOrChat(botUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(botUser, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, botUser); bottomCell = new TextInfoPrivacyCell(context); bottomCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); @@ -6826,7 +6826,7 @@ private void createChatAttachView() { return; } if (chatAttachAlert == null) { - chatAttachAlert = new ChatAttachAlert(getParentActivity(), this); + chatAttachAlert = new ChatAttachAlert(getParentActivity(), this, false); chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { @Override @@ -7384,8 +7384,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); - Intent mailer = new Intent(Intent.ACTION_SEND); - mailer.setType("message/rfc822"); + Intent mailer = new Intent(Intent.ACTION_SENDTO); + mailer.setData(Uri.parse("mailto:")); mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"}); mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + phone); mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + phone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java index f2a7f031d69..7c579dc4ac2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java @@ -24,6 +24,7 @@ import android.graphics.Canvas; import android.graphics.Typeface; import android.net.Uri; +import android.os.AsyncTask; import android.os.Build; import android.os.Vibrator; import android.telephony.TelephonyManager; @@ -53,6 +54,7 @@ import android.webkit.WebViewClient; import android.widget.EditText; import android.widget.FrameLayout; +import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; @@ -83,6 +85,7 @@ import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -103,6 +106,7 @@ import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.EditTextSettingsCell; @@ -120,9 +124,15 @@ import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.HintEditText; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.UndoView; import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -131,6 +141,7 @@ import java.util.List; import java.util.Locale; import java.util.Optional; +import java.util.Scanner; public class PaymentFormActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { @@ -213,7 +224,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen private boolean need_card_country; private boolean need_card_postcode; private boolean need_card_name; - private String stripeApiKey; + private String providerApiKey; private boolean initGooglePay; private TLRPC.User botUser; @@ -225,6 +236,10 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen private String currentBotName; private String currentItemName; + private BaseFragment parentFragment; + + private LinearLayout tipLayout; + private int currentStep; private boolean passwordOk; private String paymentJson; @@ -233,8 +248,10 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen private String countryName; private String totalPriceDecimal; private TLRPC.TL_payments_paymentForm paymentForm; + private TLRPC.TL_payments_paymentReceipt paymentReceipt; private TLRPC.TL_payments_validatedRequestedInfo requestedInfo; private TLRPC.TL_shippingOption shippingOption; + private Long tipAmount; private TLRPC.TL_payments_validateRequestedInfo validateRequest; private TLRPC.TL_inputPaymentCredentialsGooglePay googlePayCredentials; private String googlePayPublicKey; @@ -244,6 +261,8 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen private boolean donePressed; private boolean canceled; + private String[] totalPrice; + private boolean isWebView; private boolean saveShippingInfo; @@ -254,9 +273,21 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen private static final int LOAD_PAYMENT_DATA_REQUEST_CODE = 991; private interface PaymentFormActivityDelegate { - boolean didSelectNewCard(String tokenJson, String card, boolean saveCard, TLRPC.TL_inputPaymentCredentialsGooglePay googlePay); - void onFragmentDestroyed(); - void currentPasswordUpdated(TLRPC.TL_account_password password); + default boolean didSelectNewCard(String tokenJson, String card, boolean saveCard, TLRPC.TL_inputPaymentCredentialsGooglePay googlePay) { + return false; + } + + default void didSelectNewAddress(TLRPC.TL_payments_validateRequestedInfo validateRequested) { + + } + + default void onFragmentDestroyed() { + + } + + default void currentPasswordUpdated(TLRPC.TL_account_password password) { + + } } private class TelegramWebviewProxy { @@ -295,30 +326,34 @@ public void onClick(View widget) { } } - public PaymentFormActivity(MessageObject message, TLRPC.TL_payments_paymentReceipt receipt) { + public PaymentFormActivity(TLRPC.TL_payments_paymentReceipt receipt) { currentStep = 5; paymentForm = new TLRPC.TL_payments_paymentForm(); + paymentReceipt = receipt; paymentForm.bot_id = receipt.bot_id; paymentForm.invoice = receipt.invoice; paymentForm.provider_id = receipt.provider_id; paymentForm.users = receipt.users; shippingOption = receipt.shipping; - messageObject = message; - botUser = MessagesController.getInstance(currentAccount).getUser(receipt.bot_id); + if (receipt.tip_amount != 0) { + tipAmount = receipt.tip_amount; + } + botUser = getMessagesController().getUser(receipt.bot_id); if (botUser != null) { currentBotName = botUser.first_name; } else { currentBotName = ""; } - currentItemName = message.messageOwner.media.title; + currentItemName = receipt.title; if (receipt.info != null) { validateRequest = new TLRPC.TL_payments_validateRequestedInfo(); + validateRequest.peer = getMessagesController().getInputPeer(receipt.bot_id); validateRequest.info = receipt.info; } cardName = receipt.credentials_title; } - public PaymentFormActivity(TLRPC.TL_payments_paymentForm form, MessageObject message) { + public PaymentFormActivity(TLRPC.TL_payments_paymentForm form, MessageObject message, BaseFragment parentFragment) { int step; if (form.invoice.shipping_address_requested || form.invoice.email_requested || form.invoice.name_requested || form.invoice.phone_requested) { step = 0; @@ -337,11 +372,11 @@ public PaymentFormActivity(TLRPC.TL_payments_paymentForm form, MessageObject mes } else { step = 2; } - init(form, message, step, null, null, null, null, null, false, null); + init(form, message, step, null, null, null, null, null, null, false, null, parentFragment); } - private PaymentFormActivity(TLRPC.TL_payments_paymentForm form, MessageObject message, int step, TLRPC.TL_payments_validatedRequestedInfo validatedRequestedInfo, TLRPC.TL_shippingOption shipping, String tokenJson, String card, TLRPC.TL_payments_validateRequestedInfo request, boolean saveCard, TLRPC.TL_inputPaymentCredentialsGooglePay googlePay) { - init(form, message, step, validatedRequestedInfo, shipping, tokenJson, card, request, saveCard, googlePay); + private PaymentFormActivity(TLRPC.TL_payments_paymentForm form, MessageObject message, int step, TLRPC.TL_payments_validatedRequestedInfo validatedRequestedInfo, TLRPC.TL_shippingOption shipping, Long tips, String tokenJson, String card, TLRPC.TL_payments_validateRequestedInfo request, boolean saveCard, TLRPC.TL_inputPaymentCredentialsGooglePay googlePay, BaseFragment parent) { + init(form, message, step, validatedRequestedInfo, shipping, tips, tokenJson, card, request, saveCard, googlePay, parent); } private void setCurrentPassword(TLRPC.TL_account_password password) { @@ -352,9 +387,7 @@ private void setCurrentPassword(TLRPC.TL_account_password password) { goToNextStep(); } else { currentPassword = password; - if (currentPassword != null) { - waitingForEmail = !TextUtils.isEmpty(currentPassword.email_unconfirmed_pattern); - } + waitingForEmail = !TextUtils.isEmpty(currentPassword.email_unconfirmed_pattern); updatePasswordFields(); } } @@ -363,17 +396,19 @@ private void setDelegate(PaymentFormActivityDelegate paymentFormActivityDelegate delegate = paymentFormActivityDelegate; } - private void init(TLRPC.TL_payments_paymentForm form, MessageObject message, int step, TLRPC.TL_payments_validatedRequestedInfo validatedRequestedInfo, TLRPC.TL_shippingOption shipping, String tokenJson, String card, TLRPC.TL_payments_validateRequestedInfo request, boolean saveCard, TLRPC.TL_inputPaymentCredentialsGooglePay googlePay) { + private void init(TLRPC.TL_payments_paymentForm form, MessageObject message, int step, TLRPC.TL_payments_validatedRequestedInfo validatedRequestedInfo, TLRPC.TL_shippingOption shipping, Long tips, String tokenJson, String card, TLRPC.TL_payments_validateRequestedInfo request, boolean saveCard, TLRPC.TL_inputPaymentCredentialsGooglePay googlePay, BaseFragment parent) { currentStep = step; + parentFragment = parent; paymentJson = tokenJson; googlePayCredentials = googlePay; requestedInfo = validatedRequestedInfo; paymentForm = form; shippingOption = shipping; + tipAmount = tips; messageObject = message; saveCardInfo = saveCard; - isWebView = !"stripe".equals(paymentForm.native_provider); - botUser = MessagesController.getInstance(currentAccount).getUser(form.bot_id); + isWebView = !"stripe".equals(paymentForm.native_provider) && !"smartglocal".equals(paymentForm.native_provider); + botUser = getMessagesController().getUser(form.bot_id); if (botUser != null) { currentBotName = botUser.first_name; } else { @@ -503,6 +538,7 @@ public void onItemClick(int id) { linearLayout2 = new LinearLayout(context); linearLayout2.setOrientation(LinearLayout.VERTICAL); + linearLayout2.setClipChildren(false); scrollView.addView(linearLayout2, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); if (currentStep == 0) { @@ -548,6 +584,7 @@ public void onItemClick(int id) { ViewGroup container; if (a == FIELD_PHONECODE) { container = new LinearLayout(context); + container.setClipChildren(false); ((LinearLayout) container).setOrientation(LinearLayout.HORIZONTAL); linearLayout2.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); container.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -555,10 +592,11 @@ public void onItemClick(int id) { container = (ViewGroup) inputFields[FIELD_PHONECODE].getParent(); } else { container = new FrameLayout(context); + container.setClipChildren(false); linearLayout2.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); container.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - boolean allowDivider = a != FIELD_POSTCODE && a != FIELD_PHONE; + boolean allowDivider = a != FIELD_POSTCODE; if (allowDivider) { if (a == FIELD_EMAIL && !paymentForm.invoice.phone_requested) { allowDivider = false; @@ -1076,10 +1114,14 @@ public void onPageFinished(WebView view, String url) { } catch (Exception e) { need_card_name = false; } - try { - stripeApiKey = jsonObject.getString("publishable_key"); - } catch (Exception e) { - stripeApiKey = ""; + if (jsonObject.has("public_token")) { + providerApiKey = jsonObject.getString("public_token"); + } else { + try { + providerApiKey = jsonObject.getString("publishable_key"); + } catch (Exception e) { + providerApiKey = ""; + } } initGooglePay = !jsonObject.optBoolean("google_pay_hidden", false); } catch (Exception e) { @@ -1087,7 +1129,7 @@ public void onPageFinished(WebView view, String url) { } } - if (initGooglePay && (!TextUtils.isEmpty(stripeApiKey) || googlePayParameters != null)) { + if (initGooglePay && (!TextUtils.isEmpty(providerApiKey) && "stripe".equals(paymentForm.native_provider) || googlePayParameters != null)) { initGooglePay(context); } @@ -1107,8 +1149,9 @@ public void onPageFinished(WebView view, String url) { boolean allowDivider = a != FIELD_CVV && a != FIELD_CARD_POSTCODE && !(a == FIELD_CARD_COUNTRY && !need_card_postcode); ViewGroup container = new FrameLayout(context); - linearLayout2.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); + container.setClipChildren(false); container.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + linearLayout2.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); View.OnTouchListener onTouchListener = null; inputFields[a] = new EditTextBoldCursor(context); @@ -1285,17 +1328,13 @@ public void afterTextChanged(Editable editable) { break; } } - if (maxLength != 0) { - if (builder.length() > maxLength) { - builder.setLength(maxLength); - } + if (builder.length() > maxLength) { + builder.setLength(maxLength); } } if (hint != null) { - if (maxLength != 0) { - if (builder.length() == maxLength) { - inputFields[FIELD_EXPIRE_DATE].requestFocus(); - } + if (builder.length() == maxLength) { + inputFields[FIELD_EXPIRE_DATE].requestFocus(); } phoneField.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); for (int a = 0; a < builder.length(); a++) { @@ -1490,7 +1529,7 @@ public void afterTextChanged(Editable s) { linearLayout2.addView(bottomCell[0], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } else if (a == FIELD_CARD) { createGooglePayButton(context); - container.addView(googlePayContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.RIGHT, 0, 0, 4, 0)); + container.addView(googlePayContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT), 0, 0, 4, 0)); } if (allowDivider) { @@ -1550,6 +1589,7 @@ protected void onDraw(Canvas canvas) { } ViewGroup container = new FrameLayout(context); + container.setClipChildren(false); linearLayout2.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); container.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -1634,7 +1674,11 @@ protected void onDraw(Canvas canvas) { } else if (currentStep == 4 || currentStep == 5) { paymentInfoCell = new PaymentInfoCell(context); paymentInfoCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - paymentInfoCell.setInvoice((TLRPC.TL_messageMediaInvoice) messageObject.messageOwner.media, currentBotName); + if (messageObject != null) { + paymentInfoCell.setInvoice((TLRPC.TL_messageMediaInvoice) messageObject.messageOwner.media, currentBotName); + } else if (paymentReceipt != null) { + paymentInfoCell.setReceipt(paymentReceipt, currentBotName); + } linearLayout2.addView(paymentInfoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); sectionCell[0] = new ShadowSectionCell(context); @@ -1644,7 +1688,7 @@ protected void onDraw(Canvas canvas) { if (shippingOption != null) { arrayList.addAll(shippingOption.prices); } - final String totalPrice = getTotalPriceString(arrayList); + totalPrice = new String[1]; for (int a = 0; a < arrayList.size(); a++) { TLRPC.TL_labeledPrice price = arrayList.get(a); @@ -1655,51 +1699,290 @@ protected void onDraw(Canvas canvas) { linearLayout2.addView(priceCell); } + if (currentStep == 5 && tipAmount != null) { + TextPriceCell priceCell = new TextPriceCell(context); + priceCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + priceCell.setTextAndValue(LocaleController.getString("PaymentTip", R.string.PaymentTip), LocaleController.getInstance().formatCurrencyString(tipAmount, paymentForm.invoice.currency), false); + linearLayout2.addView(priceCell); + } + TextPriceCell priceCell = new TextPriceCell(context); priceCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - priceCell.setTextAndValue(LocaleController.getString("PaymentTransactionTotal", R.string.PaymentTransactionTotal), totalPrice, true); - linearLayout2.addView(priceCell); + totalPrice[0] = getTotalPriceString(arrayList); + priceCell.setTextAndValue(LocaleController.getString("PaymentTransactionTotal", R.string.PaymentTransactionTotal), totalPrice[0], true); - View divider = new View(context) { - @Override - protected void onDraw(Canvas canvas) { - canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(20) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); - } - }; - divider.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - dividers.add(divider); - linearLayout2.addView(divider, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1, Gravity.LEFT | Gravity.BOTTOM)); + if (currentStep == 4 && (paymentForm.invoice.flags & 256) != 0) { + ViewGroup container = new FrameLayout(context); + container.setClipChildren(false); + container.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + linearLayout2.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, paymentForm.invoice.suggested_tip_amounts.isEmpty() ? 40 : 78)); + container.setOnClickListener(v -> { + inputFields[0].requestFocus(); + AndroidUtilities.showKeyboard(inputFields[0]); + }); - detailSettingsCell[0] = new TextDetailSettingsCell(context); - detailSettingsCell[0].setBackgroundDrawable(Theme.getSelectorDrawable(true)); - detailSettingsCell[0].setTextAndValue(cardName, LocaleController.getString("PaymentCheckoutMethod", R.string.PaymentCheckoutMethod), true); - linearLayout2.addView(detailSettingsCell[0]); - if (currentStep == 4) { - detailSettingsCell[0].setOnClickListener(v -> { - PaymentFormActivity activity = new PaymentFormActivity(paymentForm, messageObject, 2, requestedInfo, shippingOption, null, cardName, validateRequest, saveCardInfo, null); - activity.setDelegate(new PaymentFormActivityDelegate() { - @Override - public boolean didSelectNewCard(String tokenJson, String card, boolean saveCard, TLRPC.TL_inputPaymentCredentialsGooglePay googlePay) { - paymentForm.saved_credentials = null; - paymentJson = tokenJson; - saveCardInfo = saveCard; - cardName = card; - googlePayCredentials = googlePay; - detailSettingsCell[0].setTextAndValue(cardName, LocaleController.getString("PaymentCheckoutMethod", R.string.PaymentCheckoutMethod), true); - return false; + TextPriceCell cell = new TextPriceCell(context); + cell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + cell.setTextAndValue(LocaleController.getString("PaymentTipOptional", R.string.PaymentTipOptional), "", false); + container.addView(cell); + + inputFields = new EditTextBoldCursor[1]; + inputFields[0] = new EditTextBoldCursor(context); + inputFields[0].setTag(0); + inputFields[0].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + inputFields[0].setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); + inputFields[0].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); + inputFields[0].setBackgroundDrawable(null); + inputFields[0].setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + inputFields[0].setCursorSize(AndroidUtilities.dp(20)); + inputFields[0].setCursorWidth(1.5f); + inputFields[0].setInputType(InputType.TYPE_CLASS_PHONE); + inputFields[0].setImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI); + inputFields[0].setHint(LocaleController.getInstance().formatCurrencyString(0, paymentForm.invoice.currency)); + inputFields[0].setPadding(0, 0, 0, AndroidUtilities.dp(6)); + inputFields[0].setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + container.addView(inputFields[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 21, 9, 21, 1)); + inputFields[0].addTextChangedListener(new TextWatcher() { + + private boolean anyBefore; + private String overrideText; + private boolean dotEntered; + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + if (ignoreOnTextChange) { + return; + } + anyBefore = !TextUtils.isEmpty(s); + overrideText = null; + if (count == 1 && after == 0) { + String fixed = LocaleController.fixNumbers(s); + char actionCh = fixed.charAt(start); + if (actionCh < '0' || actionCh > '9') { + while (--start > 0) { + actionCh = fixed.charAt(start); + if (actionCh >= '0' && actionCh <= '9') { + overrideText = fixed.substring(0, start) + fixed.substring(start + 1); + break; + } + } + } } + } - @Override - public void onFragmentDestroyed() { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (ignoreOnTextChange) { + return; + } + long oldAmount = tipAmount != null ? tipAmount : 0; + + String text; + if (overrideText != null) { + text = overrideText; + } else { + text = LocaleController.fixNumbers(s.toString()); + } + tipAmount = Utilities.parseLong(PhoneFormat.stripExceptNumbers(text)); + /*if (!dotEntered) { } + if (text.endsWith(",") || text.endsWith(".")) { + dotEntered = true; + } + if (tipAmount == 0) { + dotEntered = false; + }*/ + if (paymentForm.invoice.max_tip_amount != 0 && tipAmount > paymentForm.invoice.max_tip_amount) { + tipAmount = paymentForm.invoice.max_tip_amount; + } + int start = inputFields[0].getSelectionStart(); + String phoneChars = "0123456789,."; + String str = inputFields[0].getText().toString(); + StringBuilder builder = new StringBuilder(str.length()); + for (int a = 0; a < str.length(); a++) { + String ch = str.substring(a, a + 1); + if (phoneChars.contains(ch)) { + builder.append(ch); + } + } + ignoreOnTextChange = true; + inputFields[0].setText(LocaleController.getInstance().formatCurrencyString(tipAmount, false, paymentForm.invoice.currency)); + if (oldAmount < tipAmount && oldAmount != 0 && anyBefore && start >= 0) { + inputFields[0].setSelection(Math.min(start, inputFields[0].length())); + } else { + inputFields[0].setSelection(inputFields[0].length()); + } + totalPrice[0] = getTotalPriceString(arrayList); + priceCell.setTextAndValue(LocaleController.getString("PaymentTransactionTotal", R.string.PaymentTransactionTotal), totalPrice[0], true); + if (payTextView != null) { + payTextView.setText(LocaleController.formatString("PaymentCheckoutPay", R.string.PaymentCheckoutPay, totalPrice[0])); + } + checkSelectedTip(); + ignoreOnTextChange = false; + } + }); + inputFields[0].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_DONE) { + AndroidUtilities.hideKeyboard(textView); + return true; + } + return false; + }); + inputFields[0].requestFocus(); + + if (!paymentForm.invoice.suggested_tip_amounts.isEmpty()) { + HorizontalScrollView scrollView = new HorizontalScrollView(context); + scrollView.setHorizontalScrollBarEnabled(false); + scrollView.setVerticalScrollBarEnabled(false); + scrollView.setClipToPadding(false); + scrollView.setPadding(AndroidUtilities.dp(21), 0, AndroidUtilities.dp(21), 0); + scrollView.setFillViewport(true); + container.addView(scrollView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.LEFT | Gravity.TOP, 0, 44, 0, 0)); + int[] maxTextWidth = new int[1]; + int[] textWidths = new int[1]; + int N = paymentForm.invoice.suggested_tip_amounts.size(); + + tipLayout = new LinearLayout(context) { + + boolean ignoreLayout; @Override - public void currentPasswordUpdated(TLRPC.TL_account_password password) { + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int availableSize = MeasureSpec.getSize(widthMeasureSpec); + ignoreLayout = true; + int gaps = AndroidUtilities.dp(9) * (N - 1); + if (maxTextWidth[0] * N + gaps <= availableSize) { + setWeightSum(1.0f); + for (int a = 0, N2 = getChildCount(); a < N2; a++) { + getChildAt(a).getLayoutParams().width = 0; + ((LayoutParams) getChildAt(a).getLayoutParams()).weight = 1.0f / N2; + } + } else if (textWidths[0] + gaps <= availableSize) { + setWeightSum(1.0f); + availableSize -= gaps; + float extraWeight = 1.0f; + for (int a = 0, N2 = getChildCount(); a < N2; a++) { + View child = getChildAt(a); + LayoutParams layoutParams = (LayoutParams) child.getLayoutParams(); + layoutParams.width = 0; + int width = (Integer) child.getTag(R.id.width_tag); + layoutParams.weight = width / (float) availableSize; + extraWeight -= layoutParams.weight; + } + extraWeight /= (N - 1); + if (extraWeight > 0) { + for (int a = 0, N2 = getChildCount(); a < N2; a++) { + View child = getChildAt(a); + LayoutParams layoutParams = (LayoutParams) child.getLayoutParams(); + int width = (Integer) child.getTag(R.id.width_tag); + if (width != maxTextWidth[0]) { + layoutParams.weight += extraWeight; + } + } + } + } else { + setWeightSum(0.0f); + for (int a = 0, N2 = getChildCount(); a < N2; a++) { + getChildAt(a).getLayoutParams().width = LayoutHelper.WRAP_CONTENT; + ((LayoutParams) getChildAt(a).getLayoutParams()).weight = 0.0f; + } + } + ignoreLayout = false; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); } - }); - presentFragment(activity); + }; + tipLayout.setOrientation(LinearLayout.HORIZONTAL); + scrollView.addView(tipLayout, LayoutHelper.createScroll(LayoutHelper.MATCH_PARENT, 30, Gravity.LEFT | Gravity.TOP)); + int color = Theme.getColor(Theme.key_contacts_inviteBackground); + for (int a = 0; a < N; a++) { + long amount; + if (LocaleController.isRTL) { + amount = paymentForm.invoice.suggested_tip_amounts.get(N - a - 1); + } else { + amount = paymentForm.invoice.suggested_tip_amounts.get(a); + } + String text = LocaleController.getInstance().formatCurrencyString(amount, paymentForm.invoice.currency); + TextView valueTextView = new TextView(context); + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + valueTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + valueTextView.setLines(1); + valueTextView.setTag(amount); + valueTextView.setMaxLines(1); + valueTextView.setText(text); + valueTextView.setPadding(AndroidUtilities.dp(15), 0, AndroidUtilities.dp(15), 0); + valueTextView.setTextColor(Theme.getColor(Theme.key_chats_secretName)); + valueTextView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(15), color & 0x1fffffff)); + valueTextView.setSingleLine(true); + valueTextView.setGravity(Gravity.CENTER); + tipLayout.addView(valueTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | Gravity.LEFT, 0, 0, a != N -1 ? 9 : 0, 0)); + valueTextView.setOnClickListener(v -> { + long amoumt = (Long) valueTextView.getTag(); + if (tipAmount != null && amoumt == tipAmount) { + inputFields[0].setText(LocaleController.getInstance().formatCurrencyString(0, false, paymentForm.invoice.currency)); + } else { + inputFields[0].setText(LocaleController.getInstance().formatCurrencyString(amount, false, paymentForm.invoice.currency)); + } + inputFields[0].setSelection(inputFields[0].length()); + }); + int width = (int) Math.ceil(valueTextView.getPaint().measureText(text)) + AndroidUtilities.dp(30); + valueTextView.setTag(R.id.width_tag, width); + maxTextWidth[0] = Math.max(maxTextWidth[0], width); + textWidths[0] += width; + } + } + } + + linearLayout2.addView(priceCell); + + sectionCell[2] = new ShadowSectionCell(context); + sectionCell[2].setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + linearLayout2.addView(sectionCell[2], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + detailSettingsCell[0] = new TextDetailSettingsCell(context); + detailSettingsCell[0].setBackgroundDrawable(Theme.getSelectorDrawable(true)); + detailSettingsCell[0].setTextAndValueAndIcon(cardName != null && cardName.length() > 1 ? cardName.substring(0, 1).toUpperCase() + cardName.substring(1) : cardName, LocaleController.getString("PaymentCheckoutMethod", R.string.PaymentCheckoutMethod), R.drawable.payment_card, true); + linearLayout2.addView(detailSettingsCell[0]); + if (currentStep == 4) { + detailSettingsCell[0].setOnClickListener(v -> { + if (getParentActivity() == null) { + return; + } + BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("PaymentCheckoutMethod", R.string.PaymentCheckoutMethod), true); + builder.setItems(new CharSequence[]{cardName, LocaleController.getString("PaymentCheckoutMethodNewCard", R.string.PaymentCheckoutMethodNewCard)}, + new int[]{R.drawable.payment_card, R.drawable.msg_addbot}, (dialog, which) -> { + if (which == 1) { + PaymentFormActivity activity = new PaymentFormActivity(paymentForm, messageObject, 2, requestedInfo, shippingOption, tipAmount, null, cardName, validateRequest, saveCardInfo, null, parentFragment); + activity.setDelegate(new PaymentFormActivityDelegate() { + @Override + public boolean didSelectNewCard(String tokenJson, String card, boolean saveCard, TLRPC.TL_inputPaymentCredentialsGooglePay googlePay) { + paymentForm.saved_credentials = null; + paymentJson = tokenJson; + saveCardInfo = saveCard; + cardName = card; + googlePayCredentials = googlePay; + detailSettingsCell[0].setTextAndValue(cardName, LocaleController.getString("PaymentCheckoutMethod", R.string.PaymentCheckoutMethod), true); + return false; + } + }); + presentFragment(activity); + } + }); + showDialog(builder.create()); }); } @@ -1714,7 +1997,7 @@ public void currentPasswordUpdated(TLRPC.TL_account_password password) { if (providerUser != null) { detailSettingsCell[1] = new TextDetailSettingsCell(context); detailSettingsCell[1].setBackgroundDrawable(Theme.getSelectorDrawable(true)); - detailSettingsCell[1].setTextAndValue(providerName = ContactsController.formatName(providerUser.first_name, providerUser.last_name), LocaleController.getString("PaymentCheckoutProvider", R.string.PaymentCheckoutProvider), true); + detailSettingsCell[1].setTextAndValueAndIcon(providerName = ContactsController.formatName(providerUser.first_name, providerUser.last_name), LocaleController.getString("PaymentCheckoutProvider", R.string.PaymentCheckoutProvider), R.drawable.payment_provider, validateRequest != null && (validateRequest.info.shipping_address != null || shippingOption != null)); linearLayout2.addView(detailSettingsCell[1]); } else { providerName = ""; @@ -1722,45 +2005,105 @@ public void currentPasswordUpdated(TLRPC.TL_account_password password) { if (validateRequest != null) { if (validateRequest.info.shipping_address != null) { - String address = String.format("%s %s, %s, %s, %s, %s", validateRequest.info.shipping_address.street_line1, validateRequest.info.shipping_address.street_line2, validateRequest.info.shipping_address.city, validateRequest.info.shipping_address.state, validateRequest.info.shipping_address.country_iso2, validateRequest.info.shipping_address.post_code); detailSettingsCell[2] = new TextDetailSettingsCell(context); - detailSettingsCell[2].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - detailSettingsCell[2].setTextAndValue(address, LocaleController.getString("PaymentShippingAddress", R.string.PaymentShippingAddress), true); linearLayout2.addView(detailSettingsCell[2]); + if (currentStep == 4) { + detailSettingsCell[2].setBackgroundDrawable(Theme.getSelectorDrawable(true)); + detailSettingsCell[2].setOnClickListener(v -> { + PaymentFormActivity activity = new PaymentFormActivity(paymentForm, messageObject, 0, requestedInfo, shippingOption, tipAmount, null, cardName, validateRequest, saveCardInfo, null, parentFragment); + activity.setDelegate(new PaymentFormActivityDelegate() { + @Override + public void didSelectNewAddress(TLRPC.TL_payments_validateRequestedInfo validateRequested) { + validateRequest = validateRequested; + setAddressFields(); + } + }); + presentFragment(activity); + }); + } else { + detailSettingsCell[2].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } } if (validateRequest.info.name != null) { detailSettingsCell[3] = new TextDetailSettingsCell(context); - detailSettingsCell[3].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - detailSettingsCell[3].setTextAndValue(validateRequest.info.name, LocaleController.getString("PaymentCheckoutName", R.string.PaymentCheckoutName), true); linearLayout2.addView(detailSettingsCell[3]); + if (currentStep == 4) { + detailSettingsCell[3].setBackgroundDrawable(Theme.getSelectorDrawable(true)); + detailSettingsCell[3].setOnClickListener(v -> { + PaymentFormActivity activity = new PaymentFormActivity(paymentForm, messageObject, 0, requestedInfo, shippingOption, tipAmount, null, cardName, validateRequest, saveCardInfo, null, parentFragment); + activity.setDelegate(new PaymentFormActivityDelegate() { + @Override + public void didSelectNewAddress(TLRPC.TL_payments_validateRequestedInfo validateRequested) { + validateRequest = validateRequested; + setAddressFields(); + } + }); + presentFragment(activity); + }); + } else { + detailSettingsCell[3].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } } if (validateRequest.info.phone != null) { detailSettingsCell[4] = new TextDetailSettingsCell(context); - detailSettingsCell[4].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - detailSettingsCell[4].setTextAndValue(PhoneFormat.getInstance().format(validateRequest.info.phone), LocaleController.getString("PaymentCheckoutPhoneNumber", R.string.PaymentCheckoutPhoneNumber), true); linearLayout2.addView(detailSettingsCell[4]); + if (currentStep == 4) { + detailSettingsCell[4].setBackgroundDrawable(Theme.getSelectorDrawable(true)); + detailSettingsCell[4].setOnClickListener(v -> { + PaymentFormActivity activity = new PaymentFormActivity(paymentForm, messageObject, 0, requestedInfo, shippingOption, tipAmount, null, cardName, validateRequest, saveCardInfo, null, parentFragment); + activity.setDelegate(new PaymentFormActivityDelegate() { + @Override + public void didSelectNewAddress(TLRPC.TL_payments_validateRequestedInfo validateRequested) { + validateRequest = validateRequested; + setAddressFields(); + } + }); + presentFragment(activity); + }); + } else { + detailSettingsCell[4].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } } if (validateRequest.info.email != null) { detailSettingsCell[5] = new TextDetailSettingsCell(context); - detailSettingsCell[5].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - detailSettingsCell[5].setTextAndValue(validateRequest.info.email, LocaleController.getString("PaymentCheckoutEmail", R.string.PaymentCheckoutEmail), true); linearLayout2.addView(detailSettingsCell[5]); + if (currentStep == 4) { + detailSettingsCell[5].setBackgroundDrawable(Theme.getSelectorDrawable(true)); + detailSettingsCell[5].setOnClickListener(v -> { + PaymentFormActivity activity = new PaymentFormActivity(paymentForm, messageObject, 0, requestedInfo, shippingOption, tipAmount, null, cardName, validateRequest, saveCardInfo, null, parentFragment); + activity.setDelegate(new PaymentFormActivityDelegate() { + @Override + public void didSelectNewAddress(TLRPC.TL_payments_validateRequestedInfo validateRequested) { + validateRequest = validateRequested; + setAddressFields(); + } + }); + presentFragment(activity); + }); + } else { + detailSettingsCell[5].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } } if (shippingOption != null) { detailSettingsCell[6] = new TextDetailSettingsCell(context); detailSettingsCell[6].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - detailSettingsCell[6].setTextAndValue(shippingOption.title, LocaleController.getString("PaymentCheckoutShippingMethod", R.string.PaymentCheckoutShippingMethod), false); + detailSettingsCell[6].setTextAndValueAndIcon(shippingOption.title, LocaleController.getString("PaymentCheckoutShippingMethod", R.string.PaymentCheckoutShippingMethod), R.drawable.payment_delivery, false); linearLayout2.addView(detailSettingsCell[6]); } + setAddressFields(); } if (currentStep == 4) { bottomLayout = new FrameLayout(context); - bottomLayout.setBackgroundDrawable(Theme.getSelectorDrawable(true)); + if (Build.VERSION.SDK_INT >= 21) { + bottomLayout.setBackgroundDrawable(Theme.getSelectorDrawable(Theme.getColor(Theme.key_listSelector), Theme.key_contacts_inviteBackground)); + } else { + bottomLayout.setBackgroundColor(Theme.getColor(Theme.key_contacts_inviteBackground)); + } frameLayout.addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); bottomLayout.setOnClickListener(v -> { if (botUser != null && !botUser.verified) { @@ -1771,18 +2114,18 @@ public void currentPasswordUpdated(TLRPC.TL_account_password password) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("PaymentWarning", R.string.PaymentWarning)); builder.setMessage(LocaleController.formatString("PaymentWarningText", R.string.PaymentWarningText, currentBotName, providerName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> showPayAlert(totalPrice)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> showPayAlert(totalPrice[0])); showDialog(builder.create()); } else { - showPayAlert(totalPrice); + showPayAlert(totalPrice[0]); } } else { - showPayAlert(totalPrice); + showPayAlert(totalPrice[0]); } }); payTextView = new TextView(context); - payTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText6)); - payTextView.setText(LocaleController.formatString("PaymentCheckoutPay", R.string.PaymentCheckoutPay, totalPrice)); + payTextView.setTextColor(Theme.getColor(Theme.key_contacts_inviteText)); + payTextView.setText(LocaleController.formatString("PaymentCheckoutPay", R.string.PaymentCheckoutPay, totalPrice[0])); payTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); payTextView.setGravity(Gravity.CENTER); payTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -1790,12 +2133,10 @@ public void currentPasswordUpdated(TLRPC.TL_account_password password) { progressViewButton = new ContextProgressView(context, 0); progressViewButton.setVisibility(View.INVISIBLE); + int color = Theme.getColor(Theme.key_contacts_inviteText); + progressViewButton.setColors(color & 0x2fffffff, color); bottomLayout.addView(progressViewButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - View shadow = new View(context); - shadow.setBackgroundResource(R.drawable.header_shadow_reverse); - frameLayout.addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 48)); - doneItem.setEnabled(false); doneItem.getContentView().setVisibility(View.INVISIBLE); @@ -1957,6 +2298,7 @@ public void afterTextChanged(Editable s) { } ViewGroup container = new FrameLayout(context); + container.setClipChildren(false); linearLayout2.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); container.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -2039,6 +2381,35 @@ protected void onDraw(Canvas canvas) { return fragmentView; } + private void checkSelectedTip() { + int color = Theme.getColor(Theme.key_contacts_inviteBackground); + for (int b = 0, N2 = tipLayout.getChildCount(); b < N2; b++) { + View child = tipLayout.getChildAt(b); + int alpha = child.getTag().equals(tipAmount) ? 0x3fffffff : 0x1fffffff; + Theme.setDrawableColor(child.getBackground(), color & alpha); + child.invalidate(); + } + } + + private void setAddressFields() { + if (validateRequest.info.shipping_address != null) { + String address = String.format("%s %s, %s, %s, %s, %s", validateRequest.info.shipping_address.street_line1, validateRequest.info.shipping_address.street_line2, validateRequest.info.shipping_address.city, validateRequest.info.shipping_address.state, validateRequest.info.shipping_address.country_iso2, validateRequest.info.shipping_address.post_code); + detailSettingsCell[2].setTextAndValueAndIcon(address, LocaleController.getString("PaymentShippingAddress", R.string.PaymentShippingAddress), R.drawable.payment_address, true); + } + + if (validateRequest.info.name != null) { + detailSettingsCell[3].setTextAndValueAndIcon(validateRequest.info.name, LocaleController.getString("PaymentCheckoutName", R.string.PaymentCheckoutName), R.drawable.payment_name, true); + } + + if (validateRequest.info.phone != null) { + detailSettingsCell[4].setTextAndValueAndIcon(PhoneFormat.getInstance().format(validateRequest.info.phone), LocaleController.getString("PaymentCheckoutPhoneNumber", R.string.PaymentCheckoutPhoneNumber), R.drawable.payment_phone, validateRequest.info.email != null || shippingOption != null); + } + + if (validateRequest.info.email != null) { + detailSettingsCell[5].setTextAndValueAndIcon(validateRequest.info.email, LocaleController.getString("PaymentCheckoutEmail", R.string.PaymentCheckoutEmail), R.drawable.payment_email, shippingOption != null); + } + } + private void createGooglePayButton(Context context) { googlePayContainer = new FrameLayout(context); googlePayContainer.setBackgroundDrawable(Theme.getSelectorDrawable(true)); @@ -2076,7 +2447,7 @@ private void createGooglePayButton(Context context) { } else { put("parameters", new JSONObject() {{ put("gateway", "stripe"); - put("stripe:publishableKey", stripeApiKey); + put("stripe:publishableKey", providerApiKey); put("stripe:version", StripeApiHandler.VERSION); }}); } @@ -2278,13 +2649,6 @@ private JSONObject getBaseCardPaymentMethod() throws JSONException { parameters.put("allowedAuthMethods", new JSONArray(SUPPORTED_METHODS)); parameters.put("allowedCardNetworks", new JSONArray(SUPPORTED_NETWORKS)); - // Optionally, you can add billing address/phone number associated with a CARD payment method. - /*parameters.put("billingAddressRequired", true); - - JSONObject billingAddressParameters = new JSONObject(); - billingAddressParameters.put("format", "FULL"); - parameters.put("billingAddressParameters", billingAddressParameters);*/ - cardPaymentMethod.put("parameters", parameters); return cardPaymentMethod; @@ -2344,6 +2708,9 @@ private String getTotalPriceString(ArrayList prices) { for (int a = 0; a < prices.size(); a++) { amount += prices.get(a).amount; } + if (tipAmount != null) { + amount += tipAmount; + } return LocaleController.getInstance().formatCurrencyString(amount, paymentForm.invoice.currency); } @@ -2409,11 +2776,17 @@ protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { webView.loadUrl(webViewUrl = paymentForm.url); } } else if (currentStep == 2) { - inputFields[FIELD_CARD].requestFocus(); - AndroidUtilities.showKeyboard(inputFields[FIELD_CARD]); + AndroidUtilities.runOnUIThread(() -> { + inputFields[FIELD_CARD].requestFocus(); + AndroidUtilities.showKeyboard(inputFields[FIELD_CARD]); + }, 100); } else if (currentStep == 3) { inputFields[FIELD_SAVEDPASSWORD].requestFocus(); AndroidUtilities.showKeyboard(inputFields[FIELD_SAVEDPASSWORD]); + } else if (currentStep == 4) { + if (inputFields != null) { + inputFields[0].requestFocus(); + } } else if (currentStep == 6) { if (!waitingForEmail) { inputFields[FIELD_ENTERPASSWORD].requestFocus(); @@ -2444,6 +2817,9 @@ public void onActivityResultFragment(int requestCode, int resultCode, Intent dat AndroidUtilities.runOnUIThread(() -> { if (resultCode == Activity.RESULT_OK) { PaymentData paymentData = PaymentData.getFromIntent(data); + if (paymentData == null) { + return; + } final String paymentInfo = paymentData.toJson(); if (paymentInfo == null) { return; @@ -2477,7 +2853,7 @@ public void onActivityResultFragment(int requestCode, int resultCode, Intent dat } else { if (resultCode == AutoResolveHelper.RESULT_ERROR) { Status status = AutoResolveHelper.getStatusFromIntent(data); - FileLog.e("android pay error " + status.getStatusMessage()); + FileLog.e("android pay error " + (status != null ? status.getStatusMessage() : "")); } } showEditDoneProgress(true, false); @@ -2489,25 +2865,30 @@ public void onActivityResultFragment(int requestCode, int resultCode, Intent dat private void goToNextStep() { if (currentStep == 0) { - int nextStep; - if (paymentForm.invoice.flexible) { - nextStep = 1; - } else if (paymentForm.saved_credentials != null) { - if (UserConfig.getInstance(currentAccount).tmpPassword != null) { - if (UserConfig.getInstance(currentAccount).tmpPassword.valid_until < ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 60) { - UserConfig.getInstance(currentAccount).tmpPassword = null; - UserConfig.getInstance(currentAccount).saveConfig(false); + if (delegate != null) { + delegate.didSelectNewAddress(validateRequest); + finishFragment(); + } else { + int nextStep; + if (paymentForm.invoice.flexible) { + nextStep = 1; + } else if (paymentForm.saved_credentials != null) { + if (UserConfig.getInstance(currentAccount).tmpPassword != null) { + if (UserConfig.getInstance(currentAccount).tmpPassword.valid_until < ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 60) { + UserConfig.getInstance(currentAccount).tmpPassword = null; + UserConfig.getInstance(currentAccount).saveConfig(false); + } + } + if (UserConfig.getInstance(currentAccount).tmpPassword != null) { + nextStep = 4; + } else { + nextStep = 3; } - } - if (UserConfig.getInstance(currentAccount).tmpPassword != null) { - nextStep = 4; } else { - nextStep = 3; + nextStep = 2; } - } else { - nextStep = 2; + presentFragment(new PaymentFormActivity(paymentForm, messageObject, nextStep, requestedInfo, null, null, null, cardName, validateRequest, saveCardInfo, googlePayCredentials, parentFragment), isWebView); } - presentFragment(new PaymentFormActivity(paymentForm, messageObject, nextStep, requestedInfo, null, null, cardName, validateRequest, saveCardInfo, googlePayCredentials), isWebView); } else if (currentStep == 1) { int nextStep; if (paymentForm.saved_credentials != null) { @@ -2525,10 +2906,10 @@ private void goToNextStep() { } else { nextStep = 2; } - presentFragment(new PaymentFormActivity(paymentForm, messageObject, nextStep, requestedInfo, shippingOption, null, cardName, validateRequest, saveCardInfo, googlePayCredentials), isWebView); + presentFragment(new PaymentFormActivity(paymentForm, messageObject, nextStep, requestedInfo, shippingOption, tipAmount, null, cardName, validateRequest, saveCardInfo, googlePayCredentials, parentFragment), isWebView); } else if (currentStep == 2) { if (paymentForm.password_missing && saveCardInfo) { - passwordFragment = new PaymentFormActivity(paymentForm, messageObject, 6, requestedInfo, shippingOption, paymentJson, cardName, validateRequest, saveCardInfo, googlePayCredentials); + passwordFragment = new PaymentFormActivity(paymentForm, messageObject, 6, requestedInfo, shippingOption, tipAmount, paymentJson, cardName, validateRequest, saveCardInfo, googlePayCredentials, parentFragment); passwordFragment.setCurrentPassword(currentPassword); passwordFragment.setDelegate(new PaymentFormActivityDelegate() { @Override @@ -2558,7 +2939,7 @@ public void currentPasswordUpdated(TLRPC.TL_account_password password) { delegate.didSelectNewCard(paymentJson, cardName, saveCardInfo, googlePayCredentials); finishFragment(); } else { - presentFragment(new PaymentFormActivity(paymentForm, messageObject, 4, requestedInfo, shippingOption, paymentJson, cardName, validateRequest, saveCardInfo, googlePayCredentials), isWebView); + presentFragment(new PaymentFormActivity(paymentForm, messageObject, 4, requestedInfo, shippingOption, tipAmount, paymentJson, cardName, validateRequest, saveCardInfo, googlePayCredentials, parentFragment), isWebView); } } } else if (currentStep == 3) { @@ -2568,13 +2949,13 @@ public void currentPasswordUpdated(TLRPC.TL_account_password password) { } else { nextStep = 2; } - presentFragment(new PaymentFormActivity(paymentForm, messageObject, nextStep, requestedInfo, shippingOption, paymentJson, cardName, validateRequest, saveCardInfo, googlePayCredentials), !passwordOk); + presentFragment(new PaymentFormActivity(paymentForm, messageObject, nextStep, requestedInfo, shippingOption, tipAmount, paymentJson, cardName, validateRequest, saveCardInfo, googlePayCredentials, parentFragment), true); } else if (currentStep == 4) { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.paymentFinished); finishFragment(); } else if (currentStep == 6) { if (!delegate.didSelectNewCard(paymentJson, cardName, saveCardInfo, googlePayCredentials)) { - presentFragment(new PaymentFormActivity(paymentForm, messageObject, 4, requestedInfo, shippingOption, paymentJson, cardName, validateRequest, saveCardInfo, googlePayCredentials), true); + presentFragment(new PaymentFormActivity(paymentForm, messageObject, 4, requestedInfo, shippingOption, tipAmount, paymentJson, cardName, validateRequest, saveCardInfo, googlePayCredentials, parentFragment), true); } else { finishFragment(); } @@ -2585,7 +2966,7 @@ private void updateSavePaymentField() { if (bottomCell[0] == null || sectionCell[2] == null) { return; } - if ((paymentForm.password_missing || paymentForm.can_save_credentials) && (webView == null || webView != null && !webviewLoading)) { + if ((paymentForm.password_missing || paymentForm.can_save_credentials) && (webView == null || !webviewLoading)) { SpannableStringBuilder text = new SpannableStringBuilder(LocaleController.getString("PaymentCardSavePaymentInformationInfoLine1", R.string.PaymentCardSavePaymentInformationInfoLine1)); if (paymentForm.password_missing) { loadPasswordInfo(); @@ -2746,10 +3127,8 @@ private void sendSavePassword(final boolean clear) { req.new_settings.hint = ""; req.new_settings.new_algo = currentPassword.new_algo; - if (email.length() > 0) { - req.new_settings.flags |= 2; - req.new_settings.email = email.trim(); - } + req.new_settings.flags |= 2; + req.new_settings.email = email.trim(); } showEditDoneProgress(true, true); Utilities.globalQueue.postRunnable(() -> { @@ -2880,46 +3259,129 @@ private boolean sendCardData() { } showEditDoneProgress(true, true); try { - Stripe stripe = new Stripe(stripeApiKey); - stripe.createToken(card, new TokenCallback() { - public void onSuccess(Token token) { - if (canceled) { - return; + if ("stripe".equals(paymentForm.native_provider)) { + Stripe stripe = new Stripe(providerApiKey); + stripe.createToken(card, new TokenCallback() { + public void onSuccess(Token token) { + if (canceled) { + return; + } + paymentJson = String.format(Locale.US, "{\"type\":\"%1$s\", \"id\":\"%2$s\"}", token.getType(), token.getId()); + AndroidUtilities.runOnUIThread(() -> { + goToNextStep(); + showEditDoneProgress(true, false); + setDonePressed(false); + }); } - paymentJson = String.format(Locale.US, "{\"type\":\"%1$s\", \"id\":\"%2$s\"}", token.getType(), token.getId()); - AndroidUtilities.runOnUIThread(() -> { - goToNextStep(); + + public void onError(Exception error) { + if (canceled) { + return; + } showEditDoneProgress(true, false); setDonePressed(false); - }); + if (error instanceof APIConnectionException || error instanceof APIException) { + AlertsCreator.showSimpleToast(PaymentFormActivity.this, LocaleController.getString("PaymentConnectionFailed", R.string.PaymentConnectionFailed)); + } else { + AlertsCreator.showSimpleToast(PaymentFormActivity.this, error.getMessage()); + } + } } - - public void onError(Exception error) { - if (canceled) { - return; + ); + } else if ("smartglocal".equals(paymentForm.native_provider)) { + AsyncTask task = new AsyncTask() { + @Override + protected String doInBackground(Object... objects) { + HttpURLConnection conn = null; + try { + JSONObject jsonObject = new JSONObject(); + JSONObject cardObject = new JSONObject(); + cardObject.put("number", card.getNumber()); + cardObject.put("expiration_month", String.format(Locale.US, "%02d", card.getExpMonth())); + cardObject.put("expiration_year", "" + card.getExpYear()); + cardObject.put("security_code", "" + card.getCVC()); + jsonObject.put("card", cardObject); + + URL connectionUrl; + if (paymentForm.invoice.test) { + connectionUrl = new URL("https://tgb-playground.smart-glocal.com/cds/v1/tokenize/card"); + } else { + connectionUrl = new URL("https://tgb.smart-glocal.com/cds/v1/tokenize/card"); } - showEditDoneProgress(true, false); - setDonePressed(false); - if (error instanceof APIConnectionException || error instanceof APIException) { - AlertsCreator.showSimpleToast(PaymentFormActivity.this, LocaleController.getString("PaymentConnectionFailed", R.string.PaymentConnectionFailed)); + conn = (HttpURLConnection) connectionUrl.openConnection(); + conn.setConnectTimeout(30 * 1000); + conn.setReadTimeout(80 * 1000); + conn.setUseCaches(false); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/json"); + conn.setRequestProperty("X-PUBLIC-TOKEN", providerApiKey); + + try (OutputStream output = conn.getOutputStream()) { + output.write(jsonObject.toString().getBytes("UTF-8")); + } + + int code = conn.getResponseCode(); + if (code >= 200 && code < 300) { + JSONObject result = new JSONObject(); + JSONObject jsonObject1 = new JSONObject(getResponseBody(conn.getInputStream())); + String token = jsonObject1.getJSONObject("data").getString("token"); + result.put("token", token); + result.put("type", "card"); + return result.toString(); } else { - AlertsCreator.showSimpleToast(PaymentFormActivity.this, error.getMessage()); + if (BuildVars.DEBUG_VERSION) { + FileLog.e("" + getResponseBody(conn.getErrorStream())); + } + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (conn != null) { + conn.disconnect(); } } + return null; + } + + @Override + protected void onPostExecute(String result) { + if (canceled) { + return; + } + if (result == null) { + AlertsCreator.showSimpleToast(PaymentFormActivity.this, LocaleController.getString("PaymentConnectionFailed", R.string.PaymentConnectionFailed)); + } else { + paymentJson = result; + goToNextStep(); + } + showEditDoneProgress(true, false); + setDonePressed(false); } - ); + }; + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null); + } } catch (Exception e) { FileLog.e(e); } return true; } + private static String getResponseBody(InputStream responseStream) throws IOException { + String rBody = new Scanner(responseStream, "UTF-8") + .useDelimiter("\\A") + .next(); + responseStream.close(); + return rBody; + } + private void sendForm() { if (canceled) { return; } showEditDoneProgress(true, true); validateRequest = new TLRPC.TL_payments_validateRequestedInfo(); + validateRequest.peer = getMessagesController().getInputPeer(messageObject.messageOwner.peer_id); validateRequest.save = saveShippingInfo; validateRequest.msg_id = messageObject.getId(); validateRequest.info = new TLRPC.TL_paymentRequestedInfo(); @@ -3004,33 +3466,6 @@ private void sendForm() { }, ConnectionsManager.RequestFlagFailOnServerErrors); } - private TLRPC.TL_paymentRequestedInfo getRequestInfo() { - TLRPC.TL_paymentRequestedInfo info = new TLRPC.TL_paymentRequestedInfo(); - if (paymentForm.invoice.name_requested) { - info.name = inputFields[FIELD_NAME].getText().toString(); - info.flags |= 1; - } - if (paymentForm.invoice.phone_requested) { - info.phone = "+" + inputFields[FIELD_PHONECODE].getText().toString() + inputFields[FIELD_PHONE].getText().toString(); - info.flags |= 2; - } - if (paymentForm.invoice.email_requested) { - info.email = inputFields[FIELD_EMAIL].getText().toString().trim(); - info.flags |= 4; - } - if (paymentForm.invoice.shipping_address_requested) { - info.shipping_address = new TLRPC.TL_postAddress(); - info.shipping_address.street_line1 = inputFields[FIELD_STREET1].getText().toString(); - info.shipping_address.street_line2 = inputFields[FIELD_STREET2].getText().toString(); - info.shipping_address.city = inputFields[FIELD_CITY].getText().toString(); - info.shipping_address.state = inputFields[FIELD_STATE].getText().toString(); - info.shipping_address.country_iso2 = countryName != null ? countryName : ""; - info.shipping_address.post_code = inputFields[FIELD_POSTCODE].getText().toString(); - info.flags |= 8; - } - return info; - } - private void sendData() { if (canceled) { return; @@ -3038,6 +3473,8 @@ private void sendData() { showEditDoneProgress(false, true); final TLRPC.TL_payments_sendPaymentForm req = new TLRPC.TL_payments_sendPaymentForm(); req.msg_id = messageObject.getId(); + req.peer = getMessagesController().getInputPeer(messageObject.messageOwner.peer_id); + req.form_id = paymentForm.form_id; if (UserConfig.getInstance(currentAccount).tmpPassword != null && paymentForm.saved_credentials != null) { req.credentials = new TLRPC.TL_inputPaymentCredentialsSaved(); req.credentials.id = paymentForm.saved_credentials.id; @@ -3058,11 +3495,33 @@ private void sendData() { req.shipping_option_id = shippingOption.id; req.flags |= 2; } + if ((paymentForm.invoice.flags & 256) != 0) { + req.tip_amount = tipAmount != null ? tipAmount : 0; + req.flags |= 4; + } ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (response != null) { if (response instanceof TLRPC.TL_payments_paymentResult) { - MessagesController.getInstance(currentAccount).processUpdates(((TLRPC.TL_payments_paymentResult) response).updates, false); - AndroidUtilities.runOnUIThread(this::goToNextStep); + TLRPC.Updates updates = ((TLRPC.TL_payments_paymentResult) response).updates; + TLRPC.Message[] message = new TLRPC.Message[1]; + for (int a = 0, N = updates.updates.size(); a < N; a++) { + TLRPC.Update update = updates.updates.get(a); + if (update instanceof TLRPC.TL_updateNewMessage) { + message[0] = ((TLRPC.TL_updateNewMessage) update).message; + break; + } else if (update instanceof TLRPC.TL_updateNewChannelMessage) { + message[0] = ((TLRPC.TL_updateNewChannelMessage) update).message; + break; + } + } + getMessagesController().processUpdates(updates, false); + AndroidUtilities.runOnUIThread(() -> { + goToNextStep(); + if (parentFragment instanceof ChatActivity) { + CharSequence info = AndroidUtilities.replaceTags(LocaleController.formatString("PaymentInfoHint", R.string.PaymentInfoHint, totalPrice[0], currentItemName)); + ((ChatActivity) parentFragment).getUndoView().showWithAction(0, UndoView.ACTION_PAYMENT_SUCCESS, info, message[0], null, null); + } + }); } else if (response instanceof TLRPC.TL_payments_paymentVerificationNeeded) { AndroidUtilities.runOnUIThread(() -> { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.paymentFinished); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index abe0c4b6b1b..a2d5d0d8cf7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -481,6 +481,16 @@ public void run() { public final static int SELECT_TYPE_WALLPAPER = 3; public final static int SELECT_TYPE_QR = 10; + private boolean longPressed; + private int rewindCount; + private boolean rewindForward; + private boolean rewindByBackSeek; + private long startRewindFrom; + private Runnable updateRewindRunnable; + private long rewindLastTime; + private long rewindLastUpdatePlayerTime; + private long rewindBackSeekPlayerPosition; + public final Property FLASH_VIEW_VALUE = new AnimationProperties.FloatProperty("flashViewAlpha") { @Override public void setValue(View object, float value) { @@ -750,8 +760,8 @@ public void run() { videoPlayerSeekbar.setProgress(progress); } } else { - if (seekToProgressPending == 0) { - videoPlayerSeekbar.setProgress(progress); + if (seekToProgressPending == 0 && (rewindCount == 0 || !rewindByBackSeek)) { + videoPlayerSeekbar.setProgress(progress, false); } if (bufferedProgress != -1) { videoPlayerSeekbar.setBufferedProgress(bufferedProgress); @@ -1452,16 +1462,16 @@ public void setProgress(float value, boolean animated) { parent.invalidate(); } - public void setBackgroundState(int state, boolean animated) { + public void setBackgroundState(int state, boolean animated, boolean animateIcon) { if (backgroundState == state) { return; } if (playPauseDrawable != null) { - boolean animateIcon = backgroundState == 3 || backgroundState == 4; + boolean animatePlayPause = animateIcon && (backgroundState == 3 || backgroundState == 4); if (state == 3) { - playPauseDrawable.setPause(false, animateIcon); + playPauseDrawable.setPause(false, animatePlayPause); } else if (state == 4) { - playPauseDrawable.setPause(true, animateIcon); + playPauseDrawable.setPause(true, animatePlayPause); } playPauseDrawable.setParent(parent); playPauseDrawable.invalidateSelf(); @@ -3018,9 +3028,9 @@ public void didReceivedNotification(int id, int account, Object... args) { if (user != null || chat != null) { ImageLocation location; if (user != null) { - location = ImageLocation.getForUser(user, true); + location = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_BIG); } else { - location = ImageLocation.getForChat(chat, true); + location = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_BIG); } if (location != null) { imagesArrLocations.add(0, location); @@ -3196,7 +3206,7 @@ public void didReceivedNotification(int id, int account, Object... args) { if (finalSize != 0) { requestingPreview = false; photoProgressViews[0].setProgress(1f, true); - photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, true); + photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, true, true); preparePlayer(Uri.fromFile(new File(finalPath)), false, true, editState.savedFilterState); } } @@ -3918,7 +3928,7 @@ public void onItemClick(int id) { if (avatarsDialogId > 0) { MessagesController.getInstance(currentAccount).deleteUserPhoto(null); } else { - MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, null, null, null, 0, null, null, null); + MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, null, null, null, 0, null, null, null, null); } closePhoto(false, false); } else { @@ -4106,7 +4116,7 @@ public void dismiss() { 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); + MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, inputChatPhoto, 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; @@ -4352,7 +4362,7 @@ protected void onVisibilityChanged(boolean visible) { } } }; - photoProgressViews[a].setBackgroundState(PROGRESS_EMPTY, false); + photoProgressViews[a].setBackgroundState(PROGRESS_EMPTY, false, true); } miniProgressView = new RadialProgressView(activityContext) { @@ -6669,17 +6679,17 @@ private void updatePlayerState(boolean playWhenReady, int playbackState) { if (videoPlayer.isPlaying() && playbackState != ExoPlayer.STATE_ENDED) { if (!isPlaying) { isPlaying = true; - photoProgressViews[0].setBackgroundState(isCurrentVideo ? PROGRESS_NONE : PROGRESS_PAUSE, false); + photoProgressViews[0].setBackgroundState(isCurrentVideo ? PROGRESS_NONE : PROGRESS_PAUSE, false, true); photoProgressViews[0].setIndexedAlpha(1, !isCurrentVideo && (!isAccessibilityEnabled() || playerWasPlaying) && ((playerAutoStarted && !playerWasPlaying) || !isActionBarVisible) ? 0f : 1f, false); playerWasPlaying = true; AndroidUtilities.runOnUIThread(updateProgressRunnable); } } else if (isPlaying || playbackState == ExoPlayer.STATE_ENDED) { - isPlaying = false; if (currentEditMode != 3) { photoProgressViews[0].setIndexedAlpha(1, 1f, false); - photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false); + photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false, isPlaying); } + isPlaying = false; AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); if (playbackState == ExoPlayer.STATE_ENDED) { if (isCurrentVideo) { @@ -9412,7 +9422,7 @@ private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLoca } for (int a = 0; a < 3; a++) { if (photoProgressViews[a] != null) { - photoProgressViews[a].setBackgroundState(PROGRESS_NONE, false); + photoProgressViews[a].setBackgroundState(PROGRESS_NONE, false, true); } } if (groupedPhotosListView != null) { @@ -9494,10 +9504,10 @@ private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLoca if (imageLocation == null && avatarsDialogId != 0) { if (avatarsDialogId > 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(avatarsDialogId); - imageLocation = ImageLocation.getForUser(user, true); + imageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_BIG); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-avatarsDialogId); - imageLocation = ImageLocation.getForChat(chat, true); + imageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_BIG); } } if (imageLocation == null) { @@ -10740,13 +10750,13 @@ private void checkProgress(int a, boolean scroll, boolean animated) { MessageObject messageObject = null; if (currentMessageObject != null) { if (index < 0 || index >= imagesArr.size()) { - photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated, true); return; } messageObject = imagesArr.get(index); canAutoPlay = shouldMessageObjectAutoPlayed(messageObject); if (sharedMediaType == MediaDataController.MEDIA_FILE && !messageObject.canPreviewDocument()) { - photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated, true); return; } if (!TextUtils.isEmpty(messageObject.messageOwner.attachPath)) { @@ -10764,7 +10774,7 @@ private void checkProgress(int a, boolean scroll, boolean animated) { } } else if (currentBotInlineResult != null) { if (index < 0 || index >= imagesArrLocals.size()) { - photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated, true); return; } TLRPC.BotInlineResult botInlineResult = (TLRPC.BotInlineResult) imagesArrLocals.get(index); @@ -10783,14 +10793,14 @@ private void checkProgress(int a, boolean scroll, boolean animated) { f2 = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), currentFileNames[a]); } else if (currentFileLocation != null) { if (index < 0 || index >= imagesArrLocationsVideo.size()) { - photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated, true); return; } ImageLocation location = imagesArrLocationsVideo.get(index); f1 = FileLoader.getPathToAttach(location.location, getFileLocationExt(location), avatarsDialogId != 0 || isEvent); } else if (currentSecureDocument != null) { if (index < 0 || index >= secureDocuments.size()) { - photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated, true); return; } SecureDocument location = secureDocuments.get(index); @@ -10832,9 +10842,9 @@ private void checkProgress(int a, boolean scroll, boolean animated) { if ((f1Final != null || f2Final != null) && (existsFinal || canStreamFinal)) { if (a != 0 || !isPlaying) { if (isVideoFinal && (!canAutoPlayFinal || a == 0 && playerWasPlaying)) { - photoProgressViews[a].setBackgroundState(PROGRESS_PLAY, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_PLAY, animated, true); } else { - photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated, true); } } if (a == 0) { @@ -10851,12 +10861,12 @@ private void checkProgress(int a, boolean scroll, boolean animated) { } else { if (isVideoFinal) { if (!FileLoader.getInstance(currentAccount).isLoadingFile(currentFileNames[a])) { - photoProgressViews[a].setBackgroundState(PROGRESS_LOAD, false); + photoProgressViews[a].setBackgroundState(PROGRESS_LOAD, false, true); } else { - photoProgressViews[a].setBackgroundState(PROGRESS_CANCEL, false); + photoProgressViews[a].setBackgroundState(PROGRESS_CANCEL, false, true); } } else { - photoProgressViews[a].setBackgroundState(PROGRESS_EMPTY, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_EMPTY, animated, true); } Float progress = ImageLoader.getInstance().getFileProgress(currentFileNames[a]); if (progress == null) { @@ -10879,9 +10889,9 @@ private void checkProgress(int a, boolean scroll, boolean animated) { } } if (isLocalVideo) { - photoProgressViews[a].setBackgroundState(PROGRESS_PLAY, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_PLAY, animated, true); } else { - photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); + photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated, true); } } } @@ -11018,7 +11028,7 @@ private void setIndexToImage(ImageReceiver imageReceiver, int index) { imageReceiver.setImage(ImageLocation.getForObject(photo, photoObject), filter, placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, imageSize, null, object, cacheType); } else if (webDocument != null) { if (videoThumb != null) { - imageReceiver.setImage(ImageLocation.getForWebFile(webDocument), filter, videoThumb, null, null, object, cacheType); + imageReceiver.setImage(ImageLocation.getForWebFile(webDocument), filter, videoThumb, null, (Drawable) null, object, cacheType); } else { imageReceiver.setImage(ImageLocation.getForWebFile(webDocument), filter, placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : (isVideo && parentActivity != null ? parentActivity.getResources().getDrawable(R.drawable.nophotos) : null), null, object, cacheType); } @@ -12400,7 +12410,7 @@ private void onPhotoClosed(PlaceProviderObject object) { } for (int a = 0; a < 3; a++) { if (photoProgressViews[a] != null) { - photoProgressViews[a].setBackgroundState(PROGRESS_NONE, false); + photoProgressViews[a].setBackgroundState(PROGRESS_NONE, false, true); } } requestVideoPreview(0); @@ -12578,6 +12588,14 @@ private int getContainerViewHeight(boolean trueHeight, int mode) { return height; } + float longPressX; + Runnable longPressRunnable = new Runnable() { + @Override + public void run() { + onLongPress(); + } + }; + private boolean onTouchEvent(MotionEvent ev) { if (currentEditMode == 3 && animationStartTime != 0 && (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN)) { if (ev.getPointerCount() >= 2) { @@ -12590,6 +12608,14 @@ private boolean onTouchEvent(MotionEvent ev) { return false; } + if (rewindCount > 0) { + if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL ) { + cancelRewind(); + return false; + } + return true; + } + if (currentEditMode == 2) { photoFilterView.onTouch(ev); return true; @@ -12672,7 +12698,14 @@ private boolean onTouchEvent(MotionEvent ev) { } } } + if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { + longPressX = ev.getX(); + AndroidUtilities.runOnUIThread(longPressRunnable, 300); + } else { + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); + } } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) { + if (canZoom && ev.getPointerCount() == 2 && !draggingDown && zooming && !changingPage) { discardTap = true; if (currentEditMode == 3) { @@ -12714,6 +12747,7 @@ private boolean onTouchEvent(MotionEvent ev) { if (dx > touchSlop || dy > touchSlop) { discardTap = true; hidePressedDrawables(); + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); if (qualityChooseView != null && qualityChooseView.getVisibility() == View.VISIBLE) { return true; } @@ -12779,6 +12813,7 @@ private boolean onTouchEvent(MotionEvent ev) { } } } else if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL || ev.getActionMasked() == MotionEvent.ACTION_UP || ev.getActionMasked() == MotionEvent.ACTION_POINTER_UP) { + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); if (paintViewTouched == 1) { if (photoPaintView != null) { MotionEvent event = MotionEvent.obtain(ev); @@ -12999,6 +13034,7 @@ private void switchToNextIndex(int add, boolean init) { onActionClick(true); checkProgress(0, false, true); } + checkFullscreenButton(); } private boolean shouldMessageObjectAutoPlayed(MessageObject messageObject) { @@ -13775,11 +13811,172 @@ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float d return false; } + private final Runnable backSeek = new Runnable() { + @Override + public void run() { + long duration = videoPlayer.getDuration(); + if (duration == 0 || duration == C.TIME_UNSET) { + rewindLastTime = System.currentTimeMillis(); + return; + } + + long t = System.currentTimeMillis(); + long dt = t - rewindLastTime; + rewindLastTime = t; + if (rewindCount == 1) { + dt *= 3; + } else if (rewindCount == 2) { + dt *= 6; + } else { + dt *= 12; + } + if (rewindForward) { + rewindBackSeekPlayerPosition += dt; + } else { + rewindBackSeekPlayerPosition -= dt; + } + if (rewindBackSeekPlayerPosition < 0) { + rewindBackSeekPlayerPosition = 0; + } else if (rewindBackSeekPlayerPosition > duration) { + rewindBackSeekPlayerPosition = duration; + } + if (rewindByBackSeek && videoPlayer != null && rewindLastTime - rewindLastUpdatePlayerTime > 350) { + rewindLastUpdatePlayerTime = rewindLastTime; + videoPlayer.seekTo(rewindBackSeekPlayerPosition); + } + + if (videoPlayer != null) { + long timeDiff = rewindBackSeekPlayerPosition - startRewindFrom; + videoForwardDrawable.setTime(Math.abs(timeDiff)); + if (rewindByBackSeek) { + videoPlayerSeekbar.setProgress(rewindBackSeekPlayerPosition / (float) videoPlayer.getDuration()); + videoPlayerSeekbarView.invalidate(); + } + } + + if (rewindBackSeekPlayerPosition == 0 || rewindBackSeekPlayerPosition >= duration) { + if (rewindByBackSeek && videoPlayer != null) { + rewindLastUpdatePlayerTime = rewindLastTime; + videoPlayer.seekTo(rewindBackSeekPlayerPosition); + } + cancelRewind(); + onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0)); + } + if (rewindCount > 0) { + AndroidUtilities.runOnUIThread(backSeek, 16); + } + } + }; + @Override - public void onLongPress(MotionEvent e) { + public void onLongPress(MotionEvent ev) { + + } + + public void onLongPress() { + longPressed = true; + if (videoPlayer != null && videoPlayerControlVisible) { + long current = videoPlayer.getCurrentPosition(); + long total = videoPlayer.getDuration(); + if (current == C.TIME_UNSET || total < 15 * 1000) { + return; + } + float x = longPressX; + int width = getContainerViewWidth(); + boolean forward; + if (x >= width / 3 * 2) { + forward = true; + } else if (x < width / 3) { + forward = false; + } else { + return; + } + rewindForward = forward; + cancelRewind(); + incrementRewindCount(); + } + } + + private void cancelRewind() { + if (rewindCount != 0) { + rewindCount = 0; + + if (videoPlayer != null) { + if (rewindByBackSeek) { + videoPlayer.seekTo(rewindBackSeekPlayerPosition); + } else { + long current = videoPlayer.getCurrentPosition(); + videoPlayer.seekTo(current); + } + videoPlayer.setPlaybackSpeed(1); + } + } + AndroidUtilities.cancelRunOnUIThread(backSeek); + + if (updateRewindRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(updateRewindRunnable); + updateRewindRunnable = null; + } + videoForwardDrawable.setShowing(false); } + void incrementRewindCount() { + if (videoPlayer == null) { + return; + } + rewindCount++; + boolean needUpdate = false; + if (rewindCount == 1) { + if (rewindForward && videoPlayer.isPlaying()) { + rewindByBackSeek = false; + } else { + rewindByBackSeek = true; + } + } + if (rewindForward && !rewindByBackSeek) { + if (rewindCount == 1) { + videoPlayer.setPlaybackSpeed(4); + needUpdate = true; + } else if (rewindCount == 2) { + videoPlayer.setPlaybackSpeed(7); + needUpdate = true; + } else { + videoPlayer.setPlaybackSpeed(13); + } + } else { + if (rewindCount == 1 || rewindCount == 2) { + needUpdate = true; + } + } + + + if (rewindCount == 1) { + rewindBackSeekPlayerPosition = videoPlayer.getCurrentPosition(); + rewindLastTime = System.currentTimeMillis(); + rewindLastUpdatePlayerTime = rewindLastTime; + startRewindFrom = videoPlayer.getCurrentPosition(); + videoForwardDrawable.setOneShootAnimation(false); + videoForwardDrawable.setLeftSide(!rewindForward); + videoForwardDrawable.setShowing(true); + containerView.invalidate(); + } + + AndroidUtilities.cancelRunOnUIThread(backSeek); + AndroidUtilities.runOnUIThread(backSeek); + + if (needUpdate) { + if (updateRewindRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(updateRewindRunnable); + } + AndroidUtilities.runOnUIThread(updateRewindRunnable = () -> { + updateRewindRunnable = null; + incrementRewindCount(); + }, 2000); + } + } + + @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (scale != 1) { @@ -13913,6 +14110,7 @@ public boolean onDoubleTap(MotionEvent e) { current = 0; } if (apply) { + videoForwardDrawable.setOneShootAnimation(true); videoForwardDrawable.setLeftSide(x < width / 3); videoForwardDrawable.addTime(10000); videoPlayer.seekTo(current); @@ -14251,7 +14449,7 @@ private void requestVideoPreview(int request) { if (resultHeight == originalHeight && resultWidth == originalWidth) { tryStartRequestPreviewOnFinish = false; photoProgressViews[0].setProgress(0,photoProgressViews[0].backgroundState == 0 || photoProgressViews[0].previousBackgroundState == 0); - photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false); + photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false, true); if (!wasRequestingPreview) { preparePlayer(currentPlayingVideoFile, false, false, editState.savedFilterState); videoPlayer.seekTo((long) (videoTimelineView.getLeftProgress() * videoDuration)); @@ -14299,11 +14497,11 @@ private void requestVideoPreview(int request) { requestingPreview = true; photoProgressViews[0].setProgress(0,photoProgressViews[0].backgroundState == 0 || photoProgressViews[0].previousBackgroundState == 0); - photoProgressViews[0].setBackgroundState(PROGRESS_EMPTY, false); + photoProgressViews[0].setBackgroundState(PROGRESS_EMPTY, false, true); } } else { tryStartRequestPreviewOnFinish = false; - photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false); + photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false, true); if (request == 2) { preparePlayer(currentPlayingVideoFile, false, false, editState.savedFilterState); videoPlayer.seekTo((long) (videoTimelineView.getLeftProgress() * videoDuration)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java new file mode 100644 index 00000000000..71cfe9f19d2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java @@ -0,0 +1,708 @@ +package org.telegram.ui; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.TextureView; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.widget.FrameLayout; + +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.R; +import org.telegram.messenger.WebFile; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedFileDrawable; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; + +public class PinchToZoomHelper { + + private final ViewGroup parentView; + + private ZoomOverlayView overlayView; + private View child; + private ImageReceiver childImage; + + private ImageReceiver fullImage = new ImageReceiver(); + + private boolean inOverlayMode; + + float parentOffsetX; + float parentOffsetY; + + float pinchCenterX; + float pinchCenterY; + + private float imageX; + private float imageY; + private float imageHeight; + private float imageWidth; + + private float fullImageHeight; + private float fullImageWidth; + + private float finishProgress; + private float progressToFullView; + ValueAnimator finishTransition; + private MessageObject messageObject; + + Callback callback; + ClipBoundsListener clipBoundsListener; + + float pinchStartCenterX; + float pinchStartCenterY; + float pinchStartDistance; + float pinchTranslationX; + float pinchTranslationY; + boolean isInPinchToZoomTouchMode; + + private int pointerId1, pointerId2; + + float pinchScale; + + private float enterProgress; + private float[] clipTopBottom = new float[2]; + + private boolean isHardwareVideo; + + public PinchToZoomHelper(ViewGroup parentView) { + this.parentView = parentView; + } + + public void startZoom(View child, ImageReceiver image, MessageObject messageObject) { + this.child = child; + this.messageObject = messageObject; + + if (overlayView == null) { + overlayView = new ZoomOverlayView(parentView.getContext()); + overlayView.setFocusable(false); + overlayView.setFocusableInTouchMode(false); + overlayView.setEnabled(false); + } + + if (fullImage == null) { + fullImage = new ImageReceiver(); + fullImage.setCrossfadeAlpha((byte) 2); + fullImage.setCrossfadeWithOldImage(false); + fullImage.onAttachedToWindow(); + } + + inOverlayMode = true; + parentView.addView(overlayView); + finishProgress = 1f; + progressToFullView = 0f; + + setFullImage(messageObject); + + imageX = image.getImageX(); + imageY = image.getImageY(); + imageHeight = image.getImageHeight(); + imageWidth = image.getImageWidth(); + fullImageHeight = image.getBitmapHeight(); + fullImageWidth = image.getBitmapWidth(); + + if (fullImageHeight / fullImageWidth != imageHeight / imageWidth) { + if (fullImageHeight / fullImageWidth < imageHeight / imageWidth) { + fullImageWidth = fullImageWidth / fullImageHeight * imageHeight; + fullImageHeight = imageHeight; + } else { + fullImageHeight = fullImageHeight / fullImageWidth * imageWidth; + fullImageWidth = imageWidth; + } + } else { + fullImageHeight = imageHeight; + fullImageWidth = imageWidth; + } + + + if (messageObject != null && messageObject.isVideo() && MediaController.getInstance().isPlayingMessage(messageObject)) { + isHardwareVideo = true; + MediaController.getInstance().setTextureView(overlayView.videoTextureView, overlayView.aspectRatioFrameLayout, overlayView.videoPlayerContainer, true); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) overlayView.videoPlayerContainer.getLayoutParams(); + overlayView.videoPlayerContainer.setTag(R.id.parent_tag, image); + if (layoutParams.width != image.getImageWidth() || layoutParams.height != image.getImageHeight()) { + overlayView.aspectRatioFrameLayout.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL); + layoutParams.width = (int) image.getImageWidth(); + layoutParams.height = (int) image.getImageHeight(); + overlayView.videoPlayerContainer.setLayoutParams(layoutParams); + } + overlayView.videoTextureView.setScaleX(1f); + overlayView.videoTextureView.setScaleY(1f); + + if (callback != null) { + overlayView.backupImageView.setImageBitmap(callback.getCurrentTextureView().getBitmap((int) fullImageWidth, (int) fullImageHeight)); + overlayView.backupImageView.setSize((int) fullImageWidth, (int) fullImageHeight); + overlayView.backupImageView.getImageReceiver().setRoundRadius(image.getRoundRadius()); + } + overlayView.videoPlayerContainer.setVisibility(View.VISIBLE); + } else { + isHardwareVideo = false; + this.childImage = new ImageReceiver(); + this.childImage.onAttachedToWindow(); + Drawable drawable = image.getDrawable(); + this.childImage.setImageBitmap(drawable); + if (drawable instanceof AnimatedFileDrawable) { + ((AnimatedFileDrawable) drawable).addSecondParentView(overlayView); + ((AnimatedFileDrawable) drawable).setInvalidateParentViewWithSecond(true); + } + this.childImage.setImageCoords(imageX, imageY, imageWidth, imageHeight); + this.childImage.setRoundRadius(image.getRoundRadius()); + + this.fullImage.setRoundRadius(image.getRoundRadius()); + overlayView.videoPlayerContainer.setVisibility(View.GONE); + } + + if (callback != null) { + callback.onZoomStarted(messageObject); + } + enterProgress = 0f; + } + + private void setFullImage(MessageObject messageObject) { + if (messageObject == null) { + return; + } + if (!messageObject.isPhoto()) { + return; + } + int[] size = new int[1]; + ImageLocation imageLocation = getImageLocation(messageObject, size); + if (imageLocation != null) { + boolean cacheOnly = messageObject != null && messageObject.isWebpage(); + Object parentObject; + parentObject = messageObject; + + String filter = null; + fullImage.setImage(imageLocation, filter, null, null, null, size[0], null, parentObject, cacheOnly ? 1 : 0); + fullImage.setCrossfadeAlpha((byte) 2); + } + + updateViewsLocation(); + } + + private boolean updateViewsLocation() { + float parentOffsetX = 0; + float parentOffsetY = 0; + View currentView = child; + while (currentView != parentView) { + if (currentView == null) { + return false; + } + parentOffsetX += currentView.getLeft(); + parentOffsetY += currentView.getTop(); + currentView = (View) currentView.getParent(); + } + + this.parentOffsetX = parentOffsetX; + this.parentOffsetY = parentOffsetY; + return true; + } + + public void finishZoom() { + if (finishTransition != null || !inOverlayMode) { + return; + } + if (!updateViewsLocation()) { + clear(); + } + finishTransition = ValueAnimator.ofFloat(1f, 0); + finishTransition.addUpdateListener(valueAnimator -> { + finishProgress = (float) valueAnimator.getAnimatedValue(); + invalidateViews(); + }); + finishTransition.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (finishTransition != null) { + finishTransition = null; + clear(); + } + } + }); +// finishTransition.setDuration(350); +// finishTransition.setInterpolator(new OvershootInterpolator(1.05f)); + + finishTransition.setDuration(220); + finishTransition.setInterpolator(CubicBezierInterpolator.DEFAULT); + finishTransition.start(); + } + + public void clear() { + if (inOverlayMode) { + if (callback != null) { + callback.onZoomFinished(messageObject); + } + inOverlayMode = false; + } + if (overlayView != null && overlayView.getParent() != null) { + parentView.removeView(overlayView); + overlayView.backupImageView.getImageReceiver().clearImage(); + + if (childImage != null) { + Drawable drawable = this.childImage.getDrawable(); + if (drawable instanceof AnimatedFileDrawable) { + ((AnimatedFileDrawable) drawable).removeSecondParentView(overlayView); + } + } + } + if (child != null) { + child.invalidate(); + child = null; + } + if (childImage != null) { + this.childImage.onDetachedFromWindow(); + this.childImage.clearImage(); + this.childImage = null; + } + if (fullImage != null) { + fullImage.onDetachedFromWindow(); + fullImage.clearImage(); + fullImage = null; + } + + messageObject = null; + } + + public boolean inOverlayMode() { + return inOverlayMode; + } + + + public boolean isInOverlayMode() { + return inOverlayMode; + } + + public boolean isInOverlayModeFor(View child) { + return inOverlayMode && child == this.child; + } + + public boolean onTouchEvent(MotionEvent ev) { + if (updateViewsLocation() && child != null) { + ev.offsetLocation(-parentOffsetX, -parentOffsetY); + return child.onTouchEvent(ev); + } + return false; + } + + public Bitmap getVideoBitmap(int w, int h) { + if (overlayView == null) { + return null; + } + return overlayView.videoTextureView.getBitmap(w, h); + } + + public ImageReceiver getPhotoImage() { + return childImage; + } + + protected boolean zoomEnabled(View child, ImageReceiver receiver) { + Drawable drawable = receiver.getDrawable(); + if (drawable instanceof AnimatedFileDrawable) { + if (((AnimatedFileDrawable)receiver.getDrawable()).isLoadingStream()) { + return false; + } else { + return true; + } + } + return receiver.hasNotThumb(); + } + + + private class ZoomOverlayView extends FrameLayout { + + private FrameLayout videoPlayerContainer; + private TextureView videoTextureView; + private AspectRatioFrameLayout aspectRatioFrameLayout; + private BackupImageView backupImageView; + private Path aspectPath = new Path(); + private Paint aspectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public ZoomOverlayView(Context context) { + super(context); + + if (Build.VERSION.SDK_INT >= 21) { + videoPlayerContainer = new FrameLayout(context); + videoPlayerContainer.setOutlineProvider(new ViewOutlineProvider() { + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public void getOutline(View view, Outline outline) { + ImageReceiver imageReceiver = (ImageReceiver) view.getTag(R.id.parent_tag); + if (imageReceiver != null) { + int[] rad = imageReceiver.getRoundRadius(); + int maxRad = 0; + for (int a = 0; a < 4; a++) { + maxRad = Math.max(maxRad, rad[a]); + } + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), maxRad); + } else { + outline.setOval(0, 0, AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize); + } + } + }); + videoPlayerContainer.setClipToOutline(true); + } else { + videoPlayerContainer = new FrameLayout(context) { + + RectF rect = new RectF(); + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + aspectPath.reset(); + ImageReceiver imageReceiver = (ImageReceiver) getTag(R.id.parent_tag); + if (imageReceiver != null) { + int[] rad = imageReceiver.getRoundRadius(); + int maxRad = 0; + for (int a = 0; a < 4; a++) { + maxRad = Math.max(maxRad, rad[a]); + } + rect.set(0, 0, w, h); + aspectPath.addRoundRect(rect, AndroidUtilities.dp(4), AndroidUtilities.dp(4), Path.Direction.CW); + } else { + aspectPath.addCircle(w / 2, h / 2, w / 2, Path.Direction.CW); + } + aspectPath.toggleInverseFillType(); + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (visibility == VISIBLE) { + setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (getTag() == null) { + canvas.drawPath(aspectPath, aspectPaint); + } + } + }; + aspectPath = new Path(); + aspectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + aspectPaint.setColor(0xff000000); + aspectPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + + backupImageView = new BackupImageView(context); + videoPlayerContainer.addView(backupImageView); + + videoPlayerContainer.setWillNotDraw(false); + + aspectRatioFrameLayout = new AspectRatioFrameLayout(context); + aspectRatioFrameLayout.setBackgroundColor(0); + videoPlayerContainer.addView(aspectRatioFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER)); + + videoTextureView = new TextureView(context); + videoTextureView.setOpaque(false); + aspectRatioFrameLayout.addView(videoTextureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + addView(videoPlayerContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + setWillNotDraw(false); + // videoTextureView.setVisibility(GONE); + } + + + @Override + protected void dispatchDraw(Canvas canvas) { + if (finishTransition == null && enterProgress != 1f) { + enterProgress += 16f / 220; + if (enterProgress > 1f) { + enterProgress = 1f; + } else { + invalidateViews(); + } + } + + float progress = finishProgress * CubicBezierInterpolator.DEFAULT.getInterpolation(enterProgress); + float clipTop = 0; + float clipBottom = getMeasuredHeight(); + if (progress != 1f && clipBoundsListener != null) { + clipBoundsListener.getClipTopBottom(clipTopBottom); + canvas.save(); + clipTop = clipTopBottom[0] * (1f - progress); + clipBottom = clipTopBottom[1] * (1f - progress) + getMeasuredHeight() * progress; + canvas.clipRect(0, clipTop, getMeasuredWidth(), clipBottom); + drawImage(canvas); + super.dispatchDraw(canvas); + canvas.restore(); + } else { + drawImage(canvas); + super.dispatchDraw(canvas); + } + + float parentOffsetX = PinchToZoomHelper.this.parentOffsetX - getLeft(); + float parentOffsetY = PinchToZoomHelper.this.parentOffsetY - getTop(); + + drawOverlays(canvas, (1f - progress), parentOffsetX, parentOffsetY, clipTop, clipBottom); + } + + private void drawImage(Canvas canvas) { + if (!inOverlayMode || child == null || parentView == null) { + return; + } + + updateViewsLocation(); + + float parentOffsetX = PinchToZoomHelper.this.parentOffsetX - getLeft(); + float parentOffsetY = PinchToZoomHelper.this.parentOffsetY - getTop(); + + canvas.save(); + float s = pinchScale * finishProgress + 1f * 1f - finishProgress; + canvas.scale(s, s, parentOffsetX + pinchCenterX, parentOffsetY + pinchCenterY); + canvas.translate(parentOffsetX + pinchTranslationX * finishProgress, parentOffsetY + pinchTranslationY * finishProgress); + if (fullImage != null && fullImage.hasNotThumb()) { + if (progressToFullView != 1) { + progressToFullView += 16f / 150f; + if (progressToFullView > 1) { + progressToFullView = 1f; + } else { + invalidateViews(); + } + } + fullImage.setAlpha(progressToFullView); + } + + float x = imageX; + float y = imageY; + if (imageHeight != fullImageHeight || imageWidth != fullImageWidth) { + float p; + if (s < 1f) { + p = 0; + } else if (s < 1.4f) { + p = (s - 1f) / 0.4f; + } else { + p = 1f; + } + float verticalPadding = (fullImageHeight - imageHeight) / 2f; + float horizontalPadding = (fullImageWidth - imageWidth) / 2f; + x = imageX - horizontalPadding * p; + y = imageY - verticalPadding * p; + if (childImage != null) { + childImage.setImageCoords(x, y, imageWidth + horizontalPadding * p * 2, imageHeight + verticalPadding * p * 2); + } + } + + if (!isHardwareVideo) { + if (childImage != null) { + if (progressToFullView != 1f) { + childImage.draw(canvas); + fullImage.setImageCoords(childImage.getImageX(), childImage.getImageY(), childImage.getImageWidth(), childImage.getImageHeight()); + fullImage.draw(canvas); + } else { + fullImage.setImageCoords(childImage.getImageX(), childImage.getImageY(), childImage.getImageWidth(), childImage.getImageHeight()); + fullImage.draw(canvas); + } + } + } else { + videoPlayerContainer.setPivotX(pinchCenterX - imageX); + videoPlayerContainer.setPivotY(pinchCenterY - imageY); + + videoPlayerContainer.setScaleY(s); + videoPlayerContainer.setScaleX(s); + + videoPlayerContainer.setTranslationX(x + parentOffsetX + pinchTranslationX * s * finishProgress); + videoPlayerContainer.setTranslationY(y + parentOffsetY + pinchTranslationY* s * finishProgress); + } + + canvas.restore(); + } + } + + protected void drawOverlays(Canvas canvas, float alpha, float parentOffsetX, float parentOffsetY, float clipTop, float clipBottom) { + + } + + private ImageLocation getImageLocation(MessageObject message, int[] size) { + if (message.messageOwner instanceof TLRPC.TL_messageService) { + if (message.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { + return null; + } else { + TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + if (size != null) { + size[0] = sizeFull.size; + if (size[0] == 0) { + size[0] = -1; + } + } + return ImageLocation.getForObject(sizeFull, message.photoThumbsObject); + } else if (size != null) { + size[0] = -1; + } + } + } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && message.messageOwner.media.photo != null || message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && message.messageOwner.media.webpage != null) { + if (message.isGif()) { + return ImageLocation.getForDocument(message.getDocument()); + } else { + TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize(), false, null, true); + if (sizeFull != null) { + if (size != null) { + size[0] = sizeFull.size; + if (size[0] == 0) { + size[0] = -1; + } + } + return ImageLocation.getForObject(sizeFull, message.photoThumbsObject); + } else if (size != null) { + size[0] = -1; + } + } + } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice) { + return ImageLocation.getForWebFile(WebFile.createWithWebDocument(((TLRPC.TL_messageMediaInvoice) message.messageOwner.media).photo)); + } else if (message.getDocument() != null) { + TLRPC.Document document = message.getDocument(); + if (MessageObject.isDocumentHasThumb(message.getDocument())) { + TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); + if (size != null) { + size[0] = thumb.size; + if (size[0] == 0) { + size[0] = -1; + } + } + return ImageLocation.getForDocument(thumb, document); + } + } + return null; + } + + public void setClipBoundsListener(ClipBoundsListener clipBoundsListener) { + this.clipBoundsListener = clipBoundsListener; + } + + public interface Callback { + default TextureView getCurrentTextureView() { + return null; + } + default void onZoomStarted(MessageObject messageObject) { + + } + default void onZoomFinished(MessageObject messageObject) { + + } + + } + + public void setCallback(Callback callback) { + this.callback = callback; + } + + public interface ClipBoundsListener { + void getClipTopBottom(float[] topBottom); + } + + public boolean checkPinchToZoom(MotionEvent ev, View child, ImageReceiver image, MessageObject messageObject) { + if (!zoomEnabled(child, image)) { + return false; + } + if (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { + if (!isInPinchToZoomTouchMode && ev.getPointerCount() == 2) { + pinchStartDistance = (float) Math.hypot(ev.getX(1) - ev.getX(0), ev.getY(1) - ev.getY(0)); + pinchStartCenterX = pinchCenterX = (ev.getX(0) + ev.getX(1)) / 2.0f; + pinchStartCenterY = pinchCenterY = (ev.getY(0) + ev.getY(1)) / 2.0f; + pinchScale = 1f; + + pointerId1 = ev.getPointerId(0); + pointerId2 = ev.getPointerId(1); + isInPinchToZoomTouchMode = true; + } + } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE && isInPinchToZoomTouchMode) { + int index1 = -1; + int index2 = -1; + for (int i = 0; i < ev.getPointerCount(); i++) { + if (pointerId1 == ev.getPointerId(i)) { + index1 = i; + } + if (pointerId2 == ev.getPointerId(i)) { + index2 = i; + } + } + if (index1 == -1 || index2 == -1) { + isInPinchToZoomTouchMode = false; + child.getParent().requestDisallowInterceptTouchEvent(false); + finishZoom(); + return false; + } + pinchScale = (float) Math.hypot(ev.getX(index2) - ev.getX(index1), ev.getY(index2) - ev.getY(index1)) / pinchStartDistance; + if (pinchScale > 1.005f && !isInOverlayMode()) { + pinchStartDistance = (float) Math.hypot(ev.getX(index2) - ev.getX(index1), ev.getY(index2) - ev.getY(index1)); + pinchStartCenterX = pinchCenterX = (ev.getX(index1) + ev.getX(index2)) / 2.0f; + pinchStartCenterY = pinchCenterY = (ev.getY(index1) + ev.getY(index2)) / 2.0f; + pinchScale = 1f; + pinchTranslationX = 0f; + pinchTranslationY = 0f; + child.getParent().requestDisallowInterceptTouchEvent(true); + startZoom(child, image, messageObject); + + } + + float newPinchCenterX = (ev.getX(index1) + ev.getX(index2)) / 2.0f; + float newPinchCenterY = (ev.getY(index1) + ev.getY(index2)) / 2.0f; + + + + float moveDx = pinchStartCenterX - newPinchCenterX; + float moveDy = pinchStartCenterY - newPinchCenterY; + pinchTranslationX = -moveDx / pinchScale; + pinchTranslationY = -moveDy / pinchScale; + 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); + finishZoom(); + } + return isInOverlayModeFor(child); + } + + private boolean checkPointerIds(MotionEvent ev) { + if (ev.getPointerCount() < 2) { + return false; + } + if (pointerId1 == ev.getPointerId(0) && pointerId2 == ev.getPointerId(1)) { + return true; + } + + if (pointerId1 == ev.getPointerId(1) && pointerId2 == ev.getPointerId(0)) { + return true; + } + + return false; + } + + protected void invalidateViews() { + if (overlayView != null) { + overlayView.invalidate(); + } + } + + public View getChild() { + return child; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java index f9677b3b021..fcb1a681a6b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -1372,7 +1372,7 @@ private void checkAndUpdateAvatar() { currentChat = chat; if (avatarImageView != null) { AvatarDrawable avatarDrawable = new AvatarDrawable(currentChat); - avatarImageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + avatarImageView.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, chat); } } else if (currentUser != null) { TLRPC.User user = MessagesController.getInstance(currentMessageObject.currentAccount).getUser(currentUser.id); @@ -1382,7 +1382,7 @@ private void checkAndUpdateAvatar() { currentUser = user; if (avatarImageView != null) { AvatarDrawable avatarDrawable = new AvatarDrawable(currentUser); - avatarImageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); + avatarImageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", avatarDrawable, user); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index 75a1f505e5b..21b434618f7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -41,6 +41,8 @@ import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; @@ -447,6 +449,17 @@ public boolean supportsPredictiveItemAnimations() { getConnectionsManager().sendRequest(req, (response, error) -> { }); + String text; + if (clear[0] && clear[1]) { + text = LocaleController.getString("PrivacyPaymentsPaymentShippingCleared", R.string.PrivacyPaymentsPaymentShippingCleared); + } else if (clear[0]) { + text = LocaleController.getString("PrivacyPaymentsShippingInfoCleared", R.string.PrivacyPaymentsShippingInfoCleared); + } else if (clear[1]) { + text = LocaleController.getString("PrivacyPaymentsPaymentInfoCleared", R.string.PrivacyPaymentsPaymentInfoCleared); + } else { + return; + } + BulletinFactory.of(PrivacySettingsActivity.this).createSimpleBulletin(R.raw.chats_infotip, text).show(); }); builder1.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder1.create()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index bb4b9e88560..59d2263bec8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -13,9 +13,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.animation.StateListAnimator; import android.animation.ValueAnimator; -import android.annotation.SuppressLint; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; @@ -25,9 +23,9 @@ 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.Outline; import android.graphics.Paint; import android.graphics.Point; import android.graphics.PorterDuff; @@ -57,7 +55,6 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; -import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -310,6 +307,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private TLRPC.FileLocation avatar; private TLRPC.FileLocation avatarBig; + private ImageLocation uploadingImageLocation; private final static int add_contact = 1; private final static int block_contact = 2; @@ -410,6 +408,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private boolean firstLayout = true; private boolean invalidateScroll = true; + PinchToZoomHelper pinchToZoomHelper; + private final Property HEADER_SHADOW = new AnimationProperties.FloatProperty("headerShadow") { @Override public void setValue(ProfileActivity object, float value) { @@ -588,7 +588,6 @@ protected void onDraw(Canvas canvas) { public void invalidate() { super.invalidate(); if (avatarsViewPager != null) { - BackupImageView imageView = avatarsViewPager.getCurrentItemView(); avatarsViewPager.invalidate(); } } @@ -1389,10 +1388,6 @@ public boolean onFragmentCreate() { listAdapter.notifyDataSetChanged(); } - if (arguments.containsKey("nearby_distance")) { - getMessagesController().preloadGreetingsSticker(); - } - if (arguments.containsKey("preload_messages")) { getMessagesController().ensureMessagesLoaded(user_id, 0, null); } @@ -1440,6 +1435,9 @@ public void onFragmentDestroy() { if (imageUpdater != null) { imageUpdater.clear(); } + if (pinchToZoomHelper != null) { + pinchToZoomHelper.clear(); + } } @Override @@ -1959,6 +1957,14 @@ public void onTextChanged(EditText editText) { fragmentView = new NestedFrameLayout(context) { + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (pinchToZoomHelper.isInOverlayMode()) { + return pinchToZoomHelper.onTouchEvent(ev); + } + return super.dispatchTouchEvent(ev); + } + private boolean ignoreLayout; private Paint grayPaint = new Paint(); @@ -2264,6 +2270,14 @@ protected void dispatchDraw(Canvas canvas) { } } } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (pinchToZoomHelper.isInOverlayMode() && (child == avatarContainer2 || child == actionBar || child == writeButton)) { + return true; + } + return super.drawChild(canvas, child, drawingTime); + } }; fragmentView.setWillNotDraw(false); FrameLayout frameLayout = (FrameLayout) fragmentView; @@ -2652,7 +2666,7 @@ public boolean onItemClick(View view, int position) { BuildVars.DEBUG_VERSION && !AndroidUtilities.isTablet() && Build.VERSION.SDK_INT >= 23 ? (SharedConfig.smoothKeyboard ? LocaleController.getString("DebugMenuDisableSmoothKeyboard", R.string.DebugMenuDisableSmoothKeyboard) : LocaleController.getString("DebugMenuEnableSmoothKeyboard", R.string.DebugMenuEnableSmoothKeyboard)) : null, BuildVars.DEBUG_PRIVATE_VERSION ? (SharedConfig.disableVoiceAudioEffects ? "Enable voip audio effects" : "Disable voip audio effects") : null, Build.VERSION.SDK_INT >= 21 ? (SharedConfig.noStatusBar ? "Show status bar background" : "Hide status bar background") : null, - SharedConfig.useMediaStream ? "Use call stream in voice chats" : "User media stream in voice chats" + SharedConfig.useMediaStream ? "Use call stream in voice chats" : "Use media stream in voice chats" }; builder.setItems(items, (dialog, which) -> { if (which == 0) { @@ -2677,7 +2691,7 @@ public boolean onItemClick(View view, int position) { getMessagesStorage().clearSentMedia(); SharedConfig.setNoSoundHintShowed(false); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); - editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("soundHint").remove("themehint").remove("filterhint").commit(); + editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("filterhint").commit(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; SharedConfig.stickersReorderingHintUsed = false; @@ -2877,6 +2891,7 @@ public void didChangeOwner(TLRPC.User user) { avatarContainer = new FrameLayout(context); avatarContainer2 = new FrameLayout(context); + AndroidUtilities.updateViewVisibilityAnimated(avatarContainer2, true, 1f, false); frameLayout.addView(avatarContainer2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); avatarContainer.setPivotX(0); avatarContainer.setPivotY(0); @@ -3030,15 +3045,14 @@ protected TextView createTextView() { updateProfileData(); writeButton = new RLottieImageView(context); - Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_profile_actionBackground), Theme.getColor(Theme.key_profile_actionPressedBackground)); - if (Build.VERSION.SDK_INT < 21) { - Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); - shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); - CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); - drawable = combinedDrawable; - } - writeButton.setBackgroundDrawable(drawable); + + Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); + shadowDrawable.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, + Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_profile_actionBackground), Theme.getColor(Theme.key_profile_actionPressedBackground)), + 0, 0); + combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + writeButton.setBackgroundDrawable(combinedDrawable); if (user_id != 0) { if (imageUpdater != null) { cameraDrawable = new RLottieDrawable(R.raw.camera_outline, "" + R.raw.camera_outline, AndroidUtilities.dp(56), AndroidUtilities.dp(56), false, null); @@ -3056,20 +3070,8 @@ protected TextView createTextView() { } writeButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_profile_actionIcon), PorterDuff.Mode.MULTIPLY)); writeButton.setScaleType(ImageView.ScaleType.CENTER); - if (Build.VERSION.SDK_INT >= 21) { - StateListAnimator animator = new StateListAnimator(); - animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(writeButton, View.TRANSLATION_Z, AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); - animator.addState(new int[]{}, ObjectAnimator.ofFloat(writeButton, View.TRANSLATION_Z, AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); - writeButton.setStateListAnimator(animator); - writeButton.setOutlineProvider(new ViewOutlineProvider() { - @SuppressLint("NewApi") - @Override - public void getOutline(View view, Outline outline) { - outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); - } - }); - } - frameLayout.addView(writeButton, LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 56 : 60, Build.VERSION.SDK_INT >= 21 ? 56 : 60, Gravity.RIGHT | Gravity.TOP, 0, 0, 16, 0)); + + frameLayout.addView(writeButton, LayoutHelper.createFrame(60, 60, Gravity.RIGHT | Gravity.TOP, 0, 0, 16, 0)); writeButton.setOnClickListener(v -> { if (writeButton.getTag() != null) { return; @@ -3079,8 +3081,6 @@ public void getOutline(View view, Outline outline) { needLayout(false); if (scrollTo != -1) { - //layoutManager.scrollToPositionWithOffset(scrollTo, scrollToPosition); - if (writeButtonTag != null) { writeButton.setTag(0); writeButton.setScaleX(0.2f); @@ -3214,6 +3214,82 @@ public void onAnimationEnd(Animator animation) { updateSelectedMediaTabText(); + + ViewGroup decorView; + if (Build.VERSION.SDK_INT >= 21) { + decorView = (ViewGroup) getParentActivity().getWindow().getDecorView(); + } else { + decorView = frameLayout; + } + pinchToZoomHelper = new PinchToZoomHelper(decorView) { + + Paint statusBarPaint; + @Override + protected void invalidateViews() { + super.invalidateViews(); + fragmentView.invalidate(); + for (int i = 0; i < avatarsViewPager.getChildCount(); i++) { + avatarsViewPager.getChildAt(i).invalidate(); + } + if (writeButton != null) { + writeButton.invalidate(); + } + } + + @Override + protected void drawOverlays(Canvas canvas, float alpha, float parentOffsetX, float parentOffsetY, float clipTop, float clipBottom) { + if (alpha > 0) { + AndroidUtilities.rectTmp.set(0, 0, avatarsViewPager.getMeasuredWidth(), avatarsViewPager.getMeasuredHeight() + AndroidUtilities.dp(30)); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (255 * alpha), Canvas.ALL_SAVE_FLAG); + + avatarContainer2.draw(canvas); + + if (actionBar.getOccupyStatusBar()) { + if (statusBarPaint == null) { + statusBarPaint = new Paint(); + statusBarPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.2f))); + } + canvas.drawRect(actionBar.getX(), actionBar.getY(), actionBar.getX() + actionBar.getMeasuredWidth(), actionBar.getY() + AndroidUtilities.statusBarHeight, statusBarPaint); + } + canvas.save(); + canvas.translate(actionBar.getX(), actionBar.getY()); + actionBar.draw(canvas); + canvas.restore(); + + if (writeButton != null && writeButton.getVisibility() == View.VISIBLE && writeButton.getAlpha() > 0) { + canvas.save(); + float s = 0.5f + 0.5f * alpha; + canvas.scale(s, s, writeButton.getX() + writeButton.getMeasuredWidth() / 2f, writeButton.getY() + writeButton.getMeasuredHeight() / 2f); + canvas.translate(writeButton.getX(), writeButton.getY()); + writeButton.draw(canvas); + canvas.restore(); + } + canvas.restore(); + } + } + + @Override + protected boolean zoomEnabled(View child, ImageReceiver receiver) { + if (!super.zoomEnabled(child, receiver)) { + return false; + } + return listView.getScrollState() != RecyclerView.SCROLL_STATE_DRAGGING; + } + }; + pinchToZoomHelper.setCallback(new PinchToZoomHelper.Callback() { + @Override + public void onZoomStarted(MessageObject messageObject) { + listView.cancelClickRunnables(true); + 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), Theme.getColor(Theme.key_windowBackgroundWhite), 0.1f)); + } + } + }); + avatarsViewPager.setPinchToZoomHelper(pinchToZoomHelper); return fragmentView; } @@ -3304,7 +3380,7 @@ private void onWriteButtonClick() { args.putInt("nearby_distance", distance); } ChatActivity chatActivity = new ChatActivity(args); - chatActivity.setPreloadedSticker(getMessagesController().getPreloadedSticker(), false); + chatActivity.setPreloadedSticker(getMediaDataController().getGreetingsSticker(), false); presentFragment(chatActivity, true); if (AndroidUtilities.isTablet()) { finishFragment(); @@ -3558,9 +3634,9 @@ private boolean processOnClickOrPress(final int position) { if (i == 0) { try { android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", "@" + username); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", "https://" + MessagesController.getInstance(UserConfig.selectedAccount).linkPrefix + "/" + username); clipboard.setPrimaryClip(clip); - BulletinFactory.of(this).createCopyBulletin(LocaleController.getString("UsernameCopied", R.string.UsernameCopied)).show(); + BulletinFactory.of(this).createCopyBulletin(LocaleController.getString("LinkCopied", R.string.LinkCopied)).show(); } catch (Exception e) { FileLog.e(e); } @@ -4085,6 +4161,8 @@ public void onAnimationEnd(Animator animation) { isPulledDown = true; overlaysView.setOverlaysVisible(true, durationFactor); avatarsViewPagerIndicatorView.refreshVisibility(durationFactor); + avatarsViewPager.setCreateThumbFromParent(true); + avatarsViewPager.getAdapter().notifyDataSetChanged(); expandAnimator.cancel(); float value = AndroidUtilities.lerp(expandAnimatorValues, currentExpanAnimatorFracture); expandAnimatorValues[0] = value; @@ -5487,8 +5565,8 @@ private void updateProfileData() { } avatarDrawable.setInfo(user); - final ImageLocation imageLocation = ImageLocation.getForUser(user, true); - final ImageLocation thumbLocation = ImageLocation.getForUser(user, false); + final ImageLocation imageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_BIG); + final ImageLocation thumbLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL); final ImageLocation videoLocation = avatarsViewPager.getCurrentVideoLocation(thumbLocation, imageLocation); avatarsViewPager.initIfEmpty(imageLocation, thumbLocation); String filter; @@ -5694,8 +5772,8 @@ private void updateProfileData() { photoBig = chat.photo.photo_big; } avatarDrawable.setInfo(chat); - final ImageLocation imageLocation = ImageLocation.getForChat(chat, true); - final ImageLocation thumbLocation = ImageLocation.getForChat(chat, false); + final ImageLocation imageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_BIG); + final ImageLocation thumbLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL); final ImageLocation videoLocation = avatarsViewPager.getCurrentVideoLocation(thumbLocation, imageLocation); boolean initied = avatarsViewPager.initIfEmpty(imageLocation, thumbLocation); if ((imageLocation == null || initied) && isPulledDown) { @@ -6166,6 +6244,7 @@ public void onUploadProgressChanged(float progress) { return; } avatarProgressView.setProgress(progress); + avatarsViewPager.setUploadProgress(uploadingImageLocation, progress); } @Override @@ -6192,6 +6271,7 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi req.flags |= 4; } getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + avatarsViewPager.removeUploadingImage(uploadingImageLocation); if (error == null) { TLRPC.User user = getMessagesController().getUser(getUserConfig().getClientUserId()); if (user == null) { @@ -6223,7 +6303,7 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi src.renameTo(destFile); String oldKey = avatar.volume_id + "_" + avatar.local_id + "@50_50"; String newKey = small.location.volume_id + "_" + small.location.local_id + "@50_50"; - ImageLoader.getInstance().replaceImageInCache(oldKey, newKey, ImageLocation.getForUser(user, false), false); + ImageLoader.getInstance().replaceImageInCache(oldKey, newKey, ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), false); } if (big != null && avatarBig != null) { File destFile = FileLoader.getPathToAttach(big, true); @@ -6245,6 +6325,7 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi allowPullingDown = !AndroidUtilities.isTablet() && !isInLandscapeMode && avatarImage.getImageReceiver().hasNotThumb(); avatar = null; avatarBig = null; + avatarsViewPager.setCreateThumbFromParent(false); updateProfileData(); showAvatarProgress(false, true); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_ALL); @@ -6252,7 +6333,6 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi getUserConfig().saveConfig(true); })); } else { - allowPullingDown = false; avatar = smallSize.location; avatarBig = bigSize.location; avatarImage.setImage(ImageLocation.getForLocal(avatar), "50_50", avatarDrawable, null); @@ -6263,11 +6343,8 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi } needLayout(true); } + avatarsViewPager.addUploadingImage(uploadingImageLocation = ImageLocation.getForLocal(avatarBig), ImageLocation.getForLocal(avatar)); showAvatarProgress(true, false); - final View view = layoutManager.findViewByPosition(0); - if (view != null && isPulledDown) { - listView.smoothScrollBy(0, view.getTop() - AndroidUtilities.dp(88), CubicBezierInterpolator.EASE_OUT_QUINT); - } } actionBar.createMenu().requestLayout(); }); @@ -6582,7 +6659,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { break; case 0: case 9: - abi = "universal " + Build.CPU_ABI + " " + Build.CPU_ABI2; + if (AndroidUtilities.isStandaloneApp()) { + abi = "direct " + Build.CPU_ABI + " " + Build.CPU_ABI2; + } else { + abi = "universal " + Build.CPU_ABI + " " + Build.CPU_ABI2; + } break; } cell.setText(LocaleController.formatString("TelegramVersion", R.string.TelegramVersion, String.format(Locale.US, "v%s (%d) %s", pInfo.versionName, code, abi))); @@ -7586,6 +7667,8 @@ public ArrayList getThemeDescriptions() { final Object onlineTextViewTag = onlineTextView[1].getTag(); if (onlineTextViewTag instanceof String) { onlineTextView[1].setTextColor(Theme.getColor((String) onlineTextViewTag)); + } else { + onlineTextView[1].setTextColor(Theme.getColor(Theme.key_avatar_subtitleInProfileBlue)); } } if (lockIconDrawable != null) { @@ -7594,7 +7677,6 @@ public ArrayList getThemeDescriptions() { if (scamDrawable != null) { scamDrawable.setColor(Theme.getColor(Theme.key_avatar_subtitleInProfileBlue)); } - nameTextView[1].setBackgroundColor(Theme.getColor(Theme.key_avatar_backgroundActionBarBlue)); nameTextView[1].setTextColor(Theme.getColor(Theme.key_profile_title)); actionBar.setItemsColor(Theme.getColor(Theme.key_actionBarDefaultIcon), false); actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_avatar_actionBarSelectorBlue), false); @@ -7766,6 +7848,10 @@ private void saveScrollPosition() { } } + public void scrollToSharedMedia() { + layoutManager.scrollToPositionWithOffset(sharedMediaRow, -listView.getPaddingTop()); + } + private class DiffCallback extends DiffUtil.Callback { int oldRowCount; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java index 5a876ec85fe..843db008632 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java @@ -427,11 +427,9 @@ public void didReceivedNotification(int id, int account, Object... args) { initRenderers(); VoIPService.getSharedInstance().registerStateListener(this); } - } - if (id == NotificationCenter.emojiDidLoad) { - checkEmojiLoaded(true); - } - if (id == NotificationCenter.closeInCallActivity) { + } else if (id == NotificationCenter.emojiDidLoad) { + updateKeyView(true); + } else if (id == NotificationCenter.closeInCallActivity) { windowView.finish(); } } @@ -574,7 +572,7 @@ public void onAllSizesReady() { } }); - callingUserPhotoView.setImage(ImageLocation.getForUser(callingUser, true), null, gradientDrawable, callingUser); + callingUserPhotoView.setImage(ImageLocation.getForUserOrChat(callingUser, ImageLocation.TYPE_BIG), null, gradientDrawable, callingUser); currentUserCameraFloatingLayout = new VoIPFloatingLayout(context); currentUserCameraFloatingLayout.setRelativePosition(1f, 1f); @@ -696,7 +694,7 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { statusLayout.setFocusableInTouchMode(true); callingUserPhotoViewMini = new BackupImageView(context); - callingUserPhotoViewMini.setImage(ImageLocation.getForUser(callingUser, false), null, Theme.createCircleDrawable(AndroidUtilities.dp(135), 0xFF000000), callingUser); + callingUserPhotoViewMini.setImage(ImageLocation.getForUserOrChat(callingUser, ImageLocation.TYPE_SMALL), null, Theme.createCircleDrawable(AndroidUtilities.dp(135), 0xFF000000), callingUser); callingUserPhotoViewMini.setRoundRadius(AndroidUtilities.dp(135) / 2); callingUserPhotoViewMini.setVisibility(View.GONE); @@ -1670,20 +1668,23 @@ public void onAnimationEnd(Animator animation) { } private void updateKeyView(boolean animated) { - TLRPC.EncryptedChat encryptedChat = new TLRPC.TL_encryptedChat(); VoIPService service = VoIPService.getSharedInstance(); if (service == null) { return; } + byte[] auth_key = null; try { ByteArrayOutputStream buf = new ByteArrayOutputStream(); buf.write(service.getEncryptionKey()); buf.write(service.getGA()); - encryptedChat.auth_key = buf.toByteArray(); + auth_key = buf.toByteArray(); } catch (Exception checkedExceptionsAreBad) { FileLog.e(checkedExceptionsAreBad); } - byte[] sha256 = Utilities.computeSHA256(encryptedChat.auth_key, 0, encryptedChat.auth_key.length); + if (auth_key == null) { + return; + } + byte[] sha256 = Utilities.computeSHA256(auth_key, 0, auth_key.length); String[] emoji = EncryptionKeyEmojifier.emojifyForCall(sha256); for (int i = 0; i < 4; i++) { Emoji.EmojiDrawable drawable = Emoji.getEmojiDrawable(emoji[i]); @@ -1701,6 +1702,7 @@ private void updateKeyView(boolean animated) { private void checkEmojiLoaded(boolean animated) { int count = 0; + for (int i = 0; i < 4; i++) { if (emojiDrawables[i] != null && emojiDrawables[i].isLoaded()) { count++; diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_card.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_card.png new file mode 100644 index 0000000000000000000000000000000000000000..ebe0630d57b677b3433c1599e838fdc3e0cdac10 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~STEL88gA~qMxhWJ#`FXlHhFAzD zCrIpj@c;k+c@BRhI!>}G?48%+@W{|$Mv4Z{Ds_eCf590i6t4Q2t~U%k-MpAhkk2zf s!d7uj&w?(XRxzya}?w)78&qol`;+0EDAAwEzGB literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_addbio.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_addbio.png new file mode 100644 index 0000000000000000000000000000000000000000..67ab5fba86c570d8f61a7f7a6f562c374b9379b1 GIT binary patch literal 1050 zcmV+#1m*jQP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0gh@m}R9Fekm`_L)Q5?s2wG=H1 zG7&2(@KSn^f-ZHaESz=;FZ+LLIyH$Drt1n&lztA_Seh6j&Y1Ls=%6 zq(KK=+&J8Souo6= zN8mI3fLYi9&Cm)R;GUgD+P9&PC0(XWZcJtyjDTxes-qBl5OyRqN8lMOgS9tQbiE}r zf|}r?%|iJBjwQ>IR}*&_-h;IXDox(G5ZA&x8%;R~x|_;2;_KisSR13V)hi)FH}C=N zlFQ?j7!kSdg0;btaVR^insO92mkdfEAYV0TOR#n(HXKD2=vtA@f!D={t`&Mz#wK?h z=o(-aWRp!I?l^u z>}1HfP7TI7WCx_Y;0~k5!vWKwZT+q5T*vx2xicnz=!VdQ>~m*^XN?tk&4r`u2Q68@ zSAY>Qj-GE5rg_kfbtj|;Wm3}}sa@CW&MZhiY}$HA2gcF81ld^7>sQN%<$wJm!YU$L z!ab>!&X7GbcIgT=>(*xJz7!^RC#0wRrb0ob+lXC8InE87r8y@nyLE~b}zA| zPfTeIXQkZNj}~HkVAbubQR&wO{1tpGgDAMrX;l0LjhvT#X5wfjL$9bf9&uouIy!6s zy1B-(xmFoJ@_z9uAmUhtzg{~p@hzQh{&%H3dXnCoz5!zJ$(91r0e{qD78^~FmP=+B1xpxZKu%_COa9(M%V zHK4n%&FxQICxOr3F`9(F;X9!|@gM}mE?KE$45$|~{o~OHe?dz(wU%vy_>E`(0GjGU Ut;P9eF#rGn07*qoM6N<$f)Sh7!TPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~=t)FDR9Fekm_JMuK@`SsiAtj8 zD3E~H(ij_RNi1l=o{Gla3SviPXsoE!hS;i!K^qzh3mY0^Vk~S$Ljs9^VxmFU-?uxD z%-;T+J=o)3^39u_`M&qw&Ft;YU8gf*7M-S^IF7HP?}15h2==2W`iUQoQNR?q3tob6 zpvW|?dGV%Nsf@rq@E9C}CMLdgTE!r%+%f`<5oI0R2baBwU+KRBAHhD*c4^y`_y)KG zW`Nl*IuF4Ew)CG3Hu4nH1+Rf`FSxh`>OM&1c;fq}c-=;Yh>U0keDET@qd(s`P#S9< zt@LJ!>#tsQSjgkxt*P6@H4 zCRW67ww7n)N8nC^?@lAHuYRq;TXPz@l|lg%JC5`jA9TaPn{yg-bA`eC1{EJDk8G!J zI=SH{nD~=S$MI&4P%(h!3HTvjLCa0S-vlz{oyZUvSk{cQh0J727vx&7g!pAkV>gr@ z_p-m>P10+>Q6A-!S^ka{WG}x1-ZjT5C#>buZ2)cAMwlXHxjY9>WBJodf^7rYUX!5W zqWPUD@dIf0oOau^wnBD2$W!@}6PveKA>Q)EMz(@TtTo z1tBPXb=ZOqemvuIbrY&K%?6}+(HhvbkK zf!Qvdwhw5F#btY=6frtSShq^L;dBT$dq(Fh4*7~>ruac;u4JtskIv5^+dYcvf}#IV zw3nOJk?|Cy$HF=||DV!+Wfax}L;178&s*E4sMi0Esob)<3Mue>|FEhn@GR#41A@s; U#m^^Gs{jB107*qoM6N<$f}#eM1^@s6 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-mdpi/msg_report_abuse.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_report_abuse.png similarity index 100% rename from TMessagesProj/src/main/res/mipmap-mdpi/msg_report_abuse.png rename to TMessagesProj/src/main/res/drawable-hdpi/msg_report_abuse.png diff --git a/TMessagesProj/src/main/res/mipmap-mdpi/msg_report_fake.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_report_fake.png similarity index 100% rename from TMessagesProj/src/main/res/mipmap-mdpi/msg_report_fake.png rename to TMessagesProj/src/main/res/drawable-hdpi/msg_report_fake.png diff --git a/TMessagesProj/src/main/res/mipmap-mdpi/msg_report_other.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_report_other.png similarity index 100% rename from TMessagesProj/src/main/res/mipmap-mdpi/msg_report_other.png rename to TMessagesProj/src/main/res/drawable-hdpi/msg_report_other.png diff --git a/TMessagesProj/src/main/res/mipmap-mdpi/msg_report_spam.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_report_spam.png similarity index 100% rename from TMessagesProj/src/main/res/mipmap-mdpi/msg_report_spam.png rename to TMessagesProj/src/main/res/drawable-hdpi/msg_report_spam.png diff --git a/TMessagesProj/src/main/res/mipmap-mdpi/msg_report_violence.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_report_violence.png similarity index 100% rename from TMessagesProj/src/main/res/mipmap-mdpi/msg_report_violence.png rename to TMessagesProj/src/main/res/drawable-hdpi/msg_report_violence.png diff --git a/TMessagesProj/src/main/res/mipmap-mdpi/msg_report_xxx.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_report_xxx.png similarity index 100% rename from TMessagesProj/src/main/res/mipmap-mdpi/msg_report_xxx.png rename to TMessagesProj/src/main/res/drawable-hdpi/msg_report_xxx.png diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_timeredit.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_timeredit.png new file mode 100644 index 0000000000000000000000000000000000000000..a0bbaad250d9046a79089a936eccfb564587b8a0 GIT binary patch literal 1086 zcmV-E1i|}>P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0s7XXYR9Fe^mPu@lQ545Lijc-o zikc#^5gH2wX@Ybih(t^YB4T01jG!_jcIoop{<15O=!kw(sZ@9BEQB)n4s~!l zkw`qncfQfkDu}W-EFOf(9o`j1yM>Apn*!QA&T0vc57o%KPV!(_4o9E?zQg8FBC#Uq z3xl8nR>L_^p0ytgwn6?|1(6EQgxzopTEI6I>>p|>Y8|~A+yQQ5$C>NC3mby75M@m) zes%&2!d1c%^2fm)r_OoC;VVV3#)yC7ufP^q3SU8{b=kh~w(${i`@v-uF}5j~fuIDY zL0>Ckdm+6q6(2JlHg7Bxq=%gLD$rOB=#EQ4l~ za6kdZ-Qc}hJCYTffmxSJ`mv}vx>B$Y%VDeOY6qU5&D_S)Vm<@StW_IbA5Y)rDfM2F zbkQWvp}E*6?j!ZFj{5SLL+78~Jv;|p<3Mx@t8{AZ!H+NaiG zX3v}}WPT#uaI(P}SJ2-xMpcQ|w<>r#aHGPyfJ{Yu=ZM<5KrJ0_t!*#33>jN(7XCEkdusC5 zrbZ>`C@iao!oQ1%yTS#qrl#6`rO2HRA5AfxhbHFz4}1Yhy20<7B69lqCi%L!IeMKE zb|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31CxNKi(^Ox z=i6!aI?RDG$D=2SDZ1#0DXI$2HksJ5WaSJMwv7f?R8-g&&peVPG~3mOhexQT^GJds z+p;JhC-F|kkIU`s_h#RH`tI)hxUJ6hC%3=9TfP7N``UL)%fCA<%nB)AaHvdS_SwG0 z3%d?5EfM#uSr~G2VS@)(uh{%8!l|uH5A-J#>|GqFA7C0csrHH6hc}F-Z>~jWDLh=^ z{M&(dSK}{!g@+j~?G9h99a(urLUnE&y2BYz+chU3!t|wy`$xZ`C!SIcg(A*=rt&8| zTMj?8zV(Q?gJYIs`U~lwoz*_Fu9pK`?j6dsXAzTIdHEeTSF*O%CXJ{!7kF83**GRn zIPVy+JE@d;I*-}TCMCnZd23g(*qE(mzG?SO=Z5Pg#;j|Ty|3&G_#P4|Jwsy`Z-w}p zQ+thOgd94d;^`gsuHm@d3iD@d%i51@ZxA=1KKb*dDat+DtfkY+IoCaZlfbjSQf%7s z_kve%OK$mS@>cZJ0`;|1|8dN6Uls9W^Tt(PC(bjP$>I^TWP6|i9%1@Adw_#UGDSOSE1N?r5e?nP)e+>nt5l>e?mvv4FO#rqV B3xfav literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/payment_address.png b/TMessagesProj/src/main/res/drawable-hdpi/payment_address.png new file mode 100644 index 0000000000000000000000000000000000000000..7341068be35e770a0580f1ffef3135029382775b GIT binary patch literal 930 zcmV;T16}-yP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz03`s;mR9Fe^n7wNhQ53~z{fI<^ z2#KPNU||u1Ni5=D5JDP-RCacXR$7FJe@O}j5tJZkVLtGqQPfyyXKJ%eFg7aD#=>O% zo!z<1b>_X<*-h3)FPwdM?mg$+x3iO((IojF#b=;W+>Uo^wc2jFXTb?@EM=~8YU zrLvjUy1THE5pWND1+h?1oRO~W2J?O}2ev@j5LcT19o-m)qo4{bev;e=7r;r-mqNK} z>WO1fB^lk3O<^*7K(iQeG7ywnE_yw*N3Ia`Oz$Q?vf`I_7 zTnX_lxuh{&PL*e&pEeWL+j&Nb3c^94v!ZxhLQ+VPN8PF6Iao*zH4)FI20GpC8)Qu7 z0qm!n&9qw|B3=WE#UeKSqu?^Qq`U=p5sqT5h?naj7_Q42A6IgOv_N|d_#341u>$_p zhGqS8IL6D>p-+_&!dZ4aOP6zoX#s-&qEjK>u27MhKlOS(#Uk`APshmAy_cWSl*Bf4 zsL4o@4VP!r57`38D}kDoyqBM0{Uo-bFHJ_09C3Lzy-wkqD=Jql7T(LxX!7?ovp}w%fipFT6kqhFR+JW`}d5nZGxxW+vMFFp@qu` z?4F^A;=wShd{rJmUW&qdThJBJWL?_$m(7=^wSL&+#$SOWLQ@^apF{ zC%?Er8pS#|oEy+d0iy}91r&PgYiTSF_y`ozPINLms=@GvoYQ#A8oiIG2mFKgX4H5) z4TjtS7SBocW&KnGPmRQSH_O?vW6XQN6E|#ue6I~q4(46|8F`QOyRtGsKgSDTp$+Z_ zsxMiQ^`&ZE*+kZqLHdW`Yhdw)iX%+>biQ&K%Eu;^Kn=YU0VmbIy`31U|lm0 z>f301=q9?YYo@bjirXO@&`aJqAg_hL_TMmW5C2yB8+N?)MBmw|p8x;=07*qoM6N<$ Ef@MITaR2}S literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/payment_card.png b/TMessagesProj/src/main/res/drawable-hdpi/payment_card.png new file mode 100644 index 0000000000000000000000000000000000000000..7572ef30b2002d63b11cf74aadcf3067cd81a277 GIT binary patch literal 451 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`nXadcV@L$& z+i*v|CIbPH$J~2n7JNA;{-f>BvDNPte(=^bmG`sc*DR;+t#HK`E<2>#uV{T`# zX(nSv1OJ3W>olSmpD3yS-RYI)0CQfsUp3Y_~mGw;Oz z18V=?NnP6AqyPC;TddjFjn=JSwuzTUS-5y<2hQQhS-DU=WDmQsGW(5pG0TFc-@Q92 z(z&X$B!?^06^U3Q`fC^Go{LM(fTm9LmzUMuWWL~#zqR@a)vh|9WaFaT+`oq|Z#=Iu z>x5xW)k*$oJnUKRZCnpHS%Q@MGS~R_J&kp&C({=w|dS>y10?^ad K&t;ucLK6V>4x;7& literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/payment_delivery.png b/TMessagesProj/src/main/res/drawable-hdpi/payment_delivery.png new file mode 100644 index 0000000000000000000000000000000000000000..2f5fc2389396d43689b4b46f95f88f1a62430efd GIT binary patch literal 842 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31Jf2y7srqY z&bQOgdxr#y98Z@y?W85~qP<0N>jaHMVhgu&+;;IUf3(c3aa)o2+Zc|2+>wgAasnMW z|8+;?-Ddh}&v!x=41+XKM<bZqE`RxSlG?B_Iu7~kf+!I$sIbUM<8W-uyE1$WFjW>10&#>862k!HkhQ4hpnLca9 z?ghTA<$2#-MYFaWG3PPw)|mZxmuqrw(8@I4m*-=G^v~}x>&(78p;q{uhx5t*QZqzp6;5M-hU^y|6yH&*atZu=J|IOKMLeDac8{Y2s91jd|I0BY^!I= z^}Lg%(J_y0enakYW+ukY{8=&EJOw{??Tt&?;mumJ@@C8l?qe$MC5?M--Zkb-`YB~7 z&miAy9ssHeUNmpr`vd>?GuJaN`enZL$33y{ Ppmgl%>gTe~DWM4f`kGul literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/payment_email.png b/TMessagesProj/src/main/res/drawable-hdpi/payment_email.png new file mode 100644 index 0000000000000000000000000000000000000000..a5062eeea4e0e16464280f368166a31ce872e784 GIT binary patch literal 1116 zcmV-i1f%Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0#z{m$R9Fe^mtAO%VHn5vj%Mrt z!?Nu_lzfC7EJ<;IMC4tv`K9~n{9so zclY(UpO5!_pRpa#{`KE=-`DlO@B7;Q++S}|(K!CG8OV$@-=U$Q656bU>)={g38y&r zVV}UKuobptGMORl=z~N`;Q{y_rbP$BBXCmMj8e@I9oEv}X;>BM_ycv#$TRp8mcwO^ z6R?Ko6zZ6*Tjuy9OClNA2z`8}athAN)hV$`co23$!ytu*Tx|;aX{=-}TW`*`U^NS= zfVK>tfCJFbn5uD9MC)VL1NJN26V;@x({?NDgNC}aZL>OB)k00Npk!8zsDlJCeXN1s zq3{hZO_0T12(_EuLc{L3YS@EdI@}B!U_IOcbAD1{yP)9_g~FQ(k+!y>B`Fz#GoaR! z{l})4mG2BJ&C&L%L=M}MG=UFM3AA%YyJ>n5bOn5i;VW1OcM()1wAT*QClek->1%eWFeiVB6ppINMR>c4&A)VPZl*7fgViAB_iff=4~!+#uiz#Ljwgolmhf zARlbyGHveXsthQf6}R_s?O z>!K8N9YnDThb`3Re3zz+HMsI@nx%eIDo8!l#3F+1rbT>t@$aCahjKe}-v(Rg6 zMf(b~%^{mBp?+WF%0Ci(`CR@dot7Z%alTo8ESiwsGeXkg)-@c;{;l!Kxr)BVPtNoM zt`N#0R6(GJm9S*kg#O;7_RVG$%cuk-$PC-Q|6VeXlGonIbxQMnxW7SLsKa+ zKL7mC){Z5GuNWSOKJNL05zqnL=>+%vSg4F(trN-Y4+W{4} z>et8%cn7_0X{y;ztwp^7&V!%eJv2#Y9iap;kS^IlDD=Y6Nt@7Q>|G?GN4i08oSkDo zYJm|*qR}#P_6pYSy8^ApC`|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM315>7_i(^Ox z=iBM$y+s2h+GLM9Y}h1lk>gPB>}^@n%{h~$r|Wee=)EAnKzsW-mWg3&d9(^HE}Oes zyNP>qhGJ9P%DIlJ5h`9YAAdG`ejss|aq+WzJ1-^KRXm$x`MJ*iPujV_=qN93>wq$a zR}KyKa|*a(8|a8dh6HDlYvXZhK}eTl-t`;QZMvRlfgA z)Z`@2F1ncgqTfFM$Gio%d^dIZ8qE~q)!j&<&VYigGdDZXluRklmnGiBNO*OHFA9n?4Y zJU`>H)?v-+8R7}K+or9XU~1%ZL#M|oeaqIZvqRo6*s$D|T=p>fg@#IHkbsa+qu&Fa zV8gwhglFeEsNy{zlo6oITvQk#*fH0Fz(_d8?qxFZ< zPZ-TTxBX$4@|~o*`FXXa*ZwRMS$yt>{U*N|=MRM1zxQahYjC{5ke%)GhW~{)Uwhex z^`1w0epOxzdw8Gibi&)h+|)x_agVP}E>v@zmOazrdgA>fwbQTvTv>Rfp6{Lc1Z}?< zpEZ@j;m+lMcD|c@Z|SyeYfiEMP@W}Lbhl*D4ViO6MUKGGo|~cZ=GC#ymYbR{pHr+@ pX&61%-|>v)#Ph2|{vVgMVE^NHCi(38Dbk?C=jrO_vd$@?2>?vHMa2LB literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/payment_phone.png b/TMessagesProj/src/main/res/drawable-hdpi/payment_phone.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba9c8f28e128e40b9a40fe9b853bccc43afd478 GIT binary patch literal 778 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM315=5oi(^Ox z=i6!Ly+a*Ej_=KKP4EavN(^|mh-1+LUzZDR8&V(c5=(s7q@Wcg;@G{wSK!K`-g<}K zw_F~^2S`sm)an&EiBnbO%i($J&rd(sn7AYE{^Q>3XKg=Jra!wgvv^46xOrjMoNxI_zk|D9 z>3CSAT%Y#wd7|~3R^|fPZHE+WT2sPQR@_~6<%aS4JxZ$={Rq9m^jFUR>E4XEeUjW| z%1O)l9qwr5=H^A-ub=*IyT^r`0JXSI%iY`bB_=P4R5=mu(Yhty>9go9S+?LU-7LPr z2}ir;d`kLLd+WyXwg0a^URu%B-<;#c`f;~I`h?pBnofH-Lf2QO{wb`G{v!W#$0eJi z{VYt=n!ZWAEseL9R+@6?J+oq#U2`9=<~5I?uJ{RDn>qLRy*O*kQgWz=^HO(c{=c)P zE-_|~MYnFauAejQh}jlH!3DOTrOricZQtYc#V-2tjLps6ix)V5Wq(ofpG7`#(bIe_ zt~ZUW1=5Oz>kJkR4R{yZxsFd{g!_8wSUaEb0D{@<&sr}JU z-|wDAJoe3R&S!qt65Pk1cJS@8qsB~o3z+m8^W4f7XEIg_dz1)md6RcPGp13K|H1pG zXH6SVo4q?2l{~9&ash*yZsD7GBC06`RgPuLWmV)`^(QWh{}SKuPcHXEuHJ+)>leG; z>^nZWN~ru`><_leW$X``dk&vYIB;}{)1wrTODor@e>6PfJkhs!qxQLr7Y<7JXD#tJ ztoJS3j3^P6|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31CyVpi(^Ox z=i6y}y=5Imj+RfJuti8(bkS5ZwI7XQ|Clw`s4VT6;N-39ddi`NB`$Tc7mKUQhRr?` z4@m^*xNOwP$4k+N`}&=YOT zu-FZ8!X=kqTn(>$Ay&Yo@~gHoqEt+!x3Qy#$^V&5?E3zKgC8w#Fh+Ks*u$It$fn?0 ze@NJ()%6Gdu0OzfEHC0^*}UTl PpcLlm>gTe~DWM4f%Re?g literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_card.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_card.png new file mode 100644 index 0000000000000000000000000000000000000000..471992ec8993997c777c52c4ac88d208fcceeb56 GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz1&S-^~7gA@w${E7uqZk{fVAsV8| z2@0Zr{{P?4+fmPGsK^j>`51>v9iwid>ZL{ZT~;l2kUZh}-}B;mm#(A$zslrwhHiniPvne}Y{(7F0h5a)Xv%ec$sia!yOJWhfjJl z{2gqkXFT889c}n5W1{E;pPBcw=Tt?!s@$Oa9iy0R$$!r@Z~ zw=1V#tdcU-l2|;)CHI%Q#b>*epvPy@9U^q2w%odO>+7oGGZwYtORxR-wqnA(gLZq` zpRb8~T9Fm$ajkHfpTj;g3&z+^&e|WR^J-$QTjZ678szhAda^ox#+qsR*3VvWU3_+m zFJ#YLiRqKLx75V`K6x&nG-c(*_s3a2|0$UAStQPxH*GD$x2@YxBx(9C>XZGII`7eb zrpdNF$IT>nGd(t&=C?QKWJAs*>H1&0{Ok^^M?CAjeEWO-Q~eh&JmxS*b^__CNb$3eho0E-Bev{@rIdryh^_*)b=XTp4JR3T(+xlsb%9dzt zdnHe=Q~e)*-kOH#0r9iB-)hyxRu@MkzP`O}u8Vx5;Ry$An?s^+ z4oypqoW5m0w^&|_YXyV(yccs0>(*F!ZhbwWH-@oTU8eaF&ojlhu?>aBK8MUS<|Uqb z&G{zz)Ir-lj&f2=z4KJ&CGKE2+T?DuyF)jiMO?!4>IcDpA~FZ8d)RjgUUM)M&iJ8t zau3g)gQg~uWkPosys~b4Ai3bH6X&OSTQ0iJW<5G7K0@>P+dAhDJQtSBo^MmnEx9Nh z(9#rdp%`g2X&>V**4l);|GV==`<2u+{oMag(Yq16D5_w=o2*&->zP-)xacnvv_M$4 zN~v;!qRsCOJc$q2T~?dS<-%**;dI^gNkF6Yg>Sc&&vTjYdi`Qw*U`%D>$fa7Sm45& zbRqJw$J*arW-rS>%v=4>cdq9`-p|4kY70&@%ZHue2;_?ro6mPECUw#JX0e(JPn`d} z4xO0R`(X7U%>}2|F?`+mW{%R=-RnXf4)VSFeo%Az53NZ{0(|Xe{{MWjygaD;oAB(( VoU!U+fuBK<>gnp|vd$@?2>>YD^~wMM literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_timeredit.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_timeredit.png new file mode 100644 index 0000000000000000000000000000000000000000..fe98501226f829efdfc14b06ff33000dd3df4d02 GIT binary patch literal 726 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfyu$s#WBQ# z_v%!Cj}S+hw2`# zJl~xAL+yUKzs?;8h0YwbKL7dBmZ#FfTMn?@n6}KA=Xlv1#z5gOhgsGf%--H{gKkj9tvl{lk(JLZVDyFIH zY|FiM&snQXJt9!RdR{KqzkAB74&FER+_OL_dVbdvjTdZ@;VPM|C)(XB`SzdldbwAY zRrac(wcHPu#~=9BlswfNp6Q)%dn@wyp2Df8TOV7_e^RV$F`ql{@r;A(S~GvSJ8ZXP zZ9iNQ=dHvj`GbwO@}!dNmR(EMJCrT%FtPX_8#(uX>$j3XLr;@k`ue_SPx$>(=>MVi z;`NHFJPuDHgf35uXoZOno^uK>T&`>S(7ihU`rAqD+ge4k@~t0e z>NNbj_^&DMne>ZBsol$R<}=>qj`}vETJC}UoDA>e!v|QVfYOwwtDnm{r-UW|dL$>F literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_voiceshare.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_voiceshare.png new file mode 100644 index 0000000000000000000000000000000000000000..610261900216f118d4213635e350d747c3ac62fc 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?G!`r!wCXy!V@38h}+=IZq8n)ReEJ_^MjBAUDouwOLlZWc=SMpqvNXl4yRpqMf_n*WOm{e7-hWRJvo)3(mL&o49KEAC^yeaX9Uz zTE{WAq)!~uOJ|*t>^N!rW9f_zftmv~cSOt_GTHSK7!-B7UdO1dxZ*f(+I`n9x4%Y{ zIoWrANaje8hY@5!HaVMme7nOnb73anEdHgZ;e%a!cYycYB*Xo2At zzb7kL&%Dd}_{4O1p+~a6`Tx(7*A;yf8U(C1uv#s8b{i!E-g=9qslGqLfj(Q9>CI#DCzi0MJ;3g*B-%@!Y{_X|I9WJw9RC@K|lN_M(E zn)mVV@q5SZs=ryPwN0(rd_C^<|LbPwQj2!h_tn^bUVU{{3G)Tc&>c;WYwXtl`F`+0 z*^QRy56-4vZ*BJT_{%2YZkXrHKIZ`6oW@1$X$$1FHk{agGj*-LgdLOq2bR+po>+$( z+h#72{b+j7_K?|*=5z_Jt~rZL+_e2?U*=lgam{g~RM?fUrM)s0*}LOdAF|GIKA8P< z1#h>*-UJ)*I{l6ASD3qs79DJh(tK4@JB8`*rkAhTIu7rz*mYiXdA#?d;*&Rb?$nL$ zpDTFvFLPASue-bEe7$gzf6kp{*OJp+zNXzaeLXRfeebSq+#8Z!MW>aDzustk=U(}_ z{~zU?>K|^`m~c`#f5B88#ZBVHS~orKKb*1($c`l#Nycr-#0XhS2Sxz2&wQUUY>c~BP=yvIsK56)TK=q zX8La6p0Vq*!?A3S)5?dpKTlk_@qp8;jzfnIxt;WysIxI}o5-Y`zl>gg7#A(m(b1gUc|#-k(5b!? zNo}8!A76JfG`72+{qFU-3d6;bR$pgUpWl1G_}uKz?`jub*#GwubsJhNSB^iIVBN5`?^>9XK^N zom(KhlKZvzi4&R&Z6~aD`{^_P&XF(cSocepZ0f66WL$oK?qc4@-1Uta>-)e zM47%sk)Q)tGU?U}=} zb}r`-J~RGPTOS>N;G)22R4dzS7;mH<-zqjnAOb+$Z? zZ?=nD+w(3wEFM6-hKS?O(jd?VuHYmnDUHx3vIVCg!0PzF( AfB*mh literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/payment_email.png b/TMessagesProj/src/main/res/drawable-mdpi/payment_email.png new file mode 100644 index 0000000000000000000000000000000000000000..37ad4f77f1ea0b53162bdae9c310138dc78695a2 GIT binary patch literal 713 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfyvm@#WBQ# z_wJPa{=tDF$8WbCw6HL+RERa5;J~x2d3Nd~DJOQBpW<^AeDsdEh)-Upljn1H&H^W% z84R49yqvNsie-!&13qqVinF^P{_gb4*TxHbyXQQaTz&5Qoa*=0-@}y(SDv-J&dUFg z_00jrnpUne2Q^Acw{Vo4IUN1rn_Rl!v_$cL4L-vB@fAW{!5>6Y>=VWET-hDGn_ty6 z+iG61`wz`+x~`mC zeDYnS?FYe9kyP_qp?Z~oInhh^CVq)~WO~7KSMC>{jcXok-Qaqq@HRKA%p=ze)7zVW z+ssnCIA3J%vS}6kr^2{vTw)hZ@)f9WOI;l~|BiHp_{F$|SNBZ&#P?RT)>c)K{~OrPM7 zj$Ij6o>kFoIgB5fFLeImn4iE|v})np2Hgvpw_6HtZ$GL2GXF7SU3~DTcvc=8UZcIb z;`ME}e=@MmW3r7giv90n{WmxF65F-(fW2Mk58BuK{&Bm2-6hjs+qVku zEn3X@k9W)3w&b>-w!c~@D(Bz(Fn8+#@BJInOeU0P{@8Z($Kh(Ws9CISzs0_abIxrx zHk(k%_i5gfOtEO@xzExw4l=6$Y<_)T%YyOoYtz^^)fqfFpZj*4J7{_NNTZCs&u6w0 zh4p@YJ5O ZoN@27n8T*=krAL!_jL7hS?83{1OSc zl&PMaKLc&%C!f3g_H6CtJC)MimS1PSw|qYD^WMvAXSysBTc`ivcb(L>hg^OM+-@ z!QFXRtFQ8zzkamkZ4Pd@6L@}hacXhf>jZz_a~JI*9m2Pkcl8}&TH_!mcY0PEf27ADHjh2d1&M8Y zj?P(rkFk?&b9~^rOConpZ98UX#aUn9^kjEcSp3AyijLGuqn{s7Za072`G_Y@A^lxt x+QUi7D)n{37x?#HU}lZ@W~1MH?a}-_2l!b%>Q8gLz99mN4Nq4;mvv4FO#n%z%Z2~| literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/payment_provider.png b/TMessagesProj/src/main/res/drawable-mdpi/payment_provider.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5187d71da0345d707a7efad61a8a5151beba35 GIT binary patch literal 523 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgftkl!RF~o!S z?UcP<%#I?h)bmpvkB2AhXHsqRfo#SxUs4I%FIcWUmW@GmU&axMum?c{i7-#>P<|EbU zEdHC#_1@fr(|?Fv@P8m#9j8{4ellvV_D{n(TZ4Yt$+YCk_-f4L(O$5TV|vNu$tF?% zT&`Ua*IPc(?`3tpj!E&u35&0*^oBiL%KE+`MRrAcbzY}IRdlxm3-^nyFPuD=%*_6# zbxp41;14biu?u;#-z*Z4%q(ENv&R2r#gzWDwr%FG&fUBfxsF}v|Fifnu75=5G`R;v zoEQDU-MZxS2f=-ZGM|A5|D_GeQo7^XjvEC1ff)68^!1J{+G>*inm sv#z#ze_HVy&XR@vAM{og?>|xTm$%BzIIlrH&jJ(?p00i_>zopr0ND}CdjJ3c literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_card.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_card.png new file mode 100644 index 0000000000000000000000000000000000000000..844da73b99ec0b729d5e1a312b0080b99f73239d GIT binary patch literal 259 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 Yzhra_ZTAFRQvd(}07*qoM6N<$g6X*d<^TWy literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_timeredit.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_timeredit.png new file mode 100644 index 0000000000000000000000000000000000000000..4a6b4ba2f640a9c41dadac51ba33901879ec449b GIT binary patch literal 1437 zcmV;O1!DS%P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NH2T4RhRA>e5nQf>RMHI(<%2zN8 zHD59-sgN+DHv{R#%q;3dkr7lB7oiVD5*0-S6KBqf6`p-Gfr7-D{i zLWv?R!$K{s%IDmBcN!%;#db>0+$Wgk#KSEfE4=*(n2u$m<)zQ zCxhtpgEI&02dTCb;%yxt1frwB4PYtQ1~e^x1hZqw;ApU8!31y)m!31iC)+7WKx0z5}K!hHBMXA-@$p&a7Y)5U9dlCcY{a4 zqC%fF*G0u^5D?Wn^SX)WrBK!3o z$WP2u1&!$6p0*Z&n!kR&ueMJ7_d8*&USq7!myV-qlL3q-&R@g(UO)Cn=o-l5UBIiZ z?jPq+{8zfZj#b&Y9z<-J6V!q*+}g1L++;+`-QaU;BfNvUU>4mQ8L>h6fs4_GPd7HR zIs@qDqWdf`FYl(*BYg&R=e~{?KSSIYO~PXu1H9Fqze?f-s5jEcb>4MaYis~j zPvA@=<>j}9_OWjMoKE?-8*9HIWe6KKw`&>J< z>hrf(q^be5NqL6iOP!RMska59_CS6ry~ZH!N)k9q^7)H5_bAKPNa9asOMGA5I$HBV z4=~gA4bNEMM%~KXD;wIGZtfkxB4jR zGm-);NN5z#5(n{JS`nff=?^!%Xs2ykAnJ39PF!Xys}iO5A@;Zl=H*+VSo$Xe9c|5) zhq$GFqLy1Er5=Cf-6|C+aiX)>={{IO$y{*s!kg(la#4s|>L*|#IA98tpMt8@t5m1V ziOwu=by=T$^j!@6i~nYbTj@t+5%9LOGN1#UBs(4a;F9WvKdX^6fjSlKaAK-X3vk9SL3PKkEePlAzI=(O*(X0o}abSZb$xD6gN?UoV(jsy*(2L|vFWIoF zxYRy$W`OU!IQ4CybD!N2TL2CNZ`*0yo_e809!Gy-Jk3V%NWY#=HyDJz(CPcWU+!o&w$(&V@AP#>^+-AbJOnla zzgeRhwLf6I2WCYRl@Ji>>x^gKopal#!00000NkvXXu0mjfE=+}x literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_voiceshare.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_voiceshare.png new file mode 100644 index 0000000000000000000000000000000000000000..f0b6e673a716235fd3237ab2f06553099b5549cc GIT binary patch literal 862 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^?OH;uw;_ z`gVrDhiIV4G1-#=-bMwm|x^tPX$v$DE0 ztO80Fyf{#Qv9W099o~7(>hbh{LQat6y&WbUgRIHReX4zS=hPgzJBBSqnpC!X0mK=o}9qr z(`@-bdituxW^0;u^*-RKc(d9>tv=|i@^ULn9ncpUkT{a%aZH9X@wC*WW6s_jvgw`@)aAy(?~T)@6i*J=pQ$ z_Roez{UTi10X9Ww+uFBD zG5ce1hJ~PdoX^dDb-z+BD&L#z^Ei4a9zPlaA1gVTTHwpvZ-ZF|*z z#p5m8li-s1S+X4G8$YjFQqSAdes<#g_YVI$Px~wUSfio-Wc4a@`%}D2Iqq|BlMX(* j;f2G+#zoAQ?+@e$tl(Og@Vxg2C~bSX`njxgN@xNA1+Hy& literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/payment_address.png b/TMessagesProj/src/main/res/drawable-xhdpi/payment_address.png new file mode 100644 index 0000000000000000000000000000000000000000..5b98c004875b1eee793947d2e1f64c7b2d4a6b0a GIT binary patch literal 1220 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 Zt^hIz_L{mq%+LS;002ovPDHLkV1kkEsc!%P literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/payment_name.png b/TMessagesProj/src/main/res/drawable-xhdpi/payment_name.png new file mode 100644 index 0000000000000000000000000000000000000000..5ce8b3a4022ff5da8c298269647af661031a1531 GIT binary patch literal 863 zcmV-l1EBngP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NE$w@>(RA>e5n7?ZjK@`Vx7KwsC zK`|JDidqO3rn5*RLMjQy&LVJ~BKR+)vlY?_+QfiZp4LKYtAG|3qDhEEK~Yfggox|s znOpfX;j%NkJK0;<2Vdsx-h1Eo<7RhfW@xC9rUOj}nhsRifmV#*Ns^4fyC2xN3A(LT z>j&fD3P}%xJKzQQ16*0>#yl7wxGG5M3RnR?(#2>FMEUoFn?oWu!6pcm4h}ZOsuL2p z2HffLl6!4%5{!UjU7P^t)iVUsC*b6>I>Nc0c>5_sQVCW`Ta& zCm?pGffoLr>wP}HrP&a0FZcygd5+@!P-1&4b?l8dN=wd%h@h981kU^TsSWaa7y91t>=udXkqUZvkH= z;2F_FRQ3B1;;6QH3s@DBb3BZ}4>A7J!m%uRe3gXj{Tj6vQAB+|WW54LDdHPQrCv*k zUJ>8%p}6;a;}jTBMImeP9#nI`HpGOZ3`cN`o7KfxE)OCK2or<7wMswouQ5w3IxFod6*MB=l*Bak>`s(fn|k|5 zrLtQaZ#RzSkmmA#%qqaXu&LOqayP_{qd9DgpH;xBc)Sxmn%aB!uSkG3(Zf{c-$n2c pw8K1$SyvUeSk{eq(}8L_@E4K7v@3XJrsV(t002ovPDHLkV1nlQaufgn literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/payment_phone.png b/TMessagesProj/src/main/res/drawable-xhdpi/payment_phone.png new file mode 100644 index 0000000000000000000000000000000000000000..d74d70a9da55bcb772232bf513ab52e5dde08352 GIT binary patch literal 994 zcmV<810DQ{P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFOi4sRRA>e5nBR*{Q547T88i$U z`4uxfAe0B|6l$)uKMAk9FUfqG^jsC4i`q0mCx zPOt%tf7OBf2lxu2Y>3J|-l<2_9PlwpxvBdBUs}saG*mFyF4`P5wnPt5`w3}O zRq$h4Q7rFioi`=I);c2FMI5n1AaCk^!&iGF+zLV1fDw8gz7LF<*eJZi{>CegxT{9& zXZVQm$KeOO66}gW;9euxrH9@2-uWn=2Hv{L@lSduHcSv=k2n*!9@f^&IN}?@pqYf6 zIxD>t8zu_DU1kD8?}H$$y?1fMHi3R%?L@tVPAYRKZ$oev=nIkDmo{>5>aBDl^s$Au zM}gd4<+3O@TDcTz`GWqQ;U{AVu-6M&4Ox}gcLCZ2K>i5rKR9k#dqs3xA~T?45pvfV zHivItK}*J_{(|$HI9LAdH#RB8R`kVqYoa2GV+tygcZ_KM3Tz zX_(!l;(1tQL|oqVYGY(hw$v%`-N~Z5a)dqv-JlIDc9juxZ@*1$o5X!Y$OC=}`~h($ z&&5+9&(b;22h?6CE;ecaRI~zlkh4I}^@-ZqsQznOhjRJv=mfWcJkW9Wm6gB0F2&*5QUVEW?e;uw;_ z`gX?t><~wRMsy$T?I_WjFE?9abOhEL~l8r+33&b)_{yRt=blS45BO^DF zhhyaxBe6rANz)@LT+W|2f75od%KzTmch&71m=B)=f|~Si$8YcUTOP2|0SX&d9w@Mw z)AatJ{Db&{=p_+dD{lm|U8+!;9RASr@~es!b4^z~SMR-ZWd8ceE;~Zf&o0qFQU0Lu zqN%3bp`Xq_c5o}{=+B9{*}^GfJni+}yze_-n(GDq?PmGN8KEL1L|RSENs;z`e)b5r+dCKeB&~(aw~f!q6=Y2Jt(TN8mA8!T{}-6EPjdFIM~=xE zPyJ4D{kVPXcik)2%WYO`eZssv6|^Trq-%2KusW`1sV#Mmt#9$2r1gvEh4RsPamu^w z*}e15|IStZ;LUb7>d8NIy?{7Fb5!32kiQQs-xXOBYwOs3dt=}(_ z-~HJrbb3-l{|g3lzFWtGXYXlUv)S{+L#{8p9hY-DPk&)|yT0W`eXr&@zqtvCO!+fP z4*O2ooL)M|B<1tPA6wtgzso*N{`U6P8;5@h{=LNSx8bi}&hIMQ#0?oa{ohm{Y?+?% z{_v^;`OC9cU;O;UwC33Tgq&nssa&S{x0xoZ@^QY1%*#~kerz_U;g?L#|9diDH|8*( zsxV}*i*DHt18x2GHKWLAHILKK6Ib7^n_I=8(Y6jykxt6^(WB-Ut{z`v;x5JLJaFa YhIh7)m`=M*a|h)EPgg&ebxsLQ0L3qic>n+a literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_card.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_card.png new file mode 100644 index 0000000000000000000000000000000000000000..b16909e05feb91de72cab9722b1d23f8253c13bc GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKNx+V1J%7!twx zcKSiiRs#W-UeyZWH;P~Xux;gy{$bm(^RL(=o)-r%H`Q$FK6B{NI_)zbgp^)dwQ}s4 z=&-ib>D&p~n^r44-*)C)j;smfKewU&!g&*u#Xl@&?|dRIb?aj9b?N8n3m3l1d8Bs# z{w@Yz3und|Cz?3^Om8@+*qy$k*rRPriWp<|I$ISdAa%|*WKF-+Id0yyysWw_r`m_d zT{v{-^sgzG*qkMID%eizpLONja`7o#f)#!b7_LlTX{plbmmdKI;Vst0Fo$h AH~;_u literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_addbio.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_addbio.png new file mode 100644 index 0000000000000000000000000000000000000000..aaf83b51a0ad096979b619872a6cbcd30347cf8d GIT binary patch literal 1986 zcmV;z2R-Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?EJ;K`RCodHoLh)hRT#%-(xfsk zl`|>Pgk{=8Mb?YVgOwCLNCjz;Y0(WTf?f(LhzK7n!l8PRGzqaQQD8+6Y9`r>PeGK? zl;q_>g_81`T57-lboRK;+TY%1?Q`}zmuWuu&tB_W-)((o?X}n1m+9&nrO^zGW*}k) zx+B_7nLd5`^jMhF!Avj(OsGI{90G^I@8B2kYj=0|363qLs0kt=O2SQG9+(T1n6p6$ zokU29`UZRrHj%J>96Osx%6VWhSPxEuvPiZzfk(llj>{53_kd;K0EkToaWDWbZTmzK z90kp$6F7VWTo5Z!4b4FWwurz6z_bDZY91K`yTC!9iTM;rChW^7UkNS&q4DiU z_Ic*0w>Y+*^oxOYAcVFfq+j_?5d2FcI|T211!tnxdEGN2Cw7mzW$BGWyePA{C8)T6t@w;NhVA{pu6Cm%h zy@B@Grg8)(zGi@TK^{F5!FAds5hyuXbeM*PX|3jP@U2m;5o3`?^pdEN;9w!h8abMa zu8kT%fN^4&1vK|qq@}>E0cMJeU|17!)||72ww~fv<7g1ec<=$RNF(gJQaxi(m-1bf zH+Y(eL-$mr##PH0ajngWc`y9FTKd8582dECkw#8iCP$r9Y(V=!i#EdyU3_Ne3M2Pf z*5T~{ZF5>>^?(>BfNz0CPiE-_@v*4Am4>5FhhSV2WTXv*h;=I1?RSE@uDV6GM%BGR zS-WJ57F0{Ne~nJuZgm9S%DSRQu@_jo^7VBY%u&M6WCaTLRG{+Y9F@A7u=zRgNvrT# zg$<(gif@U!7F(rWBC$6HYz01vH>PmlISSaD4*v2TQD2>-mTp2p>j-N_`c7K9F%EvT zOV6VDjag4?mEZ>k6fY={+eG`V84CI5rJ+y9W4vF{Sc{PQ9w=PtH}1Be9~34|Co1^zH6S z|2~12dB!L~R-<*=jhK8@67qIPhjfbl?-CS}m_$Yi+MiUMW9o(hi#ewcYy^7npkrTfYzVhxtASsWf&(ugh$AJ%rHuvDhaR>yeY5ID>y`@z9w?0c zV^HF)3gVN z3J!m|59HIH!hr`U_)b(0P#Y3SCh0CtvmbLrSL&nZijTF1FN7#6tR)4ko|RzAAixh?Aa@B8an3nmr5s!cD{)G#?&CYs>G^05$8t?;PCJqlsF*)2Pr?D)SaUO`HY}?9A2x7TO$XMZJ$K6{Y#w0 z*!(#t`9*Nvk*@(K@w-R*k|MXg?lM;A04)|R((AzObh>5s(+WOQxM%~$+x}C8T78O| zAUVguOPp{Rs>|>T%$*IJj3O_`zkPIH$>T{?f!KbnVqlkX6EOzzjQP!NKI8K4s zAJpmA%u8S=&@(Q5P@G!Nxt*dtMQ(ekWjtx(R&aTwrTQvR<|mo6v9|(PTcL;ZI*Cq- z^5h$C!<&`>>r!5AM!g^PUW~chz-yq^53(|^Q|SA9wcvZwxkEG0soHS7h{FJwrg|Xl zLv9f04HB)|wOvpg`fmz)X-i9otAW4Oft5)Qu>)9>)k>UtigAn6{w4BpKC*M13>9&n z{9}P5l$%YO4_^kUEt4B3?a7L}_;WGWP$Ol6(B!FL4}jS82M(5jBBQL4?vN2b8Oxq`VIXM)hL6^|ji4SWamK;aAK zji$dh88tz4s)|UMUbnd%=)FiKPp{bsTDa*gFC{?O4F*ZbKO9GCGy|g<7`Ykv7osm5 Uc&Y=rVgLXD07*qoM6N<$f_*8Y%K!iX literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_bio.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_bio.png new file mode 100644 index 0000000000000000000000000000000000000000..7a988c39edef527f189f39b28629b1f187d73e28 GIT binary patch literal 1715 zcmV;k22A;hP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>9Z5t%RCodHoXv|IMHt3+ObmoY zRueOY$T{BbNGqdRz9=f}#`u%vOy1Kr4R#tlH8R!{kk%2*rx}&OhcXtnx z`6hS=90jj9a9DZb@R;L0@L(_){L67J(g{Hja*XIsgO9+6;B6q1azy0Z2e-jCxCLR4 zI4-w9$|_g~H^G0Plt`C!O84s0v4qpd!6on~Xj^1MwvI16Q8>8#sZvfzm(wZTDUol(Qg$cO zgW3UUerXvQ<155OrFU(^V3sOFUSevBY|MY@ljjeV-D0*AXy+O{6Ouhp79ExI_ ze(c808vI!@w^w;CDPcK+P#3_G%VF89Ycy%f!WxxtWht1T5Oy@y`VKsF(0TS)E!Pw} zt5D~iuw^nd&uZJ0Pci_T-t%$;B(5MQ$230A9pF|{!tl}XeLk-QK4KL z6)JRsfis~I@A^z3Gb1(V*7z_K#TuQNd}(y|-pOa2YEH(NXIy;kCloq=FQF%um$)sN zr5F^8FN*b3Kfyn@2wL|Gxbv$_LTO^FwEUD%n957s7SD1qTs2BuFw*KtRJCKkdQOYY z=lE8!)ma-<*~R855Q<{f%1c@(qycFtTAON3FxJUi%ntyY*39HNzl?d#jhi7mTwgH@ zFL9z`GUD8{LJHd;E$W4GD@@o2*H%nc?0ccY=t1z0!EEtP+n&|=oDriQ>rfPXZME00 zL2u!1SYU^i|Bv~E(VkTola`%)QS9PiOnid0ULMNbFroA{zuF;i5mZABogXS~$IxfR zR^!00G1_GjN*jHj(8f0;eCZ`t=U;hgZJb)M)j05LP}qBxQ(EzCTdYo+l~&phE4CU3 zi$Kr`BXTRvC^l2l#01S`ZNJ{^*Ptv$_Yo1b$BEc#9P|W@|Kdr49*>uOe%0FAx?!v9 zBrCQW2YwCGKEP14KWD#+68_*c9(n`6$-T4{K|T9C@)nMW`5si2h@iij3INkrb;*s!i&U72WI^^F`^hXlDLzUV2ka)2}aXW>n?3X(K-(*Rc^5@+AUd{1kmNG@!pe6?hWNH5%rxSug z0wJv0FsVI(M}fAYRNGOs!$QzT0Fw&%p9C@IQ!kdF;ywcqae=002ov JPDHLkV1k9@Aa4Kw literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_timeredit.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_timeredit.png new file mode 100644 index 0000000000000000000000000000000000000000..21b2ff7b530d5f9fc29bd2d6d5e5fdf2d838a65a GIT binary patch literal 2185 zcmV;42zK|0P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?^GQTORCodHn`x+3RTRg4YB{8q zrkDk4vsz%;XvtI5%rb+tBpZk#3Qa$Vp)``88o*3K%!DWdiOk`Hg+&fDP_G z6G7LrzL#iZb8rGAk&`$r1;ao^-4&Vsa5U~`kXD3aV5W&>Nk(!lfs7xq1-~1>W{`!< zfuvLHBrJ#2mm^8Y{eK4-0_2zL2zG;M45F`bj4fWnTHx3m$gvIR33`L;yrWCw_hCB; zyhkntj`<78w*~itx4|Y5CX@5Zh@ic|RIn#30k3X8N9pM71>$C)FL)Vz4gLkLvJb;^ zv(M@jqws?Vz*itlmQ&g8lxK=Fh&q8WU;)?<(nxKJRARZ3l};JHilpT z_&X#>+^Q*dj6BOE*8$81^61xO3(Dm4CY-<1SVMGCbC+-O?2sUC@*N3|2IT!C`ee60 zjvE3q@;so#e7I&$5yJDVP1?y)eX5+Y;^Wr-g$MuH3bUMl2cQso!yEMjjlCq1Rs||EDV4d(IR)`7Wh?E^95asBVik@Z~e-up>v5y|tnFirEN7=dPmH|5SeAp&A2reH7cr zG+R@r_+)+sNj&1*qQsK-%4AC-ILd6)78#FPnhiA1shb33WkANGSs?O?#ioInoLQX{ zq$$vrMzp&mIxJ+98)RN6EROQTrv(V?MB879k;@e%af$VT67K~wrv~p>W~Fs5Yr(ce zPSd&HkJ(NYR9>s(a)qgjyyOjIZGhDR7%mlmx>L!pyjmf3aXP5GLbg%Sok=RKgDx~1 z;M76fr!q^nM|T+;_L^j8;Q0exC#AYT9eh4dzF%`ubpu^Xp=&At)fe< zqLbD`G87zC$ZF9oq?5GqLop9kY5Duw8K;AOQ9{Wtor};(Da16$;y-~|CLnW*6(0*={%z4C_~%PX020^-*zfU`>+p0X`u^3>A4 zQa)TZ%ISo-_ko~YB{P$Rh3`3F%Z4OeWgpmNpN%c^$_6=}5cClcv=89*xS`>yvl~Kr zT3jBVJp|fXuB-`N>@&=%K%A#Rko0#A3xTX{Xzd?$xsKzxgPNIOQGtf2y zEK0(c)Q248O4MDtAH)C`y;z|OUSe@rxJ9yOQKoX5HHpv9{Xn`Nkt}R zl~a+203Cp~yHtM7YcdU%5gB<60P^n(wroU^#jM<)DWs3vk-W0(0raiP`8^xIL_U{+ zpq+4obIFK+az8Hsnk+|oPA-9Cl9ESTpnXL}U6>w|E}l67&I4;Dk|ImdWxakAD?#FS z1#6VtMD+zo`z{xq4?(&C?E@U@;{RPV+T-8Mme{g&aF-;Z$gk+yoA$Y$6RaNydZCo} zw_&*^V389~#>b$1WJ78X%O(FJK_3G3AV}s>;rr&4byo2A0kSk3B(jHcP}Xss`3PPM zw8wubVR<8;0Ww{HhwoA_7ijNSsEe|dzuE$sbNezeB#G`|T`{HLKk`e;TFyw&CP`rY z+5>sR{{#fxPE-|T1%Kt=v?@bLrVUtBOfCA)QA}i=c`T4CP+nzxGh``)OTa)d0W1SS z>qAueWEQ20m~!}j9g>npJq5J4f7GEO>pn8L%R7=>ZDF?#)v9bmd%rKKN-U6MM=%pa z-3FLsBGRF+f<(9OY3oB0mRsa4AXi2nA`gct;IvLoQ+F^8Xaz=tPl2pPrV;6EnLfz2 z<6OoW-(Z-!^)U%(l>8s*tw6qY$tr++h?K3ka(kG$$xf2}K=xY8cPsgBwgRm5K8tgj zkC;j16CnXB9Vg%Gq?1~Ke*|u-uS&HCsy$Hcfocz&i9PTiCCCu>bG%e?00000 LNkvXXu0mjf`xy2f literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_voiceshare.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_voiceshare.png new file mode 100644 index 0000000000000000000000000000000000000000..67f50d7708b04e63b089d6a397563c4741105bd0 GIT binary patch literal 1356 zcmV-S1+)5zP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=mu)c;usRk86X=`sSQ$SN-Us@tpjq)uMQeN0O^gysFXN%OQ58=X5UUHvr9l)m~@6&1tcynqsu^AkR+rm z0}_|nMM(3Kf|PYY;xZR?Fq7sa0VxlF#AQCxa;uLUQeFUw%d1Ey?iq1H$`c@QS&Z6& zG%YSjc>^RaD^MGdrp5s&kATFb5q%A$Nh(CKyaE!F4d?=pCgc)Oaf!@|GB}QX7kz=R z&=VmN-H6Hme>elsP3R)D6zK+4uevJ5k>3{l44|DTI|h_`^cngY4WXp%WX;ooz+|); z>5)Y>pb+LcJ6e;FNO2BoMLo}@n@(Y0%|K%OQ_z0Yn+^-lsJl{!L~0+PF3%LxZ5Sc^ z_EaDdxB*>Bcl<`thw1fEB}j!z9fGtI@W0I&$LNV)7VKY=e7{gAeCw5L=na(9A#iq6 z_dUuA91TJHtc%4DR^>8_JcDpP5wE9EI%~RYNTDhQIcgm<>8kVSNPvLz5)RwY8mHq7 zmVX1#YtFnw11ioOEvYx1PBU8W2T<8_q$ua0GdY5z&-5F&4>lAaW{J{`W($%Arq`P@_HDU|UO!T&E2lL83Vc{r*FCf}KG|!`~r*^34Q3tw4l0#)Z zd@AVw7)XK{1<)b`43^3=-VYHyJR`(j(aGj(~o} zTQqJ%dUzI_;qL$nV`n+2;`!AiQNJa&*1$m*eOk~3rt+{s|DavM4Du_2>?9wZoFiLU zK)P&xj#@}WSDvIS=pcV2ku3>*SYu;kdQL!n9&=m&nOHv7JGpnn333kliT<(QNPEp7 z{j#FYW$5~PL>sOoXH98X(;1}us!imjTZvfBYbULrpg8R~74KCMjx)Yj`A-@)ke6;k zV>hoERQf*%eTt!Xq7gH$bdv7GzaCrMj~K`EaFZF-Oah^{>7G%|8~m2oJ>2Ml*IjdW zG4`jRP literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/payment_address.png b/TMessagesProj/src/main/res/drawable-xxhdpi/payment_address.png new file mode 100644 index 0000000000000000000000000000000000000000..39f1e849e9dca70dd35aa90c05395de937f24b65 GIT binary patch literal 1855 zcmV-F2f+A=P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>sYygZRCodHn_Y-iRTRf(1j~;! zL2N9fVM>k30zu$Y400n4pz)q4&+3&yK`l9e9L)s2gUZwIc{_Rmk1Cqo6#AVrzfKvH~qG&Dn&rtR& zz6bMXv@41Wh|@P|d)Uq@*bDJYaL!l6T%rp3liO%X;&j{$H71QS8|4;q4$`!*)<7YI z8H%E5pr$ofCgpzB;GGA4xxzno^ae-cUH@cQYFvo8fi(Cgt@GllMr1*@%U8hsPp}}O zT&^k7;IuH**sffO(uzSj7g)cqcBbW&?ML6vn%0a?q=Snx?jzh@xNP_vx)85V$9`~sgFv0z?_wK-)t_>j-l{*-Wv#&o8+C;?Xt7ag(C}q( zJwZ^T<|H)~qu3aG+eot3V1$jjLL0QmsC35gWpQoJ669iH8)Rv-){rVCv_aN>pvN;Y zwj?0wwt(2`P)nP&hU%P}O$P3nGKw!}#K&}7)kifsjJ;5-tDm<6frE+2 zs&QN1JY)4BSzJYw9RAHgaX$dZ*uxH_2}ql7L08gYtVF{$>@zZdG`LW~3DRWf94?r4 zq(Qq4;-SKc0}0SLWa!)-SSCCi(iH}=Tz7|8D<(r)QZ%k8hS94E`7uMlAup_DQ?wm2 z^yx2SIR^Q9Lx3Lt>Q$ANnlu3GQS|!Kgdsq8>&^n-^u3R|>diyExWPNVDCW`{b=Nam z7ld03A#yz)U9`zWxHn0FVNW($Iy@Z_Q^0XU%msXU&9_t&ClI%9(ir-SAs_7!uk_Wp z`K$RbWUm6R?p<59GJBN*B2o03r3&As0_e<=aBWP{aL`OB(}^%W3;)Rws3)7nUe>cv zI2HjtPxDQh7L?hGR4#<9_0_rgM~qFsmzYLO?W@3tj>{j`rRBB6kGeg+LO0)6lpyNw zP2r5a16h>Rk&n9GIQuk3@H2Tc!}D|s*Jt?4f1@nR0ui;4h$kxxgjzaaejTB(7SX`_zb z?0v4bn6sc;!FSeb@oDqzPlR&37+6nFa94f+w{ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/payment_card.png b/TMessagesProj/src/main/res/drawable-xxhdpi/payment_card.png new file mode 100644 index 0000000000000000000000000000000000000000..14d8c8087b737d7756adb6eb1da6b764ff72e60c GIT binary patch literal 692 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==Pq0fl1EO#WAFU z@$GDXufq-^$9g@&;|}zS3)r-9FPvWRRJMwHci^s%a!uU)ieH%aI^EUC_#>C*C2agt z>W{N<9dm!mr?};x|9&csDk&;(Xl7thU|{5MU|MLAtQ;`pj0!1O>f+s*=JUX%YzD*c}> z+kWQ{e{tulU%h?Ft-?ai(HUp9t!aKTFQRy!C|^?9hej1Ulk=bNWlv%_D|+_ZDsJPW zCmoLDFOw`@_e@S|R_;E{J6~Otb!IPKVSoGU*WXd%Qc)#e|GQmQcs;F=?fIN%y_1#| z1Z`eByL9FKt!z_QYRG=IJbP{VEJc}Szv6k8xykVjvt_EjGp0-cdaA9#^RWW+ixW?> zUv9g)Kg{3|AD@xAr~`u$i;on$q{CjZmv_z=ewM4A{_b;XbMu+E%mNKOjFXQ!LKHBb z5HQG;VNq~Cu%wWXggt}E@2+g$`Zsb%*;dV3vHqO-+Lg;rJFX7dQo84smHeyB*==TP z@BVrsW>&}*Smr&KVIyxu!zOvdzmpBh>hyNinsvQdbm^9s+Uo@?rgcAxWRr8va9!T5 zBz@k%N3^`_#zZ?%Xa_$pmQvhy*)ecJ)K;~R79mWB1fj78kHCLD2h^9Z{JWpy$|7A* Oit%*yb6Mw<&;$Tt>jSp{ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/payment_delivery.png b/TMessagesProj/src/main/res/drawable-xxhdpi/payment_delivery.png new file mode 100644 index 0000000000000000000000000000000000000000..8ed8b265545e1265138cf9695c2a147c2fedce2a GIT binary patch literal 1544 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 Cq9UmP literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-anydpi-v26/ic_launcher_sa.xml b/TMessagesProj/src/main/res/mipmap-anydpi-v26/ic_launcher_sa.xml new file mode 100644 index 00000000000..bd195b5c43b --- /dev/null +++ b/TMessagesProj/src/main/res/mipmap-anydpi-v26/ic_launcher_sa.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/mipmap-hdpi/ic_launcher_sa.png b/TMessagesProj/src/main/res/mipmap-hdpi/ic_launcher_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..fede4550b3dda0677bdf8536deafc2dab3421543 GIT binary patch literal 5750 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-hdpi/icon_foreground_sa.png b/TMessagesProj/src/main/res/mipmap-hdpi/icon_foreground_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..188a738cc26d9d689696f63d10691e9603c2ebba GIT binary patch literal 1857 zcmdT_{XY{37~h04A4Q}x(aSoo7v*IslWNSWjfjinWSBF_OBP8h@>Z7NFmzs)658^T zm$cF$CK+dK%Vnq=810TY1)wqYXV(XK&_!f03I#A-_getK)ZYNg8`Mk7)Sd!pD%B9m3V4tb?Q{ITf0zUN$chq?<>S@TkNp27< zJ%23LL@cb)l2^jgGMzTj#+${ELDEY7^^D`#*~o+;u1@KSAV-9x3yT8iXR_FVxby%y zmetl(tO6_yRO31>=Z28IUU$g5s_Q)_mRVHW(E2b_-dKsv&QdKtwMp2$aJ7)aViW2o zw5QTC9`bNV^94Me%>IhiP?<@In+kOoOxHataKKC_69YfDKGHWHuJj*C>GT<;r317b z(Bl2S>YTe>;7O=uIoCbQx-b9h9)VOh+0uD))F2AjG7i~pkuSN+`ZVbQqJ{kw!1XMj zv$}%MsDKVG{Xp z!nh}I+VFk8CVD~4TeILfUV9o6GGFChx|(-bqz!SvuO+az8V{W)eqwOIil$-(&l^L# z!{l!Z*h@mqEtV22ski*g*?k8=U1$#TJFz({HRhX+ctr650T#u_JF1Wezc0$7A#5u* zziPO`2q|9D6B#gguiB*F{i&FK74rC?>A9$i*W%#zZhLi3??KlXpXWXEhd#vn=5Heb za`eXJ^V6|;{0B00L5!sMy6^VI&_%h2LtMod>3(4FnyM7Ht!3OS)Nfc&J6ShQG_c2e z4ZI-fqTZEKF&y;X$b`HvNgxY19DT;#yOmsi8%N5v>f}%`5hHg%mdTOS#%%j@{3c#_ zSN>dt(`y!{2*W^(=vve&p5nXstNS$l`L6pUeI^UplqN3!n9M;sW)vhvXI|xF0(dSb zoNw)FT0X!Y)K68qPfKqaXF{+!K~o`8jkuDq-C(f1pd>j-udD9Q9jjbCpi?9OlpD}XT(r#Yj6#F*$XlK^N?6s5iCtWHQMJp6X$1{Ar};BiKAZH@*j zHzGUV;drCn6+6-d=v%Pf^IH)+2soOhD?Lo?|4qhtGv%M`PQ{OKLd$w|jCICm=PpPi zWh|d$IZoZMKNmEm)_+}{p_u9eX^`iK`)))?(cRPS=8i_xy(NKrJo&y*bbZ3K zt_cMV$G%y6o`;#?!=4`w#q!SuWJLRAFF9*RvfdBvi literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-mdpi/ic_launcher_sa.png b/TMessagesProj/src/main/res/mipmap-mdpi/ic_launcher_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..19df9e17136d9776d54aae896106b02a7a4e7d4a GIT binary patch literal 3179 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 FV1hoy=pg_A literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-mdpi/icon_foreground_sa.png b/TMessagesProj/src/main/res/mipmap-mdpi/icon_foreground_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..e73ac3b18c97ead3e516ef8dd47304c3d7914261 GIT binary patch literal 1178 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz1|<8_!p{OJ#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz1gS-^~7gB1R}eM^pkfrZ7>#WAFU z@$IeCtA*2L+6()m){EpTtnd)Ms3dokThCRXB>13StKJ?(y){9FPvsRvx)iit9BX}W zsC5CyBUaa?+Jy@jh?#4xP^h>br2kcDez-s1;W=kiCZAE9eDd?5>pp4EYCrFrFK?Nq zCTVnJSpyT7#scaQ7uXu-ne9nSjNcTr(kHoS{{+`1PT#(M`Euvs#V`@ZE|Y0%)Tf^m z7s}nfq!o%nm$p=+_LxS5#}d>%(8W%R_u%mj!%?* z636`FV(_`oDQc3Qd9M5_IpnpQm-1g(&g}J^rE@nM+@O{@!iA}A4KHt^< zykGz2#&uS~+uSDzOS)M`zkQwD#jxP=$@xzz+3x&U`S<;*4?!|K*sVZZT;i8ZbH>j?(3nqPc%sHdh=Sf-&6ao zS5B3kudqWEQ>1s_gxyPS$!!qar#3TWwf%4LN$E?jmTkE9<6U+D!`}j5GrPAXefkP( zW4JEt-T!yqx2U%^*96O7|5Q8^J;5o5y{hy~UJlotc zzbM8dvA!mFTGQPH5$45OH-zt9^e>ju{+{R+XwYDJbgrmm#L(dJSHabsPl#m!H zq8nqqR_XSM`Xx8RUNo8RUg7lpv9rgHf`7aJ8^>?!G8@9fh)YDd_ Q2PzjlUHx3vIVCg!00V*VrT_o{ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-xhdpi/ic_launcher_sa.png b/TMessagesProj/src/main/res/mipmap-xhdpi/ic_launcher_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..88fad92c5c9b9b24fd4c27d4443d553dc60def13 GIT binary patch literal 8405 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-xhdpi/icon_foreground_sa.png b/TMessagesProj/src/main/res/mipmap-xhdpi/icon_foreground_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..ac5945bf84101821e815e748cf8c5254987db435 GIT binary patch literal 2868 zcmeHJX*(N;7LJr#qNZ0(xwY4nG*QdgmneglG>NpK1})LC?@Nl3pkZ1ww3bAKSUWXQ zOT$&76}xsuEa_q_u~e5J5~&et4X)k~_kNmRaPNoryze>Z{dAt^JkR^{Wj7ZEkSYiO z04Ts+oiT?z`316nJFGuz8;A}`3WsrV1TZ-2ONWhfkQY1{g#thiwJbm?D-0n0#c~MM zLjV9rs-yr%4q58UtP1#_?PS%F|LQNsWr1lp0063hJAdbKOG-40e^ec$arDn8QQ=Y1 zerLHRCtI5{PJWZ)c+4bo$|UrGefuXJ?gd0n2Jm##E7={F_Oq`kcR&WZvY~qg^sq8wd8j~PV!>;V)EOUF#8aWE!EVrMp4`0 zHb4p}E&KQXi@!R8!zQr4y)xs}y08CSS87msSy34Yrps*)AFDgM)_C!D&lw=3E<|tT z5(A!iCNm11w&fE)c_x*mKs*V_&#;DZi?36cFI{XM@;pj zYrv&s>@i3o+|u4;G}c^w#yx`Xq+)l{b*#hK9iQH8ZLL?!ifUx_dkfLTkx4t+FFxf? zDY*C>;;Cx(gpHQ#!PE&LC{nI0tQ~r%)o`s-J2^(&QM8bTMSMhxj6sp%EA4wq=o{tb z2o+s5G84PinRIYYl2m*fsHQjiQ3RigPG9O(PqCAc85gobq75%xb;EQRZeMOb4T)ij5G@|jrf&Dk2ebKQRI|8B z$+vq&b8{61gwwSTAx)rc&0eVXSSJD`c)q^f%d>+k#oVA(iYu-^)!9Z?a419b)$DO` zjDqN;`T7HS;AgqOxXN;ZWwJ?F`z%Sy&%|n1LU0uOqmEE(T2zVAGR?(#t`@r8@Tt&) zL2WJgS1ENRm6ep4ia*BO_@3i@eIM=mTfXt$;>*7J?T+^LBj@MO@xC*d&V@%mj@_+e z!74O5pX2hIwR{u@`taV(y4>=XG0hBrI;Bt0D#P>=F!3S%WLsPs z?BIk~k%Mx0a@&ieBwJO#mWS;|A+l(1fq(p-JZbl0f=B=72r4a0D0}bg0iAP3gJ~Aq zE(-GT*1m-kt%h#OWvA6)KV9!WUn{)8yJ_AsYj4FElK$<)Kr?hsZR;^_&WY-U|Gw}E z>7`ZzfV+5--EV-Z?+C%vpN)N0zjrdml*|f>)1+LdWa_Vs;jg`!m#Y%rsnA0Cl`EY> zbk$nm(oh@vV6$A*RH$3*y$3V%I;sJ*kx#S>KFW*t*@#k&TFgrKuwN<0YhL3|1ao+| zV>uQjZqZF@*c`MKh@zSJHCg7tzCq0l%aAc!(hnv*fhtefHm@YWOJ7jlFMREF<pEoGb$8#K9jL&-k|0XCYq)13$_Knp533 zW6%uLe#yBuN)of1P*xIn&`%O4k#=7VQpKUt0+j)QVI}fyJ^}Jf|5Od-xUV0nK{F(n z+btR4t$i(BioYYq-2=VZqwh-zpf`>b^@aEuEoJ* zJQc%ZEoCeoz22KwC~?GAGV$3~y*rovm8#5dkq=Tk6EgRVY9jLdmH5^yM1U7j{ZmwGSuu%xrq)^oGV=_Y`iVJw#GMqZ}&@&-j5N2U`TT# zeMOuQJHK`#HLP1WL|XXBIN{ucy0gienn@uFH@uyVHtKdX7~#2+ddzI)t#Q(9SZKrX+P zO(oN(*g3}{l!z4Fd;v7wXK9~Szg)1sh+G@=xs;n&?2!GQ&r>s3=DxgpKL~Fw)tz}2 zN6YRMWEsr-zdWjWrJ2EzQz1a&*q^L!;;QQH`)EyMhFds_O= zMribCTi(bqTjaFdO>n-WH&x<4th4(=lBtCW5%RSwG3rvH$JrL~@8jsQJ}0vv;4G** zwxYCfVx+?LZYye*^M)@?zphQWx=$OfAz{Jun~x8@F_(7MQGM==$eq8+0soshDN0VF Y^2k*aS6ltvm*fk8UvP6~IQnP&3o~@LA^-pY literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-xxhdpi/ic_launcher_sa.png b/TMessagesProj/src/main/res/mipmap-xxhdpi/ic_launcher_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..f8aa06f8f0ce18f7269a862647a94e5a06c3f308 GIT binary patch literal 15490 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

^+DKSFG12S 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 Ef;2q@_W%F@ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-xxhdpi/icon_background_sa.png b/TMessagesProj/src/main/res/mipmap-xxhdpi/icon_background_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..1bbf66361ec3be269cc966519b643a68c53546e7 GIT binary patch literal 33126 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-xxxhdpi/icon_background_sa.png b/TMessagesProj/src/main/res/mipmap-xxxhdpi/icon_background_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..5d9f485f5afa1bb985039d0a2b408bdd164a52dc GIT binary patch literal 51199 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/mipmap-xxxhdpi/icon_foreground_sa.png b/TMessagesProj/src/main/res/mipmap-xxxhdpi/icon_foreground_sa.png new file mode 100644 index 0000000000000000000000000000000000000000..07c31a0935803502772bfc93faa2b0fca8c4a013 GIT binary patch literal 7553 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 s_vBxq{9h3MPZ8z+PYetrue false - @null - @null - false + #4991cc + #527da3 + #808080 + #60808080 + true diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 6e5e94ac702..531d455156b 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -68,6 +68,8 @@ Postcode Receiver Full Name + Tip + Tip (Optional) Phone Number Email Save Shipping Information @@ -89,6 +91,7 @@ TEST INVOICE PAY %1$s Payment method + New card Payment provider Name Phone number @@ -113,6 +116,7 @@ Phone will be passed to %1$s as billing info. Email address will be passed to %1$s as billing info. Phone and email address will be passed to %1$s as billing info. + You paid **%1$s** for **%2$s**. New conversation Auto-Night Mode is off @@ -649,7 +653,10 @@ Collapse Expand Sorry, public polls can’t be forwarded to channels. + Sorry, invoices can’t be forwarded to secret chats. Sorry, polls can’t be forwarded to secret chats. + Sorry, games can’t be sent to secret chats. + Sorry, invoices can’t be sent to secret chats. Multiple Answers Tap to choose the correct answer Polls in Quiz Mode have one correct answer. Users can\'t revoke their answers. @@ -1856,6 +1863,8 @@ Ask a volunteer Telegram FAQ Telegram FAQ + Telegram Features + https://t.me/TelegramTips Add Account Select Account https://telegram.org/faq @@ -2864,6 +2873,9 @@ Clear payment info Are you sure you want to clear your payment and shipping info? Delete your shipping info and instruct all payment providers to remove your saved credit cards? Note that Telegram never stores your credit card data. + Payment info cleared. + Shipping info cleared. + Payment and shipping info cleared. Websites where you used Telegram to log in. Shipping info Payment info @@ -3032,6 +3044,7 @@ un1 started a voice chat You started a voice chat Voice chat started + Voice chat scheduled on %1$s Voice chat finished (%s) un1 invited un2 to the voice chat You invited un2 to the voice chat @@ -3465,6 +3478,7 @@ %1$s members talking %1$s members talking speaking + %1$d%% speaking listening wants to speak invited @@ -3484,6 +3498,7 @@ New paricipants are muted Share invite link End voice chat + Cancel voice chat Connecting... Leave voice chat Do you want to leave this voice chat? @@ -3492,6 +3507,7 @@ End voice chat VIEW VOICE CHAT Voice Chat + Scheduled Voice Chat Open voice chat The selected user is already in this voice chat. Sorry, you can\'t join voice chats as an anonymous administrator. @@ -3500,6 +3516,7 @@ Join voice chat Hey! Join our voice chat: %1$s Invite Members + Share Invite Link Remove Open Profile Open Channel @@ -3553,6 +3570,20 @@ Are sure you want to appear in this voice chat as your personal account? Voice chat sound muted. Voice chat sound unmuted. + Members of this group will be notified once you start the voice chat. + Subscribers of this channel will be notified once you start the voice chat. + You will be displayed as: + Start Voice Chat + Schedule Voice Chat + Start Now + Set Reminder + Cancel Reminder + Members of the group will be notified that the voice chat will start in %1$s. + Subscribers of the channel will be notified that the voice chat will start in %1$s. + Starts in + Late by + Share + We will notify you when it starts. Manage Invite Links You can create additional invite links that have a limited time or number of uses @@ -3759,6 +3790,30 @@ from %1$d chats from %1$d chats from %1$d chats + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days %1$d seconds %1$d second %1$d seconds @@ -4299,6 +4354,15 @@ \'Send today at\' HH:mm \'Send on\' MMM d \'at\' HH:mm \'Send on\' MMM d yyyy \'at\' HH:mm + \'Start today at\' HH:mm + \'Start on\' MMM d \'at\' HH:mm + \'Start on\' MMM d yyyy \'at\' HH:mm + \'Starts today at\' HH:mm + \'Starts on\' MMM d \'at\' HH:mm + \'Starts on\' MMM d yyyy \'at\' HH:mm + \'Today,\' HH:mm + MMM d\',\' HH:mm + MMM d yyyy\',\' HH:mm \'Remind today at\' HH:mm \'Remind on\' MMM d \'at\' HH:mm \'Remind on\' MMM d yyyy \'at\' HH:mm @@ -4324,4 +4388,25 @@ Cancel Forwarding this is you Open Chat + Add Photo + Add Bio + Edit Name + Bio + You can add a few lines about yourself. Everyone will see this text. + Tap to add a Bio + Edit Bio + Add description + Edit description + tap to add photo or bio + tap to add bio + tap to add photo + tap to add description + Tap to add photo or description + Edit title + Title + Set New Photo + Bio updated. + Name updated. + Channel title updated. + Channel description updated.