From 1e50785b9008b42f4c59813a025d9b9869ec5d7d Mon Sep 17 00:00:00 2001 From: xaxtix Date: Sat, 16 Apr 2022 17:43:17 +0300 Subject: [PATCH 1/3] Update to 8.7.0 --- TMessagesProj/build.gradle | 4 +- TMessagesProj/jni/voip/CMakeLists.txt | 4 + .../org_telegram_messenger_voip_Instance.cpp | 4 +- .../jni/voip/tgcalls/MediaManager.cpp | 2 +- .../jni/voip/tgcalls/NetworkManager.cpp | 1 + .../group/AudioStreamingPartInternal.cpp | 5 +- .../AudioStreamingPartPersistentDecoder.cpp | 2 +- .../tgcalls/group/GroupInstanceCustomImpl.cpp | 10 +- .../tgcalls/group/StreamingMediaContext.cpp | 24 + .../voip/tgcalls/group/VideoStreamingPart.cpp | 65 +- .../voip/tgcalls/group/VideoStreamingPart.h | 5 +- .../voip/tgcalls/platform/PlatformInterface.h | 2 +- .../platform/android/AndroidInterface.cpp | 2 +- .../platform/android/AndroidInterface.h | 2 +- .../voip/tgcalls/v2/ContentNegotiation.cpp | 696 +++++ .../jni/voip/tgcalls/v2/ContentNegotiation.h | 99 + .../jni/voip/tgcalls/v2/InstanceV2Impl.cpp | 1495 +++++------ .../tgcalls/v2/InstanceV2ReferenceImpl.cpp | 1023 ++++++++ .../voip/tgcalls/v2/InstanceV2ReferenceImpl.h | 59 + .../voip/tgcalls/v2/NativeNetworkingImpl.cpp | 279 +- .../voip/tgcalls/v2/NativeNetworkingImpl.h | 87 +- .../jni/voip/tgcalls/v2/Signaling.cpp | 192 +- TMessagesProj/jni/voip/tgcalls/v2/Signaling.h | 91 +- .../tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp | 2242 +++++++++++++++++ .../tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h | 59 + .../voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp | 705 ++++++ .../voip/tgcalls/v2_4_0_0/Signaling_4_0_0.h | 105 + .../rtc_base/synchronization/mutex_pthread.h | 3 + TMessagesProj/src/main/AndroidManifest.xml | 1 + .../widget/ChatListItemAnimator.java | 2 +- .../android/exoplayer2/SimpleExoPlayer.java | 7 - .../telegram/messenger/AndroidUtilities.java | 77 +- .../telegram/messenger/ApplicationLoader.java | 1 + .../org/telegram/messenger/BuildVars.java | 4 +- .../messenger/ChatThemeController.java | 1 + .../messenger/DownloadController.java | 98 +- .../org/telegram/messenger/FileLoader.java | 9 +- .../messenger/ForwardingMessagesParams.java | 1 + .../org/telegram/messenger/ImageLoader.java | 61 +- .../org/telegram/messenger/ImageReceiver.java | 7 +- .../telegram/messenger/LanguageDetector.java | 36 +- .../telegram/messenger/LocaleController.java | 23 +- .../telegram/messenger/MediaController.java | 39 +- .../messenger/MediaDataController.java | 246 +- .../org/telegram/messenger/MessageObject.java | 32 +- .../messenger/MessagesController.java | 292 ++- .../telegram/messenger/MessagesStorage.java | 26 +- .../messenger/NotificationCenter.java | 5 + .../messenger/NotificationsController.java | 239 +- .../telegram/messenger/OneUIUtilities.java | 46 +- .../messenger/SendMessagesHelper.java | 57 +- .../org/telegram/messenger/SharedConfig.java | 5 +- .../telegram/messenger/SharedPrefsHelper.java | 36 + .../org/telegram/messenger/Utilities.java | 15 +- .../telegram/messenger/VideoEditedInfo.java | 2 + .../messenger/ringtone/RingtoneDataStore.java | 318 +++ .../messenger/ringtone/RingtoneUploader.java | 97 + .../video/MediaCodecVideoConvertor.java | 8 +- .../messenger/video/TextureRenderer.java | 61 +- .../org/telegram/messenger/voip/Instance.java | 4 +- .../telegram/messenger/voip/VoIPService.java | 38 +- .../main/java/org/telegram/tgnet/TLRPC.java | 1619 +++++++++++- .../telegram/ui/ActionBar/ActionBarMenu.java | 13 +- .../ui/ActionBar/ActionBarMenuItem.java | 87 +- .../ui/ActionBar/ActionBarMenuSubItem.java | 13 +- .../ui/ActionBar/ActionBarPopupWindow.java | 143 +- .../telegram/ui/ActionBar/AlertDialog.java | 8 +- .../telegram/ui/ActionBar/BaseFragment.java | 8 +- .../telegram/ui/ActionBar/BottomSheet.java | 139 +- .../ui/ActionBar/DrawerLayoutContainer.java | 7 + .../java/org/telegram/ui/ActionBar/Theme.java | 116 +- .../org/telegram/ui/ActionIntroActivity.java | 82 +- .../telegram/ui/Adapters/DialogsAdapter.java | 129 +- .../ui/Adapters/DialogsSearchAdapter.java | 63 +- .../ui/Adapters/DrawerLayoutAdapter.java | 8 +- .../java/org/telegram/ui/ArticleViewer.java | 178 +- .../org/telegram/ui/CacheControlActivity.java | 20 + .../org/telegram/ui/CalendarActivity.java | 4 +- .../org/telegram/ui/CameraScanActivity.java | 75 +- .../org/telegram/ui/Cells/AboutLinkCell.java | 65 +- .../org/telegram/ui/Cells/ChatActionCell.java | 7 +- .../telegram/ui/Cells/ChatMessageCell.java | 514 ++-- .../telegram/ui/Cells/CreationTextCell.java | 79 + .../org/telegram/ui/Cells/DialogCell.java | 51 +- .../telegram/ui/Cells/DrawerProfileCell.java | 14 +- .../org/telegram/ui/Cells/HeaderCell.java | 8 + .../ui/Cells/NotificationsCheckCell.java | 7 +- .../telegram/ui/Cells/RadioButtonCell.java | 2 +- .../org/telegram/ui/Cells/TextCheckCell2.java | 25 + .../ui/Cells/TextSelectionHelper.java | 3 +- .../java/org/telegram/ui/Cells/UserCell2.java | 15 +- .../telegram/ui/ChannelAdminLogActivity.java | 17 +- .../java/org/telegram/ui/ChatActivity.java | 1688 ++++++++----- .../org/telegram/ui/ChatEditActivity.java | 2 +- .../ui/ChatReactionsEditActivity.java | 1 - .../telegram/ui/ChatRightsEditActivity.java | 772 +++++- .../org/telegram/ui/ChatUsersActivity.java | 24 +- .../telegram/ui/Components/AlertsCreator.java | 697 ++++- .../ui/Components/AnimatedFileDrawable.java | 20 +- .../ui/Components/AnimationProperties.java | 12 + .../ui/Components/AttachBotIntroTopView.java | 101 + .../ui/Components/AutoDeletePopupWrapper.java | 105 + .../ui/Components/BackupImageView.java | 6 + .../ui/Components/BotCommandsMenuView.java | 121 +- .../ui/Components/BotKeyboardView.java | 27 +- .../ui/Components/BotWebViewContainer.java | 800 ++++++ .../Components/BotWebViewMenuContainer.java | 657 +++++ .../ui/Components/BotWebViewSheet.java | 639 +++++ .../org/telegram/ui/Components/Bulletin.java | 3 + .../ui/Components/BulletinFactory.java | 75 +- .../ChatActivityBotWebViewButton.java | 135 + .../ui/Components/ChatActivityEnterView.java | 242 +- .../ui/Components/ChatAttachAlert.java | 633 ++++- .../ChatAttachAlertBotWebViewLayout.java | 812 ++++++ .../ChatAttachAlertContactsLayout.java | 2 +- .../ChatAttachAlertDocumentLayout.java | 163 +- .../ChatAttachAlertLocationLayout.java | 20 +- .../ChatAttachAlertPhotoLayout.java | 33 +- .../ChatAttachAlertPhotoLayoutPreview.java | 5 +- .../Components/ChatAttachAlertPollLayout.java | 4 +- .../ui/Components/ChatAvatarContainer.java | 94 +- .../ChatNotificationsPopupWrapper.java | 233 ++ .../ui/Components/ChatThemeBottomSheet.java | 15 +- .../Components/CircularProgressDrawable.java | 96 + .../ui/Components/Crop/CropTransform.java | 25 + .../ui/Components/CrossfadeDrawable.java | 31 + .../ui/Components/EmbedBottomSheet.java | 62 +- .../org/telegram/ui/Components/EmojiView.java | 12 +- .../ui/Components/FilterTabsView.java | 3 +- .../ui/Components/ForwardingPreviewView.java | 13 +- .../ui/Components/FragmentContextView.java | 16 +- .../ui/Components/InstantCameraView.java | 65 +- .../org/telegram/ui/Components/LinkPath.java | 17 +- .../ui/Components/LinkSpanDrawable.java | 364 +++ .../telegram/ui/Components/NumberPicker.java | 47 +- .../Components/Paint/Views/StickerView.java | 14 +- .../ui/Components/PhotoPaintView.java | 65 +- .../PhotoViewerCaptionEnterView.java | 2 + .../ui/Components/PhotoViewerWebView.java | 26 +- .../ui/Components/PipVideoOverlay.java | 941 +++++++ .../ui/Components/PopupSwipeBackLayout.java | 51 +- .../ui/Components/ReactedUsersListView.java | 3 +- .../Components/ReactionsContainerLayout.java | 30 +- .../ui/Components/RecyclerListView.java | 21 +- .../ui/Components/SearchViewPager.java | 6 +- .../ui/Components/SenderSelectPopup.java | 14 + .../ui/Components/SharedMediaLayout.java | 18 +- .../Components/SimpleFloatPropertyCompat.java | 4 + .../SizeNotifierFrameLayoutPhoto.java | 6 +- .../telegram/ui/Components/TableLayout.java | 6 +- .../telegram/ui/Components/TimerDrawable.java | 188 +- .../ui/Components/TranslateAlert.java | 62 +- .../ui/Components/URLSpanNoUnderline.java | 8 +- .../org/telegram/ui/Components/UndoView.java | 38 +- .../telegram/ui/Components/WebPlayerView.java | 17 +- .../Components/voip/CellFlickerDrawable.java | 19 +- .../Components/voip/RTMPStreamPipOverlay.java | 7 - .../ui/Components/voip/VoIPHelper.java | 6 +- .../java/org/telegram/ui/DialogsActivity.java | 122 +- .../java/org/telegram/ui/LaunchActivity.java | 256 +- .../org/telegram/ui/ManageLinksActivity.java | 81 +- .../NotificationsCustomSettingsActivity.java | 104 +- .../ui/NotificationsSettingsActivity.java | 20 +- .../ui/NotificationsSoundActivity.java | 956 +++++++ .../org/telegram/ui/PassportActivity.java | 19 - .../org/telegram/ui/PaymentFormActivity.java | 1 + .../org/telegram/ui/PeopleNearbyActivity.java | 20 +- .../java/org/telegram/ui/PhotoViewer.java | 1130 ++++++--- .../java/org/telegram/ui/ProfileActivity.java | 273 +- .../ui/ProfileNotificationsActivity.java | 188 +- .../org/telegram/ui/SecretMediaViewer.java | 85 +- .../org/telegram/ui/StatisticActivity.java | 2 +- .../java/org/telegram/ui/ThemeActivity.java | 26 +- .../org/telegram/ui/ThemePreviewActivity.java | 62 +- .../ui/TwoStepVerificationActivity.java | 10 +- .../ui/TwoStepVerificationSetupActivity.java | 11 +- .../src/main/res/drawable-hdpi/bot_invite.png | Bin 0 -> 232 bytes .../main/res/drawable-hdpi/bot_webview.png | Bin 0 -> 336 bytes .../main/res/drawable-hdpi/msg_autodelete.png | Bin 0 -> 928 bytes .../res/drawable-hdpi/msg_autodelete_1d.png | Bin 0 -> 1043 bytes .../res/drawable-hdpi/msg_autodelete_1h.png | Bin 0 -> 1002 bytes .../res/drawable-hdpi/msg_autodelete_1m.png | Bin 0 -> 1069 bytes .../res/drawable-hdpi/msg_autodelete_1w.png | Bin 0 -> 1128 bytes .../src/main/res/drawable-hdpi/msg_bot.png | Bin 0 -> 916 bytes .../main/res/drawable-hdpi/msg_customize.png | Bin 0 -> 794 bytes .../src/main/res/drawable-hdpi/msg_delete.png | Bin 638 -> 751 bytes .../res/drawable-hdpi/msg_delete_auto.png | Bin 1036 -> 1002 bytes .../main/res/drawable-hdpi/msg_disable.png | Bin 0 -> 803 bytes .../res/drawable-hdpi/msg_mini_autodelete.png | Bin 0 -> 755 bytes .../msg_mini_autodelete_empty.png | Bin 0 -> 638 bytes .../msg_mini_autodelete_timer.png | Bin 0 -> 436 bytes .../src/main/res/drawable-hdpi/msg_mute.png | Bin 770 -> 1157 bytes .../main/res/drawable-hdpi/msg_mute_1h.png | Bin 0 -> 1233 bytes .../main/res/drawable-hdpi/msg_mute_8h.png | Bin 0 -> 1360 bytes .../res/drawable-hdpi/msg_mute_period.png | Bin 0 -> 978 bytes .../src/main/res/drawable-hdpi/msg_silent.png | Bin 0 -> 801 bytes .../main/res/drawable-hdpi/msg_tone_add.png | Bin 0 -> 965 bytes .../main/res/drawable-hdpi/msg_tone_off.png | Bin 0 -> 1129 bytes .../main/res/drawable-hdpi/msg_tone_on.png | Bin 0 -> 831 bytes .../src/main/res/drawable-hdpi/msg_unmute.png | Bin 883 -> 969 bytes .../main/res/drawable-hdpi/msg_videocall.png | Bin 593 -> 688 bytes .../res/drawable-hdpi/pip_pause_large.png | Bin 0 -> 470 bytes .../main/res/drawable-hdpi/pip_play_large.png | Bin 0 -> 651 bytes .../res/drawable-hdpi/pip_replay_large.png | Bin 0 -> 984 bytes .../src/main/res/drawable-mdpi/bot_invite.png | Bin 0 -> 186 bytes .../main/res/drawable-mdpi/bot_webview.png | Bin 0 -> 276 bytes .../main/res/drawable-mdpi/msg_autodelete.png | Bin 0 -> 643 bytes .../res/drawable-mdpi/msg_autodelete_1d.png | Bin 0 -> 725 bytes .../res/drawable-mdpi/msg_autodelete_1h.png | Bin 0 -> 707 bytes .../res/drawable-mdpi/msg_autodelete_1m.png | Bin 0 -> 740 bytes .../res/drawable-mdpi/msg_autodelete_1w.png | Bin 0 -> 777 bytes .../src/main/res/drawable-mdpi/msg_bot.png | Bin 0 -> 657 bytes .../main/res/drawable-mdpi/msg_customize.png | Bin 0 -> 525 bytes .../src/main/res/drawable-mdpi/msg_delete.png | Bin 427 -> 523 bytes .../res/drawable-mdpi/msg_delete_auto.png | Bin 627 -> 652 bytes .../main/res/drawable-mdpi/msg_disable.png | Bin 0 -> 646 bytes .../res/drawable-mdpi/msg_mini_autodelete.png | Bin 0 -> 509 bytes .../msg_mini_autodelete_empty.png | Bin 0 -> 444 bytes .../msg_mini_autodelete_timer.png | Bin 0 -> 319 bytes .../src/main/res/drawable-mdpi/msg_mute.png | Bin 496 -> 762 bytes .../main/res/drawable-mdpi/msg_mute_1h.png | Bin 0 -> 809 bytes .../main/res/drawable-mdpi/msg_mute_8h.png | Bin 0 -> 851 bytes .../res/drawable-mdpi/msg_mute_period.png | Bin 0 -> 736 bytes .../src/main/res/drawable-mdpi/msg_silent.png | Bin 0 -> 609 bytes .../main/res/drawable-mdpi/msg_tone_add.png | Bin 0 -> 661 bytes .../main/res/drawable-mdpi/msg_tone_off.png | Bin 0 -> 738 bytes .../main/res/drawable-mdpi/msg_tone_on.png | Bin 0 -> 592 bytes .../src/main/res/drawable-mdpi/msg_unmute.png | Bin 552 -> 690 bytes .../main/res/drawable-mdpi/msg_videocall.png | Bin 429 -> 505 bytes .../res/drawable-mdpi/pip_pause_large.png | Bin 0 -> 365 bytes .../main/res/drawable-mdpi/pip_play_large.png | Bin 0 -> 450 bytes .../res/drawable-mdpi/pip_replay_large.png | Bin 0 -> 681 bytes .../main/res/drawable-xhdpi/bot_invite.png | Bin 0 -> 243 bytes .../main/res/drawable-xhdpi/bot_webview.png | Bin 0 -> 384 bytes .../res/drawable-xhdpi/msg_autodelete.png | Bin 0 -> 1273 bytes .../res/drawable-xhdpi/msg_autodelete_1d.png | Bin 0 -> 1426 bytes .../res/drawable-xhdpi/msg_autodelete_1h.png | Bin 0 -> 1358 bytes .../res/drawable-xhdpi/msg_autodelete_1m.png | Bin 0 -> 1505 bytes .../res/drawable-xhdpi/msg_autodelete_1w.png | Bin 0 -> 1591 bytes .../src/main/res/drawable-xhdpi/msg_bot.png | Bin 0 -> 1199 bytes .../main/res/drawable-xhdpi/msg_customize.png | Bin 0 -> 989 bytes .../main/res/drawable-xhdpi/msg_delete.png | Bin 745 -> 992 bytes .../res/drawable-xhdpi/msg_delete_auto.png | Bin 1269 -> 1333 bytes .../main/res/drawable-xhdpi/msg_disable.png | Bin 0 -> 1204 bytes .../drawable-xhdpi/msg_mini_autodelete.png | Bin 0 -> 984 bytes .../msg_mini_autodelete_empty.png | Bin 0 -> 829 bytes .../msg_mini_autodelete_timer.png | Bin 0 -> 489 bytes .../src/main/res/drawable-xhdpi/msg_mute.png | Bin 1027 -> 1507 bytes .../main/res/drawable-xhdpi/msg_mute_1h.png | Bin 0 -> 1671 bytes .../main/res/drawable-xhdpi/msg_mute_8h.png | Bin 0 -> 1856 bytes .../res/drawable-xhdpi/msg_mute_period.png | Bin 0 -> 1351 bytes .../main/res/drawable-xhdpi/msg_silent.png | Bin 0 -> 1121 bytes .../main/res/drawable-xhdpi/msg_tone_add.png | Bin 0 -> 1275 bytes .../main/res/drawable-xhdpi/msg_tone_off.png | Bin 0 -> 1427 bytes .../main/res/drawable-xhdpi/msg_tone_on.png | Bin 0 -> 1064 bytes .../main/res/drawable-xhdpi/msg_unmute.png | Bin 1206 -> 1353 bytes .../main/res/drawable-xhdpi/msg_videocall.png | Bin 815 -> 909 bytes .../res/drawable-xhdpi/pip_pause_large.png | Bin 0 -> 651 bytes .../res/drawable-xhdpi/pip_play_large.png | Bin 0 -> 900 bytes .../res/drawable-xhdpi/pip_replay_large.png | Bin 0 -> 1330 bytes .../main/res/drawable-xxhdpi/bot_invite.png | Bin 0 -> 303 bytes .../main/res/drawable-xxhdpi/bot_webview.png | Bin 0 -> 437 bytes .../res/drawable-xxhdpi/msg_autodelete.png | Bin 0 -> 1900 bytes .../res/drawable-xxhdpi/msg_autodelete_1d.png | Bin 0 -> 2147 bytes .../res/drawable-xxhdpi/msg_autodelete_1h.png | Bin 0 -> 1980 bytes .../res/drawable-xxhdpi/msg_autodelete_1m.png | Bin 0 -> 2303 bytes .../res/drawable-xxhdpi/msg_autodelete_1w.png | Bin 0 -> 2470 bytes .../src/main/res/drawable-xxhdpi/msg_bot.png | Bin 0 -> 1692 bytes .../res/drawable-xxhdpi/msg_customize.png | Bin 0 -> 1463 bytes .../main/res/drawable-xxhdpi/msg_delete.png | Bin 724 -> 1288 bytes .../res/drawable-xxhdpi/msg_delete_auto.png | Bin 1828 -> 1834 bytes .../main/res/drawable-xxhdpi/msg_disable.png | Bin 0 -> 1659 bytes .../drawable-xxhdpi/msg_mini_autodelete.png | Bin 0 -> 1438 bytes .../msg_mini_autodelete_empty.png | Bin 0 -> 1190 bytes .../msg_mini_autodelete_timer.png | Bin 0 -> 733 bytes .../src/main/res/drawable-xxhdpi/msg_mute.png | Bin 1198 -> 2300 bytes .../main/res/drawable-xxhdpi/msg_mute_1h.png | Bin 0 -> 2540 bytes .../main/res/drawable-xxhdpi/msg_mute_8h.png | Bin 0 -> 2863 bytes .../res/drawable-xxhdpi/msg_mute_period.png | Bin 0 -> 1921 bytes .../main/res/drawable-xxhdpi/msg_silent.png | Bin 0 -> 1356 bytes .../main/res/drawable-xxhdpi/msg_tone_add.png | Bin 0 -> 1909 bytes .../main/res/drawable-xxhdpi/msg_tone_off.png | Bin 0 -> 2341 bytes .../main/res/drawable-xxhdpi/msg_tone_on.png | Bin 0 -> 1609 bytes .../main/res/drawable-xxhdpi/msg_unmute.png | Bin 1598 -> 1942 bytes .../res/drawable-xxhdpi/msg_videocall.png | Bin 1046 -> 1126 bytes .../res/drawable-xxhdpi/pip_pause_large.png | Bin 0 -> 1070 bytes .../res/drawable-xxhdpi/pip_play_large.png | Bin 0 -> 1450 bytes .../res/drawable-xxhdpi/pip_replay_large.png | Bin 0 -> 2040 bytes .../src/main/res/drawable/avd_flip.xml | 136 + .../src/main/res/drawable/tg_splash_320.xml | 110 + .../src/main/res/drawable/vd_flip.xml | 53 + .../res/raw/bot_webview_cross_to_sheet.json | 1 + .../res/raw/bot_webview_sheet_to_cross.json | 1 + .../main/res/raw/durgerking_placeholder.svg | 1 + TMessagesProj/src/main/res/raw/mute_for.json | 1 + .../src/main/res/raw/sound_download.json | 1 + TMessagesProj/src/main/res/raw/sound_off.json | 1 + TMessagesProj/src/main/res/raw/sound_on.json | 1 + .../src/main/res/raw/utyan_change_number.tgs | 1 + .../src/main/res/raw/utyan_newborn.json | 1 - .../src/main/res/raw/utyan_newborn.tgs | 1 + .../src/main/res/values-night/styles.xml | 3 + .../src/main/res/values-v31/styles.xml | 15 + TMessagesProj/src/main/res/values/ids.xml | 5 + .../src/main/res/values/integers.xml | 4 + TMessagesProj/src/main/res/values/strings.xml | 106 +- 306 files changed, 22967 insertions(+), 3965 deletions(-) create mode 100644 TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.cpp create mode 100644 TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.h create mode 100644 TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.cpp create mode 100644 TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.h create mode 100644 TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp create mode 100644 TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h create mode 100644 TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp create mode 100644 TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.h create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/SharedPrefsHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneDataStore.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneUploader.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/CreationTextCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewContainer.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewMenuContainer.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityBotWebViewButton.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_invite.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_webview.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1d.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1h.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1m.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1w.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_bot.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_customize.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_disable.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete_empty.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete_timer.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_mute_1h.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_mute_8h.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_mute_period.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_silent.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_tone_add.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_tone_off.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_tone_on.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pip_pause_large.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pip_play_large.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pip_replay_large.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_invite.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_webview.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1d.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1h.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1m.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1w.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_bot.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_customize.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_disable.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_empty.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_timer.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_mute_1h.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_mute_8h.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_mute_period.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_silent.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_tone_add.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_tone_off.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_tone_on.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pip_pause_large.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pip_play_large.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pip_replay_large.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_invite.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_webview.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1d.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1h.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1m.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1w.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_bot.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_customize.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_disable.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_empty.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_timer.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_1h.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_8h.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_period.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_silent.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_add.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_off.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_on.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pip_pause_large.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pip_play_large.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pip_replay_large.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_invite.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_webview.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1d.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1h.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1m.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1w.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_bot.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_customize.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_disable.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_empty.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_timer.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_1h.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_8h.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_period.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_silent.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_add.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_off.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_on.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pip_pause_large.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pip_play_large.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pip_replay_large.png create mode 100644 TMessagesProj/src/main/res/drawable/avd_flip.xml create mode 100644 TMessagesProj/src/main/res/drawable/tg_splash_320.xml create mode 100644 TMessagesProj/src/main/res/drawable/vd_flip.xml create mode 100644 TMessagesProj/src/main/res/raw/bot_webview_cross_to_sheet.json create mode 100644 TMessagesProj/src/main/res/raw/bot_webview_sheet_to_cross.json create mode 100644 TMessagesProj/src/main/res/raw/durgerking_placeholder.svg create mode 100644 TMessagesProj/src/main/res/raw/mute_for.json create mode 100644 TMessagesProj/src/main/res/raw/sound_download.json create mode 100644 TMessagesProj/src/main/res/raw/sound_off.json create mode 100644 TMessagesProj/src/main/res/raw/sound_on.json create mode 100644 TMessagesProj/src/main/res/raw/utyan_change_number.tgs delete mode 100644 TMessagesProj/src/main/res/raw/utyan_newborn.json create mode 100644 TMessagesProj/src/main/res/raw/utyan_newborn.tgs create mode 100644 TMessagesProj/src/main/res/values/integers.xml diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 29b6baa91..b700ac90a 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -300,7 +300,7 @@ android { } } - defaultConfig.versionCode = 2600 + defaultConfig.versionCode = 2622 applicationVariants.all { variant -> variant.outputs.all { output -> @@ -319,7 +319,7 @@ android { defaultConfig { minSdkVersion 16 targetSdkVersion 30 - versionName "8.6.2" + versionName "8.7.0" vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi'] diff --git a/TMessagesProj/jni/voip/CMakeLists.txt b/TMessagesProj/jni/voip/CMakeLists.txt index da5a84b6a..74acffcf3 100644 --- a/TMessagesProj/jni/voip/CMakeLists.txt +++ b/TMessagesProj/jni/voip/CMakeLists.txt @@ -457,6 +457,10 @@ add_library(tgcalls STATIC voip/tgcalls/v2/NativeNetworkingImpl.cpp voip/tgcalls/v2/Signaling.cpp voip/tgcalls/v2/SignalingEncryption.cpp + voip/tgcalls/v2/ContentNegotiation.cpp + voip/tgcalls/v2/InstanceV2ReferenceImpl.cpp + voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp + voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp voip/webrtc/rtc_base/bitstream_reader.cc voip/webrtc/rtc_base/async_invoker.cc voip/webrtc/rtc_base/system_time.cc diff --git a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp index 96a05d237..7f4e9e35d 100644 --- a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp +++ b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp @@ -24,12 +24,14 @@ #include "libtgvoip/os/android/JNIUtilities.h" #include "tgcalls/VideoCaptureInterface.h" #include "tgcalls/v2/InstanceV2Impl.h" +#include "tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h" using namespace tgcalls; const auto RegisterTag = Register(); const auto RegisterTagLegacy = Register(); -const auto RegisterTagV2 = Register(); +const auto RegisterTagV2_4_0_0 = Register(); +const auto RegisterTagV2_4_0_1 = Register(); jclass TrafficStatsClass; jclass FingerprintClass; diff --git a/TMessagesProj/jni/voip/tgcalls/MediaManager.cpp b/TMessagesProj/jni/voip/tgcalls/MediaManager.cpp index 2db2b783f..0f5d5558f 100644 --- a/TMessagesProj/jni/voip/tgcalls/MediaManager.cpp +++ b/TMessagesProj/jni/voip/tgcalls/MediaManager.cpp @@ -408,7 +408,7 @@ _platformContext(platformContext) { rtc::scoped_refptr MediaManager::createAudioDeviceModule() { const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { #ifdef WEBRTC_IOS - return rtc::make_ref_counted(false, false); + return rtc::make_ref_counted(false, false, 1); #else return webrtc::AudioDeviceModule::Create( layer, diff --git a/TMessagesProj/jni/voip/tgcalls/NetworkManager.cpp b/TMessagesProj/jni/voip/tgcalls/NetworkManager.cpp index faa7f50e7..fd87da112 100644 --- a/TMessagesProj/jni/voip/tgcalls/NetworkManager.cpp +++ b/TMessagesProj/jni/voip/tgcalls/NetworkManager.cpp @@ -104,6 +104,7 @@ NetworkManager::~NetworkManager() { _portAllocator.reset(); _networkManager.reset(); _socketFactory.reset(); + _networkMonitorFactory.reset(); } void NetworkManager::start() { diff --git a/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartInternal.cpp b/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartInternal.cpp index 27a71cbad..56390368a 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartInternal.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartInternal.cpp @@ -104,6 +104,9 @@ _avIoContext(std::move(fileData)) { _frame = av_frame_alloc(); +#if LIBAVFORMAT_VERSION_MAJOR >= 59 + const +#endif AVInputFormat *inputFormat = av_find_input_format(container.c_str()); if (!inputFormat) { _didReadToEnd = true; @@ -144,7 +147,7 @@ _avIoContext(std::move(fileData)) { _streamId = i; - _durationInMilliseconds = (int)((inStream->duration + inStream->first_dts) * 1000 / 48000); + _durationInMilliseconds = (int)(inStream->duration * av_q2d(inStream->time_base) * 1000); if (inStream->metadata) { AVDictionaryEntry *entry = av_dict_get(inStream->metadata, "TG_META", nullptr, 0); diff --git a/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartPersistentDecoder.cpp b/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartPersistentDecoder.cpp index e79d4304d..63ef4755f 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartPersistentDecoder.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartPersistentDecoder.cpp @@ -32,7 +32,7 @@ public: AudioStreamingPartPersistentDecoderState(AVCodecParameters const *codecParameters, AVRational timeBase) : _codecParameters(codecParameters), _timeBase(timeBase) { - AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id); + const AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id); if (codec) { _codecContext = avcodec_alloc_context3(codec); int ret = avcodec_parameters_to_context(_codecContext, codecParameters); diff --git a/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp b/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp index f124ded4c..eaf6c941a 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp @@ -1514,7 +1514,13 @@ public: std::unique_ptr audioProcessor = nullptr; #endif if (_videoContentType != VideoContentType::Screencast) { - PlatformInterface::SharedInstance()->configurePlatformAudio(); + int numChannels = 1; +#ifdef WEBRTC_IOS + if (_disableAudioInput) { + numChannels = 2; + } +#endif + PlatformInterface::SharedInstance()->configurePlatformAudio(numChannels); #if USE_RNNOISE audioProcessor = std::make_unique([weak, threads = _threads](GroupLevelValue const &level) { @@ -3297,7 +3303,7 @@ private: #endif const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { #ifdef WEBRTC_IOS - return rtc::make_ref_counted(false, disableRecording); + return rtc::make_ref_counted(false, disableRecording, disableRecording ? 2 : 1); #else return webrtc::AudioDeviceModule::Create( layer, diff --git a/TMessagesProj/jni/voip/tgcalls/group/StreamingMediaContext.cpp b/TMessagesProj/jni/voip/tgcalls/group/StreamingMediaContext.cpp index 905532f9a..9b566735c 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/StreamingMediaContext.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/StreamingMediaContext.cpp @@ -423,6 +423,27 @@ public: if (numChannels == 1) { frameOut.UpdateFrame(0, audioChannels[0].pcmData.data(), audioChannels[0].pcmData.size(), 48000, webrtc::AudioFrame::SpeechType::kNormalSpeech, webrtc::AudioFrame::VADActivity::kVadActive, numChannels); + } else if (numChannels == _audioRingBufferNumChannels) { + bool skipFrame = false; + int numSamples = (int)audioChannels[0].pcmData.size(); + for (int i = 1; i < numChannels; i++) { + if (audioChannels[i].pcmData.size() != numSamples) { + skipFrame = true; + break; + } + } + if (skipFrame) { + break; + } + if (_stereoShuffleBuffer.size() < numChannels * numSamples) { + _stereoShuffleBuffer.resize(numChannels * numSamples); + } + for (int i = 0; i < numSamples; i++) { + for (int j = 0; j < numChannels; j++) { + _stereoShuffleBuffer[i * numChannels + j] = audioChannels[j].pcmData[i]; + } + } + frameOut.UpdateFrame(0, _stereoShuffleBuffer.data(), numSamples, 48000, webrtc::AudioFrame::SpeechType::kNormalSpeech, webrtc::AudioFrame::VADActivity::kVadActive, numChannels); } else { bool skipFrame = false; int numSamples = (int)audioChannels[0].pcmData.size(); @@ -483,6 +504,9 @@ public: RTC_LOG(LS_INFO) << "render: discarding video frames at the end of a segment (displayed " << segment->video[0]->_displayedFrames << " frames)"; } } + if (!segment->unified.empty() && segment->unified[0]->videoPart->hasRemainingFrames()) { + RTC_LOG(LS_INFO) << "render: discarding video frames at the end of a segment (displayed " << segment->unified[0]->_displayedFrames << " frames)"; + } _availableSegments.erase(_availableSegments.begin()); } diff --git a/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.cpp b/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.cpp index 84ecad22a..4a3441d5c 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.cpp @@ -87,20 +87,16 @@ public: return _frame; } - double pts(AVStream *stream) { + double pts(AVStream *stream, double &firstFramePts) { int64_t framePts = _frame->pts; double spf = av_q2d(stream->time_base); - return ((double)framePts) * spf; - } - - double duration(AVStream *stream) { - int64_t frameDuration = _frame->pkt_duration; - double spf = av_q2d(stream->time_base); - if (frameDuration != 0) { - return ((double)frameDuration) * spf; - } else { - return spf; + double value = ((double)framePts) * spf; + + if (firstFramePts < 0.0) { + firstFramePts = value; } + + return value - firstFramePts; } private: @@ -280,6 +276,9 @@ public: int ret = 0; +#if LIBAVFORMAT_VERSION_MAJOR >= 59 + const +#endif AVInputFormat *inputFormat = av_find_input_format(container.c_str()); if (!inputFormat) { _didReadToEnd = true; @@ -323,7 +322,7 @@ public: } if (videoCodecParameters && videoStream) { - AVCodec *codec = avcodec_find_decoder(videoCodecParameters->codec_id); + const AVCodec *codec = avcodec_find_decoder(videoCodecParameters->codec_id); if (codec) { _codecContext = avcodec_alloc_context3(codec); ret = avcodec_parameters_to_context(_codecContext, videoCodecParameters); @@ -410,7 +409,7 @@ public: .set_rotation(_rotation) .build(); - return VideoStreamingPartFrame(_endpointId, videoFrame, _frame.pts(_videoStream), _frame.duration(_videoStream), _frameIndex); + return VideoStreamingPartFrame(_endpointId, videoFrame, _frame.pts(_videoStream, _firstFramePts), _frameIndex); } else { return absl::nullopt; } @@ -490,6 +489,7 @@ private: std::vector _finalFrames; int _frameIndex = 0; + double _firstFramePts = -1.0; bool _didReadToEnd = false; }; @@ -566,25 +566,33 @@ public: absl::optional getFrameAtRelativeTimestamp(double timestamp) { while (true) { - if (!_currentFrame) { + while (_availableFrames.size() >= 2) { + if (timestamp >= _availableFrames[1].pts) { + _availableFrames.erase(_availableFrames.begin()); + } else { + break; + } + } + + if (_availableFrames.size() < 2) { if (!_parsedVideoParts.empty()) { auto result = _parsedVideoParts[0]->getNextFrame(); if (result) { - _currentFrame = result; - _relativeTimestamp += result->duration; + _availableFrames.push_back(result.value()); } else { _parsedVideoParts.erase(_parsedVideoParts.begin()); - continue; } + continue; } } - if (_currentFrame) { - if (timestamp <= _relativeTimestamp) { - return _currentFrame; - } else { - _currentFrame = absl::nullopt; + if (!_availableFrames.empty()) { + for (size_t i = 1; i < _availableFrames.size(); i++) { + if (timestamp < _availableFrames[i].pts) { + return _availableFrames[i - 1]; + } } + return _availableFrames[_availableFrames.size() - 1]; } else { return absl::nullopt; } @@ -598,6 +606,10 @@ public: return absl::nullopt; } } + + bool hasRemainingFrames() const { + return !_parsedVideoParts.empty(); + } int getAudioRemainingMilliseconds() { while (!_parsedAudioParts.empty()) { @@ -626,8 +638,7 @@ public: private: absl::optional _videoStreamInfo; std::vector> _parsedVideoParts; - absl::optional _currentFrame; - double _relativeTimestamp = 0.0; + std::vector _availableFrames; std::vector> _parsedAudioParts; }; @@ -656,6 +667,12 @@ absl::optional VideoStreamingPart::getActiveEndpointId() const { : absl::nullopt; } +bool VideoStreamingPart::hasRemainingFrames() const { + return _state + ? _state->hasRemainingFrames() + : false; +} + int VideoStreamingPart::getAudioRemainingMilliseconds() { return _state ? _state->getAudioRemainingMilliseconds() diff --git a/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.h b/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.h index 87f7f15d1..16bc0ab4b 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.h +++ b/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.h @@ -19,14 +19,12 @@ struct VideoStreamingPartFrame { std::string endpointId; webrtc::VideoFrame frame; double pts = 0; - double duration = 0.0; int index = 0; - VideoStreamingPartFrame(std::string endpointId_, webrtc::VideoFrame const &frame_, double pts_, double duration_, int index_) : + VideoStreamingPartFrame(std::string endpointId_, webrtc::VideoFrame const &frame_, double pts_, int index_) : endpointId(endpointId_), frame(frame_), pts(pts_), - duration(duration_), index(index_) { } }; @@ -52,6 +50,7 @@ public: absl::optional getFrameAtRelativeTimestamp(double timestamp); absl::optional getActiveEndpointId() const; + bool hasRemainingFrames() const; int getAudioRemainingMilliseconds(); std::vector getAudio10msPerChannel(AudioStreamingPartPersistentDecoder &persistentDecoder); diff --git a/TMessagesProj/jni/voip/tgcalls/platform/PlatformInterface.h b/TMessagesProj/jni/voip/tgcalls/platform/PlatformInterface.h index b1a588413..234a91a4b 100644 --- a/TMessagesProj/jni/voip/tgcalls/platform/PlatformInterface.h +++ b/TMessagesProj/jni/voip/tgcalls/platform/PlatformInterface.h @@ -297,7 +297,7 @@ public: static PlatformInterface *SharedInstance(); virtual ~PlatformInterface() = default; - virtual void configurePlatformAudio() { + virtual void configurePlatformAudio(int numChannels = 1) { } virtual std::unique_ptr createNetworkMonitorFactory() { diff --git a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.cpp b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.cpp index 7a968bd90..85067628e 100644 --- a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.cpp +++ b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.cpp @@ -23,7 +23,7 @@ namespace tgcalls { -void AndroidInterface::configurePlatformAudio() { +void AndroidInterface::configurePlatformAudio(int numChannels) { } diff --git a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.h b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.h index d2b1820e1..f19374c01 100644 --- a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.h +++ b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.h @@ -9,7 +9,7 @@ namespace tgcalls { class AndroidInterface : public PlatformInterface { public: - void configurePlatformAudio() override; + void configurePlatformAudio(int numChannels = 1) override; std::unique_ptr makeVideoEncoderFactory(std::shared_ptr platformContext, bool preferHardwareEncoding = false, bool isScreencast = false) override; std::unique_ptr makeVideoDecoderFactory(std::shared_ptr platformContext) override; bool supportsEncoding(const std::string &codecName, std::shared_ptr platformContext) override; diff --git a/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.cpp b/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.cpp new file mode 100644 index 000000000..4ee37c249 --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.cpp @@ -0,0 +1,696 @@ +#include "v2/ContentNegotiation.h" + +#include "rtc_base/rtc_certificate_generator.h" + +#include + +namespace tgcalls { + +namespace { + +signaling::MediaContent convertContentInfoToSingalingContent(cricket::ContentInfo const &content) { + signaling::MediaContent mappedContent; + + switch (content.media_description()->type()) { + case cricket::MediaType::MEDIA_TYPE_AUDIO: { + mappedContent.type = signaling::MediaContent::Type::Audio; + + for (const auto &codec : content.media_description()->as_audio()->codecs()) { + signaling::PayloadType mappedPayloadType; + mappedPayloadType.id = codec.id; + mappedPayloadType.name = codec.name; + mappedPayloadType.clockrate = codec.clockrate; + mappedPayloadType.channels = (uint32_t)codec.channels; + + for (const auto &feedbackType : codec.feedback_params.params()) { + signaling::FeedbackType mappedFeedbackType; + mappedFeedbackType.type = feedbackType.id(); + mappedFeedbackType.subtype = feedbackType.param(); + mappedPayloadType.feedbackTypes.push_back(std::move(mappedFeedbackType)); + } + + for (const auto ¶meter : codec.params) { + mappedPayloadType.parameters.push_back(std::make_pair(parameter.first, parameter.second)); + } + std::sort(mappedPayloadType.parameters.begin(), mappedPayloadType.parameters.end(), [](std::pair const &lhs, std::pair const &rhs) -> bool { + return lhs.first < rhs.first; + }); + + mappedContent.payloadTypes.push_back(std::move(mappedPayloadType)); + } + break; + } + case cricket::MediaType::MEDIA_TYPE_VIDEO: { + mappedContent.type = signaling::MediaContent::Type::Video; + + for (const auto &codec : content.media_description()->as_video()->codecs()) { + signaling::PayloadType mappedPayloadType; + mappedPayloadType.id = codec.id; + mappedPayloadType.name = codec.name; + mappedPayloadType.clockrate = codec.clockrate; + mappedPayloadType.channels = 0; + + for (const auto &feedbackType : codec.feedback_params.params()) { + signaling::FeedbackType mappedFeedbackType; + mappedFeedbackType.type = feedbackType.id(); + mappedFeedbackType.subtype = feedbackType.param(); + mappedPayloadType.feedbackTypes.push_back(std::move(mappedFeedbackType)); + } + + for (const auto ¶meter : codec.params) { + mappedPayloadType.parameters.push_back(std::make_pair(parameter.first, parameter.second)); + } + std::sort(mappedPayloadType.parameters.begin(), mappedPayloadType.parameters.end(), [](std::pair const &lhs, std::pair const &rhs) -> bool { + return lhs.first < rhs.first; + }); + + mappedContent.payloadTypes.push_back(std::move(mappedPayloadType)); + } + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + + if (!content.media_description()->streams().empty()) { + mappedContent.ssrc = content.media_description()->streams()[0].first_ssrc(); + for (const auto &ssrcGroup : content.media_description()->streams()[0].ssrc_groups) { + signaling::SsrcGroup mappedSsrcGroup; + mappedSsrcGroup.semantics = ssrcGroup.semantics; + mappedSsrcGroup.ssrcs = ssrcGroup.ssrcs; + mappedContent.ssrcGroups.push_back(std::move(mappedSsrcGroup)); + } + } + + for (const auto &extension : content.media_description()->rtp_header_extensions()) { + mappedContent.rtpExtensions.push_back(extension); + } + + return mappedContent; +} + +cricket::ContentInfo convertSingalingContentToContentInfo(std::string const &contentId, signaling::MediaContent const &content, webrtc::RtpTransceiverDirection direction) { + std::unique_ptr contentDescription; + + switch (content.type) { + case signaling::MediaContent::Type::Audio: { + auto audioDescription = std::make_unique(); + + for (const auto &payloadType : content.payloadTypes) { + cricket::AudioCodec mappedCodec((int)payloadType.id, payloadType.name, (int)payloadType.clockrate, 0, payloadType.channels); + for (const auto ¶meter : payloadType.parameters) { + mappedCodec.params.insert(parameter); + } + for (const auto &feedbackParam : payloadType.feedbackTypes) { + mappedCodec.AddFeedbackParam(cricket::FeedbackParam(feedbackParam.type, feedbackParam.subtype)); + } + audioDescription->AddCodec(mappedCodec); + } + + contentDescription = std::move(audioDescription); + + break; + } + case signaling::MediaContent::Type::Video: { + auto videoDescription = std::make_unique(); + + for (const auto &payloadType : content.payloadTypes) { + cricket::VideoCodec mappedCodec((int)payloadType.id, payloadType.name); + for (const auto ¶meter : payloadType.parameters) { + mappedCodec.params.insert(parameter); + } + for (const auto &feedbackParam : payloadType.feedbackTypes) { + mappedCodec.AddFeedbackParam(cricket::FeedbackParam(feedbackParam.type, feedbackParam.subtype)); + } + videoDescription->AddCodec(mappedCodec); + } + + contentDescription = std::move(videoDescription); + + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + + cricket::StreamParams streamParams; + streamParams.id = contentId; + streamParams.set_stream_ids({ contentId }); + streamParams.add_ssrc(content.ssrc); + for (const auto &ssrcGroup : content.ssrcGroups) { + streamParams.ssrc_groups.push_back(cricket::SsrcGroup(ssrcGroup.semantics, ssrcGroup.ssrcs)); + for (const auto &ssrc : ssrcGroup.ssrcs) { + if (!streamParams.has_ssrc(ssrc)) { + streamParams.add_ssrc(ssrc); + } + } + } + contentDescription->AddStream(streamParams); + + for (const auto &extension : content.rtpExtensions) { + contentDescription->AddRtpHeaderExtension(extension); + } + + contentDescription->set_direction(direction); + contentDescription->set_rtcp_mux(true); + + cricket::ContentInfo mappedContentInfo(cricket::MediaProtocolType::kRtp); + mappedContentInfo.name = contentId; + mappedContentInfo.rejected = false; + mappedContentInfo.bundle_only = false; + mappedContentInfo.set_media_description(std::move(contentDescription)); + + return mappedContentInfo; +} + +cricket::ContentInfo createInactiveContentInfo(std::string const &contentId) { + std::unique_ptr contentDescription; + + auto audioDescription = std::make_unique(); + contentDescription = std::move(audioDescription); + + contentDescription->set_direction(webrtc::RtpTransceiverDirection::kInactive); + contentDescription->set_rtcp_mux(true); + + cricket::ContentInfo mappedContentInfo(cricket::MediaProtocolType::kRtp); + mappedContentInfo.name = contentId; + mappedContentInfo.rejected = false; + mappedContentInfo.bundle_only = false; + mappedContentInfo.set_media_description(std::move(contentDescription)); + + return mappedContentInfo; +} + +std::string contentIdBySsrc(uint32_t ssrc) { + std::ostringstream contentIdString; + + contentIdString << ssrc; + + return contentIdString.str(); +} + +} + +ContentNegotiationContext::ContentNegotiationContext(bool isOutgoing, rtc::UniqueRandomIdGenerator *uniqueRandomIdGenerator) : +_isOutgoing(isOutgoing), +_uniqueRandomIdGenerator(uniqueRandomIdGenerator) { + _transportDescriptionFactory = std::make_unique(); + + // tempCertificate is only used to fill in the local SDP + auto tempCertificate = rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams(rtc::KT_ECDSA), absl::nullopt); + _transportDescriptionFactory->set_secure(cricket::SecurePolicy::SEC_REQUIRED); + _transportDescriptionFactory->set_certificate(tempCertificate); + + _sessionDescriptionFactory = std::make_unique(_transportDescriptionFactory.get(), uniqueRandomIdGenerator); + + _needNegotiation = true; +} + +ContentNegotiationContext::~ContentNegotiationContext() { + +} + +void ContentNegotiationContext::copyCodecsFromChannelManager(cricket::ChannelManager *channelManager, bool randomize) { + cricket::AudioCodecs audioSendCodecs; + cricket::AudioCodecs audioRecvCodecs; + cricket::VideoCodecs videoSendCodecs; + cricket::VideoCodecs videoRecvCodecs; + + channelManager->GetSupportedAudioSendCodecs(&audioSendCodecs); + channelManager->GetSupportedAudioReceiveCodecs(&audioRecvCodecs); + channelManager->GetSupportedVideoSendCodecs(&videoSendCodecs); + channelManager->GetSupportedVideoReceiveCodecs(&videoRecvCodecs); + + for (const auto &codec : audioSendCodecs) { + if (codec.name == "opus") { + audioSendCodecs = { codec }; + audioRecvCodecs = { codec }; + break; + } + } + + if (randomize) { + for (auto &codec : audioSendCodecs) { + codec.id += 3; + } + for (auto &codec : videoSendCodecs) { + codec.id += 3; + } + for (auto &codec : audioRecvCodecs) { + codec.id += 3; + } + for (auto &codec : videoRecvCodecs) { + codec.id += 3; + } + } + + _sessionDescriptionFactory->set_audio_codecs(audioSendCodecs, audioRecvCodecs); + _sessionDescriptionFactory->set_video_codecs(videoSendCodecs, videoRecvCodecs); + + int absSendTimeUriId = 2; + int transportSequenceNumberUriId = 3; + int videoRotationUri = 13; + + if (randomize) { + absSendTimeUriId = 3; + transportSequenceNumberUriId = 2; + videoRotationUri = 4; + } + + _rtpAudioExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, absSendTimeUriId); + _rtpAudioExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, transportSequenceNumberUriId); + + _rtpVideoExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, absSendTimeUriId); + _rtpVideoExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, transportSequenceNumberUriId); + _rtpVideoExtensions.emplace_back(webrtc::RtpExtension::kVideoRotationUri, videoRotationUri); +} + +std::string ContentNegotiationContext::addOutgoingChannel(signaling::MediaContent::Type mediaType) { + std::string channelId = takeNextOutgoingChannelId(); + + cricket::MediaType mappedMediaType; + std::vector rtpExtensions; + switch (mediaType) { + case signaling::MediaContent::Type::Audio: { + mappedMediaType = cricket::MediaType::MEDIA_TYPE_AUDIO; + rtpExtensions = _rtpAudioExtensions; + break; + } + case signaling::MediaContent::Type::Video: { + mappedMediaType = cricket::MediaType::MEDIA_TYPE_VIDEO; + rtpExtensions = _rtpVideoExtensions; + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + cricket::MediaDescriptionOptions offerDescription(mappedMediaType, channelId, webrtc::RtpTransceiverDirection::kSendOnly, false); + offerDescription.header_extensions = rtpExtensions; + + switch (mediaType) { + case signaling::MediaContent::Type::Audio: { + offerDescription.AddAudioSender(channelId, { channelId }); + break; + } + case signaling::MediaContent::Type::Video: { + cricket::SimulcastLayerList simulcastLayers; + offerDescription.AddVideoSender(channelId, { channelId }, {}, simulcastLayers, 1); + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + + _outgoingChannelDescriptions.emplace_back(std::move(offerDescription)); + _needNegotiation = true; + + return channelId; +} + +void ContentNegotiationContext::removeOutgoingChannel(std::string const &id) { + for (size_t i = 0; i < _outgoingChannels.size(); i++) { + if (_outgoingChannelDescriptions[i].description.mid == id) { + _outgoingChannelDescriptions.erase(_outgoingChannelDescriptions.begin() + i); + + _needNegotiation = true; + + break; + } + } +} + +std::unique_ptr ContentNegotiationContext::currentSessionDescriptionFromCoordinatedState() { + if (_channelIdOrder.empty()) { + return nullptr; + } + + auto sessionDescription = std::make_unique(); + + for (const auto &id : _channelIdOrder) { + bool found = false; + + for (const auto &channel : _incomingChannels) { + if (contentIdBySsrc(channel.ssrc) == id) { + found = true; + + auto mappedContent = convertSingalingContentToContentInfo(contentIdBySsrc(channel.ssrc), channel, webrtc::RtpTransceiverDirection::kRecvOnly); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(contentIdBySsrc(channel.ssrc), transportDescription); + sessionDescription->AddTransportInfo(transportInfo); + + sessionDescription->AddContent(std::move(mappedContent)); + + break; + } + } + + for (const auto &channel : _outgoingChannels) { + if (channel.id == id) { + found = true; + + auto mappedContent = convertSingalingContentToContentInfo(channel.id, channel.content, webrtc::RtpTransceiverDirection::kSendOnly); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.name, transportDescription); + sessionDescription->AddTransportInfo(transportInfo); + + sessionDescription->AddContent(std::move(mappedContent)); + + break; + } + } + + if (!found) { + auto mappedContent = createInactiveContentInfo("_" + id); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.name, transportDescription); + sessionDescription->AddTransportInfo(transportInfo); + + sessionDescription->AddContent(std::move(mappedContent)); + } + } + + return sessionDescription; +} + +static cricket::MediaDescriptionOptions getIncomingContentDescription(signaling::MediaContent const &content) { + auto mappedContent = convertSingalingContentToContentInfo(contentIdBySsrc(content.ssrc), content, webrtc::RtpTransceiverDirection::kSendOnly); + + cricket::MediaDescriptionOptions contentDescription(mappedContent.media_description()->type(), mappedContent.name, webrtc::RtpTransceiverDirection::kRecvOnly, false); + for (const auto &extension : mappedContent.media_description()->rtp_header_extensions()) { + contentDescription.header_extensions.emplace_back(extension.uri, extension.id); + } + + return contentDescription; +} + +std::unique_ptr ContentNegotiationContext::getPendingOffer() { + if (!_needNegotiation) { + return nullptr; + } + if (_pendingOutgoingOffer) { + return nullptr; + } + + _pendingOutgoingOffer = std::make_unique(); + _pendingOutgoingOffer->exchangeId = _uniqueRandomIdGenerator->GenerateId(); + + auto currentSessionDescription = currentSessionDescriptionFromCoordinatedState(); + + cricket::MediaSessionOptions offerOptions; + offerOptions.offer_extmap_allow_mixed = true; + offerOptions.bundle_enabled = true; + + for (const auto &id : _channelIdOrder) { + bool found = false; + + for (const auto &channel : _outgoingChannelDescriptions) { + if (channel.description.mid == id) { + found = true; + offerOptions.media_description_options.push_back(channel.description); + + break; + } + } + + for (const auto &content : _incomingChannels) { + if (contentIdBySsrc(content.ssrc) == id) { + found = true; + offerOptions.media_description_options.push_back(getIncomingContentDescription(content)); + + break; + } + } + + if (!found) { + cricket::MediaDescriptionOptions contentDescription(cricket::MediaType::MEDIA_TYPE_AUDIO, "_" + id, webrtc::RtpTransceiverDirection::kInactive, false); + offerOptions.media_description_options.push_back(contentDescription); + } + } + + for (const auto &channel : _outgoingChannelDescriptions) { + if (std::find(_channelIdOrder.begin(), _channelIdOrder.end(), channel.description.mid) == _channelIdOrder.end()) { + _channelIdOrder.push_back(channel.description.mid); + + offerOptions.media_description_options.push_back(channel.description); + } + + for (const auto &content : _incomingChannels) { + if (std::find(_channelIdOrder.begin(), _channelIdOrder.end(), contentIdBySsrc(content.ssrc)) == _channelIdOrder.end()) { + _channelIdOrder.push_back(contentIdBySsrc(content.ssrc)); + + offerOptions.media_description_options.push_back(getIncomingContentDescription(content)); + } + } + } + + std::unique_ptr offer = _sessionDescriptionFactory->CreateOffer(offerOptions, currentSessionDescription.get()); + + auto mappedOffer = std::make_unique(); + + mappedOffer->exchangeId = _pendingOutgoingOffer->exchangeId; + + for (const auto &content : offer->contents()) { + auto mappedContent = convertContentInfoToSingalingContent(content); + + if (content.media_description()->direction() == webrtc::RtpTransceiverDirection::kSendOnly) { + mappedOffer->contents.push_back(std::move(mappedContent)); + + for (auto &channel : _outgoingChannelDescriptions) { + if (channel.description.mid == content.mid()) { + channel.ssrc = mappedContent.ssrc; + channel.ssrcGroups = mappedContent.ssrcGroups; + } + } + } + } + + return mappedOffer; +} + +std::unique_ptr ContentNegotiationContext::setRemoteNegotiationContent(std::unique_ptr &&remoteNegotiationContent) { + if (!remoteNegotiationContent) { + return nullptr; + } + + if (_pendingOutgoingOffer) { + if (remoteNegotiationContent->exchangeId == _pendingOutgoingOffer->exchangeId) { + setAnswer(std::move(remoteNegotiationContent)); + return nullptr; + } else { + // race condition detected — call initiator wins + if (!_isOutgoing) { + _pendingOutgoingOffer.reset(); + return getAnswer(std::move(remoteNegotiationContent)); + } else { + return nullptr; + } + } + } else { + return getAnswer(std::move(remoteNegotiationContent)); + } +} + +std::unique_ptr ContentNegotiationContext::getAnswer(std::unique_ptr &&offer) { + auto currentSessionDescription = currentSessionDescriptionFromCoordinatedState(); + + auto mappedOffer = std::make_unique(); + + cricket::MediaSessionOptions answerOptions; + answerOptions.offer_extmap_allow_mixed = true; + answerOptions.bundle_enabled = true; + + for (const auto &id : _channelIdOrder) { + bool found = false; + + for (const auto &channel : _outgoingChannels) { + if (channel.id == id) { + found = true; + + auto mappedContent = convertSingalingContentToContentInfo(channel.id, channel.content, webrtc::RtpTransceiverDirection::kRecvOnly); + + cricket::MediaDescriptionOptions contentDescription(mappedContent.media_description()->type(), mappedContent.name, webrtc::RtpTransceiverDirection::kSendOnly, false); + for (const auto &extension : mappedContent.media_description()->rtp_header_extensions()) { + contentDescription.header_extensions.emplace_back(extension.uri, extension.id); + } + answerOptions.media_description_options.push_back(contentDescription); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(channel.id, transportDescription); + mappedOffer->AddTransportInfo(transportInfo); + + mappedOffer->AddContent(std::move(mappedContent)); + + break; + } + } + + for (const auto &content : offer->contents) { + if (contentIdBySsrc(content.ssrc) == id) { + found = true; + + auto mappedContent = convertSingalingContentToContentInfo(contentIdBySsrc(content.ssrc), content, webrtc::RtpTransceiverDirection::kSendOnly); + + cricket::MediaDescriptionOptions contentDescription(mappedContent.media_description()->type(), mappedContent.name, webrtc::RtpTransceiverDirection::kRecvOnly, false); + for (const auto &extension : mappedContent.media_description()->rtp_header_extensions()) { + contentDescription.header_extensions.emplace_back(extension.uri, extension.id); + } + answerOptions.media_description_options.push_back(contentDescription); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.mid(), transportDescription); + mappedOffer->AddTransportInfo(transportInfo); + + mappedOffer->AddContent(std::move(mappedContent)); + + break; + } + } + + if (!found) { + auto mappedContent = createInactiveContentInfo("_" + id); + + cricket::MediaDescriptionOptions contentDescription(cricket::MediaType::MEDIA_TYPE_AUDIO, "_" + id, webrtc::RtpTransceiverDirection::kInactive, false); + answerOptions.media_description_options.push_back(contentDescription); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.mid(), transportDescription); + mappedOffer->AddTransportInfo(transportInfo); + + mappedOffer->AddContent(std::move(mappedContent)); + } + } + + for (const auto &content : offer->contents) { + if (std::find(_channelIdOrder.begin(), _channelIdOrder.end(), contentIdBySsrc(content.ssrc)) == _channelIdOrder.end()) { + _channelIdOrder.push_back(contentIdBySsrc(content.ssrc)); + + answerOptions.media_description_options.push_back(getIncomingContentDescription(content)); + + auto mappedContent = convertSingalingContentToContentInfo(contentIdBySsrc(content.ssrc), content, webrtc::RtpTransceiverDirection::kSendOnly); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.mid(), transportDescription); + mappedOffer->AddTransportInfo(transportInfo); + + mappedOffer->AddContent(std::move(mappedContent)); + } + } + + std::unique_ptr answer = _sessionDescriptionFactory->CreateAnswer(mappedOffer.get(), answerOptions, currentSessionDescription.get()); + + auto mappedAnswer = std::make_unique(); + + mappedAnswer->exchangeId = offer->exchangeId; + + std::vector incomingChannels; + + for (const auto &content : answer->contents()) { + auto mappedContent = convertContentInfoToSingalingContent(content); + + if (content.media_description()->direction() == webrtc::RtpTransceiverDirection::kRecvOnly) { + for (const auto &offerContent : offer->contents) { + if (contentIdBySsrc(offerContent.ssrc) == content.mid()) { + mappedContent.ssrc = offerContent.ssrc; + mappedContent.ssrcGroups = offerContent.ssrcGroups; + + break; + } + } + + incomingChannels.push_back(mappedContent); + mappedAnswer->contents.push_back(std::move(mappedContent)); + } + } + + _incomingChannels = incomingChannels; + + return mappedAnswer; +} + +void ContentNegotiationContext::setAnswer(std::unique_ptr &&answer) { + if (!_pendingOutgoingOffer) { + return; + } + if (_pendingOutgoingOffer->exchangeId != answer->exchangeId) { + return; + } + + _pendingOutgoingOffer.reset(); + _needNegotiation = false; + + _outgoingChannels.clear(); + + for (const auto &content : answer->contents) { + for (const auto &pendingChannel : _outgoingChannelDescriptions) { + if (pendingChannel.ssrc != 0 && content.ssrc == pendingChannel.ssrc) { + _outgoingChannels.emplace_back(pendingChannel.description.mid, content); + + break; + } + } + } +} + +std::string ContentNegotiationContext::takeNextOutgoingChannelId() { + std::ostringstream result; + result << "m" << _nextOutgoingChannelId; + _nextOutgoingChannelId++; + + return result.str(); +} + +std::unique_ptr ContentNegotiationContext::coordinatedState() const { + auto result = std::make_unique(); + + result->incomingContents = _incomingChannels; + for (const auto &channel : _outgoingChannels) { + bool found = false; + + for (const auto &channelDescription : _outgoingChannelDescriptions) { + if (channelDescription.description.mid == channel.id) { + found = true; + break; + } + } + + if (found) { + result->outgoingContents.push_back(channel.content); + } + } + + return result; +} + +absl::optional ContentNegotiationContext::outgoingChannelSsrc(std::string const &id) const { + for (const auto &channel : _outgoingChannels) { + bool found = false; + + for (const auto &channelDescription : _outgoingChannelDescriptions) { + if (channelDescription.description.mid == channel.id) { + found = true; + break; + } + } + + if (found && channel.id == id) { + if (channel.content.ssrc != 0) { + return channel.content.ssrc; + } + } + } + + return absl::nullopt; +} + +} // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.h b/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.h new file mode 100644 index 000000000..53e16d73e --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.h @@ -0,0 +1,99 @@ +#ifndef TGCALLS_CONTENT_NEGOTIATION_H +#define TGCALLS_CONTENT_NEGOTIATION_H + +#include + +#include "pc/channel_manager.h" +#include "pc/media_session.h" +#include "pc/session_description.h" +#include "p2p/base/transport_description_factory.h" + +#include "v2/Signaling.h" + +namespace tgcalls { + +class ContentNegotiationContext { +public: + struct NegotiationContents { + uint32_t exchangeId = 0; + std::vector contents; + }; + + struct PendingOutgoingOffer { + uint32_t exchangeId = 0; + }; + + struct PendingOutgoingChannel { + cricket::MediaDescriptionOptions description; + + uint32_t ssrc = 0; + std::vector ssrcGroups; + + PendingOutgoingChannel(cricket::MediaDescriptionOptions &&description_) : + description(std::move(description_)) { + } + }; + + struct OutgoingChannel { + std::string id; + signaling::MediaContent content; + + OutgoingChannel(std::string id_, signaling::MediaContent content_) : + id(id_), content(content_) { + } + }; + + struct CoordinatedState { + std::vector outgoingContents; + std::vector incomingContents; + }; + +public: + ContentNegotiationContext(bool isOutgoing, rtc::UniqueRandomIdGenerator *uniqueRandomIdGenerator); + ~ContentNegotiationContext(); + + void copyCodecsFromChannelManager(cricket::ChannelManager *channelManager, bool randomize); + + std::string addOutgoingChannel(signaling::MediaContent::Type mediaType); + void removeOutgoingChannel(std::string const &id); + + std::unique_ptr getPendingOffer(); + std::unique_ptr setRemoteNegotiationContent(std::unique_ptr &&remoteNegotiationContent); + + std::unique_ptr coordinatedState() const; + absl::optional outgoingChannelSsrc(std::string const &id) const; + +private: + std::string takeNextOutgoingChannelId(); + std::unique_ptr currentSessionDescriptionFromCoordinatedState(); + + std::unique_ptr getAnswer(std::unique_ptr &&offer); + void setAnswer(std::unique_ptr &&answer); + +private: + bool _isOutgoing = false; + rtc::UniqueRandomIdGenerator *_uniqueRandomIdGenerator = nullptr; + + std::unique_ptr _transportDescriptionFactory; + std::unique_ptr _sessionDescriptionFactory; + + std::vector _channelIdOrder; + + std::vector _rtpAudioExtensions; + std::vector _rtpVideoExtensions; + + std::vector _outgoingChannelDescriptions; + bool _needNegotiation = false; + + std::vector _outgoingChannels; + std::vector _incomingChannels; + + std::unique_ptr _pendingOutgoingOffer; + + int _nextOutgoingChannelId = 0; + +}; + +} // namespace tgcalls + +#endif diff --git a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp index c2962ec65..a8c920815 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp +++ b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp @@ -5,6 +5,7 @@ #include "VideoCapturerInterface.h" #include "v2/NativeNetworkingImpl.h" #include "v2/Signaling.h" +#include "v2/ContentNegotiation.h" #include "CodecSelectHelper.h" #include "platform/PlatformInterface.h" @@ -32,6 +33,8 @@ #include "api/jsep_ice_candidate.h" #include "pc/used_ids.h" #include "media/base/sdp_video_format_utils.h" +#include "pc/media_session.h" +#include "rtc_base/rtc_certificate_generator.h" #include "AudioFrame.h" #include "ThreadLocalObject.h" @@ -49,479 +52,18 @@ #include #include +#include "third-party/json11.hpp" + namespace tgcalls { namespace { -static std::string intToString(int value) { - std::ostringstream stringStream; - stringStream << value; - return stringStream.str(); -} - static VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(VideoCaptureInterface *videoCapture) { return videoCapture ? static_cast(videoCapture)->object()->getSyncAssumingSameThread() : nullptr; } -struct OutgoingVideoFormat { - cricket::VideoCodec videoCodec; - absl::optional rtxCodec; -}; - -static void addDefaultFeedbackParams(cricket::VideoCodec *codec) { - // Don't add any feedback params for RED and ULPFEC. - if (codec->name == cricket::kRedCodecName || codec->name == cricket::kUlpfecCodecName) { - return; - } - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)); - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamTransportCc, cricket::kParamValueEmpty)); - // Don't add any more feedback params for FLEXFEC. - if (codec->name == cricket::kFlexfecCodecName) { - return; - } - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)); - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)); - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)); -} - -template -static bool IsRtxCodec(const C& codec) { - return absl::EqualsIgnoreCase(codec.name, cricket::kRtxCodecName); -} - -template -static bool ReferencedCodecsMatch(const std::vector& codecs1, - const int codec1_id, - const std::vector& codecs2, - const int codec2_id) { - const C* codec1 = FindCodecById(codecs1, codec1_id); - const C* codec2 = FindCodecById(codecs2, codec2_id); - return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2); -} - -// Finds a codec in |codecs2| that matches |codec_to_match|, which is -// a member of |codecs1|. If |codec_to_match| is an RTX codec, both -// the codecs themselves and their associated codecs must match. -template -static bool FindMatchingCodec(const std::vector& codecs1, - const std::vector& codecs2, - const C& codec_to_match, - C* found_codec) { - // |codec_to_match| should be a member of |codecs1|, in order to look up RTX - // codecs' associated codecs correctly. If not, that's a programming error. - RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) { - return &codec == &codec_to_match; - })); - for (const C& potential_match : codecs2) { - if (potential_match.Matches(codec_to_match)) { - if (IsRtxCodec(codec_to_match)) { - int apt_value_1 = 0; - int apt_value_2 = 0; - if (!codec_to_match.GetParam(cricket::kCodecParamAssociatedPayloadType, - &apt_value_1) || - !potential_match.GetParam(cricket::kCodecParamAssociatedPayloadType, - &apt_value_2)) { - RTC_LOG(LS_WARNING) << "RTX missing associated payload type."; - continue; - } - if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2, - apt_value_2)) { - continue; - } - } - if (found_codec) { - *found_codec = potential_match; - } - return true; - } - } - return false; -} - -template -static void NegotiatePacketization(const C& local_codec, - const C& remote_codec, - C* negotiated_codec) {} - -template <> -void NegotiatePacketization(const cricket::VideoCodec& local_codec, - const cricket::VideoCodec& remote_codec, - cricket::VideoCodec* negotiated_codec) { - negotiated_codec->packetization = - cricket::VideoCodec::IntersectPacketization(local_codec, remote_codec); -} - -template -static void NegotiateCodecs(const std::vector& local_codecs, - const std::vector& offered_codecs, - std::vector* negotiated_codecs, - bool keep_offer_order) { - for (const C& ours : local_codecs) { - C theirs; - // Note that we intentionally only find one matching codec for each of our - // local codecs, in case the remote offer contains duplicate codecs. - if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) { - C negotiated = ours; - NegotiatePacketization(ours, theirs, &negotiated); - negotiated.IntersectFeedbackParams(theirs); - if (IsRtxCodec(negotiated)) { - const auto apt_it = - theirs.params.find(cricket::kCodecParamAssociatedPayloadType); - // FindMatchingCodec shouldn't return something with no apt value. - RTC_DCHECK(apt_it != theirs.params.end()); - negotiated.SetParam(cricket::kCodecParamAssociatedPayloadType, apt_it->second); - } - if (absl::EqualsIgnoreCase(ours.name, cricket::kH264CodecName)) { - webrtc::H264GenerateProfileLevelIdForAnswer( - ours.params, theirs.params, &negotiated.params); - } - negotiated.id = theirs.id; - negotiated.name = theirs.name; - negotiated_codecs->push_back(std::move(negotiated)); - } - } - if (keep_offer_order) { - // RFC3264: Although the answerer MAY list the formats in their desired - // order of preference, it is RECOMMENDED that unless there is a - // specific reason, the answerer list formats in the same relative order - // they were present in the offer. - // This can be skipped when the transceiver has any codec preferences. - std::unordered_map payload_type_preferences; - int preference = static_cast(offered_codecs.size() + 1); - for (const C& codec : offered_codecs) { - payload_type_preferences[codec.id] = preference--; - } - absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a, - const C& b) { - return payload_type_preferences[a.id] > payload_type_preferences[b.id]; - }); - } -} - -// Find the codec in |codec_list| that |rtx_codec| is associated with. -template -static const C* GetAssociatedCodec(const std::vector& codec_list, - const C& rtx_codec) { - std::string associated_pt_str; - if (!rtx_codec.GetParam(cricket::kCodecParamAssociatedPayloadType, - &associated_pt_str)) { - RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name - << " is missing an associated payload type."; - return nullptr; - } - - int associated_pt; - if (!rtc::FromString(associated_pt_str, &associated_pt)) { - RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str - << " of RTX codec " << rtx_codec.name - << " to an integer."; - return nullptr; - } - - // Find the associated reference codec for the reference RTX codec. - const C* associated_codec = FindCodecById(codec_list, associated_pt); - if (!associated_codec) { - RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type " - << associated_pt << " for RTX codec " << rtx_codec.name - << "."; - } - return associated_codec; -} - -// Adds all codecs from |reference_codecs| to |offered_codecs| that don't -// already exist in |offered_codecs| and ensure the payload types don't -// collide. -template -static void MergeCodecs(const std::vector& reference_codecs, - std::vector* offered_codecs, - cricket::UsedPayloadTypes* used_pltypes) { - // Add all new codecs that are not RTX codecs. - for (const C& reference_codec : reference_codecs) { - if (!IsRtxCodec(reference_codec) && - !FindMatchingCodec(reference_codecs, *offered_codecs, - reference_codec, nullptr)) { - C codec = reference_codec; - used_pltypes->FindAndSetIdUsed(&codec); - offered_codecs->push_back(codec); - } - } - - // Add all new RTX codecs. - for (const C& reference_codec : reference_codecs) { - if (IsRtxCodec(reference_codec) && - !FindMatchingCodec(reference_codecs, *offered_codecs, - reference_codec, nullptr)) { - C rtx_codec = reference_codec; - const C* associated_codec = - GetAssociatedCodec(reference_codecs, rtx_codec); - if (!associated_codec) { - continue; - } - // Find a codec in the offered list that matches the reference codec. - // Its payload type may be different than the reference codec. - C matching_codec; - if (!FindMatchingCodec(reference_codecs, *offered_codecs, - *associated_codec, &matching_codec)) { - RTC_LOG(LS_WARNING) - << "Couldn't find matching " << associated_codec->name << " codec."; - continue; - } - - rtx_codec.params[cricket::kCodecParamAssociatedPayloadType] = - rtc::ToString(matching_codec.id); - used_pltypes->FindAndSetIdUsed(&rtx_codec); - offered_codecs->push_back(rtx_codec); - } - } -} - -static std::vector generateAvailableVideoFormats(std::vector const &formats) { - if (formats.empty()) { - return {}; - } - - constexpr int kFirstDynamicPayloadType = 100; - constexpr int kLastDynamicPayloadType = 127; - - int payload_type = kFirstDynamicPayloadType; - - std::vector result; - - //bool codecSelected = false; - - for (const auto &format : formats) { - /*if (codecSelected) { - break; - }*/ - - bool alreadyAdded = false; - for (const auto &it : result) { - if (it.videoCodec.name == format.name) { - alreadyAdded = true; - break; - } - } - if (alreadyAdded) { - continue; - } - - OutgoingVideoFormat resultFormat; - - cricket::VideoCodec codec(format); - codec.id = payload_type; - addDefaultFeedbackParams(&codec); - - resultFormat.videoCodec = codec; - //codecSelected = true; - - // Increment payload type. - ++payload_type; - if (payload_type > kLastDynamicPayloadType) { - RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; - break; - } - - // Add associated RTX codec for non-FEC codecs. - if (!absl::EqualsIgnoreCase(codec.name, cricket::kUlpfecCodecName) && - !absl::EqualsIgnoreCase(codec.name, cricket::kFlexfecCodecName)) { - resultFormat.rtxCodec = cricket::VideoCodec::CreateRtxCodec(payload_type, codec.id); - - // Increment payload type. - ++payload_type; - if (payload_type > kLastDynamicPayloadType) { - RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; - break; - } - } - - result.push_back(std::move(resultFormat)); - } - return result; -} - -static void getCodecsFromMediaContent(signaling::MediaContent const &content, std::vector &codecs) { - for (const auto &payloadType : content.payloadTypes) { - cricket::VideoCodec codec(payloadType.id, payloadType.name); - for (const auto &feedbackType : payloadType.feedbackTypes) { - codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); - } - for (const auto ¶meter : payloadType.parameters) { - codec.SetParam(parameter.first, parameter.second); - } - codecs.push_back(std::move(codec)); - } -} - -static std::vector getPayloadTypesFromVideoCodecs(std::vector const &codecs) { - std::vector payloadTypes; - - for (const auto &codec : codecs) { - signaling::PayloadType payloadType; - - payloadType.id = codec.id; - payloadType.name = codec.name; - payloadType.clockrate = 90000; - payloadType.channels = 0; - - for (const auto &feedbackParam : codec.feedback_params.params()) { - signaling::FeedbackType feedbackType; - feedbackType.type = feedbackParam.id(); - feedbackType.subtype = feedbackParam.param(); - payloadType.feedbackTypes.push_back(std::move(feedbackType)); - } - - for (const auto ¶m : codec.params) { - payloadType.parameters.push_back(std::make_pair(param.first, param.second)); - } - - payloadTypes.push_back(std::move(payloadType)); - } - - return payloadTypes; -} - -static void getCodecsFromMediaContent(signaling::MediaContent const &content, std::vector &codecs) { - for (const auto &payloadType : content.payloadTypes) { - cricket::AudioCodec codec(payloadType.id, payloadType.name, payloadType.clockrate, 0, payloadType.channels); - for (const auto &feedbackType : payloadType.feedbackTypes) { - codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); - } - for (const auto ¶meter : payloadType.parameters) { - codec.SetParam(parameter.first, parameter.second); - } - codecs.push_back(std::move(codec)); - } -} - -static std::vector getPayloadTypesFromAudioCodecs(std::vector const &codecs) { - std::vector payloadTypes; - - for (const auto &codec : codecs) { - signaling::PayloadType payloadType; - - payloadType.id = codec.id; - payloadType.name = codec.name; - payloadType.clockrate = codec.clockrate; - payloadType.channels = (uint32_t)codec.channels; - - for (const auto &feedbackParam : codec.feedback_params.params()) { - signaling::FeedbackType feedbackType; - feedbackType.type = feedbackParam.id(); - feedbackType.subtype = feedbackParam.param(); - payloadType.feedbackTypes.push_back(std::move(feedbackType)); - } - - for (const auto ¶m : codec.params) { - payloadType.parameters.push_back(std::make_pair(param.first, param.second)); - } - - payloadTypes.push_back(std::move(payloadType)); - } - - return payloadTypes; -} - -template -struct NegotiatedMediaContent { - uint32_t ssrc = 0; - std::vector ssrcGroups; - std::vector rtpExtensions; - std::vector codecs; -}; - -static bool FindByUri(const cricket::RtpHeaderExtensions& extensions, - const webrtc::RtpExtension& ext_to_match, - webrtc::RtpExtension* found_extension) { - // We assume that all URIs are given in a canonical format. - const webrtc::RtpExtension* found = - webrtc::RtpExtension::FindHeaderExtensionByUri( - extensions, - ext_to_match.uri, - webrtc::RtpExtension::Filter::kPreferEncryptedExtension - ); - if (!found) { - return false; - } - if (found_extension) { - *found_extension = *found; - } - return true; -} - -template -static NegotiatedMediaContent negotiateMediaContent(signaling::MediaContent const &baseMediaContent, signaling::MediaContent const &localContent, signaling::MediaContent const &remoteContent, bool isAnswer) { - std::vector localCodecs; - getCodecsFromMediaContent(localContent, localCodecs); - - std::vector remoteCodecs; - getCodecsFromMediaContent(remoteContent, remoteCodecs); - - std::vector negotiatedCodecs; - - cricket::UsedPayloadTypes usedPayloadTypes; - NegotiateCodecs(localCodecs, remoteCodecs, &negotiatedCodecs, true); - - NegotiatedMediaContent result; - - result.ssrc = baseMediaContent.ssrc; - result.ssrcGroups = baseMediaContent.ssrcGroups; - result.codecs = std::move(negotiatedCodecs); - - cricket::UsedRtpHeaderExtensionIds extensionIds(cricket::UsedRtpHeaderExtensionIds::IdDomain::kOneByteOnly); - - for (const auto &extension : remoteContent.rtpExtensions) { - if (isAnswer) { - webrtc::RtpExtension found; - if (!FindByUri(localContent.rtpExtensions, extension, &found)) { - continue; - } - } - - webrtc::RtpExtension mutableExtension = extension; - extensionIds.FindAndSetIdUsed(&mutableExtension); - result.rtpExtensions.push_back(std::move(mutableExtension)); - } - - if (!isAnswer) { - for (const auto &extension : localContent.rtpExtensions) { - webrtc::RtpExtension found; - if (!FindByUri(result.rtpExtensions, extension, &found)) { - webrtc::RtpExtension mutableExtension = extension; - extensionIds.FindAndSetIdUsed(&mutableExtension); - result.rtpExtensions.push_back(std::move(mutableExtension)); - } - } - } - - return result; -} - class OutgoingAudioChannel : public sigslot::has_slots<> { -public: - static absl::optional createOutgoingContentDescription() { - signaling::MediaContent mediaContent; - - auto generator = std::mt19937(std::random_device()()); - auto distribution = std::uniform_int_distribution(); - do { - mediaContent.ssrc = distribution(generator) & 0x7fffffffU; - } while (!mediaContent.ssrc); - - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAudioLevelUri, 1); - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, 2); - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, 3); - - cricket::AudioCodec opusCodec(109, "opus", 48000, 0, 2); - opusCodec.AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamTransportCc)); - opusCodec.SetParam(cricket::kCodecParamUseInbandFec, 1); - opusCodec.SetParam(cricket::kCodecParamMinPTime, 60); - - mediaContent.payloadTypes = getPayloadTypesFromAudioCodecs({ opusCodec }); - - return mediaContent; - } - public: OutgoingAudioChannel( webrtc::Call *call, @@ -529,7 +71,7 @@ public: rtc::UniqueRandomIdGenerator *uniqueRandomIdGenerator, webrtc::LocalAudioSinkAdapter *audioSource, webrtc::RtpTransport *rtpTransport, - NegotiatedMediaContent const &mediaContent, + signaling::MediaContent const &mediaContent, std::shared_ptr threads ) : _threads(threads), @@ -553,29 +95,30 @@ public: audioOptions.echo_cancellation = true; audioOptions.noise_suppression = true; } + + std::ostringstream contentId; + contentId << _ssrc; std::vector streamIds; - streamIds.push_back("1"); + streamIds.push_back(contentId.str()); - _outgoingAudioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "audio0", false, NativeNetworkingImpl::getDefaulCryptoOptions(), uniqueRandomIdGenerator, audioOptions); + _outgoingAudioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), contentId.str(), false, NativeNetworkingImpl::getDefaulCryptoOptions(), uniqueRandomIdGenerator, audioOptions); std::vector codecs; - for (const auto &codec : mediaContent.codecs) { - if (codec.name == "opus") { - auto mutableCodec = codec; + for (const auto &payloadType : mediaContent.payloadTypes) { + if (payloadType.name == "opus") { + cricket::AudioCodec codec(payloadType.id, payloadType.name, payloadType.clockrate, 0, payloadType.channels); - const uint8_t opusMinBitrateKbps = 16; - const uint8_t opusMaxBitrateKbps = 32; - const uint8_t opusStartBitrateKbps = 32; - const uint8_t opusPTimeMs = 60; + codec.SetParam(cricket::kCodecParamUseInbandFec, 1); + codec.SetParam(cricket::kCodecParamPTime, 60); + + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } - mutableCodec.SetParam(cricket::kCodecParamMinBitrate, opusMinBitrateKbps); - mutableCodec.SetParam(cricket::kCodecParamStartBitrate, opusStartBitrateKbps); - mutableCodec.SetParam(cricket::kCodecParamMaxBitrate, opusMaxBitrateKbps); - mutableCodec.SetParam(cricket::kCodecParamUseInbandFec, 1); - mutableCodec.SetParam(cricket::kCodecParamPTime, opusPTimeMs); - - codecs.push_back(std::move(mutableCodec)); + codecs.push_back(std::move(codec)); + + break; } } @@ -606,14 +149,10 @@ public: _outgoingAudioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, nullptr); }); - //_outgoingAudioChannel->SignalSentPacket().connect(this, &OutgoingAudioChannel::OnSentPacket_w); - //_outgoingAudioChannel->UpdateRtpTransport(nullptr); - setIsMuted(false); } ~OutgoingAudioChannel() { - //_outgoingAudioChannel->SignalSentPacket().disconnect(this); _outgoingAudioChannel->Enable(false); _channelManager->DestroyVoiceChannel(_outgoingAudioChannel); _outgoingAudioChannel = nullptr; @@ -629,6 +168,27 @@ public: }); } } + + uint32_t ssrc() const { + return _ssrc; + } + + void setMaxBitrate(int bitrate) { + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + webrtc::RtpParameters initialParameters = _outgoingAudioChannel->media_channel()->GetRtpSendParameters(_ssrc); + webrtc::RtpParameters updatedParameters = initialParameters; + + if (updatedParameters.encodings.empty()) { + updatedParameters.encodings.push_back(webrtc::RtpEncodingParameters()); + } + + updatedParameters.encodings[0].max_bitrate_bps = bitrate; + + if (initialParameters != updatedParameters) { + _outgoingAudioChannel->media_channel()->SetRtpSendParameters(_ssrc, updatedParameters); + } + }); + } private: void OnSentPacket_w(const rtc::SentPacket& sent_packet) { @@ -653,7 +213,7 @@ public: webrtc::Call *call, webrtc::RtpTransport *rtpTransport, rtc::UniqueRandomIdGenerator *randomIdGenerator, - NegotiatedMediaContent const &mediaContent, + signaling::MediaContent const &mediaContent, std::shared_ptr threads) : _ssrc(mediaContent.ssrc), _channelManager(channelManager), @@ -663,12 +223,25 @@ public: cricket::AudioOptions audioOptions; audioOptions.audio_jitter_buffer_fast_accelerate = true; audioOptions.audio_jitter_buffer_min_delay_ms = 50; + + std::ostringstream contentId; + contentId << _ssrc; - std::string streamId = std::string("stream1"); + std::string streamId = contentId.str(); - _audioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "0", false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, audioOptions); + _audioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), contentId.str(), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, audioOptions); - auto audioCodecs = mediaContent.codecs; + std::vector codecs; + for (const auto &payloadType : mediaContent.payloadTypes) { + cricket::AudioCodec codec(payloadType.id, payloadType.name, payloadType.clockrate, 0, payloadType.channels); + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + codecs.push_back(std::move(codec)); + } auto outgoingAudioDescription = std::make_unique(); for (const auto &rtpExtension : mediaContent.rtpExtensions) { @@ -677,7 +250,7 @@ public: outgoingAudioDescription->set_rtcp_mux(true); outgoingAudioDescription->set_rtcp_reduced_size(true); outgoingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); - outgoingAudioDescription->set_codecs(audioCodecs); + outgoingAudioDescription->set_codecs(codecs); outgoingAudioDescription->set_bandwidth(-1); auto incomingAudioDescription = std::make_unique(); @@ -687,7 +260,7 @@ public: incomingAudioDescription->set_rtcp_mux(true); incomingAudioDescription->set_rtcp_reduced_size(true); incomingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); - incomingAudioDescription->set_codecs(audioCodecs); + incomingAudioDescription->set_codecs(codecs); incomingAudioDescription->set_bandwidth(-1); cricket::StreamParams streamParams = cricket::StreamParams::CreateLegacy(mediaContent.ssrc); streamParams.set_stream_ids({ streamId }); @@ -725,6 +298,10 @@ public: int64_t getActivity() { return _activityTimestamp; } + + uint32_t ssrc() const { + return _ssrc; + } private: void OnSentPacket_w(const rtc::SentPacket& sent_packet) { @@ -743,101 +320,6 @@ private: }; class OutgoingVideoChannel : public sigslot::has_slots<>, public std::enable_shared_from_this { -public: - static absl::optional createOutgoingContentDescription(std::vector const &availableVideoFormats, bool isScreencast) { - signaling::MediaContent mediaContent; - - auto generator = std::mt19937(std::random_device()()); - auto distribution = std::uniform_int_distribution(); - do { - mediaContent.ssrc = distribution(generator) & 0x7fffffffU; - } while (!mediaContent.ssrc); - - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, 2); - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, 3); - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kVideoRotationUri, 13); - - signaling::SsrcGroup fidGroup; - fidGroup.semantics = "FID"; - fidGroup.ssrcs.push_back(mediaContent.ssrc); - fidGroup.ssrcs.push_back(mediaContent.ssrc + 1); - mediaContent.ssrcGroups.push_back(std::move(fidGroup)); - - auto unsortedVideoFormats = generateAvailableVideoFormats(availableVideoFormats); - - std::vector formatPreferences; - if (isScreencast) { - formatPreferences.push_back(cricket::kVp8CodecName); - } else { -#ifndef WEBRTC_DISABLE_H265 - formatPreferences.push_back(cricket::kH265CodecName); -#endif - formatPreferences.push_back(cricket::kH264CodecName); - } - - std::vector videoFormats; - for (const auto &name : formatPreferences) { - for (size_t i = 0; i < unsortedVideoFormats.size(); i++) { - if (absl::EqualsIgnoreCase(name, unsortedVideoFormats[i].videoCodec.name)) { - videoFormats.push_back(unsortedVideoFormats[i]); - unsortedVideoFormats.erase(unsortedVideoFormats.begin() + i); - break; - } - } - } - for (const auto &format : unsortedVideoFormats) { - videoFormats.push_back(format); - } - - for (const auto &format : videoFormats) { - signaling::PayloadType videoPayload; - videoPayload.id = format.videoCodec.id; - videoPayload.name = format.videoCodec.name; - videoPayload.clockrate = format.videoCodec.clockrate; - videoPayload.channels = 0; - - std::vector videoFeedbackTypes; - - signaling::FeedbackType fbGoogRemb; - fbGoogRemb.type = "goog-remb"; - videoFeedbackTypes.push_back(fbGoogRemb); - - signaling::FeedbackType fbTransportCc; - fbTransportCc.type = "transport-cc"; - videoFeedbackTypes.push_back(fbTransportCc); - - signaling::FeedbackType fbCcmFir; - fbCcmFir.type = "ccm"; - fbCcmFir.subtype = "fir"; - videoFeedbackTypes.push_back(fbCcmFir); - - signaling::FeedbackType fbNack; - fbNack.type = "nack"; - videoFeedbackTypes.push_back(fbNack); - - signaling::FeedbackType fbNackPli; - fbNackPli.type = "nack"; - fbNackPli.subtype = "pli"; - videoFeedbackTypes.push_back(fbNackPli); - - videoPayload.feedbackTypes = videoFeedbackTypes; - videoPayload.parameters = {}; - - mediaContent.payloadTypes.push_back(std::move(videoPayload)); - - if (format.rtxCodec) { - signaling::PayloadType rtxPayload; - rtxPayload.id = format.rtxCodec->id; - rtxPayload.name = format.rtxCodec->name; - rtxPayload.clockrate = format.rtxCodec->clockrate; - rtxPayload.parameters.push_back(std::make_pair("apt", intToString(videoPayload.id))); - mediaContent.payloadTypes.push_back(std::move(rtxPayload)); - } - } - - return mediaContent; - } - public: OutgoingVideoChannel( std::shared_ptr threads, @@ -847,7 +329,7 @@ public: rtc::UniqueRandomIdGenerator *randomIdGenerator, webrtc::VideoBitrateAllocatorFactory *videoBitrateAllocatorFactory, std::function rotationUpdated, - NegotiatedMediaContent const &mediaContent, + signaling::MediaContent const &mediaContent, bool isScreencast ) : _threads(threads), @@ -857,9 +339,44 @@ public: _rotationUpdated(rotationUpdated) { cricket::VideoOptions videoOptions; videoOptions.is_screencast = isScreencast; - _outgoingVideoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "out" + intToString(mediaContent.ssrc), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, videoOptions, videoBitrateAllocatorFactory); + + std::ostringstream contentId; + contentId << mediaContent.ssrc; + + _outgoingVideoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), contentId.str(), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, videoOptions, videoBitrateAllocatorFactory); - auto videoCodecs = mediaContent.codecs; + std::vector unsortedCodecs; + for (const auto &payloadType : mediaContent.payloadTypes) { + cricket::VideoCodec codec(payloadType.id, payloadType.name); + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + unsortedCodecs.push_back(std::move(codec)); + } + + std::vector codecPreferences = { +#ifndef WEBRTC_DISABLE_H265 + cricket::kH265CodecName, +#endif + cricket::kH264CodecName + }; + + std::vector codecs; + for (const auto &name : codecPreferences) { + for (const auto &codec : unsortedCodecs) { + if (codec.name == name) { + codecs.push_back(codec); + } + } + } + for (const auto &codec : unsortedCodecs) { + if (std::find(codecs.begin(), codecs.end(), codec) == codecs.end()) { + codecs.push_back(codec); + } + } auto outgoingVideoDescription = std::make_unique(); for (const auto &rtpExtension : mediaContent.rtpExtensions) { @@ -869,14 +386,16 @@ public: outgoingVideoDescription->set_rtcp_mux(true); outgoingVideoDescription->set_rtcp_reduced_size(true); outgoingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); - outgoingVideoDescription->set_codecs(videoCodecs); + outgoingVideoDescription->set_codecs(codecs); outgoingVideoDescription->set_bandwidth(-1); cricket::StreamParams videoSendStreamParams; for (const auto &ssrcGroup : mediaContent.ssrcGroups) { for (auto ssrc : ssrcGroup.ssrcs) { - videoSendStreamParams.ssrcs.push_back(ssrc); + if (!videoSendStreamParams.has_ssrc(ssrc)) { + videoSendStreamParams.ssrcs.push_back(ssrc); + } } cricket::SsrcGroup mappedGroup(ssrcGroup.semantics, ssrcGroup.ssrcs); @@ -894,7 +413,7 @@ public: incomingVideoDescription->set_rtcp_mux(true); incomingVideoDescription->set_rtcp_reduced_size(true); incomingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); - incomingVideoDescription->set_codecs(videoCodecs); + incomingVideoDescription->set_codecs(codecs); incomingVideoDescription->set_bandwidth(-1); threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { @@ -903,6 +422,10 @@ public: _outgoingVideoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, nullptr); webrtc::RtpParameters rtpParameters = _outgoingVideoChannel->media_channel()->GetRtpSendParameters(mediaContent.ssrc); + + if (isScreencast) { + rtpParameters.degradation_preference = webrtc::DegradationPreference::MAINTAIN_RESOLUTION; + } _outgoingVideoChannel->media_channel()->SetRtpSendParameters(mediaContent.ssrc, rtpParameters); }); @@ -999,6 +522,27 @@ public: }); } } + + uint32_t ssrc() const { + return _mainSsrc; + } + + void setMaxBitrate(int bitrate) { + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + webrtc::RtpParameters initialParameters = _outgoingVideoChannel->media_channel()->GetRtpSendParameters(_mainSsrc); + webrtc::RtpParameters updatedParameters = initialParameters; + + if (updatedParameters.encodings.empty()) { + updatedParameters.encodings.push_back(webrtc::RtpEncodingParameters()); + } + + updatedParameters.encodings[0].max_bitrate_bps = bitrate; + + if (initialParameters != updatedParameters) { + _outgoingVideoChannel->media_channel()->SetRtpSendParameters(_mainSsrc, updatedParameters); + } + }); + } public: std::shared_ptr videoCapture() { @@ -1081,18 +625,30 @@ public: webrtc::Call *call, webrtc::RtpTransport *rtpTransport, rtc::UniqueRandomIdGenerator *randomIdGenerator, - NegotiatedMediaContent const &mediaContent, - std::string const &streamId, + signaling::MediaContent const &mediaContent, std::shared_ptr threads) : _channelManager(channelManager), _call(call) { _videoSink.reset(new VideoSinkImpl()); _videoBitrateAllocatorFactory = webrtc::CreateBuiltinVideoBitrateAllocatorFactory(); + + std::ostringstream contentId; + contentId << mediaContent.ssrc; - _videoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), streamId, false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, cricket::VideoOptions(), _videoBitrateAllocatorFactory.get()); + _videoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), contentId.str(), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, cricket::VideoOptions(), _videoBitrateAllocatorFactory.get()); - std::vector videoCodecs = mediaContent.codecs; + std::vector codecs; + for (const auto &payloadType : mediaContent.payloadTypes) { + cricket::VideoCodec codec(payloadType.id, payloadType.name); + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + codecs.push_back(std::move(codec)); + } auto outgoingVideoDescription = std::make_unique(); for (const auto &rtpExtension : mediaContent.rtpExtensions) { @@ -1101,7 +657,7 @@ public: outgoingVideoDescription->set_rtcp_mux(true); outgoingVideoDescription->set_rtcp_reduced_size(true); outgoingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); - outgoingVideoDescription->set_codecs(videoCodecs); + outgoingVideoDescription->set_codecs(codecs); outgoingVideoDescription->set_bandwidth(-1); cricket::StreamParams videoRecvStreamParams; @@ -1122,7 +678,7 @@ public: videoRecvStreamParams.ssrcs = allSsrcs; videoRecvStreamParams.cname = "cname"; - videoRecvStreamParams.set_stream_ids({ streamId }); + videoRecvStreamParams.set_stream_ids({ contentId.str() }); auto incomingVideoDescription = std::make_unique(); for (const auto &rtpExtension : mediaContent.rtpExtensions) { @@ -1131,7 +687,7 @@ public: incomingVideoDescription->set_rtcp_mux(true); incomingVideoDescription->set_rtcp_reduced_size(true); incomingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); - incomingVideoDescription->set_codecs(videoCodecs); + incomingVideoDescription->set_codecs(codecs); incomingVideoDescription->set_bandwidth(-1); incomingVideoDescription->AddStream(videoRecvStreamParams); @@ -1156,6 +712,10 @@ public: void addSink(std::weak_ptr> impl) { _videoSink->addSink(impl); } + + uint32_t ssrc() const { + return _mainVideoSsrc; + } private: void OnSentPacket_w(const rtc::SentPacket& sent_packet) { @@ -1173,6 +733,45 @@ private: webrtc::Call *_call = nullptr; }; +template +struct StateLogRecord { + int64_t timestamp = 0; + T record; + + explicit StateLogRecord(int32_t timestamp_, T &&record_) : + timestamp(timestamp_), + record(std::move(record_)) { + } +}; + +struct NetworkStateLogRecord { + bool isConnected = false; + bool isFailed = false; + absl::optional route; + absl::optional connection; + + bool operator==(NetworkStateLogRecord const &rhs) const { + if (isConnected != rhs.isConnected) { + return false; + } + if (isFailed != rhs.isFailed) { + return false; + } + if (route != rhs.route) { + return false; + } + if (connection != rhs.connection) { + return false; + } + + return true; + } +}; + +struct NetworkBitrateLogRecord { + int32_t bitrate = 0; +}; + } // namespace class InstanceV2ImplInternal : public std::enable_shared_from_this { @@ -1180,6 +779,8 @@ public: InstanceV2ImplInternal(Descriptor &&descriptor, std::shared_ptr threads) : _threads(threads), _rtcServers(descriptor.rtcServers), + _proxy(std::move(descriptor.proxy)), + _enableP2P(descriptor.config.enableP2P), _encryptionKey(std::move(descriptor.encryptionKey)), _stateUpdated(descriptor.stateUpdated), _signalBarsUpdated(descriptor.signalBarsUpdated), @@ -1189,6 +790,7 @@ public: _remotePrefferedAspectRatioUpdated(descriptor.remotePrefferedAspectRatioUpdated), _signalingDataEmitted(descriptor.signalingDataEmitted), _createAudioDeviceModule(descriptor.createAudioDeviceModule), + _statsLogPath(descriptor.config.statsLogPath), _eventLog(std::make_unique()), _taskQueueFactory(webrtc::CreateDefaultTaskQueueFactory()), _videoCapture(descriptor.videoCapture), @@ -1213,20 +815,31 @@ public: _call.reset(); _audioDeviceModule = nullptr; }); + + _contentNegotiationContext.reset(); + _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, []() { }); } void start() { + _startTimestamp = rtc::TimeMillis(); + const auto weak = std::weak_ptr(shared_from_this()); + + absl::optional proxy; + if (_proxy) { + proxy = *(_proxy.get()); + } - _networking.reset(new ThreadLocalObject(_threads->getNetworkThread(), [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing, rtcServers = _rtcServers]() { + _networking.reset(new ThreadLocalObject(_threads->getNetworkThread(), [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing, rtcServers = _rtcServers, proxy, enableP2P = _enableP2P]() { return new NativeNetworkingImpl(NativeNetworkingImpl::Configuration{ .isOutgoing = isOutgoing, .enableStunMarking = false, .enableTCP = false, - .enableP2P = true, + .enableP2P = enableP2P, .rtcServers = rtcServers, + .proxy = proxy, .stateUpdated = [threads, weak](const NativeNetworkingImpl::State &state) { threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { const auto strong = weak.lock(); @@ -1323,6 +936,12 @@ public: }); _uniqueRandomIdGenerator.reset(new rtc::UniqueRandomIdGenerator()); + + _contentNegotiationContext = std::make_unique(_encryptionKey.isOutgoing, _uniqueRandomIdGenerator.get()); + _contentNegotiationContext->copyCodecsFromChannelManager(_channelManager.get(), false); + + _outgoingAudioChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Audio); + //_contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, [this]() { _rtpTransport = _networking->getSyncAssumingSameThread()->getRtpTransport(); @@ -1341,6 +960,75 @@ public: beginSignaling(); adjustBitratePreferences(true); + + beginQualityTimer(0); + beginLogTimer(0); + } + + void beginQualityTimer(int delayMs) { + const auto weak = std::weak_ptr(shared_from_this()); + _threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + auto strong = weak.lock(); + if (!strong) { + return; + } + + + + strong->beginQualityTimer(500); + }, delayMs); + } + + void beginLogTimer(int delayMs) { + const auto weak = std::weak_ptr(shared_from_this()); + _threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + auto strong = weak.lock(); + if (!strong) { + return; + } + + strong->writeStateLogRecords(); + + strong->beginLogTimer(1000); + }, delayMs); + } + + void writeStateLogRecords() { + const auto weak = std::weak_ptr(shared_from_this()); + _threads->getWorkerThread()->PostTask(RTC_FROM_HERE, [weak]() { + auto strong = weak.lock(); + if (!strong) { + return; + } + + auto stats = strong->_call->GetStats(); + float sendBitrateKbps = ((float)stats.send_bandwidth_bps / 1000.0f); + + strong->_threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, sendBitrateKbps]() { + auto strong = weak.lock(); + if (!strong) { + return; + } + + float bitrateNorm = 16.0f; + if (strong->_outgoingVideoChannel) { + bitrateNorm = 600.0f; + } + + float signalBarsNorm = 4.0f; + float adjustedQuality = sendBitrateKbps / bitrateNorm; + adjustedQuality = fmaxf(0.0f, adjustedQuality); + adjustedQuality = fminf(1.0f, adjustedQuality); + if (strong->_signalBarsUpdated) { + strong->_signalBarsUpdated((int)(adjustedQuality * signalBarsNorm)); + } + + NetworkBitrateLogRecord networkBitrateLogRecord; + networkBitrateLogRecord.bitrate = (int32_t)sendBitrateKbps; + + strong->_networkBitrateLogRecords.emplace_back(rtc::TimeMillis(), std::move(networkBitrateLogRecord)); + }); + }); } void sendSignalingMessage(signaling::Message const &message) { @@ -1363,42 +1051,188 @@ public: _signalingEncryption.reset(new SignalingEncryption(_encryptionKey)); if (_encryptionKey.isOutgoing) { - _outgoingAudioContent = OutgoingAudioChannel::createOutgoingContentDescription(); - _outgoingVideoContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, false); - _outgoingScreencastContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, true); - sendInitialSetup(); } } void createNegotiatedChannels() { - if (_negotiatedOutgoingVideoContent) { - const auto weak = std::weak_ptr(shared_from_this()); - - _outgoingVideoChannel.reset(new OutgoingVideoChannel( - _threads, - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - _videoBitrateAllocatorFactory.get(), - [threads = _threads, weak]() { - threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { - const auto strong = weak.lock(); - if (!strong) { - return; - } - strong->sendMediaState(); - }); - }, - _negotiatedOutgoingVideoContent.value(), - false - )); - - if (_videoCapture) { - _outgoingVideoChannel->setVideoCapture(_videoCapture); + const auto coordinatedState = _contentNegotiationContext->coordinatedState(); + if (!coordinatedState) { + return; + } + + if (_outgoingAudioChannelId) { + const auto audioSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingAudioChannelId.value()); + if (audioSsrc) { + if (_outgoingAudioChannel && _outgoingAudioChannel->ssrc() != audioSsrc.value()) { + _outgoingAudioChannel.reset(); + } + + absl::optional outgoingAudioContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Audio && content.ssrc == audioSsrc.value()) { + outgoingAudioContent = content; + break; + } + } + + if (outgoingAudioContent) { + if (!_outgoingAudioChannel) { + _outgoingAudioChannel.reset(new OutgoingAudioChannel( + _call.get(), + _channelManager.get(), + _uniqueRandomIdGenerator.get(), + &_audioSource, + _rtpTransport, + outgoingAudioContent.value(), + _threads + )); + } + } } } + + if (_outgoingVideoChannelId) { + const auto videoSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingVideoChannelId.value()); + if (videoSsrc) { + if (_outgoingVideoChannel && _outgoingVideoChannel->ssrc() != videoSsrc.value()) { + _outgoingVideoChannel.reset(); + } + + absl::optional outgoingVideoContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Video && content.ssrc == videoSsrc.value()) { + outgoingVideoContent = content; + break; + } + } + + if (outgoingVideoContent) { + if (!_outgoingVideoChannel) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingVideoChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + outgoingVideoContent.value(), + false + )); + + if (_videoCapture) { + _outgoingVideoChannel->setVideoCapture(_videoCapture); + } + } + } + } + } + + if (_outgoingScreencastChannelId) { + const auto screencastSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingScreencastChannelId.value()); + if (screencastSsrc) { + if (_outgoingScreencastChannel && _outgoingScreencastChannel->ssrc() != screencastSsrc.value()) { + _outgoingScreencastChannel.reset(); + } + + absl::optional outgoingScreencastContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Video && content.ssrc == screencastSsrc.value()) { + outgoingScreencastContent = content; + break; + } + } + + if (outgoingScreencastContent) { + if (!_outgoingScreencastChannel) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingScreencastChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + outgoingScreencastContent.value(), + true + )); + + if (_screencastCapture) { + _outgoingScreencastChannel->setVideoCapture(_screencastCapture); + } + } + } + } + } + + for (const auto &content : coordinatedState->incomingContents) { + switch (content.type) { + case signaling::MediaContent::Type::Audio: { + if (_incomingAudioChannel && _incomingAudioChannel->ssrc() != content.ssrc) { + _incomingAudioChannel.reset(); + } + + if (!_incomingAudioChannel) { + _incomingAudioChannel.reset(new IncomingV2AudioChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + content, + _threads + )); + } + + break; + } + case signaling::MediaContent::Type::Video: { + if (_incomingVideoChannel && _incomingVideoChannel->ssrc() != content.ssrc) { + _incomingVideoChannel.reset(); + } + + if (!_incomingVideoChannel) { + _incomingVideoChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + content, + _threads + )); + _incomingVideoChannel->addSink(_currentSink); + } + + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + } + + /* if (_negotiatedOutgoingScreencastContent) { const auto weak = std::weak_ptr(shared_from_this()); @@ -1438,9 +1272,10 @@ public: _negotiatedOutgoingAudioContent.value(), _threads )); - } + }*/ adjustBitratePreferences(true); + sendMediaState(); } void sendInitialSetup() { @@ -1469,16 +1304,6 @@ public: signaling::InitialSetupMessage data; - if (strong->_outgoingAudioContent) { - data.audio = strong->_outgoingAudioContent.value(); - } - if (strong->_outgoingVideoContent) { - data.video = strong->_outgoingVideoContent.value(); - } - if (strong->_outgoingScreencastContent) { - data.screencast = strong->_outgoingScreencastContent.value(); - } - data.ufrag = ufrag; data.pwd = pwd; @@ -1494,6 +1319,20 @@ public: }); }); } + + void sendOfferIfNeeded() { + if (const auto offer = _contentNegotiationContext->getPendingOffer()) { + signaling::NegotiateChannelsMessage data; + + data.exchangeId = offer->exchangeId; + + data.contents = offer->contents; + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + } void receiveSignalingData(const std::vector &data) { std::vector decryptedData; @@ -1537,185 +1376,35 @@ public: _networking->perform(RTC_FROM_HERE, [threads = _threads, remoteIceParameters = std::move(remoteIceParameters), fingerprint = std::move(fingerprint), sslSetup = std::move(sslSetup)](NativeNetworkingImpl *networking) { networking->setRemoteParams(remoteIceParameters, fingerprint.get(), sslSetup); }); + + _handshakeCompleted = true; - if (const auto audio = initialSetup->audio) { - if (_encryptionKey.isOutgoing) { - if (_outgoingAudioContent) { - _negotiatedOutgoingAudioContent = negotiateMediaContent(_outgoingAudioContent.value(), _outgoingAudioContent.value(), audio.value(), false); - const auto incomingAudioContent = negotiateMediaContent(audio.value(), _outgoingAudioContent.value(), audio.value(), false); - - signaling::MediaContent outgoingAudioContent; - - outgoingAudioContent.ssrc = _outgoingAudioContent->ssrc; - outgoingAudioContent.ssrcGroups = _outgoingAudioContent->ssrcGroups; - outgoingAudioContent.rtpExtensions = _negotiatedOutgoingAudioContent->rtpExtensions; - outgoingAudioContent.payloadTypes = getPayloadTypesFromAudioCodecs(_negotiatedOutgoingAudioContent->codecs); - - _outgoingAudioContent = std::move(outgoingAudioContent); - - _incomingAudioChannel.reset(new IncomingV2AudioChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingAudioContent, - _threads - )); - } - } else { - const auto generatedOutgoingContent = OutgoingAudioChannel::createOutgoingContentDescription(); - - if (generatedOutgoingContent) { - _negotiatedOutgoingAudioContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), audio.value(), true); - const auto incomingAudioContent = negotiateMediaContent(audio.value(), generatedOutgoingContent.value(), audio.value(), true); - - if (_negotiatedOutgoingAudioContent) { - signaling::MediaContent outgoingAudioContent; - - outgoingAudioContent.ssrc = generatedOutgoingContent->ssrc; - outgoingAudioContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; - outgoingAudioContent.rtpExtensions = _negotiatedOutgoingAudioContent->rtpExtensions; - outgoingAudioContent.payloadTypes = getPayloadTypesFromAudioCodecs(_negotiatedOutgoingAudioContent->codecs); - - _outgoingAudioContent = std::move(outgoingAudioContent); - - _incomingAudioChannel.reset(new IncomingV2AudioChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingAudioContent, - _threads - )); - } - } - } - } - - if (const auto video = initialSetup->video) { - if (_encryptionKey.isOutgoing) { - if (_outgoingVideoContent) { - _negotiatedOutgoingVideoContent = negotiateMediaContent(_outgoingVideoContent.value(), _outgoingVideoContent.value(), video.value(), false); - const auto incomingVideoContent = negotiateMediaContent(video.value(), _outgoingVideoContent.value(), video.value(), false); - - signaling::MediaContent outgoingVideoContent; - - outgoingVideoContent.ssrc = _outgoingVideoContent->ssrc; - outgoingVideoContent.ssrcGroups = _outgoingVideoContent->ssrcGroups; - outgoingVideoContent.rtpExtensions = _negotiatedOutgoingVideoContent->rtpExtensions; - outgoingVideoContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingVideoContent->codecs); - - _outgoingVideoContent = std::move(outgoingVideoContent); - - _incomingVideoChannel.reset(new IncomingV2VideoChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingVideoContent, - "1", - _threads - )); - _incomingVideoChannel->addSink(_currentSink); - } - } else { - const auto generatedOutgoingContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, false); - - if (generatedOutgoingContent) { - _negotiatedOutgoingVideoContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), video.value(), true); - const auto incomingVideoContent = negotiateMediaContent(video.value(), generatedOutgoingContent.value(), video.value(), true); - - if (_negotiatedOutgoingVideoContent) { - signaling::MediaContent outgoingVideoContent; - - outgoingVideoContent.ssrc = generatedOutgoingContent->ssrc; - outgoingVideoContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; - outgoingVideoContent.rtpExtensions = _negotiatedOutgoingVideoContent->rtpExtensions; - outgoingVideoContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingVideoContent->codecs); - - _outgoingVideoContent = std::move(outgoingVideoContent); - - _incomingVideoChannel.reset(new IncomingV2VideoChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingVideoContent, - "1", - _threads - )); - _incomingVideoChannel->addSink(_currentSink); - } - } - } - } - - if (const auto screencast = initialSetup->screencast) { - if (_encryptionKey.isOutgoing) { - if (_outgoingScreencastContent) { - _negotiatedOutgoingScreencastContent = negotiateMediaContent(_outgoingScreencastContent.value(), _outgoingScreencastContent.value(), screencast.value(), false); - const auto incomingScreencastContent = negotiateMediaContent(screencast.value(), _outgoingScreencastContent.value(), screencast.value(), false); - - signaling::MediaContent outgoingScreencastContent; - - outgoingScreencastContent.ssrc = _outgoingScreencastContent->ssrc; - outgoingScreencastContent.ssrcGroups = _outgoingScreencastContent->ssrcGroups; - outgoingScreencastContent.rtpExtensions = _negotiatedOutgoingScreencastContent->rtpExtensions; - outgoingScreencastContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingScreencastContent->codecs); - - _outgoingScreencastContent = std::move(outgoingScreencastContent); - - _incomingScreencastChannel.reset(new IncomingV2VideoChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingScreencastContent, - "2", - _threads - )); - _incomingScreencastChannel->addSink(_currentSink); - } - } else { - const auto generatedOutgoingContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, true); - - if (generatedOutgoingContent) { - _negotiatedOutgoingScreencastContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), screencast.value(), true); - const auto incomingScreencastContent = negotiateMediaContent(screencast.value(), generatedOutgoingContent.value(), screencast.value(), true); - - if (_negotiatedOutgoingScreencastContent) { - signaling::MediaContent outgoingScreencastContent; - - outgoingScreencastContent.ssrc = generatedOutgoingContent->ssrc; - outgoingScreencastContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; - outgoingScreencastContent.rtpExtensions = _negotiatedOutgoingScreencastContent->rtpExtensions; - outgoingScreencastContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingScreencastContent->codecs); - - _outgoingScreencastContent = std::move(outgoingScreencastContent); - - _incomingScreencastChannel.reset(new IncomingV2VideoChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingScreencastContent, - "2", - _threads - )); - _incomingScreencastChannel->addSink(_currentSink); - } - } - } - } - - createNegotiatedChannels(); - - if (!_encryptionKey.isOutgoing) { + if (_encryptionKey.isOutgoing) { + sendOfferIfNeeded(); + } else { sendInitialSetup(); } - _handshakeCompleted = true; commitPendingIceCandidates(); + } else if (const auto offerAnwer = absl::get_if(messageData)) { + auto negotiationContents = std::make_unique(); + negotiationContents->exchangeId = offerAnwer->exchangeId; + negotiationContents->contents = offerAnwer->contents; + + if (const auto response = _contentNegotiationContext->setRemoteNegotiationContent(std::move(negotiationContents))) { + signaling::NegotiateChannelsMessage data; + + data.exchangeId = response->exchangeId; + data.contents = response->contents; + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + + sendOfferIfNeeded(); + + createNegotiatedChannels(); } else if (const auto candidatesList = absl::get_if(messageData)) { for (const auto &candidate : candidatesList->iceCandidates) { webrtc::JsepIceCandidate parseCandidate{ std::string(), 0 }; @@ -1804,11 +1493,26 @@ public: void onNetworkStateUpdated(NativeNetworkingImpl::State const &state) { State mappedState; - if (state.isReadyToSendData) { + if (state.isFailed) { + mappedState = State::Failed; + } else if (state.isReadyToSendData) { mappedState = State::Established; } else { mappedState = State::Reconnecting; } + + NetworkStateLogRecord record; + record.isConnected = state.isReadyToSendData; + record.route = state.route; + record.connection = state.connection; + record.isFailed = state.isFailed; + + if (!_currentNetworkStateLogRecord || !(_currentNetworkStateLogRecord.value() == record)) { + _currentNetworkStateLogRecord = record; + _networkStateLogRecords.emplace_back(rtc::TimeMillis(), std::move(record)); + } + + _networkState = state; _stateUpdated(mappedState); } @@ -1907,13 +1611,17 @@ public: if (_outgoingVideoChannel) { _outgoingVideoChannel->setVideoCapture(nullptr); } + if (_outgoingVideoChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingVideoChannelId.value()); + _outgoingVideoChannelId.reset(); + } if (_outgoingScreencastChannel) { _outgoingScreencastChannel->setVideoCapture(videoCapture); } - - sendMediaState(); - adjustBitratePreferences(true); + if (!_outgoingScreencastChannelId) { + _outgoingScreencastChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); + } } else { _videoCapture = videoCapture; _screencastCapture = nullptr; @@ -1921,13 +1629,17 @@ public: if (_outgoingVideoChannel) { _outgoingVideoChannel->setVideoCapture(videoCapture); } + if (!_outgoingVideoChannelId) { + _outgoingVideoChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); + } if (_outgoingScreencastChannel) { _outgoingScreencastChannel->setVideoCapture(nullptr); } - - sendMediaState(); - adjustBitratePreferences(true); + if (_outgoingScreencastChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingScreencastChannelId.value()); + _outgoingScreencastChannelId.reset(); + } } } else { _videoCapture = nullptr; @@ -1940,9 +1652,23 @@ public: if (_outgoingScreencastChannel) { _outgoingScreencastChannel->setVideoCapture(nullptr); } + + if (_outgoingVideoChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingVideoChannelId.value()); + _outgoingVideoChannelId.reset(); + } + + if (_outgoingScreencastChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingScreencastChannelId.value()); + _outgoingScreencastChannelId.reset(); + } + } + if (_handshakeCompleted) { + sendOfferIfNeeded(); sendMediaState(); adjustBitratePreferences(true); + createNegotiatedChannels(); } } @@ -1991,33 +1717,99 @@ public: } void stop(std::function completion) { - completion({}); + FinalState finalState; + + json11::Json::object statsLog; + + for (int i = (int)_networkStateLogRecords.size() - 1; i >= 1; i--) { + // coalesce events within 5ms + if (_networkStateLogRecords[i].timestamp - _networkStateLogRecords[i - 1].timestamp < 5) { + _networkStateLogRecords.erase(_networkStateLogRecords.begin() + i - 1); + } + } + + json11::Json::array jsonNetworkStateLogRecords; + int64_t baseTimestamp = 0; + for (const auto &record : _networkStateLogRecords) { + json11::Json::object jsonRecord; + + std::ostringstream timestampString; + + if (baseTimestamp == 0) { + baseTimestamp = record.timestamp; + } + timestampString << (record.timestamp - baseTimestamp); + + jsonRecord.insert(std::make_pair("t", json11::Json(timestampString.str()))); + jsonRecord.insert(std::make_pair("c", json11::Json(record.record.isConnected ? 1 : 0))); + if (record.record.route) { + jsonRecord.insert(std::make_pair("local", json11::Json(record.record.route->localDescription))); + jsonRecord.insert(std::make_pair("remote", json11::Json(record.record.route->remoteDescription))); + } + if (record.record.connection) { + json11::Json::object jsonConnection; + + auto serializeCandidate = [](NativeNetworkingImpl::ConnectionDescription::CandidateDescription const &candidate) -> json11::Json::object { + json11::Json::object jsonCandidate; + + jsonCandidate.insert(std::make_pair("type", json11::Json(candidate.type))); + jsonCandidate.insert(std::make_pair("protocol", json11::Json(candidate.protocol))); + jsonCandidate.insert(std::make_pair("address", json11::Json(candidate.address))); + + return jsonCandidate; + }; + + jsonConnection.insert(std::make_pair("local", serializeCandidate(record.record.connection->local))); + jsonConnection.insert(std::make_pair("remote", serializeCandidate(record.record.connection->remote))); + + jsonRecord.insert(std::make_pair("network", std::move(jsonConnection))); + } + if (record.record.isFailed) { + jsonRecord.insert(std::make_pair("failed", json11::Json(1))); + } + + jsonNetworkStateLogRecords.push_back(std::move(jsonRecord)); + } + statsLog.insert(std::make_pair("network", std::move(jsonNetworkStateLogRecords))); + + json11::Json::array jsonNetworkBitrateLogRecords; + for (const auto &record : _networkBitrateLogRecords) { + json11::Json::object jsonRecord; + + jsonRecord.insert(std::make_pair("b", json11::Json(record.record.bitrate))); + + jsonNetworkBitrateLogRecords.push_back(std::move(jsonRecord)); + } + statsLog.insert(std::make_pair("bitrate", std::move(jsonNetworkBitrateLogRecords))); + + auto jsonStatsLog = json11::Json(std::move(statsLog)); + + if (!_statsLogPath.data.empty()) { + std::ofstream file; + file.open(_statsLogPath.data); + + file << jsonStatsLog.dump(); + + file.close(); + } + + completion(finalState); } void adjustBitratePreferences(bool resetStartBitrate) { - webrtc::BitrateConstraints preferences; - if (_videoCapture || _screencastCapture) { - preferences.min_bitrate_bps = 64000; - if (resetStartBitrate) { - preferences.start_bitrate_bps = (100 + 800 + 32 + 100) * 1000; - } - preferences.max_bitrate_bps = (100 + 200 + 800 + 32 + 100) * 1000; - } else { - preferences.min_bitrate_bps = 32000; - if (resetStartBitrate) { - preferences.start_bitrate_bps = 32000; - } - preferences.max_bitrate_bps = 32000; + if (_outgoingAudioChannel) { + _outgoingAudioChannel->setMaxBitrate(32 * 1024); + } + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setMaxBitrate(1000 * 1024); } - - _call->GetTransportControllerSend()->SetSdpBitrateParameters(preferences); } private: rtc::scoped_refptr createAudioDeviceModule() { const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { #ifdef WEBRTC_IOS - return rtc::make_ref_counted(false, false); + return rtc::make_ref_counted(false, false, 1); #else return webrtc::AudioDeviceModule::Create( layer, @@ -2038,6 +1830,8 @@ private: private: std::shared_ptr _threads; std::vector _rtcServers; + std::unique_ptr _proxy; + bool _enableP2P = false; EncryptionKey _encryptionKey; std::function _stateUpdated; std::function _signalBarsUpdated; @@ -2047,8 +1841,17 @@ private: std::function _remotePrefferedAspectRatioUpdated; std::function &)> _signalingDataEmitted; std::function(webrtc::TaskQueueFactory*)> _createAudioDeviceModule; + FilePath _statsLogPath; std::unique_ptr _signalingEncryption; + + int64_t _startTimestamp = 0; + + absl::optional _currentNetworkStateLogRecord; + std::vector> _networkStateLogRecords; + std::vector> _networkBitrateLogRecords; + + absl::optional _networkState; bool _handshakeCompleted = false; std::vector _pendingIceCandidates; @@ -2066,24 +1869,20 @@ private: webrtc::RtpTransport *_rtpTransport = nullptr; std::unique_ptr _channelManager; std::unique_ptr _videoBitrateAllocatorFactory; + + std::unique_ptr _contentNegotiationContext; std::shared_ptr> _networking; - absl::optional _outgoingAudioContent; - absl::optional> _negotiatedOutgoingAudioContent; - + absl::optional _outgoingAudioChannelId; std::unique_ptr _outgoingAudioChannel; bool _isMicrophoneMuted = false; std::vector _availableVideoFormats; - absl::optional _outgoingVideoContent; - absl::optional> _negotiatedOutgoingVideoContent; - - absl::optional _outgoingScreencastContent; - absl::optional> _negotiatedOutgoingScreencastContent; - + absl::optional _outgoingVideoChannelId; std::shared_ptr _outgoingVideoChannel; + absl::optional _outgoingScreencastChannelId; std::shared_ptr _outgoingScreencastChannel; bool _isBatteryLow = false; @@ -2193,7 +1992,7 @@ void InstanceV2Impl::setEchoCancellationStrength(int strength) { std::vector InstanceV2Impl::GetVersions() { std::vector result; - result.push_back("4.0.0"); + result.push_back("4.0.1"); return result; } diff --git a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.cpp b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.cpp new file mode 100644 index 000000000..6cc896d05 --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.cpp @@ -0,0 +1,1023 @@ +#include "v2/InstanceV2ReferenceImpl.h" + +#include "LogSinkImpl.h" +#include "VideoCaptureInterfaceImpl.h" +#include "VideoCapturerInterface.h" +#include "v2/NativeNetworkingImpl.h" +#include "v2/Signaling.h" +#include "v2/ContentNegotiation.h" + +#include "CodecSelectHelper.h" +#include "platform/PlatformInterface.h" + +#include "api/audio_codecs/audio_decoder_factory_template.h" +#include "api/audio_codecs/audio_encoder_factory_template.h" +#include "api/audio_codecs/opus/audio_decoder_opus.h" +#include "api/audio_codecs/opus/audio_decoder_multi_channel_opus.h" +#include "api/audio_codecs/opus/audio_encoder_opus.h" +#include "api/audio_codecs/L16/audio_decoder_L16.h" +#include "api/audio_codecs/L16/audio_encoder_L16.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "media/engine/webrtc_media_engine.h" +#include "system_wrappers/include/field_trial.h" +#include "api/video/builtin_video_bitrate_allocator_factory.h" +#include "call/call.h" +#include "api/call/audio_sink.h" +#include "modules/audio_processing/audio_buffer.h" +#include "absl/strings/match.h" +#include "pc/channel_manager.h" +#include "audio/audio_state.h" +#include "modules/audio_coding/neteq/default_neteq_factory.h" +#include "modules/audio_coding/include/audio_coding_module.h" +#include "api/candidate.h" +#include "api/jsep_ice_candidate.h" +#include "pc/used_ids.h" +#include "media/base/sdp_video_format_utils.h" +#include "pc/media_session.h" +#include "rtc_base/rtc_certificate_generator.h" +#include "pc/peer_connection.h" + +#include "AudioFrame.h" +#include "ThreadLocalObject.h" +#include "Manager.h" +#include "NetworkManager.h" +#include "VideoCaptureInterfaceImpl.h" +#include "platform/PlatformInterface.h" +#include "LogSinkImpl.h" +#include "CodecSelectHelper.h" +#include "AudioDeviceHelper.h" +#include "SignalingEncryption.h" +#ifdef WEBRTC_IOS +#include "platform/darwin/iOS/tgcalls_audio_device_module_ios.h" +#endif +#include +#include + +namespace tgcalls { +namespace { + +static VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(VideoCaptureInterface *videoCapture) { + return videoCapture + ? static_cast(videoCapture)->object()->getSyncAssumingSameThread() + : nullptr; +} + +class VideoSinkImpl : public rtc::VideoSinkInterface { +public: + VideoSinkImpl() { + } + + virtual ~VideoSinkImpl() { + } + + virtual void OnFrame(const webrtc::VideoFrame& frame) override { + //_lastFrame = frame; + for (int i = (int)(_sinks.size()) - 1; i >= 0; i--) { + auto strong = _sinks[i].lock(); + if (!strong) { + _sinks.erase(_sinks.begin() + i); + } else { + strong->OnFrame(frame); + } + } + } + + virtual void OnDiscardedFrame() override { + for (int i = (int)(_sinks.size()) - 1; i >= 0; i--) { + auto strong = _sinks[i].lock(); + if (!strong) { + _sinks.erase(_sinks.begin() + i); + } else { + strong->OnDiscardedFrame(); + } + } + } + + void addSink(std::weak_ptr> impl) { + _sinks.push_back(impl); + if (_lastFrame) { + auto strong = impl.lock(); + if (strong) { + strong->OnFrame(_lastFrame.value()); + } + } + } + +private: + std::vector>> _sinks; + absl::optional _lastFrame; +}; + +} // namespace + +class InstanceV2ReferenceImplInternal : public std::enable_shared_from_this { +public: + InstanceV2ReferenceImplInternal(Descriptor &&descriptor, std::shared_ptr threads) : + _threads(threads), + _rtcServers(descriptor.rtcServers), + _proxy(std::move(descriptor.proxy)), + _enableP2P(descriptor.config.enableP2P), + _encryptionKey(std::move(descriptor.encryptionKey)), + _stateUpdated(descriptor.stateUpdated), + _signalBarsUpdated(descriptor.signalBarsUpdated), + _audioLevelUpdated(descriptor.audioLevelUpdated), + _remoteBatteryLevelIsLowUpdated(descriptor.remoteBatteryLevelIsLowUpdated), + _remoteMediaStateUpdated(descriptor.remoteMediaStateUpdated), + _remotePrefferedAspectRatioUpdated(descriptor.remotePrefferedAspectRatioUpdated), + _signalingDataEmitted(descriptor.signalingDataEmitted), + _createAudioDeviceModule(descriptor.createAudioDeviceModule), + _eventLog(std::make_unique()), + _taskQueueFactory(webrtc::CreateDefaultTaskQueueFactory()), + _videoCapture(descriptor.videoCapture), + _platformContext(descriptor.platformContext) { + } + + ~InstanceV2ReferenceImplInternal() { + + _currentSink.reset(); + } + + void start() { + const auto weak = std::weak_ptr(shared_from_this()); + + PlatformInterface::SharedInstance()->configurePlatformAudio(); + + RTC_DCHECK(_threads->getMediaThread()->IsCurrent()); + + //_threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + cricket::MediaEngineDependencies mediaDeps; + mediaDeps.task_queue_factory = _taskQueueFactory.get(); + mediaDeps.audio_encoder_factory = webrtc::CreateAudioEncoderFactory(); + mediaDeps.audio_decoder_factory = webrtc::CreateAudioDecoderFactory(); + + mediaDeps.video_encoder_factory = PlatformInterface::SharedInstance()->makeVideoEncoderFactory(_platformContext, true); + mediaDeps.video_decoder_factory = PlatformInterface::SharedInstance()->makeVideoDecoderFactory(_platformContext); + + _audioDeviceModule = createAudioDeviceModule(); + + mediaDeps.adm = _audioDeviceModule; + + std::unique_ptr mediaEngine = cricket::CreateMediaEngine(std::move(mediaDeps)); + //}); + + webrtc::PeerConnectionFactoryDependencies peerConnectionFactoryDependencies; + peerConnectionFactoryDependencies.signaling_thread = _threads->getMediaThread(); + peerConnectionFactoryDependencies.worker_thread = _threads->getWorkerThread(); + peerConnectionFactoryDependencies.task_queue_factory = std::move(_taskQueueFactory); + peerConnectionFactoryDependencies.media_engine = std::move(mediaEngine); + + auto peerConnectionFactory = webrtc::PeerConnectionFactory::Create(std::move(peerConnectionFactoryDependencies)); + + webrtc::PeerConnectionDependencies peerConnectionDependencies(nullptr); + + webrtc::PeerConnectionInterface::RTCConfiguration peerConnectionConfiguration; + + auto peerConnectionOrError = peerConnectionFactory->CreatePeerConnectionOrError(peerConnectionConfiguration, std::move(peerConnectionDependencies)); + if (peerConnectionOrError.ok()) { + _peerConnection = peerConnectionOrError.value(); + } + + if (_videoCapture) { + setVideoCapture(_videoCapture); + } + + beginSignaling(); + } + + void sendSignalingMessage(signaling::Message const &message) { + auto data = message.serialize(); + + RTC_LOG(LS_INFO) << "sendSignalingMessage: " << std::string(data.begin(), data.end()); + + if (_signalingEncryption) { + if (const auto encryptedData = _signalingEncryption->encryptOutgoing(data)) { + _signalingDataEmitted(std::vector(encryptedData->data(), encryptedData->data() + encryptedData->size())); + } else { + RTC_LOG(LS_ERROR) << "sendSignalingMessage: failed to encrypt payload"; + } + } else { + _signalingDataEmitted(data); + } + } + + void beginSignaling() { + _signalingEncryption.reset(new SignalingEncryption(_encryptionKey)); + + if (_encryptionKey.isOutgoing) { + sendInitialSetup(); + } + } + + void createNegotiatedChannels() { + /*const auto coordinatedState = _contentNegotiationContext->coordinatedState(); + if (!coordinatedState) { + return; + } + + if (_outgoingAudioChannelId) { + const auto audioSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingAudioChannelId.value()); + if (audioSsrc) { + if (_outgoingAudioChannel && _outgoingAudioChannel->ssrc() != audioSsrc.value()) { + _outgoingAudioChannel.reset(); + } + + absl::optional outgoingAudioContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Audio && content.ssrc == audioSsrc.value()) { + outgoingAudioContent = content; + break; + } + } + + if (outgoingAudioContent) { + if (!_outgoingAudioChannel) { + _outgoingAudioChannel.reset(new OutgoingAudioChannel( + _call.get(), + _channelManager.get(), + _uniqueRandomIdGenerator.get(), + &_audioSource, + _rtpTransport, + outgoingAudioContent.value(), + _threads + )); + } + } + } + } + + if (_outgoingVideoChannelId) { + const auto videoSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingVideoChannelId.value()); + if (videoSsrc) { + if (_outgoingVideoChannel && _outgoingVideoChannel->ssrc() != videoSsrc.value()) { + _outgoingVideoChannel.reset(); + } + + absl::optional outgoingVideoContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Video && content.ssrc == videoSsrc.value()) { + outgoingVideoContent = content; + break; + } + } + + if (outgoingVideoContent) { + if (!_outgoingVideoChannel) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingVideoChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + outgoingVideoContent.value(), + false + )); + + if (_videoCapture) { + _outgoingVideoChannel->setVideoCapture(_videoCapture); + } + } + } + } + } + + if (_outgoingScreencastChannelId) { + const auto screencastSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingScreencastChannelId.value()); + if (screencastSsrc) { + if (_outgoingScreencastChannel && _outgoingScreencastChannel->ssrc() != screencastSsrc.value()) { + _outgoingScreencastChannel.reset(); + } + + absl::optional outgoingScreencastContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Video && content.ssrc == screencastSsrc.value()) { + outgoingScreencastContent = content; + break; + } + } + + if (outgoingScreencastContent) { + if (!_outgoingScreencastChannel) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingScreencastChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + outgoingScreencastContent.value(), + true + )); + + if (_screencastCapture) { + _outgoingScreencastChannel->setVideoCapture(_screencastCapture); + } + } + } + } + } + + for (const auto &content : coordinatedState->incomingContents) { + switch (content.type) { + case signaling::MediaContent::Type::Audio: { + if (_incomingAudioChannel && _incomingAudioChannel->ssrc() != content.ssrc) { + _incomingAudioChannel.reset(); + } + + if (!_incomingAudioChannel) { + _incomingAudioChannel.reset(new IncomingV2AudioChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + content, + _threads + )); + } + + break; + } + case signaling::MediaContent::Type::Video: { + if (_incomingVideoChannel && _incomingVideoChannel->ssrc() != content.ssrc) { + _incomingVideoChannel.reset(); + } + + if (!_incomingVideoChannel) { + _incomingVideoChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + content, + _threads + )); + _incomingVideoChannel->addSink(_currentSink); + } + + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + } + + adjustBitratePreferences(true); + sendMediaState();*/ + } + + void sendInitialSetup() { + const auto weak = std::weak_ptr(shared_from_this()); + + /*_networking->perform(RTC_FROM_HERE, [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing](NativeNetworkingImpl *networking) { + auto localFingerprint = networking->getLocalFingerprint(); + std::string hash = localFingerprint->algorithm; + std::string fingerprint = localFingerprint->GetRfc4572Fingerprint(); + std::string setup; + if (isOutgoing) { + setup = "actpass"; + } else { + setup = "passive"; + } + + auto localIceParams = networking->getLocalIceParameters(); + std::string ufrag = localIceParams.ufrag; + std::string pwd = localIceParams.pwd; + + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ufrag, pwd, hash, fingerprint, setup, localIceParams]() { + const auto strong = weak.lock(); + if (!strong) { + return; + } + + signaling::InitialSetupMessage data; + + data.ufrag = ufrag; + data.pwd = pwd; + + signaling::DtlsFingerprint dtlsFingerprint; + dtlsFingerprint.hash = hash; + dtlsFingerprint.fingerprint = fingerprint; + dtlsFingerprint.setup = setup; + data.fingerprints.push_back(std::move(dtlsFingerprint)); + + signaling::Message message; + message.data = std::move(data); + strong->sendSignalingMessage(message); + }); + });*/ + } + + void sendOfferIfNeeded() { + /*if (const auto offer = _contentNegotiationContext->getPendingOffer()) { + signaling::NegotiateChannelsMessage data; + + data.exchangeId = offer->exchangeId; + + data.contents = offer->contents; + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + }*/ + } + + void receiveSignalingData(const std::vector &data) { + std::vector decryptedData; + + if (_signalingEncryption) { + const auto rawDecryptedData = _signalingEncryption->decryptIncoming(data); + if (!rawDecryptedData) { + RTC_LOG(LS_ERROR) << "receiveSignalingData: could not decrypt payload"; + + return; + } + + decryptedData = std::vector(rawDecryptedData->data(), rawDecryptedData->data() + rawDecryptedData->size()); + } else { + decryptedData = data; + } + + processSignalingData(decryptedData); + } + + void processSignalingData(const std::vector &data) { + RTC_LOG(LS_INFO) << "processSignalingData: " << std::string(data.begin(), data.end()); + + /*const auto message = signaling::Message::parse(data); + if (!message) { + return; + } + const auto messageData = &message->data; + if (const auto initialSetup = absl::get_if(messageData)) { + PeerIceParameters remoteIceParameters; + remoteIceParameters.ufrag = initialSetup->ufrag; + remoteIceParameters.pwd = initialSetup->pwd; + + std::unique_ptr fingerprint; + std::string sslSetup; + if (initialSetup->fingerprints.size() != 0) { + fingerprint = rtc::SSLFingerprint::CreateUniqueFromRfc4572(initialSetup->fingerprints[0].hash, initialSetup->fingerprints[0].fingerprint); + sslSetup = initialSetup->fingerprints[0].setup; + } + + _networking->perform(RTC_FROM_HERE, [threads = _threads, remoteIceParameters = std::move(remoteIceParameters), fingerprint = std::move(fingerprint), sslSetup = std::move(sslSetup)](NativeNetworkingImpl *networking) { + networking->setRemoteParams(remoteIceParameters, fingerprint.get(), sslSetup); + }); + + if (_encryptionKey.isOutgoing) { + sendOfferIfNeeded(); + } else { + sendInitialSetup(); + } + + _handshakeCompleted = true; + commitPendingIceCandidates(); + } else if (const auto offerAnwer = absl::get_if(messageData)) { + auto negotiationContents = std::make_unique(); + negotiationContents->exchangeId = offerAnwer->exchangeId; + negotiationContents->contents = offerAnwer->contents; + + if (const auto response = _contentNegotiationContext->setRemoteNegotiationContent(std::move(negotiationContents))) { + signaling::NegotiateChannelsMessage data; + + data.exchangeId = response->exchangeId; + data.contents = response->contents; + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + + sendOfferIfNeeded(); + + createNegotiatedChannels(); + } else if (const auto candidatesList = absl::get_if(messageData)) { + for (const auto &candidate : candidatesList->iceCandidates) { + webrtc::JsepIceCandidate parseCandidate{ std::string(), 0 }; + if (!parseCandidate.Initialize(candidate.sdpString, nullptr)) { + RTC_LOG(LS_ERROR) << "Could not parse candidate: " << candidate.sdpString; + continue; + } + _pendingIceCandidates.push_back(parseCandidate.candidate()); + } + + if (_handshakeCompleted) { + commitPendingIceCandidates(); + } + } else if (const auto mediaState = absl::get_if(messageData)) { + AudioState mappedAudioState; + if (mediaState->isMuted) { + mappedAudioState = AudioState::Muted; + } else { + mappedAudioState = AudioState::Active; + } + + VideoState mappedVideoState; + switch (mediaState->videoState) { + case signaling::MediaStateMessage::VideoState::Inactive: { + mappedVideoState = VideoState::Inactive; + break; + } + case signaling::MediaStateMessage::VideoState::Suspended: { + mappedVideoState = VideoState::Paused; + break; + } + case signaling::MediaStateMessage::VideoState::Active: { + mappedVideoState = VideoState::Active; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + + VideoState mappedScreencastState; + switch (mediaState->screencastState) { + case signaling::MediaStateMessage::VideoState::Inactive: { + mappedScreencastState = VideoState::Inactive; + break; + } + case signaling::MediaStateMessage::VideoState::Suspended: { + mappedScreencastState = VideoState::Paused; + break; + } + case signaling::MediaStateMessage::VideoState::Active: { + mappedScreencastState = VideoState::Active; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + + VideoState effectiveVideoState = mappedVideoState; + if (mappedScreencastState == VideoState::Active || mappedScreencastState == VideoState::Paused) { + effectiveVideoState = mappedScreencastState; + } + + if (_remoteMediaStateUpdated) { + _remoteMediaStateUpdated(mappedAudioState, effectiveVideoState); + } + + if (_remoteBatteryLevelIsLowUpdated) { + _remoteBatteryLevelIsLowUpdated(mediaState->isBatteryLow); + } + }*/ + } + + void commitPendingIceCandidates() { + if (_pendingIceCandidates.size() == 0) { + return; + } + /*_networking->perform(RTC_FROM_HERE, [threads = _threads, parsedCandidates = _pendingIceCandidates](NativeNetworkingImpl *networking) { + networking->addCandidates(parsedCandidates); + }); + _pendingIceCandidates.clear();*/ + } + + /*void onNetworkStateUpdated(NativeNetworkingImpl::State const &state) { + State mappedState; + if (state.isReadyToSendData) { + mappedState = State::Established; + } else { + mappedState = State::Reconnecting; + } + _stateUpdated(mappedState); + }*/ + + /*void onDataChannelStateUpdated(bool isDataChannelOpen) { + if (_isDataChannelOpen != isDataChannelOpen) { + _isDataChannelOpen = isDataChannelOpen; + + if (_isDataChannelOpen) { + sendMediaState(); + } + } + } + + void sendDataChannelMessage(signaling::Message const &message) { + if (!_isDataChannelOpen) { + RTC_LOG(LS_ERROR) << "sendDataChannelMessage called, but data channel is not open"; + return; + } + auto data = message.serialize(); + std::string stringData(data.begin(), data.end()); + RTC_LOG(LS_INFO) << "sendDataChannelMessage: " << stringData; + _networking->perform(RTC_FROM_HERE, [stringData = std::move(stringData)](NativeNetworkingImpl *networking) { + networking->sendDataChannelMessage(stringData); + }); + } + + void onDataChannelMessage(std::string const &message) { + RTC_LOG(LS_INFO) << "dataChannelMessage received: " << message; + std::vector data(message.begin(), message.end()); + processSignalingData(data); + }*/ + + void sendMediaState() { + /*if (!_isDataChannelOpen) { + return; + } + signaling::Message message; + signaling::MediaStateMessage data; + data.isMuted = _isMicrophoneMuted; + data.isBatteryLow = _isBatteryLow; + if (_outgoingVideoChannel) { + if (_outgoingVideoChannel->videoCapture()) { + data.videoState = signaling::MediaStateMessage::VideoState::Active; + } else{ + data.videoState = signaling::MediaStateMessage::VideoState::Inactive; + } + data.videoRotation = _outgoingVideoChannel->getRotation(); + } else { + data.videoState = signaling::MediaStateMessage::VideoState::Inactive; + data.videoRotation = signaling::MediaStateMessage::VideoRotation::Rotation0; + } + if (_outgoingScreencastChannel) { + if (_outgoingScreencastChannel->videoCapture()) { + data.screencastState = signaling::MediaStateMessage::VideoState::Active; + } else{ + data.screencastState = signaling::MediaStateMessage::VideoState::Inactive; + } + } else { + data.screencastState = signaling::MediaStateMessage::VideoState::Inactive; + } + message.data = std::move(data); + sendDataChannelMessage(message);*/ + } + + void sendCandidate(const cricket::Candidate &candidate) { + cricket::Candidate patchedCandidate = candidate; + patchedCandidate.set_component(1); + + signaling::CandidatesMessage data; + + signaling::IceCandidate serializedCandidate; + + webrtc::JsepIceCandidate iceCandidate{ std::string(), 0 }; + iceCandidate.SetCandidate(patchedCandidate); + std::string serialized; + const auto success = iceCandidate.ToString(&serialized); + assert(success); + (void)success; + + serializedCandidate.sdpString = serialized; + + data.iceCandidates.push_back(std::move(serializedCandidate)); + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + + void setVideoCapture(std::shared_ptr videoCapture) { + /*auto videoCaptureImpl = GetVideoCaptureAssumingSameThread(videoCapture.get()); + if (videoCaptureImpl) { + if (videoCaptureImpl->isScreenCapture()) { + _videoCapture = nullptr; + _screencastCapture = videoCapture; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(nullptr); + } + if (_outgoingVideoChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingVideoChannelId.value()); + _outgoingVideoChannelId.reset(); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(videoCapture); + } + if (!_outgoingScreencastChannelId) { + _outgoingScreencastChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); + } + } else { + _videoCapture = videoCapture; + _screencastCapture = nullptr; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(videoCapture); + } + if (!_outgoingVideoChannelId) { + _outgoingVideoChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(nullptr); + } + if (_outgoingScreencastChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingScreencastChannelId.value()); + _outgoingScreencastChannelId.reset(); + } + } + } else { + _videoCapture = nullptr; + _screencastCapture = nullptr; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(nullptr); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(nullptr); + } + + if (_outgoingVideoChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingVideoChannelId.value()); + _outgoingVideoChannelId.reset(); + } + + if (_outgoingScreencastChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingScreencastChannelId.value()); + _outgoingScreencastChannelId.reset(); + } + } + + sendOfferIfNeeded(); + sendMediaState(); + adjustBitratePreferences(true); + createNegotiatedChannels();*/ + } + + void setRequestedVideoAspect(float aspect) { + } + + void setNetworkType(NetworkType networkType) { + } + + void setMuteMicrophone(bool muteMicrophone) { + /*if (_isMicrophoneMuted != muteMicrophone) { + _isMicrophoneMuted = muteMicrophone; + + if (_outgoingAudioChannel) { + _outgoingAudioChannel->setIsMuted(muteMicrophone); + } + + sendMediaState(); + }*/ + } + + void setIncomingVideoOutput(std::weak_ptr> sink) { + /*_currentSink = sink; + if (_incomingVideoChannel) { + _incomingVideoChannel->addSink(sink); + } + if (_incomingScreencastChannel) { + _incomingScreencastChannel->addSink(sink); + }*/ + } + + void setAudioInputDevice(std::string id) { + } + + void setAudioOutputDevice(std::string id) { + } + + void setIsLowBatteryLevel(bool isLowBatteryLevel) { + if (_isBatteryLow != isLowBatteryLevel) { + _isBatteryLow = isLowBatteryLevel; + sendMediaState(); + } + } + + void stop(std::function completion) { + completion({}); + } + + /*void adjustBitratePreferences(bool resetStartBitrate) { + if (_outgoingAudioChannel) { + _outgoingAudioChannel->setMaxBitrate(32 * 1024); + } + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setMaxBitrate(1000 * 1024); + } + }*/ + +private: + rtc::scoped_refptr createAudioDeviceModule() { + const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { +#ifdef WEBRTC_IOS + return rtc::make_ref_counted(false, false, 1); +#else + return webrtc::AudioDeviceModule::Create( + layer, + _taskQueueFactory.get()); +#endif + }; + const auto check = [&](const rtc::scoped_refptr &result) { + return (result && result->Init() == 0) ? result : nullptr; + }; + if (_createAudioDeviceModule) { + if (const auto result = check(_createAudioDeviceModule(_taskQueueFactory.get()))) { + return result; + } + } + return check(create(webrtc::AudioDeviceModule::kPlatformDefaultAudio)); + } + +private: + std::shared_ptr _threads; + std::vector _rtcServers; + std::unique_ptr _proxy; + bool _enableP2P = false; + EncryptionKey _encryptionKey; + std::function _stateUpdated; + std::function _signalBarsUpdated; + std::function _audioLevelUpdated; + std::function _remoteBatteryLevelIsLowUpdated; + std::function _remoteMediaStateUpdated; + std::function _remotePrefferedAspectRatioUpdated; + std::function &)> _signalingDataEmitted; + std::function(webrtc::TaskQueueFactory*)> _createAudioDeviceModule; + + std::unique_ptr _signalingEncryption; + + bool _handshakeCompleted = false; + std::vector _pendingIceCandidates; + bool _isDataChannelOpen = false; + + std::unique_ptr _eventLog; + std::unique_ptr _taskQueueFactory; + rtc::scoped_refptr _peerConnection; + webrtc::FieldTrialBasedConfig _fieldTrials; + + webrtc::LocalAudioSinkAdapter _audioSource; + + rtc::scoped_refptr _audioDeviceModule; + + bool _isBatteryLow = false; + + std::weak_ptr> _currentSink; + + std::shared_ptr _videoCapture; + std::shared_ptr _screencastCapture; + std::shared_ptr _platformContext; +}; + +InstanceV2ReferenceImpl::InstanceV2ReferenceImpl(Descriptor &&descriptor) { + if (descriptor.config.logPath.data.size() != 0) { + _logSink = std::make_unique(descriptor.config.logPath); + } + rtc::LogMessage::LogToDebug(rtc::LS_INFO); + rtc::LogMessage::SetLogToStderr(false); + if (_logSink) { + rtc::LogMessage::AddLogToStream(_logSink.get(), rtc::LS_INFO); + } + + _threads = StaticThreads::getThreads(); + _internal.reset(new ThreadLocalObject(_threads->getMediaThread(), [descriptor = std::move(descriptor), threads = _threads]() mutable { + return new InstanceV2ReferenceImplInternal(std::move(descriptor), threads); + })); + _internal->perform(RTC_FROM_HERE, [](InstanceV2ReferenceImplInternal *internal) { + internal->start(); + }); +} + +InstanceV2ReferenceImpl::~InstanceV2ReferenceImpl() { + rtc::LogMessage::RemoveLogToStream(_logSink.get()); +} + +void InstanceV2ReferenceImpl::receiveSignalingData(const std::vector &data) { + _internal->perform(RTC_FROM_HERE, [data](InstanceV2ReferenceImplInternal *internal) { + internal->receiveSignalingData(data); + }); +} + +void InstanceV2ReferenceImpl::setVideoCapture(std::shared_ptr videoCapture) { + _internal->perform(RTC_FROM_HERE, [videoCapture](InstanceV2ReferenceImplInternal *internal) { + internal->setVideoCapture(videoCapture); + }); +} + +void InstanceV2ReferenceImpl::setRequestedVideoAspect(float aspect) { + _internal->perform(RTC_FROM_HERE, [aspect](InstanceV2ReferenceImplInternal *internal) { + internal->setRequestedVideoAspect(aspect); + }); +} + +void InstanceV2ReferenceImpl::setNetworkType(NetworkType networkType) { + _internal->perform(RTC_FROM_HERE, [networkType](InstanceV2ReferenceImplInternal *internal) { + internal->setNetworkType(networkType); + }); +} + +void InstanceV2ReferenceImpl::setMuteMicrophone(bool muteMicrophone) { + _internal->perform(RTC_FROM_HERE, [muteMicrophone](InstanceV2ReferenceImplInternal *internal) { + internal->setMuteMicrophone(muteMicrophone); + }); +} + +void InstanceV2ReferenceImpl::setIncomingVideoOutput(std::shared_ptr> sink) { + _internal->perform(RTC_FROM_HERE, [sink](InstanceV2ReferenceImplInternal *internal) { + internal->setIncomingVideoOutput(sink); + }); +} + +void InstanceV2ReferenceImpl::setAudioInputDevice(std::string id) { + _internal->perform(RTC_FROM_HERE, [id](InstanceV2ReferenceImplInternal *internal) { + internal->setAudioInputDevice(id); + }); +} + +void InstanceV2ReferenceImpl::setAudioOutputDevice(std::string id) { + _internal->perform(RTC_FROM_HERE, [id](InstanceV2ReferenceImplInternal *internal) { + internal->setAudioOutputDevice(id); + }); +} + +void InstanceV2ReferenceImpl::setIsLowBatteryLevel(bool isLowBatteryLevel) { + _internal->perform(RTC_FROM_HERE, [isLowBatteryLevel](InstanceV2ReferenceImplInternal *internal) { + internal->setIsLowBatteryLevel(isLowBatteryLevel); + }); +} + +void InstanceV2ReferenceImpl::setInputVolume(float level) { +} + +void InstanceV2ReferenceImpl::setOutputVolume(float level) { +} + +void InstanceV2ReferenceImpl::setAudioOutputDuckingEnabled(bool enabled) { +} + +void InstanceV2ReferenceImpl::setAudioOutputGainControlEnabled(bool enabled) { +} + +void InstanceV2ReferenceImpl::setEchoCancellationStrength(int strength) { +} + +std::vector InstanceV2ReferenceImpl::GetVersions() { + std::vector result; + result.push_back("4.0.2"); + return result; +} + +int InstanceV2ReferenceImpl::GetConnectionMaxLayer() { + return 92; +} + +std::string InstanceV2ReferenceImpl::getLastError() { + return ""; +} + +std::string InstanceV2ReferenceImpl::getDebugInfo() { + return ""; +} + +int64_t InstanceV2ReferenceImpl::getPreferredRelayId() { + return 0; +} + +TrafficStats InstanceV2ReferenceImpl::getTrafficStats() { + return {}; +} + +PersistentState InstanceV2ReferenceImpl::getPersistentState() { + return {}; +} + +void InstanceV2ReferenceImpl::stop(std::function completion) { + std::string debugLog; + if (_logSink) { + debugLog = _logSink->result(); + } + _internal->perform(RTC_FROM_HERE, [completion, debugLog = std::move(debugLog)](InstanceV2ReferenceImplInternal *internal) mutable { + internal->stop([completion, debugLog = std::move(debugLog)](FinalState finalState) mutable { + finalState.debugLog = debugLog; + completion(finalState); + }); + }); +} + +template <> +bool Register() { + return Meta::RegisterOne(); +} + +} // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.h b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.h new file mode 100644 index 000000000..44b0a9587 --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.h @@ -0,0 +1,59 @@ +#ifndef TGCALLS_INSTANCEV2_REFERENCE_IMPL_H +#define TGCALLS_INSTANCEV2_REFERENCE_IMPL_H + +#include "Instance.h" +#include "StaticThreads.h" + +namespace tgcalls { + +class LogSinkImpl; + +class Manager; +template +class ThreadLocalObject; + +class InstanceV2ReferenceImplInternal; + +class InstanceV2ReferenceImpl final : public Instance { +public: + explicit InstanceV2ReferenceImpl(Descriptor &&descriptor); + ~InstanceV2ReferenceImpl() override; + + void receiveSignalingData(const std::vector &data) override; + void setVideoCapture(std::shared_ptr videoCapture) override; + void setRequestedVideoAspect(float aspect) override; + void setNetworkType(NetworkType networkType) override; + void setMuteMicrophone(bool muteMicrophone) override; + bool supportsVideo() override { + return true; + } + void setIncomingVideoOutput(std::shared_ptr> sink) override; + void setAudioOutputGainControlEnabled(bool enabled) override; + void setEchoCancellationStrength(int strength) override; + void setAudioInputDevice(std::string id) override; + void setAudioOutputDevice(std::string id) override; + void setInputVolume(float level) override; + void setOutputVolume(float level) override; + void setAudioOutputDuckingEnabled(bool enabled) override; + void setIsLowBatteryLevel(bool isLowBatteryLevel) override; + static std::vector GetVersions(); + static int GetConnectionMaxLayer(); + std::string getLastError() override; + std::string getDebugInfo() override; + int64_t getPreferredRelayId() override; + TrafficStats getTrafficStats() override; + PersistentState getPersistentState() override; + void stop(std::function completion) override; + void sendVideoDeviceUpdated() override { + } + +private: + std::shared_ptr _threads; + std::unique_ptr> _internal; + std::unique_ptr _logSink; + +}; + +} // namespace tgcalls + +#endif diff --git a/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.cpp b/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.cpp index f234ae73a..3bf0a3c82 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.cpp +++ b/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.cpp @@ -13,12 +13,185 @@ #include "p2p/base/dtls_transport_factory.h" #include "pc/dtls_srtp_transport.h" #include "pc/dtls_transport.h" +#include "pc/jsep_transport_controller.h" +#include "api/async_dns_resolver.h" + #include "TurnCustomizerImpl.h" #include "SctpDataChannelProviderInterfaceImpl.h" #include "StaticThreads.h" +#include "platform/PlatformInterface.h" namespace tgcalls { +namespace { + +NativeNetworkingImpl::ConnectionDescription::CandidateDescription connectionDescriptionFromCandidate(cricket::Candidate const &candidate) { + NativeNetworkingImpl::ConnectionDescription::CandidateDescription result; + + result.type = candidate.type(); + result.protocol = candidate.protocol(); + result.address = candidate.address().ToString(); + + return result; +} + +class CryptStringImpl : public rtc::CryptStringImpl { +public: + CryptStringImpl(std::string const &value) : + _value(value) { + } + + virtual ~CryptStringImpl() override { + } + + virtual size_t GetLength() const override { + return _value.size(); + } + + virtual void CopyTo(char* dest, bool nullterminate) const override { + memcpy(dest, _value.data(), _value.size()); + if (nullterminate) { + dest[_value.size()] = 0; + } + } + virtual std::string UrlEncode() const override { + return _value; + } + virtual CryptStringImpl* Copy() const override { + return new CryptStringImpl(_value); + } + + virtual void CopyRawTo(std::vector* dest) const override { + dest->resize(_value.size()); + memcpy(dest->data(), _value.data(), _value.size()); + } + +private: + std::string _value; +}; + +class WrappedAsyncPacketSocket : public rtc::AsyncPacketSocket { +public: + WrappedAsyncPacketSocket(std::unique_ptr &&wrappedSocket) : + _wrappedSocket(std::move(wrappedSocket)) { + _wrappedSocket->SignalReadPacket.connect(this, &WrappedAsyncPacketSocket::onReadPacket); + _wrappedSocket->SignalSentPacket.connect(this, &WrappedAsyncPacketSocket::onSentPacket); + _wrappedSocket->SignalReadyToSend.connect(this, &WrappedAsyncPacketSocket::onReadyToSend); + _wrappedSocket->SignalAddressReady.connect(this, &WrappedAsyncPacketSocket::onAddressReady); + _wrappedSocket->SignalConnect.connect(this, &WrappedAsyncPacketSocket::onConnect); + _wrappedSocket->SignalClose.connect(this, &WrappedAsyncPacketSocket::onClose); + } + + virtual ~WrappedAsyncPacketSocket() override { + _wrappedSocket->SignalReadPacket.disconnect(this); + _wrappedSocket->SignalSentPacket.disconnect(this); + _wrappedSocket->SignalReadyToSend.disconnect(this); + _wrappedSocket->SignalAddressReady.disconnect(this); + _wrappedSocket->SignalConnect.disconnect(this); + _wrappedSocket->SignalClose.disconnect(this); + + _wrappedSocket.reset(); + } + + virtual rtc::SocketAddress GetLocalAddress() const override { + return _wrappedSocket->GetLocalAddress(); + } + + virtual rtc::SocketAddress GetRemoteAddress() const override { + return _wrappedSocket->GetRemoteAddress(); + } + + virtual int Send(const void* pv, size_t cb, const rtc::PacketOptions& options) override { + return _wrappedSocket->Send(pv, cb, options); + } + + virtual int SendTo(const void* pv, + size_t cb, + const rtc::SocketAddress& addr, + const rtc::PacketOptions& options) override { + return _wrappedSocket->SendTo(pv, cb, addr, options); + } + + virtual int Close() override { + return _wrappedSocket->Close(); + } + + virtual State GetState() const override { + return _wrappedSocket->GetState(); + } + + virtual int GetOption(rtc::Socket::Option opt, int* value) override { + return _wrappedSocket->GetOption(opt, value); + } + + virtual int SetOption(rtc::Socket::Option opt, int value) override { + return _wrappedSocket->SetOption(opt, value); + } + + virtual int GetError() const override { + return _wrappedSocket->GetError(); + } + + virtual void SetError(int error) override { + _wrappedSocket->SetError(error); + } + +private: + void onReadPacket(AsyncPacketSocket *socket, const char *data, size_t size, const rtc::SocketAddress &address, const int64_t ×tamp) { + SignalReadPacket.emit(this, data, size, address, timestamp); + } + + void onSentPacket(AsyncPacketSocket *socket, const rtc::SentPacket &packet) { + SignalSentPacket.emit(this, packet); + } + + void onReadyToSend(AsyncPacketSocket *socket) { + SignalReadyToSend.emit(this); + } + + void onAddressReady(AsyncPacketSocket *socket, const rtc::SocketAddress &address) { + SignalAddressReady.emit(this, address); + } + + void onConnect(AsyncPacketSocket *socket) { + SignalConnect.emit(this); + } + + void onClose(AsyncPacketSocket *socket, int value) { + SignalClose(this, value); + } + +private: + std::unique_ptr _wrappedSocket; +}; + +class WrappedBasicPacketSocketFactory : public rtc::BasicPacketSocketFactory { +public: + explicit WrappedBasicPacketSocketFactory(rtc::SocketFactory* socket_factory) : + rtc::BasicPacketSocketFactory(socket_factory) { + } + + virtual ~WrappedBasicPacketSocketFactory() override { + } + + rtc::AsyncPacketSocket* CreateUdpSocket(const rtc::SocketAddress& local_address, uint16_t min_port, uint16_t max_port) override { + rtc::AsyncPacketSocket *socket = rtc::BasicPacketSocketFactory::CreateUdpSocket(local_address, min_port, max_port); + if (socket) { + std::unique_ptr socketPtr; + socketPtr.reset(socket); + + return new WrappedAsyncPacketSocket(std::move(socketPtr)); + } else { + return nullptr; + } + } + +private: + +}; + +} + webrtc::CryptoOptions NativeNetworkingImpl::getDefaulCryptoOptions() { auto options = webrtc::CryptoOptions(); options.srtp.enable_aes128_sha1_80_crypto_cipher = true; @@ -33,6 +206,7 @@ _enableStunMarking(configuration.enableStunMarking), _enableTCP(configuration.enableTCP), _enableP2P(configuration.enableP2P), _rtcServers(configuration.rtcServers), +_proxy(configuration.proxy), _stateUpdated(std::move(configuration.stateUpdated)), _candidateGathered(std::move(configuration.candidateGathered)), _transportMessageReceived(std::move(configuration.transportMessageReceived)), @@ -45,9 +219,11 @@ _dataChannelMessageReceived(configuration.dataChannelMessageReceived) { _localCertificate = rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams(rtc::KT_ECDSA), absl::nullopt); + _networkMonitorFactory = PlatformInterface::SharedInstance()->createNetworkMonitorFactory(); _socketFactory.reset(new rtc::BasicPacketSocketFactory(_threads->getNetworkThread()->socketserver())); - _networkManager = std::make_unique(); - _asyncResolverFactory = std::make_unique(); + _networkManager = std::make_unique(_networkMonitorFactory.get(), nullptr); + + _asyncResolverFactory = std::make_unique(std::make_unique()); _dtlsSrtpTransport = std::make_unique(true); _dtlsSrtpTransport->SetDtlsTransports(nullptr, nullptr); @@ -72,6 +248,7 @@ NativeNetworkingImpl::~NativeNetworkingImpl() { _portAllocator.reset(); _networkManager.reset(); _socketFactory.reset(); + _networkMonitorFactory.reset(); } void NativeNetworkingImpl::resetDtlsSrtpTransport() { @@ -88,29 +265,31 @@ void NativeNetworkingImpl::resetDtlsSrtpTransport() { cricket::PORTALLOCATOR_ENABLE_IPV6 | cricket::PORTALLOCATOR_ENABLE_IPV6_ON_WIFI; - if (!_enableTCP) { - flags |= cricket::PORTALLOCATOR_DISABLE_TCP; + /*if (_proxy) { + rtc::ProxyInfo proxyInfo; + proxyInfo.type = rtc::ProxyType::PROXY_SOCKS5; + proxyInfo.address = rtc::SocketAddress(_proxy->host, _proxy->port); + proxyInfo.username = _proxy->login; + proxyInfo.password = rtc::CryptString(CryptStringImpl(_proxy->password)); + _portAllocator->set_proxy("t/1.0", proxyInfo); + + flags &= ~cricket::PORTALLOCATOR_DISABLE_TCP; + } else */{ + if (!_enableTCP) { + flags |= cricket::PORTALLOCATOR_DISABLE_TCP; + } } - if (!_enableP2P) { + + if (_proxy || !_enableP2P) { flags |= cricket::PORTALLOCATOR_DISABLE_UDP; flags |= cricket::PORTALLOCATOR_DISABLE_STUN; uint32_t candidateFilter = _portAllocator->candidate_filter(); candidateFilter &= ~(cricket::CF_REFLEXIVE); _portAllocator->SetCandidateFilter(candidateFilter); } - + _portAllocator->set_step_delay(cricket::kMinimumStepDelay); - //TODO: figure out the proxy setup - /*if (_proxy) { - rtc::ProxyInfo proxyInfo; - proxyInfo.type = rtc::ProxyType::PROXY_SOCKS5; - proxyInfo.address = rtc::SocketAddress(_proxy->host, _proxy->port); - proxyInfo.username = _proxy->login; - proxyInfo.password = rtc::CryptString(TgCallsCryptStringImpl(_proxy->password)); - _portAllocator->set_proxy("t/1.0", proxyInfo); - }*/ - _portAllocator->set_flags(flags); _portAllocator->Initialize(); @@ -133,7 +312,8 @@ void NativeNetworkingImpl::resetDtlsSrtpTransport() { _portAllocator->SetConfiguration(stunServers, turnServers, 2, webrtc::NO_PRUNE, _turnCustomizer.get()); - _transportChannel.reset(new cricket::P2PTransportChannel("transport", 0, _portAllocator.get(), _asyncResolverFactory.get(), nullptr)); + + _transportChannel = cricket::P2PTransportChannel::Create("transport", 0, _portAllocator.get(), _asyncResolverFactory.get()); cricket::IceConfig iceConfig; iceConfig.continual_gathering_policy = cricket::GATHER_CONTINUALLY; @@ -153,7 +333,9 @@ void NativeNetworkingImpl::resetDtlsSrtpTransport() { _transportChannel->SignalCandidateGathered.connect(this, &NativeNetworkingImpl::candidateGathered); _transportChannel->SignalIceTransportStateChanged.connect(this, &NativeNetworkingImpl::transportStateChanged); + _transportChannel->SignalCandidatePairChanged.connect(this, &NativeNetworkingImpl::candidatePairChanged); _transportChannel->SignalReadPacket.connect(this, &NativeNetworkingImpl::transportPacketReceived); + _transportChannel->SignalNetworkRouteChanged.connect(this, &NativeNetworkingImpl::transportRouteChanged); webrtc::CryptoOptions cryptoOptions = NativeNetworkingImpl::getDefaulCryptoOptions(); _dtlsTransport.reset(new cricket::DtlsTransport(_transportChannel.get(), cryptoOptions, nullptr)); @@ -201,12 +383,16 @@ void NativeNetworkingImpl::start() { }, _threads )); + + _lastNetworkActivityMs = rtc::TimeMillis(); + checkConnectionTimeout(); } void NativeNetworkingImpl::stop() { _transportChannel->SignalCandidateGathered.disconnect(this); _transportChannel->SignalIceTransportStateChanged.disconnect(this); _transportChannel->SignalReadPacket.disconnect(this); + _transportChannel->SignalNetworkRouteChanged.disconnect(this); _dtlsTransport->SignalWritableState.disconnect(this); _dtlsTransport->SignalReceivingState.disconnect(this); @@ -289,10 +475,8 @@ void NativeNetworkingImpl::checkConnectionTimeout() { const int64_t maxTimeout = 20000; if (strong->_lastNetworkActivityMs + maxTimeout < currentTimestamp) { - NativeNetworkingImpl::State emitState; - emitState.isReadyToSendData = false; - emitState.isFailed = true; - strong->_stateUpdated(emitState); + strong->_isFailed = true; + strong->notifyStateUpdated(); } strong->checkConnectionTimeout(); @@ -347,6 +531,46 @@ void NativeNetworkingImpl::transportPacketReceived(rtc::PacketTransportInternal assert(_threads->getNetworkThread()->IsCurrent()); _lastNetworkActivityMs = rtc::TimeMillis(); + _isFailed = false; +} + +void NativeNetworkingImpl::transportRouteChanged(absl::optional route) { + assert(_threads->getNetworkThread()->IsCurrent()); + + if (route.has_value()) { + /*cricket::IceTransportStats iceTransportStats; + if (_transportChannel->GetStats(&iceTransportStats)) { + }*/ + + RTC_LOG(LS_INFO) << "NativeNetworkingImpl route changed: " << route->DebugString(); + + bool localIsWifi = route->local.adapter_type() == rtc::AdapterType::ADAPTER_TYPE_WIFI; + bool remoteIsWifi = route->remote.adapter_type() == rtc::AdapterType::ADAPTER_TYPE_WIFI; + + RTC_LOG(LS_INFO) << "NativeNetworkingImpl is wifi: local=" << localIsWifi << ", remote=" << remoteIsWifi; + + std::string localDescription = route->local.uses_turn() ? "turn" : "p2p"; + std::string remoteDescription = route->remote.uses_turn() ? "turn" : "p2p"; + + RouteDescription routeDescription(localDescription, remoteDescription); + + if (!_currentRouteDescription || routeDescription != _currentRouteDescription.value()) { + _currentRouteDescription = std::move(routeDescription); + notifyStateUpdated(); + } + } +} + +void NativeNetworkingImpl::candidatePairChanged(cricket::CandidatePairChangeEvent const &event) { + ConnectionDescription connectionDescription; + + connectionDescription.local = connectionDescriptionFromCandidate(event.selected_candidate_pair.local); + connectionDescription.remote = connectionDescriptionFromCandidate(event.selected_candidate_pair.remote); + + if (!_currentConnectionDescription || _currentConnectionDescription.value() != connectionDescription) { + _currentConnectionDescription = std::move(connectionDescription); + notifyStateUpdated(); + } } void NativeNetworkingImpl::RtpPacketReceived_n(rtc::CopyOnWriteBuffer *packet, int64_t packet_time_us, bool isUnresolved) { @@ -382,9 +606,7 @@ void NativeNetworkingImpl::UpdateAggregateStates_n() { if (_isConnected != isConnected) { _isConnected = isConnected; - NativeNetworkingImpl::State emitState; - emitState.isReadyToSendData = isConnected; - _stateUpdated(emitState); + notifyStateUpdated(); if (_dataChannelInterface) { _dataChannelInterface->updateIsConnected(isConnected); @@ -392,6 +614,15 @@ void NativeNetworkingImpl::UpdateAggregateStates_n() { } } +void NativeNetworkingImpl::notifyStateUpdated() { + NativeNetworkingImpl::State emitState; + emitState.isReadyToSendData = _isConnected; + emitState.route = _currentRouteDescription; + emitState.connection = _currentConnectionDescription; + emitState.isFailed = _isFailed; + _stateUpdated(emitState); +} + void NativeNetworkingImpl::sctpReadyToSendData() { } diff --git a/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.h b/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.h index 9383c6beb..45af35e18 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.h +++ b/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.h @@ -10,9 +10,9 @@ #include "rtc_base/third_party/sigslot/sigslot.h" #include "api/candidate.h" #include "media/base/media_channel.h" -//#include "media/sctp/sctp_transport.h" #include "rtc_base/ssl_fingerprint.h" #include "pc/sctp_data_channel.h" +#include "p2p/base/port.h" #include #include @@ -36,10 +36,10 @@ class DtlsTransport; } // namespace cricket namespace webrtc { -class BasicAsyncResolverFactory; class TurnCustomizer; class DtlsSrtpTransport; class RtpTransport; +class AsyncDnsResolverFactoryInterface; } // namespace webrtc namespace tgcalls { @@ -50,9 +50,80 @@ class Threads; class NativeNetworkingImpl : public sigslot::has_slots<>, public std::enable_shared_from_this { public: + struct RouteDescription { + explicit RouteDescription(std::string const &localDescription_, std::string const &remoteDescription_) : + localDescription(localDescription_), + remoteDescription(remoteDescription_) { + } + + std::string localDescription; + std::string remoteDescription; + + bool operator==(RouteDescription const &rhs) const { + if (localDescription != rhs.localDescription) { + return false; + } + if (remoteDescription != rhs.remoteDescription) { + return false; + } + + return true; + } + + bool operator!=(const RouteDescription& rhs) const { + return !(*this == rhs); + } + }; + + struct ConnectionDescription { + struct CandidateDescription { + std::string protocol; + std::string type; + std::string address; + + bool operator==(CandidateDescription const &rhs) const { + if (protocol != rhs.protocol) { + return false; + } + if (type != rhs.type) { + return false; + } + if (address != rhs.address) { + return false; + } + + return true; + } + + bool operator!=(const CandidateDescription& rhs) const { + return !(*this == rhs); + } + }; + + CandidateDescription local; + CandidateDescription remote; + + bool operator==(ConnectionDescription const &rhs) const { + if (local != rhs.local) { + return false; + } + if (remote != rhs.remote) { + return false; + } + + return true; + } + + bool operator!=(const ConnectionDescription& rhs) const { + return !(*this == rhs); + } + }; + struct State { bool isReadyToSendData = false; bool isFailed = false; + absl::optional route; + absl::optional connection; }; struct Configuration { @@ -61,6 +132,7 @@ public: bool enableTCP = false; bool enableP2P = false; std::vector rtcServers; + absl::optional proxy; std::function stateUpdated; std::function candidateGathered; std::function transportMessageReceived; @@ -97,6 +169,8 @@ private: void transportStateChanged(cricket::IceTransportInternal *transport); void transportReadyToSend(cricket::IceTransportInternal *transport); void transportPacketReceived(rtc::PacketTransportInternal *transport, const char *bytes, size_t size, const int64_t ×tamp, int unused); + void transportRouteChanged(absl::optional route); + void candidatePairChanged(cricket::CandidatePairChangeEvent const &event); void DtlsReadyToSend(bool DtlsReadyToSend); void UpdateAggregateStates_n(); void RtpPacketReceived_n(rtc::CopyOnWriteBuffer *packet, int64_t packet_time_us, bool isUnresolved); @@ -104,6 +178,8 @@ private: void sctpReadyToSendData(); void sctpDataReceived(const cricket::ReceiveDataParams& params, const rtc::CopyOnWriteBuffer& buffer); + + void notifyStateUpdated(); std::shared_ptr _threads; bool _isOutgoing = false; @@ -111,6 +187,7 @@ private: bool _enableTCP = false; bool _enableP2P = false; std::vector _rtcServers; + absl::optional _proxy; std::function _stateUpdated; std::function _candidateGathered; @@ -119,11 +196,12 @@ private: std::function _dataChannelStateUpdated; std::function _dataChannelMessageReceived; + std::unique_ptr _networkMonitorFactory; std::unique_ptr _socketFactory; std::unique_ptr _networkManager; std::unique_ptr _turnCustomizer; std::unique_ptr _portAllocator; - std::unique_ptr _asyncResolverFactory; + std::unique_ptr _asyncResolverFactory; std::unique_ptr _transportChannel; std::unique_ptr _dtlsTransport; std::unique_ptr _dtlsSrtpTransport; @@ -135,7 +213,10 @@ private: absl::optional _remoteIceParameters; bool _isConnected = false; + bool _isFailed = false; int64_t _lastNetworkActivityMs = 0; + absl::optional _currentRouteDescription; + absl::optional _currentConnectionDescription; }; } // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2/Signaling.cpp b/TMessagesProj/jni/voip/tgcalls/v2/Signaling.cpp index a98c3f8be..1a981dbca 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/Signaling.cpp +++ b/TMessagesProj/jni/voip/tgcalls/v2/Signaling.cpp @@ -3,6 +3,7 @@ #include "third-party/json11.hpp" #include "rtc_base/checks.h" +#include "rtc_base/logging.h" #include @@ -40,18 +41,21 @@ absl::optional SsrcGroup_parse(json11::Json::object const &object) { const auto semantics = object.find("semantics"); if (semantics == object.end() || !semantics->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: semantics must be a string"; return absl::nullopt; } result.semantics = semantics->second.string_value(); const auto ssrcs = object.find("ssrcs"); if (ssrcs == object.end() || !ssrcs->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: ssrcs must be an array"; return absl::nullopt; } for (const auto &ssrc : ssrcs->second.array_items()) { if (ssrc.is_string()) { uint32_t parsedSsrc = stringToUInt32(ssrc.string_value()); if (parsedSsrc == 0) { + RTC_LOG(LS_ERROR) << "Signaling: parsedSsrc must not be 0"; return absl::nullopt; } result.ssrcs.push_back(parsedSsrc); @@ -59,6 +63,7 @@ absl::optional SsrcGroup_parse(json11::Json::object const &object) { uint32_t parsedSsrc = (uint32_t)ssrc.number_value(); result.ssrcs.push_back(parsedSsrc); } else { + RTC_LOG(LS_ERROR) << "Signaling: ssrcs item must be a string or a number"; return absl::nullopt; } } @@ -80,12 +85,14 @@ absl::optional FeedbackType_parse(json11::Json::object const &obje const auto type = object.find("type"); if (type == object.end() || !type->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: type must be a string"; return absl::nullopt; } result.type = type->second.string_value(); const auto subtype = object.find("subtype"); if (subtype == object.end() || !subtype->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: subtype must be a string"; return absl::nullopt; } result.subtype = subtype->second.string_value(); @@ -105,11 +112,13 @@ json11::Json::object RtpExtension_serialize(webrtc::RtpExtension const &rtpExten absl::optional RtpExtension_parse(json11::Json::object const &object) { const auto id = object.find("id"); if (id == object.end() || !id->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: id must be a number"; return absl::nullopt; } const auto uri = object.find("uri"); if (uri == object.end() || !uri->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: uri must be a string"; return absl::nullopt; } @@ -144,18 +153,21 @@ absl::optional PayloadType_parse(json11::Json::object const &object const auto id = object.find("id"); if (id == object.end() || !id->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: id must be a number"; return absl::nullopt; } result.id = id->second.int_value(); const auto name = object.find("name"); if (name == object.end() || !name->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: name must be a string"; return absl::nullopt; } result.name = name->second.string_value(); const auto clockrate = object.find("clockrate"); if (clockrate == object.end() || !clockrate->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: clockrate must be a number"; return absl::nullopt; } result.clockrate = clockrate->second.int_value(); @@ -163,6 +175,7 @@ absl::optional PayloadType_parse(json11::Json::object const &object const auto channels = object.find("channels"); if (channels != object.end()) { if (!channels->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: channels must be a number"; return absl::nullopt; } result.channels = channels->second.int_value(); @@ -171,15 +184,18 @@ absl::optional PayloadType_parse(json11::Json::object const &object const auto feedbackTypes = object.find("feedbackTypes"); if (feedbackTypes != object.end()) { if (!feedbackTypes->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: feedbackTypes must be an array"; return absl::nullopt; } for (const auto &feedbackType : feedbackTypes->second.array_items()) { if (!feedbackType.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: feedbackTypes items must be objects"; return absl::nullopt; } if (const auto parsedFeedbackType = FeedbackType_parse(feedbackType.object_items())) { result.feedbackTypes.push_back(parsedFeedbackType.value()); } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse FeedbackType"; return absl::nullopt; } } @@ -188,10 +204,12 @@ absl::optional PayloadType_parse(json11::Json::object const &object const auto parameters = object.find("parameters"); if (parameters != object.end()) { if (!parameters->second.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: parameters must be an object"; return absl::nullopt; } for (const auto &item : parameters->second.object_items()) { if (!item.second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: parameters items must be strings"; return absl::nullopt; } result.parameters.push_back(std::make_pair(item.first, item.second.string_value())); @@ -203,6 +221,23 @@ absl::optional PayloadType_parse(json11::Json::object const &object json11::Json::object MediaContent_serialize(MediaContent const &mediaContent) { json11::Json::object object; + + std::string mappedType; + switch (mediaContent.type) { + case MediaContent::Type::Audio: { + mappedType = "audio"; + break; + } + case MediaContent::Type::Video: { + mappedType = "video"; + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + object.insert(std::make_pair("type", mappedType)); object.insert(std::make_pair("ssrc", json11::Json(uint32ToString(mediaContent.ssrc)))); @@ -233,9 +268,24 @@ json11::Json::object MediaContent_serialize(MediaContent const &mediaContent) { absl::optional MediaContent_parse(json11::Json::object const &object) { MediaContent result; + + const auto type = object.find("type"); + if (type == object.end() || !type->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: type must be a string"; + return absl::nullopt; + } + if (type->second.string_value() == "audio") { + result.type = MediaContent::Type::Audio; + } else if (type->second.string_value() == "video") { + result.type = MediaContent::Type::Video; + } else { + RTC_LOG(LS_ERROR) << "Signaling: type must be one of [\"audio\", \"video\"]"; + return absl::nullopt; + } const auto ssrc = object.find("ssrc"); if (ssrc == object.end()) { + RTC_LOG(LS_ERROR) << "Signaling: ssrc must be present"; return absl::nullopt; } if (ssrc->second.is_string()) { @@ -243,21 +293,25 @@ absl::optional MediaContent_parse(json11::Json::object const &obje } else if (ssrc->second.is_number()) { result.ssrc = (uint32_t)ssrc->second.number_value(); } else { + RTC_LOG(LS_ERROR) << "Signaling: ssrc must be a string or a number"; return absl::nullopt; } const auto ssrcGroups = object.find("ssrcGroups"); if (ssrcGroups != object.end()) { if (!ssrcGroups->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: ssrcGroups must be an array"; return absl::nullopt; } for (const auto &ssrcGroup : ssrcGroups->second.array_items()) { if (!ssrcGroup.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: ssrcsGroups items must be objects"; return absl::nullopt; } if (const auto parsedSsrcGroup = SsrcGroup_parse(ssrcGroup.object_items())) { result.ssrcGroups.push_back(parsedSsrcGroup.value()); } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse SsrcGroup"; return absl::nullopt; } } @@ -266,15 +320,18 @@ absl::optional MediaContent_parse(json11::Json::object const &obje const auto payloadTypes = object.find("payloadTypes"); if (payloadTypes != object.end()) { if (!payloadTypes->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: payloadTypes must be an array"; return absl::nullopt; } for (const auto &payloadType : payloadTypes->second.array_items()) { if (!payloadType.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: payloadTypes items must be objects"; return absl::nullopt; } if (const auto parsedPayloadType = PayloadType_parse(payloadType.object_items())) { result.payloadTypes.push_back(parsedPayloadType.value()); } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse PayloadType"; return absl::nullopt; } } @@ -283,15 +340,18 @@ absl::optional MediaContent_parse(json11::Json::object const &obje const auto rtpExtensions = object.find("rtpExtensions"); if (rtpExtensions != object.end()) { if (!rtpExtensions->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: rtpExtensions must be an array"; return absl::nullopt; } for (const auto &rtpExtension : rtpExtensions->second.array_items()) { if (!rtpExtension.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: rtpExtensions items must be objects"; return absl::nullopt; } if (const auto parsedRtpExtension = RtpExtension_parse(rtpExtension.object_items())) { result.rtpExtensions.push_back(parsedRtpExtension.value()); } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse RtpExtension"; return absl::nullopt; } } @@ -317,18 +377,6 @@ std::vector InitialSetupMessage_serialize(const InitialSetupMessage * c } object.insert(std::make_pair("fingerprints", json11::Json(std::move(jsonFingerprints)))); - if (const auto audio = message->audio) { - object.insert(std::make_pair("audio", json11::Json(MediaContent_serialize(audio.value())))); - } - - if (const auto video = message->video) { - object.insert(std::make_pair("video", json11::Json(MediaContent_serialize(video.value())))); - } - - if (const auto screencast = message->screencast) { - object.insert(std::make_pair("screencast", json11::Json(MediaContent_serialize(screencast.value())))); - } - auto json = json11::Json(std::move(object)); std::string result = json.dump(); return std::vector(result.begin(), result.end()); @@ -337,31 +385,38 @@ std::vector InitialSetupMessage_serialize(const InitialSetupMessage * c absl::optional InitialSetupMessage_parse(json11::Json::object const &object) { const auto ufrag = object.find("ufrag"); if (ufrag == object.end() || !ufrag->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: ufrag must be a string"; return absl::nullopt; } const auto pwd = object.find("pwd"); if (pwd == object.end() || !pwd->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: pwd must be a string"; return absl::nullopt; } const auto fingerprints = object.find("fingerprints"); if (fingerprints == object.end() || !fingerprints->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: fingerprints must be an array"; return absl::nullopt; } std::vector parsedFingerprints; for (const auto &fingerprintObject : fingerprints->second.array_items()) { if (!fingerprintObject.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: fingerprints items must be objects"; return absl::nullopt; } const auto hash = fingerprintObject.object_items().find("hash"); if (hash == fingerprintObject.object_items().end() || !hash->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: hash must be a string"; return absl::nullopt; } const auto setup = fingerprintObject.object_items().find("setup"); if (setup == fingerprintObject.object_items().end() || !setup->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: setup must be a string"; return absl::nullopt; } const auto fingerprint = fingerprintObject.object_items().find("fingerprint"); if (fingerprint == fingerprintObject.object_items().end() || !fingerprint->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: fingerprint must be a string"; return absl::nullopt; } @@ -378,39 +433,61 @@ absl::optional InitialSetupMessage_parse(json11::Json::obje message.pwd = pwd->second.string_value(); message.fingerprints = std::move(parsedFingerprints); - const auto audio = object.find("audio"); - if (audio != object.end()) { - if (!audio->second.is_object()) { - return absl::nullopt; - } - if (const auto parsedAudio = MediaContent_parse(audio->second.object_items())) { - message.audio = parsedAudio.value(); - } else { - return absl::nullopt; - } + return message; +} + +std::vector NegotiateChannelsMessage_serialize(const NegotiateChannelsMessage * const message) { + json11::Json::object object; + + object.insert(std::make_pair("@type", json11::Json("NegotiateChannels"))); + + object.insert(std::make_pair("exchangeId", json11::Json(uint32ToString(message->exchangeId)))); + + json11::Json::array contents; + for (const auto &content : message->contents) { + contents.push_back(json11::Json(MediaContent_serialize(content))); + } + object.insert(std::make_pair("contents", std::move(contents))); + + auto json = json11::Json(std::move(object)); + std::string result = json.dump(); + return std::vector(result.begin(), result.end()); +} + +absl::optional NegotiateChannelsMessage_parse(json11::Json::object const &object) { + NegotiateChannelsMessage message; + + const auto exchangeId = object.find("exchangeId"); + + if (exchangeId == object.end()) { + RTC_LOG(LS_ERROR) << "Signaling: exchangeId must be present"; + return absl::nullopt; + } else if (exchangeId->second.is_string()) { + message.exchangeId = stringToUInt32(exchangeId->second.string_value()); + } else if (exchangeId->second.is_number()) { + message.exchangeId = (uint32_t)exchangeId->second.number_value(); + } else { + RTC_LOG(LS_ERROR) << "Signaling: exchangeId must be a string or a number"; + return absl::nullopt; } - const auto video = object.find("video"); - if (video != object.end()) { - if (!video->second.is_object()) { + const auto contents = object.find("contents"); + if (contents != object.end()) { + if (!contents->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: contents must be an array"; return absl::nullopt; } - if (const auto parsedVideo = MediaContent_parse(video->second.object_items())) { - message.video = parsedVideo.value(); - } else { - return absl::nullopt; - } - } - - const auto screencast = object.find("screencast"); - if (screencast != object.end()) { - if (!screencast->second.is_object()) { - return absl::nullopt; - } - if (const auto parsedScreencast = MediaContent_parse(screencast->second.object_items())) { - message.screencast = parsedScreencast.value(); - } else { - return absl::nullopt; + for (const auto &content : contents->second.array_items()) { + if (!content.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: contents items must be objects"; + return absl::nullopt; + } + if (auto parsedContent = MediaContent_parse(content.object_items())) { + message.contents.push_back(std::move(parsedContent.value())); + } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse MediaContent"; + return absl::nullopt; + } } } @@ -429,11 +506,13 @@ json11::Json::object ConnectionAddress_serialize(ConnectionAddress const &connec absl::optional ConnectionAddress_parse(json11::Json::object const &object) { const auto ip = object.find("ip"); if (ip == object.end() || !ip->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: ip must be a string"; return absl::nullopt; } const auto port = object.find("port"); if (port == object.end() || !port->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: port must be a number"; return absl::nullopt; } @@ -466,12 +545,14 @@ std::vector CandidatesMessage_serialize(const CandidatesMessage * const absl::optional CandidatesMessage_parse(json11::Json::object const &object) { const auto candidates = object.find("candidates"); if (candidates == object.end() || !candidates->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: candidates must be an array"; return absl::nullopt; } std::vector parsedCandidates; for (const auto &candidateObject : candidates->second.array_items()) { if (!candidateObject.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: candidates items must be objects"; return absl::nullopt; } @@ -479,6 +560,7 @@ absl::optional CandidatesMessage_parse(json11::Json::object c const auto sdpString = candidateObject.object_items().find("sdpString"); if (sdpString == candidateObject.object_items().end() || !sdpString->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: sdpString must be a string"; return absl::nullopt; } candidate.sdpString = sdpString->second.string_value(); @@ -577,6 +659,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto muted = object.find("muted"); if (muted != object.end()) { if (!muted->second.is_bool()) { + RTC_LOG(LS_ERROR) << "Signaling: muted must be a bool"; return absl::nullopt; } message.isMuted = muted->second.bool_value(); @@ -585,6 +668,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto lowBattery = object.find("lowBattery"); if (lowBattery != object.end()) { if (!lowBattery->second.is_bool()) { + RTC_LOG(LS_ERROR) << "Signaling: lowBattery must be a bool"; return absl::nullopt; } message.isBatteryLow = lowBattery->second.bool_value(); @@ -593,6 +677,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto videoState = object.find("videoState"); if (videoState != object.end()) { if (!videoState->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: videoState must be a string"; return absl::nullopt; } if (videoState->second.string_value() == "inactive") { @@ -601,6 +686,8 @@ absl::optional MediaStateMessage_parse(json11::Json::object c message.videoState = MediaStateMessage::VideoState::Suspended; } else if (videoState->second.string_value() == "active") { message.videoState = MediaStateMessage::VideoState::Active; + } else { + RTC_LOG(LS_ERROR) << "videoState must be one of [\"inactive\", \"suspended\", \"active\"]"; } } else { message.videoState = MediaStateMessage::VideoState::Inactive; @@ -609,6 +696,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto screencastState = object.find("screencastState"); if (screencastState != object.end()) { if (!screencastState->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: screencastState must be a string"; return absl::nullopt; } if (screencastState->second.string_value() == "inactive") { @@ -617,6 +705,8 @@ absl::optional MediaStateMessage_parse(json11::Json::object c message.screencastState = MediaStateMessage::VideoState::Suspended; } else if (screencastState->second.string_value() == "active") { message.screencastState = MediaStateMessage::VideoState::Active; + } else { + RTC_LOG(LS_ERROR) << "Signaling: screencastState must be one of [\"inactive\", \"suspended\", \"active\"]"; } } else { message.screencastState = MediaStateMessage::VideoState::Inactive; @@ -625,6 +715,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto videoRotation = object.find("videoRotation"); if (videoRotation != object.end()) { if (!videoRotation->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: videoRotation must be a number"; return absl::nullopt; } if (videoState->second.int_value() == 0) { @@ -636,6 +727,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c } else if (videoState->second.int_value() == 270) { message.videoRotation = MediaStateMessage::VideoRotation::Rotation270; } else { + RTC_LOG(LS_ERROR) << "Signaling: videoRotation must be one of [0, 90, 180, 270]"; message.videoRotation = MediaStateMessage::VideoRotation::Rotation0; } } else { @@ -652,6 +744,8 @@ std::vector Message::serialize() const { return CandidatesMessage_serialize(candidates); } else if (const auto mediaState = absl::get_if(&data)) { return MediaStateMessage_serialize(mediaState); + } else if (const auto negotiateChannels = absl::get_if(&data)) { + return NegotiateChannelsMessage_serialize(negotiateChannels); } else { return {}; } @@ -661,19 +755,32 @@ absl::optional Message::parse(const std::vector &data) { std::string parsingError; auto json = json11::Json::parse(std::string(data.begin(), data.end()), parsingError); if (json.type() != json11::Json::OBJECT) { + RTC_LOG(LS_ERROR) << "Signaling: message must be an object"; return absl::nullopt; } auto type = json.object_items().find("@type"); if (type == json.object_items().end()) { + RTC_LOG(LS_ERROR) << "Signaling: message does not contain @type attribute"; return absl::nullopt; } if (!type->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: @type attribute must be a string"; return absl::nullopt; } if (type->second.string_value() == "InitialSetup") { auto parsed = InitialSetupMessage_parse(json.object_items()); if (!parsed) { + RTC_LOG(LS_ERROR) << "Signaling: could not parse " << type->second.string_value() << " message"; + return absl::nullopt; + } + Message message; + message.data = std::move(parsed.value()); + return message; + } else if (type->second.string_value() == "NegotiateChannels") { + auto parsed = NegotiateChannelsMessage_parse(json.object_items()); + if (!parsed) { + RTC_LOG(LS_ERROR) << "Signaling: could not parse " << type->second.string_value() << " message"; return absl::nullopt; } Message message; @@ -682,6 +789,7 @@ absl::optional Message::parse(const std::vector &data) { } else if (type->second.string_value() == "Candidates") { auto parsed = CandidatesMessage_parse(json.object_items()); if (!parsed) { + RTC_LOG(LS_ERROR) << "Signaling: could not parse " << type->second.string_value() << " message"; return absl::nullopt; } Message message; @@ -690,12 +798,14 @@ absl::optional Message::parse(const std::vector &data) { } else if (type->second.string_value() == "MediaState") { auto parsed = MediaStateMessage_parse(json.object_items()); if (!parsed) { + RTC_LOG(LS_ERROR) << "Signaling: could not parse " << type->second.string_value() << " message"; return absl::nullopt; } Message message; message.data = std::move(parsed.value()); return message; } else { + RTC_LOG(LS_ERROR) << "Signaling: unknown message type " << type->second.string_value(); return absl::nullopt; } } diff --git a/TMessagesProj/jni/voip/tgcalls/v2/Signaling.h b/TMessagesProj/jni/voip/tgcalls/v2/Signaling.h index af957318f..686c25972 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/Signaling.h +++ b/TMessagesProj/jni/voip/tgcalls/v2/Signaling.h @@ -30,11 +30,34 @@ struct IceCandidate { struct SsrcGroup { std::vector ssrcs; std::string semantics; + + bool operator==(SsrcGroup const &rhs) const { + if (ssrcs != rhs.ssrcs) { + return false; + } + + if (semantics != rhs.semantics) { + return false; + } + + return true; + } }; struct FeedbackType { std::string type; std::string subtype; + + bool operator==(FeedbackType const &rhs) const { + if (type != rhs.type) { + return false; + } + if (subtype != rhs.subtype) { + return false; + } + + return true; + } }; struct PayloadType { @@ -44,22 +67,83 @@ struct PayloadType { uint32_t channels = 0; std::vector feedbackTypes; std::vector> parameters; + + bool operator==(PayloadType const &rhs) const { + if (id != rhs.id) { + return false; + } + if (name != rhs.name) { + return false; + } + if (clockrate != rhs.clockrate) { + return false; + } + if (channels != rhs.channels) { + return false; + } + if (feedbackTypes != rhs.feedbackTypes) { + return false; + } + if (parameters != rhs.parameters) { + return false; + } + + return true; + } }; struct MediaContent { + enum class Type { + Audio, + Video + }; + + Type type = Type::Audio; uint32_t ssrc = 0; std::vector ssrcGroups; std::vector payloadTypes; std::vector rtpExtensions; + + bool operator==(const MediaContent& rhs) const { + if (type != rhs.type) { + return false; + } + if (ssrc != rhs.ssrc) { + return false; + } + if (ssrcGroups != rhs.ssrcGroups) { + return false; + } + + std::vector sortedPayloadTypes = payloadTypes; + std::sort(sortedPayloadTypes.begin(), sortedPayloadTypes.end(), [](PayloadType const &lhs, PayloadType const &rhs) { + return lhs.id < rhs.id; + }); + std::vector sortedRhsPayloadTypes = rhs.payloadTypes; + std::sort(sortedRhsPayloadTypes.begin(), sortedRhsPayloadTypes.end(), [](PayloadType const &lhs, PayloadType const &rhs) { + return lhs.id < rhs.id; + }); + if (sortedPayloadTypes != sortedRhsPayloadTypes) { + return false; + } + + if (rtpExtensions != rhs.rtpExtensions) { + return false; + } + + return true; + } }; struct InitialSetupMessage { std::string ufrag; std::string pwd; std::vector fingerprints; - absl::optional audio; - absl::optional video; - absl::optional screencast; +}; + +struct NegotiateChannelsMessage { + uint32_t exchangeId = 0; + std::vector contents; }; struct CandidatesMessage { @@ -91,6 +175,7 @@ struct MediaStateMessage { struct Message { absl::variant< InitialSetupMessage, + NegotiateChannelsMessage, CandidatesMessage, MediaStateMessage> data; diff --git a/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp new file mode 100644 index 000000000..8a822c723 --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp @@ -0,0 +1,2242 @@ +#include "v2_4_0_0/InstanceV2_4_0_0Impl.h" + +#include "LogSinkImpl.h" +#include "VideoCaptureInterfaceImpl.h" +#include "VideoCapturerInterface.h" +#include "v2/NativeNetworkingImpl.h" +#include "v2_4_0_0/Signaling_4_0_0.h" + +#include "CodecSelectHelper.h" +#include "platform/PlatformInterface.h" + +#include "api/audio_codecs/audio_decoder_factory_template.h" +#include "api/audio_codecs/audio_encoder_factory_template.h" +#include "api/audio_codecs/opus/audio_decoder_opus.h" +#include "api/audio_codecs/opus/audio_decoder_multi_channel_opus.h" +#include "api/audio_codecs/opus/audio_encoder_opus.h" +#include "api/audio_codecs/L16/audio_decoder_L16.h" +#include "api/audio_codecs/L16/audio_encoder_L16.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "media/engine/webrtc_media_engine.h" +#include "system_wrappers/include/field_trial.h" +#include "api/video/builtin_video_bitrate_allocator_factory.h" +#include "call/call.h" +#include "api/call/audio_sink.h" +#include "modules/audio_processing/audio_buffer.h" +#include "absl/strings/match.h" +#include "pc/channel_manager.h" +#include "audio/audio_state.h" +#include "modules/audio_coding/neteq/default_neteq_factory.h" +#include "modules/audio_coding/include/audio_coding_module.h" +#include "api/candidate.h" +#include "api/jsep_ice_candidate.h" +#include "pc/used_ids.h" +#include "media/base/sdp_video_format_utils.h" + +#include "AudioFrame.h" +#include "ThreadLocalObject.h" +#include "Manager.h" +#include "NetworkManager.h" +#include "VideoCaptureInterfaceImpl.h" +#include "platform/PlatformInterface.h" +#include "LogSinkImpl.h" +#include "CodecSelectHelper.h" +#include "AudioDeviceHelper.h" +#include "v2/SignalingEncryption.h" +#ifdef WEBRTC_IOS +#include "platform/darwin/iOS/tgcalls_audio_device_module_ios.h" +#endif +#include +#include + +namespace tgcalls { +namespace { + +static std::string intToString(int value) { + std::ostringstream stringStream; + stringStream << value; + return stringStream.str(); +} + +static VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(VideoCaptureInterface *videoCapture) { + return videoCapture + ? static_cast(videoCapture)->object()->getSyncAssumingSameThread() + : nullptr; +} + +struct OutgoingVideoFormat { + cricket::VideoCodec videoCodec; + absl::optional rtxCodec; +}; + +static void addDefaultFeedbackParams(cricket::VideoCodec *codec) { + // Don't add any feedback params for RED and ULPFEC. + if (codec->name == cricket::kRedCodecName || codec->name == cricket::kUlpfecCodecName) { + return; + } + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)); + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamTransportCc, cricket::kParamValueEmpty)); + // Don't add any more feedback params for FLEXFEC. + if (codec->name == cricket::kFlexfecCodecName) { + return; + } + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)); + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)); + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)); +} + +template +static bool IsRtxCodec(const C& codec) { + return absl::EqualsIgnoreCase(codec.name, cricket::kRtxCodecName); +} + +template +static bool ReferencedCodecsMatch(const std::vector& codecs1, + const int codec1_id, + const std::vector& codecs2, + const int codec2_id) { + const C* codec1 = FindCodecById(codecs1, codec1_id); + const C* codec2 = FindCodecById(codecs2, codec2_id); + return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2); +} + +// Finds a codec in |codecs2| that matches |codec_to_match|, which is +// a member of |codecs1|. If |codec_to_match| is an RTX codec, both +// the codecs themselves and their associated codecs must match. +template +static bool FindMatchingCodec(const std::vector& codecs1, + const std::vector& codecs2, + const C& codec_to_match, + C* found_codec) { + // |codec_to_match| should be a member of |codecs1|, in order to look up RTX + // codecs' associated codecs correctly. If not, that's a programming error. + RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) { + return &codec == &codec_to_match; + })); + for (const C& potential_match : codecs2) { + if (potential_match.Matches(codec_to_match)) { + if (IsRtxCodec(codec_to_match)) { + int apt_value_1 = 0; + int apt_value_2 = 0; + if (!codec_to_match.GetParam(cricket::kCodecParamAssociatedPayloadType, + &apt_value_1) || + !potential_match.GetParam(cricket::kCodecParamAssociatedPayloadType, + &apt_value_2)) { + RTC_LOG(LS_WARNING) << "RTX missing associated payload type."; + continue; + } + if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2, + apt_value_2)) { + continue; + } + } + if (found_codec) { + *found_codec = potential_match; + } + return true; + } + } + return false; +} + +template +static void NegotiatePacketization(const C& local_codec, + const C& remote_codec, + C* negotiated_codec) {} + +template <> +void NegotiatePacketization(const cricket::VideoCodec& local_codec, + const cricket::VideoCodec& remote_codec, + cricket::VideoCodec* negotiated_codec) { + negotiated_codec->packetization = + cricket::VideoCodec::IntersectPacketization(local_codec, remote_codec); +} + +template +static void NegotiateCodecs(const std::vector& local_codecs, + const std::vector& offered_codecs, + std::vector* negotiated_codecs, + bool keep_offer_order) { + for (const C& ours : local_codecs) { + C theirs; + // Note that we intentionally only find one matching codec for each of our + // local codecs, in case the remote offer contains duplicate codecs. + if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) { + C negotiated = ours; + NegotiatePacketization(ours, theirs, &negotiated); + negotiated.IntersectFeedbackParams(theirs); + if (IsRtxCodec(negotiated)) { + const auto apt_it = + theirs.params.find(cricket::kCodecParamAssociatedPayloadType); + // FindMatchingCodec shouldn't return something with no apt value. + RTC_DCHECK(apt_it != theirs.params.end()); + negotiated.SetParam(cricket::kCodecParamAssociatedPayloadType, apt_it->second); + } + if (absl::EqualsIgnoreCase(ours.name, cricket::kH264CodecName)) { + webrtc::H264GenerateProfileLevelIdForAnswer( + ours.params, theirs.params, &negotiated.params); + } + negotiated.id = theirs.id; + negotiated.name = theirs.name; + negotiated_codecs->push_back(std::move(negotiated)); + } + } + if (keep_offer_order) { + // RFC3264: Although the answerer MAY list the formats in their desired + // order of preference, it is RECOMMENDED that unless there is a + // specific reason, the answerer list formats in the same relative order + // they were present in the offer. + // This can be skipped when the transceiver has any codec preferences. + std::unordered_map payload_type_preferences; + int preference = static_cast(offered_codecs.size() + 1); + for (const C& codec : offered_codecs) { + payload_type_preferences[codec.id] = preference--; + } + absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a, + const C& b) { + return payload_type_preferences[a.id] > payload_type_preferences[b.id]; + }); + } +} + +// Find the codec in |codec_list| that |rtx_codec| is associated with. +template +static const C* GetAssociatedCodec(const std::vector& codec_list, + const C& rtx_codec) { + std::string associated_pt_str; + if (!rtx_codec.GetParam(cricket::kCodecParamAssociatedPayloadType, + &associated_pt_str)) { + RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name + << " is missing an associated payload type."; + return nullptr; + } + + int associated_pt; + if (!rtc::FromString(associated_pt_str, &associated_pt)) { + RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str + << " of RTX codec " << rtx_codec.name + << " to an integer."; + return nullptr; + } + + // Find the associated reference codec for the reference RTX codec. + const C* associated_codec = FindCodecById(codec_list, associated_pt); + if (!associated_codec) { + RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type " + << associated_pt << " for RTX codec " << rtx_codec.name + << "."; + } + return associated_codec; +} + +// Adds all codecs from |reference_codecs| to |offered_codecs| that don't +// already exist in |offered_codecs| and ensure the payload types don't +// collide. +template +static void MergeCodecs(const std::vector& reference_codecs, + std::vector* offered_codecs, + cricket::UsedPayloadTypes* used_pltypes) { + // Add all new codecs that are not RTX codecs. + for (const C& reference_codec : reference_codecs) { + if (!IsRtxCodec(reference_codec) && + !FindMatchingCodec(reference_codecs, *offered_codecs, + reference_codec, nullptr)) { + C codec = reference_codec; + used_pltypes->FindAndSetIdUsed(&codec); + offered_codecs->push_back(codec); + } + } + + // Add all new RTX codecs. + for (const C& reference_codec : reference_codecs) { + if (IsRtxCodec(reference_codec) && + !FindMatchingCodec(reference_codecs, *offered_codecs, + reference_codec, nullptr)) { + C rtx_codec = reference_codec; + const C* associated_codec = + GetAssociatedCodec(reference_codecs, rtx_codec); + if (!associated_codec) { + continue; + } + // Find a codec in the offered list that matches the reference codec. + // Its payload type may be different than the reference codec. + C matching_codec; + if (!FindMatchingCodec(reference_codecs, *offered_codecs, + *associated_codec, &matching_codec)) { + RTC_LOG(LS_WARNING) + << "Couldn't find matching " << associated_codec->name << " codec."; + continue; + } + + rtx_codec.params[cricket::kCodecParamAssociatedPayloadType] = + rtc::ToString(matching_codec.id); + used_pltypes->FindAndSetIdUsed(&rtx_codec); + offered_codecs->push_back(rtx_codec); + } + } +} + +static std::vector generateAvailableVideoFormats(std::vector const &formats) { + if (formats.empty()) { + return {}; + } + + constexpr int kFirstDynamicPayloadType = 100; + constexpr int kLastDynamicPayloadType = 127; + + int payload_type = kFirstDynamicPayloadType; + + std::vector result; + + //bool codecSelected = false; + + for (const auto &format : formats) { + /*if (codecSelected) { + break; + }*/ + + bool alreadyAdded = false; + for (const auto &it : result) { + if (it.videoCodec.name == format.name) { + alreadyAdded = true; + break; + } + } + if (alreadyAdded) { + continue; + } + + OutgoingVideoFormat resultFormat; + + cricket::VideoCodec codec(format); + codec.id = payload_type; + addDefaultFeedbackParams(&codec); + + resultFormat.videoCodec = codec; + //codecSelected = true; + + // Increment payload type. + ++payload_type; + if (payload_type > kLastDynamicPayloadType) { + RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; + break; + } + + // Add associated RTX codec for non-FEC codecs. + if (!absl::EqualsIgnoreCase(codec.name, cricket::kUlpfecCodecName) && + !absl::EqualsIgnoreCase(codec.name, cricket::kFlexfecCodecName)) { + resultFormat.rtxCodec = cricket::VideoCodec::CreateRtxCodec(payload_type, codec.id); + + // Increment payload type. + ++payload_type; + if (payload_type > kLastDynamicPayloadType) { + RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; + break; + } + } + + result.push_back(std::move(resultFormat)); + } + return result; +} + +static void getCodecsFromMediaContent(signaling_4_0_0::MediaContent const &content, std::vector &codecs) { + for (const auto &payloadType : content.payloadTypes) { + cricket::VideoCodec codec(payloadType.id, payloadType.name); + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + codecs.push_back(std::move(codec)); + } +} + +static std::vector getPayloadTypesFromVideoCodecs(std::vector const &codecs) { + std::vector payloadTypes; + + for (const auto &codec : codecs) { + signaling_4_0_0::PayloadType payloadType; + + payloadType.id = codec.id; + payloadType.name = codec.name; + payloadType.clockrate = 90000; + payloadType.channels = 0; + + for (const auto &feedbackParam : codec.feedback_params.params()) { + signaling_4_0_0::FeedbackType feedbackType; + feedbackType.type = feedbackParam.id(); + feedbackType.subtype = feedbackParam.param(); + payloadType.feedbackTypes.push_back(std::move(feedbackType)); + } + + for (const auto ¶m : codec.params) { + payloadType.parameters.push_back(std::make_pair(param.first, param.second)); + } + + payloadTypes.push_back(std::move(payloadType)); + } + + return payloadTypes; +} + +static void getCodecsFromMediaContent(signaling_4_0_0::MediaContent const &content, std::vector &codecs) { + for (const auto &payloadType : content.payloadTypes) { + cricket::AudioCodec codec(payloadType.id, payloadType.name, payloadType.clockrate, 0, payloadType.channels); + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + codecs.push_back(std::move(codec)); + } +} + +static std::vector getPayloadTypesFromAudioCodecs(std::vector const &codecs) { + std::vector payloadTypes; + + for (const auto &codec : codecs) { + signaling_4_0_0::PayloadType payloadType; + + payloadType.id = codec.id; + payloadType.name = codec.name; + payloadType.clockrate = codec.clockrate; + payloadType.channels = (uint32_t)codec.channels; + + for (const auto &feedbackParam : codec.feedback_params.params()) { + signaling_4_0_0::FeedbackType feedbackType; + feedbackType.type = feedbackParam.id(); + feedbackType.subtype = feedbackParam.param(); + payloadType.feedbackTypes.push_back(std::move(feedbackType)); + } + + for (const auto ¶m : codec.params) { + payloadType.parameters.push_back(std::make_pair(param.first, param.second)); + } + + payloadTypes.push_back(std::move(payloadType)); + } + + return payloadTypes; +} + +template +struct NegotiatedMediaContent { + uint32_t ssrc = 0; + std::vector ssrcGroups; + std::vector rtpExtensions; + std::vector codecs; +}; + +static bool FindByUri(const cricket::RtpHeaderExtensions& extensions, + const webrtc::RtpExtension& ext_to_match, + webrtc::RtpExtension* found_extension) { + // We assume that all URIs are given in a canonical format. + const webrtc::RtpExtension* found = + webrtc::RtpExtension::FindHeaderExtensionByUri( + extensions, + ext_to_match.uri, + webrtc::RtpExtension::Filter::kPreferEncryptedExtension + ); + if (!found) { + return false; + } + if (found_extension) { + *found_extension = *found; + } + return true; +} + +template +static NegotiatedMediaContent negotiateMediaContent(signaling_4_0_0::MediaContent const &baseMediaContent, signaling_4_0_0::MediaContent const &localContent, signaling_4_0_0::MediaContent const &remoteContent, bool isAnswer) { + std::vector localCodecs; + getCodecsFromMediaContent(localContent, localCodecs); + + std::vector remoteCodecs; + getCodecsFromMediaContent(remoteContent, remoteCodecs); + + std::vector negotiatedCodecs; + + cricket::UsedPayloadTypes usedPayloadTypes; + NegotiateCodecs(localCodecs, remoteCodecs, &negotiatedCodecs, true); + + NegotiatedMediaContent result; + + result.ssrc = baseMediaContent.ssrc; + result.ssrcGroups = baseMediaContent.ssrcGroups; + result.codecs = std::move(negotiatedCodecs); + + cricket::UsedRtpHeaderExtensionIds extensionIds(cricket::UsedRtpHeaderExtensionIds::IdDomain::kOneByteOnly); + + for (const auto &extension : remoteContent.rtpExtensions) { + if (isAnswer) { + webrtc::RtpExtension found; + if (!FindByUri(localContent.rtpExtensions, extension, &found)) { + continue; + } + } + + webrtc::RtpExtension mutableExtension = extension; + extensionIds.FindAndSetIdUsed(&mutableExtension); + result.rtpExtensions.push_back(std::move(mutableExtension)); + } + + if (!isAnswer) { + for (const auto &extension : localContent.rtpExtensions) { + webrtc::RtpExtension found; + if (!FindByUri(result.rtpExtensions, extension, &found)) { + webrtc::RtpExtension mutableExtension = extension; + extensionIds.FindAndSetIdUsed(&mutableExtension); + result.rtpExtensions.push_back(std::move(mutableExtension)); + } + } + } + + return result; +} + +class OutgoingAudioChannel : public sigslot::has_slots<> { +public: + static absl::optional createOutgoingContentDescription() { + signaling_4_0_0::MediaContent mediaContent; + + auto generator = std::mt19937(std::random_device()()); + auto distribution = std::uniform_int_distribution(); + do { + mediaContent.ssrc = distribution(generator) & 0x7fffffffU; + } while (!mediaContent.ssrc); + + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAudioLevelUri, 1); + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, 2); + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, 3); + + cricket::AudioCodec opusCodec(109, "opus", 48000, 0, 2); + opusCodec.AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamTransportCc)); + opusCodec.SetParam(cricket::kCodecParamUseInbandFec, 1); + opusCodec.SetParam(cricket::kCodecParamMinPTime, 60); + + mediaContent.payloadTypes = getPayloadTypesFromAudioCodecs({ opusCodec }); + + return mediaContent; + } + +public: + OutgoingAudioChannel( + webrtc::Call *call, + cricket::ChannelManager *channelManager, + rtc::UniqueRandomIdGenerator *uniqueRandomIdGenerator, + webrtc::LocalAudioSinkAdapter *audioSource, + webrtc::RtpTransport *rtpTransport, + NegotiatedMediaContent const &mediaContent, + std::shared_ptr threads + ) : + _threads(threads), + _ssrc(mediaContent.ssrc), + _call(call), + _channelManager(channelManager), + _audioSource(audioSource) { + cricket::AudioOptions audioOptions; + bool _disableOutgoingAudioProcessing = false; + + if (_disableOutgoingAudioProcessing) { + audioOptions.echo_cancellation = false; + audioOptions.noise_suppression = false; + audioOptions.auto_gain_control = false; + audioOptions.highpass_filter = false; + audioOptions.typing_detection = false; + audioOptions.experimental_agc = false; + audioOptions.experimental_ns = false; + audioOptions.residual_echo_detector = false; + } else { + audioOptions.echo_cancellation = true; + audioOptions.noise_suppression = true; + } + + std::vector streamIds; + streamIds.push_back("1"); + + _outgoingAudioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "audio0", false, NativeNetworkingImpl::getDefaulCryptoOptions(), uniqueRandomIdGenerator, audioOptions); + + std::vector codecs; + for (const auto &codec : mediaContent.codecs) { + if (codec.name == "opus") { + auto mutableCodec = codec; + + const uint8_t opusMinBitrateKbps = 16; + const uint8_t opusMaxBitrateKbps = 32; + const uint8_t opusStartBitrateKbps = 32; + const uint8_t opusPTimeMs = 60; + + mutableCodec.SetParam(cricket::kCodecParamMinBitrate, opusMinBitrateKbps); + mutableCodec.SetParam(cricket::kCodecParamStartBitrate, opusStartBitrateKbps); + mutableCodec.SetParam(cricket::kCodecParamMaxBitrate, opusMaxBitrateKbps); + mutableCodec.SetParam(cricket::kCodecParamUseInbandFec, 1); + mutableCodec.SetParam(cricket::kCodecParamPTime, opusPTimeMs); + + codecs.push_back(std::move(mutableCodec)); + } + } + + auto outgoingAudioDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + outgoingAudioDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + outgoingAudioDescription->set_rtcp_mux(true); + outgoingAudioDescription->set_rtcp_reduced_size(true); + outgoingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); + outgoingAudioDescription->set_codecs(codecs); + outgoingAudioDescription->set_bandwidth(-1); + outgoingAudioDescription->AddStream(cricket::StreamParams::CreateLegacy(_ssrc)); + + auto incomingAudioDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + incomingAudioDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + incomingAudioDescription->set_rtcp_mux(true); + incomingAudioDescription->set_rtcp_reduced_size(true); + incomingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); + incomingAudioDescription->set_codecs(codecs); + incomingAudioDescription->set_bandwidth(-1); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingAudioChannel->SetPayloadTypeDemuxingEnabled(false); + _outgoingAudioChannel->SetLocalContent(outgoingAudioDescription.get(), webrtc::SdpType::kOffer, nullptr); + _outgoingAudioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, nullptr); + }); + + //_outgoingAudioChannel->SignalSentPacket().connect(this, &OutgoingAudioChannel::OnSentPacket_w); + //_outgoingAudioChannel->UpdateRtpTransport(nullptr); + + setIsMuted(false); + } + + ~OutgoingAudioChannel() { + //_outgoingAudioChannel->SignalSentPacket().disconnect(this); + _outgoingAudioChannel->Enable(false); + _channelManager->DestroyVoiceChannel(_outgoingAudioChannel); + _outgoingAudioChannel = nullptr; + } + + void setIsMuted(bool isMuted) { + if (_isMuted != isMuted) { + _isMuted = isMuted; + + _outgoingAudioChannel->Enable(!_isMuted); + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingAudioChannel->media_channel()->SetAudioSend(_ssrc, !_isMuted, nullptr, _audioSource); + }); + } + } + +private: + void OnSentPacket_w(const rtc::SentPacket& sent_packet) { + _call->OnSentPacket(sent_packet); + } + +private: + std::shared_ptr _threads; + uint32_t _ssrc = 0; + webrtc::Call *_call = nullptr; + cricket::ChannelManager *_channelManager = nullptr; + webrtc::LocalAudioSinkAdapter *_audioSource = nullptr; + cricket::VoiceChannel *_outgoingAudioChannel = nullptr; + + bool _isMuted = true; +}; + +class IncomingV2AudioChannel : public sigslot::has_slots<> { +public: + IncomingV2AudioChannel( + cricket::ChannelManager *channelManager, + webrtc::Call *call, + webrtc::RtpTransport *rtpTransport, + rtc::UniqueRandomIdGenerator *randomIdGenerator, + NegotiatedMediaContent const &mediaContent, + std::shared_ptr threads) : + _ssrc(mediaContent.ssrc), + _channelManager(channelManager), + _call(call) { + _creationTimestamp = rtc::TimeMillis(); + + cricket::AudioOptions audioOptions; + audioOptions.audio_jitter_buffer_fast_accelerate = true; + audioOptions.audio_jitter_buffer_min_delay_ms = 50; + + std::string streamId = std::string("stream1"); + + _audioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "0", false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, audioOptions); + + auto audioCodecs = mediaContent.codecs; + + auto outgoingAudioDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + outgoingAudioDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + outgoingAudioDescription->set_rtcp_mux(true); + outgoingAudioDescription->set_rtcp_reduced_size(true); + outgoingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); + outgoingAudioDescription->set_codecs(audioCodecs); + outgoingAudioDescription->set_bandwidth(-1); + + auto incomingAudioDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + incomingAudioDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + incomingAudioDescription->set_rtcp_mux(true); + incomingAudioDescription->set_rtcp_reduced_size(true); + incomingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); + incomingAudioDescription->set_codecs(audioCodecs); + incomingAudioDescription->set_bandwidth(-1); + cricket::StreamParams streamParams = cricket::StreamParams::CreateLegacy(mediaContent.ssrc); + streamParams.set_stream_ids({ streamId }); + incomingAudioDescription->AddStream(streamParams); + + threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _audioChannel->SetPayloadTypeDemuxingEnabled(false); + _audioChannel->SetLocalContent(outgoingAudioDescription.get(), webrtc::SdpType::kOffer, nullptr); + _audioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, nullptr); + }); + + outgoingAudioDescription.reset(); + incomingAudioDescription.reset(); + + //std::unique_ptr audioLevelSink(new AudioSinkImpl(onAudioLevelUpdated, _ssrc, std::move(onAudioFrame))); + //_audioChannel->media_channel()->SetRawAudioSink(ssrc.networkSsrc, std::move(audioLevelSink)); + + _audioChannel->Enable(true); + } + + ~IncomingV2AudioChannel() { + _audioChannel->Enable(false); + _channelManager->DestroyVoiceChannel(_audioChannel); + _audioChannel = nullptr; + } + + void setVolume(double value) { + _audioChannel->media_channel()->SetOutputVolume(_ssrc, value); + } + + void updateActivity() { + _activityTimestamp = rtc::TimeMillis(); + } + + int64_t getActivity() { + return _activityTimestamp; + } + +private: + void OnSentPacket_w(const rtc::SentPacket& sent_packet) { + _call->OnSentPacket(sent_packet); + } + +private: + uint32_t _ssrc = 0; + // Memory is managed by _channelManager + cricket::VoiceChannel *_audioChannel = nullptr; + // Memory is managed externally + cricket::ChannelManager *_channelManager = nullptr; + webrtc::Call *_call = nullptr; + int64_t _creationTimestamp = 0; + int64_t _activityTimestamp = 0; +}; + +class OutgoingVideoChannel : public sigslot::has_slots<>, public std::enable_shared_from_this { +public: + static absl::optional createOutgoingContentDescription(std::vector const &availableVideoFormats, bool isScreencast) { + signaling_4_0_0::MediaContent mediaContent; + + auto generator = std::mt19937(std::random_device()()); + auto distribution = std::uniform_int_distribution(); + do { + mediaContent.ssrc = distribution(generator) & 0x7fffffffU; + } while (!mediaContent.ssrc); + + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, 2); + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, 3); + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kVideoRotationUri, 13); + + signaling_4_0_0::SsrcGroup fidGroup; + fidGroup.semantics = "FID"; + fidGroup.ssrcs.push_back(mediaContent.ssrc); + fidGroup.ssrcs.push_back(mediaContent.ssrc + 1); + mediaContent.ssrcGroups.push_back(std::move(fidGroup)); + + auto unsortedVideoFormats = generateAvailableVideoFormats(availableVideoFormats); + + std::vector formatPreferences; + if (isScreencast) { + formatPreferences.push_back(cricket::kVp8CodecName); + } else { +#ifndef WEBRTC_DISABLE_H265 + formatPreferences.push_back(cricket::kH265CodecName); +#endif + formatPreferences.push_back(cricket::kH264CodecName); + } + + std::vector videoFormats; + for (const auto &name : formatPreferences) { + for (size_t i = 0; i < unsortedVideoFormats.size(); i++) { + if (absl::EqualsIgnoreCase(name, unsortedVideoFormats[i].videoCodec.name)) { + videoFormats.push_back(unsortedVideoFormats[i]); + unsortedVideoFormats.erase(unsortedVideoFormats.begin() + i); + break; + } + } + } + for (const auto &format : unsortedVideoFormats) { + videoFormats.push_back(format); + } + + for (const auto &format : videoFormats) { + signaling_4_0_0::PayloadType videoPayload; + videoPayload.id = format.videoCodec.id; + videoPayload.name = format.videoCodec.name; + videoPayload.clockrate = format.videoCodec.clockrate; + videoPayload.channels = 0; + + std::vector videoFeedbackTypes; + + signaling_4_0_0::FeedbackType fbGoogRemb; + fbGoogRemb.type = "goog-remb"; + videoFeedbackTypes.push_back(fbGoogRemb); + + signaling_4_0_0::FeedbackType fbTransportCc; + fbTransportCc.type = "transport-cc"; + videoFeedbackTypes.push_back(fbTransportCc); + + signaling_4_0_0::FeedbackType fbCcmFir; + fbCcmFir.type = "ccm"; + fbCcmFir.subtype = "fir"; + videoFeedbackTypes.push_back(fbCcmFir); + + signaling_4_0_0::FeedbackType fbNack; + fbNack.type = "nack"; + videoFeedbackTypes.push_back(fbNack); + + signaling_4_0_0::FeedbackType fbNackPli; + fbNackPli.type = "nack"; + fbNackPli.subtype = "pli"; + videoFeedbackTypes.push_back(fbNackPli); + + videoPayload.feedbackTypes = videoFeedbackTypes; + videoPayload.parameters = {}; + + mediaContent.payloadTypes.push_back(std::move(videoPayload)); + + if (format.rtxCodec) { + signaling_4_0_0::PayloadType rtxPayload; + rtxPayload.id = format.rtxCodec->id; + rtxPayload.name = format.rtxCodec->name; + rtxPayload.clockrate = format.rtxCodec->clockrate; + rtxPayload.parameters.push_back(std::make_pair("apt", intToString(videoPayload.id))); + mediaContent.payloadTypes.push_back(std::move(rtxPayload)); + } + } + + return mediaContent; + } + +public: + OutgoingVideoChannel( + std::shared_ptr threads, + cricket::ChannelManager *channelManager, + webrtc::Call *call, + webrtc::RtpTransport *rtpTransport, + rtc::UniqueRandomIdGenerator *randomIdGenerator, + webrtc::VideoBitrateAllocatorFactory *videoBitrateAllocatorFactory, + std::function rotationUpdated, + NegotiatedMediaContent const &mediaContent, + bool isScreencast + ) : + _threads(threads), + _mainSsrc(mediaContent.ssrc), + _call(call), + _channelManager(channelManager), + _rotationUpdated(rotationUpdated) { + cricket::VideoOptions videoOptions; + videoOptions.is_screencast = isScreencast; + _outgoingVideoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "out" + intToString(mediaContent.ssrc), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, videoOptions, videoBitrateAllocatorFactory); + + auto videoCodecs = mediaContent.codecs; + + auto outgoingVideoDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + outgoingVideoDescription->AddRtpHeaderExtension(rtpExtension); + } + + outgoingVideoDescription->set_rtcp_mux(true); + outgoingVideoDescription->set_rtcp_reduced_size(true); + outgoingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); + outgoingVideoDescription->set_codecs(videoCodecs); + outgoingVideoDescription->set_bandwidth(-1); + + cricket::StreamParams videoSendStreamParams; + + for (const auto &ssrcGroup : mediaContent.ssrcGroups) { + for (auto ssrc : ssrcGroup.ssrcs) { + videoSendStreamParams.ssrcs.push_back(ssrc); + } + + cricket::SsrcGroup mappedGroup(ssrcGroup.semantics, ssrcGroup.ssrcs); + videoSendStreamParams.ssrc_groups.push_back(std::move(mappedGroup)); + } + + videoSendStreamParams.cname = "cname"; + + outgoingVideoDescription->AddStream(videoSendStreamParams); + + auto incomingVideoDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + incomingVideoDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + incomingVideoDescription->set_rtcp_mux(true); + incomingVideoDescription->set_rtcp_reduced_size(true); + incomingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); + incomingVideoDescription->set_codecs(videoCodecs); + incomingVideoDescription->set_bandwidth(-1); + + threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingVideoChannel->SetPayloadTypeDemuxingEnabled(false); + _outgoingVideoChannel->SetLocalContent(outgoingVideoDescription.get(), webrtc::SdpType::kOffer, nullptr); + _outgoingVideoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, nullptr); + + webrtc::RtpParameters rtpParameters = _outgoingVideoChannel->media_channel()->GetRtpSendParameters(mediaContent.ssrc); + + _outgoingVideoChannel->media_channel()->SetRtpSendParameters(mediaContent.ssrc, rtpParameters); + }); + + _outgoingVideoChannel->Enable(false); + + threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingVideoChannel->media_channel()->SetVideoSend(mediaContent.ssrc, NULL, nullptr); + }); + } + + ~OutgoingVideoChannel() { + _outgoingVideoChannel->Enable(false); + _channelManager->DestroyVideoChannel(_outgoingVideoChannel); + _outgoingVideoChannel = nullptr; + } + + void setVideoCapture(std::shared_ptr videoCapture) { + _videoCapture = videoCapture; + + if (_videoCapture) { + _outgoingVideoChannel->Enable(true); + auto videoCaptureImpl = GetVideoCaptureAssumingSameThread(_videoCapture.get()); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingVideoChannel->media_channel()->SetVideoSend(_mainSsrc, NULL, videoCaptureImpl->source()); + }); + + const auto weak = std::weak_ptr(shared_from_this()); + videoCaptureImpl->setRotationUpdated([threads = _threads, weak](int angle) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + signaling_4_0_0::MediaStateMessage::VideoRotation videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + switch (angle) { + case 0: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + break; + } + case 90: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation90; + break; + } + case 180: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation180; + break; + } + case 270: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation270; + break; + } + default: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + break; + } + } + if (strong->_videoRotation != videoRotation) { + strong->_videoRotation = videoRotation; + strong->_rotationUpdated(); + } + }); + }); + + switch (videoCaptureImpl->getRotation()) { + case 0: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + break; + } + case 90: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation90; + break; + } + case 180: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation180; + break; + } + case 270: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation270; + break; + } + default: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + break; + } + } + } else { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + _outgoingVideoChannel->Enable(false); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingVideoChannel->media_channel()->SetVideoSend(_mainSsrc, NULL, nullptr); + }); + } + } + +public: + std::shared_ptr videoCapture() { + return _videoCapture; + } + + signaling_4_0_0::MediaStateMessage::VideoRotation getRotation() { + return _videoRotation; + } + +private: + void OnSentPacket_w(const rtc::SentPacket& sent_packet) { + _call->OnSentPacket(sent_packet); + } + +private: + std::shared_ptr _threads; + + uint32_t _mainSsrc = 0; + webrtc::Call *_call = nullptr; + cricket::ChannelManager *_channelManager = nullptr; + cricket::VideoChannel *_outgoingVideoChannel = nullptr; + + std::function _rotationUpdated; + + std::shared_ptr _videoCapture; + signaling_4_0_0::MediaStateMessage::VideoRotation _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; +}; + +class VideoSinkImpl : public rtc::VideoSinkInterface { +public: + VideoSinkImpl() { + } + + virtual ~VideoSinkImpl() { + } + + virtual void OnFrame(const webrtc::VideoFrame& frame) override { + //_lastFrame = frame; + for (int i = (int)(_sinks.size()) - 1; i >= 0; i--) { + auto strong = _sinks[i].lock(); + if (!strong) { + _sinks.erase(_sinks.begin() + i); + } else { + strong->OnFrame(frame); + } + } + } + + virtual void OnDiscardedFrame() override { + for (int i = (int)(_sinks.size()) - 1; i >= 0; i--) { + auto strong = _sinks[i].lock(); + if (!strong) { + _sinks.erase(_sinks.begin() + i); + } else { + strong->OnDiscardedFrame(); + } + } + } + + void addSink(std::weak_ptr> impl) { + _sinks.push_back(impl); + if (_lastFrame) { + auto strong = impl.lock(); + if (strong) { + strong->OnFrame(_lastFrame.value()); + } + } + } + +private: + std::vector>> _sinks; + absl::optional _lastFrame; +}; + +class IncomingV2VideoChannel : public sigslot::has_slots<> { +public: + IncomingV2VideoChannel( + cricket::ChannelManager *channelManager, + webrtc::Call *call, + webrtc::RtpTransport *rtpTransport, + rtc::UniqueRandomIdGenerator *randomIdGenerator, + NegotiatedMediaContent const &mediaContent, + std::string const &streamId, + std::shared_ptr threads) : + _channelManager(channelManager), + _call(call) { + _videoSink.reset(new VideoSinkImpl()); + + _videoBitrateAllocatorFactory = webrtc::CreateBuiltinVideoBitrateAllocatorFactory(); + + _videoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), streamId, false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, cricket::VideoOptions(), _videoBitrateAllocatorFactory.get()); + + std::vector videoCodecs = mediaContent.codecs; + + auto outgoingVideoDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + outgoingVideoDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + outgoingVideoDescription->set_rtcp_mux(true); + outgoingVideoDescription->set_rtcp_reduced_size(true); + outgoingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); + outgoingVideoDescription->set_codecs(videoCodecs); + outgoingVideoDescription->set_bandwidth(-1); + + cricket::StreamParams videoRecvStreamParams; + + _mainVideoSsrc = mediaContent.ssrc; + + std::vector allSsrcs; + for (const auto &group : mediaContent.ssrcGroups) { + for (auto ssrc : group.ssrcs) { + if (std::find(allSsrcs.begin(), allSsrcs.end(), ssrc) == allSsrcs.end()) { + allSsrcs.push_back(ssrc); + } + } + + cricket::SsrcGroup parsedGroup(group.semantics, group.ssrcs); + videoRecvStreamParams.ssrc_groups.push_back(parsedGroup); + } + videoRecvStreamParams.ssrcs = allSsrcs; + + videoRecvStreamParams.cname = "cname"; + videoRecvStreamParams.set_stream_ids({ streamId }); + + auto incomingVideoDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + incomingVideoDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + incomingVideoDescription->set_rtcp_mux(true); + incomingVideoDescription->set_rtcp_reduced_size(true); + incomingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); + incomingVideoDescription->set_codecs(videoCodecs); + incomingVideoDescription->set_bandwidth(-1); + + incomingVideoDescription->AddStream(videoRecvStreamParams); + + threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _videoChannel->SetPayloadTypeDemuxingEnabled(false); + _videoChannel->SetLocalContent(outgoingVideoDescription.get(), webrtc::SdpType::kOffer, nullptr); + _videoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, nullptr); + + _videoChannel->media_channel()->SetSink(_mainVideoSsrc, _videoSink.get()); + }); + + _videoChannel->Enable(true); + } + + ~IncomingV2VideoChannel() { + _videoChannel->Enable(false); + _channelManager->DestroyVideoChannel(_videoChannel); + _videoChannel = nullptr; + } + + void addSink(std::weak_ptr> impl) { + _videoSink->addSink(impl); + } + +private: + void OnSentPacket_w(const rtc::SentPacket& sent_packet) { + _call->OnSentPacket(sent_packet); + } + +private: + uint32_t _mainVideoSsrc = 0; + std::unique_ptr _videoSink; + std::unique_ptr _videoBitrateAllocatorFactory; + // Memory is managed by _channelManager + cricket::VideoChannel *_videoChannel; + // Memory is managed externally + cricket::ChannelManager *_channelManager = nullptr; + webrtc::Call *_call = nullptr; +}; + +} // namespace + +class InstanceV2_4_0_0ImplInternal : public std::enable_shared_from_this { +public: + InstanceV2_4_0_0ImplInternal(Descriptor &&descriptor, std::shared_ptr threads) : + _threads(threads), + _rtcServers(descriptor.rtcServers), + _encryptionKey(std::move(descriptor.encryptionKey)), + _stateUpdated(descriptor.stateUpdated), + _signalBarsUpdated(descriptor.signalBarsUpdated), + _audioLevelUpdated(descriptor.audioLevelUpdated), + _remoteBatteryLevelIsLowUpdated(descriptor.remoteBatteryLevelIsLowUpdated), + _remoteMediaStateUpdated(descriptor.remoteMediaStateUpdated), + _remotePrefferedAspectRatioUpdated(descriptor.remotePrefferedAspectRatioUpdated), + _signalingDataEmitted(descriptor.signalingDataEmitted), + _createAudioDeviceModule(descriptor.createAudioDeviceModule), + _eventLog(std::make_unique()), + _taskQueueFactory(webrtc::CreateDefaultTaskQueueFactory()), + _videoCapture(descriptor.videoCapture), + _platformContext(descriptor.platformContext) { + } + + ~InstanceV2_4_0_0ImplInternal() { + _networking->perform(RTC_FROM_HERE, [](NativeNetworkingImpl *networking) { + networking->stop(); + }); + + _incomingAudioChannel.reset(); + _incomingVideoChannel.reset(); + _incomingScreencastChannel.reset(); + _outgoingAudioChannel.reset(); + _outgoingVideoChannel.reset(); + _outgoingScreencastChannel.reset(); + _currentSink.reset(); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _channelManager.reset(); + _call.reset(); + _audioDeviceModule = nullptr; + }); + _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, []() { + }); + } + + void start() { + const auto weak = std::weak_ptr(shared_from_this()); + + _networking.reset(new ThreadLocalObject(_threads->getNetworkThread(), [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing, rtcServers = _rtcServers]() { + return new NativeNetworkingImpl(NativeNetworkingImpl::Configuration{ + .isOutgoing = isOutgoing, + .enableStunMarking = false, + .enableTCP = false, + .enableP2P = true, + .rtcServers = rtcServers, + .stateUpdated = [threads, weak](const NativeNetworkingImpl::State &state) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->onNetworkStateUpdated(state); + }); + }, + .candidateGathered = [threads, weak](const cricket::Candidate &candidate) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + + strong->sendCandidate(candidate); + }); + }, + .transportMessageReceived = [threads, weak](rtc::CopyOnWriteBuffer const &packet, bool isMissing) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + }); + }, + .rtcpPacketReceived = [threads, weak](rtc::CopyOnWriteBuffer const &packet, int64_t timestamp) { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->_call->Receiver()->DeliverPacket(webrtc::MediaType::ANY, packet, timestamp); + }, + .dataChannelStateUpdated = [threads, weak](bool isDataChannelOpen) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->onDataChannelStateUpdated(isDataChannelOpen); + }); + }, + .dataChannelMessageReceived = [threads, weak](std::string const &message) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->onDataChannelMessage(message); + }); + }, + .threads = threads + }); + })); + + PlatformInterface::SharedInstance()->configurePlatformAudio(); + + //setAudioInputDevice(_initialInputDeviceId); + //setAudioOutputDevice(_initialOutputDeviceId); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + cricket::MediaEngineDependencies mediaDeps; + mediaDeps.task_queue_factory = _taskQueueFactory.get(); + mediaDeps.audio_encoder_factory = webrtc::CreateAudioEncoderFactory(); + mediaDeps.audio_decoder_factory = webrtc::CreateAudioDecoderFactory(); + + mediaDeps.video_encoder_factory = PlatformInterface::SharedInstance()->makeVideoEncoderFactory(_platformContext, true); + mediaDeps.video_decoder_factory = PlatformInterface::SharedInstance()->makeVideoDecoderFactory(_platformContext); + + _audioDeviceModule = createAudioDeviceModule(); + /*if (!_audioDeviceModule) { + return; + }*/ + mediaDeps.adm = _audioDeviceModule; + + _availableVideoFormats = mediaDeps.video_encoder_factory->GetSupportedFormats(); + + std::unique_ptr mediaEngine = cricket::CreateMediaEngine(std::move(mediaDeps)); + + _channelManager = cricket::ChannelManager::Create( + std::move(mediaEngine), + true, + _threads->getWorkerThread(), + _threads->getNetworkThread() + ); + + webrtc::Call::Config callConfig(_eventLog.get()); + callConfig.task_queue_factory = _taskQueueFactory.get(); + callConfig.trials = &_fieldTrials; + callConfig.audio_state = _channelManager->media_engine()->voice().GetAudioState(); + + _call.reset(webrtc::Call::Create(callConfig, webrtc::Clock::GetRealTimeClock(), _threads->getSharedModuleThread(), webrtc::ProcessThread::Create("PacerThread"))); + }); + + _uniqueRandomIdGenerator.reset(new rtc::UniqueRandomIdGenerator()); + + _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, [this]() { + _rtpTransport = _networking->getSyncAssumingSameThread()->getRtpTransport(); + }); + + _videoBitrateAllocatorFactory = webrtc::CreateBuiltinVideoBitrateAllocatorFactory(); + + _networking->perform(RTC_FROM_HERE, [](NativeNetworkingImpl *networking) { + networking->start(); + }); + + if (_videoCapture) { + setVideoCapture(_videoCapture); + } + + beginSignaling(); + + adjustBitratePreferences(true); + } + + void sendSignalingMessage(signaling_4_0_0::Message const &message) { + auto data = message.serialize(); + + RTC_LOG(LS_INFO) << "sendSignalingMessage: " << std::string(data.begin(), data.end()); + + if (_signalingEncryption) { + if (const auto encryptedData = _signalingEncryption->encryptOutgoing(data)) { + _signalingDataEmitted(std::vector(encryptedData->data(), encryptedData->data() + encryptedData->size())); + } else { + RTC_LOG(LS_ERROR) << "sendSignalingMessage: failed to encrypt payload"; + } + } else { + _signalingDataEmitted(data); + } + } + + void beginSignaling() { + _signalingEncryption.reset(new SignalingEncryption(_encryptionKey)); + + if (_encryptionKey.isOutgoing) { + _outgoingAudioContent = OutgoingAudioChannel::createOutgoingContentDescription(); + _outgoingVideoContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, false); + _outgoingScreencastContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, true); + + sendInitialSetup(); + } + } + + void createNegotiatedChannels() { + if (_negotiatedOutgoingVideoContent) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingVideoChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + _negotiatedOutgoingVideoContent.value(), + false + )); + + if (_videoCapture) { + _outgoingVideoChannel->setVideoCapture(_videoCapture); + } + } + + if (_negotiatedOutgoingScreencastContent) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingScreencastChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + _negotiatedOutgoingScreencastContent.value(), + true + )); + + if (_screencastCapture) { + _outgoingScreencastChannel->setVideoCapture(_screencastCapture); + } + } + + if (_negotiatedOutgoingAudioContent) { + _outgoingAudioChannel.reset(new OutgoingAudioChannel( + _call.get(), + _channelManager.get(), + _uniqueRandomIdGenerator.get(), + &_audioSource, + _rtpTransport, + _negotiatedOutgoingAudioContent.value(), + _threads + )); + } + + adjustBitratePreferences(true); + } + + void sendInitialSetup() { + const auto weak = std::weak_ptr(shared_from_this()); + + _networking->perform(RTC_FROM_HERE, [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing](NativeNetworkingImpl *networking) { + auto localFingerprint = networking->getLocalFingerprint(); + std::string hash = localFingerprint->algorithm; + std::string fingerprint = localFingerprint->GetRfc4572Fingerprint(); + std::string setup; + if (isOutgoing) { + setup = "actpass"; + } else { + setup = "passive"; + } + + auto localIceParams = networking->getLocalIceParameters(); + std::string ufrag = localIceParams.ufrag; + std::string pwd = localIceParams.pwd; + + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ufrag, pwd, hash, fingerprint, setup, localIceParams]() { + const auto strong = weak.lock(); + if (!strong) { + return; + } + + signaling_4_0_0::InitialSetupMessage data; + + if (strong->_outgoingAudioContent) { + data.audio = strong->_outgoingAudioContent.value(); + } + if (strong->_outgoingVideoContent) { + data.video = strong->_outgoingVideoContent.value(); + } + if (strong->_outgoingScreencastContent) { + data.screencast = strong->_outgoingScreencastContent.value(); + } + + data.ufrag = ufrag; + data.pwd = pwd; + + signaling_4_0_0::DtlsFingerprint dtlsFingerprint; + dtlsFingerprint.hash = hash; + dtlsFingerprint.fingerprint = fingerprint; + dtlsFingerprint.setup = setup; + data.fingerprints.push_back(std::move(dtlsFingerprint)); + + signaling_4_0_0::Message message; + message.data = std::move(data); + strong->sendSignalingMessage(message); + }); + }); + } + + void receiveSignalingData(const std::vector &data) { + std::vector decryptedData; + + if (_signalingEncryption) { + const auto rawDecryptedData = _signalingEncryption->decryptIncoming(data); + if (!rawDecryptedData) { + RTC_LOG(LS_ERROR) << "receiveSignalingData: could not decrypt payload"; + + return; + } + + decryptedData = std::vector(rawDecryptedData->data(), rawDecryptedData->data() + rawDecryptedData->size()); + } else { + decryptedData = data; + } + + processSignalingData(decryptedData); + } + + void processSignalingData(const std::vector &data) { + RTC_LOG(LS_INFO) << "processSignalingData: " << std::string(data.begin(), data.end()); + + const auto message = signaling_4_0_0::Message::parse(data); + if (!message) { + return; + } + const auto messageData = &message->data; + if (const auto initialSetup = absl::get_if(messageData)) { + PeerIceParameters remoteIceParameters; + remoteIceParameters.ufrag = initialSetup->ufrag; + remoteIceParameters.pwd = initialSetup->pwd; + + std::unique_ptr fingerprint; + std::string sslSetup; + if (initialSetup->fingerprints.size() != 0) { + fingerprint = rtc::SSLFingerprint::CreateUniqueFromRfc4572(initialSetup->fingerprints[0].hash, initialSetup->fingerprints[0].fingerprint); + sslSetup = initialSetup->fingerprints[0].setup; + } + + _networking->perform(RTC_FROM_HERE, [threads = _threads, remoteIceParameters = std::move(remoteIceParameters), fingerprint = std::move(fingerprint), sslSetup = std::move(sslSetup)](NativeNetworkingImpl *networking) { + networking->setRemoteParams(remoteIceParameters, fingerprint.get(), sslSetup); + }); + + if (const auto audio = initialSetup->audio) { + if (_encryptionKey.isOutgoing) { + if (_outgoingAudioContent) { + _negotiatedOutgoingAudioContent = negotiateMediaContent(_outgoingAudioContent.value(), _outgoingAudioContent.value(), audio.value(), false); + const auto incomingAudioContent = negotiateMediaContent(audio.value(), _outgoingAudioContent.value(), audio.value(), false); + + signaling_4_0_0::MediaContent outgoingAudioContent; + + outgoingAudioContent.ssrc = _outgoingAudioContent->ssrc; + outgoingAudioContent.ssrcGroups = _outgoingAudioContent->ssrcGroups; + outgoingAudioContent.rtpExtensions = _negotiatedOutgoingAudioContent->rtpExtensions; + outgoingAudioContent.payloadTypes = getPayloadTypesFromAudioCodecs(_negotiatedOutgoingAudioContent->codecs); + + _outgoingAudioContent = std::move(outgoingAudioContent); + + _incomingAudioChannel.reset(new IncomingV2AudioChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingAudioContent, + _threads + )); + } + } else { + const auto generatedOutgoingContent = OutgoingAudioChannel::createOutgoingContentDescription(); + + if (generatedOutgoingContent) { + _negotiatedOutgoingAudioContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), audio.value(), true); + const auto incomingAudioContent = negotiateMediaContent(audio.value(), generatedOutgoingContent.value(), audio.value(), true); + + if (_negotiatedOutgoingAudioContent) { + signaling_4_0_0::MediaContent outgoingAudioContent; + + outgoingAudioContent.ssrc = generatedOutgoingContent->ssrc; + outgoingAudioContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; + outgoingAudioContent.rtpExtensions = _negotiatedOutgoingAudioContent->rtpExtensions; + outgoingAudioContent.payloadTypes = getPayloadTypesFromAudioCodecs(_negotiatedOutgoingAudioContent->codecs); + + _outgoingAudioContent = std::move(outgoingAudioContent); + + _incomingAudioChannel.reset(new IncomingV2AudioChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingAudioContent, + _threads + )); + } + } + } + } + + if (const auto video = initialSetup->video) { + if (_encryptionKey.isOutgoing) { + if (_outgoingVideoContent) { + _negotiatedOutgoingVideoContent = negotiateMediaContent(_outgoingVideoContent.value(), _outgoingVideoContent.value(), video.value(), false); + const auto incomingVideoContent = negotiateMediaContent(video.value(), _outgoingVideoContent.value(), video.value(), false); + + signaling_4_0_0::MediaContent outgoingVideoContent; + + outgoingVideoContent.ssrc = _outgoingVideoContent->ssrc; + outgoingVideoContent.ssrcGroups = _outgoingVideoContent->ssrcGroups; + outgoingVideoContent.rtpExtensions = _negotiatedOutgoingVideoContent->rtpExtensions; + outgoingVideoContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingVideoContent->codecs); + + _outgoingVideoContent = std::move(outgoingVideoContent); + + _incomingVideoChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingVideoContent, + "1", + _threads + )); + _incomingVideoChannel->addSink(_currentSink); + } + } else { + const auto generatedOutgoingContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, false); + + if (generatedOutgoingContent) { + _negotiatedOutgoingVideoContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), video.value(), true); + const auto incomingVideoContent = negotiateMediaContent(video.value(), generatedOutgoingContent.value(), video.value(), true); + + if (_negotiatedOutgoingVideoContent) { + signaling_4_0_0::MediaContent outgoingVideoContent; + + outgoingVideoContent.ssrc = generatedOutgoingContent->ssrc; + outgoingVideoContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; + outgoingVideoContent.rtpExtensions = _negotiatedOutgoingVideoContent->rtpExtensions; + outgoingVideoContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingVideoContent->codecs); + + _outgoingVideoContent = std::move(outgoingVideoContent); + + _incomingVideoChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingVideoContent, + "1", + _threads + )); + _incomingVideoChannel->addSink(_currentSink); + } + } + } + } + + if (const auto screencast = initialSetup->screencast) { + if (_encryptionKey.isOutgoing) { + if (_outgoingScreencastContent) { + _negotiatedOutgoingScreencastContent = negotiateMediaContent(_outgoingScreencastContent.value(), _outgoingScreencastContent.value(), screencast.value(), false); + const auto incomingScreencastContent = negotiateMediaContent(screencast.value(), _outgoingScreencastContent.value(), screencast.value(), false); + + signaling_4_0_0::MediaContent outgoingScreencastContent; + + outgoingScreencastContent.ssrc = _outgoingScreencastContent->ssrc; + outgoingScreencastContent.ssrcGroups = _outgoingScreencastContent->ssrcGroups; + outgoingScreencastContent.rtpExtensions = _negotiatedOutgoingScreencastContent->rtpExtensions; + outgoingScreencastContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingScreencastContent->codecs); + + _outgoingScreencastContent = std::move(outgoingScreencastContent); + + _incomingScreencastChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingScreencastContent, + "2", + _threads + )); + _incomingScreencastChannel->addSink(_currentSink); + } + } else { + const auto generatedOutgoingContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, true); + + if (generatedOutgoingContent) { + _negotiatedOutgoingScreencastContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), screencast.value(), true); + const auto incomingScreencastContent = negotiateMediaContent(screencast.value(), generatedOutgoingContent.value(), screencast.value(), true); + + if (_negotiatedOutgoingScreencastContent) { + signaling_4_0_0::MediaContent outgoingScreencastContent; + + outgoingScreencastContent.ssrc = generatedOutgoingContent->ssrc; + outgoingScreencastContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; + outgoingScreencastContent.rtpExtensions = _negotiatedOutgoingScreencastContent->rtpExtensions; + outgoingScreencastContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingScreencastContent->codecs); + + _outgoingScreencastContent = std::move(outgoingScreencastContent); + + _incomingScreencastChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingScreencastContent, + "2", + _threads + )); + _incomingScreencastChannel->addSink(_currentSink); + } + } + } + } + + createNegotiatedChannels(); + + if (!_encryptionKey.isOutgoing) { + sendInitialSetup(); + } + + _handshakeCompleted = true; + commitPendingIceCandidates(); + } else if (const auto candidatesList = absl::get_if(messageData)) { + for (const auto &candidate : candidatesList->iceCandidates) { + webrtc::JsepIceCandidate parseCandidate{ std::string(), 0 }; + if (!parseCandidate.Initialize(candidate.sdpString, nullptr)) { + RTC_LOG(LS_ERROR) << "Could not parse candidate: " << candidate.sdpString; + continue; + } + _pendingIceCandidates.push_back(parseCandidate.candidate()); + } + + if (_handshakeCompleted) { + commitPendingIceCandidates(); + } + } else if (const auto mediaState = absl::get_if(messageData)) { + AudioState mappedAudioState; + if (mediaState->isMuted) { + mappedAudioState = AudioState::Muted; + } else { + mappedAudioState = AudioState::Active; + } + + VideoState mappedVideoState; + switch (mediaState->videoState) { + case signaling_4_0_0::MediaStateMessage::VideoState::Inactive: { + mappedVideoState = VideoState::Inactive; + break; + } + case signaling_4_0_0::MediaStateMessage::VideoState::Suspended: { + mappedVideoState = VideoState::Paused; + break; + } + case signaling_4_0_0::MediaStateMessage::VideoState::Active: { + mappedVideoState = VideoState::Active; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + + VideoState mappedScreencastState; + switch (mediaState->screencastState) { + case signaling_4_0_0::MediaStateMessage::VideoState::Inactive: { + mappedScreencastState = VideoState::Inactive; + break; + } + case signaling_4_0_0::MediaStateMessage::VideoState::Suspended: { + mappedScreencastState = VideoState::Paused; + break; + } + case signaling_4_0_0::MediaStateMessage::VideoState::Active: { + mappedScreencastState = VideoState::Active; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + + VideoState effectiveVideoState = mappedVideoState; + if (mappedScreencastState == VideoState::Active || mappedScreencastState == VideoState::Paused) { + effectiveVideoState = mappedScreencastState; + } + + if (_remoteMediaStateUpdated) { + _remoteMediaStateUpdated(mappedAudioState, effectiveVideoState); + } + + if (_remoteBatteryLevelIsLowUpdated) { + _remoteBatteryLevelIsLowUpdated(mediaState->isBatteryLow); + } + } + } + + void commitPendingIceCandidates() { + if (_pendingIceCandidates.size() == 0) { + return; + } + _networking->perform(RTC_FROM_HERE, [threads = _threads, parsedCandidates = _pendingIceCandidates](NativeNetworkingImpl *networking) { + networking->addCandidates(parsedCandidates); + }); + _pendingIceCandidates.clear(); + } + + void onNetworkStateUpdated(NativeNetworkingImpl::State const &state) { + State mappedState; + if (state.isReadyToSendData) { + mappedState = State::Established; + } else { + mappedState = State::Reconnecting; + } + _stateUpdated(mappedState); + } + + void onDataChannelStateUpdated(bool isDataChannelOpen) { + if (_isDataChannelOpen != isDataChannelOpen) { + _isDataChannelOpen = isDataChannelOpen; + + if (_isDataChannelOpen) { + sendMediaState(); + } + } + } + + void sendDataChannelMessage(signaling_4_0_0::Message const &message) { + if (!_isDataChannelOpen) { + RTC_LOG(LS_ERROR) << "sendDataChannelMessage called, but data channel is not open"; + return; + } + auto data = message.serialize(); + std::string stringData(data.begin(), data.end()); + RTC_LOG(LS_INFO) << "sendDataChannelMessage: " << stringData; + _networking->perform(RTC_FROM_HERE, [stringData = std::move(stringData)](NativeNetworkingImpl *networking) { + networking->sendDataChannelMessage(stringData); + }); + } + + void onDataChannelMessage(std::string const &message) { + RTC_LOG(LS_INFO) << "dataChannelMessage received: " << message; + std::vector data(message.begin(), message.end()); + processSignalingData(data); + } + + void sendMediaState() { + if (!_isDataChannelOpen) { + return; + } + signaling_4_0_0::Message message; + signaling_4_0_0::MediaStateMessage data; + data.isMuted = _isMicrophoneMuted; + data.isBatteryLow = _isBatteryLow; + if (_outgoingVideoChannel) { + if (_outgoingVideoChannel->videoCapture()) { + data.videoState = signaling_4_0_0::MediaStateMessage::VideoState::Active; + } else{ + data.videoState = signaling_4_0_0::MediaStateMessage::VideoState::Inactive; + } + data.videoRotation = _outgoingVideoChannel->getRotation(); + } else { + data.videoState = signaling_4_0_0::MediaStateMessage::VideoState::Inactive; + data.videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + } + if (_outgoingScreencastChannel) { + if (_outgoingScreencastChannel->videoCapture()) { + data.screencastState = signaling_4_0_0::MediaStateMessage::VideoState::Active; + } else{ + data.screencastState = signaling_4_0_0::MediaStateMessage::VideoState::Inactive; + } + } else { + data.screencastState = signaling_4_0_0::MediaStateMessage::VideoState::Inactive; + } + message.data = std::move(data); + sendDataChannelMessage(message); + } + + void sendCandidate(const cricket::Candidate &candidate) { + cricket::Candidate patchedCandidate = candidate; + patchedCandidate.set_component(1); + + signaling_4_0_0::CandidatesMessage data; + + signaling_4_0_0::IceCandidate serializedCandidate; + + webrtc::JsepIceCandidate iceCandidate{ std::string(), 0 }; + iceCandidate.SetCandidate(patchedCandidate); + std::string serialized; + const auto success = iceCandidate.ToString(&serialized); + assert(success); + (void)success; + + serializedCandidate.sdpString = serialized; + + data.iceCandidates.push_back(std::move(serializedCandidate)); + + signaling_4_0_0::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + + void setVideoCapture(std::shared_ptr videoCapture) { + auto videoCaptureImpl = GetVideoCaptureAssumingSameThread(videoCapture.get()); + if (videoCaptureImpl) { + if (videoCaptureImpl->isScreenCapture()) { + _videoCapture = nullptr; + _screencastCapture = videoCapture; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(nullptr); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(videoCapture); + } + + sendMediaState(); + adjustBitratePreferences(true); + } else { + _videoCapture = videoCapture; + _screencastCapture = nullptr; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(videoCapture); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(nullptr); + } + + sendMediaState(); + adjustBitratePreferences(true); + } + } else { + _videoCapture = nullptr; + _screencastCapture = nullptr; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(nullptr); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(nullptr); + } + + sendMediaState(); + adjustBitratePreferences(true); + } + } + + void setRequestedVideoAspect(float aspect) { + } + + void setNetworkType(NetworkType networkType) { + + } + + void setMuteMicrophone(bool muteMicrophone) { + if (_isMicrophoneMuted != muteMicrophone) { + _isMicrophoneMuted = muteMicrophone; + + if (_outgoingAudioChannel) { + _outgoingAudioChannel->setIsMuted(muteMicrophone); + } + + sendMediaState(); + } + } + + void setIncomingVideoOutput(std::weak_ptr> sink) { + _currentSink = sink; + if (_incomingVideoChannel) { + _incomingVideoChannel->addSink(sink); + } + if (_incomingScreencastChannel) { + _incomingScreencastChannel->addSink(sink); + } + } + + void setAudioInputDevice(std::string id) { + + } + + void setAudioOutputDevice(std::string id) { + + } + + void setIsLowBatteryLevel(bool isLowBatteryLevel) { + if (_isBatteryLow != isLowBatteryLevel) { + _isBatteryLow = isLowBatteryLevel; + sendMediaState(); + } + } + + void stop(std::function completion) { + completion({}); + } + + void adjustBitratePreferences(bool resetStartBitrate) { + webrtc::BitrateConstraints preferences; + if (_videoCapture || _screencastCapture) { + preferences.min_bitrate_bps = 64000; + if (resetStartBitrate) { + preferences.start_bitrate_bps = (100 + 800 + 32 + 100) * 1000; + } + preferences.max_bitrate_bps = (100 + 200 + 800 + 32 + 100) * 1000; + } else { + preferences.min_bitrate_bps = 32000; + if (resetStartBitrate) { + preferences.start_bitrate_bps = 32000; + } + preferences.max_bitrate_bps = 32000; + } + + _call->GetTransportControllerSend()->SetSdpBitrateParameters(preferences); + } + +private: + rtc::scoped_refptr createAudioDeviceModule() { + const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { +#ifdef WEBRTC_IOS + return rtc::make_ref_counted(false, false, 1); +#else + return webrtc::AudioDeviceModule::Create( + layer, + _taskQueueFactory.get()); +#endif + }; + const auto check = [&](const rtc::scoped_refptr &result) { + return (result && result->Init() == 0) ? result : nullptr; + }; + if (_createAudioDeviceModule) { + if (const auto result = check(_createAudioDeviceModule(_taskQueueFactory.get()))) { + return result; + } + } + return check(create(webrtc::AudioDeviceModule::kPlatformDefaultAudio)); + } + +private: + std::shared_ptr _threads; + std::vector _rtcServers; + EncryptionKey _encryptionKey; + std::function _stateUpdated; + std::function _signalBarsUpdated; + std::function _audioLevelUpdated; + std::function _remoteBatteryLevelIsLowUpdated; + std::function _remoteMediaStateUpdated; + std::function _remotePrefferedAspectRatioUpdated; + std::function &)> _signalingDataEmitted; + std::function(webrtc::TaskQueueFactory*)> _createAudioDeviceModule; + + std::unique_ptr _signalingEncryption; + + bool _handshakeCompleted = false; + std::vector _pendingIceCandidates; + bool _isDataChannelOpen = false; + + std::unique_ptr _eventLog; + std::unique_ptr _taskQueueFactory; + std::unique_ptr _mediaEngine; + std::unique_ptr _call; + webrtc::FieldTrialBasedConfig _fieldTrials; + webrtc::LocalAudioSinkAdapter _audioSource; + rtc::scoped_refptr _audioDeviceModule; + + std::unique_ptr _uniqueRandomIdGenerator; + webrtc::RtpTransport *_rtpTransport = nullptr; + std::unique_ptr _channelManager; + std::unique_ptr _videoBitrateAllocatorFactory; + + std::shared_ptr> _networking; + + absl::optional _outgoingAudioContent; + absl::optional> _negotiatedOutgoingAudioContent; + + std::unique_ptr _outgoingAudioChannel; + bool _isMicrophoneMuted = false; + + std::vector _availableVideoFormats; + + absl::optional _outgoingVideoContent; + absl::optional> _negotiatedOutgoingVideoContent; + + absl::optional _outgoingScreencastContent; + absl::optional> _negotiatedOutgoingScreencastContent; + + std::shared_ptr _outgoingVideoChannel; + std::shared_ptr _outgoingScreencastChannel; + + bool _isBatteryLow = false; + + std::unique_ptr _incomingAudioChannel; + std::unique_ptr _incomingVideoChannel; + std::unique_ptr _incomingScreencastChannel; + + std::weak_ptr> _currentSink; + + std::shared_ptr _videoCapture; + std::shared_ptr _screencastCapture; + std::shared_ptr _platformContext; +}; + +InstanceV2_4_0_0Impl::InstanceV2_4_0_0Impl(Descriptor &&descriptor) { + if (descriptor.config.logPath.data.size() != 0) { + _logSink = std::make_unique(descriptor.config.logPath); + } + rtc::LogMessage::LogToDebug(rtc::LS_INFO); + rtc::LogMessage::SetLogToStderr(false); + if (_logSink) { + rtc::LogMessage::AddLogToStream(_logSink.get(), rtc::LS_INFO); + } + + _threads = StaticThreads::getThreads(); + _internal.reset(new ThreadLocalObject(_threads->getMediaThread(), [descriptor = std::move(descriptor), threads = _threads]() mutable { + return new InstanceV2_4_0_0ImplInternal(std::move(descriptor), threads); + })); + _internal->perform(RTC_FROM_HERE, [](InstanceV2_4_0_0ImplInternal *internal) { + internal->start(); + }); +} + +InstanceV2_4_0_0Impl::~InstanceV2_4_0_0Impl() { + rtc::LogMessage::RemoveLogToStream(_logSink.get()); +} + +void InstanceV2_4_0_0Impl::receiveSignalingData(const std::vector &data) { + _internal->perform(RTC_FROM_HERE, [data](InstanceV2_4_0_0ImplInternal *internal) { + internal->receiveSignalingData(data); + }); +} + +void InstanceV2_4_0_0Impl::setVideoCapture(std::shared_ptr videoCapture) { + _internal->perform(RTC_FROM_HERE, [videoCapture](InstanceV2_4_0_0ImplInternal *internal) { + internal->setVideoCapture(videoCapture); + }); +} + +void InstanceV2_4_0_0Impl::setRequestedVideoAspect(float aspect) { + _internal->perform(RTC_FROM_HERE, [aspect](InstanceV2_4_0_0ImplInternal *internal) { + internal->setRequestedVideoAspect(aspect); + }); +} + +void InstanceV2_4_0_0Impl::setNetworkType(NetworkType networkType) { + _internal->perform(RTC_FROM_HERE, [networkType](InstanceV2_4_0_0ImplInternal *internal) { + internal->setNetworkType(networkType); + }); +} + +void InstanceV2_4_0_0Impl::setMuteMicrophone(bool muteMicrophone) { + _internal->perform(RTC_FROM_HERE, [muteMicrophone](InstanceV2_4_0_0ImplInternal *internal) { + internal->setMuteMicrophone(muteMicrophone); + }); +} + +void InstanceV2_4_0_0Impl::setIncomingVideoOutput(std::shared_ptr> sink) { + _internal->perform(RTC_FROM_HERE, [sink](InstanceV2_4_0_0ImplInternal *internal) { + internal->setIncomingVideoOutput(sink); + }); +} + +void InstanceV2_4_0_0Impl::setAudioInputDevice(std::string id) { + _internal->perform(RTC_FROM_HERE, [id](InstanceV2_4_0_0ImplInternal *internal) { + internal->setAudioInputDevice(id); + }); +} + +void InstanceV2_4_0_0Impl::setAudioOutputDevice(std::string id) { + _internal->perform(RTC_FROM_HERE, [id](InstanceV2_4_0_0ImplInternal *internal) { + internal->setAudioOutputDevice(id); + }); +} + +void InstanceV2_4_0_0Impl::setIsLowBatteryLevel(bool isLowBatteryLevel) { + _internal->perform(RTC_FROM_HERE, [isLowBatteryLevel](InstanceV2_4_0_0ImplInternal *internal) { + internal->setIsLowBatteryLevel(isLowBatteryLevel); + }); +} + +void InstanceV2_4_0_0Impl::setInputVolume(float level) { +} + +void InstanceV2_4_0_0Impl::setOutputVolume(float level) { +} + +void InstanceV2_4_0_0Impl::setAudioOutputDuckingEnabled(bool enabled) { +} + +void InstanceV2_4_0_0Impl::setAudioOutputGainControlEnabled(bool enabled) { +} + +void InstanceV2_4_0_0Impl::setEchoCancellationStrength(int strength) { +} + +std::vector InstanceV2_4_0_0Impl::GetVersions() { + std::vector result; + result.push_back("4.0.0"); + return result; +} + +int InstanceV2_4_0_0Impl::GetConnectionMaxLayer() { + return 92; +} + +std::string InstanceV2_4_0_0Impl::getLastError() { + return ""; +} + +std::string InstanceV2_4_0_0Impl::getDebugInfo() { + return ""; +} + +int64_t InstanceV2_4_0_0Impl::getPreferredRelayId() { + return 0; +} + +TrafficStats InstanceV2_4_0_0Impl::getTrafficStats() { + return {}; +} + +PersistentState InstanceV2_4_0_0Impl::getPersistentState() { + return {}; +} + +void InstanceV2_4_0_0Impl::stop(std::function completion) { + std::string debugLog; + if (_logSink) { + debugLog = _logSink->result(); + } + _internal->perform(RTC_FROM_HERE, [completion, debugLog = std::move(debugLog)](InstanceV2_4_0_0ImplInternal *internal) mutable { + internal->stop([completion, debugLog = std::move(debugLog)](FinalState finalState) mutable { + finalState.debugLog = debugLog; + completion(finalState); + }); + }); +} + +template <> +bool Register() { + return Meta::RegisterOne(); +} + +} // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h new file mode 100644 index 000000000..1a892de4b --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h @@ -0,0 +1,59 @@ +#ifndef TGCALLS_INSTANCEV2_4_0_0_IMPL_H +#define TGCALLS_INSTANCEV2_4_0_0_IMPL_H + +#include "Instance.h" +#include "StaticThreads.h" + +namespace tgcalls { + +class LogSinkImpl; + +class Manager; +template +class ThreadLocalObject; + +class InstanceV2_4_0_0ImplInternal; + +class InstanceV2_4_0_0Impl final : public Instance { +public: + explicit InstanceV2_4_0_0Impl(Descriptor &&descriptor); + ~InstanceV2_4_0_0Impl() override; + + void receiveSignalingData(const std::vector &data) override; + void setVideoCapture(std::shared_ptr videoCapture) override; + void setRequestedVideoAspect(float aspect) override; + void setNetworkType(NetworkType networkType) override; + void setMuteMicrophone(bool muteMicrophone) override; + bool supportsVideo() override { + return true; + } + void setIncomingVideoOutput(std::shared_ptr> sink) override; + void setAudioOutputGainControlEnabled(bool enabled) override; + void setEchoCancellationStrength(int strength) override; + void setAudioInputDevice(std::string id) override; + void setAudioOutputDevice(std::string id) override; + void setInputVolume(float level) override; + void setOutputVolume(float level) override; + void setAudioOutputDuckingEnabled(bool enabled) override; + void setIsLowBatteryLevel(bool isLowBatteryLevel) override; + static std::vector GetVersions(); + static int GetConnectionMaxLayer(); + std::string getLastError() override; + std::string getDebugInfo() override; + int64_t getPreferredRelayId() override; + TrafficStats getTrafficStats() override; + PersistentState getPersistentState() override; + void stop(std::function completion) override; + void sendVideoDeviceUpdated() override { + } + +private: + std::shared_ptr _threads; + std::unique_ptr> _internal; + std::unique_ptr _logSink; + +}; + +} // namespace tgcalls + +#endif diff --git a/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp new file mode 100644 index 000000000..7d80f022c --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp @@ -0,0 +1,705 @@ +#include "v2_4_0_0/Signaling_4_0_0.h" + +#include "third-party/json11.hpp" + +#include "rtc_base/checks.h" + +#include + +namespace tgcalls { +namespace signaling_4_0_0 { + +static std::string uint32ToString(uint32_t value) { + std::ostringstream stringStream; + stringStream << value; + return stringStream.str(); +} + +static uint32_t stringToUInt32(std::string const &string) { + std::stringstream stringStream(string); + uint32_t value = 0; + stringStream >> value; + return value; +} + +json11::Json::object SsrcGroup_serialize(SsrcGroup const &ssrcGroup) { + json11::Json::object object; + + json11::Json::array ssrcs; + for (auto ssrc : ssrcGroup.ssrcs) { + ssrcs.push_back(json11::Json(uint32ToString(ssrc))); + } + object.insert(std::make_pair("semantics", json11::Json(ssrcGroup.semantics))); + object.insert(std::make_pair("ssrcs", json11::Json(std::move(ssrcs)))); + + return object; +} + +absl::optional SsrcGroup_parse(json11::Json::object const &object) { + SsrcGroup result; + + const auto semantics = object.find("semantics"); + if (semantics == object.end() || !semantics->second.is_string()) { + return absl::nullopt; + } + result.semantics = semantics->second.string_value(); + + const auto ssrcs = object.find("ssrcs"); + if (ssrcs == object.end() || !ssrcs->second.is_array()) { + return absl::nullopt; + } + for (const auto &ssrc : ssrcs->second.array_items()) { + if (ssrc.is_string()) { + uint32_t parsedSsrc = stringToUInt32(ssrc.string_value()); + if (parsedSsrc == 0) { + return absl::nullopt; + } + result.ssrcs.push_back(parsedSsrc); + } else if (ssrc.is_number()) { + uint32_t parsedSsrc = (uint32_t)ssrc.number_value(); + result.ssrcs.push_back(parsedSsrc); + } else { + return absl::nullopt; + } + } + + return result; +} + +json11::Json::object FeedbackType_serialize(FeedbackType const &feedbackType) { + json11::Json::object object; + + object.insert(std::make_pair("type", json11::Json(feedbackType.type))); + object.insert(std::make_pair("subtype", json11::Json(feedbackType.subtype))); + + return object; +} + +absl::optional FeedbackType_parse(json11::Json::object const &object) { + FeedbackType result; + + const auto type = object.find("type"); + if (type == object.end() || !type->second.is_string()) { + return absl::nullopt; + } + result.type = type->second.string_value(); + + const auto subtype = object.find("subtype"); + if (subtype == object.end() || !subtype->second.is_string()) { + return absl::nullopt; + } + result.subtype = subtype->second.string_value(); + + return result; +} + +json11::Json::object RtpExtension_serialize(webrtc::RtpExtension const &rtpExtension) { + json11::Json::object object; + + object.insert(std::make_pair("id", json11::Json(rtpExtension.id))); + object.insert(std::make_pair("uri", json11::Json(rtpExtension.uri))); + + return object; +} + +absl::optional RtpExtension_parse(json11::Json::object const &object) { + const auto id = object.find("id"); + if (id == object.end() || !id->second.is_number()) { + return absl::nullopt; + } + + const auto uri = object.find("uri"); + if (uri == object.end() || !uri->second.is_string()) { + return absl::nullopt; + } + + return webrtc::RtpExtension(uri->second.string_value(), id->second.int_value()); +} + +json11::Json::object PayloadType_serialize(PayloadType const &payloadType) { + json11::Json::object object; + + object.insert(std::make_pair("id", json11::Json((int)payloadType.id))); + object.insert(std::make_pair("name", json11::Json(payloadType.name))); + object.insert(std::make_pair("clockrate", json11::Json((int)payloadType.clockrate))); + object.insert(std::make_pair("channels", json11::Json((int)payloadType.channels))); + + json11::Json::array feedbackTypes; + for (const auto &feedbackType : payloadType.feedbackTypes) { + feedbackTypes.push_back(FeedbackType_serialize(feedbackType)); + } + object.insert(std::make_pair("feedbackTypes", json11::Json(std::move(feedbackTypes)))); + + json11::Json::object parameters; + for (auto it : payloadType.parameters) { + parameters.insert(std::make_pair(it.first, json11::Json(it.second))); + } + object.insert(std::make_pair("parameters", json11::Json(std::move(parameters)))); + + return object; +} + +absl::optional PayloadType_parse(json11::Json::object const &object) { + PayloadType result; + + const auto id = object.find("id"); + if (id == object.end() || !id->second.is_number()) { + return absl::nullopt; + } + result.id = id->second.int_value(); + + const auto name = object.find("name"); + if (name == object.end() || !name->second.is_string()) { + return absl::nullopt; + } + result.name = name->second.string_value(); + + const auto clockrate = object.find("clockrate"); + if (clockrate == object.end() || !clockrate->second.is_number()) { + return absl::nullopt; + } + result.clockrate = clockrate->second.int_value(); + + const auto channels = object.find("channels"); + if (channels != object.end()) { + if (!channels->second.is_number()) { + return absl::nullopt; + } + result.channels = channels->second.int_value(); + } + + const auto feedbackTypes = object.find("feedbackTypes"); + if (feedbackTypes != object.end()) { + if (!feedbackTypes->second.is_array()) { + return absl::nullopt; + } + for (const auto &feedbackType : feedbackTypes->second.array_items()) { + if (!feedbackType.is_object()) { + return absl::nullopt; + } + if (const auto parsedFeedbackType = FeedbackType_parse(feedbackType.object_items())) { + result.feedbackTypes.push_back(parsedFeedbackType.value()); + } else { + return absl::nullopt; + } + } + } + + const auto parameters = object.find("parameters"); + if (parameters != object.end()) { + if (!parameters->second.is_object()) { + return absl::nullopt; + } + for (const auto &item : parameters->second.object_items()) { + if (!item.second.is_string()) { + return absl::nullopt; + } + result.parameters.push_back(std::make_pair(item.first, item.second.string_value())); + } + } + + return result; +} + +json11::Json::object MediaContent_serialize(MediaContent const &mediaContent) { + json11::Json::object object; + + object.insert(std::make_pair("ssrc", json11::Json(uint32ToString(mediaContent.ssrc)))); + + if (mediaContent.ssrcGroups.size() != 0) { + json11::Json::array ssrcGroups; + for (const auto &group : mediaContent.ssrcGroups) { + ssrcGroups.push_back(SsrcGroup_serialize(group)); + } + object.insert(std::make_pair("ssrcGroups", json11::Json(std::move(ssrcGroups)))); + } + + if (mediaContent.payloadTypes.size() != 0) { + json11::Json::array payloadTypes; + for (const auto &payloadType : mediaContent.payloadTypes) { + payloadTypes.push_back(PayloadType_serialize(payloadType)); + } + object.insert(std::make_pair("payloadTypes", json11::Json(std::move(payloadTypes)))); + } + + json11::Json::array rtpExtensions; + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + rtpExtensions.push_back(RtpExtension_serialize(rtpExtension)); + } + object.insert(std::make_pair("rtpExtensions", json11::Json(std::move(rtpExtensions)))); + + return object; +} + +absl::optional MediaContent_parse(json11::Json::object const &object) { + MediaContent result; + + const auto ssrc = object.find("ssrc"); + if (ssrc == object.end()) { + return absl::nullopt; + } + if (ssrc->second.is_string()) { + result.ssrc = stringToUInt32(ssrc->second.string_value()); + } else if (ssrc->second.is_number()) { + result.ssrc = (uint32_t)ssrc->second.number_value(); + } else { + return absl::nullopt; + } + + const auto ssrcGroups = object.find("ssrcGroups"); + if (ssrcGroups != object.end()) { + if (!ssrcGroups->second.is_array()) { + return absl::nullopt; + } + for (const auto &ssrcGroup : ssrcGroups->second.array_items()) { + if (!ssrcGroup.is_object()) { + return absl::nullopt; + } + if (const auto parsedSsrcGroup = SsrcGroup_parse(ssrcGroup.object_items())) { + result.ssrcGroups.push_back(parsedSsrcGroup.value()); + } else { + return absl::nullopt; + } + } + } + + const auto payloadTypes = object.find("payloadTypes"); + if (payloadTypes != object.end()) { + if (!payloadTypes->second.is_array()) { + return absl::nullopt; + } + for (const auto &payloadType : payloadTypes->second.array_items()) { + if (!payloadType.is_object()) { + return absl::nullopt; + } + if (const auto parsedPayloadType = PayloadType_parse(payloadType.object_items())) { + result.payloadTypes.push_back(parsedPayloadType.value()); + } else { + return absl::nullopt; + } + } + } + + const auto rtpExtensions = object.find("rtpExtensions"); + if (rtpExtensions != object.end()) { + if (!rtpExtensions->second.is_array()) { + return absl::nullopt; + } + for (const auto &rtpExtension : rtpExtensions->second.array_items()) { + if (!rtpExtension.is_object()) { + return absl::nullopt; + } + if (const auto parsedRtpExtension = RtpExtension_parse(rtpExtension.object_items())) { + result.rtpExtensions.push_back(parsedRtpExtension.value()); + } else { + return absl::nullopt; + } + } + } + + return result; +} + +std::vector InitialSetupMessage_serialize(const InitialSetupMessage * const message) { + json11::Json::object object; + + object.insert(std::make_pair("@type", json11::Json("InitialSetup"))); + object.insert(std::make_pair("ufrag", json11::Json(message->ufrag))); + object.insert(std::make_pair("pwd", json11::Json(message->pwd))); + + json11::Json::array jsonFingerprints; + for (const auto &fingerprint : message->fingerprints) { + json11::Json::object jsonFingerprint; + jsonFingerprint.insert(std::make_pair("hash", json11::Json(fingerprint.hash))); + jsonFingerprint.insert(std::make_pair("setup", json11::Json(fingerprint.setup))); + jsonFingerprint.insert(std::make_pair("fingerprint", json11::Json(fingerprint.fingerprint))); + jsonFingerprints.emplace_back(std::move(jsonFingerprint)); + } + object.insert(std::make_pair("fingerprints", json11::Json(std::move(jsonFingerprints)))); + + if (const auto audio = message->audio) { + object.insert(std::make_pair("audio", json11::Json(MediaContent_serialize(audio.value())))); + } + + if (const auto video = message->video) { + object.insert(std::make_pair("video", json11::Json(MediaContent_serialize(video.value())))); + } + + if (const auto screencast = message->screencast) { + object.insert(std::make_pair("screencast", json11::Json(MediaContent_serialize(screencast.value())))); + } + + auto json = json11::Json(std::move(object)); + std::string result = json.dump(); + return std::vector(result.begin(), result.end()); +} + +absl::optional InitialSetupMessage_parse(json11::Json::object const &object) { + const auto ufrag = object.find("ufrag"); + if (ufrag == object.end() || !ufrag->second.is_string()) { + return absl::nullopt; + } + const auto pwd = object.find("pwd"); + if (pwd == object.end() || !pwd->second.is_string()) { + return absl::nullopt; + } + const auto fingerprints = object.find("fingerprints"); + if (fingerprints == object.end() || !fingerprints->second.is_array()) { + return absl::nullopt; + } + std::vector parsedFingerprints; + for (const auto &fingerprintObject : fingerprints->second.array_items()) { + if (!fingerprintObject.is_object()) { + return absl::nullopt; + } + const auto hash = fingerprintObject.object_items().find("hash"); + if (hash == fingerprintObject.object_items().end() || !hash->second.is_string()) { + return absl::nullopt; + } + const auto setup = fingerprintObject.object_items().find("setup"); + if (setup == fingerprintObject.object_items().end() || !setup->second.is_string()) { + return absl::nullopt; + } + const auto fingerprint = fingerprintObject.object_items().find("fingerprint"); + if (fingerprint == fingerprintObject.object_items().end() || !fingerprint->second.is_string()) { + return absl::nullopt; + } + + DtlsFingerprint parsedFingerprint; + parsedFingerprint.hash = hash->second.string_value(); + parsedFingerprint.setup = setup->second.string_value(); + parsedFingerprint.fingerprint = fingerprint->second.string_value(); + + parsedFingerprints.push_back(std::move(parsedFingerprint)); + } + + InitialSetupMessage message; + message.ufrag = ufrag->second.string_value(); + message.pwd = pwd->second.string_value(); + message.fingerprints = std::move(parsedFingerprints); + + const auto audio = object.find("audio"); + if (audio != object.end()) { + if (!audio->second.is_object()) { + return absl::nullopt; + } + if (const auto parsedAudio = MediaContent_parse(audio->second.object_items())) { + message.audio = parsedAudio.value(); + } else { + return absl::nullopt; + } + } + + const auto video = object.find("video"); + if (video != object.end()) { + if (!video->second.is_object()) { + return absl::nullopt; + } + if (const auto parsedVideo = MediaContent_parse(video->second.object_items())) { + message.video = parsedVideo.value(); + } else { + return absl::nullopt; + } + } + + const auto screencast = object.find("screencast"); + if (screencast != object.end()) { + if (!screencast->second.is_object()) { + return absl::nullopt; + } + if (const auto parsedScreencast = MediaContent_parse(screencast->second.object_items())) { + message.screencast = parsedScreencast.value(); + } else { + return absl::nullopt; + } + } + + return message; +} + +json11::Json::object ConnectionAddress_serialize(ConnectionAddress const &connectionAddress) { + json11::Json::object object; + + object.insert(std::make_pair("ip", json11::Json(connectionAddress.ip))); + object.insert(std::make_pair("port", json11::Json(connectionAddress.port))); + + return object; +} + +absl::optional ConnectionAddress_parse(json11::Json::object const &object) { + const auto ip = object.find("ip"); + if (ip == object.end() || !ip->second.is_string()) { + return absl::nullopt; + } + + const auto port = object.find("port"); + if (port == object.end() || !port->second.is_number()) { + return absl::nullopt; + } + + ConnectionAddress address; + address.ip = ip->second.string_value(); + address.port = port->second.int_value(); + return address; +} + +std::vector CandidatesMessage_serialize(const CandidatesMessage * const message) { + json11::Json::array candidates; + for (const auto &candidate : message->iceCandidates) { + json11::Json::object candidateObject; + + candidateObject.insert(std::make_pair("sdpString", json11::Json(candidate.sdpString))); + + candidates.emplace_back(std::move(candidateObject)); + } + + json11::Json::object object; + + object.insert(std::make_pair("@type", json11::Json("Candidates"))); + object.insert(std::make_pair("candidates", json11::Json(std::move(candidates)))); + + auto json = json11::Json(std::move(object)); + std::string result = json.dump(); + return std::vector(result.begin(), result.end()); +} + +absl::optional CandidatesMessage_parse(json11::Json::object const &object) { + const auto candidates = object.find("candidates"); + if (candidates == object.end() || !candidates->second.is_array()) { + return absl::nullopt; + } + + std::vector parsedCandidates; + for (const auto &candidateObject : candidates->second.array_items()) { + if (!candidateObject.is_object()) { + return absl::nullopt; + } + + IceCandidate candidate; + + const auto sdpString = candidateObject.object_items().find("sdpString"); + if (sdpString == candidateObject.object_items().end() || !sdpString->second.is_string()) { + return absl::nullopt; + } + candidate.sdpString = sdpString->second.string_value(); + + parsedCandidates.push_back(std::move(candidate)); + } + + CandidatesMessage message; + message.iceCandidates = std::move(parsedCandidates); + + return message; +} + +std::vector MediaStateMessage_serialize(const MediaStateMessage * const message) { + json11::Json::object object; + + object.insert(std::make_pair("@type", json11::Json("MediaState"))); + object.insert(std::make_pair("muted", json11::Json(message->isMuted))); + object.insert(std::make_pair("lowBattery", json11::Json(message->isBatteryLow))); + + std::string videoStateValue; + switch (message->videoState) { + case MediaStateMessage::VideoState::Inactive: { + videoStateValue = "inactive"; + break; + } + case MediaStateMessage::VideoState::Suspended: { + videoStateValue = "suspended"; + break; + } + case MediaStateMessage::VideoState::Active: { + videoStateValue = "active"; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + object.insert(std::make_pair("videoState", json11::Json(videoStateValue))); + + int videoRotationValue = 0; + switch (message->videoRotation) { + case MediaStateMessage::VideoRotation::Rotation0: { + videoRotationValue = 0; + break; + } + case MediaStateMessage::VideoRotation::Rotation90: { + videoRotationValue = 90; + break; + } + case MediaStateMessage::VideoRotation::Rotation180: { + videoRotationValue = 180; + break; + } + case MediaStateMessage::VideoRotation::Rotation270: { + videoRotationValue = 270; + break; + } + default: { + RTC_FATAL() << "Unknown videoRotation"; + break; + } + } + object.insert(std::make_pair("videoRotation", json11::Json(videoRotationValue))); + + std::string screencastStateValue; + switch (message->screencastState) { + case MediaStateMessage::VideoState::Inactive: { + screencastStateValue = "inactive"; + break; + } + case MediaStateMessage::VideoState::Suspended: { + screencastStateValue = "suspended"; + break; + } + case MediaStateMessage::VideoState::Active: { + screencastStateValue = "active"; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + object.insert(std::make_pair("screencastState", json11::Json(screencastStateValue))); + + auto json = json11::Json(std::move(object)); + std::string result = json.dump(); + return std::vector(result.begin(), result.end()); +} + +absl::optional MediaStateMessage_parse(json11::Json::object const &object) { + MediaStateMessage message; + + const auto muted = object.find("muted"); + if (muted != object.end()) { + if (!muted->second.is_bool()) { + return absl::nullopt; + } + message.isMuted = muted->second.bool_value(); + } + + const auto lowBattery = object.find("lowBattery"); + if (lowBattery != object.end()) { + if (!lowBattery->second.is_bool()) { + return absl::nullopt; + } + message.isBatteryLow = lowBattery->second.bool_value(); + } + + const auto videoState = object.find("videoState"); + if (videoState != object.end()) { + if (!videoState->second.is_string()) { + return absl::nullopt; + } + if (videoState->second.string_value() == "inactive") { + message.videoState = MediaStateMessage::VideoState::Inactive; + } else if (videoState->second.string_value() == "suspended") { + message.videoState = MediaStateMessage::VideoState::Suspended; + } else if (videoState->second.string_value() == "active") { + message.videoState = MediaStateMessage::VideoState::Active; + } + } else { + message.videoState = MediaStateMessage::VideoState::Inactive; + } + + const auto screencastState = object.find("screencastState"); + if (screencastState != object.end()) { + if (!screencastState->second.is_string()) { + return absl::nullopt; + } + if (screencastState->second.string_value() == "inactive") { + message.screencastState = MediaStateMessage::VideoState::Inactive; + } else if (screencastState->second.string_value() == "suspended") { + message.screencastState = MediaStateMessage::VideoState::Suspended; + } else if (screencastState->second.string_value() == "active") { + message.screencastState = MediaStateMessage::VideoState::Active; + } + } else { + message.screencastState = MediaStateMessage::VideoState::Inactive; + } + + const auto videoRotation = object.find("videoRotation"); + if (videoRotation != object.end()) { + if (!videoRotation->second.is_number()) { + return absl::nullopt; + } + if (videoState->second.int_value() == 0) { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation0; + } else if (videoState->second.int_value() == 90) { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation90; + } else if (videoState->second.int_value() == 180) { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation180; + } else if (videoState->second.int_value() == 270) { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation270; + } else { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation0; + } + } else { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation0; + } + + return message; +} + +std::vector Message::serialize() const { + if (const auto initialSetup = absl::get_if(&data)) { + return InitialSetupMessage_serialize(initialSetup); + } else if (const auto candidates = absl::get_if(&data)) { + return CandidatesMessage_serialize(candidates); + } else if (const auto mediaState = absl::get_if(&data)) { + return MediaStateMessage_serialize(mediaState); + } else { + return {}; + } +} + +absl::optional Message::parse(const std::vector &data) { + std::string parsingError; + auto json = json11::Json::parse(std::string(data.begin(), data.end()), parsingError); + if (json.type() != json11::Json::OBJECT) { + return absl::nullopt; + } + + auto type = json.object_items().find("@type"); + if (type == json.object_items().end()) { + return absl::nullopt; + } + if (!type->second.is_string()) { + return absl::nullopt; + } + if (type->second.string_value() == "InitialSetup") { + auto parsed = InitialSetupMessage_parse(json.object_items()); + if (!parsed) { + return absl::nullopt; + } + Message message; + message.data = std::move(parsed.value()); + return message; + } else if (type->second.string_value() == "Candidates") { + auto parsed = CandidatesMessage_parse(json.object_items()); + if (!parsed) { + return absl::nullopt; + } + Message message; + message.data = std::move(parsed.value()); + return message; + } else if (type->second.string_value() == "MediaState") { + auto parsed = MediaStateMessage_parse(json.object_items()); + if (!parsed) { + return absl::nullopt; + } + Message message; + message.data = std::move(parsed.value()); + return message; + } else { + return absl::nullopt; + } +} + +} // namespace signaling + +} // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.h b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.h new file mode 100644 index 000000000..75377a86e --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.h @@ -0,0 +1,105 @@ +#ifndef TGCALLS_SIGNALING_4_0_0_H +#define TGCALLS_SIGNALING_4_0_0_H + +#include +#include + +#include "absl/types/variant.h" +#include "absl/types/optional.h" +#include "api/rtp_parameters.h" + +namespace tgcalls { + +namespace signaling_4_0_0 { + +struct DtlsFingerprint { + std::string hash; + std::string setup; + std::string fingerprint; +}; + +struct ConnectionAddress { + std::string ip; + int port = 0; +}; + +struct IceCandidate { + std::string sdpString; +}; + +struct SsrcGroup { + std::vector ssrcs; + std::string semantics; +}; + +struct FeedbackType { + std::string type; + std::string subtype; +}; + +struct PayloadType { + uint32_t id = 0; + std::string name; + uint32_t clockrate = 0; + uint32_t channels = 0; + std::vector feedbackTypes; + std::vector> parameters; +}; + +struct MediaContent { + uint32_t ssrc = 0; + std::vector ssrcGroups; + std::vector payloadTypes; + std::vector rtpExtensions; +}; + +struct InitialSetupMessage { + std::string ufrag; + std::string pwd; + std::vector fingerprints; + absl::optional audio; + absl::optional video; + absl::optional screencast; +}; + +struct CandidatesMessage { + std::vector iceCandidates; +}; + +struct MediaStateMessage { + enum class VideoState { + Inactive, + Suspended, + Active + }; + + enum class VideoRotation { + Rotation0, + Rotation90, + Rotation180, + Rotation270 + }; + + bool isMuted = false; + VideoState videoState = VideoState::Inactive; + VideoRotation videoRotation = VideoRotation::Rotation0; + VideoState screencastState = VideoState::Inactive; + bool isBatteryLow = false; + +}; + +struct Message { + absl::variant< + InitialSetupMessage, + CandidatesMessage, + MediaStateMessage> data; + + std::vector serialize() const; + static absl::optional parse(const std::vector &data); +}; + +}; + +} // namespace tgcalls + +#endif \ No newline at end of file diff --git a/TMessagesProj/jni/voip/webrtc/rtc_base/synchronization/mutex_pthread.h b/TMessagesProj/jni/voip/webrtc/rtc_base/synchronization/mutex_pthread.h index 7d8c17997..90c4a7ffe 100644 --- a/TMessagesProj/jni/voip/webrtc/rtc_base/synchronization/mutex_pthread.h +++ b/TMessagesProj/jni/voip/webrtc/rtc_base/synchronization/mutex_pthread.h @@ -61,6 +61,9 @@ class RTC_LOCKABLE MutexImpl final { owner_.SetOwner(); } ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + if (!mutexEnabled()) { + return false; + } if (pthread_mutex_trylock(&mutex_) != 0) { return false; } diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index 8d2e38bc6..3d17fd82a 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -86,6 +86,7 @@ top) { animateTo = top - botCell.getTop(); diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index d7795d068..4fa7f58e2 100644 --- a/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -330,7 +330,6 @@ public class SimpleExoPlayer extends BasePlayer private final WakeLockManager wakeLockManager; private final WifiLockManager wifiLockManager; - private boolean needSetSurface = true; @Nullable private Format videoFormat; @Nullable private Format audioFormat; @@ -603,7 +602,6 @@ public class SimpleExoPlayer extends BasePlayer clearVideoDecoderOutputBufferRenderer(); } this.textureView = textureView; - needSetSurface = true; if (textureView == null) { setVideoSurfaceInternal(/* surface= */ null, /* ownsSurface= */ true); maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); @@ -1795,10 +1793,6 @@ public class SimpleExoPlayer extends BasePlayer @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { - if (needSetSurface) { - setVideoSurfaceInternal(new Surface(surfaceTexture), true); - needSetSurface = false; - } setVideoSurfaceInternal(new Surface(surfaceTexture), /* ownsSurface= */ true); maybeNotifySurfaceSizeChanged(width, height); } @@ -1817,7 +1811,6 @@ public class SimpleExoPlayer extends BasePlayer } setVideoSurfaceInternal(/* surface= */ null, /* ownsSurface= */ true); maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); - needSetSurface = true; return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index e975c2dd8..05bd16af4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -64,6 +64,7 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.text.util.Linkify; import android.util.DisplayMetrics; @@ -94,6 +95,7 @@ import android.widget.ListView; import android.widget.ScrollView; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.core.content.FileProvider; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; @@ -210,6 +212,7 @@ public class AndroidUtilities { public static Pattern BAD_CHARS_PATTERN = null; public static Pattern BAD_CHARS_MESSAGE_PATTERN = null; public static Pattern BAD_CHARS_MESSAGE_LONG_PATTERN = null; + private static Pattern singleTagPatter = null; static { try { @@ -403,6 +406,35 @@ public class AndroidUtilities { return null; } + public static CharSequence replaceSingleTag(String str, Runnable runnable) { + int startIndex = str.indexOf("**"); + int endIndex = str.indexOf("**", startIndex + 1); + str = str.replace("**", ""); + int index = -1; + int len = 0; + if (startIndex >= 0 && endIndex >= 0 && endIndex - startIndex > 2) { + len = endIndex - startIndex - 2; + index = startIndex; + } + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str); + if (index >= 0) { + spannableStringBuilder.setSpan(new ClickableSpan() { + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + + @Override + public void onClick(@NonNull View view) { + runnable.run(); + } + }, index, index + len, 0); + } + return spannableStringBuilder; + } + private static class LinkSpec { String url; int start; @@ -2423,11 +2455,11 @@ public class AndroidUtilities { } public static void appCenterLog(Throwable e) { - + } public static boolean shouldShowClipboardToast() { - return Build.VERSION.SDK_INT < Build.VERSION_CODES.S || !OneUIUtilities.isOneUI(); + return Build.VERSION.SDK_INT < Build.VERSION_CODES.S || !OneUIUtilities.hasBuiltInClipboardToasts(); } public static void addToClipboard(CharSequence str) { @@ -3954,26 +3986,38 @@ public class AndroidUtilities { return false; } - public static void setLightNavigationBar(Window window, boolean enable) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - final View decorView = window.getDecorView(); - int flags = decorView.getSystemUiVisibility(); + public static void setLightNavigationBar(View view, boolean enable) { + if (view != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + int flags = view.getSystemUiVisibility(); if (enable) { flags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; } else { flags &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; } - decorView.setSystemUiVisibility(flags); + view.setSystemUiVisibility(flags); + } + } + + public static void setLightNavigationBar(Window window, boolean enable) { + if (window != null) { + setLightNavigationBar(window.getDecorView(), enable); } } private static HashMap navigationBarColorAnimators; + public interface IntColorCallback { + public void run(int color); + } public static void setNavigationBarColor(Window window, int color) { setNavigationBarColor(window, color, true); } public static void setNavigationBarColor(Window window, int color, boolean animated) { + setNavigationBarColor(window, color, animated, null); + } + + public static void setNavigationBarColor(Window window, int color, boolean animated, IntColorCallback onUpdate) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (navigationBarColorAnimators != null) { ValueAnimator animator = navigationBarColorAnimators.get(window); @@ -3984,10 +4028,23 @@ public class AndroidUtilities { } if (!animated) { - window.setNavigationBarColor(color); + if (onUpdate != null) { + onUpdate.run(color); + } + try { + window.setNavigationBarColor(color); + } catch (Exception ignore) {} } else { ValueAnimator animator = ValueAnimator.ofArgb(window.getNavigationBarColor(), color); - animator.addUpdateListener(a -> window.setNavigationBarColor((int) a.getAnimatedValue())); + animator.addUpdateListener(a -> { + int tcolor = (int) a.getAnimatedValue(); + if (onUpdate != null) { + onUpdate.run(tcolor); + } + try { + window.setNavigationBarColor(tcolor); + } catch (Exception ignore) {} + }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -4207,7 +4264,7 @@ public class AndroidUtilities { bitmap.compress(format, 100, out); out.close(); return FileProvider.getUriForFile(ApplicationLoader.applicationContext, BuildConfig.APPLICATION_ID + ".provider", file); - } catch (IOException e) { + } catch (Exception e) { FileLog.e(e); } return null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index 78747ac02..f68809f98 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -150,6 +150,7 @@ public class ApplicationLoader extends Application { } SharedConfig.loadConfig(); + SharedPrefsHelper.init(applicationContext); for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { //TODO improve account UserConfig.getInstance(a).loadConfig(); MessagesController.getInstance(a); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 93ad7ea5d..f9854a56e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -20,8 +20,8 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 2600; - public static String BUILD_VERSION_STRING = "8.6.2"; + public static int BUILD_VERSION = 2622; + public static String BUILD_VERSION_STRING = "8.7.0"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java index 9a5d37123..9d8b8b2af 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java @@ -127,6 +127,7 @@ public class ChatThemeController extends BaseController { private static SharedPreferences getSharedPreferences() { return ApplicationLoader.applicationContext.getSharedPreferences("chatthemeconfig", Context.MODE_PRIVATE); } + private static SharedPreferences getEmojiSharedPreferences() { return ApplicationLoader.applicationContext.getSharedPreferences("chatthemeconfig_emoji", Context.MODE_PRIVATE); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java index 5689864dd..a88454f84 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java @@ -1107,16 +1107,15 @@ public class DownloadController extends BaseController implements NotificationCe public void startDownloadFile(TLRPC.Document document, MessageObject parentObject) { + if (parentObject.getDocument() == null) { + return; + } AndroidUtilities.runOnUIThread(() -> { boolean contains = false; for (int i = 0; i < recentDownloadingFiles.size(); i++) { if (recentDownloadingFiles.get(i).getDocument().id == parentObject.getDocument().id) { - if (parentObject.mediaExists) { - contains = true; - } else { - recentDownloadingFiles.remove(i); - } + contains = true; break; } } @@ -1182,51 +1181,52 @@ public class DownloadController extends BaseController implements NotificationCe putToUnviewedDownloads(parentObject); } getNotificationCenter().postNotificationName(NotificationCenter.onDownloadingFilesChanged); + getMessagesStorage().getStorageQueue().postRunnable(() -> { + try { + String req = String.format(Locale.ENGLISH, "UPDATE downloading_documents SET state = 1, date = %d WHERE hash = %d AND id = %d", System.currentTimeMillis(), parentObject.getDocument().dc_id, parentObject.getDocument().id); + getMessagesStorage().getDatabase().executeFast(req).stepThis().dispose(); + SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT COUNT(*) FROM downloading_documents WHERE state = 1"); + int count = 0; + if (cursor.next()) { + count = cursor.intValue(0); + } + cursor.dispose(); + + cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT state FROM downloading_documents WHERE state = 1"); + if (cursor.next()) { + int state = cursor.intValue(0); + } + cursor.dispose(); + + int limitDownloadsDocuments = 100; + if (count > limitDownloadsDocuments) { + cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT hash, id FROM downloading_documents WHERE state = 1 ORDER BY date ASC LIMIT " + (limitDownloadsDocuments - count)); + ArrayList entriesToRemove = new ArrayList<>(); + while (cursor.next()) { + DownloadingDocumentEntry entry = new DownloadingDocumentEntry(); + entry.hash = cursor.intValue(0); + entry.id = cursor.longValue(1); + entriesToRemove.add(entry); + } + cursor.dispose(); + + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("DELETE FROM downloading_documents WHERE hash = ? AND id = ?"); + for (int i = 0; i < entriesToRemove.size(); i++) { + state.requery(); + state.bindInteger(1, entriesToRemove.get(i).hash); + state.bindLong(2, entriesToRemove.get(i).id); + state.step(); + } + state.dispose(); + } + } catch (Exception e) { + FileLog.e(e); + } + }); } }); - getMessagesStorage().getStorageQueue().postRunnable(() -> { - try { - String req = String.format(Locale.ENGLISH, "UPDATE downloading_documents SET state = 1, date = %d WHERE hash = %d AND id = %d", System.currentTimeMillis(), parentObject.getDocument().dc_id, parentObject.getDocument().id); - getMessagesStorage().getDatabase().executeFast(req).stepThis().dispose(); - SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT COUNT(*) FROM downloading_documents WHERE state = 1"); - int count = 0; - if (cursor.next()) { - count = cursor.intValue(0); - } - cursor.dispose(); - cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT state FROM downloading_documents WHERE state = 1"); - if (cursor.next()) { - int state = cursor.intValue(0); - } - cursor.dispose(); - - int limitDownloadsDocuments = 100; - if (count > limitDownloadsDocuments) { - cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT hash, id FROM downloading_documents WHERE state = 1 ORDER BY date ASC LIMIT " + (limitDownloadsDocuments - count)); - ArrayList entriesToRemove = new ArrayList<>(); - while (cursor.next()) { - DownloadingDocumentEntry entry = new DownloadingDocumentEntry(); - entry.hash = cursor.intValue(0); - entry.id = cursor.longValue(1); - entriesToRemove.add(entry); - } - cursor.dispose(); - - SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("DELETE FROM downloading_documents WHERE hash = ? AND id = ?"); - for (int i = 0; i < entriesToRemove.size(); i++) { - state.requery(); - state.bindInteger(1, entriesToRemove.get(i).hash); - state.bindLong(2, entriesToRemove.get(i).id); - state.step(); - } - state.dispose(); - } - } catch (Exception e) { - FileLog.e(e); - } - }); } public void onDownloadFail(MessageObject parentObject, int reason) { @@ -1264,7 +1264,7 @@ public class DownloadController extends BaseController implements NotificationCe }); } - Runnable clearUnviewedDownloadsRunnbale = new Runnable() { + Runnable clearUnviewedDownloadsRunnale = new Runnable() { @Override public void run() { clearUnviewedDownloads(); @@ -1273,8 +1273,8 @@ public class DownloadController extends BaseController implements NotificationCe }; private void putToUnviewedDownloads(MessageObject parentObject) { unviewedDownloads.put(parentObject.getId(), parentObject); - AndroidUtilities.cancelRunOnUIThread(clearUnviewedDownloadsRunnbale); - AndroidUtilities.runOnUIThread(clearUnviewedDownloadsRunnbale, 60000); + AndroidUtilities.cancelRunOnUIThread(clearUnviewedDownloadsRunnale); + AndroidUtilities.runOnUIThread(clearUnviewedDownloadsRunnale, 60000); } public void clearUnviewedDownloads() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index fa979297e..644668e13 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -31,7 +31,7 @@ public class FileLoader extends BaseController { void fileUploadProgressChanged(FileUploadOperation operation, String location, long uploadedSize, long totalSize, boolean isEncrypted); void fileDidUploaded(String location, TLRPC.InputFile inputFile, TLRPC.InputEncryptedFile inputEncryptedFile, byte[] key, byte[] iv, long totalFileSize); void fileDidFailedUpload(String location, boolean isEncrypted); - void fileDidLoaded(String location, File finalFile, int type); + void fileDidLoaded(String location, File finalFile, Object parentObject, int type); void fileDidFailedLoad(String location, int state); void fileLoadProgressChanged(FileLoadOperation operation, String location, long uploadedSize, long totalSize); } @@ -42,6 +42,9 @@ public class FileLoader extends BaseController { public static final int MEDIA_DIR_DOCUMENT = 3; public static final int MEDIA_DIR_CACHE = 4; + public static final int MEDIA_DIR_IMAGE_PUBLIC = 100; + public static final int MEDIA_DIR_VIDEO_PUBLIC = 101; + public static final int IMAGE_TYPE_LOTTIE = 1; public static final int IMAGE_TYPE_ANIMATION = 2; public static final int IMAGE_TYPE_SVG = 3; @@ -707,14 +710,14 @@ public class FileLoader extends BaseController { if (!operation.isPreloadVideoOperation() && operation.isPreloadFinished()) { return; } - if (document != null && parentObject instanceof MessageObject) { + if (document != null && parentObject instanceof MessageObject && ((MessageObject) parentObject).putInDownloadsStore) { getDownloadController().onDownloadComplete((MessageObject) parentObject); } if (!operation.isPreloadVideoOperation()) { loadOperationPathsUI.remove(fileName); if (delegate != null) { - delegate.fileDidLoaded(fileName, finalFile, finalType); + delegate.fileDidLoaded(fileName, finalFile, parentObject, finalType); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ForwardingMessagesParams.java b/TMessagesProj/src/main/java/org/telegram/messenger/ForwardingMessagesParams.java index 3bfc46f5f..6454df01a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ForwardingMessagesParams.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ForwardingMessagesParams.java @@ -67,6 +67,7 @@ public class ForwardingMessagesParams { message.post = messageObject.messageOwner.post; message.legacy = messageObject.messageOwner.legacy; message.restriction_reason = messageObject.messageOwner.restriction_reason; + message.replyMessage = messageObject.messageOwner.replyMessage; TLRPC.MessageFwdHeader header = null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index 1ac00514e..b2e1dcedf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -1905,12 +1905,16 @@ public class ImageLoader { } @Override - public void fileDidLoaded(final String location, final File finalFile, final int type) { + public void fileDidLoaded(final String location, final File finalFile, Object parentObject, final int type) { fileProgresses.remove(location); AndroidUtilities.runOnUIThread(() -> { - if (SharedConfig.saveToGallery && telegramPath != null && finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { - if (finalFile.toString().startsWith(telegramPath.toString())) { - AndroidUtilities.addMediaToGallery(finalFile.toString()); + if (SharedConfig.saveToGallery && finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { + if (parentObject instanceof MessageObject) { + MessageObject messageObject = (MessageObject) parentObject; + // test add only for peer dialogs + if (messageObject.getDialogId() >= 0) { + AndroidUtilities.addMediaToGallery(finalFile.toString()); + } } } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.fileLoaded, location, finalFile); @@ -2052,14 +2056,20 @@ public class ImageLoader { } } + File publicMediaDir = null; if (Build.VERSION.SDK_INT >= 30) { - File newPath = ApplicationLoader.applicationContext.getExternalFilesDir(null); + File newPath; + try { + if (ApplicationLoader.applicationContext.getExternalMediaDirs().length > 0) { + publicMediaDir = ApplicationLoader.applicationContext.getExternalMediaDirs()[0]; + publicMediaDir = new File(publicMediaDir, "Telegram"); + publicMediaDir.mkdirs(); + } + } catch (Exception e) { + FileLog.e(e); + } + newPath = ApplicationLoader.applicationContext.getExternalFilesDir(null); telegramPath = new File(newPath, "Telegram"); -// File oldPath = new File(path, "Telegram"); -// long moveStart = System.currentTimeMillis(); -// moveDirectory(oldPath, telegramPath); -// long dt = System.currentTimeMillis() - moveStart; -// FileLog.d("move time = " + dt); } else { telegramPath = new File(path, "Telegram"); } @@ -2133,6 +2143,33 @@ public class ImageLoader { FileLog.e(e); } } + if (publicMediaDir != null && publicMediaDir.isDirectory()) { + try { + File imagePath = new File(publicMediaDir, "Telegram Images"); + imagePath.mkdir(); + if (imagePath.isDirectory() && canMoveFiles(cachePath, imagePath, FileLoader.MEDIA_DIR_IMAGE)) { + mediaDirs.put(FileLoader.MEDIA_DIR_IMAGE_PUBLIC, imagePath); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("image path = " + imagePath); + } + } + } catch (Exception e) { + FileLog.e(e); + } + + try { + File videoPath = new File(publicMediaDir, "Telegram Video"); + videoPath.mkdir(); + if (videoPath.isDirectory() && canMoveFiles(cachePath, videoPath, FileLoader.MEDIA_DIR_VIDEO)) { + mediaDirs.put(FileLoader.MEDIA_DIR_VIDEO_PUBLIC, videoPath); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("video path = " + videoPath); + } + } + } catch (Exception e) { + FileLog.e(e); + } + } } else { if (BuildVars.LOGS_ENABLED) { FileLog.d("this Android can't rename files"); @@ -3844,6 +3881,10 @@ public class ImageLoader { return null; } + public DispatchQueue getCacheOutQueue() { + return cacheOutQueue; + } + public static class MessageThumb { BitmapDrawable drawable; String key; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index 933e36975..a7445ae3e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -1552,11 +1552,12 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } public Bitmap getBitmap() { - AnimatedFileDrawable animation = getAnimation(); RLottieDrawable lottieDrawable = getLottieAnimation(); if (lottieDrawable != null && lottieDrawable.hasBitmap()) { return lottieDrawable.getAnimatedBitmap(); - } else if (animation != null && animation.hasBitmap()) { + } + AnimatedFileDrawable animation = getAnimation(); + if (animation != null && animation.hasBitmap()) { return animation.getAnimatedBitmap(); } else if (currentMediaDrawable instanceof BitmapDrawable && !(currentMediaDrawable instanceof AnimatedFileDrawable) && !(currentMediaDrawable instanceof RLottieDrawable)) { return ((BitmapDrawable) currentMediaDrawable).getBitmap(); @@ -2043,7 +2044,6 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } public AnimatedFileDrawable getAnimation() { - AnimatedFileDrawable animatedFileDrawable; if (currentMediaDrawable instanceof AnimatedFileDrawable) { return (AnimatedFileDrawable) currentMediaDrawable; } else if (currentImageDrawable instanceof AnimatedFileDrawable) { @@ -2057,7 +2057,6 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } public RLottieDrawable getLottieAnimation() { - RLottieDrawable animatedFileDrawable; if (currentMediaDrawable instanceof RLottieDrawable) { return (RLottieDrawable) currentMediaDrawable; } else if (currentImageDrawable instanceof RLottieDrawable) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LanguageDetector.java b/TMessagesProj/src/main/java/org/telegram/messenger/LanguageDetector.java index f4e30e68b..26723e790 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LanguageDetector.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LanguageDetector.java @@ -13,18 +13,40 @@ public class LanguageDetector { } public static void detectLanguage(String text, StringCallback onSuccess, ExceptionCallback onFail) { + detectLanguage(text, onSuccess, onFail, false); + } + + public static void detectLanguage(String text, StringCallback onSuccess, ExceptionCallback onFail, boolean initializeFirst) { try { + if (initializeFirst) { + com.google.mlkit.common.sdkinternal.MlKitContext.zza(ApplicationLoader.applicationContext); + } com.google.mlkit.nl.languageid.LanguageIdentification.getClient() - .identifyLanguage(text) - .addOnSuccessListener(str -> { + .identifyLanguage(text) + .addOnSuccessListener(str -> { + if (onSuccess != null) { onSuccess.run(str); - }) - .addOnFailureListener(e -> { + } + }) + .addOnFailureListener(e -> { + if (onFail != null) { onFail.run(e); - }); + } + }); + } catch (IllegalStateException e) { + if (!initializeFirst) { + detectLanguage(text, onSuccess, onFail, true); + } else if (onFail != null) { + onFail.run(e); + } } catch (Exception e) { - FileLog.e(e); - onFail.run(e); + if (onFail != null) { + onFail.run(e); + } + } catch (Throwable t) { + if (onFail != null) { + onFail.run(null); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index c9f6c5213..3e49ebaa6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -948,13 +948,20 @@ public class LocaleController { reloadLastFile = false; } if (!isLoadingRemote) { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface); + if (init) { + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface)); + } else { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface); + } } } catch (Exception e) { FileLog.e(e); changingConfiguration = false; } recreateFormatters(); + if (force) { + MediaDataController.getInstance(currentAccount).loadAttachMenuBots(false, true); + } } public LocaleInfo getCurrentLocaleInfo() { @@ -1085,6 +1092,14 @@ public class LocaleController { } } + public static String formatString(@StringRes int res, Object... args) { + String key = resourcesCacheMap.get(res); + if (key == null) { + resourcesCacheMap.put(res, key = ApplicationLoader.applicationContext.getResources().getResourceEntryName(res)); + } + return formatString(key, res, args); + } + public static String formatString(String key, int res, Object... args) { return formatString(key, null, res, args); } @@ -1121,15 +1136,15 @@ public class LocaleController { return LocaleController.formatPluralString("Hours", ttl / 60 / 60); } else if (ttl < 60 * 60 * 24 * 7) { return LocaleController.formatPluralString("Days", ttl / 60 / 60 / 24); - } else if (ttl >= 60 * 60 * 24 * 30 && ttl <= 60 * 60 * 24 * 31) { - return LocaleController.formatPluralString("Months", ttl / 60 / 60 / 24 / 30); - } else { + } else if (ttl < 60 * 60 * 24 * 31) { int days = ttl / 60 / 60 / 24; if (ttl % 7 == 0) { return LocaleController.formatPluralString("Weeks", days / 7); } else { return String.format("%s %s", LocaleController.formatPluralString("Weeks", days / 7), LocaleController.formatPluralString("Days", days % 7)); } + } else { + return LocaleController.formatPluralString("Months", ttl / 60 / 60 / 24 / 30); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 5fa715b5b..93582704a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -231,6 +231,33 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, public float lockedAspectRatio; public boolean initied; + + @Override + public CropState clone() { + CropState cloned = new CropState(); + + cloned.cropPx = this.cropPx; + cloned.cropPy = this.cropPy; + cloned.cropScale = this.cropScale; + cloned.cropRotate = this.cropRotate; + cloned.cropPw = this.cropPw; + cloned.cropPh = this.cropPh; + cloned.transformWidth = this.transformWidth; + cloned.transformHeight = this.transformHeight; + cloned.transformRotation = this.transformRotation; + cloned.mirrored = this.mirrored; + + cloned.stateScale = this.stateScale; + cloned.scale = this.scale; + cloned.matrix = this.matrix; + cloned.width = this.width; + cloned.height = this.height; + cloned.freeform = this.freeform; + cloned.lockedAspectRatio = this.lockedAspectRatio; + + cloned.initied = this.initied; + return cloned; + } } public static class MediaEditState { @@ -4082,7 +4109,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, try { int selectedType = type; ContentValues contentValues = new ContentValues(); - String extension = MimeTypeMap.getFileExtensionFromUrl(sourceFile.getAbsolutePath()); + String extension = FileLoader.getFileExtension(sourceFile); String mimeType = null; if (extension != null) { mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); @@ -4831,7 +4858,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, resultWidth = temp; } - if (framerate > 30 && (Math.min(resultHeight, resultWidth) <= 480)) { + if (framerate > 40 && (Math.min(resultHeight, resultWidth) <= 480)) { framerate = 30; } @@ -4929,12 +4956,12 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, minCompressFactor = 1f; } else if (Math.min(height, width) >= 720) { maxBitrate = 2600_000; - compressFactor = 0.8f; - minCompressFactor = 0.8f; + compressFactor = 1f; + minCompressFactor = 1f; } else if (Math.min(height, width) >= 480) { maxBitrate = 1000_000; - compressFactor = 0.7f; - minCompressFactor = 0.8f; + compressFactor = 0.75f; + minCompressFactor = 0.9f; } else { maxBitrate = 750_000; compressFactor = 0.6f; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 4d47c1358..3c85ae4c2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -34,6 +34,8 @@ import android.text.TextUtils; import android.text.style.CharacterStyle; import android.util.SparseArray; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.collection.LongSparseArray; import androidx.core.content.pm.ShortcutInfoCompat; import androidx.core.content.pm.ShortcutManagerCompat; @@ -43,6 +45,8 @@ import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteDatabase; import org.telegram.SQLite.SQLiteException; import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.ringtone.RingtoneDataStore; +import org.telegram.messenger.ringtone.RingtoneUploader; import org.telegram.messenger.support.SparseLongArray; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; @@ -76,6 +80,14 @@ import java.util.regex.Pattern; @SuppressWarnings("unchecked") public class MediaDataController extends BaseController { + public final static String ATTACH_MENU_BOT_ANIMATED_ICON_KEY = "android_animated", + ATTACH_MENU_BOT_STATIC_ICON_KEY = "default_static", + ATTACH_MENU_BOT_PLACEHOLDER_STATIC_KEY = "placeholder_static", + ATTACH_MENU_BOT_COLOR_LIGHT_ICON = "light_icon", + ATTACH_MENU_BOT_COLOR_LIGHT_TEXT = "light_text", + ATTACH_MENU_BOT_COLOR_DARK_ICON = "dark_icon", + ATTACH_MENU_BOT_COLOR_DARK_TEXT = "dark_text"; + private static Pattern BOLD_PATTERN = Pattern.compile("\\*\\*(.+?)\\*\\*"), ITALIC_PATTERN = Pattern.compile("__(.+?)__"), SPOILER_PATTERN = Pattern.compile("\\|\\|(.+?)\\|\\|"), @@ -145,6 +157,7 @@ public class MediaDataController extends BaseController { } loadStickersByEmojiOrName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME, false, true); + ringtoneDataStore = new RingtoneDataStore(currentAccount); } public static final int TYPE_IMAGE = 0; @@ -155,6 +168,11 @@ public class MediaDataController extends BaseController { public static final int TYPE_GREETINGS = 3; + private long menuBotsUpdateHash; + private TLRPC.TL_attachMenuBots attachMenuBots = new TLRPC.TL_attachMenuBots(); + private boolean isLoadingMenuBots; + private int menuBotsUpdateDate; + private int reactionsUpdateHash; private List reactionsList = new ArrayList<>(); private List enabledReactionsList = new ArrayList<>(); @@ -178,6 +196,7 @@ public class MediaDataController extends BaseController { private boolean[] stickersLoaded = new boolean[5]; private long[] loadHash = new long[5]; private int[] loadDate = new int[5]; + public HashMap ringtoneUploaderHashMap = new HashMap<>(); private HashMap> verifyingMessages = new HashMap<>(); @@ -205,6 +224,7 @@ public class MediaDataController extends BaseController { private boolean featuredStickersLoaded; private TLRPC.Document greetingsSticker; + public final RingtoneDataStore ringtoneDataStore; public void cleanup() { for (int a = 0; a < recentStickers.length; a++) { @@ -282,6 +302,108 @@ public class MediaDataController extends BaseController { } } + public void checkMenuBots() { + if (!isLoadingMenuBots && Math.abs(System.currentTimeMillis() / 1000 - menuBotsUpdateDate) >= 60 * 60) { + loadAttachMenuBots(true, false); + } + } + + public TLRPC.TL_attachMenuBots getAttachMenuBots() { + return attachMenuBots; + } + + public void loadAttachMenuBots(boolean cache, boolean force) { + isLoadingMenuBots = true; + if (cache) { + getMessagesStorage().getStorageQueue().postRunnable(() -> { + SQLiteCursor c = null; + long hash = 0; + int date = 0; + TLRPC.TL_attachMenuBots bots = null; + try { + c = getMessagesStorage().getDatabase().queryFinalized("SELECT data, hash, date FROM attach_menu_bots"); + if (c.next()) { + NativeByteBuffer data = c.byteBufferValue(0); + if (data != null) { + TLRPC.AttachMenuBots attachMenuBots = TLRPC.TL_attachMenuBots.TLdeserialize(data, data.readInt32(false), true); + if (attachMenuBots instanceof TLRPC.TL_attachMenuBots) { + bots = (TLRPC.TL_attachMenuBots) attachMenuBots; + } + data.reuse(); + } + hash = c.longValue(1); + date = c.intValue(2); + } + } catch (Exception e) { + FileLog.e(e, false); + } finally { + if (c != null) { + c.dispose(); + } + } + processLoadedMenuBots(bots, hash, date, true); + }); + } else { + TLRPC.TL_messages_getAttachMenuBots req = new TLRPC.TL_messages_getAttachMenuBots(); + req.hash = force ? 0 : menuBotsUpdateHash; + getConnectionsManager().sendRequest(req, (response, error) -> { + int date = (int) (System.currentTimeMillis() / 1000); + if (response instanceof TLRPC.TL_attachMenuBotsNotModified) { + processLoadedMenuBots(null, 0, date, false); + } else if (response instanceof TLRPC.TL_attachMenuBots) { + TLRPC.TL_attachMenuBots r = (TLRPC.TL_attachMenuBots) response; + processLoadedMenuBots(r, r.hash, date, false); + } + }); + } + } + + private void processLoadedMenuBots(TLRPC.TL_attachMenuBots bots, long hash, int date, boolean cache) { + if (bots != null && date != 0) { + attachMenuBots = bots; + menuBotsUpdateHash = hash; + } + menuBotsUpdateDate = date; + if (bots != null) { + getMessagesController().putUsers(bots.users, cache); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.attachMenuBotsDidLoad)); + } + + if (!cache) { + putMenuBotsToCache(bots, hash, date); + } else if (Math.abs(System.currentTimeMillis() / 1000 - date) >= 60 * 60) { + loadAttachMenuBots(false, true); + } + } + + private void putMenuBotsToCache(TLRPC.TL_attachMenuBots bots, long hash, int date) { + getMessagesStorage().getStorageQueue().postRunnable(() -> { + try { + if (bots != null) { + getMessagesStorage().getDatabase().executeFast("DELETE FROM attach_menu_bots").stepThis().dispose(); + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("REPLACE INTO attach_menu_bots VALUES(?, ?, ?)"); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(bots.getObjectSize()); + bots.serializeToStream(data); + state.bindByteBuffer(1, data); + state.bindLong(2, hash); + state.bindInteger(3, date); + state.step(); + data.reuse(); + state.dispose(); + } else { + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("UPDATE attach_menu_bots SET date = ?"); + state.requery(); + state.bindLong(1, date); + state.step(); + state.dispose(); + } + } catch (Exception e) { + FileLog.e(e); + } + }); + } + public List getReactionsList() { return reactionsList; } @@ -866,6 +988,36 @@ public class MediaDataController extends BaseController { return value != null ? value : ""; } + @Nullable + public static TLRPC.TL_attachMenuBotIcon getAnimatedAttachMenuBotIcon(@NonNull TLRPC.TL_attachMenuBot bot) { + for (TLRPC.TL_attachMenuBotIcon icon : bot.icons) { + if (icon.name.equals(ATTACH_MENU_BOT_ANIMATED_ICON_KEY)) { + return icon; + } + } + return null; + } + + @Nullable + public static TLRPC.TL_attachMenuBotIcon getStaticAttachMenuBotIcon(@NonNull TLRPC.TL_attachMenuBot bot) { + for (TLRPC.TL_attachMenuBotIcon icon : bot.icons) { + if (icon.name.equals(ATTACH_MENU_BOT_STATIC_ICON_KEY)) { + return icon; + } + } + return null; + } + + @Nullable + public static TLRPC.TL_attachMenuBotIcon getPlaceholderStaticAttachMenuBotIcon(@NonNull TLRPC.TL_attachMenuBot bot) { + for (TLRPC.TL_attachMenuBotIcon icon : bot.icons) { + if (icon.name.equals(ATTACH_MENU_BOT_PLACEHOLDER_STATIC_KEY)) { + return icon; + } + } + return null; + } + public static long calcDocumentsHash(ArrayList arrayList) { return calcDocumentsHash(arrayList, 200); } @@ -2640,9 +2792,9 @@ public class MediaDataController extends BaseController { type = MEDIA_MUSIC; } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterGif) { type = MEDIA_GIF; - } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterPhotos) { + } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterPhotos) { type = MEDIA_PHOTOS_ONLY; - } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterVideo) { + } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterVideo) { type = MEDIA_VIDEOS_ONLY; } else { continue; @@ -4294,7 +4446,12 @@ public class MediaDataController extends BaseController { if (ids == null) { continue; } - SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + SQLiteCursor cursor; + if (scheduled) { + cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM scheduled_messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + } else { + cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + } while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { @@ -4331,7 +4488,30 @@ public class MediaDataController extends BaseController { if (!dialogReplyMessagesIds.isEmpty()) { for (int a = 0, N = dialogReplyMessagesIds.size(); a < N; a++) { long channelId = dialogReplyMessagesIds.keyAt(a); - if (channelId != 0) { + if (scheduled) { + TLRPC.TL_messages_getScheduledMessages req = new TLRPC.TL_messages_getScheduledMessages(); + req.peer = getMessagesController().getInputPeer(dialogId); + req.id = dialogReplyMessagesIds.valueAt(a); + getConnectionsManager().sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; + for (int i = 0; i < messagesRes.messages.size(); i++) { + TLRPC.Message message = messagesRes.messages.get(i); + if (message.dialog_id == 0) { + message.dialog_id = dialogId; + } + } + MessageObject.fixMessagePeer(messagesRes.messages, channelId); + ImageLoader.saveMessagesThumbs(messagesRes.messages); + broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialogId, false); + getMessagesStorage().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); + saveReplyMessages(replyMessageOwners, messagesRes.messages, scheduled); + } + if (callback != null) { + AndroidUtilities.runOnUIThread(callback); + } + }); + } else if (channelId != 0) { TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages(); req.channel = getMessagesController().getInputChannel(channelId); req.id = dialogReplyMessagesIds.valueAt(a); @@ -4643,7 +4823,7 @@ public class MediaDataController extends BaseController { }); for (int a = 0, N = entitiesCopy.size(); a < N; a++) { TLRPC.MessageEntity entity = entitiesCopy.get(a); - if (entity.length <= 0 || entity.offset < 0 || entity.offset >= text.length()) { + if (entity == null || entity.length <= 0 || entity.offset < 0 || entity.offset >= text.length()) { continue; } else if (entity.offset + entity.length > text.length()) { entity.length = text.length() - entity.offset; @@ -5482,6 +5662,61 @@ public class MediaDataController extends BaseController { public List getEnabledReactionsList() { return enabledReactionsList; } + + public void uploadRingtone(String filePath) { + if (ringtoneUploaderHashMap.containsKey(filePath)) { + return; + } + ringtoneUploaderHashMap.put(filePath, new RingtoneUploader(filePath, currentAccount)); + ringtoneDataStore.addUploadingTone(filePath); + } + + public void onRingtoneUploaded(String filePath, TLRPC.Document document, boolean error) { + ringtoneUploaderHashMap.remove(filePath); + ringtoneDataStore.onRingtoneUploaded(filePath, document, error); + } + + public void checkRingtones() { + ringtoneDataStore.loadUserRingtones(); + } + + public boolean saveToRingtones(TLRPC.Document document) { + if (document == null) { + return false; + } + if (ringtoneDataStore.contains(document.id)) { + return true; + } + if (document.size > MessagesController.getInstance(currentAccount).ringtoneSizeMax) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("TooLargeError", R.string.TooLargeError), LocaleController.formatString("ErrorRingtoneSizeTooBig", R.string.ErrorRingtoneSizeTooBig, (MessagesController.getInstance(UserConfig.selectedAccount).ringtoneSizeMax / 1024))); + return false; + } + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.duration > MessagesController.getInstance(currentAccount).ringtoneDurationMax) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("TooLongError", R.string.TooLongError), LocaleController.formatString("ErrorRingtoneDurationTooLong", R.string.ErrorRingtoneDurationTooLong, MessagesController.getInstance(UserConfig.selectedAccount).ringtoneDurationMax)); + return false; + } + } + } + TLRPC.TL_account_saveRingtone saveRingtone = new TLRPC.TL_account_saveRingtone(); + saveRingtone.id = new TLRPC.TL_inputDocument(); + saveRingtone.id.id = document.id; + saveRingtone.id.file_reference = document.file_reference; + saveRingtone.id.access_hash = document.access_hash; + ConnectionsManager.getInstance(currentAccount).sendRequest(saveRingtone, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + if (response instanceof TLRPC.TL_account_savedRingtoneConverted) { + ringtoneDataStore.addTone(((TLRPC.TL_account_savedRingtoneConverted) response).document); + } else { + ringtoneDataStore.addTone(document); + } + } + })); + return true; + } + //---------------- BOT END ---------------- //---------------- EMOJI START ---------------- @@ -5491,6 +5726,7 @@ public class MediaDataController extends BaseController { public String keyword; } + public interface KeywordResultCallback { void run(ArrayList param, String alias); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 601b53fb9..3d19da05e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -30,13 +30,13 @@ import androidx.collection.LongSparseArray; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.browser.Browser; +import org.telegram.messenger.ringtone.RingtoneDataStore; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.ChatMessageCell; -import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanBotCommand; @@ -46,6 +46,7 @@ import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.URLSpanNoUnderlineBold; import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; +import org.telegram.ui.Components.spoilers.SpoilerEffect; import java.io.BufferedReader; import java.io.File; @@ -205,6 +206,10 @@ public class MessageObject { public ImageLocation mediaThumb; public ImageLocation mediaSmallThumb; + // forwarding preview params + public boolean hideSendersName; + public TLRPC.Peer sendAsPeer; + static final String[] excludeWords = new String[] { " vs. ", " vs ", @@ -2532,7 +2537,11 @@ public class MessageObject { if (button instanceof TLRPC.TL_keyboardButtonBuy && (messageOwner.media.flags & 4) != 0) { text = LocaleController.getString("PaymentReceipt", R.string.PaymentReceipt); } else { - text = Emoji.replaceEmoji(button.text, Theme.chat_msgBotButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); + String str = button.text; + if (str == null) { + str = ""; + } + text = Emoji.replaceEmoji(str, Theme.chat_msgBotButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); } StaticLayout staticLayout = new StaticLayout(text, Theme.chat_msgBotButtonPaint, AndroidUtilities.dp(2000), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (staticLayout.getLineCount() > 0) { @@ -3058,6 +3067,9 @@ public class MessageObject { user = getUser(users, sUsers, messageOwner.peer_id.user_id); } messageText = LocaleController.formatString("ActionBotDocuments", R.string.ActionBotDocuments, UserObject.getFirstName(user), str.toString()); + } else if (messageOwner.action instanceof TLRPC.TL_messageActionWebViewDataSent) { + TLRPC.TL_messageActionWebViewDataSent dataSent = (TLRPC.TL_messageActionWebViewDataSent) messageOwner.action; + messageText = LocaleController.formatString("ActionBotWebViewData", R.string.ActionBotWebViewData, dataSent.text); } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetChatTheme) { String emoticon = ((TLRPC.TL_messageActionSetChatTheme) messageOwner.action).emoticon; String userName = UserObject.getFirstName(fromUser); @@ -5513,7 +5525,7 @@ public class MessageObject { } public boolean isMusic() { - return isMusicMessage(messageOwner); + return isMusicMessage(messageOwner) && !isVideo(); } public boolean isDocument() { @@ -6399,4 +6411,18 @@ public class MessageObject { reactionsChanged = true; return true; } + + public boolean probablyRingtone() { + if (getDocument() != null && RingtoneDataStore.ringtoneSupportedMimeType.contains(getDocument().mime_type) && getDocument().size < MessagesController.getInstance(currentAccount).ringtoneSizeMax * 2) { + for (int a = 0; a < getDocument().attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = getDocument().attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.duration < MessagesController.getInstance(currentAccount).ringtoneDurationMax * 2) { + return true; + } + } + } + } + return false; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 756c74f81..aa7be0def 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -8,6 +8,9 @@ package org.telegram.messenger; +import static org.telegram.messenger.NotificationsController.TYPE_CHANNEL; +import static org.telegram.messenger.NotificationsController.TYPE_PRIVATE; + import android.app.Activity; import android.appwidget.AppWidgetManager; import android.content.Context; @@ -45,6 +48,7 @@ import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; +import org.telegram.ui.ChatRightsEditActivity; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.JoinCallAlert; @@ -88,6 +92,8 @@ public class MessagesController extends BaseController implements NotificationCe public ArrayList dialogsForward = new ArrayList<>(); public ArrayList dialogsServerOnly = new ArrayList<>(); public ArrayList dialogsCanAddUsers = new ArrayList<>(); + public ArrayList dialogsMyChannels = new ArrayList<>(); + public ArrayList dialogsMyGroups = new ArrayList<>(); public ArrayList dialogsChannelsOnly = new ArrayList<>(); public ArrayList dialogsUsersOnly = new ArrayList<>(); public ArrayList dialogsForBlock = new ArrayList<>(); @@ -97,13 +103,7 @@ public class MessagesController extends BaseController implements NotificationCe public int unreadUnmutedDialogs; public ConcurrentHashMap dialogs_read_inbox_max = new ConcurrentHashMap<>(100, 1.0f, 2); public ConcurrentHashMap dialogs_read_outbox_max = new ConcurrentHashMap<>(100, 1.0f, 2); - public LongSparseArray dialogs_dict = new LongSparseArray() { - - @Override - public void put(long key, TLRPC.Dialog value) { - super.put(key, value); - } - }; + public LongSparseArray dialogs_dict = new LongSparseArray<>(); public LongSparseArray dialogMessage = new LongSparseArray<>(); public LongSparseArray dialogMessagesByRandomIds = new LongSparseArray<>(); public LongSparseIntArray deletedHistory = new LongSparseIntArray(); @@ -332,6 +332,8 @@ public class MessagesController extends BaseController implements NotificationCe public HashMap emojiSounds = new HashMap<>(); public HashMap> emojiInteractions = new HashMap<>(); public boolean remoteConfigLoaded; + public int ringtoneDurationMax; + public int ringtoneSizeMax; private SharedPreferences notificationsPreferences; private SharedPreferences mainPreferences; @@ -835,6 +837,9 @@ public class MessagesController extends BaseController implements NotificationCe groupCallVideoMaxParticipants = mainPreferences.getInt("groipCallVideoMaxParticipants", 30); chatReadMarkSizeThreshold = mainPreferences.getInt("chatReadMarkSizeThreshold", 50); chatReadMarkExpirePeriod = mainPreferences.getInt("chatReadMarkExpirePeriod", 7 * 86400); + ringtoneDurationMax = mainPreferences.getInt("ringtoneDurationMax", 5); + ringtoneSizeMax = mainPreferences.getInt("ringtoneSizeMax", 1024_00); + chatReadMarkExpirePeriod = mainPreferences.getInt("chatReadMarkExpirePeriod", 7 * 86400); suggestStickersApiOnly = mainPreferences.getBoolean("suggestStickersApiOnly", false); roundVideoSize = mainPreferences.getInt("roundVideoSize", 384); roundVideoBitrate = mainPreferences.getInt("roundVideoBitrate", 1000); @@ -1900,6 +1905,28 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + case "ringtone_size_max": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value; + if (number.value != ringtoneSizeMax) { + ringtoneSizeMax = (int) number.value; + editor.putInt("ringtoneSizeMax", ringtoneSizeMax); + changed = true; + } + } + break; + } + case "ringtone_duration_max": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value; + if (number.value != ringtoneDurationMax) { + ringtoneDurationMax = (int) number.value; + editor.putInt("ringtoneDurationMax", ringtoneDurationMax); + changed = true; + } + } + break; + } } } if (changed) { @@ -2665,6 +2692,8 @@ public class MessagesController extends BaseController implements NotificationCe allDialogs.clear(); dialogsLoadedTillDate = Integer.MAX_VALUE; dialogsCanAddUsers.clear(); + dialogsMyChannels.clear(); + dialogsMyGroups.clear(); dialogsChannelsOnly.clear(); dialogsGroupsOnly.clear(); dialogsUsersOnly.clear(); @@ -4183,7 +4212,11 @@ public class MessagesController extends BaseController implements NotificationCe }); } - public void setUserAdminRole(long chatId, TLRPC.User user, TLRPC.TL_chatAdminRights rights, String rank, boolean isChannel, BaseFragment parentFragment, boolean addingNew) { + public void setUserAdminRole(long chatId, TLRPC.User user, TLRPC.TL_chatAdminRights rights, String rank, boolean isChannel, BaseFragment parentFragment, boolean addingNew, boolean forceAdmin, String botHash, Runnable onSuccess) { + setUserAdminRole(chatId, user, rights, rank, isChannel, parentFragment, addingNew, forceAdmin, botHash, onSuccess, null); + } + + public void setUserAdminRole(long chatId, TLRPC.User user, TLRPC.TL_chatAdminRights rights, String rank, boolean isChannel, BaseFragment parentFragment, boolean addingNew, boolean forceAdmin, String botHash, Runnable onSuccess, Runnable onError) { if (user == null || rights == null) { return; } @@ -4194,28 +4227,49 @@ public class MessagesController extends BaseController implements NotificationCe req.user_id = getInputUser(user); req.admin_rights = rights; req.rank = rank; - getConnectionsManager().sendRequest(req, (response, error) -> { + RequestDelegate requestDelegate = (response, error) -> { if (error == null) { processUpdates((TLRPC.Updates) response, false); - AndroidUtilities.runOnUIThread(() -> loadFullChat(chatId, 0, true), 1000); + AndroidUtilities.runOnUIThread(() -> { + loadFullChat(chatId, 0, true); + if (onSuccess != null) { + onSuccess.run(); + } + }, 1000); } else { AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, parentFragment, req, isChannel)); + if (onError != null) { + AndroidUtilities.runOnUIThread(onError); + } } - }); + }; + if (chat.megagroup && addingNew) { + addUserToChat(chatId, user, 0, botHash, parentFragment, true, () -> getConnectionsManager().sendRequest(req, requestDelegate), onError); + } else { + getConnectionsManager().sendRequest(req, requestDelegate); + } } else { TLRPC.TL_messages_editChatAdmin req = new TLRPC.TL_messages_editChatAdmin(); req.chat_id = chatId; req.user_id = getInputUser(user); - req.is_admin = rights.change_info || rights.delete_messages || rights.ban_users || rights.invite_users || rights.pin_messages || rights.add_admins || rights.manage_call; + req.is_admin = forceAdmin || rights.change_info || rights.delete_messages || rights.ban_users || rights.invite_users || rights.pin_messages || rights.add_admins || rights.manage_call; RequestDelegate requestDelegate = (response, error) -> { if (error == null) { - AndroidUtilities.runOnUIThread(() -> loadFullChat(chatId, 0, true), 1000); + AndroidUtilities.runOnUIThread(() -> { + loadFullChat(chatId, 0, true); + if (onSuccess != null) { + onSuccess.run(); + } + }, 1000); } else { AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, parentFragment, req, false)); + if (onError != null) { + AndroidUtilities.runOnUIThread(onError); + } } }; - if (req.is_admin && addingNew) { - addUserToChat(chatId, user, 0, null, parentFragment, () -> getConnectionsManager().sendRequest(req, requestDelegate)); + if (req.is_admin || addingNew) { + addUserToChat(chatId, user, 0, botHash, parentFragment, true, () -> getConnectionsManager().sendRequest(req, requestDelegate), onError); } else { getConnectionsManager().sendRequest(req, requestDelegate); } @@ -4939,6 +4993,8 @@ public class MessagesController extends BaseController implements NotificationCe }); } allDialogs.remove(dialog); + dialogsMyChannels.remove(dialog); + dialogsMyGroups.remove(dialog); dialogsCanAddUsers.remove(dialog); dialogsChannelsOnly.remove(dialog); dialogsGroupsOnly.remove(dialog); @@ -5221,6 +5277,7 @@ public class MessagesController extends BaseController implements NotificationCe } TLRPC.TL_channels_deleteHistory req = new TLRPC.TL_channels_deleteHistory(); req.channel = new TLRPC.TL_inputChannel(); + req.for_everyone = revoke; req.channel.channel_id = peer.channel_id; req.channel.access_hash = peer.access_hash; req.max_id = max_id_delete > 0 ? max_id_delete : Integer.MAX_VALUE; @@ -5228,6 +5285,9 @@ public class MessagesController extends BaseController implements NotificationCe if (newTaskId != 0) { getMessagesStorage().removePendingTask(newTaskId); } + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + } }, ConnectionsManager.RequestFlagInvokeAfter); } else { TLRPC.TL_messages_deleteHistory req = new TLRPC.TL_messages_deleteHistory(); @@ -6585,6 +6645,10 @@ public class MessagesController extends BaseController implements NotificationCe reload = ((SystemClock.elapsedRealtime() - lastScheduledServerQueryTime.get(dialogId, 0L)) > 60 * 1000); } else { reload = resCount == 0 && (!isInitialLoading || (SystemClock.elapsedRealtime() - lastServerQueryTime.get(dialogId, 0L)) > 60 * 1000); + if (mode == 0 && isCache && dialogId < 0 && !dialogs_dict.containsKey(dialogId) && (SystemClock.elapsedRealtime() - lastServerQueryTime.get(dialogId, 0L)) > 24 * 60 * 60 * 1000) { + messagesRes.messages.clear(); + reload = true; + } } if (!DialogObject.isEncryptedDialog(dialogId) && isCache && reload) { int hash; @@ -7119,6 +7183,7 @@ public class MessagesController extends BaseController implements NotificationCe editor.putInt("EnableChannel2", notify_settings.mute_until); } } + applySoundSettings(notify_settings.android_sound, editor, 0, type, false); editor.commit(); if (loadingNotificationSettings == 0) { getUserConfig().notificationsSettingsLoaded = true; @@ -8148,6 +8213,7 @@ public class MessagesController extends BaseController implements NotificationCe } getMessagesStorage().setDialogFlags(dialogId, 0); } + applySoundSettings(notify_settings.android_sound, editor, dialogId, 0, false); editor.commit(); if (updated) { getNotificationCenter().postNotificationName(NotificationCenter.notificationsSettingsUpdated); @@ -9398,6 +9464,10 @@ public class MessagesController extends BaseController implements NotificationCe } public void addUserToChat(long chatId, TLRPC.User user, int forwardCount, String botHash, BaseFragment fragment, Runnable onFinishRunnable) { + addUserToChat(chatId, user, forwardCount, botHash, fragment, false, onFinishRunnable, null); + } + + public void addUserToChat(long chatId, TLRPC.User user, int forwardCount, String botHash, BaseFragment fragment, boolean ignoreIfAlreadyExists, Runnable onFinishRunnable, Runnable onError) { if (user == null) { return; } @@ -9449,6 +9519,15 @@ public class MessagesController extends BaseController implements NotificationCe AndroidUtilities.runOnUIThread(() -> joiningToChannels.remove(chatId)); } if (error != null) { + if ("USER_ALREADY_PARTICIPANT".equals(error.text) && ignoreIfAlreadyExists) { + if (onFinishRunnable != null) { + AndroidUtilities.runOnUIThread(onFinishRunnable); + } + return; + } + if (onError != null) { + AndroidUtilities.runOnUIThread(onError); + } AndroidUtilities.runOnUIThread(() -> { AlertsCreator.processError(currentAccount, error, fragment, request, isChannel && !isMegagroup); if (isChannel && inputUser instanceof TLRPC.TL_inputUserSelf) { @@ -9711,6 +9790,7 @@ public class MessagesController extends BaseController implements NotificationCe getConnectionsManager().cleanup(type == 2); } getUserConfig().clearConfig(); + SharedPrefsHelper.cleanupAccount(currentAccount); boolean shouldHandle = true; ArrayList observers = getNotificationCenter().getObservers(NotificationCenter.appDidLogout); @@ -12996,6 +13076,16 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new ArrayList<>(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateWebViewResultSent) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateAttachMenuBots) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateReadChannelDiscussionInbox) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); @@ -13016,6 +13106,11 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new ArrayList<>(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateSavedRingtones) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } } if (messages != null) { @@ -13292,6 +13387,7 @@ public class MessagesController extends BaseController implements NotificationCe editor.remove("notify2_" + dialogId); getMessagesStorage().setDialogFlags(dialogId, 0); } + applySoundSettings(update.notify_settings.android_sound, editor, dialogId, 0, true); } else if (update.peer instanceof TLRPC.TL_notifyChats) { if ((update.notify_settings.flags & 1) != 0) { editor.putBoolean("EnablePreviewGroup", update.notify_settings.show_previews); @@ -13310,6 +13406,7 @@ public class MessagesController extends BaseController implements NotificationCe AndroidUtilities.runOnUIThread(() -> getNotificationsController().deleteNotificationChannelGlobal(NotificationsController.TYPE_GROUP)); } } + applySoundSettings(update.notify_settings.android_sound, editor, 0, NotificationsController.TYPE_GROUP, false); } else if (update.peer instanceof TLRPC.TL_notifyUsers) { if ((update.notify_settings.flags & 1) != 0) { editor.putBoolean("EnablePreviewAll", update.notify_settings.show_previews); @@ -13321,11 +13418,12 @@ public class MessagesController extends BaseController implements NotificationCe editor.remove("GlobalSoundPath"); }*/ } + applySoundSettings(update.notify_settings.android_sound, editor, 0, TYPE_PRIVATE, false); if ((update.notify_settings.flags & 4) != 0) { if (notificationsPreferences.getInt("EnableAll2", 0) != update.notify_settings.mute_until) { editor.putInt("EnableAll2", update.notify_settings.mute_until); editor.putBoolean("overwrite_private", true); - AndroidUtilities.runOnUIThread(() -> getNotificationsController().deleteNotificationChannelGlobal(NotificationsController.TYPE_PRIVATE)); + AndroidUtilities.runOnUIThread(() -> getNotificationsController().deleteNotificationChannelGlobal(TYPE_PRIVATE)); } } } else if (update.peer instanceof TLRPC.TL_notifyBroadcasts) { @@ -13346,6 +13444,7 @@ public class MessagesController extends BaseController implements NotificationCe AndroidUtilities.runOnUIThread(() -> getNotificationsController().deleteNotificationChannelGlobal(NotificationsController.TYPE_CHANNEL)); } } + applySoundSettings(update.notify_settings.android_sound, editor, 0, TYPE_CHANNEL, false); } getMessagesStorage().updateMutedDialogsFiltersCounters(); } @@ -13617,6 +13716,11 @@ public class MessagesController extends BaseController implements NotificationCe loadRemoteFilters(true); } else if (baseUpdate instanceof TLRPC.TL_updateDialogFilters) { loadRemoteFilters(true); + } else if (baseUpdate instanceof TLRPC.TL_updateWebViewResultSent) { + TLRPC.TL_updateWebViewResultSent resultSent = (TLRPC.TL_updateWebViewResultSent) baseUpdate; + getNotificationCenter().postNotificationName(NotificationCenter.webViewResultSent, resultSent.query_id); + } else if (baseUpdate instanceof TLRPC.TL_updateAttachMenuBots) { + getMediaDataController().loadAttachMenuBots(false, true); } else if (baseUpdate instanceof TLRPC.TL_updateReadChannelDiscussionInbox) { TLRPC.TL_updateReadChannelDiscussionInbox update = (TLRPC.TL_updateReadChannelDiscussionInbox) baseUpdate; getNotificationCenter().postNotificationName(NotificationCenter.threadMessagesRead, -update.channel_id, update.top_msg_id, update.read_max_id, 0); @@ -13671,6 +13775,8 @@ public class MessagesController extends BaseController implements NotificationCe } else if (baseUpdate instanceof TLRPC.TL_updatePendingJoinRequests) { TLRPC.TL_updatePendingJoinRequests update = (TLRPC.TL_updatePendingJoinRequests) baseUpdate; getMemberRequestsController().onPendingRequestsUpdated(update); + } else if (baseUpdate instanceof TLRPC.TL_updateSavedRingtones) { + getMediaDataController().ringtoneDataStore.loadUserRingtones(); } } if (editor != null) { @@ -14063,7 +14169,6 @@ public class MessagesController extends BaseController implements NotificationCe if (reactionsMentionsMessageIds.get(messageId) != hasUnreadReaction) { newUnreadCount += hasUnreadReaction ? 1 : -1; changed = true; - } } else { needReload = true; @@ -14086,13 +14191,14 @@ public class MessagesController extends BaseController implements NotificationCe } } if (needReload) { - TLRPC.TL_messages_getUnreadReactions req = new TLRPC.TL_messages_getUnreadReactions(); - req.limit = 1; - req.peer = getInputPeer(dialogId); + TLRPC.TL_messages_getPeerDialogs req = new TLRPC.TL_messages_getPeerDialogs(); + TLRPC.TL_inputDialogPeer inputDialogPeer = new TLRPC.TL_inputDialogPeer(); + inputDialogPeer.peer = getInputPeer(dialogId); + req.peers.add(inputDialogPeer); ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (response != null) { - TLRPC.messages_Messages messages = (TLRPC.messages_Messages) response; - int count = Math.max(messages.count, messages.messages.size()); + TLRPC.TL_messages_peerDialogs dialogs = (TLRPC.TL_messages_peerDialogs) response; + int count = dialogs.dialogs.size() == 0 ? 0 : dialogs.dialogs.get(0).unread_reactions_count; AndroidUtilities.runOnUIThread(() -> { TLRPC.Dialog dialog = dialogs_dict.get(dialogId); if (dialog == null) { @@ -14128,6 +14234,10 @@ public class MessagesController extends BaseController implements NotificationCe return isDialogMuted(dialogId, null); } + public boolean isDialogNotificationsSoundEnabled(long dialogId) { + return notificationsPreferences.getBoolean("sound_enabled_" + dialogId, true); + } + public boolean isDialogMuted(long dialogId, TLRPC.Chat chat) { int mute_type = notificationsPreferences.getInt("notify2_" + dialogId, -1); if (mute_type == -1) { @@ -14431,6 +14541,8 @@ public class MessagesController extends BaseController implements NotificationCe allDialogs.remove(dialog); dialogsServerOnly.remove(dialog); dialogsCanAddUsers.remove(dialog); + dialogsMyGroups.remove(dialog); + dialogsMyChannels.remove(dialog); dialogsChannelsOnly.remove(dialog); dialogsGroupsOnly.remove(dialog); for (int a = 0; a < selectedDialogFilter.length; a++) { @@ -14591,6 +14703,8 @@ public class MessagesController extends BaseController implements NotificationCe public void sortDialogs(LongSparseArray chatsDict) { dialogsServerOnly.clear(); dialogsCanAddUsers.clear(); + dialogsMyGroups.clear(); + dialogsMyChannels.clear(); dialogsChannelsOnly.clear(); dialogsGroupsOnly.clear(); for (int a = 0; a < selectedDialogFilter.length; a++) { @@ -14657,8 +14771,16 @@ public class MessagesController extends BaseController implements NotificationCe dialogsServerOnly.add(d); if (DialogObject.isChannel(d)) { TLRPC.Chat chat = getChat(-d.id); - if (chat != null && chat.megagroup && (chat.admin_rights != null && (chat.admin_rights.post_messages || chat.admin_rights.add_admins) || chat.creator)) { - dialogsCanAddUsers.add(d); + if (chat != null && (chat.creator || chat.megagroup && (chat.admin_rights != null && (chat.admin_rights.post_messages || chat.admin_rights.add_admins) || chat.default_banned_rights == null || !chat.default_banned_rights.invite_users) || !chat.megagroup && chat.admin_rights != null && chat.admin_rights.add_admins)) { + if (chat.creator || chat.megagroup && chat.admin_rights != null || !chat.megagroup && chat.admin_rights != null) { + if (chat.megagroup) { + dialogsMyGroups.add(d); + } else { + dialogsMyChannels.add(d); + } + } else { + dialogsCanAddUsers.add(d); + } } if (chat != null && chat.megagroup) { dialogsGroupsOnly.add(d); @@ -14677,7 +14799,14 @@ public class MessagesController extends BaseController implements NotificationCe continue; } } - dialogsCanAddUsers.add(d); + TLRPC.Chat chat = getChat(-d.id); + if (chat != null && (chat.admin_rights != null && (chat.admin_rights.add_admins || chat.admin_rights.invite_users) || chat.creator)) { + if (chat.creator) { + dialogsMyGroups.add(d); + } else { + dialogsCanAddUsers.add(d); + } + } dialogsGroupsOnly.add(d); } else if (d.id != selfId) { dialogsUsersOnly.add(d); @@ -15008,9 +15137,9 @@ public class MessagesController extends BaseController implements NotificationCe int lastMessageId = (int) args[4]; if ((size < count / 2 && !isEnd) && isCache) { if (finalMessageId != 0) { - loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 3, lastMessageId, 0, 0, 0, 0, 0, 0, false, 0, true, false); + loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 3, lastMessageId, 0, 0, -1, 0, 0, 0, false, 0, true, false); } else { - loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 2, lastMessageId, 0, 0, 0, 0, 0, 0, false, 0, true, false); + loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 2, lastMessageId, 0, 0, -1, 0, 0, 0, false, 0, true, false); } } else { getNotificationCenter().removeObserver(this, NotificationCenter.messagesDidLoadWithoutProcess); @@ -15034,9 +15163,9 @@ public class MessagesController extends BaseController implements NotificationCe getNotificationCenter().addObserver(delegate, NotificationCenter.loadingMessagesFailed); if (messageId != 0) { - loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 3, 0, 0, 0, 0, 0, 0, 0, false, 0, true, false); + loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 3, 0, 0, 0, -1, 0, 0, 0, false, 0, true, false); } else { - loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 2, 0, 0, 0, 0, 0, 0, 0, false, 0, true, false); + loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 2, 0, 0, 0, -1, 0, 0, 0, false, 0, true, false); } } @@ -15106,6 +15235,111 @@ public class MessagesController extends BaseController implements NotificationCe }); } + public void checkIsInChat(TLRPC.Chat chat, TLRPC.User user, IsInChatCheckedCallback callback) { + if (chat == null || user == null) { + if (callback != null) { + callback.run(false, null, null); + } + return; + } + if (chat.megagroup || ChatObject.isChannel(chat)) { + TLRPC.TL_channels_getParticipant req = new TLRPC.TL_channels_getParticipant(); + req.channel = getInputChannel(chat.id); + req.participant = getInputPeer(user); + getConnectionsManager().sendRequest(req, (res, err) -> { + if (callback != null) { + TLRPC.ChannelParticipant participant = res instanceof TLRPC.TL_channels_channelParticipant ? ((TLRPC.TL_channels_channelParticipant) res).participant : null; + callback.run( + err == null && participant != null && !participant.left, + participant != null ? participant.admin_rights : null, + participant != null ? participant.rank : null + ); + } + }); + } else { + TLRPC.ChatFull chatFull = getChatFull(chat.id); + if (chatFull != null) { + TLRPC.ChatParticipant userParticipant = null; + if (chatFull.participants != null && chatFull.participants.participants != null) { + final int count = chatFull.participants.participants.size(); + for (int i = 0; i < count; ++i) { + TLRPC.ChatParticipant participant = chatFull.participants.participants.get(i); + if (participant != null && participant.user_id == user.id) { + userParticipant = participant; + break; + } + } + } + if (callback != null) { + callback.run( + userParticipant != null, + chatFull.participants != null && chatFull.participants.admin_id == user.id ? ChatRightsEditActivity.emptyAdminRights(true) : null, + null + ); + } + } else { + if (callback != null) { + callback.run(false, null, null); + } + } + } + } + + private void applySoundSettings(TLRPC.NotificationSound settings, SharedPreferences.Editor editor, long dialogId, int globalType, boolean serverUpdate) { + if (settings == null) { + return; + } + String soundPref; + String soundPathPref; + String soundDocPref; + if (dialogId != 0) { + soundPref = "sound_" + dialogId; + soundPathPref = "sound_path_" + dialogId; + soundDocPref = "sound_document_id_" + dialogId; + } else { + if (globalType == NotificationsController.TYPE_GROUP) { + soundPref = "GroupSound"; + soundDocPref = "GroupSoundDocId"; + soundPathPref = "GroupSoundPath"; + } else if (globalType == TYPE_PRIVATE) { + soundPref = "GlobalSound"; + soundDocPref = "GlobalSoundDocId"; + soundPathPref = "GlobalSoundPath"; + } else { + soundPref = "ChannelSound"; + soundDocPref = "ChannelSoundDocId"; + soundPathPref = "ChannelSoundPath"; + } + } + + if (settings instanceof TLRPC.TL_notificationSoundDefault) { + editor.putString(soundPref, "Default"); + editor.putString(soundPathPref, "Default"); + editor.remove(soundDocPref); + } else if (settings instanceof TLRPC.TL_notificationSoundNone) { + editor.putString(soundPref, "NoSound"); + editor.putString(soundPathPref, "NoSound"); + editor.remove(soundDocPref); + } else if (settings instanceof TLRPC.TL_notificationSoundLocal) { + TLRPC.TL_notificationSoundLocal localSound = (TLRPC.TL_notificationSoundLocal) settings; + editor.putString(soundPref, localSound.title); + editor.putString(soundPathPref, localSound.data); + editor.remove(soundDocPref); + } else if (settings instanceof TLRPC.TL_notificationSoundRingtone) { + TLRPC.TL_notificationSoundRingtone soundRingtone = (TLRPC.TL_notificationSoundRingtone) settings; + editor.putLong(soundDocPref, soundRingtone.id); + getMediaDataController().checkRingtones(); + if (serverUpdate && dialogId != 0) { + editor.putBoolean("custom_" + dialogId, true); + } + getMediaDataController().ringtoneDataStore.getDocument(soundRingtone.id); + } + } + + public interface IsInChatCheckedCallback { + void run(boolean isInChat, TLRPC.TL_chatAdminRights currentAdminRights, String rank); + } + public interface MessagesLoadedCallback { void onMessagesLoaded(boolean fromCache); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index f7d87e04d..8ce3b2678 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -82,7 +82,7 @@ public class MessagesStorage extends BaseController { private CountDownLatch openSync = new CountDownLatch(1); private static volatile MessagesStorage[] Instance = new MessagesStorage[UserConfig.MAX_ACCOUNT_COUNT]; - private final static int LAST_DB_VERSION = 92; + private final static int LAST_DB_VERSION = 93; private boolean databaseMigrationInProgress; public boolean showClearDatabaseAlert; @@ -394,6 +394,8 @@ public class MessagesStorage extends BaseController { database.executeFast("CREATE INDEX IF NOT EXISTS reaction_mentions_did ON reaction_mentions(dialog_id);").stepThis().dispose(); database.executeFast("CREATE TABLE downloading_documents(data BLOB, hash INTEGER, id INTEGER, state INTEGER, date INTEGER, PRIMARY KEY(hash, id));").stepThis().dispose(); + + database.executeFast("CREATE TABLE attach_menu_bots(data BLOB, hash INTEGER, date INTEGER);").stepThis().dispose(); //version database.executeFast("PRAGMA user_version = " + LAST_DB_VERSION).stepThis().dispose(); } else { @@ -1560,6 +1562,11 @@ public class MessagesStorage extends BaseController { version = 92; } + if (version == 92) { + database.executeFast("CREATE TABLE IF NOT EXISTS attach_menu_bots(data BLOB, hash INTEGER, date INTEGER);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 93").stepThis().dispose(); + } + FileLog.d("MessagesStorage db migration finished"); AndroidUtilities.runOnUIThread(() -> { databaseMigrationInProgress = false; @@ -2081,6 +2088,7 @@ public class MessagesStorage extends BaseController { database.executeFast("DELETE FROM reaction_mentions").stepThis().dispose(); database.executeFast("DELETE FROM downloading_documents").stepThis().dispose(); + database.executeFast("DELETE FROM attach_menu_bots").stepThis().dispose(); SQLiteCursor cursor = database.queryFinalized("SELECT did FROM dialogs WHERE 1"); StringBuilder ids = new StringBuilder(); @@ -2156,6 +2164,7 @@ public class MessagesStorage extends BaseController { } finally { AndroidUtilities.runOnUIThread(() -> { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didClearDatabase); + getMediaDataController().loadAttachMenuBots(false, true); }); } }); @@ -3354,7 +3363,7 @@ public class MessagesStorage extends BaseController { arrayList.add(message); } - protected void loadReplyMessages(LongSparseArray>> replyMessageOwners, LongSparseArray> dialogReplyMessagesIds, ArrayList usersToLoad, ArrayList chatsToLoad) throws SQLiteException { + protected void loadReplyMessages(LongSparseArray>> replyMessageOwners, LongSparseArray> dialogReplyMessagesIds, ArrayList usersToLoad, ArrayList chatsToLoad, boolean scheduled) throws SQLiteException { if (replyMessageOwners.isEmpty()) { return; } @@ -3366,7 +3375,12 @@ public class MessagesStorage extends BaseController { if (ids == null) { continue; } - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + SQLiteCursor cursor; + if (scheduled) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM scheduled_messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + } while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { @@ -3533,7 +3547,7 @@ public class MessagesStorage extends BaseController { } cursor.dispose(); - loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad); + loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false); if (!encryptedChatIds.isEmpty()) { getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad); @@ -7446,7 +7460,7 @@ public class MessagesStorage extends BaseController { } } } else { - loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad); + loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, scheduled); } if (!usersToLoad.isEmpty()) { getUsersInternal(TextUtils.join(",", usersToLoad), res.users); @@ -11540,7 +11554,7 @@ public class MessagesStorage extends BaseController { cursor.dispose(); } - loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad); + loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false); if (draftsDialogIds != null) { ArrayList unloadedDialogs = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index aa32d6975..1f094179c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -123,6 +123,7 @@ public class NotificationCenter { public static final int stickersImportProgressChanged = totalEvents++; public static final int stickersImportComplete = totalEvents++; public static final int dialogDeleted = totalEvents++; + public static final int webViewResultSent = totalEvents++; public static final int didGenerateFingerprintKeyPair = totalEvents++; @@ -233,10 +234,14 @@ public class NotificationCenter { public static final int onEmojiInteractionsReceived = totalEvents++; public static final int emojiPreviewThemesChanged = totalEvents++; public static final int reactionsDidLoad = totalEvents++; + public static final int attachMenuBotsDidLoad = totalEvents++; public static final int chatAvailableReactionsUpdated = totalEvents++; public static final int dialogsUnreadReactionsCounterChanged = totalEvents++; public static final int onDatabaseOpened = totalEvents++; public static final int onDownloadingFilesChanged = totalEvents++; + public static final int onActivityResultReceived = totalEvents++; + public static final int onRequestPermissionResultReceived = totalEvents++; + public static final int onUserRingtonesUpdated = 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 ad8238939..2a9e77d4b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -42,6 +42,10 @@ import android.os.Build; import android.os.PowerManager; import android.os.SystemClock; import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; +import android.util.SparseBooleanArray; import androidx.collection.LongSparseArray; import androidx.core.app.NotificationCompat; @@ -53,9 +57,6 @@ import androidx.core.content.LocusIdCompat; import androidx.core.content.pm.ShortcutInfoCompat; import androidx.core.content.pm.ShortcutManagerCompat; import androidx.core.graphics.drawable.IconCompat; -import android.text.TextUtils; -import android.util.SparseArray; -import android.util.SparseBooleanArray; import org.telegram.messenger.support.LongSparseIntArray; import org.telegram.tgnet.ConnectionsManager; @@ -131,6 +132,9 @@ public class NotificationsController extends BaseController { private int notificationId; private String notificationGroup; + public static final int SETTING_SOUND_ON = 0; + public static final int SETTING_SOUND_OFF = 1; + static { if (Build.VERSION.SDK_INT >= 26 && ApplicationLoader.applicationContext != null) { notificationManager = NotificationManagerCompat.from(ApplicationLoader.applicationContext); @@ -240,6 +244,40 @@ public class NotificationsController extends BaseController { } } + public void muteUntil(long did, int selectedTimeInSeconds) { + if (did != 0) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + long flags; + boolean defaultEnabled = NotificationsController.getInstance(currentAccount).isGlobalNotificationsEnabled(did); + + if (selectedTimeInSeconds == Integer.MAX_VALUE) { + if (!defaultEnabled) { + editor.remove("notify2_" + did); + flags = 0; + } else { + editor.putInt("notify2_" + did, 2); + flags = 1; + } + } else { + editor.putInt("notify2_" + did, 3); + editor.putInt("notifyuntil_" + did, getConnectionsManager().getCurrentTime() + selectedTimeInSeconds); + flags = ((long) selectedTimeInSeconds << 32) | 1; + } + NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(did); + MessagesStorage.getInstance(currentAccount).setDialogFlags(did, flags); + editor.commit(); + TLRPC.Dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); + if (dialog != null) { + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + if (selectedTimeInSeconds != Integer.MAX_VALUE || defaultEnabled) { + dialog.notify_settings.mute_until = selectedTimeInSeconds; + } + } + NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(did); + } + } + public void cleanup() { popupMessages.clear(); popupReplyMessages.clear(); @@ -3062,6 +3100,10 @@ public class NotificationsController extends BaseController { boolean secretChat = !isDefault && DialogObject.isEncryptedDialog(dialogId); boolean shouldOverwrite = !isInApp && overwriteKey != null && preferences.getBoolean(overwriteKey, false); + String soundHash = Utilities.MD5(sound == null ? "NoSound" : sound.toString()); + if (soundHash != null && soundHash.length() > 5) { + soundHash = soundHash.substring(0, 5); + } if (isSilent) { name = LocaleController.getString("NotificationsSilent", R.string.NotificationsSilent); key = "silent"; @@ -3080,6 +3122,7 @@ public class NotificationsController extends BaseController { } key = (isInApp ? "org.telegram.keyia" : "org.telegram.key") + dialogId; } + key += "_" + soundHash; String channelId = preferences.getString(key, null); String settings = preferences.getString(key + "_s", null); boolean edited = false; @@ -3163,66 +3206,6 @@ public class NotificationsController extends BaseController { } edited = true; } - if (channelSound == null && sound != null || channelSound != null && (sound == null || !TextUtils.equals(channelSound.toString(), sound.toString()))) { - if (!isInApp) { - if (editor == null) { - editor = preferences.edit(); - } - String newSound; - if (channelSound == null) { - newSound = "NoSound"; - if (isDefault) { - if (type == TYPE_CHANNEL) { - editor.putString("ChannelSound", "NoSound"); - } else if (type == TYPE_GROUP) { - editor.putString("GroupSound", "NoSound"); - } else { - editor.putString("GlobalSound", "NoSound"); - } - } else { - editor.putString("sound_" + dialogId, "NoSound"); - } - } else { - newSound = channelSound.toString(); - Ringtone rng = RingtoneManager.getRingtone(ApplicationLoader.applicationContext, channelSound); - String ringtoneName = null; - if (rng != null) { - if (channelSound.equals(Settings.System.DEFAULT_RINGTONE_URI)) { - ringtoneName = LocaleController.getString("DefaultRingtone", R.string.DefaultRingtone); - } else { - ringtoneName = rng.getTitle(ApplicationLoader.applicationContext); - } - rng.stop(); - } - if (ringtoneName != null) { - if (isDefault) { - if (type == TYPE_CHANNEL) { - editor.putString("ChannelSound", ringtoneName); - } else if (type == TYPE_GROUP) { - editor.putString("GroupSound", ringtoneName); - } else { - editor.putString("GlobalSound", ringtoneName); - } - } else { - editor.putString("sound_" + dialogId, ringtoneName); - } - } - } - if (isDefault) { - if (type == TYPE_CHANNEL) { - editor.putString("ChannelSoundPath", newSound); - } else if (type == TYPE_GROUP) { - editor.putString("GroupSoundPath", newSound); - } else { - editor.putString("GlobalSoundPath", newSound); - } - } else { - editor.putString("sound_path_" + dialogId, newSound); - } - } - sound = channelSound; - edited = true; - } boolean hasVibration = !isEmptyVibration(vibrationPattern); if (hasVibration != vibrate) { if (!isInApp) { @@ -3334,7 +3317,7 @@ public class NotificationsController extends BaseController { if (sound != null) { notificationChannel.setSound(sound, builder.build()); } else { - notificationChannel.setSound(null, builder.build()); + notificationChannel.setSound(null, null); } if (BuildVars.LOGS_ENABLED) { FileLog.d("create new channel " + channelId); @@ -3390,6 +3373,7 @@ public class NotificationsController extends BaseController { boolean notifyDisabled = false; int vibrate = 0; String soundPath = null; + boolean isInternalSoundFile = false; int ledColor = 0xff0000ff; int importance = 0; @@ -3541,6 +3525,10 @@ public class NotificationsController extends BaseController { } } + if (!notifyDisabled && !preferences.getBoolean("sound_enabled_" + dialog_id, true)) { + notifyDisabled = true; + } + String defaultPath = Settings.System.DEFAULT_NOTIFICATION_URI.getPath(); boolean isDefault = true; @@ -3548,13 +3536,20 @@ public class NotificationsController extends BaseController { int chatType = TYPE_PRIVATE; String customSoundPath; + boolean customIsInternalSound = false; int customVibrate; int customImportance; Integer customLedColor; if (preferences.getBoolean("custom_" + dialog_id, false)) { customVibrate = preferences.getInt("vibrate_" + dialog_id, 0); customImportance = preferences.getInt("priority_" + dialog_id, 3); - customSoundPath = preferences.getString("sound_path_" + dialog_id, null); + long soundDocumentId = preferences.getLong("sound_document_id_" + dialog_id, 0); + if (soundDocumentId != 0) { + customIsInternalSound = true; + customSoundPath = getMediaDataController().ringtoneDataStore.getSoundPath(soundDocumentId); + } else { + customSoundPath = preferences.getString("sound_path_" + dialog_id, null); + } if (preferences.contains("color_" + dialog_id)) { customLedColor = preferences.getInt("color_" + dialog_id, 0); } else { @@ -3570,20 +3565,38 @@ public class NotificationsController extends BaseController { if (chatId != 0) { if (isChannel) { - soundPath = preferences.getString("ChannelSoundPath", defaultPath); + long soundDocumentId = preferences.getLong("ChannelSoundDocId", 0); + if (soundDocumentId != 0) { + isInternalSoundFile = true; + soundPath = getMediaDataController().ringtoneDataStore.getSoundPath(soundDocumentId); + } else { + soundPath = preferences.getString("ChannelSoundPath", defaultPath); + } vibrate = preferences.getInt("vibrate_channel", 0); importance = preferences.getInt("priority_channel", 1); ledColor = preferences.getInt("ChannelLed", 0xff0000ff); chatType = TYPE_CHANNEL; } else { - soundPath = preferences.getString("GroupSoundPath", defaultPath); + long soundDocumentId = preferences.getLong("GroupSoundDocId", 0); + if (soundDocumentId != 0) { + isInternalSoundFile = true; + soundPath = getMediaDataController().ringtoneDataStore.getSoundPath(soundDocumentId); + } else { + soundPath = preferences.getString("GroupSoundPath", defaultPath); + } vibrate = preferences.getInt("vibrate_group", 0); importance = preferences.getInt("priority_group", 1); ledColor = preferences.getInt("GroupLed", 0xff0000ff); chatType = TYPE_GROUP; } } else if (userId != 0) { - soundPath = preferences.getString("GlobalSoundPath", defaultPath); + long soundDocumentId = preferences.getLong("GlobalSoundDocId", 0); + if (soundDocumentId != 0) { + isInternalSoundFile = true; + soundPath = getMediaDataController().ringtoneDataStore.getSoundPath(soundDocumentId); + } else { + soundPath = preferences.getString("GlobalSoundPath", defaultPath); + } vibrate = preferences.getInt("vibrate_messages", 0); importance = preferences.getInt("priority_messages", 1); ledColor = preferences.getInt("MessagesLed", 0xff0000ff); @@ -3593,7 +3606,8 @@ public class NotificationsController extends BaseController { vibrateOnlyIfSilent = true; vibrate = 0; } - if (customSoundPath != null && !TextUtils.equals(soundPath, customSoundPath)) { + if (!TextUtils.isEmpty(customSoundPath) && !TextUtils.equals(soundPath, customSoundPath)) { + isInternalSoundFile = customIsInternalSound; soundPath = customSoundPath; isDefault = false; } @@ -3760,10 +3774,15 @@ public class NotificationsController extends BaseController { } if (soundPath != null && !soundPath.equals("NoSound")) { if (Build.VERSION.SDK_INT >= 26) { - if (soundPath.equals(defaultPath)) { + if (soundPath.equals("Default") || soundPath.equals(defaultPath)) { sound = Settings.System.DEFAULT_NOTIFICATION_URI; } else { - sound = Uri.parse(soundPath); + if (isInternalSoundFile) { + sound = FileProvider.getUriForFile(ApplicationLoader.applicationContext, BuildConfig.APPLICATION_ID + ".provider", new File(soundPath)); + ApplicationLoader.applicationContext.grantUriPermission("com.android.systemui", sound, Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + sound = Uri.parse(soundPath); + } } } else { if (soundPath.equals(defaultPath)) { @@ -3920,7 +3939,6 @@ public class NotificationsController extends BaseController { arrayList.add(messageObject); } - LongSparseArray oldIdsWear = new LongSparseArray<>(); for (int i = 0; i < wearNotificationsIds.size(); i++) { oldIdsWear.put(wearNotificationsIds.keyAt(i), wearNotificationsIds.valueAt(i)); @@ -4586,6 +4604,7 @@ public class NotificationsController extends BaseController { public static final int SETTING_MUTE_2_DAYS = 2; public static final int SETTING_MUTE_FOREVER = 3; public static final int SETTING_MUTE_UNMUTE = 4; + public static final int SETTING_MUTE_CUSTOM = 5; public void clearDialogNotificationsSettings(long did) { SharedPreferences preferences = getAccountInstance().getNotificationsSettings(); @@ -4677,7 +4696,28 @@ public class NotificationsController extends BaseController { } } + long soundDocumentId = preferences.getLong("sound_document_id_" + dialogId, 0); + String soundPath = preferences.getString("sound_path_" + dialogId, null); + req.settings.flags |= 8; + if (soundDocumentId != 0) { + TLRPC.TL_notificationSoundRingtone ringtoneSound = new TLRPC.TL_notificationSoundRingtone(); + ringtoneSound.id = soundDocumentId; + req.settings.sound = ringtoneSound; + } else if (soundPath != null) { + if (soundPath.equals("NoSound")){ + req.settings.sound = new TLRPC.TL_notificationSoundNone(); + } else { + TLRPC.TL_notificationSoundLocal localSound = new TLRPC.TL_notificationSoundLocal(); + localSound.title = preferences.getString("sound_" + dialogId, null); + localSound.data = soundPath; + req.settings.sound = localSound; + } + } else { + req.settings.sound = new TLRPC.TL_notificationSoundDefault(); + } + req.peer = new TLRPC.TL_inputNotifyPeer(); + ((TLRPC.TL_inputNotifyPeer) req.peer).peer = getMessagesController().getInputPeer(dialogId); getConnectionsManager().sendRequest(req, (response, error) -> { @@ -4693,18 +4733,51 @@ public class NotificationsController extends BaseController { TLRPC.TL_account_updateNotifySettings req = new TLRPC.TL_account_updateNotifySettings(); req.settings = new TLRPC.TL_inputPeerNotifySettings(); req.settings.flags = 5; + String soundDocumentIdPref; + String soundPathPref; + String soundNamePref; if (type == TYPE_GROUP) { req.peer = new TLRPC.TL_inputNotifyChats(); req.settings.mute_until = preferences.getInt("EnableGroup2", 0); req.settings.show_previews = preferences.getBoolean("EnablePreviewGroup", true); + soundNamePref = "GroupSound"; + soundDocumentIdPref = "GroupSoundDocId"; + soundPathPref = "GroupSoundPath"; } else if (type == TYPE_PRIVATE) { req.peer = new TLRPC.TL_inputNotifyUsers(); req.settings.mute_until = preferences.getInt("EnableAll2", 0); req.settings.show_previews = preferences.getBoolean("EnablePreviewAll", true); + soundNamePref = "GlobalSound"; + soundDocumentIdPref = "GlobalSoundDocId"; + soundPathPref = "GlobalSoundPath"; } else { req.peer = new TLRPC.TL_inputNotifyBroadcasts(); req.settings.mute_until = preferences.getInt("EnableChannel2", 0); req.settings.show_previews = preferences.getBoolean("EnablePreviewChannel", true); + soundNamePref = "ChannelSound"; + soundDocumentIdPref = "ChannelSoundDocId"; + soundPathPref = "ChannelSoundPath"; + } + + req.settings.flags |= 8; + long soundDocumentId = preferences.getLong(soundDocumentIdPref, 0); + String soundPath = preferences.getString(soundPathPref, "NoSound"); + + if (soundDocumentId != 0) { + TLRPC.TL_notificationSoundRingtone ringtoneSound = new TLRPC.TL_notificationSoundRingtone(); + ringtoneSound.id = soundDocumentId; + req.settings.sound = ringtoneSound; + } else if (soundPath != null) { + if (soundPath.equals("NoSound")){ + req.settings.sound = new TLRPC.TL_notificationSoundNone(); + } else { + TLRPC.TL_notificationSoundLocal localSound = new TLRPC.TL_notificationSoundLocal(); + localSound.title = preferences.getString(soundNamePref, null); + localSound.data = soundPath; + req.settings.sound = localSound; + } + } else { + req.settings.sound = new TLRPC.TL_notificationSoundDefault(); } getConnectionsManager().sendRequest(req, (response, error) -> { @@ -4758,4 +4831,26 @@ public class NotificationsController extends BaseController { return "EnableChannel2"; } } + + public void muteDialog(long dialog_id, boolean mute) { + if (mute) { + NotificationsController.getInstance(currentAccount).muteUntil(dialog_id, Integer.MAX_VALUE); + } else { + boolean defaultEnabled = NotificationsController.getInstance(currentAccount).isGlobalNotificationsEnabled(dialog_id); + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + if (defaultEnabled) { + editor.remove("notify2_" + dialog_id); + } else { + editor.putInt("notify2_" + dialog_id, 0); + } + getMessagesStorage().setDialogFlags(dialog_id, 0); + editor.apply(); + TLRPC.Dialog dialog = getMessagesController().dialogs_dict.get(dialog_id); + if (dialog != null) { + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + } + updateServerNotificationsSettings(dialog_id); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/OneUIUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/OneUIUtilities.java index 1f83a748d..1afbc7646 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/OneUIUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/OneUIUtilities.java @@ -2,8 +2,15 @@ package org.telegram.messenger; import android.os.Build; +import java.lang.reflect.Field; + public class OneUIUtilities { + public final static int ONE_UI_4_0 = 40000; + private static Boolean isOneUI; + private static int oneUIEncodedVersion; + private static int oneUIMajorVersion; + private static float oneUIMinorVersion; @SuppressWarnings("JavaReflectionMemberAccess") public static boolean isOneUI() { @@ -12,11 +19,46 @@ public class OneUIUtilities { } try { - Build.VERSION.class.getDeclaredField("SEM_PLATFORM_INT"); + Field f = Build.VERSION.class.getDeclaredField("SEM_PLATFORM_INT"); + f.setAccessible(true); + int semPlatformInt = (int) f.get(null); + if (semPlatformInt < 100000) { + // Samsung Experience then + return false; + } + + oneUIEncodedVersion = semPlatformInt - 90000; + oneUIMajorVersion = oneUIEncodedVersion / 10000; + oneUIMinorVersion = (oneUIEncodedVersion % 10000) / 100F; isOneUI = true; - } catch (NoSuchFieldException e) { + } catch (Exception e) { isOneUI = false; } return isOneUI; } + + public static boolean hasBuiltInClipboardToasts() { + return isOneUI() && getOneUIEncodedVersion() == ONE_UI_4_0; + } + + public static int getOneUIMajorVersion() { + if (!isOneUI()) { + return 0; + } + return oneUIMajorVersion; + } + + public static int getOneUIEncodedVersion() { + if (!isOneUI()) { + return 0; + } + return oneUIEncodedVersion; + } + + public static float getOneUIMinorVersion() { + if (!isOneUI()) { + return 0; + } + return oneUIMinorVersion; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index bdced2950..2baedb789 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -1934,6 +1934,16 @@ public class SendMessagesHelper extends BaseController implements NotificationCe objArr.add(newMsgObj); arr.add(newMsg); + if (msgObj.replyMessageObject != null) { + for (int i = 0; i < messages.size(); i++) { + if (messages.get(i).getId() == msgObj.replyMessageObject.getId()) { + newMsgObj.messageOwner.replyMessage = msgObj.replyMessageObject.messageOwner; + newMsgObj.replyMessageObject = msgObj.replyMessageObject; + break; + } + } + } + putToSendingMessages(newMsg, scheduleDate != 0); boolean differentDialog = false; @@ -2746,6 +2756,27 @@ public class SendMessagesHelper extends BaseController implements NotificationCe passwordFragment.needHideProgress(); passwordFragment.finishFragment(); } + + long uid = messageObject.getFromChatId(); + if (messageObject.messageOwner.via_bot_id != 0) { + uid = messageObject.messageOwner.via_bot_id; + } + String name = null; + if (uid > 0) { + TLRPC.User user = getMessagesController().getUser(uid); + if (user != null) { + name = ContactsController.formatName(user.first_name, user.last_name); + } + } else { + TLRPC.Chat chat = getMessagesController().getChat(-uid); + if (chat != null) { + name = chat.title; + } + } + if (name == null) { + name = "bot"; + } + if (button instanceof TLRPC.TL_keyboardButtonUrlAuth) { if (response instanceof TLRPC.TL_urlAuthResultRequest) { TLRPC.TL_urlAuthResultRequest res = (TLRPC.TL_urlAuthResultRequest) response; @@ -2770,26 +2801,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (!cacheFinal && res.cache_time != 0 && !button.requires_password) { getMessagesStorage().saveBotCache(key, res); } + if (res.message != null) { - long uid = messageObject.getFromChatId(); - if (messageObject.messageOwner.via_bot_id != 0) { - uid = messageObject.messageOwner.via_bot_id; - } - String name = null; - if (uid > 0) { - TLRPC.User user = getMessagesController().getUser(uid); - if (user != null) { - name = ContactsController.formatName(user.first_name, user.last_name); - } - } else { - TLRPC.Chat chat = getMessagesController().getChat(-uid); - if (chat != null) { - name = chat.title; - } - } - if (name == null) { - name = "bot"; - } if (res.alert) { if (parentFragment.getParentActivity() == null) { return; @@ -2806,10 +2819,6 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (parentFragment.getParentActivity() == null) { return; } - long uid = messageObject.getFromChatId(); - if (messageObject.messageOwner.via_bot_id != 0) { - uid = messageObject.messageOwner.via_bot_id; - } TLRPC.User user = getMessagesController().getUser(uid); boolean verified = user != null && user.verified; if (button instanceof TLRPC.TL_keyboardButtonGame) { @@ -7868,7 +7877,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe selectedCompression = compressionsCount; } boolean needCompress = false; - if (selectedCompression != compressionsCount - 1 || Math.max(videoEditedInfo.originalWidth, videoEditedInfo.originalHeight) > 1280) { + if (selectedCompression != compressionsCount || Math.max(videoEditedInfo.originalWidth, videoEditedInfo.originalHeight) > 1280) { needCompress = true; switch (selectedCompression) { case 1: diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index e7462b352..39f0cca36 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -806,7 +806,10 @@ public class SharedConfig { SharedPreferences.Editor editor = preferences.edit(); editor.putBoolean("save_gallery", saveToGallery); editor.commit(); - checkSaveToGalleryFiles(); + ImageLoader.getInstance().checkMediaPaths(); + ImageLoader.getInstance().getCacheOutQueue().postRunnable(() -> { + checkSaveToGalleryFiles(); + }); } public static void toggleAutoplayGifs() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedPrefsHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedPrefsHelper.java new file mode 100644 index 000000000..33e7f44bb --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedPrefsHelper.java @@ -0,0 +1,36 @@ +package org.telegram.messenger; + +import android.content.Context; +import android.content.SharedPreferences; + +public class SharedPrefsHelper { + private static String WEB_VIEW_SHOWN_DIALOG_FORMAT = "confirm_shown_%d_%d"; + + private static SharedPreferences webViewBotsPrefs; + + public static void init(Context ctx) { + webViewBotsPrefs = ctx.getSharedPreferences("webview_bots", Context.MODE_PRIVATE); + } + + public static boolean isWebViewConfirmShown(int currentAccount, long botId) { + return webViewBotsPrefs.getBoolean(String.format(WEB_VIEW_SHOWN_DIALOG_FORMAT, currentAccount, botId), false); + } + + public static void setWebViewConfirmShown(int currentAccount, long botId, boolean shown) { + webViewBotsPrefs.edit().putBoolean(String.format(WEB_VIEW_SHOWN_DIALOG_FORMAT, currentAccount, botId), shown).apply(); + } + + public static void cleanupAccount(int account) { + SharedPreferences.Editor editor = webViewBotsPrefs.edit(); + for (String key : webViewBotsPrefs.getAll().keySet()) { + if (key.startsWith("confirm_shown_" + account + "_")) { + editor.remove(key); + } + } + editor.apply(); + } + + public static SharedPreferences getWebViewBotsPrefs() { + return webViewBotsPrefs; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 9470e1a97..ea3f1862a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -27,7 +27,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class Utilities { - public static Pattern pattern = Pattern.compile("[\\-0-9]+"); public static SecureRandom random = new SecureRandom(); public static Random fastRandom = new Xoroshiro128PlusRandom(random.nextLong()); @@ -39,6 +38,8 @@ public class Utilities { public static volatile DispatchQueue phoneBookQueue = new DispatchQueue("phoneBookQueue"); public static volatile DispatchQueue themeQueue = new DispatchQueue("themeQueue"); + private final static String RANDOM_STRING_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); static { @@ -405,4 +406,16 @@ public class Utilities { public static float clamp(float value, float top, float bottom) { return Math.max(Math.min(value, top), bottom); } + + public static String generateRandomString() { + return generateRandomString(16); + } + + public static String generateRandomString(int chars) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < chars; i++) { + sb.append(RANDOM_STRING_CHARS.charAt(fastRandom.nextInt(RANDOM_STRING_CHARS.length()))); + } + return sb.toString(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index f0b59ae0e..ae3bbf151 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -13,6 +13,7 @@ import android.view.View; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.PhotoFilterView; import org.telegram.ui.Components.Point; @@ -84,6 +85,7 @@ public class VideoEditedInfo { public Bitmap bitmap; public View view; + public AnimatedFileDrawable animatedFileDrawable; public MediaEntity() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneDataStore.java b/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneDataStore.java new file mode 100644 index 000000000..14ac394ea --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneDataStore.java @@ -0,0 +1,318 @@ +package org.telegram.messenger.ringtone; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.SerializedData; +import org.telegram.tgnet.TLRPC; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; + +public class RingtoneDataStore { + + private final long clientUserId; + String prefName = null; + + private static volatile long queryHash; + private static volatile long lastReloadTimeMs; + private final int currentAccount; + private int localIds; + + private static final long reloadTimeoutMs = 24 * 60 * 60 * 1000;//1 day + + public final ArrayList userRingtones = new ArrayList<>(); + private boolean loaded; + + public final static HashSet ringtoneSupportedMimeType = new HashSet<>(Arrays.asList("audio/mpeg", "audio/ogg", "audio/m4a")); + + public RingtoneDataStore(int currentAccount) { + this.currentAccount = currentAccount; + this.clientUserId = UserConfig.getInstance(currentAccount).clientUserId; + SharedPreferences preferences = getSharedPreferences(); + try { + queryHash = preferences.getLong("hash", 0); + lastReloadTimeMs = preferences.getLong("lastReload", 0); + } catch (Exception e) { + FileLog.e(e); + } + loadUserRingtones(); + } + + public void loadUserRingtones() { + boolean needReload = System.currentTimeMillis() - lastReloadTimeMs > reloadTimeoutMs; + TLRPC.TL_account_getSavedRingtones req = new TLRPC.TL_account_getSavedRingtones(); + req.hash = queryHash; + if (needReload) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + if (response instanceof TLRPC.TL_account_savedRingtonesNotModified) { + loadFromPrefs(true); + } else if (response instanceof TLRPC.TL_account_savedRingtones) { + TLRPC.TL_account_savedRingtones res = (TLRPC.TL_account_savedRingtones) response; + saveTones(res.ringtones); + getSharedPreferences().edit() + .putLong("hash", queryHash = res.hash) + .putLong("lastReload", lastReloadTimeMs = System.currentTimeMillis()) + .apply(); + } + checkRingtoneSoundsLoaded(); + } + })); + } else { + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + checkRingtoneSoundsLoaded(); + } + } + + private void loadFromPrefs(boolean notify) { + SharedPreferences preferences = getSharedPreferences(); + int count = preferences.getInt("count", 0); + userRingtones.clear(); + for (int i = 0; i < count; ++i) { + String value = preferences.getString("tone_document" + i, ""); + String localPath = preferences.getString("tone_local_path" + i, ""); + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + try { + TLRPC.Document document = TLRPC.Document.TLdeserialize(serializedData, serializedData.readInt32(true), true); + CachedTone tone = new CachedTone(); + tone.document = document; + tone.localUri = localPath; + tone.localId = localIds++; + userRingtones.add(tone); + } catch (Throwable e) { + if (BuildVars.DEBUG_PRIVATE_VERSION) { + throw e; + } + FileLog.e(e); + } + } + if (notify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + } + + private void saveTones(ArrayList ringtones) { + if (!loaded) { + loadFromPrefs(false); + loaded = true; + } + HashMap documentIdToLocalFilePath = new HashMap<>(); + for (CachedTone cachedTone : userRingtones) { + if (cachedTone.localUri != null && cachedTone.document != null) { + documentIdToLocalFilePath.put(cachedTone.document.id, cachedTone.localUri); + } + } + userRingtones.clear(); + SharedPreferences preferences = getSharedPreferences(); + preferences.edit().clear().apply(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("count", ringtones.size()); + + for (int i = 0; i < ringtones.size(); i++) { + TLRPC.Document document = ringtones.get(i); + String localPath = documentIdToLocalFilePath.get(document.id); + SerializedData data = new SerializedData(document.getObjectSize()); + document.serializeToStream(data); + editor.putString("tone_document" + i, Utilities.bytesToHex(data.toByteArray())); + if (localPath != null) { + editor.putString("tone_local_path" + i, localPath); + } + CachedTone tone = new CachedTone(); + tone.document = document; + tone.localUri = localPath; + tone.localId = localIds++; + userRingtones.add(tone); + } + editor.apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + + public void saveTones() { + SharedPreferences preferences = getSharedPreferences(); + preferences.edit().clear().apply(); + SharedPreferences.Editor editor = preferences.edit(); + + int count = 0; + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).uploading) { + continue; + } + count++; + TLRPC.Document document = userRingtones.get(i).document; + String localPath = userRingtones.get(i).localUri; + SerializedData data = new SerializedData(document.getObjectSize()); + document.serializeToStream(data); + editor.putString("tone_document" + i, Utilities.bytesToHex(data.toByteArray())); + if (localPath != null) { + editor.putString("tone_local_path" + i, localPath); + } + } + + editor.putInt("count", count); + editor.apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + + + private SharedPreferences getSharedPreferences() { + if (prefName == null) { + prefName = "ringtones_pref_" + clientUserId; + } + return ApplicationLoader.applicationContext.getSharedPreferences(prefName, Context.MODE_PRIVATE); + } + + public void addUploadingTone(String filePath) { + CachedTone cachedTone = new CachedTone(); + cachedTone.localUri = filePath; + cachedTone.localId = localIds++; + cachedTone.uploading = true; + userRingtones.add(cachedTone); + } + + public void onRingtoneUploaded(String filePath, TLRPC.Document document, boolean error) { + boolean changed = false; + if (error) { + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).uploading && filePath.equals(userRingtones.get(i).localUri)) { + userRingtones.remove(i); + changed = true; + break; + } + } + } else { + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).uploading && filePath.equals(userRingtones.get(i).localUri)) { + userRingtones.get(i).uploading = false; + userRingtones.get(i).document = document; + changed = true; + break; + } + } + if (changed) { + saveTones(); + } + } + if (changed) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + } + + public String getSoundPath(long id) { + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).document != null && userRingtones.get(i).document.id == id) { + if (!TextUtils.isEmpty(userRingtones.get(i).localUri)) { + return userRingtones.get(i).localUri; + } + return FileLoader.getPathToAttach(userRingtones.get(i).document).toString(); + } + } + return "NoSound"; + } + + public void checkRingtoneSoundsLoaded() { + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + final ArrayList cachedTones = new ArrayList<>(userRingtones); + Utilities.globalQueue.postRunnable(() -> { + for (int i = 0; i < cachedTones.size(); i++) { + CachedTone tone = cachedTones.get(i); + if (!TextUtils.isEmpty(tone.localUri)) { + File file = new File(tone.localUri); + if (file.exists()) { + continue; + } + } + + if (tone.document != null) { + TLRPC.Document document = tone.document; + File file = FileLoader.getPathToAttach(document); + if (file == null || !file.exists()) { + AndroidUtilities.runOnUIThread(() -> { + FileLoader.getInstance(currentAccount).loadFile(document, null, 0, 0); + }); + } + } + } + }); + + } + + public boolean isLoaded() { + return loaded; + } + + public void remove(TLRPC.Document document) { + if (document == null) { + return; + } + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).document != null && userRingtones.get(i).document.id == document.id) { + userRingtones.remove(i); + break; + } + } + } + + public boolean contains(long id) { + return getDocument(id) != null; + } + + public void addTone(TLRPC.Document document) { + if (document == null || contains(document.id)) { + return; + } + CachedTone cachedTone = new CachedTone(); + cachedTone.document = document; + cachedTone.localId = localIds++; + cachedTone.uploading = false; + userRingtones.add(cachedTone); + saveTones(); + } + + public TLRPC.Document getDocument(long id) { + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).document != null && userRingtones.get(i).document.id == id) { + return userRingtones.get(i).document; + } + } + return null; + } + + public class CachedTone { + public TLRPC.Document document; + public String localUri; + public int localId; + public boolean uploading; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneUploader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneUploader.java new file mode 100644 index 000000000..f0566c216 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneUploader.java @@ -0,0 +1,97 @@ +package org.telegram.messenger.ringtone; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.Bulletin; + +import java.io.File; + +public class RingtoneUploader implements NotificationCenter.NotificationCenterDelegate { + + private int currentAccount; + public final String filePath; + private boolean canceled; + + public RingtoneUploader(String filePath, int currentAccount) { + this.currentAccount = currentAccount; + this.filePath = filePath; + subscribe(); + FileLoader.getInstance(currentAccount).uploadFile(filePath, false, true, ConnectionsManager.FileTypeAudio); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.fileUploaded) { + final String location = (String) args[0]; + if (canceled) { + return; + } + if (location.equals(filePath)) { + final TLRPC.InputFile file = (TLRPC.InputFile) args[1]; + TLRPC.TL_account_uploadRingtone req = new TLRPC.TL_account_uploadRingtone(); + req.file = file; + req.file_name = file.name; + req.mime_type = FileLoader.getFileExtension(new File(file.name)); + if ("ogg".equals(req.mime_type)) { + req.mime_type = "audio/ogg"; + } else { + req.mime_type = "audio/mpeg"; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + onComplete((TLRPC.Document) response); + } else { + error(error); + } + unsubscribe(); + }); + }); + } + } + } + + private void subscribe() { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.fileUploaded); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.fileUploadFailed); + } + + private void unsubscribe() { + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileUploaded); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileUploadFailed); + } + + private void onComplete(TLRPC.Document document) { + MediaDataController.getInstance(currentAccount).onRingtoneUploaded(filePath, document, false); + } + + public void cancel() { + canceled = true; + unsubscribe(); + FileLoader.getInstance(currentAccount).cancelFileUpload(filePath, false); + MediaDataController.getInstance(currentAccount).onRingtoneUploaded(filePath, null, true); + } + + public void error(TLRPC.TL_error error) { + unsubscribe(); + MediaDataController.getInstance(currentAccount).onRingtoneUploaded(filePath, null, true); + if (error != null) { + NotificationCenter.getInstance(currentAccount).doOnIdle(() -> { + if (error.text.equals("RINGTONE_DURATION_TOO_LONG")) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("TooLongError", R.string.TooLongError), LocaleController.formatString("ErrorRingtoneDurationTooLong", R.string.ErrorRingtoneDurationTooLong, MessagesController.getInstance(currentAccount).ringtoneDurationMax)); + } else if (error.text.equals("RINGTONE_SIZE_TOO_BIG")) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("TooLargeError", R.string.TooLargeError), LocaleController.formatString("ErrorRingtoneSizeTooBig", R.string.ErrorRingtoneSizeTooBig, (MessagesController.getInstance(currentAccount).ringtoneSizeMax / 1024))); + } else { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("InvalidFormatError", R.string.InvalidFormatError), LocaleController.formatString("ErrorRingtoneInvalidFormat", R.string.ErrorRingtoneInvalidFormat)); + } + }); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java index 989ba9d37..f7a34449c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java @@ -330,6 +330,12 @@ public class MediaCodecVideoConvertor { long additionalPresentationTime = 0; long minPresentationTime = Integer.MIN_VALUE; long frameDelta = 1000 / framerate * 1000; + long frameDeltaFroSkipFrames; + if (framerate < 30) { + frameDeltaFroSkipFrames = 1000 / (framerate + 5) * 1000; + } else { + frameDeltaFroSkipFrames = 1000 / (framerate + 1) * 1000; + } extractor.selectTrack(videoIndex); MediaFormat videoFormat = extractor.getTrackFormat(videoIndex); @@ -681,7 +687,7 @@ public class MediaCodecVideoConvertor { decoder.flush(); flushed = true; } - if (lastFramePts > 0 && info.presentationTimeUs - lastFramePts < frameDelta && (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) == 0) { + if (lastFramePts > 0 && info.presentationTimeUs - lastFramePts < frameDeltaFroSkipFrames && (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) == 0) { doRender = false; } trueStartTime = avatarStartTime >= 0 ? avatarStartTime : startTime; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java index 1d34cb14a..9445351e3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java @@ -8,14 +8,6 @@ package org.telegram.messenger.video; -import java.io.File; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; -import java.nio.channels.FileChannel; -import java.util.ArrayList; - import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -35,22 +27,32 @@ import android.view.Gravity; import android.view.View; import android.view.inputmethod.EditorInfo; +import androidx.annotation.RequiresApi; +import androidx.exifinterface.media.ExifInterface; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Bitmaps; import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLog; import org.telegram.messenger.MediaController; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; +import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.FilterShaders; import org.telegram.ui.Components.Paint.Views.EditTextOutline; import org.telegram.ui.Components.RLottieDrawable; -import javax.microedition.khronos.opengles.GL10; +import java.io.File; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; -import androidx.annotation.RequiresApi; -import androidx.exifinterface.media.ExifInterface; +import javax.microedition.khronos.opengles.GL10; public class TextureRenderer { @@ -121,6 +123,7 @@ public class TextureRenderer { private int[] paintTexture; private int[] stickerTexture; private Bitmap stickerBitmap; + private Canvas stickerCanvas; private float videoFps; private int imageOrientation; @@ -398,10 +401,31 @@ public class TextureRenderer { entity.currentFrame = 0; } drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); - } else if (entity.bitmap != null) { - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, entity.bitmap, 0); - drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); + } else if (entity.animatedFileDrawable != null) { + int lastFrame = (int) entity.currentFrame; + entity.currentFrame += entity.framesPerDraw; + int currentFrame = (int) entity.currentFrame; + while (lastFrame != currentFrame) { + entity.animatedFileDrawable.getNextFrame(); + currentFrame--; + } + Bitmap frameBitmap = entity.animatedFileDrawable.getBackgroundBitmap(); + if (stickerCanvas == null && stickerBitmap != null) { + stickerCanvas = new Canvas(stickerBitmap); + } + if (stickerBitmap != null && frameBitmap != null) { + stickerBitmap.eraseColor(Color.TRANSPARENT); + stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); + drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); + } + } else { + if (entity.bitmap != null) { + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, entity.bitmap, 0); + drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); + } } } } @@ -608,6 +632,10 @@ public class TextureRenderer { entity.metadata = new int[3]; entity.ptr = RLottieDrawable.create(entity.text, null, 512, 512, entity.metadata, false, null, false, 0); entity.framesPerDraw = entity.metadata[1] / videoFps; + } else if ((entity.subType & 4) != 0) { + entity.animatedFileDrawable = new AnimatedFileDrawable(new File(entity.text), true, 0, null, null, null, 0, UserConfig.selectedAccount, true, 512, 512); + entity.framesPerDraw = videoFps / 30f; + entity.currentFrame = 0; } else { if (Build.VERSION.SDK_INT >= 19) { entity.bitmap = BitmapFactory.decodeFile(entity.text); @@ -713,6 +741,9 @@ public class TextureRenderer { if (entity.ptr != 0) { RLottieDrawable.destroy(entity.ptr); } + if (entity.animatedFileDrawable != null) { + entity.animatedFileDrawable.recycle(); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/Instance.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/Instance.java index 85a387160..06256befb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/Instance.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/Instance.java @@ -15,7 +15,7 @@ import java.util.List; public final class Instance { - public static final List AVAILABLE_VERSIONS = Build.VERSION.SDK_INT >= 18 ? Arrays.asList("4.0.0", "3.0.0", "2.7.7", "2.4.4") : Arrays.asList("2.4.4"); + public static final List AVAILABLE_VERSIONS = Build.VERSION.SDK_INT >= 18 ? Arrays.asList("4.0.1", "4.0.0", "3.0.0", "2.7.7", "2.4.4") : Arrays.asList("2.4.4"); public static final int AUDIO_STATE_MUTED = 0; public static final int AUDIO_STATE_ACTIVE = 1; @@ -283,7 +283,7 @@ public final class Instance { public static final class FinalState { public final byte[] persistentState; - public final String debugLog; + public String debugLog; public final TrafficStats trafficStats; public final boolean isRatingSuggested; 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 399b4e89f..9eefe7afd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java @@ -108,7 +108,6 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.XiaomiUtilities; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.BottomSheet; @@ -124,9 +123,13 @@ import org.webrtc.VideoFrame; import org.webrtc.VideoSink; import org.webrtc.voiceengine.WebRtcAudioTrack; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigInteger; @@ -2332,11 +2335,11 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa final boolean enableAec = !(sysAecAvailable && serverConfig.useSystemAec); final boolean enableNs = !(sysNsAvailable && serverConfig.useSystemNs); final String logFilePath = BuildVars.DEBUG_VERSION ? VoIPHelper.getLogFilePath("voip" + privateCall.id) : VoIPHelper.getLogFilePath(privateCall.id, false); - final String statisLogFilePath = ""; - final Instance.Config config = new Instance.Config(initializationTimeout, receiveTimeout, voipDataSaving, privateCall.p2p_allowed, enableAec, enableNs, true, false, serverConfig.enableStunMarking, logFilePath, statisLogFilePath, privateCall.protocol.max_layer); + final String statsLogFilePath = VoIPHelper.getLogFilePath(privateCall.id, true); + final Instance.Config config = new Instance.Config(initializationTimeout, receiveTimeout, voipDataSaving, privateCall.p2p_allowed, enableAec, enableNs, true, false, serverConfig.enableStunMarking, logFilePath, statsLogFilePath, privateCall.protocol.max_layer); // persistent state - final String persistentStateFilePath = new File(ApplicationLoader.applicationContext.getFilesDir(), "voip_persistent_state.json").getAbsolutePath(); + final String persistentStateFilePath = new File(ApplicationLoader.applicationContext.getCacheDir(), "voip_persistent_state.json").getAbsolutePath(); // endpoints final boolean forceTcp = preferences.getBoolean("dbg_force_tcp_in_calls", false); @@ -3362,10 +3365,37 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa }*/ } + public static String convertStreamToString(InputStream is) throws Exception { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + String line = null; + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + reader.close(); + return sb.toString(); + } + + public static String getStringFromFile(String filePath) throws Exception { + File fl = new File(filePath); + FileInputStream fin = new FileInputStream(fl); + String ret = convertStreamToString(fin); + fin.close(); + return ret; + } + private void onTgVoipStop(Instance.FinalState finalState) { if (user == null) { return; } + if (TextUtils.isEmpty(finalState.debugLog)) { + try { + finalState.debugLog = getStringFromFile(VoIPHelper.getLogFilePath(privateCall.id, true)); + } catch (Exception e) { + e.printStackTrace(); + } + } + if (needRateCall || forceRating || finalState.isRatingSuggested) { startRatingActivity(); needRateCall = false; diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index 49bb8bc2b..af0091477 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -66,7 +66,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 = 139; + public static final int LAYER = 140; public static class TL_stats_megagroupStats extends TLObject { public static int constructor = 0xef7ff916; @@ -7975,6 +7975,85 @@ public class TLRPC { } } + public static class TL_notificationSoundDefault extends NotificationSound { + public static int constructor = 0x97e8bebe; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notificationSoundNone extends NotificationSound { + public static int constructor = 0x6f0c34df; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notificationSoundRingtone extends NotificationSound { + public static int constructor = 0xff6c8049; + + public long id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + } + } + + public static class TL_notificationSoundLocal extends NotificationSound { + public static int constructor = 0x830b9ae4; + + public String title; + public String data; + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + data = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + stream.writeString(data); + } + } + + public static abstract class NotificationSound extends TLObject { + + public static NotificationSound TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + NotificationSound result = null; + switch (constructor) { + case 0x97e8bebe: + result = new TL_notificationSoundDefault(); + break; + case 0x6f0c34df: + result = new TL_notificationSoundNone(); + break; + case 0xff6c8049: + result = new TL_notificationSoundRingtone(); + break; + case 0x830b9ae4: + result = new TL_notificationSoundLocal(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in NotificationSound", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + public static abstract class PeerNotifySettings extends TLObject { public int flags; public int mute_until; @@ -7982,15 +8061,21 @@ public class TLRPC { public boolean show_previews; public int events_mask; public boolean silent; + public NotificationSound ios_sound; + public NotificationSound android_sound; + public NotificationSound other_sound; public static PeerNotifySettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { PeerNotifySettings result = null; switch (constructor) { + case 0xa83b0426: + result = new TL_peerNotifySettings(); + break; case 0x9acda4c0: result = new TL_peerNotifySettings_layer77(); break; case 0xaf509d20: - result = new TL_peerNotifySettings(); + result = new TL_peerNotifySettings_layer139(); break; case 0x8d5e11ee: result = new TL_peerNotifySettings_layer47(); @@ -8031,6 +8116,55 @@ public class TLRPC { } public static class TL_peerNotifySettings extends PeerNotifySettings { + public static int constructor = 0xa83b0426; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + show_previews = stream.readBool(exception); + } + if ((flags & 2) != 0) { + silent = stream.readBool(exception); + } + if ((flags & 4) != 0) { + mute_until = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + ios_sound = NotificationSound.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16) != 0) { + android_sound = NotificationSound.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32) != 0) { + other_sound = NotificationSound.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeBool(show_previews); + } + if ((flags & 2) != 0) { + stream.writeBool(silent); + } + if ((flags & 4) != 0) { + stream.writeInt32(mute_until); + } + if ((flags & 8) != 0) { + ios_sound.serializeToStream(stream); + } + if ((flags & 16) != 0) { + android_sound.serializeToStream(stream); + } + if ((flags & 32) != 0) { + other_sound.serializeToStream(stream); + } + } + } + + public static class TL_peerNotifySettings_layer139 extends TL_peerNotifySettings { public static int constructor = 0xaf509d20; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -9097,6 +9231,7 @@ public class TLRPC { public String description; public ArrayList commands = new ArrayList<>(); public int version; + public BotMenuButton menu_button; public static BotInfo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { BotInfo result = null; @@ -9111,6 +9246,9 @@ public class TLRPC { result = new TL_botInfo_layer48(); break; case 0x1b74b335: + result = new TL_botInfo_layer139(); + break; + case 0xe4169b5d: result = new TL_botInfo(); break; } @@ -9211,7 +9349,7 @@ public class TLRPC { } } - public static class TL_botInfo extends BotInfo { + public static class TL_botInfo_layer139 extends BotInfo { public static int constructor = 0x1b74b335; @@ -9248,6 +9386,45 @@ public class TLRPC { } } + public static class TL_botInfo extends BotInfo { + public static int constructor = 0xe4169b5d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt64(exception); + description = 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_botCommand object = TL_botCommand.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + commands.add(object); + } + menu_button = BotMenuButton.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(user_id); + stream.writeString(description); + stream.writeInt32(0x1cb5c415); + int count = commands.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + commands.get(a).serializeToStream(stream); + } + menu_button.serializeToStream(stream); + } + } + public static abstract class InputGame extends TLObject { public InputUser bot_id; public String short_name; @@ -10505,6 +10682,8 @@ public class TLRPC { public int requests_pending; public Peer default_send_as; public ArrayList available_reactions = new ArrayList<>(); + public int flags2; + public boolean can_delete_channel; public long inviterId; //custom public int invitesCount; //custom @@ -10515,9 +10694,12 @@ public class TLRPC { case 0xd18ee226: result = new TL_chatFull(); break; - case 0xe13c3d20: + case 0xea68a619: result = new TL_channelFull(); break; + case 0xe13c3d20: + result = new TL_channelFull_layer139(); + break; case 0x56662e2e: result = new TL_channelFull_layer135(); break; @@ -12810,6 +12992,277 @@ public class TLRPC { } public static class TL_channelFull extends ChatFull { + public static int constructor = 0xea68a619; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_view_participants = (flags & 8) != 0; + can_set_username = (flags & 64) != 0; + can_set_stickers = (flags & 128) != 0; + hidden_prehistory = (flags & 1024) != 0; + can_set_location = (flags & 65536) != 0; + has_scheduled = (flags & 524288) != 0; + can_view_stats = (flags & 1048576) != 0; + blocked = (flags & 4194304) != 0; + flags2 = stream.readInt32(exception); + can_delete_channel = (flags2 & 1) != 0; + id = stream.readInt64(exception); + about = stream.readString(exception); + if ((flags & 1) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + admins_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + kicked_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + banned_count = stream.readInt32(exception); + } + if ((flags & 8192) != 0) { + online_count = stream.readInt32(exception); + } + read_inbox_max_id = stream.readInt32(exception); + read_outbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 8388608) != 0) { + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + } + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + BotInfo object = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bot_info.add(object); + } + if ((flags & 16) != 0) { + migrated_from_chat_id = stream.readInt64(exception); + } + if ((flags & 16) != 0) { + migrated_from_max_id = stream.readInt32(exception); + } + if ((flags & 32) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + if ((flags & 256) != 0) { + stickerset = StickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 512) != 0) { + available_min_id = stream.readInt32(exception); + } + if ((flags & 2048) != 0) { + folder_id = stream.readInt32(exception); + } + if ((flags & 16384) != 0) { + linked_chat_id = stream.readInt64(exception); + } + if ((flags & 32768) != 0) { + location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + slowmode_seconds = stream.readInt32(exception); + } + if ((flags & 262144) != 0) { + slowmode_next_send_date = stream.readInt32(exception); + } + if ((flags & 4096) != 0) { + stats_dc = stream.readInt32(exception); + } + pts = stream.readInt32(exception); + if ((flags & 2097152) != 0) { + call = TL_inputGroupCall.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16777216) != 0) { + ttl_period = stream.readInt32(exception); + } + if ((flags & 33554432) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + pending_suggestions.add(stream.readString(exception)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 134217728) != 0) { + theme_emoticon = stream.readString(exception); + } + if ((flags & 268435456) != 0) { + requests_pending = stream.readInt32(exception); + } + if ((flags & 268435456) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + recent_requesters.add(stream.readInt64(exception)); + } + } + if ((flags & 536870912) != 0) { + default_send_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 1073741824) != 0) { + 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++) { + available_reactions.add(stream.readString(exception)); + } + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_view_participants ? (flags | 8) : (flags &~ 8); + flags = can_set_username ? (flags | 64) : (flags &~ 64); + flags = can_set_stickers ? (flags | 128) : (flags &~ 128); + flags = hidden_prehistory ? (flags | 1024) : (flags &~ 1024); + flags = can_set_location ? (flags | 65536) : (flags &~ 65536); + flags = has_scheduled ? (flags | 524288) : (flags &~ 524288); + flags = can_view_stats ? (flags | 1048576) : (flags &~ 1048576); + flags = blocked ? (flags | 4194304) : (flags &~ 4194304); + stream.writeInt32(flags); + flags2 = can_delete_channel ? (flags2 | 1) : (flags2 &~ 1); + stream.writeInt32(flags2); + stream.writeInt64(id); + stream.writeString(about); + if ((flags & 1) != 0) { + stream.writeInt32(participants_count); + } + if ((flags & 2) != 0) { + stream.writeInt32(admins_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(kicked_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(banned_count); + } + if ((flags & 8192) != 0) { + stream.writeInt32(online_count); + } + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(read_outbox_max_id); + stream.writeInt32(unread_count); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + if ((flags & 8388608) != 0) { + exported_invite.serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + int count = bot_info.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bot_info.get(a).serializeToStream(stream); + } + if ((flags & 16) != 0) { + stream.writeInt64(migrated_from_chat_id); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_max_id); + } + if ((flags & 32) != 0) { + stream.writeInt32(pinned_msg_id); + } + if ((flags & 256) != 0) { + stickerset.serializeToStream(stream); + } + if ((flags & 512) != 0) { + stream.writeInt32(available_min_id); + } + if ((flags & 2048) != 0) { + stream.writeInt32(folder_id); + } + if ((flags & 16384) != 0) { + stream.writeInt64(linked_chat_id); + } + if ((flags & 32768) != 0) { + location.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(slowmode_seconds); + } + if ((flags & 262144) != 0) { + stream.writeInt32(slowmode_next_send_date); + } + if ((flags & 4096) != 0) { + stream.writeInt32(stats_dc); + } + stream.writeInt32(pts); + if ((flags & 2097152) != 0) { + call.serializeToStream(stream); + } + if ((flags & 16777216) != 0) { + stream.writeInt32(ttl_period); + } + if ((flags & 33554432) != 0) { + stream.writeInt32(0x1cb5c415); + count = pending_suggestions.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(pending_suggestions.get(a)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as.serializeToStream(stream); + } + if ((flags & 134217728) != 0) { + stream.writeString(theme_emoticon); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(requests_pending); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(0x1cb5c415); + count = recent_requesters.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(recent_requesters.get(a)); + } + } + if ((flags & 536870912) != 0) { + default_send_as.serializeToStream(stream); + } + if ((flags & 1073741824) != 0) { + stream.writeInt32(0x1cb5c415); + count = available_reactions.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(available_reactions.get(a)); + } + } + } + } + + public static class TL_channelFull_layer139 extends ChatFull { public static int constructor = 0xe13c3d20; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -15272,13 +15725,13 @@ public class TLRPC { } public static class TL_inputPeerNotifySettings extends TLObject { - public static int constructor = 0x9c3d198e; + public static int constructor = 0xdf1f002b; public int flags; public boolean show_previews; public boolean silent; public int mute_until; - public String sound; + public NotificationSound sound; public static TL_inputPeerNotifySettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_inputPeerNotifySettings.constructor != constructor) { @@ -15305,7 +15758,7 @@ public class TLRPC { mute_until = stream.readInt32(exception); } if ((flags & 8) != 0) { - sound = stream.readString(exception); + sound = NotificationSound.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -15322,7 +15775,7 @@ public class TLRPC { stream.writeInt32(mute_until); } if ((flags & 8) != 0) { - stream.writeString(sound); + sound.serializeToStream(stream); } } } @@ -16266,6 +16719,9 @@ public class TLRPC { public static KeyboardButton TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { KeyboardButton result = null; switch (constructor) { + case 0xa0c0505c: + result = new TL_keyboardButtonSimpleWebView(); + break; case 0xb16a6c29: result = new TL_keyboardButtonRequestPhone(); break; @@ -16308,6 +16764,9 @@ public class TLRPC { case 0x308660c1: result = new TL_keyboardButtonUserProfile(); break; + case 0x13767230: + result = new TL_keyboardButtonWebView(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in KeyboardButton", constructor)); @@ -19749,6 +20208,8 @@ public class TLRPC { public boolean inactive; public boolean explicit_content; public ArrayList restriction_reason = new ArrayList<>(); + public boolean bot_attach_menu; + public boolean bot_menu_webview; public static User TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { User result = null; @@ -19907,6 +20368,8 @@ public class TLRPC { scam = (flags & 16777216) != 0; apply_min_photo = (flags & 33554432) != 0; fake = (flags & 67108864) != 0; + bot_attach_menu = (flags & 134217728) != 0; + bot_menu_webview = (flags & 268435456) != 0; id = stream.readInt64(exception); if ((flags & 1) != 0) { access_hash = stream.readInt64(exception); @@ -19974,6 +20437,8 @@ public class TLRPC { flags = scam ? (flags | 16777216) : (flags &~ 16777216); flags = apply_min_photo ? (flags | 33554432) : (flags &~ 33554432); flags = fake ? (flags | 67108864) : (flags &~ 67108864); + flags = bot_attach_menu ? (flags | 134217728) : (flags &~ 134217728); + flags = bot_menu_webview ? (flags | 268435456) : (flags &~ 268435456); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 1) != 0) { @@ -21319,6 +21784,12 @@ public class TLRPC { case 0xd95c6154: result = new TL_messageActionSecureValuesSent(); break; + case 0x47dd8079: + result = new TL_messageActionWebViewDataSentMe(); + break; + case 0xb4c38cb5: + result = new TL_messageActionWebViewDataSent(); + break; case 0xf89cf5e8: result = new TL_messageActionChatJoinedByLink_layer131(); break; @@ -21818,6 +22289,39 @@ public class TLRPC { } } + public static class TL_messageActionWebViewDataSentMe extends MessageAction { + public static int constructor = 0x47dd8079; + + public String text; + public String data; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + data = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(data); + } + } + + public static class TL_messageActionWebViewDataSent extends MessageAction { + public static int constructor = 0xb4c38cb5; + + public String text; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + } + } + public static class TL_messageActionUserJoined extends MessageAction { public static int constructor = 0x55555550; @@ -27440,6 +27944,9 @@ public class TLRPC { case 0x62ba04d9: result = new TL_updateNewChannelMessage(); break; + case 0x1592b79d: + result = new TL_updateWebViewResultSent(); + break; case 0x6e6fe51c: result = new TL_updateDialogPinned(); break; @@ -27581,6 +28088,9 @@ public class TLRPC { case 0xfa0f3ca2: result = new TL_updatePinnedDialogs(); break; + case 0x74d8be99: + result = new TL_updateSavedRingtones(); + break; case 0xb4afcfb0: result = new TL_updatePeerLocated(); break; @@ -27617,6 +28127,9 @@ public class TLRPC { case 0xf227868c: result = new TL_updateUserPhoto(); break; + case 0x17b7a20b: + result = new TL_updateAttachMenuBots(); + break; case 0x3504914f: result = new TL_updateDialogFilters(); break; @@ -27656,6 +28169,9 @@ public class TLRPC { case 0x54c01850: result = new TL_updateChatDefaultBannedRights(); break; + case 0x14b85813: + result = new TL_updateBotMenuButton(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in Update", constructor)); @@ -28669,6 +29185,14 @@ public class TLRPC { } } + public static class TL_updateSavedRingtones extends Update { + public static int constructor = 0x74d8be99; + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + public static class TL_updateLangPack extends Update { public static int constructor = 0x56022f4d; @@ -41981,13 +42505,18 @@ public class TLRPC { public String theme_emoticon; public long id; public String private_forward_name; + public TL_chatAdminRights bot_group_admin_rights; + public TL_chatAdminRights bot_broadcast_admin_rights; public static UserFull TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { UserFull result = null; switch (constructor) { - case 0xcf366521: + case 0x8c72ea81: result = new TL_userFull(); break; + case 0xcf366521: + result = new TL_userFull_layer139(); + break; case 0xd697ff05: result = new TL_userFull_layer134(); break; @@ -42015,6 +42544,99 @@ public class TLRPC { } public static class TL_userFull extends UserFull { + public static int constructor = 0x8c72ea81; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + blocked = (flags & 1) != 0; + phone_calls_available = (flags & 16) != 0; + phone_calls_private = (flags & 32) != 0; + can_pin_message = (flags & 128) != 0; + has_scheduled = (flags & 4096) != 0; + video_calls_available = (flags & 8192) != 0; + id = stream.readInt64(exception); + if ((flags & 2) != 0) { + about = stream.readString(exception); + } + settings = TL_peerSettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + profile_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 8) != 0) { + bot_info = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 64) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + common_chats_count = stream.readInt32(exception); + if ((flags & 2048) != 0) { + folder_id = stream.readInt32(exception); + } + if ((flags & 16384) != 0) { + ttl_period = stream.readInt32(exception); + } + if ((flags & 32768) != 0) { + theme_emoticon = stream.readString(exception); + } + if ((flags & 65536) != 0) { + private_forward_name = stream.readString(exception); + } + if ((flags & 131072) != 0) { + bot_group_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 262144) != 0) { + bot_broadcast_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = blocked ? (flags | 1) : (flags &~ 1); + flags = phone_calls_available ? (flags | 16) : (flags &~ 16); + flags = phone_calls_private ? (flags | 32) : (flags &~ 32); + flags = can_pin_message ? (flags | 128) : (flags &~ 128); + flags = has_scheduled ? (flags | 4096) : (flags &~ 4096); + flags = video_calls_available ? (flags | 8192) : (flags &~ 8192); + stream.writeInt32(flags); + stream.writeInt64(id); + if ((flags & 2) != 0) { + stream.writeString(about); + } + settings.serializeToStream(stream); + if ((flags & 4) != 0) { + profile_photo.serializeToStream(stream); + } + notify_settings.serializeToStream(stream); + if ((flags & 8) != 0) { + bot_info.serializeToStream(stream); + } + if ((flags & 64) != 0) { + stream.writeInt32(pinned_msg_id); + } + stream.writeInt32(common_chats_count); + if ((flags & 2048) != 0) { + stream.writeInt32(folder_id); + } + if ((flags & 16384) != 0) { + stream.writeInt32(ttl_period); + } + if ((flags & 32768) != 0) { + stream.writeString(theme_emoticon); + } + if ((flags & 65536) != 0) { + stream.writeString(private_forward_name); + } + if ((flags & 131072) != 0) { + bot_group_admin_rights.serializeToStream(stream); + } + if ((flags & 262144) != 0) { + bot_broadcast_admin_rights.serializeToStream(stream); + } + } + } + + public static class TL_userFull_layer139 extends UserFull { public static int constructor = 0xcf366521; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -49879,6 +50501,27 @@ public class TLRPC { } } + public static class TL_messages_sendWebViewData extends TLObject { + public static int constructor = 0xdc0242c8; + + public InputUser bot; + public long random_id; + public String button_text; + public String data; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + bot.serializeToStream(stream); + stream.writeInt64(random_id); + stream.writeString(button_text); + stream.writeString(data); + } + } + public static class TL_messages_getMessagesReactions extends TLObject { public static int constructor = 0x8bba90e6; @@ -51478,17 +52121,21 @@ public class TLRPC { } public static class TL_channels_deleteHistory extends TLObject { - public static int constructor = 0xaf369d42; + public static int constructor = 0x9baa9647; + public int flags; + public boolean for_everyone; public InputChannel channel; public int max_id; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return Bool.TLdeserialize(stream, constructor, exception); + return Updates.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = for_everyone ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); channel.serializeToStream(stream); stream.writeInt32(max_id); } @@ -57562,6 +58209,956 @@ public class TLRPC { } } + public static class TL_attachMenuBot extends TLObject { + public static int constructor = 0xe93cb772; + + public int flags; + public boolean inactive; + public long bot_id; + public String short_name; + public ArrayList icons = new ArrayList<>(); + + public static TL_attachMenuBot TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_attachMenuBot.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_attachMenuBot", constructor)); + } else { + return null; + } + } + TL_attachMenuBot result = new TL_attachMenuBot(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + inactive = (flags & 1) != 0; + bot_id = stream.readInt64(exception); + short_name = 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_attachMenuBotIcon object = TL_attachMenuBotIcon.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + icons.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = inactive ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt64(bot_id); + stream.writeString(short_name); + stream.writeInt32(0x1cb5c415); + int count = icons.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + icons.get(a).serializeToStream(stream); + } + } + } + + public static abstract class AttachMenuBots extends TLObject { + + public static AttachMenuBots TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + AttachMenuBots result = null; + switch (constructor) { + case 0xf1d88a5c: + result = new TL_attachMenuBotsNotModified(); + break; + case 0x3c4301c0: + result = new TL_attachMenuBots(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in AttachMenuBots", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_attachMenuBotsNotModified extends AttachMenuBots { + public static int constructor = 0xf1d88a5c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_attachMenuBots extends AttachMenuBots { + public static int constructor = 0x3c4301c0; + + public long hash; + public ArrayList bots = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt64(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_attachMenuBot object = TL_attachMenuBot.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bots.add(object); + } + 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++) { + 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.writeInt64(hash); + stream.writeInt32(0x1cb5c415); + int count = bots.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bots.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_updateAttachMenuBots extends Update { + public static int constructor = 0x17b7a20b; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_webViewResult extends TLObject { + public static int constructor = 0xaadf159b; + + public BotInlineResult result; + public ArrayList users = new ArrayList<>(); + + public static TL_messages_webViewResult TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_webViewResult.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_webViewResult", constructor)); + } else { + return null; + } + } + TL_messages_webViewResult result = new TL_messages_webViewResult(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + result = BotInlineResult.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); + result.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 class TL_keyboardButtonWebView extends KeyboardButton { + public static int constructor = 0x13767230; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(url); + } + } + + public static class TL_messages_getAttachMenuBots extends TLObject { + public static int constructor = 0x16fcc2cb; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return AttachMenuBots.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + + public static class TL_messages_toggleBotInAttachMenu extends TLObject { + public static int constructor = 0x1aee33af; + + public InputUser bot; + public boolean enabled; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + bot.serializeToStream(stream); + stream.writeBool(enabled); + } + } + + public static class TL_webViewResultUrl extends TLObject { + public static int constructor = 0xc14557c; + + public long query_id; + public String url; + + public static TL_webViewResultUrl TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_webViewResultUrl.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_webViewResultUrl", constructor)); + } else { + return null; + } + } + TL_webViewResultUrl result = new TL_webViewResultUrl(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + query_id = stream.readInt64(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + stream.writeString(url); + } + } + + public static class TL_messages_requestWebView extends TLObject { + public static int constructor = 0xfa04dff; + + public int flags; + public boolean silent; + public boolean background; + public InputPeer peer; + public InputUser bot; + public String url; + public String start_param; + public TL_dataJSON theme_params; + public int reply_to_msg_id; + public boolean from_bot_menu; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_webViewResultUrl.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); + flags = from_bot_menu ? (flags | 16) : (flags &~ 16); + stream.writeInt32(flags); + peer.serializeToStream(stream); + bot.serializeToStream(stream); + if ((flags & 2) != 0) { + stream.writeString(url); + } + if ((flags & 8) != 0) { + stream.writeString(start_param); + } + if ((flags & 4) != 0) { + theme_params.serializeToStream(stream); + } + if ((flags & 1) != 0) { + stream.writeInt32(reply_to_msg_id); + } + } + } + + public static class TL_messages_prolongWebView extends TLObject { + public static int constructor = 0xd22ad148; + + public int flags; + public boolean silent; + public InputPeer peer; + public InputUser bot; + public long query_id; + public int reply_to_msg_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = silent ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + peer.serializeToStream(stream); + bot.serializeToStream(stream); + stream.writeInt64(query_id); + if ((flags & 1) != 0) { + stream.writeInt32(reply_to_msg_id); + } + } + } + + public static class TL_messages_requestSimpleWebView extends TLObject { + public static int constructor = 0x6abb2f73; + + public int flags; + public InputUser bot; + public String url; + public TL_dataJSON theme_params; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_simpleWebViewResultUrl.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + bot.serializeToStream(stream); + stream.writeString(url); + if ((flags & 1) != 0) { + theme_params.serializeToStream(stream); + } + } + } + + public static class TL_messages_sendWebViewResultMessage extends TLObject { + public static int constructor = 0xddcf50eb; + + public long query_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_webViewMessageSent.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + } + } + + public static class TL_messages_setWebViewResult extends TLObject { + public static int constructor = 0xe41cd11d; + + public long query_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + } + } + + public static class TL_messages_getWebViewResult extends TLObject { + public static int constructor = 0x22b6c214; + + public InputPeer peer; + public InputUser bot; + public long query_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_webViewResult.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + bot.serializeToStream(stream); + stream.writeInt64(query_id); + } + } + + public static class TL_attachMenuBotsBot extends TLObject { + public static int constructor = 0x93bf667f; + + public TL_attachMenuBot bot; + public ArrayList users = new ArrayList<>(); + + public static TL_attachMenuBotsBot TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_attachMenuBotsBot.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_attachMenuBotsBot", constructor)); + } else { + return null; + } + } + TL_attachMenuBotsBot result = new TL_attachMenuBotsBot(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + bot = TL_attachMenuBot.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); + bot.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 class TL_simpleWebViewResultUrl extends TLObject { + public static int constructor = 0x882f76bb; + + public String url; + + public static TL_simpleWebViewResultUrl TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_simpleWebViewResultUrl.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_simpleWebViewResultUrl", constructor)); + } else { + return null; + } + } + TL_simpleWebViewResultUrl result = new TL_simpleWebViewResultUrl(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + } + } + + public static class TL_webViewMessageSent extends TLObject { + public static int constructor = 0xc94511c; + + public int flags; + public TL_inputBotInlineMessageID msg_id; + + public static TL_webViewMessageSent TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_webViewMessageSent.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_webViewMessageSent", constructor)); + } else { + return null; + } + } + TL_webViewMessageSent result = new TL_webViewMessageSent(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + msg_id = TL_inputBotInlineMessageID.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + msg_id.serializeToStream(stream); + } + } + } + + public static class TL_updateWebViewResultSent extends Update { + public static int constructor = 0x1592b79d; + + public long query_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + query_id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + } + } + + public static class TL_keyboardButtonSimpleWebView extends KeyboardButton { + public static int constructor = 0xa0c0505c; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(url); + } + } + + public static class TL_messages_getAttachMenuBot extends TLObject { + public static int constructor = 0x77216192; + + public InputUser bot; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_attachMenuBotsBot.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + bot.serializeToStream(stream); + } + } + + public static abstract class account_SavedRingtones extends TLObject { + + public static account_SavedRingtones TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + account_SavedRingtones result = null; + switch (constructor) { + case 0xfbf6e8b1: + result = new TL_account_savedRingtonesNotModified(); + break; + case 0xc1e92cc5: + result = new TL_account_savedRingtones(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in account_SavedRingtones", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_account_savedRingtonesNotModified extends account_SavedRingtones { + public static int constructor = 0xfbf6e8b1; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_account_savedRingtones extends account_SavedRingtones { + public static int constructor = 0xc1e92cc5; + + public long hash; + public ArrayList ringtones = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt64(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Document object = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + ringtones.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + stream.writeInt32(0x1cb5c415); + int count = ringtones.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + ringtones.get(a).serializeToStream(stream); + } + } + } + + public static class TL_account_uploadRingtone extends TLObject { + public static int constructor = 0x831a83a2; + + public InputFile file; + public String file_name; + public String mime_type; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Document.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + file.serializeToStream(stream); + stream.writeString(file_name); + stream.writeString(mime_type); + } + } + + public static class TL_account_getSavedRingtones extends TLObject { + public static int constructor = 0xe1902288; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return account_SavedRingtones.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + + public static class TL_account_saveRingtone extends TLObject { + public static int constructor = 0x3dea5b03; + + public InputDocument id; + public boolean unsave; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return account_SavedRingtone.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + stream.writeBool(unsave); + } + } + + public static class TL_attachMenuBotIconColor extends TLObject { + public static int constructor = 0x4576f3f0; + + public String name; + public int color; + + public static TL_attachMenuBotIconColor TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_attachMenuBotIconColor.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_attachMenuBotIconColor", constructor)); + } else { + return null; + } + } + TL_attachMenuBotIconColor result = new TL_attachMenuBotIconColor(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + name = stream.readString(exception); + color = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(name); + stream.writeInt32(color); + } + } + + public static class TL_attachMenuBotIcon extends TLObject { + public static int constructor = 0xb2a7386b; + + public int flags; + public String name; + public Document icon; + public ArrayList colors = new ArrayList<>(); + + public static TL_attachMenuBotIcon TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_attachMenuBotIcon.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_attachMenuBotIcon", constructor)); + } else { + return null; + } + } + TL_attachMenuBotIcon result = new TL_attachMenuBotIcon(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + name = stream.readString(exception); + icon = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 1) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_attachMenuBotIconColor object = TL_attachMenuBotIconColor.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + colors.add(object); + } + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(name); + icon.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = colors.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + colors.get(a).serializeToStream(stream); + } + } + } + } + + public static abstract class BotMenuButton extends TLObject { + + public static BotMenuButton TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + BotMenuButton result = null; + switch (constructor) { + case 0xc7b57ce6: + result = new TL_botMenuButton(); + break; + case 0x7533a588: + result = new TL_botMenuButtonDefault(); + break; + case 0x4258c205: + result = new TL_botMenuButtonCommands(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in BotMenuButton", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_botMenuButton extends BotMenuButton { + public static int constructor = 0xc7b57ce6; + + public String text; + public String url; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(url); + } + } + + public static class TL_botMenuButtonDefault extends BotMenuButton { + public static int constructor = 0x7533a588; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_botMenuButtonCommands extends BotMenuButton { + public static int constructor = 0x4258c205; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_updateBotMenuButton extends Update { + public static int constructor = 0x14b85813; + + public long bot_id; + public BotMenuButton button; + + public void readParams(AbstractSerializedData stream, boolean exception) { + bot_id = stream.readInt64(exception); + button = BotMenuButton.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(bot_id); + button.serializeToStream(stream); + } + } + + public static class TL_bots_setBotMenuButton extends TLObject { + public static int constructor = 0x4504d54f; + + public InputUser user_id; + public BotMenuButton button; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + user_id.serializeToStream(stream); + button.serializeToStream(stream); + } + } + + public static class TL_bots_getBotMenuButton extends TLObject { + public static int constructor = 0x9c60eb28; + + public InputUser user_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return BotMenuButton.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + user_id.serializeToStream(stream); + } + } + + public static abstract class account_SavedRingtone extends TLObject { + + public static account_SavedRingtone TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + account_SavedRingtone result = null; + switch (constructor) { + case 0x1f307eb7: + result = new TL_account_savedRingtoneConverted(); + break; + case 0xb7263f6d: + result = new TL_account_savedRingtone(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in account_SavedRingtone", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_account_savedRingtoneConverted extends account_SavedRingtone { + public static int constructor = 0x1f307eb7; + + public Document document; + + public void readParams(AbstractSerializedData stream, boolean exception) { + document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + document.serializeToStream(stream); + } + } + + public static class TL_account_savedRingtone extends account_SavedRingtone { + public static int constructor = 0xb7263f6d; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } //functions public static class Vector extends TLObject { 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 7290a988a..283670468 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java @@ -14,7 +14,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; import org.telegram.ui.Adapters.FiltersView; import org.telegram.ui.Components.RLottieDrawable; @@ -91,7 +94,15 @@ public class ActionBarMenu extends LinearLayout { } public ActionBarMenuItem addItem(int id, int icon, CharSequence text, int backgroundColor, Drawable drawable, int width, CharSequence title, Theme.ResourcesProvider resourcesProvider) { - ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, backgroundColor, isActionMode ? parentActionBar.itemsActionModeColor : parentActionBar.itemsColor, text != null, resourcesProvider); + ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, backgroundColor, isActionMode ? parentActionBar.itemsActionModeColor : parentActionBar.itemsColor, text != null, resourcesProvider) { + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (icon == R.drawable.ic_ab_other && (id == 0 || id == 14)) { + Log.d("kek", id + " " + (View.VISIBLE == visibility)); + } + } + }; menuItem.setTag(id); if (text != null) { menuItem.textView.setText(text); 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 4598a8f6b..af93f999e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -50,6 +50,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; @@ -169,6 +170,8 @@ public class ActionBarMenuItem extends FrameLayout { private View showSubMenuFrom; private final Theme.ResourcesProvider resourcesProvider; + private OnClickListener onClickListener; + public ActionBarMenuItem(Context context, ActionBarMenu menu, int backgroundColor, int iconColor) { this(context, menu, backgroundColor, iconColor, false); } @@ -337,7 +340,7 @@ public class ActionBarMenuItem extends FrameLayout { } rect = new Rect(); location = new int[2]; - popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), resourcesProvider); + popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), R.drawable.popup_fixed_alert2, resourcesProvider, ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_USE_SWIPEBACK); popupLayout.setOnTouchListener((v, event) -> { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { if (popupWindow != null && popupWindow.isShowing()) { @@ -354,6 +357,14 @@ public class ActionBarMenuItem extends FrameLayout { popupWindow.dismiss(); } }); + + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().setOnClickListener(view -> { + if (popupWindow != null) { + popupWindow.dismiss(); + } + }); + } } public void removeAllSubItems() { @@ -511,6 +522,35 @@ public class ActionBarMenuItem extends FrameLayout { return cell; } + public ActionBarMenuSubItem addSwipeBackItem(int icon, Drawable iconDrawable, String text, View viewToSwipeBack) { + createPopupLayout(); + + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getContext(), false, false, false, resourcesProvider); + cell.setTextAndIcon(text, icon, iconDrawable); + cell.setMinimumWidth(AndroidUtilities.dp(196)); + cell.setRightIcon(R.drawable.msg_arrowright); + popupLayout.addView(cell); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams(); + if (LocaleController.isRTL) { + layoutParams.gravity = Gravity.RIGHT; + } + layoutParams.width = LayoutHelper.MATCH_PARENT; + layoutParams.height = AndroidUtilities.dp(48); + cell.setLayoutParams(layoutParams); + int swipeBackIndex = popupLayout.addViewToSwipeBack(viewToSwipeBack); + cell.openSwipeBackLayout = () -> { + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().openForeground(swipeBackIndex); + } + }; + cell.setOnClickListener(view -> { + cell.openSwipeBack(); + }); + + popupLayout.swipeBackGravityRight = true; + return cell; + } + public View addDivider(int color) { createPopupLayout(); @@ -579,6 +619,9 @@ public class ActionBarMenuItem extends FrameLayout { } public ActionBarPopupWindow.ActionBarPopupWindowLayout getPopupLayout() { + if (popupLayout == null) { + createPopupLayout(); + } return popupLayout; } @@ -613,7 +656,11 @@ public class ActionBarMenuItem extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { popupLayout.measure(widthMeasureSpec, heightMeasureSpec); - topView.getLayoutParams().width = popupLayout.getMeasuredWidth() - AndroidUtilities.dp(16); + if (popupLayout.getSwipeBack() != null) { + topView.getLayoutParams().width = popupLayout.getSwipeBack().getChildAt(0).getMeasuredWidth(); + } else { + topView.getLayoutParams().width = popupLayout.getMeasuredWidth() - AndroidUtilities.dp(16); + } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }; @@ -629,6 +676,7 @@ public class ActionBarMenuItem extends FrameLayout { linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); linearLayout.addView(popupLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 0, -AndroidUtilities.dp(4), 0, 0)); container = linearLayout; + popupLayout.setTopView(frameLayout); } popupWindow = new ActionBarPopupWindow(container, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); if (animationEnabled && Build.VERSION.SDK_INT >= 19) { @@ -673,6 +721,9 @@ public class ActionBarMenuItem extends FrameLayout { updateOrShowPopup(true, false); } popupLayout.updateRadialSelectors(); + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().closeForeground(false); + } popupWindow.startAnimation(); } public void toggleSubMenu() { @@ -1389,6 +1440,15 @@ public class ActionBarMenuItem extends FrameLayout { return this; } + public OnClickListener getOnClickListener() { + return onClickListener; + } + + @Override + public void setOnClickListener(@Nullable OnClickListener l) { + super.setOnClickListener(onClickListener = l); + } + private void checkClearButton() { if (clearButton != null) { if (!hasRemovableFilters() && TextUtils.isEmpty(searchField.getText()) && @@ -1853,4 +1913,27 @@ public class ActionBarMenuItem extends FrameLayout { return color != null ? color : Theme.getColor(key); } } + + public View addColoredGap() { + createPopupLayout(); + View gap = new ActionBarPopupWindow.GapView(getContext(), Theme.key_graySection); + gap.setTag(R.id.fit_width_tag, 1); + popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + return gap; + } + + public static ActionBarMenuSubItem addItem(ActionBarPopupWindow.ActionBarPopupWindowLayout windowLayout, int icon, String text, boolean needCheck, Theme.ResourcesProvider resourcesProvider) { + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(windowLayout.getContext(), needCheck, false, false, resourcesProvider); + cell.setTextAndIcon(text, icon); + cell.setMinimumWidth(AndroidUtilities.dp(196)); + windowLayout.addView(cell); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams(); + if (LocaleController.isRTL) { + layoutParams.gravity = Gravity.RIGHT; + } + layoutParams.width = LayoutHelper.MATCH_PARENT; + layoutParams.height = AndroidUtilities.dp(48); + cell.setLayoutParams(layoutParams); + return cell; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java index c52acdb62..6e97e7e0c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java @@ -34,6 +34,7 @@ public class ActionBarMenuSubItem extends FrameLayout { private int itemHeight = 48; private final Theme.ResourcesProvider resourcesProvider; + Runnable openSwipeBackLayout; public ActionBarMenuSubItem(Context context, boolean top, boolean bottom) { this(context, false, top, bottom); @@ -108,7 +109,7 @@ public class ActionBarMenuSubItem extends FrameLayout { if (rightIcon == null) { rightIcon = new ImageView(getContext()); rightIcon.setScaleType(ImageView.ScaleType.CENTER); - rightIcon.setColorFilter(textColor, PorterDuff.Mode.MULTIPLY); + rightIcon.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); if (LocaleController.isRTL) { rightIcon.setScaleX(-1); } @@ -237,4 +238,14 @@ public class ActionBarMenuSubItem extends FrameLayout { public CheckBox2 getCheckView() { return checkView; } + + public void openSwipeBack() { + if (openSwipeBackLayout != null) { + openSwipeBackLayout.run(); + } + } + + public ImageView getRightIcon() { + return rightIcon; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java index 067161535..743185e4a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java @@ -16,13 +16,13 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; import android.view.KeyEvent; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -36,8 +36,6 @@ import android.widget.ScrollView; import androidx.annotation.Keep; import androidx.annotation.Nullable; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.messenger.NotificationCenter; @@ -90,6 +88,8 @@ public class ActionBarPopupWindow extends PopupWindow { public static class ActionBarPopupWindowLayout extends FrameLayout { public final static int FLAG_USE_SWIPEBACK = 1; + public boolean updateAnimation; + public boolean swipeBackGravityRight; private OnDispatchKeyEventListener mOnDispatchKeyEventListener; private float backScaleX = 1; @@ -114,6 +114,7 @@ public class ActionBarPopupWindow extends PopupWindow { private boolean fitItems; private final Theme.ResourcesProvider resourcesProvider; + private View topView; public ActionBarPopupWindowLayout(Context context) { this(context, null); @@ -130,14 +131,16 @@ public class ActionBarPopupWindow extends PopupWindow { public ActionBarPopupWindowLayout(Context context, int resId, Theme.ResourcesProvider resourcesProvider, int flags) { super(context); this.resourcesProvider = resourcesProvider; - - backgroundDrawable = getResources().getDrawable(resId).mutate(); + if (resId != 0) { + backgroundDrawable = getResources().getDrawable(resId).mutate(); + setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + } if (backgroundDrawable != null) { backgroundDrawable.getPadding(bgPaddings); + setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); } - setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); - setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + setWillNotDraw(false); if ((flags & FLAG_USE_SWIPEBACK) > 0) { @@ -171,11 +174,14 @@ public class ActionBarPopupWindow extends PopupWindow { } Object tag = view.getTag(R.id.width_tag); Object tag2 = view.getTag(R.id.object_tag); + Object fitToWidth = view.getTag(R.id.fit_width_tag); if (tag != null) { view.getLayoutParams().width = LayoutHelper.WRAP_CONTENT; } measureChildWithMargins(view, widthMeasureSpec, 0, heightMeasureSpec, 0); - if (!(tag instanceof Integer) && tag2 == null) { + if (fitToWidth != null) { + + } else if (!(tag instanceof Integer) && tag2 == null) { maxWidth = Math.max(maxWidth, view.getMeasuredWidth()); continue; } else if (tag instanceof Integer) { @@ -213,7 +219,7 @@ public class ActionBarPopupWindow extends PopupWindow { } public int addViewToSwipeBack(View v) { - swipeBackLayout.addView(v); + swipeBackLayout.addView(v, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); return swipeBackLayout.getChildCount() - 1; } @@ -234,7 +240,7 @@ public class ActionBarPopupWindow extends PopupWindow { } public void setBackgroundColor(int color) { - if (backgroundColor != color) { + if (backgroundColor != color && backgroundDrawable != null) { backgroundDrawable.setColorFilter(new PorterDuffColorFilter(backgroundColor = color, PorterDuff.Mode.MULTIPLY)); } } @@ -265,12 +271,12 @@ public class ActionBarPopupWindow extends PopupWindow { public void setBackScaleY(float value) { if (backScaleY != value) { backScaleY = value; - if (animationEnabled) { + if (animationEnabled && updateAnimation) { int height = getMeasuredHeight() - AndroidUtilities.dp(16); if (shownFromBotton) { for (int a = lastStartedChild; a >= 0; a--) { View child = getItemAt(a); - if (child.getVisibility() != VISIBLE) { + if (child.getVisibility() != VISIBLE || child instanceof GapView) { continue; } Integer position = positions.get(child); @@ -371,20 +377,50 @@ public class ActionBarPopupWindow extends PopupWindow { return super.dispatchKeyEvent(event); } + @Override + protected void dispatchDraw(Canvas canvas) { + if (swipeBackGravityRight) { + setTranslationX(getMeasuredWidth() * (1f - backScaleX)); + if (topView != null) { + topView.setTranslationX(getMeasuredWidth() * (1f - backScaleX)); + topView.setAlpha(1f - swipeBackLayout.transitionProgress); + float h = topView.getMeasuredHeight() - AndroidUtilities.dp(16); + float yOffset = -h * swipeBackLayout.transitionProgress; + topView.setTranslationY(yOffset); + setTranslationY(yOffset); + } + } + super.dispatchDraw(canvas); + } + @Override protected void onDraw(Canvas canvas) { if (backgroundDrawable != null) { int start = gapStartY - scrollView.getScrollY(); int end = gapEndY - scrollView.getScrollY(); + boolean hasGap = false; + for (int i = 0; i < linearLayout.getChildCount(); i++) { + if (linearLayout.getChildAt(i) instanceof GapView) { + hasGap = true; + break; + } + } for (int a = 0; a < 2; a++) { if (a == 1 && start < -AndroidUtilities.dp(16)) { break; } - if (gapStartY != -1000000) { + boolean needRestore = false; + boolean applyAlpha = true; + if (hasGap && backAlpha != 255) { + canvas.saveLayerAlpha(0, bgPaddings.top, getMeasuredWidth(), getMeasuredHeight(), backAlpha, Canvas.ALL_SAVE_FLAG); + needRestore = true; + applyAlpha = false; + } else if (gapStartY != -1000000) { + needRestore = true; canvas.save(); canvas.clipRect(0, bgPaddings.top, getMeasuredWidth(), getMeasuredHeight()); } - backgroundDrawable.setAlpha(backAlpha); + backgroundDrawable.setAlpha(applyAlpha ? backAlpha : 255); if (shownFromBotton) { final int height = getMeasuredHeight(); backgroundDrawable.setBounds(0, (int) (height * (1.0f - backScaleY)), (int) (getMeasuredWidth() * backScaleX), height); @@ -407,7 +443,33 @@ public class ActionBarPopupWindow extends PopupWindow { } } backgroundDrawable.draw(canvas); - if (gapStartY != -1000000) { + + if (hasGap) { + canvas.save(); + AndroidUtilities.rectTmp2.set(backgroundDrawable.getBounds()); + AndroidUtilities.rectTmp2.inset(AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + canvas.clipRect(AndroidUtilities.rectTmp2); + for (int i = 0; i < linearLayout.getChildCount(); i++) { + if (linearLayout.getChildAt(i) instanceof GapView) { + canvas.save(); + float x = 0, y = 0; + View view = linearLayout.getChildAt(i) ; + while (view != this) { + x += view.getX(); + y += view.getY(); + view = (View) view.getParent(); + if (view == null) { + return; + } + } + canvas.translate(x, y); + linearLayout.getChildAt(i).draw(canvas); + canvas.restore(); + } + } + canvas.restore(); + } + if (needRestore) { canvas.restore(); } } @@ -485,6 +547,10 @@ public class ActionBarPopupWindow extends PopupWindow { public int getVisibleHeight() { return (int) (getMeasuredHeight() * backScaleY); } + + public void setTopView(View topView) { + this.topView = topView; + } } public ActionBarPopupWindow() { @@ -582,6 +648,26 @@ public class ActionBarPopupWindow extends PopupWindow { wm.updateViewLayout(container, p); } + private void dismissDim() { + View container = getContentView().getRootView(); + Context context = getContentView().getContext(); + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + + if (container.getLayoutParams() == null || !(container.getLayoutParams() instanceof WindowManager.LayoutParams)) { + return; + } + WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams(); + try { + if ((p.flags & WindowManager.LayoutParams.FLAG_DIM_BEHIND) != 0) { + p.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; + p.dimAmount = 0.0f; + wm.updateViewLayout(container, p); + } + } catch (Exception e) { + + } + } + @Override public void showAsDropDown(View anchor, int xoff, int yoff) { try { @@ -630,9 +716,14 @@ public class ActionBarPopupWindow extends PopupWindow { } else { content.lastStartedChild = 0; } + float finalsScaleY = 1f; + if (content.getSwipeBack() != null) { + content.getSwipeBack().invalidateTransforms(); + finalsScaleY = content.backScaleY; + } windowAnimatorSet = new AnimatorSet(); windowAnimatorSet.playTogether( - ObjectAnimator.ofFloat(content, "backScaleY", 0.0f, 1.0f), + ObjectAnimator.ofFloat(content, "backScaleY", 0.0f, finalsScaleY), ObjectAnimator.ofInt(content, "backAlpha", 0, 255)); windowAnimatorSet.setDuration(150 + 16 * visibleCount); windowAnimatorSet.addListener(new AnimatorListenerAdapter() { @@ -653,6 +744,9 @@ public class ActionBarPopupWindow extends PopupWindow { int count = content.getItemsCount(); for (int a = 0; a < count; a++) { View child = content.getItemAt(a); + if (child instanceof GapView) { + continue; + } child.setAlpha(child.isEnabled() ? 1f : 0.5f); } } @@ -690,6 +784,7 @@ public class ActionBarPopupWindow extends PopupWindow { public void dismiss(boolean animated) { setFocusable(false); + dismissDim(); if (windowAnimatorSet != null) { if (animated && isClosingAnimated) { return; @@ -766,4 +861,20 @@ public class ActionBarPopupWindow extends PopupWindow { public interface onSizeChangedListener { void onSizeChanged(); } + + public static class GapView extends FrameLayout { + + Paint paint = new Paint(); + String colorKey; + public GapView(Context context, String colorKey) { + super(context); + this.colorKey = colorKey; + } + + @Override + protected void onDraw(Canvas canvas) { + paint.setColor(Theme.getColor(colorKey)); + canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint); + } + } } \ No newline at end of file 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 b7b6dc3f0..960089a8e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -139,6 +139,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback { private ArrayList itemViews = new ArrayList<>(); private float aspectRatio; private boolean dimEnabled = true; + private float dimAlpha = 0.6f; private final Theme.ResourcesProvider resourcesProvider; private boolean topAnimationAutoRepeat = true; @@ -867,7 +868,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback { params.width = WindowManager.LayoutParams.MATCH_PARENT; } else { if (dimEnabled) { - params.dimAmount = 0.6f; + params.dimAmount = dimAlpha; params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; } else { params.dimAmount = 0f; @@ -1375,6 +1376,11 @@ public class AlertDialog extends Dialog implements Drawable.Callback { return this; } + public Builder setDimAlpha(float dimAlpha) { + alertDialog.dimAlpha = dimAlpha; + return this; + } + public void notDrawBackgroundOnTopView(boolean b) { alertDialog.notDrawBackgroundOnTopView = b; } 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 aa930a356..7d38023e6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -772,10 +772,14 @@ public abstract class BaseFragment { } Theme.ResourcesProvider resourcesProvider = getResourceProvider(); int color; + String key = Theme.key_actionBarDefault; + if (actionBar != null && actionBar.isActionModeShowed()) { + key = Theme.key_actionBarActionModeDefault; + } if (resourcesProvider != null) { - color = resourcesProvider.getColorOrDefault(Theme.key_actionBarDefault); + color = resourcesProvider.getColorOrDefault(key); } else { - color = Theme.getColor(Theme.key_actionBarDefault, null, true); + color = Theme.getColor(key, null, true); } return ColorUtils.calculateLuminance(color) > 0.7f; } 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 6cf920d2d..159923c23 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -23,6 +23,7 @@ import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; +import android.graphics.Region; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; @@ -55,6 +56,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.camera.CameraView; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -70,8 +72,8 @@ public class BottomSheet extends Dialog { protected ContainerView container; protected boolean keyboardVisible; private WindowInsets lastInsets; - protected boolean drawNavigationBar; - protected boolean scrollNavBar; + public boolean drawNavigationBar; + public boolean scrollNavBar; protected boolean useSmoothKeyboard; @@ -576,7 +578,83 @@ public class BottomSheet extends Dialog { @Override protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (navBarColorKey != null) { + backgroundPaint.setColor(getThemedColor(navBarColorKey)); + } else { + backgroundPaint.setColor(navBarColor); + } + } else { + backgroundPaint.setColor(0xff000000); + } + if (backgroundPaint.getAlpha() < 255 && drawNavigationBar) { + float translation = 0; + if (scrollNavBar || Build.VERSION.SDK_INT >= 29 && getAdditionalMandatoryOffsets() > 0) { + float dist = containerView.getMeasuredHeight() - containerView.getTranslationY(); + translation = Math.max(0, getBottomInset() - dist); + } + int navBarHeight = drawNavigationBar ? getBottomInset() : 0; + canvas.save(); + canvas.clipRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - navBarHeight + translation - currentPanTranslationY, containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() + translation, Region.Op.DIFFERENCE); + super.dispatchDraw(canvas); + canvas.restore(); + } else { + super.dispatchDraw(canvas); + } + if (!shouldOverlayCameraViewOverNavBar()) { + drawNavigationBar(canvas); + } + if (drawNavigationBar && rightInset != 0 && rightInset > leftInset && fullWidth && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + canvas.drawRect(containerView.getRight() - backgroundPaddingLeft, containerView.getTranslationY(), containerView.getRight() + rightInset, getMeasuredHeight(), backgroundPaint); + } + + if (drawNavigationBar && leftInset != 0 && leftInset > rightInset && fullWidth && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + canvas.drawRect(0, containerView.getTranslationY(), containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight(), backgroundPaint); + } + + if (containerView.getTranslationY() < 0) { + backgroundPaint.setColor(behindKeyboardColorKey != null ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); + canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, containerView.getY() + containerView.getMeasuredHeight(), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight(), backgroundPaint); + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child instanceof CameraView) { + if (shouldOverlayCameraViewOverNavBar()) { + drawNavigationBar(canvas); + } + return super.drawChild(canvas, child, drawingTime); + } + return super.drawChild(canvas, child, drawingTime); + } + + @Override + protected void onDraw(Canvas canvas) { + boolean restore = false; + if (backgroundPaint.getAlpha() < 255 && drawNavigationBar) { + float translation = 0; + if (scrollNavBar || Build.VERSION.SDK_INT >= 29 && getAdditionalMandatoryOffsets() > 0) { + float dist = containerView.getMeasuredHeight() - containerView.getTranslationY(); + translation = Math.max(0, getBottomInset() - dist); + } + int navBarHeight = drawNavigationBar ? getBottomInset() : 0; + canvas.save(); + canvas.clipRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - navBarHeight + translation - currentPanTranslationY, containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() + translation, Region.Op.DIFFERENCE); + restore = true; + } + super.onDraw(canvas); + if (lastInsets != null && keyboardHeight != 0) { + backgroundPaint.setColor(behindKeyboardColorKey != null ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); + canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - keyboardHeight - (drawNavigationBar ? getBottomInset() : 0), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() - (drawNavigationBar ? getBottomInset() : 0), backgroundPaint); + } + onContainerDraw(canvas); + if (restore) { + canvas.restore(); + } + } + + public void drawNavigationBar(Canvas canvas) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (navBarColorKey != null) { backgroundPaint.setColor(getThemedColor(navBarColorKey)); @@ -600,29 +678,11 @@ public class BottomSheet extends Dialog { canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - navBarHeight + translation - currentPanTranslationY, containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() + translation, backgroundPaint); } } - if (drawNavigationBar && rightInset != 0 && rightInset > leftInset && fullWidth && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { - canvas.drawRect(containerView.getRight() - backgroundPaddingLeft, containerView.getTranslationY(), containerView.getRight() + rightInset, getMeasuredHeight(), backgroundPaint); - } - - if (drawNavigationBar && leftInset != 0 && leftInset > rightInset && fullWidth && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { - canvas.drawRect(0, containerView.getTranslationY(), containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight(), backgroundPaint); - } - - if (containerView.getTranslationY() < 0) { - backgroundPaint.setColor(behindKeyboardColorKey != null ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); - canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, containerView.getY() + containerView.getMeasuredHeight(), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight(), backgroundPaint); - } } + } - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (lastInsets != null && keyboardHeight != 0) { - backgroundPaint.setColor(behindKeyboardColorKey != null ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); - canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - keyboardHeight - (drawNavigationBar ? getBottomInset() : 0), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() - (drawNavigationBar ? getBottomInset() : 0), backgroundPaint); - } - onContainerDraw(canvas); - } + protected boolean shouldOverlayCameraViewOverNavBar() { + return false; } public void setHideSystemVerticalInsets(boolean hideSystemVerticalInsets) { @@ -1035,7 +1095,7 @@ public class BottomSheet extends Dialog { backDrawable.setAlpha(0); if (Build.VERSION.SDK_INT >= 18) { layoutCount = 2; - containerView.setTranslationY((Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight * (1f - hideSystemVerticalInsetsProgress) : 0) + containerView.getMeasuredHeight()); + containerView.setTranslationY((Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight * (1f - hideSystemVerticalInsetsProgress) : 0) + containerView.getMeasuredHeight() + (scrollNavBar ? getBottomInset() : 0)); AndroidUtilities.runOnUIThread(startAnimationRunnable = new Runnable() { @Override public void run() { @@ -1152,7 +1212,7 @@ public class BottomSheet extends Dialog { if (Build.VERSION.SDK_INT >= 20 && useHardwareLayer) { container.setLayerType(View.LAYER_TYPE_HARDWARE, null); } - containerView.setTranslationY(containerView.getMeasuredHeight()); + containerView.setTranslationY(containerView.getMeasuredHeight() + (scrollNavBar ? getBottomInset() : 0)); currentSheetAnimationType = 1; currentSheetAnimation = new AnimatorSet(); currentSheetAnimation.playTogether( @@ -1267,7 +1327,7 @@ public class BottomSheet extends Dialog { currentSheetAnimationType = 2; currentSheetAnimation = new AnimatorSet(); currentSheetAnimation.playTogether( - ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + AndroidUtilities.dp(10)), + ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + AndroidUtilities.dp(10) + (scrollNavBar ? getBottomInset() : 0)), ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0) ); currentSheetAnimation.setDuration(180); @@ -1333,7 +1393,7 @@ public class BottomSheet extends Dialog { currentSheetAnimationType = 2; currentSheetAnimation = new AnimatorSet(); currentSheetAnimation.playTogether( - ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + container.keyboardHeight + AndroidUtilities.dp(10)), + ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + container.keyboardHeight + AndroidUtilities.dp(10) + (scrollNavBar ? getBottomInset() : 0)), ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0) ); if (useFastDismiss) { @@ -1509,6 +1569,13 @@ public class BottomSheet extends Dialog { bottomSheet.setOnHideListener(onDismissListener); return this; } + + public Builder fixNavigationBar() { + bottomSheet.drawNavigationBar = true; + bottomSheet.scrollNavBar = true; + bottomSheet.setOverlayNavBarColor(bottomSheet.getThemedColor(Theme.key_dialogBackground)); + return this; + } } public int getLeftInset() { @@ -1570,13 +1637,15 @@ public class BottomSheet extends Dialog { container.invalidate(); } - if (Color.alpha(color) > 120) { - AndroidUtilities.setLightStatusBar(getWindow(), false); - AndroidUtilities.setLightNavigationBar(getWindow(), false); - } else { - AndroidUtilities.setLightNavigationBar(getWindow(), !useLightNavBar); - AndroidUtilities.setLightStatusBar(getWindow(), !useLightStatusBar); - } +// if (Color.alpha(color) > 120) { +// AndroidUtilities.setLightStatusBar(getWindow(), false); +// AndroidUtilities.setLightNavigationBar(getWindow(), false); +// } else { +// AndroidUtilities.setLightStatusBar(getWindow(), !useLightStatusBar); +// AndroidUtilities.setLightNavigationBar(getWindow(), !useLightNavBar); +// } + AndroidUtilities.setNavigationBarColor(getWindow(), overlayDrawNavBarColor); + AndroidUtilities.setLightNavigationBar(getWindow(), AndroidUtilities.computePerceivedBrightness(overlayDrawNavBarColor) > .721); } public ViewGroup getContainerView() { 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 8babd13fa..01a0e252f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java @@ -311,6 +311,13 @@ public class DrawerLayoutContainer extends FrameLayout { parentActionBarLayout = layout; } + public void presentFragment(BaseFragment fragment) { + if (parentActionBarLayout != null) { + parentActionBarLayout.presentFragment(fragment); + } + closeDrawer(false); + } + public void closeDrawer() { if (drawerPosition != 0) { setDrawerPosition(0); 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 ae3bc8b95..9b8511c32 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -1529,6 +1529,14 @@ public class Theme { currentColors.put(key_chat_wallpaper_gradient_rotation, backgroundRotation); } + Integer outBubble = currentColors.get(key_chat_outBubble); + if (outBubble == null) { + outBubble = getColor(key_chat_outBubble); + } + Integer inBubble = currentColors.get(key_chat_inBubble); + if (inBubble == null) { + inBubble = getColor(key_chat_inBubble); + } if (info != null && info.emoticon != null && !isDarkTheme) { currentColors.remove(key_chat_selectedBackground); int gradientAverageColor = averageColor(currentColors, key_chat_wallpaper_gradient_to1, key_chat_wallpaper_gradient_to2, key_chat_wallpaper_gradient_to3); @@ -1539,24 +1547,27 @@ public class Theme { gradientAverageColor = accentColor; } - Integer outBubble = currentColors.get(key_chat_outBubble); - if (outBubble == null) { - outBubble = getColor(key_chat_outBubble); - } int outOverlay = bubbleSelectedOverlay(outBubble, gradientAverageColor); currentColors.put(key_chat_outBubbleSelectedOverlay, outOverlay); currentColors.put(key_chat_outBubbleGradientSelectedOverlay, outOverlay); currentColors.put(key_chat_outBubbleSelected, Theme.blendOver(outBubble, outOverlay)); - Integer inBubble = currentColors.get(key_chat_inBubble); - if (inBubble == null) { - inBubble = getColor(key_chat_inBubble); - } int inOverlay = bubbleSelectedOverlay(inBubble, accentColor); currentColors.put(key_chat_inBubbleSelectedOverlay, inOverlay); currentColors.put(key_chat_inBubbleSelected, Theme.blendOver(inBubble, inOverlay)); } + Integer inMsgLink = currentColors.get(key_chat_messageLinkIn); + if (inMsgLink == null) { + inMsgLink = getColor(key_chat_messageLinkIn); + } + Integer outMsgLink = currentColors.get(key_chat_messageLinkOut); + if (outMsgLink == null) { + outMsgLink = getColor(key_chat_messageLinkOut); + } + currentColors.put(key_chat_linkSelectBackground, linkSelectionBackground(inMsgLink, inBubble, isDarkTheme)); + currentColors.put(key_chat_outLinkSelectBackground, linkSelectionBackground(outMsgLink, outBubble, isDarkTheme)); + return !isMyMessagesGradientColorsNear; } @@ -1572,6 +1583,12 @@ public class Theme { tempHSV[2] = Math.max(0, Math.min(1, tempHSV[2] - .05f)); return Color.HSVToColor(30, tempHSV); } + private int linkSelectionBackground(int linkColor, int bgColor, boolean isDarkTheme) { + Color.colorToHSV(ColorUtils.blendARGB(linkColor, bgColor, .25f), tempHSV); + tempHSV[1] = Math.max(0, Math.min(1, tempHSV[1] - .1f)); + tempHSV[2] = Math.max(0, Math.min(1, tempHSV[2] + (isDarkTheme ? .1f : 0))); + return Color.HSVToColor(0x33, tempHSV); + } private int averageColor(HashMap colors, String ...keys) { int r = 0, g = 0, b = 0, c = 0; for (int i = 0; i < keys.length; ++i) { @@ -2817,6 +2834,7 @@ public class Theme { public static Paint chat_deleteProgressPaint; public static Paint chat_botProgressPaint; public static Paint chat_urlPaint; + public static Paint chat_outUrlPaint; public static Paint chat_textSearchSelectionPaint; public static Paint chat_instantViewRectPaint; public static Paint chat_pollTimerPaint; @@ -2936,9 +2954,11 @@ public class Theme { public static Drawable chat_shareIconDrawable; public static Drawable chat_replyIconDrawable; public static Drawable chat_goIconDrawable; - public static Drawable chat_botLinkDrawalbe; - public static Drawable chat_botCardDrawalbe; + public static Drawable chat_botLinkDrawable; + public static Drawable chat_botCardDrawable; public static Drawable chat_botInlineDrawable; + public static Drawable chat_botWebViewDrawable; + public static Drawable chat_botInviteDrawable; public static Drawable chat_commentDrawable; public static Drawable chat_commentStickerDrawable; public static Drawable chat_commentArrowDrawable; @@ -3432,6 +3452,7 @@ public class Theme { public static final String key_chat_outVenueInfoSelectedText = "chat_outVenueInfoSelectedText"; public static final String key_chat_mediaInfoText = "chat_mediaInfoText"; public static final String key_chat_linkSelectBackground = "chat_linkSelectBackground"; + public static final String key_chat_outLinkSelectBackground = "chat_outLinkSelectBackground"; public static final String key_chat_textSelectBackground = "chat_textSelectBackground"; public static final String key_chat_wallpaper = "chat_wallpaper"; public static final String key_chat_wallpaper_gradient_to1 = "chat_wallpaper_gradient_to"; @@ -3782,6 +3803,8 @@ public class Theme { public static final String key_drawable_botInline = "drawableBotInline"; public static final String key_drawable_botLink = "drawableBotLink"; + public static final String key_drawable_botWebView = "drawableBotWebView"; + public static final String key_drawable_botInvite = "drawable_botInvite"; public static final String key_drawable_commentSticker = "drawableCommentSticker"; public static final String key_drawable_goIcon = "drawableGoIcon"; public static final String key_drawable_msgError = "drawableMsgError"; @@ -4289,6 +4312,7 @@ public class Theme { defaultColors.put(key_chat_outVenueInfoSelectedText, 0xff65b05b); defaultColors.put(key_chat_mediaInfoText, 0xffffffff); defaultColors.put(key_chat_linkSelectBackground, 0x3362a9e3); + defaultColors.put(key_chat_outLinkSelectBackground, 0x3362a9e3); defaultColors.put(key_chat_textSelectBackground, 0x6662a9e3); defaultColors.put(key_chat_emojiPanelBackground, 0xfff0f2f5); defaultColors.put(key_chat_emojiPanelBadgeBackground, 0xff4da6ea); @@ -4729,6 +4753,7 @@ public class Theme { fallbackKeys.put(key_actionBarTabSelector, key_actionBarDefaultSelector); fallbackKeys.put(key_profile_status, key_avatar_subtitleInProfileBlue); fallbackKeys.put(key_chats_menuTopBackgroundCats, key_avatar_backgroundActionBarBlue); + fallbackKeys.put(key_chat_outLinkSelectBackground, key_chat_linkSelectBackground); //fallbackKeys.put(key_chat_attachActiveTab, 0xff33a7f5); //fallbackKeys.put(key_chat_attachUnactiveTab, 0xff92999e); fallbackKeys.put(key_chat_attachPermissionImage, key_dialogTextBlack); @@ -5771,6 +5796,12 @@ public class Theme { return defaultDrawable; } + public static Drawable createRoundRectDrawable(int topRad, int bottomRad, int defaultColor) { + ShapeDrawable defaultDrawable = new ShapeDrawable(new RoundRectShape(new float[]{topRad, topRad, topRad, topRad, bottomRad, bottomRad, bottomRad, bottomRad}, null, null)); + defaultDrawable.getPaint().setColor(defaultColor); + return defaultDrawable; + } + public static Drawable createServiceDrawable(int rad, View view, View containerView) { return createServiceDrawable(rad, view, containerView, chat_actionBackgroundPaint); } @@ -5861,6 +5892,23 @@ public class Theme { } } + public static Drawable getRoundRectSelectorWithBackgroundDrawable(int corners, int bgColor, int color) { + if (Build.VERSION.SDK_INT >= 21) { + Drawable maskDrawable = createRoundRectDrawable(corners, 0xffffffff); + ColorStateList colorStateList = new ColorStateList( + new int[][]{StateSet.WILD_CARD}, + new int[]{color} + ); + return new RippleDrawable(colorStateList, createRoundRectDrawable(corners, bgColor), maskDrawable); + } else { + StateListDrawable stateListDrawable = new StateListDrawable(); + stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, createRoundRectDrawable(corners, color)); + stateListDrawable.addState(new int[]{android.R.attr.state_selected}, createRoundRectDrawable(corners, color)); + stateListDrawable.addState(StateSet.WILD_CARD, new ColorDrawable(bgColor)); + return stateListDrawable; + } + } + public static Drawable createSelectorWithBackgroundDrawable(int backgroundColor, int color) { if (Build.VERSION.SDK_INT >= 21) { Drawable maskDrawable = new ColorDrawable(backgroundColor); @@ -6034,8 +6082,8 @@ public class Theme { public static class RippleRadMaskDrawable extends Drawable { private Path path = new Path(); - private RectF rect = new RectF(); private float[] radii = new float[8]; + boolean invalidatePath = true; public RippleRadMaskDrawable(float top, float bottom) { radii[0] = radii[1] = radii[2] = radii[3] = AndroidUtilities.dp(top); @@ -6051,6 +6099,7 @@ public class Theme { public void setRadius(float top, float bottom) { radii[0] = radii[1] = radii[2] = radii[3] = AndroidUtilities.dp(top); radii[4] = radii[5] = radii[6] = radii[7] = AndroidUtilities.dp(bottom); + invalidatePath = true; invalidateSelf(); } public void setRadius(float topLeft, float topRight, float bottomRight, float bottomLeft) { @@ -6058,13 +6107,23 @@ public class Theme { radii[2] = radii[3] = AndroidUtilities.dp(topRight); radii[4] = radii[5] = AndroidUtilities.dp(bottomRight); radii[6] = radii[7] = AndroidUtilities.dp(bottomLeft); + invalidatePath = true; invalidateSelf(); } + @Override + protected void onBoundsChange(Rect bounds) { + invalidatePath = true; + } + @Override public void draw(Canvas canvas) { - rect.set(getBounds()); - path.addRoundRect(rect, radii, Path.Direction.CW); + if (invalidatePath) { + invalidatePath = false; + path.reset(); + AndroidUtilities.rectTmp.set(getBounds()); + path.addRoundRect(AndroidUtilities.rectTmp, radii, Path.Direction.CW); + } canvas.drawPath(path, maskPaint); } @@ -8046,7 +8105,7 @@ public class Theme { checkboxSquare_backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); linkSelectionPaint = new Paint(); - linkSelectionPaint.setPathEffect(LinkPath.roundedEffect); + linkSelectionPaint.setPathEffect(LinkPath.getRoundedEffect()); Resources resources = context.getResources(); @@ -8368,9 +8427,11 @@ public class Theme { chat_locationTitlePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); chat_locationAddressPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_urlPaint = new Paint(); - chat_urlPaint.setPathEffect(LinkPath.roundedEffect); + chat_urlPaint.setPathEffect(LinkPath.getRoundedEffect()); + chat_outUrlPaint = new Paint(); + chat_outUrlPaint.setPathEffect(LinkPath.getRoundedEffect()); chat_textSearchSelectionPaint = new Paint(); - chat_textSearchSelectionPaint.setPathEffect(LinkPath.roundedEffect); + chat_textSearchSelectionPaint.setPathEffect(LinkPath.getRoundedEffect()); chat_radialProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_radialProgressPaint.setStrokeCap(Paint.Cap.ROUND); chat_radialProgressPaint.setStyle(Paint.Style.STROKE); @@ -8540,9 +8601,11 @@ public class Theme { chat_inlineResultLocation = resources.getDrawable(R.drawable.bot_location); chat_redLocationIcon = resources.getDrawable(R.drawable.map_pin).mutate(); - chat_botLinkDrawalbe = resources.getDrawable(R.drawable.bot_link); + chat_botLinkDrawable = resources.getDrawable(R.drawable.bot_link); chat_botInlineDrawable = resources.getDrawable(R.drawable.bot_lines); - chat_botCardDrawalbe = resources.getDrawable(R.drawable.bot_card); + chat_botCardDrawable = resources.getDrawable(R.drawable.bot_card); + chat_botWebViewDrawable = resources.getDrawable(R.drawable.bot_webview); + chat_botInviteDrawable = resources.getDrawable(R.drawable.bot_invite); chat_commentDrawable = resources.getDrawable(R.drawable.msg_msgbubble); chat_commentStickerDrawable = resources.getDrawable(R.drawable.msg_msgbubble2); @@ -8685,7 +8748,9 @@ public class Theme { defaultChatDrawableColorKeys.clear(); addChatDrawable(key_drawable_botInline, chat_botInlineDrawable, key_chat_serviceIcon); - addChatDrawable(key_drawable_botLink, chat_botLinkDrawalbe, key_chat_serviceIcon); + addChatDrawable(key_drawable_botWebView, chat_botWebViewDrawable, key_chat_serviceIcon); + addChatDrawable(key_drawable_botLink, chat_botLinkDrawable, key_chat_serviceIcon); + addChatDrawable(key_drawable_botInvite, chat_botInviteDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_goIcon, chat_goIconDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_commentSticker, chat_commentStickerDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_msgError, chat_msgErrorDrawable, key_chat_sentErrorIcon); @@ -8808,6 +8873,7 @@ public class Theme { chat_durationPaint.setColor(getColor(key_chat_previewDurationText)); chat_botButtonPaint.setColor(getColor(key_chat_botButtonText)); chat_urlPaint.setColor(getColor(key_chat_linkSelectBackground)); + chat_outUrlPaint.setColor(getColor(key_chat_outLinkSelectBackground)); chat_botProgressPaint.setColor(getColor(key_chat_botProgress)); chat_deleteProgressPaint.setColor(getColor(key_chat_secretTimeText)); chat_textSearchSelectionPaint.setColor(getColor(key_chat_textSelectBackground)); @@ -8841,7 +8907,9 @@ public class Theme { setDrawableColorByKey(chat_replyIconDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_goIconDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_botInlineDrawable, key_chat_serviceIcon); - setDrawableColorByKey(chat_botLinkDrawalbe, key_chat_serviceIcon); + setDrawableColorByKey(chat_botWebViewDrawable, key_chat_serviceIcon); + setDrawableColorByKey(chat_botInviteDrawable, key_chat_serviceIcon); + setDrawableColorByKey(chat_botLinkDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_msgInViewsDrawable, key_chat_inViews); setDrawableColorByKey(chat_msgInViewsSelectedDrawable, key_chat_inViewsSelected); setDrawableColorByKey(chat_msgOutViewsDrawable, key_chat_outViews); @@ -9084,7 +9152,9 @@ public class Theme { setDrawableColor(chat_replyIconDrawable, 0xffffffff); setDrawableColor(chat_goIconDrawable, 0xffffffff); setDrawableColor(chat_botInlineDrawable, 0xffffffff); - setDrawableColor(chat_botLinkDrawalbe, 0xffffffff); + setDrawableColor(chat_botWebViewDrawable, 0xffffffff); + setDrawableColor(chat_botInviteDrawable, 0xffffffff); + setDrawableColor(chat_botLinkDrawable, 0xffffffff); } else { serviceBitmap = null; serviceBitmapShader = null; @@ -9101,7 +9171,9 @@ public class Theme { setDrawableColorByKey(chat_replyIconDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_goIconDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_botInlineDrawable, key_chat_serviceIcon); - setDrawableColorByKey(chat_botLinkDrawalbe, key_chat_serviceIcon); + setDrawableColorByKey(chat_botWebViewDrawable, key_chat_serviceIcon); + setDrawableColorByKey(chat_botInviteDrawable, key_chat_serviceIcon); + setDrawableColorByKey(chat_botLinkDrawable, key_chat_serviceIcon); chat_botButtonPaint.setColor(getColor(key_chat_botButtonText)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java index b59690039..b04e7c3e9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java @@ -14,8 +14,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Canvas; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.location.Location; import android.location.LocationManager; @@ -35,6 +33,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.IntDef; +import androidx.core.graphics.ColorUtils; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; @@ -52,7 +51,6 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Components.AlertsCreator; -import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.ShareLocationDrawable; @@ -131,9 +129,6 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarWhiteSelector), false); actionBar.setCastShadows(false); actionBar.setAddToContainer(false); - if (!AndroidUtilities.isTablet()) { - actionBar.showActionModeTop(); - } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -231,18 +226,18 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl break; } case ACTION_TYPE_CHANGE_PHONE_NUMBER: { + imageView.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(150), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(150), MeasureSpec.EXACTLY)); + if (width > height) { - imageView.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.45f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) (height * 0.78f), MeasureSpec.AT_MOST)); subtitleTextView.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.45f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); titleTextView.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.6f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); descriptionText.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.6f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); buttonTextView.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.6f), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY)); } else { - imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) (height * 0.44f), MeasureSpec.AT_MOST)); titleTextView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); - subtitleTextView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); descriptionText.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); - buttonTextView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY)); + subtitleTextView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); + buttonTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(24 * 2), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); } break; } @@ -432,10 +427,9 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl case ACTION_TYPE_CHANGE_PHONE_NUMBER: { if (r > b) { int y = (int) (height * 0.95f - imageView.getMeasuredHeight()) / 2; - imageView.layout(0, y, imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); - y += imageView.getMeasuredHeight() + AndroidUtilities.dp(10); - subtitleTextView.layout(0, y, subtitleTextView.getMeasuredWidth(), y + subtitleTextView.getMeasuredHeight()); - int x = (int) (width * 0.4f); + int x = (int) (getWidth() * 0.35f - imageView.getMeasuredWidth()); + imageView.layout(x, y, x + imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); + x = (int) (width * 0.4f); y = (int) (height * 0.12f); titleTextView.layout(x, y, x + titleTextView.getMeasuredWidth(), y + titleTextView.getMeasuredHeight()); x = (int) (width * 0.4f); @@ -444,18 +438,25 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl x = (int) (width * 0.4f + (width * 0.6f - buttonTextView.getMeasuredWidth()) / 2); y = (int) (height * 0.8f); buttonTextView.layout(x, y, x + buttonTextView.getMeasuredWidth(), y + buttonTextView.getMeasuredHeight()); + + x = (int) (width * 0.4f + (width * 0.6f - subtitleTextView.getMeasuredWidth()) / 2); + y -= subtitleTextView.getMeasuredHeight() + AndroidUtilities.dp(16); + subtitleTextView.layout(x, y, x + subtitleTextView.getMeasuredWidth(), y + subtitleTextView.getMeasuredHeight()); } else { - int y = (int) (height * 0.2229f); - imageView.layout(0, y, imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); - y = (int) (height * 0.352f); + int y = (int) (height * 0.3f); + int x = (width - imageView.getMeasuredWidth()) / 2; + imageView.layout(x, y, x + imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); + y += imageView.getMeasuredHeight() + AndroidUtilities.dp(24); titleTextView.layout(0, y, titleTextView.getMeasuredWidth(), y + titleTextView.getMeasuredHeight()); - y = (int) (height * 0.409f); - subtitleTextView.layout(0, y, subtitleTextView.getMeasuredWidth(), y + subtitleTextView.getMeasuredHeight()); - y = (int) (height * 0.468f); + y += titleTextView.getTextSize() + AndroidUtilities.dp(16); descriptionText.layout(0, y, descriptionText.getMeasuredWidth(), y + descriptionText.getMeasuredHeight()); - int x = (width - buttonTextView.getMeasuredWidth()) / 2; - y = (int) (height * 0.805f); + x = (width - buttonTextView.getMeasuredWidth()) / 2; + y = height - buttonTextView.getMeasuredHeight() - AndroidUtilities.dp(48); buttonTextView.layout(x, y, x + buttonTextView.getMeasuredWidth(), y + buttonTextView.getMeasuredHeight()); + + x = (width - subtitleTextView.getMeasuredWidth()) / 2; + y -= subtitleTextView.getMeasuredHeight() + AndroidUtilities.dp(32); + subtitleTextView.layout(x, y, x + subtitleTextView.getMeasuredWidth(), y + subtitleTextView.getMeasuredHeight()); } break; } @@ -481,7 +482,7 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl viewGroup.addView(titleTextView); subtitleTextView = new TextView(context); - subtitleTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + subtitleTextView.setTextColor(Theme.getColor(currentType == ACTION_TYPE_CHANGE_PHONE_NUMBER ? Theme.key_featuredStickers_addButton : Theme.key_windowBackgroundWhiteBlackText)); subtitleTextView.setGravity(Gravity.CENTER_HORIZONTAL); subtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); subtitleTextView.setSingleLine(true); @@ -499,7 +500,7 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl descriptionText.setGravity(Gravity.CENTER_HORIZONTAL); descriptionText.setLineSpacing(AndroidUtilities.dp(2), 1); descriptionText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - if (currentType == ACTION_TYPE_SET_PASSCODE) { + if (currentType == ACTION_TYPE_SET_PASSCODE || currentType == ACTION_TYPE_CHANGE_PHONE_NUMBER) { descriptionText.setPadding(AndroidUtilities.dp(48), 0, AndroidUtilities.dp(48), 0); } else if (currentType == ACTION_TYPE_NEARBY_GROUP_CREATE) { descriptionText.setPadding(AndroidUtilities.dp(24), 0, AndroidUtilities.dp(24), 0); @@ -601,7 +602,7 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - int buttonRadiusDp = currentType == ACTION_TYPE_SET_PASSCODE ? 6 : 4; + int buttonRadiusDp = currentType == ACTION_TYPE_SET_PASSCODE || currentType == ACTION_TYPE_CHANGE_PHONE_NUMBER ? 6 : 4; buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(buttonRadiusDp), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); viewGroup.addView(buttonTextView); buttonTextView.setOnClickListener(v -> { @@ -736,23 +737,29 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl } case ACTION_TYPE_CHANGE_PHONE_NUMBER: { subtitleTextView.setVisibility(View.VISIBLE); - drawable1 = context.getResources().getDrawable(R.drawable.sim_old); - drawable2 = context.getResources().getDrawable(R.drawable.sim_new); - drawable1.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_changephoneinfo_image), PorterDuff.Mode.MULTIPLY)); - drawable2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_changephoneinfo_image2), PorterDuff.Mode.MULTIPLY)); - imageView.setImageDrawable(new CombinedDrawable(drawable1, drawable2)); - imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setAnimation(R.raw.utyan_change_number, 200, 200); + imageView.setOnClickListener(v -> { + if (!imageView.getAnimatedDrawable().isRunning()) { + imageView.getAnimatedDrawable().setCurrentFrame(0, false); + imageView.playAnimation(); + } + }); + UserConfig userConfig = getUserConfig(); TLRPC.User user = getMessagesController().getUser(userConfig.clientUserId); if (user == null) { user = userConfig.getCurrentUser(); } if (user != null) { - subtitleTextView.setText(PhoneFormat.getInstance().format("+" + user.phone)); + subtitleTextView.setText(LocaleController.formatString("PhoneNumberKeepButton", R.string.PhoneNumberKeepButton, PhoneFormat.getInstance().format("+" + user.phone))); } + subtitleTextView.setOnClickListener(v -> getParentLayout().closeLastFragment(true)); titleTextView.setText(LocaleController.getString("PhoneNumberChange2", R.string.PhoneNumberChange2)); descriptionText.setText(AndroidUtilities.replaceTags(LocaleController.getString("PhoneNumberHelp", R.string.PhoneNumberHelp))); buttonTextView.setText(LocaleController.getString("PhoneNumberChange2", R.string.PhoneNumberChange2)); + imageView.playAnimation(); + flickerButton = true; break; } } @@ -765,11 +772,6 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl return fragmentView; } - @Override - public boolean hasForceLightStatusBar() { - return true; - } - @Override public void onLocationAddressAvailable(String address, String displayAddress, Location location) { if (subtitleTextView == null) { @@ -921,4 +923,10 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl return themeDescriptions; } + + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + return ColorUtils.calculateLuminance(color) > 0.7f; + } } 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 d1095b389..f1fd62971 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -17,6 +17,7 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.SystemClock; +import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -27,8 +28,10 @@ import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager.widget.ViewPager; +import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLog; @@ -47,6 +50,7 @@ import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.DialogMeUrlCell; import org.telegram.ui.Cells.DialogsEmptyCell; import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.ProfileSearchCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; @@ -77,7 +81,8 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { VIEW_TYPE_LAST_EMPTY = 10, VIEW_TYPE_NEW_CHAT_HINT = 11, VIEW_TYPE_TEXT = 12, - VIEW_TYPE_CONTACTS_FLICKER = 13; + VIEW_TYPE_CONTACTS_FLICKER = 13, + VIEW_TYPE_HEADER_2 = 14; private Context mContext; private ArchiveHintCell archiveHintCell; @@ -400,10 +405,14 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { View view; switch (viewType) { case VIEW_TYPE_DIALOG: - DialogCell dialogCell = new DialogCell(parentFragment, mContext, true, false, currentAccount, null); - dialogCell.setArchivedPullAnimation(pullForegroundDrawable); - dialogCell.setPreloader(preloader); - view = dialogCell; + if (dialogsType == 2) { + view = new ProfileSearchCell(mContext); + } else { + DialogCell dialogCell = new DialogCell(parentFragment, mContext, true, false, currentAccount, null); + dialogCell.setArchivedPullAnimation(pullForegroundDrawable); + dialogCell.setPreloader(preloader); + view = dialogCell; + } break; case VIEW_TYPE_FLICKER: case VIEW_TYPE_CONTACTS_FLICKER: @@ -462,6 +471,12 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { view = new HeaderCell(mContext); view.setPadding(0, 0, 0, AndroidUtilities.dp(12)); break; + case VIEW_TYPE_HEADER_2: + HeaderCell cell = new HeaderCell(mContext, Theme.key_graySectionText, 16, 0, false); + cell.setHeight(32); + view = cell; + view.setClickable(false); + break; case VIEW_TYPE_SHADOW: { view = new ShadowSectionCell(mContext); Drawable drawable = Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow); @@ -559,20 +574,72 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { switch (holder.getItemViewType()) { case VIEW_TYPE_DIALOG: { - DialogCell cell = (DialogCell) holder.itemView; TLRPC.Dialog dialog = (TLRPC.Dialog) getItem(i); TLRPC.Dialog nextDialog = (TLRPC.Dialog) getItem(i + 1); - cell.useSeparator = nextDialog != null; - cell.fullSeparator = dialog.pinned && nextDialog != null && !nextDialog.pinned; - if (dialogsType == 0) { - if (AndroidUtilities.isTablet()) { - cell.setDialogSelected(dialog.id == openedDialogId); + if (dialogsType == 2) { + ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; + long oldDialogId = cell.getDialogId(); + + TLRPC.Chat chat = null; + CharSequence title = null; + CharSequence subtitle; + boolean isRecent = false; + + if (dialog.id != 0) { + chat = MessagesController.getInstance(currentAccount).getChat(-dialog.id); + if (chat != null && chat.migrated_to != null) { + TLRPC.Chat chat2 = MessagesController.getInstance(currentAccount).getChat(chat.migrated_to.channel_id); + if (chat2 != null) { + chat = chat2; + } + } + } + + if (chat != null) { + title = chat.title; + if (ChatObject.isChannel(chat) && !chat.megagroup) { + if (chat.participants_count != 0) { + subtitle = LocaleController.formatPluralStringComma("Subscribers", chat.participants_count); + } else { + if (TextUtils.isEmpty(chat.username)) { + subtitle = LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate).toLowerCase(); + } else { + subtitle = LocaleController.getString("ChannelPublic", R.string.ChannelPublic).toLowerCase(); + } + } + } else { + if (chat.participants_count != 0) { + subtitle = LocaleController.formatPluralStringComma("Members", chat.participants_count); + } else { + if (chat.has_geo) { + subtitle = LocaleController.getString("MegaLocation", R.string.MegaLocation); + } else if (TextUtils.isEmpty(chat.username)) { + subtitle = LocaleController.getString("MegaPrivate", R.string.MegaPrivate).toLowerCase(); + } else { + subtitle = LocaleController.getString("MegaPublic", R.string.MegaPublic).toLowerCase(); + } + } + } + } else { + subtitle = ""; + } + cell.useSeparator = nextDialog != null; + cell.setData(chat, null, title, subtitle, isRecent, false); + cell.setChecked(selectedDialogs.contains(cell.getDialogId()), oldDialogId == cell.getDialogId()); + } else { + DialogCell cell = (DialogCell) holder.itemView; + cell.useSeparator = nextDialog != null; + cell.fullSeparator = dialog.pinned && nextDialog != null && !nextDialog.pinned; + if (dialogsType == 0) { + if (AndroidUtilities.isTablet()) { + cell.setDialogSelected(dialog.id == openedDialogId); + } + } + cell.setChecked(selectedDialogs.contains(dialog.id), false); + cell.setDialog(dialog, dialogsType, folderId); + if (preloader != null && i < 10) { + preloader.add(dialog.id); } - } - cell.setChecked(selectedDialogs.contains(dialog.id), false); - cell.setDialog(dialog, dialogsType, folderId); - if (preloader != null && i < 10) { - preloader.add(dialog.id); } break; } @@ -631,6 +698,32 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { } break; } + case VIEW_TYPE_HEADER_2: { + HeaderCell cell = (HeaderCell) holder.itemView; + cell.setTextSize(14); + cell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + cell.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + try { + MessagesController messagesController = AccountInstance.getInstance(currentAccount).getMessagesController(); + int j = 0; + if (messagesController.dialogsMyChannels.size() > 0) { + if (i == j) { + cell.setText(LocaleController.getString("MyChannels", R.string.MyChannels)); + } + j += 1 + messagesController.dialogsMyChannels.size(); + } + if (messagesController.dialogsMyGroups.size() > 0) { + if (i == j) { + cell.setText(LocaleController.getString("MyGroups", R.string.MyGroups)); + } + j += 1 + messagesController.dialogsMyGroups.size(); + } + if (messagesController.dialogsCanAddUsers.size() > 0 && i == j) { + cell.setText(LocaleController.getString("FilterGroups", R.string.FilterGroups)); + } + } catch (Exception ignore) {} + break; + } case VIEW_TYPE_NEW_CHAT_HINT: { TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; cell.setText(LocaleController.getString("TapOnThePencil", R.string.TapOnThePencil)); @@ -746,6 +839,9 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { } else if (i > size) { return VIEW_TYPE_LAST_EMPTY; } + if (dialogsType == 2 && getItem(i) == null) { + return VIEW_TYPE_HEADER_2; + } return VIEW_TYPE_DIALOG; } @@ -929,6 +1025,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { blurOffset = ((BlurredRecyclerView) parent).blurTopPadding; } int paddingTop = parent.getPaddingTop(); + paddingTop -= blurOffset; if (size == 0 || paddingTop == 0 && !hasArchive) { height = 0; } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java index fddb6e882..70ecdca10 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -59,6 +59,14 @@ import androidx.recyclerview.widget.RecyclerView; public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { + private final int VIEW_TYPE_PROFILE_CELL = 0; + private final int VIEW_TYPE_GRAY_SECTION = 1; + private final int VIEW_TYPE_DIALOG_CELL = 2; + private final int VIEW_TYPE_LOADING = 3; + private final int VIEW_TYPE_HASHTAG_CELL = 4; + private final int VIEW_TYPE_CATEGORY_LIST = 5; + private final int VIEW_TYPE_ADD_BY_PHONE = 6; + private Context mContext; private Runnable searchRunnable; private Runnable searchRunnable2; @@ -932,25 +940,25 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_PROFILE_CELL: view = new ProfileSearchCell(mContext); break; - case 1: + case VIEW_TYPE_GRAY_SECTION: view = new GraySectionCell(mContext); break; - case 2: + case VIEW_TYPE_DIALOG_CELL: view = new DialogCell(null, mContext, false, true); break; - case 3: + case VIEW_TYPE_LOADING: FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); flickerLoadingView.setViewType(FlickerLoadingView.DIALOG_TYPE); flickerLoadingView.setIsSingleCell(true); view = flickerLoadingView; break; - case 4: + case VIEW_TYPE_HASHTAG_CELL: view = new HashtagSearchCell(mContext); break; - case 5: + case VIEW_TYPE_CATEGORY_LIST: RecyclerListView horizontalListView = new RecyclerListView(mContext) { @Override public boolean onInterceptTouchEvent(MotionEvent e) { @@ -960,7 +968,6 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { return super.onInterceptTouchEvent(e); } }; - horizontalListView.setSelectorRadius(AndroidUtilities.dp(4)); horizontalListView.setSelectorDrawableColor(Theme.getColor(Theme.key_listSelector)); horizontalListView.setTag(9); horizontalListView.setItemAnimator(null); @@ -989,7 +996,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { view = horizontalListView; innerListView = horizontalListView; break; - case 6: + case VIEW_TYPE_ADD_BY_PHONE: default: view = new TextCell(mContext, 16, false); break; @@ -1005,7 +1012,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: { + case VIEW_TYPE_PROFILE_CELL: { ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; long oldDialogId = cell.getDialogId(); @@ -1127,7 +1134,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { cell.setChecked(delegate.isSelected(cell.getDialogId()), oldDialogId == cell.getDialogId()); break; } - case 1: { + case VIEW_TYPE_GRAY_SECTION: { GraySectionCell cell = (GraySectionCell) holder.itemView; if (isRecentSearchDisplayed()) { int offset = (!MediaDataController.getInstance(currentAccount).hints.isEmpty() ? 1 : 0); @@ -1197,25 +1204,25 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { } break; } - case 2: { + case VIEW_TYPE_DIALOG_CELL: { DialogCell cell = (DialogCell) holder.itemView; cell.useSeparator = (position != getItemCount() - 1); MessageObject messageObject = (MessageObject) getItem(position); cell.setDialog(messageObject.getDialogId(), messageObject, messageObject.messageOwner.date, false); break; } - case 4: { + case VIEW_TYPE_HASHTAG_CELL: { HashtagSearchCell cell = (HashtagSearchCell) holder.itemView; cell.setText(searchResultHashtags.get(position - 1)); cell.setNeedDivider(position != searchResultHashtags.size()); break; } - case 5: { + case VIEW_TYPE_CATEGORY_LIST: { RecyclerListView recyclerListView = (RecyclerListView) holder.itemView; ((CategoryAdapterRecycler) recyclerListView.getAdapter()).setIndex(position / 2); break; } - case 6: { + case VIEW_TYPE_ADD_BY_PHONE: { String str = (String) getItem(position); TextCell cell = (TextCell) holder.itemView; cell.setColors(null, Theme.key_windowBackgroundWhiteBlueText2); @@ -1233,15 +1240,15 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { if (isRecentSearchDisplayed()) { int offset = (!MediaDataController.getInstance(currentAccount).hints.isEmpty() ? 1 : 0); if (i < offset) { - return 5; + return VIEW_TYPE_CATEGORY_LIST; } if (i == offset) { - return 1; + return VIEW_TYPE_GRAY_SECTION; } - return 0; + return VIEW_TYPE_PROFILE_CELL; } if (!searchResultHashtags.isEmpty()) { - return i == 0 ? 1 : 4; + return i == 0 ? VIEW_TYPE_GRAY_SECTION : VIEW_TYPE_HASHTAG_CELL; } ArrayList globalSearch = searchAdapterHelper.getGlobalSearch(); int localCount = searchResult.size(); @@ -1257,11 +1264,11 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { int messagesCount = searchResultMessages.isEmpty() ? 0 : searchResultMessages.size() + 1; if (i >= 0 && i < localCount) { - return 0; + return VIEW_TYPE_PROFILE_CELL; } else { i -= localCount; if (i >= 0 && i < localServerCount) { - return 0; + return VIEW_TYPE_PROFILE_CELL; } else { i -= localServerCount; if (i >= 0 && i < phoneCount) { @@ -1269,34 +1276,34 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { if (object instanceof String) { String str = (String) object; if ("section".equals(str)) { - return 1; + return VIEW_TYPE_GRAY_SECTION; } else { - return 6; + return VIEW_TYPE_ADD_BY_PHONE; } } - return 0; + return VIEW_TYPE_PROFILE_CELL; } else { i -= phoneCount; if (i >= 0 && i < globalCount) { if (i == 0) { - return 1; + return VIEW_TYPE_GRAY_SECTION; } else { - return 0; + return VIEW_TYPE_PROFILE_CELL; } } else { i -= globalCount; if (i >= 0 && i < messagesCount) { if (i == 0) { - return 1; + return VIEW_TYPE_GRAY_SECTION; } else { - return 2; + return VIEW_TYPE_DIALOG_CELL; } } } } } } - return 3; + return VIEW_TYPE_LOADING; } public void setFiltersDelegate(FilteredSearchView.Delegate filtersDelegate, boolean update) { 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 a863a977a..741297e35 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java @@ -19,6 +19,8 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.ui.ActionBar.ActionBarLayout; +import org.telegram.ui.ActionBar.DrawerLayoutContainer; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.DrawerActionCell; import org.telegram.ui.Cells.DividerCell; @@ -37,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView; public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; + private DrawerLayoutContainer mDrawerLayoutContainer; private ArrayList items = new ArrayList<>(11); private ArrayList accountNumbers = new ArrayList<>(); private boolean accountsShown; @@ -44,8 +47,9 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { private SideMenultItemAnimator itemAnimator; private boolean hasGps; - public DrawerLayoutAdapter(Context context, SideMenultItemAnimator animator) { + public DrawerLayoutAdapter(Context context, SideMenultItemAnimator animator, DrawerLayoutContainer drawerLayoutContainer) { mContext = context; + mDrawerLayoutContainer = drawerLayoutContainer; itemAnimator = animator; accountsShown = UserConfig.getActivatedAccountsCount() > 1 && MessagesController.getGlobalMainSettings().getBoolean("accountsShown", true); Theme.createCommonDialogResources(context); @@ -116,7 +120,7 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { View view; switch (viewType) { case 0: - view = profileCell = new DrawerProfileCell(mContext); + view = profileCell = new DrawerProfileCell(mContext, mDrawerLayoutContainer); break; case 2: view = new DividerCell(mContext); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index e32c5b715..7bc02653a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -149,6 +149,7 @@ import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LineProgressView; import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.MediaActionDrawable; import org.telegram.ui.Components.RadialProgress2; import org.telegram.ui.Components.RadioButton; @@ -274,7 +275,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg private int pressCount = 0; private CheckForTap pendingCheckForTap = null; - private TextPaintUrlSpan pressedLink; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(); private BottomSheet linkSheet; private int pressedLayoutY; private DrawingText pressedLinkOwnerLayout; @@ -380,6 +382,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } public class DrawingText implements TextSelectionHelper.TextLayoutBlock { + public View latestParentView; + public StaticLayout textLayout; public LinkPath textPath; public LinkPath markPath; @@ -392,7 +396,9 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg public int row; public CharSequence prefix; - public void draw(Canvas canvas) { + public void draw(Canvas canvas, View view) { + latestParentView = view; + if (!searchResults.isEmpty()) { SearchResult result = searchResults.get(currentSearchIndex); if (result.block == parentBlock && (result.text == parentText || result.text instanceof String && parentText == null)) { @@ -421,7 +427,21 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (markPath != null) { canvas.drawPath(markPath, webpageMarkPaint); } - drawLayoutLink(canvas, this); + if (links.draw(canvas, this)) { + view.invalidate(); + } + if (pressedLinkOwnerLayout == this && pressedLink == null && drawBlockSelection) { + float width; + float x; + if (getLineCount() == 1) { + width = getLineWidth(0); + x = getLineLeft(0); + } else { + width = getWidth(); + x = 0; + } + canvas.drawRect(-AndroidUtilities.dp(2) + x, 0, x + width + AndroidUtilities.dp(2), getHeight(), urlPaint); + } textLayout.draw(canvas); } @@ -1084,8 +1104,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (checkingForLongPress && windowView != null) { checkingForLongPress = false; if (pressedLink != null) { - windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - showCopyPopup(pressedLink.getUrl()); + windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + showCopyPopup(pressedLink.getSpan().getUrl()); pressedLink = null; pressedLinkOwnerLayout = null; if (pressedLinkOwnerView != null) { @@ -1098,10 +1118,10 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg textSelectionHelper.trySelect(pressedLinkOwnerView); } if (textSelectionHelper.isSelectionMode()) { - windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } } else if (pressedLinkOwnerLayout != null && pressedLinkOwnerView != null) { - windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);; int[] location = new int[2]; pressedLinkOwnerView.getLocationInWindow(location); @@ -1150,16 +1170,16 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg float lightness = (0.2126f * Color.red(color2) + 0.7152f * Color.green(color2) + 0.0722f * Color.blue(color2)) / 255.0f; webpageSearchPaint.setColor(lightness <= 0.705f ? 0xffd1982e : 0xffffe669); webpageUrlPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); - webpageUrlPaint.setPathEffect(LinkPath.roundedEffect); + webpageUrlPaint.setPathEffect(LinkPath.getRoundedEffect()); urlPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); - urlPaint.setPathEffect(LinkPath.roundedEffect); + urlPaint.setPathEffect(LinkPath.getRoundedEffect()); tableHalfLinePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputField)); tableLinePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputField)); photoBackgroundPaint.setColor(0x0f000000); dividerPaint.setColor(Theme.getColor(Theme.key_divider)); webpageMarkPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); - webpageMarkPaint.setPathEffect(LinkPath.roundedEffect); + webpageMarkPaint.setPathEffect(LinkPath.getRoundedEffect()); int color = Theme.getColor(Theme.key_switchTrack); int r = Color.red(color); @@ -1228,6 +1248,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg AndroidUtilities.addToClipboard(url); } }); + builder.setOnPreDismissListener(di -> links.clear()); BottomSheet sheet = builder.create(); showDialog(sheet); } @@ -2577,26 +2598,6 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg return drawingText; } - private void drawLayoutLink(Canvas canvas, DrawingText layout) { - if (canvas == null || layout == null || pressedLinkOwnerLayout != layout) { - return; - } - if (pressedLink != null) { - canvas.drawPath(urlPath, urlPaint); - } else if (drawBlockSelection && layout != null) { - float width; - float x; - if (layout.getLineCount() == 1) { - width = layout.getLineWidth(0); - x = layout.getLineLeft(0); - } else { - width = layout.getWidth(); - x = 0; - } - canvas.drawRect(-AndroidUtilities.dp(2) + x, 0, x + width + AndroidUtilities.dp(2), layout.getHeight(), urlPaint); - } - } - private boolean checkLayoutForLinks(WebpageAdapter adapter, MotionEvent event, View parentView, DrawingText drawingText, int layoutX, int layoutY) { if (pageSwitchAnimation != null || parentView == null || !textSelectionHelper.isSelectable(parentView)) { return false; @@ -2616,7 +2617,6 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } if (x >= layoutX + left && x <= left + layoutX + width && y >= layoutY && y <= layoutY + layout.getHeight()) { pressedLinkOwnerLayout = drawingText; - pressedLinkOwnerView = parentView; pressedLayoutY = layoutY; CharSequence text = layout.getText(); if (text instanceof Spannable) { @@ -2630,25 +2630,32 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg Spannable buffer = (Spannable) layout.getText(); TextPaintUrlSpan[] link = buffer.getSpans(off, off, TextPaintUrlSpan.class); if (link != null && link.length > 0) { - pressedLink = link[0]; - int pressedStart = buffer.getSpanStart(pressedLink); - int pressedEnd = buffer.getSpanEnd(pressedLink); + TextPaintUrlSpan selectedLink = link[0]; + int pressedStart = buffer.getSpanStart(selectedLink); + int pressedEnd = buffer.getSpanEnd(selectedLink); for (int a = 1; a < link.length; a++) { TextPaintUrlSpan span = link[a]; int start = buffer.getSpanStart(span); int end = buffer.getSpanEnd(span); if (pressedStart > start || end > pressedEnd) { - pressedLink = span; + selectedLink = span; pressedStart = start; pressedEnd = end; } } + if (pressedLink != null) { + links.removeLink(pressedLink); + } + pressedLink = new LinkSpanDrawable(selectedLink, null, x, y); + pressedLink.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); + links.addLink(pressedLink, pressedLinkOwnerLayout); try { - urlPath.setUseRoundRect(true); - urlPath.setCurrentLayout(layout, pressedStart, 0); - int shift = pressedLink.getTextPaint() != null ? pressedLink.getTextPaint().baselineShift : 0; - urlPath.setBaselineShift(shift != 0 ? shift + AndroidUtilities.dp(shift > 0 ? 5 : -2) : 0); - layout.getSelectionPath(pressedStart, pressedEnd, urlPath); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(layout, pressedStart, 0); + TextPaint textPaint = selectedLink.getTextPaint(); + int shift = textPaint != null ? textPaint.baselineShift : 0; + path.setBaselineShift(shift != 0 ? shift + AndroidUtilities.dp(shift > 0 ? 5 : -2) : 0); + layout.getSelectionPath(pressedStart, pressedEnd, path); parentView.invalidate(); } catch (Exception e) { FileLog.e(e); @@ -2663,7 +2670,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } else if (event.getAction() == MotionEvent.ACTION_UP) { if (pressedLink != null) { removeLink = true; - String url = pressedLink.getUrl(); + String url = pressedLink.getSpan().getUrl(); if (url != null) { if (linkSheet != null) { linkSheet.dismiss(); @@ -2697,7 +2704,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg anchor = null; } if (!isAnchor) { - openWebpageUrl(pressedLink.getUrl(), anchor); + openWebpageUrl(pressedLink.getSpan().getUrl(), anchor); } } } @@ -2726,6 +2733,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg return; } View parentView = pressedLinkOwnerView; + links.clear(); pressedLink = null; pressedLinkOwnerLayout = null; pressedLinkOwnerView = null; @@ -6189,14 +6197,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -6555,7 +6563,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg titleLayout.y = seekBarY - AndroidUtilities.dp(16); canvas.translate(titleLayout.x, titleLayout.y); drawTextSelection(canvas, this, count++); - titleLayout.draw(canvas); + titleLayout.draw(canvas, this); canvas.restore(); } if (captionLayout != null) { @@ -6564,7 +6572,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg captionLayout.y = textY; canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { @@ -6573,7 +6581,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg creditLayout.y = textY + creditOffset; canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -6886,14 +6894,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(AndroidUtilities.dp(18 + 14 + (avatarVisible ? 40 + 14 : 0)), AndroidUtilities.dp(dateLayout != null ? 10 : 19)); drawTextSelection(canvas, this, count++); - nameLayout.draw(canvas); + nameLayout.draw(canvas, this); canvas.restore(); } if (dateLayout != null) { canvas.save(); canvas.translate(AndroidUtilities.dp(18 + 14 + (avatarVisible ? 40 + 14 : 0)), AndroidUtilities.dp(29)); drawTextSelection(canvas, this, count++); - dateLayout.draw(canvas); + dateLayout.draw(canvas, this); canvas.restore(); } canvas.drawRect(AndroidUtilities.dp(18), AndroidUtilities.dp(6), AndroidUtilities.dp(20), lineHeight - (currentBlock.level != 0 ? 0 : AndroidUtilities.dp(6)), quoteLinePaint); @@ -6902,14 +6910,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } } @@ -6998,7 +7006,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -7129,7 +7137,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } @Override - public TextureView onSwitchInlineMode(View controlsView, boolean inline, float aspectRatio, int rotation, boolean animated) { + public TextureView onSwitchInlineMode(View controlsView, boolean inline, int videoWidth, int videoHeight, int rotation, boolean animated) { return null; } @@ -7430,14 +7438,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -7715,7 +7723,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, 0); - titleLayout.draw(canvas); + titleLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -8319,14 +8327,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -8579,14 +8587,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } } @@ -8803,14 +8811,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } else { canvas.translate(AndroidUtilities.dp(15) + currentBlock.parent.maxNumWidth - (int) Math.ceil(currentBlock.numLayout.getLineWidth(0)) + currentBlock.parent.level * AndroidUtilities.dp(12), textY + numOffsetY - (drawDot ? AndroidUtilities.dp(1) : 0)); } - currentBlock.numLayout.draw(canvas); + currentBlock.numLayout.draw(canvas, this); canvas.restore(); } if (textLayout != null) { canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas,this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9039,14 +9047,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } else { canvas.translate(AndroidUtilities.dp(18) + currentBlock.parent.maxNumWidth - (int) Math.ceil(currentBlock.numLayout.getLineWidth(0)) + currentBlock.parent.level * AndroidUtilities.dp(20), textY + numOffsetY); } - currentBlock.numLayout.draw(canvas); + currentBlock.numLayout.draw(canvas, this); canvas.restore(); } if (textLayout != null) { canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9155,7 +9163,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas,this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } @@ -9262,7 +9270,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9398,12 +9406,12 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.translate(textX, AndroidUtilities.dp(10)); if (textLayout != null) { drawTextSelection(canvas, this, count++); - textLayout.draw(canvas); + textLayout.draw(canvas, this); } if (textLayout2 != null) { canvas.translate(0, textOffset); drawTextSelection(canvas, this, count); - textLayout2.draw(canvas); + textLayout2.draw(canvas, this); } canvas.restore(); if (divider) { @@ -9476,7 +9484,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9573,7 +9581,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9662,14 +9670,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } if (textLayout2 != null) { canvas.save(); canvas.translate(textX, textY2); drawTextSelection(canvas, this, count); - textLayout2.draw(canvas); + textLayout2.draw(canvas, this); canvas.restore(); } } @@ -9773,14 +9781,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, counter++); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } if (textLayout2 != null) { canvas.save(); canvas.translate(textX, textY2); drawTextSelection(canvas, this, counter); - textLayout2.draw(canvas); + textLayout2.draw(canvas, this); canvas.restore(); } if (parentAdapter.isRtl) { @@ -10074,14 +10082,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas,this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas,this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -10369,14 +10377,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -10580,7 +10588,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (currentType == 0) { drawTextSelection(canvas, this); } - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -10683,7 +10691,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -10765,7 +10773,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas,this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -10847,7 +10855,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -10926,7 +10934,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -11007,7 +11015,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (textLayout != null) { canvas.save(); drawTextSelection(canvas, BlockPreformattedCell.this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); textLayout.x = (int) getX(); textLayout.y = (int) getY(); @@ -11119,7 +11127,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index 68a0814af..aae03c136 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -121,10 +121,12 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe return; } photoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE), 0); + photoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE_PUBLIC), 0); if (canceled) { return; } videoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO), 0); + videoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO_PUBLIC), 0); if (canceled) { return; } @@ -320,6 +322,19 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe if (file != null) { Utilities.clearDir(file.getAbsolutePath(), documentsMusicType, Long.MAX_VALUE, false); } + if (type == FileLoader.MEDIA_DIR_IMAGE || type == FileLoader.MEDIA_DIR_VIDEO) { + int publicDirectoryType; + if (type == FileLoader.MEDIA_DIR_IMAGE) { + publicDirectoryType = FileLoader.MEDIA_DIR_IMAGE_PUBLIC; + } else { + publicDirectoryType = FileLoader.MEDIA_DIR_VIDEO_PUBLIC; + } + file = FileLoader.checkDirectory(publicDirectoryType); + + if (file != null) { + Utilities.clearDir(file.getAbsolutePath(), documentsMusicType, Long.MAX_VALUE, false); + } + } if (type == FileLoader.MEDIA_DIR_CACHE) { cacheSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), documentsMusicType); imagesCleared = true; @@ -334,8 +349,10 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe } else if (type == FileLoader.MEDIA_DIR_IMAGE) { imagesCleared = true; photoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE), documentsMusicType); + photoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE_PUBLIC), documentsMusicType); } else if (type == FileLoader.MEDIA_DIR_VIDEO) { videoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO), documentsMusicType); + videoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO_PUBLIC), documentsMusicType); } else if (type == 100) { imagesCleared = true; stickersSize = getDirectorySize(new File(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), "acache"), documentsMusicType); @@ -384,8 +401,11 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe FileLog.e(e); } + getMediaDataController().ringtoneDataStore.checkRingtoneSoundsLoaded(); cacheRemovedTooltip.setInfoText(LocaleController.formatString("CacheWasCleared", R.string.CacheWasCleared, AndroidUtilities.formatFileSize(finalClearedSize))); cacheRemovedTooltip.showWithAction(0, UndoView.ACTION_CACHE_WAS_CLEARED, null, null); + + getMediaDataController().loadAttachMenuBots(false, true); }); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java index 400ab0249..dc9c3f422 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java @@ -308,7 +308,7 @@ public class CalendarActivity extends BaseFragment { selectDaysHint.showForView(bottomBar, true); return; } - AlertsCreator.createClearDaysDialogAlert(this, lastDaysSelected, getMessagesController().getUser(dialogId), new MessagesStorage.BooleanCallback() { + AlertsCreator.createClearDaysDialogAlert(this, lastDaysSelected, getMessagesController().getUser(dialogId), null, false, new MessagesStorage.BooleanCallback() { @Override public void run(boolean forAll) { finishFragment(); @@ -743,7 +743,7 @@ public class CalendarActivity extends BaseFragment { if (parentLayout.fragmentsStack.size() >= 3) { BaseFragment fragment = parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 3); if (fragment instanceof ChatActivity) { - AlertsCreator.createClearDaysDialogAlert(CalendarActivity.this, 1, getMessagesController().getUser(dialogId), new MessagesStorage.BooleanCallback() { + AlertsCreator.createClearDaysDialogAlert(CalendarActivity.this, 1, getMessagesController().getUser(dialogId), null, false, new MessagesStorage.BooleanCallback() { @Override public void run(boolean forAll) { finishFragment(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java index 5abde8de1..988847827 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java @@ -27,13 +27,19 @@ import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; +import android.text.Layout; +import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.StaticLayout; import android.text.TextUtils; +import android.text.style.ClickableSpan; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; @@ -81,6 +87,7 @@ import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanNoUnderline; @@ -418,7 +425,7 @@ public class CameraScanActivity extends BaseFragment { fragmentView = viewGroup; if (currentType == TYPE_QR || currentType == TYPE_QR_LOGIN) { - fragmentView.postDelayed(this::initCameraView, 200); + fragmentView.postDelayed(this::initCameraView, 350); } else { initCameraView(); } @@ -440,10 +447,12 @@ public class CameraScanActivity extends BaseFragment { } Paint selectionPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - selectionPaint.setPathEffect(LinkPath.roundedEffect); - selectionPaint.setColor(ColorUtils.setAlphaComponent(Color.WHITE, 50)); + selectionPaint.setPathEffect(LinkPath.getRoundedEffect()); + selectionPaint.setColor(ColorUtils.setAlphaComponent(Color.WHITE, 40)); titleTextView = new TextView(context) { LinkPath textPath; + private LinkSpanDrawable pressedLink; + LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -467,11 +476,56 @@ public class CameraScanActivity extends BaseFragment { } } + @Override + public boolean onTouchEvent(MotionEvent e) { + final Layout textLayout = getLayout(); + int textX = 0, textY = 0; + int x = (int) (e.getX() - textX); + int y = (int) (e.getY() - textY); + if (e.getAction() == MotionEvent.ACTION_DOWN || e.getAction() == MotionEvent.ACTION_UP) { + final int line = textLayout.getLineForVertical(y); + final int off = textLayout.getOffsetForHorizontal(line, x); + + final float left = textLayout.getLineLeft(line); + if (left <= x && left + textLayout.getLineWidth(line) >= x && y >= 0 && y <= textLayout.getHeight()) { + Spannable buffer = (Spannable) textLayout.getText(); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + links.clear(); + if (e.getAction() == MotionEvent.ACTION_DOWN) { + pressedLink = new LinkSpanDrawable(link[0], null, e.getX(), e.getY()); + pressedLink.setColor(0x2dffffff); + links.addLink(pressedLink); + int start = buffer.getSpanStart(pressedLink.getSpan()); + int end = buffer.getSpanEnd(pressedLink.getSpan()); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(textLayout, start, textY); + textLayout.getSelectionPath(start, end, path); + } else if (e.getAction() == MotionEvent.ACTION_UP) { + if (pressedLink != null && pressedLink.getSpan() == link[0]) { + link[0].onClick(this); + } + pressedLink = null; + } + return true; + } + } + } + if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) { + links.clear(); + pressedLink = null; + } + return super.onTouchEvent(e); + } + @Override protected void onDraw(Canvas canvas) { if (textPath != null) { canvas.drawPath(textPath, selectionPaint); } + if (links.draw(canvas)) { + invalidate(); + } super.onDraw(canvas); } }; @@ -507,8 +561,8 @@ public class CameraScanActivity extends BaseFragment { SpannableStringBuilder spanned = new SpannableStringBuilder(text); String[] links = new String[] { - LocaleController.getString("AuthAnotherWebClientUrl", R.string.AuthAnotherWebClientUrl), - LocaleController.getString("AuthAnotherClientDownloadClientUrl", R.string.AuthAnotherClientDownloadClientUrl) + LocaleController.getString("AuthAnotherClientDownloadClientUrl", R.string.AuthAnotherClientDownloadClientUrl), + LocaleController.getString("AuthAnotherWebClientUrl", R.string.AuthAnotherWebClientUrl) }; for (int i = 0; i < links.length; ++i) { text = spanned.toString(); @@ -521,15 +575,14 @@ public class CameraScanActivity extends BaseFragment { spanned.replace(index1, index1 + 1, " "); index1 += 1; index2 += 1; - spanned.setSpan(new URLSpanNoUnderline(links[i]), index1, index2 - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + spanned.setSpan(new URLSpanNoUnderline(links[i], true), index1, index2 - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spanned.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), index1, index2 - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { break; } } - titleTextView.setLinkTextColor(Color.WHITE); - titleTextView.setHighlightColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection)); + titleTextView.setLinkTextColor(0xffffffff); titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); titleTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); @@ -771,9 +824,9 @@ public class CameraScanActivity extends BaseFragment { if (normalBounds == null) { normalBounds = new RectF(); } - int width = AndroidUtilities.displaySize.x, - height = AndroidUtilities.displaySize.y, - side = (int) (Math.min(width, height) / 1.5f); + int width = Math.max(AndroidUtilities.displaySize.x, fragmentView.getWidth()), + height = Math.max(AndroidUtilities.displaySize.y, fragmentView.getHeight()), + side = (int) (Math.min(width, height) / 1.5f); normalBounds.set( (width - side) / 2f / (float) width, (height - side) / 2f / (float) height, diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java index 1ebb676cf..1fea1d142 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java @@ -29,6 +29,7 @@ import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.util.TypedValue; import android.view.Gravity; +import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -54,6 +55,7 @@ import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.StaticLayoutEx; import org.telegram.ui.Components.URLSpanNoUnderline; @@ -72,7 +74,8 @@ public class AboutLinkCell extends FrameLayout { private FrameLayout bottomShadow; private Drawable showMoreBackgroundDrawable; - private ClickableSpan pressedLink; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links; private Point urlPathOffset = new Point(); private LinkPath urlPath = new LinkPath(true); @@ -122,7 +125,7 @@ public class AboutLinkCell extends FrameLayout { } } else if (pressedLink != null) { try { - onLinkClick(pressedLink); + onLinkClick((ClickableSpan) pressedLink.getSpan()); } catch (Exception e) { FileLog.e(e); } @@ -136,6 +139,7 @@ public class AboutLinkCell extends FrameLayout { return result || super.onTouchEvent(event); } }; + links = new LinkSpanDrawable.LinkCollector(container); container.setClickable(true); rippleBackground = Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector), 0, 0); @@ -257,15 +261,12 @@ public class AboutLinkCell extends FrameLayout { final float SPACE = AndroidUtilities.dp(3f); private void drawText(Canvas canvas) { canvas.save(); - AndroidUtilities.rectTmp.set(AndroidUtilities.dp(23 - 8), AndroidUtilities.dp(8), getWidth() - AndroidUtilities.dp(23), getHeight()); - canvas.clipRect(AndroidUtilities.rectTmp); - if (pressedLink != null) { - canvas.save(); - canvas.translate(urlPathOffset.x, urlPathOffset.y); - canvas.drawPath(urlPath, Theme.linkSelectionPaint); - canvas.restore(); + canvas.clipRect(AndroidUtilities.dp(23 - 8), AndroidUtilities.dp(8), getWidth() - AndroidUtilities.dp(23), getHeight()); + canvas.translate(textX = AndroidUtilities.dp(23), 0); + if (links != null && links.draw(canvas)) { + invalidate(); } - canvas.translate(textX = AndroidUtilities.dp(23), textY = AndroidUtilities.dp(8)); + canvas.translate(0, textY = AndroidUtilities.dp(8)); try { if (firstThreeLinesLayout == null || !shouldExpand) { @@ -324,10 +325,8 @@ public class AboutLinkCell extends FrameLayout { protected void didExtend() {} private void resetPressedLink() { - if (pressedLink != null) { - pressedLink = null; - container.invalidate(); - } + links.clear(); + pressedLink = null; AndroidUtilities.cancelRunOnUIThread(longPressedRunnable); invalidate(); } @@ -371,15 +370,19 @@ public class AboutLinkCell extends FrameLayout { public void run() { if (pressedLink != null) { String url; - if (pressedLink instanceof URLSpanNoUnderline) { - url = ((URLSpanNoUnderline) pressedLink).getURL(); - } else if (pressedLink instanceof URLSpan) { - url = ((URLSpan) pressedLink).getURL(); + if (pressedLink.getSpan() instanceof URLSpanNoUnderline) { + url = ((URLSpanNoUnderline) pressedLink.getSpan()).getURL(); + } else if (pressedLink.getSpan() instanceof URLSpan) { + url = ((URLSpan) pressedLink.getSpan()).getURL(); } else { - url = pressedLink.toString(); + url = pressedLink.getSpan().toString(); } - ClickableSpan pressedLinkFinal = pressedLink; + try { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) {} + + ClickableSpan pressedLinkFinal = (ClickableSpan) pressedLink.getSpan(); BottomSheet.Builder builder = new BottomSheet.Builder(parentFragment.getParentActivity()); builder.setTitle(url); builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { @@ -398,8 +401,10 @@ public class AboutLinkCell extends FrameLayout { } } }); + builder.setOnPreDismissListener(di -> resetPressedLink()); builder.show(); - resetPressedLink(); + + pressedLink = null; } } }; @@ -417,16 +422,13 @@ public class AboutLinkCell extends FrameLayout { ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { resetPressedLink(); - pressedLink = link[0]; - try { - int start = buffer.getSpanStart(pressedLink); - urlPathOffset.set(textX, textY); - urlPath.setCurrentLayout(textLayout, start, 0); - textLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), urlPath); - } catch (Exception e) { - FileLog.e(e); - } - container.invalidate(); + pressedLink = new LinkSpanDrawable(link[0], parentFragment.getResourceProvider(), ex, ey); + links.addLink(pressedLink); + int start = buffer.getSpanStart(pressedLink.getSpan()); + int end = buffer.getSpanEnd(pressedLink.getSpan()); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(textLayout, start, textY); + textLayout.getSelectionPath(start, end, path); AndroidUtilities.runOnUIThread(longPressedRunnable, ViewConfiguration.getLongPressTimeout()); return true; } else { @@ -599,7 +601,6 @@ public class AboutLinkCell extends FrameLayout { int height = updateHeight(); super.onMeasure( widthMeasureSpec, -// heightMeasureSpec MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) ); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java index 7c8fa4458..df47f8b6d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -73,7 +73,8 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD default void didClickImage(ChatActionCell cell) { } - default void didLongPress(ChatActionCell cell, float x, float y) { + default boolean didLongPress(ChatActionCell cell, float x, float y) { + return false; } default void needOpenUserProfile(long uid) { @@ -283,9 +284,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD @Override protected boolean onLongPress() { if (delegate != null) { - delegate.didLongPress(this, lastTouchX, lastTouchY); + return delegate.didLongPress(this, lastTouchX, lastTouchY); } - return true; + return false; } @Override 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 39e69ef8a..2220dcafc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -71,6 +71,7 @@ import android.widget.Toast; import androidx.core.graphics.ColorUtils; import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; @@ -115,6 +116,7 @@ import org.telegram.ui.Components.EmptyStubSpan; import org.telegram.ui.Components.FloatSeekBarAccessibilityDelegate; import org.telegram.ui.Components.InfiniteProgress; import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.MediaActionDrawable; import org.telegram.ui.Components.MessageBackgroundDrawable; import org.telegram.ui.Components.MotionBackgroundDrawable; @@ -284,6 +286,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate default void didPressHiddenForward(ChatMessageCell cell) { } + default void didPressViaBotNotInline(ChatMessageCell cell, long botId) { + } + default void didPressViaBot(ChatMessageCell cell, String username) { } @@ -425,6 +430,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private int angle; private float progressAlpha; private long lastUpdateTime; + private boolean isInviteButton; } public static class PollButton { @@ -635,12 +641,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean mediaWasInvisible; private boolean timeWasInvisible; - private CharacterStyle pressedLink; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); private int pressedLinkType; private boolean linkPreviewPressed; private boolean gamePreviewPressed; private ArrayList urlPathCache = new ArrayList<>(); - private ArrayList urlPath = new ArrayList<>(); private ArrayList urlPathSelection = new ArrayList<>(); private Path rectPath = new Path(); @@ -1084,47 +1090,38 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - private void resetPressedLink(int type) { + public void resetPressedLink(int type) { + if (type != -1) { + links.removeLinks(type); + } else { + links.clear(); + } if (pressedLink == null || pressedLinkType != type && type != -1) { return; } - resetUrlPaths(false); pressedLink = null; pressedLinkType = -1; invalidate(); } - private void resetUrlPaths(boolean text) { - if (text) { - if (urlPathSelection.isEmpty()) { - return; - } - urlPathCache.addAll(urlPathSelection); - urlPathSelection.clear(); - } else { - if (urlPath.isEmpty()) { - return; - } - urlPathCache.addAll(urlPath); - urlPath.clear(); + private void resetUrlPaths() { + if (urlPathSelection.isEmpty()) { + return; } + urlPathCache.addAll(urlPathSelection); + urlPathSelection.clear(); } - private LinkPath obtainNewUrlPath(boolean text) { + private LinkPath obtainNewUrlPath() { LinkPath linkPath; if (!urlPathCache.isEmpty()) { linkPath = urlPathCache.get(0); urlPathCache.remove(0); } else { - linkPath = new LinkPath(); - linkPath.setUseRoundRect(true); + linkPath = new LinkPath(true); } linkPath.reset(); - if (text) { - urlPathSelection.add(linkPath); - } else { - urlPath.add(linkPath); - } + urlPathSelection.add(linkPath); return linkPath; } @@ -1186,70 +1183,74 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (!ignore) { if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressedLink = link[0]; - linkBlockNum = blockNum; - pressedLinkType = 1; - resetUrlPaths(false); - try { - LinkPath path = obtainNewUrlPath(false); - int[] pos = getRealSpanStartAndEnd(buffer, pressedLink); - pos[0] -= block.charactersOffset; - pos[1] -= block.charactersOffset; - path.setCurrentLayout(block.textLayout, pos[0], 0); - block.textLayout.getSelectionPath(pos[0], pos[1], path); - if (pos[1] >= block.charactersEnd) { - for (int a = blockNum + 1; a < currentMessageObject.textLayoutBlocks.size(); a++) { - MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); - CharacterStyle[] nextLink; - if (isMono) { - nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, URLSpanMono.class); - } else { - nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, ClickableSpan.class); - } - if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink) { - break; - } - path = obtainNewUrlPath(false); - path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.textYOffset - block.textYOffset); - int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; - nextBlock.textLayout.getSelectionPath(0, p1, path); - if (p1 < nextBlock.charactersEnd - 1) { - break; + if (pressedLink == null || pressedLink.getSpan() != link[0]) { + links.removeLink(pressedLink); + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); + pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); + linkBlockNum = blockNum; + pressedLinkType = 1; + try { + LinkPath path = pressedLink.obtainNewPath(); + int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); + pos[0] -= block.charactersOffset; + pos[1] -= block.charactersOffset; + path.setCurrentLayout(block.textLayout, pos[0], 0); + block.textLayout.getSelectionPath(pos[0], pos[1], path); + if (pos[1] >= block.charactersEnd) { + for (int a = blockNum + 1; a < currentMessageObject.textLayoutBlocks.size(); a++) { + MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); + CharacterStyle[] nextLink; + if (isMono) { + nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, URLSpanMono.class); + } else { + nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, ClickableSpan.class); + } + if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { + break; + } + path = pressedLink.obtainNewPath(); + path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.textYOffset - block.textYOffset); + int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; + nextBlock.textLayout.getSelectionPath(0, p1, path); + if (p1 < nextBlock.charactersEnd - 1) { + break; + } } } - } - if (pos[0] <= block.charactersOffset) { - int offsetY = 0; - for (int a = blockNum - 1; a >= 0; a--) { - MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); - CharacterStyle[] nextLink; - if (isMono) { - nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, URLSpanMono.class); - } else { - nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, ClickableSpan.class); - } - if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink) { - break; - } - path = obtainNewUrlPath(false); - offsetY -= nextBlock.height; - int p0 = pos[0] + block.charactersOffset - nextBlock.charactersOffset; - int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; - path.setCurrentLayout(nextBlock.textLayout, p0, offsetY); - nextBlock.textLayout.getSelectionPath(p0, p1, path); - if (p0 > nextBlock.charactersOffset) { - break; + if (pos[0] <= block.charactersOffset) { + int offsetY = 0; + for (int a = blockNum - 1; a >= 0; a--) { + MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); + CharacterStyle[] nextLink; + if (isMono) { + nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, URLSpanMono.class); + } else { + nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, ClickableSpan.class); + } + if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { + break; + } + path = pressedLink.obtainNewPath(); + offsetY -= nextBlock.height; + int p0 = pos[0] + block.charactersOffset - nextBlock.charactersOffset; + int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; + path.setCurrentLayout(nextBlock.textLayout, p0, offsetY); + nextBlock.textLayout.getSelectionPath(p0, p1, path); + if (p0 > nextBlock.charactersOffset) { + break; + } } } + } catch (Exception e) { + FileLog.e(e); } - } catch (Exception e) { - FileLog.e(e); + links.addLink(pressedLink, 1); } invalidate(); return true; } else { - if (link[0] == pressedLink) { - delegate.didPressUrl(this, pressedLink, false); + if (link[0] == pressedLink.getSpan()) { + delegate.didPressUrl(this, pressedLink.getSpan(), false); resetPressedLink(1); return true; } @@ -1293,16 +1294,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ignore = true; } if (!ignore) { - pressedLink = link[0]; - pressedLinkType = 3; - resetUrlPaths(false); - try { - LinkPath path = obtainNewUrlPath(false); - int[] pos = getRealSpanStartAndEnd(buffer, pressedLink); - path.setCurrentLayout(captionLayout, pos[0], 0); - captionLayout.getSelectionPath(pos[0], pos[1], path); - } catch (Exception e) { - FileLog.e(e); + if (pressedLink == null || pressedLink.getSpan() != link[0]) { + links.removeLink(pressedLink); + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); + pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); + pressedLinkType = 3; + try { + LinkPath path = pressedLink.obtainNewPath(); + int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); + path.setCurrentLayout(captionLayout, pos[0], 0); + captionLayout.getSelectionPath(pos[0], pos[1], path); + } catch (Exception e) { + FileLog.e(e); + } + links.addLink(pressedLink, 3); } invalidateWithParent(); return true; @@ -1312,7 +1317,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate FileLog.e(e); } } else if (pressedLinkType == 3) { - delegate.didPressUrl(this, pressedLink, false); + delegate.didPressUrl(this, pressedLink.getSpan(), false); resetPressedLink(3); return true; } @@ -1354,17 +1359,21 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ignore = true; } if (!ignore) { - pressedLink = link[0]; - linkBlockNum = -10; - pressedLinkType = 2; - resetUrlPaths(false); - try { - LinkPath path = obtainNewUrlPath(false); - int[] pos = getRealSpanStartAndEnd(buffer, pressedLink); - path.setCurrentLayout(descriptionLayout, pos[0], 0); - descriptionLayout.getSelectionPath(pos[0], pos[1], path); - } catch (Exception e) { - FileLog.e(e); + if (pressedLink == null || pressedLink.getSpan() != link[0]) { + links.removeLink(pressedLink); + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); + pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); + linkBlockNum = -10; + pressedLinkType = 2; + try { + LinkPath path = pressedLink.obtainNewPath(); + int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); + path.setCurrentLayout(descriptionLayout, pos[0], 0); + descriptionLayout.getSelectionPath(pos[0], pos[1], path); + } catch (Exception e) { + FileLog.e(e); + } + links.addLink(pressedLink, 2); } invalidate(); return true; @@ -1382,10 +1391,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate didPressButton(true, false); invalidate(); } else if (pressedLink != null) { - if (pressedLink instanceof URLSpan) { - Browser.openUrl(getContext(), ((URLSpan) pressedLink).getURL()); - } else if (pressedLink instanceof ClickableSpan) { - ((ClickableSpan) pressedLink).onClick(this); + if (pressedLink.getSpan() instanceof URLSpan) { + Browser.openUrl(getContext(), ((URLSpan) pressedLink.getSpan()).getURL()); + } else if (pressedLink.getSpan() instanceof ClickableSpan) { + ((ClickableSpan) pressedLink.getSpan()).onClick(this); } resetPressedLink(2); } else { @@ -1435,18 +1444,22 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ignore = true; } if (!ignore) { - pressedLink = link[0]; - linkBlockNum = -10; - pressedLinkType = 2; - resetUrlPaths(false); - startCheckLongPress(); - try { - LinkPath path = obtainNewUrlPath(false); - int[] pos = getRealSpanStartAndEnd(buffer, pressedLink); - path.setCurrentLayout(descriptionLayout, pos[0], 0); - descriptionLayout.getSelectionPath(pos[0], pos[1], path); - } catch (Exception e) { - FileLog.e(e); + if (pressedLink == null || pressedLink.getSpan() != link[0]) { + links.removeLink(pressedLink); + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); + pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); + linkBlockNum = -10; + pressedLinkType = 2; + startCheckLongPress(); + try { + LinkPath path = pressedLink.obtainNewPath(); + int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); + path.setCurrentLayout(descriptionLayout, pos[0], 0); + descriptionLayout.getSelectionPath(pos[0], pos[1], path); + } catch (Exception e) { + FileLog.e(e); + } + links.addLink(pressedLink, 2); } invalidate(); return true; @@ -1530,10 +1543,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate didPressMiniButton(true); invalidate(); } else if (pressedLink != null) { - if (pressedLink instanceof URLSpan) { - delegate.didPressUrl(this, pressedLink, false); - } else if (pressedLink instanceof ClickableSpan) { - ((ClickableSpan) pressedLink).onClick(this); + if (pressedLink.getSpan() instanceof URLSpan) { + delegate.didPressUrl(this, pressedLink.getSpan(), false); + } else if (pressedLink.getSpan() instanceof ClickableSpan) { + ((ClickableSpan) pressedLink.getSpan()).onClick(this); } resetPressedLink(2); } else { @@ -1574,7 +1587,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate resetPressedLink(2); return true; } - } else { + } else if (!hadLongPress) { + hadLongPress = false; resetPressedLink(2); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { @@ -2419,7 +2433,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } result = false; - resetPressedLink(-1); + if (hadLongPress) { + if (pressedLinkType != 2) { + hadLongPress = false; + } + pressedLink = null; + pressedLinkType = -1; + } else { + resetPressedLink(-1); + } } updateRadialProgressBackground(); if (!disallowLongPress && result && event.getAction() == MotionEvent.ACTION_DOWN) { @@ -2556,7 +2578,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate forwardBotPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - delegate.didPressViaBot(this, currentViaBotUser != null ? currentViaBotUser.username : currentMessageObject.messageOwner.via_bot_name); + if (currentViaBotUser.bot_inline_placeholder == null) { + delegate.didPressViaBotNotInline(this, currentViaBotUser != null ? currentViaBotUser.id : 0); + } else { + delegate.didPressViaBot(this, currentViaBotUser != null ? currentViaBotUser.username : currentMessageObject.messageOwner.via_bot_name); + } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { forwardBotPressed = false; @@ -3547,8 +3573,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate AndroidUtilities.cancelRunOnUIThread(invalidateRunnable); scheduledInvalidate = false; } - - resetPressedLink(-1); + links.clear(); + pressedLink = null; + pressedLinkType = -1; messageObject.forceUpdate = false; drawPhotoImage = false; drawMediaCheckBox = false; @@ -6545,7 +6572,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (botButton.button instanceof TLRPC.TL_keyboardButtonBuy && (messageObject.messageOwner.media.flags & 4) != 0) { buttonText = LocaleController.getString("PaymentReceipt", R.string.PaymentReceipt); } else { - buttonText = Emoji.replaceEmoji(botButton.button.text, botButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); + buttonText = botButton.button.text == null ? "" : botButton.button.text; + buttonText = Emoji.replaceEmoji(buttonText, botButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); buttonText = TextUtils.ellipsize(buttonText, botButtonPaint, buttonWidth - AndroidUtilities.dp(10), TextUtils.TruncateAt.END); } botButton.title = new StaticLayout(buttonText, botButtonPaint, buttonWidth - AndroidUtilities.dp(10), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); @@ -6553,6 +6581,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (b == row.buttons.size() - 1) { maxButtonsWidth = Math.max(maxButtonsWidth, botButton.x + botButton.width); } + if (messageObject.isFromUser() && botButton.button instanceof TLRPC.TL_keyboardButtonUrl) { // TODO(dkaraush): or instanceof TLRPC.TL_keyboardButtonInvite in the future + try { + final Uri uri = Uri.parse(botButton.button.url); + final String host = uri.getHost().toLowerCase(); + botButton.isInviteButton = (uri.getQueryParameter("startgroup") != null && ( + ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) && ("t.me".equals(host) || "telegram.me".equals(host) || "telegram.dog".equals(host)) || + "tg".equals(uri.getScheme()) && (botButton.button.url.startsWith("tg:resolve") || botButton.button.url.startsWith("tg://resolve")) + )); + } catch (Exception ignore) {} + } } } } @@ -6740,6 +6778,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean hadLongPress = false; + private static boolean spanSupportsLongPress(CharacterStyle span) { + return span instanceof URLSpanMono || span instanceof URLSpan; + } + @Override protected boolean onLongPress() { if (isRoundVideo && isPlayingRound && MediaController.getInstance().isPlayingMessage(currentMessageObject)) { @@ -6790,18 +6832,23 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return false; } } - if (pressedLink instanceof URLSpanMono) { - delegate.didPressUrl(this, pressedLink, true); - return true; - } else if (pressedLink instanceof URLSpanNoUnderline) { - URLSpanNoUnderline url = (URLSpanNoUnderline) pressedLink; - if (ChatActivity.isClickableLink(url.getURL()) || url.getURL().startsWith("/")) { - delegate.didPressUrl(this, pressedLink, true); + if (pressedLink != null) { + if (pressedLink.getSpan() instanceof URLSpanMono) { + hadLongPress = true; + delegate.didPressUrl(this, pressedLink.getSpan(), true); + return true; + } else if (pressedLink.getSpan() instanceof URLSpanNoUnderline) { + URLSpanNoUnderline url = (URLSpanNoUnderline) pressedLink.getSpan(); + if (ChatActivity.isClickableLink(url.getURL()) || url.getURL().startsWith("/")) { + hadLongPress = true; + delegate.didPressUrl(this, pressedLink.getSpan(), true); + return true; + } + } else if (pressedLink.getSpan() instanceof URLSpan) { + hadLongPress = true; + delegate.didPressUrl(this, pressedLink.getSpan(), true); return true; } - } else if (pressedLink instanceof URLSpan) { - delegate.didPressUrl(this, pressedLink, true); - return true; } resetPressedLink(-1); if (buttonPressed != 0 || miniButtonPressed != 0 || videoButtonPressed != 0 || pressedBotButton != -1) { @@ -6915,7 +6962,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return; } super.invalidate(); - if (invalidatesParent && getParent() != null) { + if ((invalidatesParent || currentMessagesGroup != null && !links.isEmpty()) && getParent() != null) { View parent = (View) getParent(); if (parent.getParent() != null) { parent.invalidate(); @@ -7081,6 +7128,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } seekBarWaveform.setMessageObject(messageObject); return 0; + } else if (MessageObject.isVideoDocument(documentAttach)) { + documentAttachType = DOCUMENT_ATTACH_TYPE_VIDEO; + if (!messageObject.needDrawBluredPreview()) { + updatePlayingMessageProgress(); + String str; + str = String.format("%s", AndroidUtilities.formatFileSize(documentAttach.size)); + docTitleWidth = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); + docTitleLayout = new StaticLayout(str, Theme.chat_infoPaint, docTitleWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } + return 0; } else if (MessageObject.isMusicDocument(documentAttach)) { documentAttachType = DOCUMENT_ATTACH_TYPE_MUSIC; @@ -7113,16 +7170,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate widthBeforeNewTimeLine = backgroundWidth - AndroidUtilities.dp(10 + 76) - durationWidth; availableTimeWidth = backgroundWidth - AndroidUtilities.dp(28); return durationWidth; - } else if (MessageObject.isVideoDocument(documentAttach)) { - documentAttachType = DOCUMENT_ATTACH_TYPE_VIDEO; - if (!messageObject.needDrawBluredPreview()) { - updatePlayingMessageProgress(); - String str; - str = String.format("%s", AndroidUtilities.formatFileSize(documentAttach.size)); - docTitleWidth = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); - docTitleLayout = new StaticLayout(str, Theme.chat_infoPaint, docTitleWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - } - return 0; } else if (MessageObject.isGifDocument(documentAttach, messageObject.hasValidGroupId())) { documentAttachType = DOCUMENT_ATTACH_TYPE_GIF; if (!messageObject.needDrawBluredPreview()) { @@ -7224,7 +7271,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (messageObject == null || messageObject.messageOwner.message == null || TextUtils.isEmpty(text)) { if (!urlPathSelection.isEmpty()) { linkSelectionBlockNum = -1; - resetUrlPaths(true); + resetUrlPaths(); invalidate(); } return; @@ -7257,7 +7304,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (start == -1) { if (!urlPathSelection.isEmpty()) { linkSelectionBlockNum = -1; - resetUrlPaths(true); + resetUrlPaths(); invalidate(); } return; @@ -7271,9 +7318,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } int end = start + length; if (captionLayout != null && !TextUtils.isEmpty(messageObject.caption)) { - resetUrlPaths(true); + resetUrlPaths(); try { - LinkPath path = obtainNewUrlPath(true); + LinkPath path = obtainNewUrlPath(); path.setCurrentLayout(captionLayout, start, 0); captionLayout.getSelectionPath(start, end, path); } catch (Exception e) { @@ -7285,16 +7332,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate MessageObject.TextLayoutBlock block = messageObject.textLayoutBlocks.get(c); if (start >= block.charactersOffset && start < block.charactersEnd) { linkSelectionBlockNum = c; - resetUrlPaths(true); + resetUrlPaths(); try { - LinkPath path = obtainNewUrlPath(true); + LinkPath path = obtainNewUrlPath(); path.setCurrentLayout(block.textLayout, start, 0); block.textLayout.getSelectionPath(start, end, path); if (end >= block.charactersOffset + length) { for (int a = c + 1; a < messageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = messageObject.textLayoutBlocks.get(a); length = nextBlock.charactersEnd - nextBlock.charactersOffset; - path = obtainNewUrlPath(true); + path = obtainNewUrlPath(); path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.height); nextBlock.textLayout.getSelectionPath(0, end - nextBlock.charactersOffset, path); if (end < block.charactersOffset + length - 1) { @@ -8569,7 +8616,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (hasNewLineForTime) { reactionsLayoutInBubble.y -= AndroidUtilities.dp(16); } - if (captionLayout != null && ((currentMessageObject.type != 2 && !(currentMessageObject.type == 9 && drawPhotoImage)) || (currentPosition != null && currentMessagesGroup != null))) { + if (captionLayout != null && ((currentMessageObject.type != 2 && !(currentMessageObject.isOut() && drawForwardedName && !drawPhotoImage) && !(currentMessageObject.type == 9 && drawPhotoImage)) || (currentPosition != null && currentMessagesGroup != null))) { reactionsLayoutInBubble.y -= AndroidUtilities.dp(14); } reactionsLayoutInBubble.y = reactionsLayoutInBubble.y + reactionsLayoutInBubble.positionOffsetY; @@ -8772,9 +8819,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate descriptionY = linkPreviewY - AndroidUtilities.dp(3); canvas.save(); canvas.translate(linkX + (hasInvoicePreview ? 0 : AndroidUtilities.dp(10)) + descriptionX, descriptionY); - if (pressedLink != null && linkBlockNum == -10) { - for (int b = 0; b < urlPath.size(); b++) { - canvas.drawPath(urlPath.get(b), Theme.chat_urlPaint); + if (linkBlockNum == -10) { + if (links.draw(canvas)) { + invalidate(); } } if (delegate != null && delegate.getTextSelectionHelper() != null && getDelegate().getTextSelectionHelper().isSelected(currentMessageObject)) { @@ -8951,8 +8998,18 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.translate(button.x + addX + AndroidUtilities.dp(5), y + (AndroidUtilities.dp(44) - button.title.getLineBottom(button.title.getLineCount() - 1)) / 2); button.title.draw(canvas); canvas.restore(); - if (button.button instanceof TLRPC.TL_keyboardButtonUrl) { - Drawable drawable = getThemedDrawable(Theme.key_drawable_botLink); + if (button.button instanceof TLRPC.TL_keyboardButtonWebView) { + Drawable drawable = getThemedDrawable(Theme.key_drawable_botWebView); + int x = button.x + button.width - AndroidUtilities.dp(3) - drawable.getIntrinsicWidth() + addX; + setDrawableBounds(drawable, x, y + AndroidUtilities.dp(3)); + drawable.draw(canvas); + } else if (button.button instanceof TLRPC.TL_keyboardButtonUrl) { + Drawable drawable; + if (button.isInviteButton) { + drawable = getThemedDrawable(Theme.key_drawable_botInvite); + } else { + drawable = getThemedDrawable(Theme.key_drawable_botLink); + } int x = button.x + button.width - AndroidUtilities.dp(3) - drawable.getIntrinsicWidth() + addX; setDrawableBounds(drawable, x, y + AndroidUtilities.dp(3)); drawable.draw(canvas); @@ -8963,9 +9020,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate drawable.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); + int x = button.x + button.width - AndroidUtilities.dp(5) - Theme.chat_botCardDrawable.getIntrinsicWidth() + addX; + setDrawableBounds(Theme.chat_botCardDrawable, x, y + AndroidUtilities.dp(4)); + Theme.chat_botCardDrawable.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); @@ -9071,9 +9128,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate MessageObject.TextLayoutBlock block = textLayoutBlocks.get(a); canvas.save(); canvas.translate(textX - (block.isRtl() ? (int) Math.ceil(currentMessageObject.textXOffset) : 0), textY + block.textYOffset + transitionYOffsetForDrawables); - if (pressedLink != null && a == linkBlockNum && !drawOnlyText) { - for (int b = 0; b < urlPath.size(); b++) { - canvas.drawPath(urlPath.get(b), Theme.chat_urlPaint); + if (a == linkBlockNum && !drawOnlyText) { + if (links.draw(canvas)) { + invalidate(); } } if (a == linkSelectionBlockNum && !urlPathSelection.isEmpty() && !drawOnlyText) { @@ -10685,24 +10742,41 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate maxWidth -= AndroidUtilities.dp(44); } - if (messageObject.customReplyName != null) { - name = messageObject.customReplyName; - } else { - long fromId = messageObject.replyMessageObject.getFromChatId(); - if (fromId > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(fromId); - if (user != null) { + if (messageObject.hideSendersName) { + if (messageObject.sendAsPeer != null) { + if (messageObject.sendAsPeer.channel_id != 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(messageObject.sendAsPeer.channel_id); + if (chat != null) { + name = chat.title; + } + } else { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(messageObject.sendAsPeer.user_id); name = UserObject.getUserName(user); } - } else if (fromId < 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId); - if (chat != null) { - name = chat.title; - } } else { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(messageObject.replyMessageObject.messageOwner.peer_id.channel_id); - if (chat != null) { - name = chat.title; + name = UserObject.getUserName(AccountInstance.getInstance(currentAccount).getUserConfig().getCurrentUser()); + } + } else if (messageObject.customReplyName != null) { + name = messageObject.customReplyName; + } else { + name = messageObject.replyMessageObject.getForwardedName(); + if (name == null) { + long fromId = messageObject.replyMessageObject.getFromChatId(); + if (fromId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(fromId); + if (user != null) { + name = UserObject.getUserName(user); + } + } else if (fromId < 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId); + if (chat != null) { + name = chat.title; + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(messageObject.replyMessageObject.messageOwner.peer_id.channel_id); + if (chat != null) { + name = chat.title; + } } } } @@ -11119,7 +11193,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { replyStartX = backgroundDrawableLeft + backgroundDrawableRight + AndroidUtilities.dp(17); } - replyStartY = AndroidUtilities.dp(12); + if (drawForwardedName) { + replyStartY = forwardNameY + AndroidUtilities.dp(38); + } else { + replyStartY = AndroidUtilities.dp(12); + } } else { if (currentMessageObject.isOutOwner()) { replyStartX = backgroundDrawableLeft + AndroidUtilities.dp(12) + getExtraTextX(); @@ -11998,6 +12076,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } boolean drawForwardedNameLocal = drawForwardedName; + boolean hasReply = replyNameLayout != null; StaticLayout[] forwardedNameLayoutLocal = forwardedNameLayout; float animatingAlpha = 1f; int forwardedNameWidthLocal = forwardedNameWidth; @@ -12013,6 +12092,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } float forwardNameXLocal; + boolean needDrawReplyBackground = true; if (drawForwardedNameLocal && forwardedNameLayoutLocal[0] != null && forwardedNameLayoutLocal[1] != null && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0)) { if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO || currentMessageObject.isAnyKindOfSticker()) { Theme.chat_forwardNamePaint.setColor(getThemedColor(Theme.key_chat_stickerReplyNameText)); @@ -12031,8 +12111,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate forwardNameY = AndroidUtilities.dp(12); int backWidth = forwardedNameWidthLocal + AndroidUtilities.dp(14); - - rect.set((int) forwardNameXLocal - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), (int) forwardNameXLocal - AndroidUtilities.dp(7) + backWidth, forwardNameY + AndroidUtilities.dp(38)); + if (hasReply) { + needDrawReplyBackground = false; + int replyBackWidth = Math.max(replyNameWidth, replyTextWidth) + AndroidUtilities.dp(14); + rect.set((int) forwardNameXLocal - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), (int) forwardNameXLocal - AndroidUtilities.dp(7) + Math.max(backWidth, replyBackWidth), forwardNameY + AndroidUtilities.dp(38) + AndroidUtilities.dp(41)); + } else { + rect.set((int) forwardNameXLocal - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), (int) forwardNameXLocal - AndroidUtilities.dp(7) + backWidth, forwardNameY + AndroidUtilities.dp(38)); + } applyServiceShaderMatrix(); int oldAlpha1 = -1, oldAlpha2 = -1; if (animatingAlpha != 1f || replyForwardAlpha != 1f) { @@ -12157,8 +12242,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - if (replyNameLayout != null) { + if (hasReply) { float replyStartX = this.replyStartX; + float replyStartY = this.replyStartY; if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { replyStartX += currentMessagesGroup.transitionParams.offsetLeft; } @@ -12168,6 +12254,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { replyStartX += transitionParams.deltaLeft; } + replyStartY = this.replyStartY * transitionParams.animateChangeProgress + transitionParams.animateFromReplyY * (1f - transitionParams.animateChangeProgress); } if (currentMessageObject.shouldDrawWithoutBackground()) { Theme.chat_replyLinePaint.setColor(getThemedColor(Theme.key_chat_stickerReplyLine)); @@ -12179,19 +12266,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Theme.chat_replyTextPaint.setColor(getThemedColor(Theme.key_chat_stickerReplyMessageText)); oldAlpha = Theme.chat_replyTextPaint.getAlpha(); Theme.chat_replyTextPaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); - int backWidth = Math.max(replyNameWidth, replyTextWidth) + AndroidUtilities.dp(14); - - rect.set((int) replyStartX - AndroidUtilities.dp(7), replyStartY - AndroidUtilities.dp(6), (int) replyStartX - AndroidUtilities.dp(7) + backWidth, replyStartY + AndroidUtilities.dp(41)); - applyServiceShaderMatrix(); - oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); - getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); - canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), getThemedPaint(Theme.key_paint_chatActionBackground)); - getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); - if (hasGradientService()) { - oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); - canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), Theme.chat_actionBackgroundGradientDarkenPaint); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); + if (needDrawReplyBackground) { + int backWidth = Math.max(replyNameWidth, replyTextWidth) + AndroidUtilities.dp(14); + rect.set((int) replyStartX - AndroidUtilities.dp(7), replyStartY - AndroidUtilities.dp(6), (int) replyStartX - AndroidUtilities.dp(7) + backWidth, replyStartY + AndroidUtilities.dp(41)); + applyServiceShaderMatrix(); + oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); + canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), getThemedPaint(Theme.key_paint_chatActionBackground)); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); + if (hasGradientService()) { + oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); + canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), Theme.chat_actionBackgroundGradientDarkenPaint); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); + } } } else { if (currentMessageObject.isOutOwner()) { @@ -12214,7 +12302,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } forwardNameX = replyStartX - replyTextOffset + AndroidUtilities.dp(10 + (needReplyImage ? 44 : 0)); if ((currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0) && !(enterTransitionInProgress && !currentMessageObject.isVoice())) { - canvas.drawRect(replyStartX, replyStartY, replyStartX + AndroidUtilities.dp(2), replyStartY + AndroidUtilities.dp(35), Theme.chat_replyLinePaint); + AndroidUtilities.rectTmp.set(replyStartX, replyStartY, replyStartX + AndroidUtilities.dp(2), replyStartY + AndroidUtilities.dp(35)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(1), AndroidUtilities.dp(1), Theme.chat_replyLinePaint); if (needReplyImage) { replyImageReceiver.setAlpha(replyForwardAlpha); replyImageReceiver.setImageCoords(replyStartX + AndroidUtilities.dp(10), replyStartY, AndroidUtilities.dp(35), AndroidUtilities.dp(35)); @@ -12604,7 +12693,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - if (captionLayout == null || selectionOnly && pressedLink == null || (currentMessageObject.deleted && currentPosition != null) || alpha == 0) { + if (captionLayout == null || selectionOnly && links.isEmpty() || (currentMessageObject.deleted && currentPosition != null) || alpha == 0) { return; } if (currentMessageObject.isOutOwner()) { @@ -12660,10 +12749,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } canvas.translate(captionX, captionY); - if (pressedLink != null) { - for (int b = 0; b < urlPath.size(); b++) { - canvas.drawPath(urlPath.get(b), Theme.chat_urlPaint); - } + if (links.draw(canvas)) { + invalidate(); } if (!urlPathSelection.isEmpty()) { for (int b = 0; b < urlPathSelection.size(); b++) { @@ -15473,6 +15560,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public boolean animateRoundVideoDotY; public float lastDrawRoundVideoDotY; public float animateFromRoundVideoDotY; + public boolean animateReplyY; + public float lastDrawReplyY; + public float animateFromReplyY; private boolean lastIsPinned; private boolean animatePinned; @@ -15671,6 +15761,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate lastBackgroundRight = currentBackgroundDrawable.getBounds().right; reactionsLayoutInBubble.recordDrawingState(); + if (replyNameLayout != null) { + lastDrawReplyY = replyStartY; + } else { + lastDrawReplyY = 0; + } } public void recordDrawingStatePreview() { @@ -15897,6 +15992,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + if (replyNameLayout != null && replyStartX != lastDrawReplyY && lastDrawReplyY != 0) { + animateReplyY = true; + animateFromReplyY = lastDrawReplyY; + changed = true; + } + return changed; } @@ -15959,6 +16060,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate animatingForwardedNameLayout[0] = null; animatingForwardedNameLayout[1] = null; animateRoundVideoDotY = false; + animateReplyY = false; reactionsLayoutInBubble.resetAnimation(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/CreationTextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CreationTextCell.java new file mode 100644 index 000000000..458abdb8f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CreationTextCell.java @@ -0,0 +1,79 @@ +package org.telegram.ui.Cells; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; + +public class CreationTextCell extends FrameLayout { + + private SimpleTextView textView; + private ImageView imageView; + boolean divider; + public int startPadding = 70; + + public CreationTextCell(Context context) { + super(context); + + textView = new SimpleTextView(context); + textView.setTextSize(16); + textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText2)); + textView.setTag(Theme.key_windowBackgroundWhiteBlueText2); + addView(textView); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + addView(imageView); + setWillNotDraw(false); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = AndroidUtilities.dp(48); + + textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + 23), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); + setMeasuredDimension(width, AndroidUtilities.dp(50)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int height = bottom - top; + int width = right - left; + + int viewLeft; + int viewTop = (height - textView.getTextHeight()) / 2; + if (LocaleController.isRTL) { + viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? startPadding : 25); + } else { + viewLeft = AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? startPadding : 25); + } + textView.layout(viewLeft, viewTop, viewLeft + textView.getMeasuredWidth(), viewTop + textView.getMeasuredHeight()); + + viewLeft = !LocaleController.isRTL ? (AndroidUtilities.dp(startPadding) - imageView.getMeasuredWidth()) / 2 : width - imageView.getMeasuredWidth() - AndroidUtilities.dp(25); + imageView.layout(viewLeft, 0, viewLeft + imageView.getMeasuredWidth(), imageView.getMeasuredHeight()); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (divider) { + canvas.drawLine(AndroidUtilities.dp(startPadding), getMeasuredHeight() - 1, getMeasuredWidth() + AndroidUtilities.dp(23), getMeasuredHeight(), Theme.dividerPaint); + } + } + + public void setTextAndIcon(String text, Drawable icon, boolean divider) { + textView.setText(text); + imageView.setImageDrawable(icon); + this.divider = divider; + } +} \ No newline at end of file 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 da1a124e5..74b1e0e68 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -264,6 +264,7 @@ public class DialogCell extends BaseCell { private int pinLeft; private boolean drawCount; + private boolean drawCount2 = true; private int countTop; private int countLeft; private int countWidth; @@ -525,6 +526,7 @@ public class DialogCell extends BaseCell { bottomClip = getMeasuredHeight(); } + int lastSize; @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (currentDialogId == 0 && customDialog == null) { @@ -535,7 +537,9 @@ public class DialogCell extends BaseCell { int y = AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 48 : 42); checkBox.layout(x, y, x + checkBox.getMeasuredWidth(), y + checkBox.getMeasuredHeight()); } - if (changed) { + int size = getMeasuredHeight() + getMeasuredWidth() << 16; + if (size != lastSize) { + lastSize = size; try { buildLayout(); } catch (Exception e) { @@ -1012,7 +1016,39 @@ public class DialogCell extends BaseCell { } else { fromChat = MessagesController.getInstance(currentAccount).getChat(-fromId); } - if (dialogsType == 3 && UserObject.isUserSelf(user)) { + drawCount2 = true; + if (dialogsType == 2) { + if (chat != null) { + if (ChatObject.isChannel(chat) && !chat.megagroup) { + if (chat.participants_count != 0) { + messageString = LocaleController.formatPluralStringComma("Subscribers", chat.participants_count); + } else { + if (TextUtils.isEmpty(chat.username)) { + messageString = LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate).toLowerCase(); + } else { + messageString = LocaleController.getString("ChannelPublic", R.string.ChannelPublic).toLowerCase(); + } + } + } else { + if (chat.participants_count != 0) { + messageString = LocaleController.formatPluralStringComma("Members", chat.participants_count); + } else { + if (chat.has_geo) { + messageString = LocaleController.getString("MegaLocation", R.string.MegaLocation); + } else if (TextUtils.isEmpty(chat.username)) { + messageString = LocaleController.getString("MegaPrivate", R.string.MegaPrivate).toLowerCase(); + } else { + messageString = LocaleController.getString("MegaPublic", R.string.MegaPublic).toLowerCase(); + } + } + } + } else { + messageString = ""; + } + drawCount2 = false; + showChecks = false; + drawTime = false; + } else if (dialogsType == 3 && UserObject.isUserSelf(user)) { messageString = LocaleController.getString("SavedMessagesInfo", R.string.SavedMessagesInfo); showChecks = false; drawTime = false; @@ -2092,6 +2128,9 @@ public class DialogCell extends BaseCell { } else { drawPin = false; } + if (dialogsType == 2) { + drawPin = false; + } if (mask != 0) { boolean continueUpdate = false; @@ -2272,7 +2311,7 @@ public class DialogCell extends BaseCell { countAnimator.setDuration(430); countAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); } - if (drawCount && countLayout != null) { + if (drawCount && drawCount2 && countLayout != null) { String oldStr = String.valueOf(oldUnreadCount); String newStr = String.valueOf(unreadCount); @@ -2769,7 +2808,7 @@ public class DialogCell extends BaseCell { lastStatusDrawableParams = (this.drawClock ? 1 : 0) + (this.drawCheck1 ? 2 : 0) + (this.drawCheck2 ? 4 : 0); } - if ((dialogMuted || dialogMutedProgress > 0) && !drawVerified && drawScam == 0) { + if (dialogsType != 2 && (dialogMuted || dialogMutedProgress > 0) && !drawVerified && drawScam == 0) { if (dialogMuted && dialogMutedProgress != 1f) { dialogMutedProgress += 16 / 150f; if (dialogMutedProgress > 1f) { @@ -2818,8 +2857,8 @@ public class DialogCell extends BaseCell { canvas.drawRoundRect(rect, 11.5f * AndroidUtilities.density, 11.5f * AndroidUtilities.density, Theme.dialogs_errorPaint); setDrawableBounds(Theme.dialogs_errorDrawable, errorLeft + AndroidUtilities.dp(5.5f), errorTop + AndroidUtilities.dp(5)); Theme.dialogs_errorDrawable.draw(canvas); - } else if (drawCount || drawMention || countChangeProgress != 1f || drawReactionMention || reactionsMentionsChangeProgress != 1f) { - if (drawCount || countChangeProgress != 1f) { + } else if ((drawCount || drawMention) && drawCount2 || countChangeProgress != 1f || drawReactionMention || reactionsMentionsChangeProgress != 1f) { + if (drawCount && drawCount2 || countChangeProgress != 1f) { final float progressFinal = (unreadCount == 0 && !markUnread) ? 1f - countChangeProgress : countChangeProgress; if (countOldLayout == null || unreadCount == 0) { StaticLayout drawLayout = unreadCount == 0 ? countOldLayout : countLayout; 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 096210cb6..f6101d400 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java @@ -41,6 +41,9 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBarLayout; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.DrawerLayoutContainer; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -49,6 +52,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.SnowflakesEffect; +import org.telegram.ui.ThemeActivity; public class DrawerProfileCell extends FrameLayout { @@ -71,7 +75,7 @@ public class DrawerProfileCell extends FrameLayout { private int darkThemeBackgroundColor; public static boolean switchingTheme; - public DrawerProfileCell(Context context) { + public DrawerProfileCell(Context context, DrawerLayoutContainer drawerLayoutContainer) { super(context); shadowView = new ImageView(context); @@ -127,6 +131,7 @@ public class DrawerProfileCell extends FrameLayout { } } }; + darkThemeView.setBackground(Theme.createCircleSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 0, 0)); sunDrawable.beginApplyLayerColors(); int color = Theme.getColor(Theme.key_chats_menuName); sunDrawable.setLayerColor("Sunny.**", color); @@ -180,6 +185,13 @@ public class DrawerProfileCell extends FrameLayout { } switchTheme(themeInfo, toDark); }); + darkThemeView.setOnLongClickListener(e -> { + if (drawerLayoutContainer != null) { + drawerLayoutContainer.presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC)); + return true; + } + return false; + }); addView(darkThemeView, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 6, 90)); if (Theme.getEventType() == 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java index 4cb684855..aadad0a6a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java @@ -93,6 +93,14 @@ public class HeaderCell extends FrameLayout { super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); } + public void setTextSize(float dip) { + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, dip); + } + + public void setTextColor(int color) { + textView.setTextColor(color); + } + public void setText(CharSequence text) { textView.setText(text); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java index 290a578dd..97d086b14 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java @@ -37,6 +37,7 @@ public class NotificationsCheckCell extends FrameLayout { private boolean drawLine = true; private boolean isMultiline; private int currentHeight; + private boolean animationsEnabled; public NotificationsCheckCell(Context context) { this(context, 21, 70, false); @@ -103,7 +104,7 @@ public class NotificationsCheckCell extends FrameLayout { public void setTextAndValueAndCheck(String text, CharSequence value, boolean checked, int iconType, boolean multiline, boolean divider) { textView.setText(text); valueTextView.setText(value); - checkBox.setChecked(checked, iconType, false); + checkBox.setChecked(checked, iconType, animationsEnabled); valueTextView.setVisibility(VISIBLE); needDivider = divider; isMultiline = multiline; @@ -151,4 +152,8 @@ public class NotificationsCheckCell extends FrameLayout { canvas.drawRect(x, y, x + 2, y + AndroidUtilities.dp(22), Theme.dividerPaint); } } + + public void setAnimationsEnabled(boolean animationsEnabled) { + this.animationsEnabled = animationsEnabled; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java index 05241c71d..8982ce84b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java @@ -26,7 +26,7 @@ import org.telegram.ui.Components.RadioButton; public class RadioButtonCell extends FrameLayout { private TextView textView; - private TextView valueTextView; + public TextView valueTextView; private RadioButton radioButton; private boolean needDivider; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java index 99676b052..c9e0ecf9e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java @@ -113,6 +113,9 @@ public class TextCheckCell2 extends FrameLayout { @Override public void setEnabled(boolean value) { super.setEnabled(value); + textView.clearAnimation(); + valueTextView.clearAnimation(); + checkBox.clearAnimation(); if (value) { textView.setAlpha(1.0f); valueTextView.setAlpha(1.0f); @@ -124,6 +127,28 @@ public class TextCheckCell2 extends FrameLayout { } } + public void setEnabled(boolean value, boolean animated) { + super.setEnabled(value); + if (animated) { + textView.clearAnimation(); + valueTextView.clearAnimation(); + checkBox.clearAnimation(); + textView.animate().alpha(value ? 1 : .5f).start(); + valueTextView.animate().alpha(value ? 1 : .5f).start(); + checkBox.animate().alpha(value ? 1 : .5f).start(); + } else { + if (value) { + textView.setAlpha(1.0f); + valueTextView.setAlpha(1.0f); + checkBox.setAlpha(1.0f); + } else { + checkBox.setAlpha(0.5f); + textView.setAlpha(0.5f); + valueTextView.setAlpha(0.5f); + } + } + } + public void setChecked(boolean checked) { checkBox.setChecked(checked, true); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java index d1aad0464..da2ad6957 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java @@ -55,7 +55,6 @@ import org.telegram.ui.ActionBar.FloatingToolbar; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ArticleViewer; import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.LinkPath; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.RestrictedLanguagesSelectActivity; @@ -1473,7 +1472,7 @@ public abstract class TextSelectionHelper { @@ -1246,6 +1246,7 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio builder.setTitle(LocaleController.getString("Message", R.string.Message)); showDialog(builder.create()); + return true; } private String getMessageContent(MessageObject messageObject, int previousUid, boolean name) { @@ -2361,8 +2362,8 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio } @Override - public void didLongPress(ChatActionCell cell, float x, float y) { - createMenu(cell); + public boolean didLongPress(ChatActionCell cell, float x, float y) { + return createMenu(cell); } @Override @@ -2764,7 +2765,7 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio 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_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}, null, new Drawable[]{Theme.chat_botCardDrawable, Theme.chat_shareIconDrawable, Theme.chat_botInlineDrawable, Theme.chat_botLinkDrawable, 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/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index c1049a4df..01fdb6151 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -129,6 +129,7 @@ import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; import org.telegram.messenger.SecretChatHelper; import org.telegram.messenger.SendMessagesHelper; @@ -176,6 +177,8 @@ import org.telegram.ui.Cells.TextSelectionHelper; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimationProperties; +import org.telegram.ui.Components.AttachBotIntroTopView; +import org.telegram.ui.Components.AutoDeletePopupWrapper; import org.telegram.ui.Components.BackButtonMenu; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BlurBehindDrawable; @@ -191,10 +194,10 @@ import org.telegram.ui.Components.ChatAttachAlertDocumentLayout; import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.ChatBigEmptyView; import org.telegram.ui.Components.ChatGreetingsView; +import org.telegram.ui.Components.ChatNotificationsPopupWrapper; import org.telegram.ui.Components.ChatScrimPopupContainerLayout; import org.telegram.ui.Components.ChatThemeBottomSheet; import org.telegram.ui.Components.ChecksHintView; -import org.telegram.ui.Components.ClearHistoryAlert; import org.telegram.ui.Components.ClippingImageView; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CounterView; @@ -308,6 +311,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean searchItemVisible; private RadialProgressView progressBar; private ActionBarMenuSubItem addContactItem; + private ActionBarMenuSubItem clearHistoryItem; private ClippingImageView animatingImageView; private RecyclerListView chatListView; private ChatListItemAnimator chatListItemAnimator; @@ -336,6 +340,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private StickersAdapter stickersAdapter; private FrameLayout stickersPanel; private ActionBarMenuSubItem muteItem; + private View muteItemGap; + private ChatNotificationsPopupWrapper chatNotificationsPopupWrapper; private float pagedownButtonEnterProgress; private float mentionsButtonEnterProgress; private float reactionsMentionButtonEnterProgress; @@ -402,11 +408,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean setPinnedTextTranslationX; private AnimatorSet pinnedMessageViewAnimator; private BackupImageView[] pinnedMessageImageView = new BackupImageView[2]; - private SimpleTextView[] pinnedNameTextView = new SimpleTextView[2]; + private TrackingWidthSimpleTextView[] pinnedNameTextView = new TrackingWidthSimpleTextView[2]; private SimpleTextView[] pinnedMessageTextView = new SimpleTextView[2]; + private PinnedMessageButton[] pinnedMessageButton = new PinnedMessageButton[2]; private NumberTextView pinnedCounterTextView; private int pinnedCounterTextViewX; private AnimatorSet[] pinnedNextAnimation = new AnimatorSet[2]; + private boolean pinnedMessageButtonShown = false; private ImageView closePinned; private RadialProgressView pinnedProgress; private ImageView pinnedListButton; @@ -667,10 +675,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private long inlineReturn; private String voiceChatHash; private boolean livestream; + private String attachMenuBotToOpen; + private String attachMenuBotStartCommand; private MessageObject botButtons; private MessageObject botReplyButtons; private int botsCount; private boolean hasBotsCommands; + private boolean hasBotWebView; private long chatEnterTime; private long chatLeaveTime; @@ -889,7 +900,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private EmojiAnimationsOverlay emojiAnimationsOverlay; public float drawingChatLisViewYoffset; public int blurredViewTopOffset; - private int blurredViewBottomOffset; + public int blurredViewBottomOffset; public void deleteHistory(int dateSelectedStart, int dateSelectedEnd, boolean forAll) { chatAdapter.frozenMessages.clear(); @@ -922,6 +933,34 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); } + public void showHeaderItem(boolean show) { + if (show) { + if (chatActivityEnterView.hasText() && TextUtils.isEmpty(chatActivityEnterView.getSlowModeTimer())) { + if (attachItem != null) { + attachItem.setVisibility(View.VISIBLE); + } + if (headerItem != null) { + headerItem.setVisibility(View.GONE); + } + } else { + if (attachItem != null) { + attachItem.setVisibility(View.GONE); + } + if (headerItem != null) { + headerItem.setVisibility(View.VISIBLE); + } + } + } else { + if (attachItem != null) { + attachItem.setVisibility(View.GONE); + } + if (headerItem != null) { + headerItem.setVisibility(View.GONE); + } + } + + } + private interface ChatActivityDelegate { default void openReplyMessage(int mid) { @@ -929,6 +968,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not default void openSearch(String text) { + } default void onUnpin(boolean all, boolean hide) { @@ -1271,8 +1311,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return false; } wasManualScroll = true; - if (!actionBar.isActionModeShowed() && reportType < 0) { - createMenu(view, false, true, x, y); + boolean result = true; + if (!actionBar.isActionModeShowed() && (reportType < 0 || (view instanceof ChatActionCell && ((ChatActionCell) view).getMessageObject().messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL))) { + result = createMenu(view, false, true, x, y); } else { boolean outside = false; if (view instanceof ChatMessageCell) { @@ -1282,8 +1323,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (view instanceof ChatMessageCell) { startMultiselect(position); + result = true; } - return true; + return result; } }; @@ -1502,6 +1544,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatMode = arguments.getInt("chatMode", 0); voiceChatHash = arguments.getString("voicechat", null); livestream = !TextUtils.isEmpty(arguments.getString("livestream", null)); + attachMenuBotToOpen = arguments.getString("attach_bot", null); + attachMenuBotStartCommand = arguments.getString("attach_bot_start_command", null); inlineReturn = arguments.getLong("inline_return", 0); String inlineQuery = arguments.getString("inline_query"); startLoadFromMessageId = arguments.getInt("message_id", 0); @@ -2253,37 +2297,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (getParentActivity() == null) { return; } - if (id == auto_delete_timer || id == clear_history && currentEncryptedChat == null && (currentUser != null && !UserObject.isUserSelf(currentUser) && !UserObject.isDeleted(currentUser) || ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_DELETE_MESSAGES) && (!ChatObject.isChannel(currentChat) || currentChat.megagroup && TextUtils.isEmpty(currentChat.username)))) { - ClearHistoryAlert alert = new ClearHistoryAlert(getParentActivity(), currentUser, currentChat, id != auto_delete_timer, themeDelegate); - alert.setDelegate(new ClearHistoryAlert.ClearHistoryAlertDelegate() { + boolean canDeleteHistory = chatInfo != null && chatInfo.can_delete_channel; + if (id == auto_delete_timer || id == clear_history && currentEncryptedChat == null && ((currentUser != null && !UserObject.isUserSelf(currentUser) && !UserObject.isDeleted(currentUser)) || (chatInfo != null && chatInfo.can_delete_channel))) { + AlertsCreator.createClearDaysDialogAlert(ChatActivity.this, -1, currentUser, currentChat, canDeleteHistory, new MessagesStorage.BooleanCallback() { @Override - public void onClearHistory(boolean revoke) { - if (revoke && currentUser != null) { - getMessagesStorage().getMessagesCount(currentUser.id, (count) -> { + public void run(boolean revoke) { + if (revoke && (currentUser != null || canDeleteHistory)) { + getMessagesStorage().getMessagesCount(dialog_id, (count) -> { if (count >= 50) { - AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, true, false, true, null, currentUser, false, false, (param) -> performHistoryClear(true), themeDelegate); + AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, true, false, true, currentChat, currentUser, false, false, canDeleteHistory, (param) -> performHistoryClear(true, canDeleteHistory), themeDelegate); } else { - performHistoryClear(true); + performHistoryClear(true, canDeleteHistory); } }); } else { - performHistoryClear(revoke); + performHistoryClear(revoke, canDeleteHistory); } } - - @Override - public void onAutoDeleteHistory(int ttl, int action) { - getMessagesController().setDialogHistoryTTL(dialog_id, ttl); - if (userInfo != null || chatInfo != null) { - undoView.showWithAction(dialog_id, action, currentUser, userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period, null, null); - } - } - }); - showDialog(alert); + }, getResourceProvider()); return; } - - AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, id == clear_history, currentChat, currentUser, currentEncryptedChat != null, true, (param) -> { + AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, id == clear_history, currentChat, currentUser, currentEncryptedChat != null, true, canDeleteHistory, (param) -> { if (id == clear_history && ChatObject.isChannel(currentChat) && (!currentChat.megagroup || !TextUtils.isEmpty(currentChat.username))) { getMessagesController().deleteDialog(dialog_id, 2, param); } else { @@ -2293,7 +2327,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not finishFragment(); getNotificationCenter().postNotificationName(NotificationCenter.needDeleteDialog, dialog_id, currentUser, currentChat, param); } else { - performHistoryClear(param); + performHistoryClear(param, canDeleteHistory); } } }, themeDelegate); @@ -2708,6 +2742,66 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } headerItem = menu.addItem(0, R.drawable.ic_ab_other, themeDelegate); headerItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); + + if (currentUser == null || !currentUser.self) { + chatNotificationsPopupWrapper = new ChatNotificationsPopupWrapper(context, currentAccount, headerItem.getPopupLayout().getSwipeBack(), false, false, new ChatNotificationsPopupWrapper.Callback() { + @Override + public void dismiss() { + headerItem.toggleSubMenu(); + } + + @Override + public void toggleSound() { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + boolean enabled = !preferences.getBoolean("sound_enabled_" + dialog_id, true); + preferences.edit().putBoolean("sound_enabled_" + dialog_id, enabled).apply(); + if (BulletinFactory.canShowBulletin(ChatActivity.this)) { + BulletinFactory.createSoundEnabledBulletin(ChatActivity.this, enabled ? NotificationsController.SETTING_SOUND_ON : NotificationsController.SETTING_SOUND_OFF, getResourceProvider()).show(); + } + updateTitleIcons(); + } + + @Override + public void muteFor(int timeInSeconds) { + getNotificationsController().muteUntil(dialog_id, timeInSeconds); + if (BulletinFactory.canShowBulletin(ChatActivity.this)) { + BulletinFactory.createMuteBulletin(ChatActivity.this, NotificationsController.SETTING_MUTE_CUSTOM, timeInSeconds, getResourceProvider()).show(); + } + } + + @Override + public void showCustomize() { + if (dialog_id != 0) { + if (currentUser != null) { + getMessagesController().putUser(currentUser, true); + } + Bundle args = new Bundle(); + args.putLong("dialog_id", dialog_id); + presentFragment(new ProfileNotificationsActivity(args)); + } + } + + @Override + public void toggleMute() { + ChatActivity.this.toggleMute(true); + BulletinFactory.createMuteBulletin(ChatActivity.this, getMessagesController().isDialogMuted(dialog_id), themeDelegate).show(); + } + }, getResourceProvider()); + muteItem = headerItem.addSwipeBackItem(R.drawable.msg_mute, null, null, chatNotificationsPopupWrapper.windowLayout); + muteItem.setOnClickListener(view -> { + boolean muted = MessagesController.getInstance(currentAccount).isDialogMuted(dialog_id); + if (muted) { + AndroidUtilities.runOnUIThread(() -> { + ChatActivity.this.toggleMute(true); + }, 150); + headerItem.toggleSubMenu(); + BulletinFactory.createMuteBulletin(ChatActivity.this, false, themeDelegate).show(); + } else { + muteItem.openSwipeBack(); + } + }); + muteItemGap = headerItem.addColoredGap(); + } if (currentUser != null) { headerItem.addSubItem(call, R.drawable.msg_callback, LocaleController.getString("Call", R.string.Call), themeDelegate); if (Build.VERSION.SDK_INT >= 18) { @@ -2768,17 +2862,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentEncryptedChat != null) { timeItem2 = headerItem.addSubItem(chat_enc_timer, R.drawable.msg_timer, LocaleController.getString("SetTimer", R.string.SetTimer), themeDelegate); } - if (!ChatObject.isChannel(currentChat) || currentChat.megagroup && TextUtils.isEmpty(currentChat.username)) { - headerItem.addSubItem(clear_history, R.drawable.msg_clear, LocaleController.getString("ClearHistory", R.string.ClearHistory), themeDelegate); - } else if (ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_DELETE_MESSAGES)) { - headerItem.addSubItem(auto_delete_timer, R.drawable.msg_timer, LocaleController.getString("AutoDeleteSetTimer", R.string.AutoDeleteSetTimer), themeDelegate); - } + + clearHistoryItem = headerItem.addSubItem(clear_history, R.drawable.msg_clear, LocaleController.getString("ClearHistory", R.string.ClearHistory), themeDelegate); + if (themeDelegate.isThemeChangeAvailable()) { headerItem.addSubItem(change_colors, R.drawable.msg_colors, LocaleController.getString("ChangeColors", R.string.ChangeColors), themeDelegate); } - if (currentUser == null || !currentUser.self) { - muteItem = headerItem.addSubItem(mute, R.drawable.msg_mute, null, themeDelegate); - } if (ChatObject.isChannel(currentChat) && !currentChat.creator) { if (!ChatObject.isNotInChat(currentChat)) { if (currentChat.megagroup) { @@ -2926,7 +3015,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not protected void onTransitionStart(boolean keyboardVisible, int contentHeight) { wasManualScroll = true; if (chatActivityEnterView != null) { - chatActivityEnterView.onAdjustPanTransitionStart(keyboardVisible); + chatActivityEnterView.onAdjustPanTransitionStart(keyboardVisible, contentHeight); } } @@ -2960,6 +3049,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatListView.invalidate(); updateBulletinLayout(); + if (chatActivityEnterView != null) { + chatActivityEnterView.onAdjustPanTransitionUpdate(y, progress, keyboardVisible); + } } @Override @@ -3078,7 +3170,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if ((scrimView != null || messageEnterTransitionContainer.isRunning()) && (child == pagedownButton || child == mentiondownButton || child == floatingDateView || child == fireworksOverlay || child == reactionsMentiondownButton || child == gifHintTextView)) { + if ((scrimView != null || messageEnterTransitionContainer.isRunning()) && (child == pagedownButton || child == mentiondownButton || child == floatingDateView || child == fireworksOverlay || child == reactionsMentiondownButton || child == gifHintTextView || child == undoView || child == topUndoView)) { return false; } if (child == fragmentContextView && fragmentContextView.isCallStyle()) { @@ -3473,6 +3565,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (gifHintTextView != null) { super.drawChild(canvas, gifHintTextView, SystemClock.uptimeMillis()); } + if (undoView != null && undoView.getVisibility() == View.VISIBLE) { + super.drawChild(canvas, undoView, SystemClock.uptimeMillis()); + } + if (topUndoView != null && undoView.getVisibility() == View.VISIBLE) { + super.drawChild(canvas, topUndoView, SystemClock.uptimeMillis()); + } } if (fixedKeyboardHeight > 0 && keyboardHeight < AndroidUtilities.dp(20)) { @@ -4528,7 +4626,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not View child = getChildAt(a); if (chatAdapter.isBot && child instanceof BotHelpCell) { BotHelpCell botCell = (BotHelpCell) child; - float top = getMeasuredHeight() / 2 - child.getMeasuredHeight() / 2 + chatListViewPaddingTop; + float top = (getMeasuredHeight() - chatListViewPaddingTop - blurredViewBottomOffset) / 2 - child.getMeasuredHeight() / 2 + chatListViewPaddingTop; if (!botCell.animating() && !chatListView.fastScrollAnimationRunning) { if (child.getTop() > top) { child.setTranslationY(top - child.getTop()); @@ -4943,11 +5041,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not r - AndroidUtilities.dp(8), b - AndroidUtilities.dp(8) ); } - canvas.translate(canvasOffsetX, canvasOffsetY); - cell.setInvalidatesParent(true); - cell.drawCaptionLayout(canvas, selectionOnly, alpha); - cell.setInvalidatesParent(false); - canvas.restore(); + if (cell.getTransitionParams().wasDraw) { + canvas.translate(canvasOffsetX, canvasOffsetY); + cell.setInvalidatesParent(true); + cell.drawCaptionLayout(canvas, selectionOnly, alpha); + cell.setInvalidatesParent(false); + canvas.restore(); + } } drawCaptionAfter.clear(); } @@ -5012,7 +5112,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ); } canvas.translate(canvasOffsetX, canvasOffsetY); - if (position == null || (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { + if (chatMessageCell.getTransitionParams().wasDraw && (position == null || (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0)) { boolean selectionOnly = position != null && (position.flags & MessageObject.POSITION_FLAG_LEFT) == 0; chatMessageCell.setInvalidatesParent(true); chatMessageCell.drawCaptionLayout(canvas, selectionOnly, alpha); @@ -5947,19 +6047,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageView.addView(pinnedCounterTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 18, Gravity.TOP | Gravity.LEFT, 18, 7, 44, 0)); for (int a = 0; a < 2; a++) { - pinnedNameTextView[a] = new SimpleTextView(context) { - @Override - protected boolean createLayout(int width) { - boolean result = super.createLayout(width); - if (this == pinnedNameTextView[0] && pinnedCounterTextView != null) { - int newX = getTextWidth() + AndroidUtilities.dp(4); - if (newX != pinnedCounterTextViewX) { - pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX = newX); - } - } - return result; - } - }; + pinnedNameTextView[a] = new TrackingWidthSimpleTextView(context); pinnedNameTextView[a].setTextSize(14); pinnedNameTextView[a].setTextColor(getThemedColor(Theme.key_chat_topPanelTitle)); pinnedNameTextView[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -5982,12 +6070,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[a].setTextColor(getThemedColor(Theme.key_chat_topPanelMessage)); pinnedMessageView.addView(pinnedMessageTextView[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 18, Gravity.TOP | Gravity.LEFT, 18, 25.3f, 44, 0)); + pinnedMessageButton[a] = new PinnedMessageButton(context); + pinnedMessageView.addView(pinnedMessageButton[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 28, Gravity.TOP | Gravity.RIGHT, 0, 10, 14, 0)); + pinnedMessageImageView[a] = new BackupImageView(context); pinnedMessageImageView[a].setRoundRadius(AndroidUtilities.dp(2)); pinnedMessageView.addView(pinnedMessageImageView[a], LayoutHelper.createFrame(32, 32, Gravity.TOP | Gravity.LEFT, 17, 8, 0, 0)); if (a == 1) { - pinnedMessageTextView[a].setVisibility(View.INVISIBLE); pinnedNameTextView[a].setVisibility(View.INVISIBLE); + pinnedMessageButton[a].setVisibility(View.INVISIBLE); + pinnedMessageTextView[a].setVisibility(View.INVISIBLE); pinnedMessageImageView[a].setVisibility(View.INVISIBLE); } } @@ -6123,7 +6215,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not reportSpamButton = new TextView(context); reportSpamButton.setTextColor(getThemedColor(Theme.key_chat_reportSpam)); if (Build.VERSION.SDK_INT >= 21) { - reportSpamButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_reportSpam) & 0x19ffffff, 2)); + reportSpamButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_reportSpam) & 0x19ffffff, 3)); } reportSpamButton.setTag(Theme.key_chat_reportSpam); reportSpamButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); @@ -6150,7 +6242,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not addToContactsButton.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); addToContactsButton.setGravity(Gravity.CENTER); if (Build.VERSION.SDK_INT >= 21) { - addToContactsButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_addContact) & 0x19ffffff, 2)); + addToContactsButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_addContact) & 0x19ffffff, 3)); } topChatPanelView.addView(addToContactsButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 1)); addToContactsButton.setOnClickListener(v -> { @@ -6348,7 +6440,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; }); - mentionContainer = new FrameLayout(context) { private Rect padding; @@ -6398,6 +6489,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionContainer.setVisibility(View.GONE); updateMessageListAccessibilityVisibility(); mentionContainer.setWillNotDraw(false); + + reactionsMentiondownButton = new FrameLayout(context); + contentView.addView(reactionsMentiondownButton, LayoutHelper.createFrame(46, 61, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 7, 5)); + contentView.addView(mentionContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 110, Gravity.LEFT | Gravity.BOTTOM)); final ContentPreviewViewer.ContentPreviewViewerDelegate contentPreviewViewerDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { @@ -7036,7 +7131,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentiondownButton.addView(mentiondownButtonCounter, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 23, Gravity.TOP | Gravity.CENTER_HORIZONTAL)); mentiondownButton.setContentDescription(LocaleController.getString("AccDescrMentionDown", R.string.AccDescrMentionDown)); - reactionsMentiondownButton = new FrameLayout(context); reactionsMentiondownButton.setOnClickListener(view -> { wasManualScroll = true; getMessagesController().getNextReactionMention(dialog_id, reactionsMentionCount, (messageId) -> { @@ -7077,7 +7171,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return false; }); reactionsMentiondownButton.setVisibility(View.INVISIBLE); - contentView.addView(reactionsMentiondownButton, LayoutHelper.createFrame(46, 61, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 7, 5)); reactionsMentiondownButtonImage = new ImageView(context); reactionsMentiondownButtonImage.setImageResource(R.drawable.reactionbutton); reactionsMentiondownButtonImage.setScaleType(ImageView.ScaleType.CENTER); @@ -7721,6 +7814,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatActivityEnterView.setId(id_chat_compose_panel); chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, false); + chatActivityEnterView.updateBotWebView(false); chatActivityEnterView.setMinimumHeight(AndroidUtilities.dp(51)); chatActivityEnterView.setAllowStickersAndGifs(true, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); if (inPreviewMode) { @@ -8201,7 +8295,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not toggleMute(true); } } else { - AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, false, currentChat, currentUser, currentEncryptedChat != null, true, (param) -> { + boolean canDeleteHistory = chatInfo != null && chatInfo.can_delete_channel; + AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, false, currentChat, currentUser, currentEncryptedChat != null, true, canDeleteHistory, (param) -> { getNotificationCenter().removeObserver(ChatActivity.this, NotificationCenter.closeChats); getNotificationCenter().postNotificationName(NotificationCenter.closeChats); finishFragment(); @@ -8485,6 +8580,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return fragmentView; } + public ActionBarMenuItem getHeaderItem() { + return headerItem; + } + private void playReactionAnimation(Integer messageId) { if (fragmentView == null) { return; @@ -8510,7 +8609,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dimBehindView(value, view != reactionsMentiondownButton && view != mentiondownButton); } - private void dimBehindView(boolean enable) { + public void dimBehindView(boolean enable) { dimBehindView(enable ? 0.2f : 0, true); } @@ -8577,6 +8676,31 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not scrimAnimatorSet.start(); } + private class PinnedMessageButton extends TextView { + public PinnedMessageButton(Context context) { + super(context); + + setSingleLine(true); + setLines(1); + setMaxLines(1); + setEllipsize(TextUtils.TruncateAt.END); + setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText)); + setBackground(Theme.getRoundRectSelectorWithBackgroundDrawable(AndroidUtilities.dp(16), getThemedColor(Theme.key_featuredStickers_addButton), 0x60ffffff)); + setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + setGravity(Gravity.CENTER); + setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + View.MeasureSpec.makeMeasureSpec(Math.min(View.MeasureSpec.getSize(widthMeasureSpec), (int) (AndroidUtilities.displaySize.x * 0.35f)), View.MeasureSpec.AT_MOST), + heightMeasureSpec + ); + } + }; + private void updatePagedownButtonsPosition() { float baseTranslationY = chatActivityEnterView.getAnimatedTop() + chatActivityEnterView.getTranslationY() + (chatActivityEnterTopView.getVisibility() == View.VISIBLE ? chatActivityEnterTopView.getTranslationY() : 0); if (pagedownButton != null) { @@ -8591,7 +8715,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateReactionsMentionButton(boolean animated) { - boolean visible = reactionsMentionCount > 0; + if (reactionsMentiondownButtonCounter == null || getParentActivity() == null) { + return; + } + boolean visible = reactionsMentionCount > 0 && chatMode == 0; reactionsMentiondownButtonCounter.setCount(reactionsMentionCount, animated); if (visible && reactionsMentiondownButton.getTag() == null) { reactionsMentiondownButton.setTag(1); @@ -8714,6 +8841,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.getSendButton().callOnClick(); } }; + TLRPC.Peer defPeer = chatInfo != null ? chatInfo.default_send_as : null; + if (defPeer == null && sendAsPeersObj != null && !sendAsPeersObj.peers.isEmpty()) { + defPeer = sendAsPeersObj.peers.get(0); + } + forwardingPreviewView.setSendAsPeer(defPeer); checkShowBlur(true); contentView.addView(forwardingPreviewView); @@ -9786,7 +9918,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatAttachAlert = new ChatAttachAlert(getParentActivity(), this, false, false, themeDelegate) { @Override public void dismissInternal() { - if (chatAttachAlert.isShowing()) { + if (chatAttachAlert != null && chatAttachAlert.isShowing()) { AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); } super.dismissInternal(); @@ -9862,7 +9994,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void didSelectBot(TLRPC.User user) { - if (chatActivityEnterView == null || TextUtils.isEmpty(user.username)) { + if (chatActivityEnterView == null || user == null || TextUtils.isEmpty(user.username)) { return; } chatActivityEnterView.setFieldText("@" + user.username + " "); @@ -9912,7 +10044,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getInstance(currentAccount).doOnIdle(runnable); } - public void performHistoryClear(boolean revoke) { + public void performHistoryClear(boolean revoke, boolean canDeleteHistory) { clearingHistory = true; undoView.showWithAction(dialog_id, UndoView.ACTION_CLEAR, () -> { if (!pinnedMessageIds.isEmpty()) { @@ -11436,8 +11568,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not CharSequence sourceText = null; if (!TextUtils.isEmpty(restrictionReason)) { replyObjectText = restrictionReason; + sourceText = restrictionReason; } else if (messageObjectToReply.messageOwner.media instanceof TLRPC.TL_messageMediaGame) { replyObjectText = Emoji.replaceEmoji(messageObjectToReply.messageOwner.media.game.title, replyObjectTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); + sourceText = messageObjectToReply.messageOwner.media.game.title; } else if (messageObjectToReply.messageText != null || messageObjectToReply.caption != null) { String mess = messageObjectToReply.caption != null ? messageObjectToReply.caption.toString() : messageObjectToReply.messageText.toString(); sourceText = mess; @@ -11448,8 +11582,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyObjectText = Emoji.replaceEmoji(mess, replyObjectTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); } if (replyObjectText != null) { - if (replyObjectText instanceof Spannable) + if (replyObjectText instanceof Spannable && sourceText != null) { MediaDataController.addTextStyleRuns(messageObjectToReply.messageOwner.entities, sourceText, (Spannable) replyObjectText); + } replyObjectTextView.setText(replyObjectText); } @@ -12472,36 +12607,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean muted = getMessagesController().isDialogMuted(dialog_id); if (!muted) { if (instant) { - long flags; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("notify2_" + dialog_id, 2); - flags = 1; - getMessagesStorage().setDialogFlags(dialog_id, flags); - editor.commit(); - TLRPC.Dialog dialog = getMessagesController().dialogs_dict.get(dialog_id); - if (dialog != null) { - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - dialog.notify_settings.mute_until = Integer.MAX_VALUE; - } - getNotificationsController().updateServerNotificationsSettings(dialog_id); - getNotificationsController().removeNotificationsForDialog(dialog_id); + getNotificationsController().muteDialog(dialog_id, true); } else { BottomSheet alert = AlertsCreator.createMuteAlert(this, dialog_id, themeDelegate); alert.setCalcMandatoryInsets(isKeyboardVisible()); showDialog(alert); } } else { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("notify2_" + dialog_id, 0); - getMessagesStorage().setDialogFlags(dialog_id, 0); - editor.commit(); - TLRPC.Dialog dialog = getMessagesController().dialogs_dict.get(dialog_id); - if (dialog != null) { - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - } - getNotificationsController().updateServerNotificationsSettings(dialog_id); + getNotificationsController().muteDialog(dialog_id, false); if (!instant) { BulletinFactory.createMuteBulletin(this, false, themeDelegate).show(); } @@ -12553,7 +12666,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean nextScrollForce; private int nextScrollForcePinnedMessageId; - private boolean pinnedPorgressIsShowing; + private boolean pinnedProgressIsShowing; Runnable updatePinnedProgressRunnable; public void scrollToMessageId(int id, int fromMessageId, boolean select, int loadIndex, boolean forceScroll, int forcePinnedMessageId) { @@ -12738,7 +12851,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (show) { if (updatePinnedProgressRunnable == null) { updatePinnedProgressRunnable = () -> { - pinnedPorgressIsShowing = true; + pinnedProgressIsShowing = true; updatePinnedListButton(true); }; AndroidUtilities.runOnUIThread(updatePinnedProgressRunnable, 100); @@ -12748,7 +12861,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.cancelRunOnUIThread(updatePinnedProgressRunnable); } updatePinnedProgressRunnable = null; - pinnedPorgressIsShowing = false; + pinnedProgressIsShowing = false; updatePinnedListButton(true); } } @@ -13036,13 +13149,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (avatarContainer != null) { if (currentEncryptedChat != null) { - avatarContainer.setTime(currentEncryptedChat.ttl); + avatarContainer.setTime(currentEncryptedChat.ttl, animated); } else if (userInfo != null) { - avatarContainer.setTime(userInfo.ttl_period); + avatarContainer.setTime(userInfo.ttl_period, animated); } else if (chatInfo != null) { - avatarContainer.setTime(chatInfo.ttl_period); + avatarContainer.setTime(chatInfo.ttl_period, animated); } } + if (clearHistoryItem != null && chatInfo != null) { + boolean visible = chatInfo.can_delete_channel || !ChatObject.isChannel(currentChat) || currentChat.megagroup && TextUtils.isEmpty(currentChat.username); + clearHistoryItem.setVisibility(visible ? View.VISIBLE : View.GONE); + } checkAndUpdateAvatar(); } @@ -13657,15 +13774,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (avatarContainer == null || chatMode != 0) { return; } - Drawable rightIcon = getMessagesController().isDialogMuted(dialog_id) ? getThemedDrawable(Theme.key_drawable_muteIconDrawable) : null; + boolean isMuted = getMessagesController().isDialogMuted(dialog_id); + Drawable rightIcon = isMuted ? getThemedDrawable(Theme.key_drawable_muteIconDrawable) : null; avatarContainer.setTitleIcons(currentEncryptedChat != null ? getThemedDrawable(Theme.key_drawable_lockIconDrawable) : null, !UserObject.isReplyUser(currentUser) && !isThreadChat() ? rightIcon : null); if (muteItem != null) { - if (rightIcon != null) { - muteItem.setTextAndIcon(LocaleController.getString("UnmuteNotifications", R.string.UnmuteNotifications), R.drawable.msg_unmute); + if (isMuted) { + muteItem.getRightIcon().setVisibility(View.GONE); + muteItem.setTextAndIcon(LocaleController.getString("Unmute", R.string.Unmute), R.drawable.msg_mute); } else { - muteItem.setTextAndIcon(LocaleController.getString("MuteNotifications", R.string.MuteNotifications), R.drawable.msg_mute); + muteItem.getRightIcon().setVisibility(View.VISIBLE); + if (getMessagesController().isDialogNotificationsSoundEnabled(dialog_id)) { + muteItem.setTextAndIcon(LocaleController.getString("Mute", R.string.Mute), R.drawable.msg_unmute); + } else { + muteItem.setTextAndIcon(LocaleController.getString("Mute", R.string.Mute), R.drawable.msg_silent); + } } } + if (chatNotificationsPopupWrapper != null) { + chatNotificationsPopupWrapper.update(dialog_id); + } } private void checkAndUpdateAvatar() { @@ -14390,7 +14517,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not endReached[0] = cacheEndReached[0] = true; forwardEndReached[0] = forwardEndReached[0] = true; } - if (ChatObject.isChannel(currentChat) && !getMessagesController().dialogs_dict.containsKey(dialog_id) && load_type == 2 && isCache && loadIndex == 0) { + if (ChatObject.isChannel(currentChat) && !getMessagesController().dialogs_dict.containsKey(dialog_id) && load_type == 2 && loadIndex == 0) { forwardEndReached[0] = false; hideForwardEndReached = true; } @@ -15823,9 +15950,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); if (reason == 0) { if (currentChat.has_link) { - builder.setMessage(LocaleController.getString("ChannelCantOpenBannedByAdmin", R.string.ChannelCantOpenBannedByAdmin)); - } else { builder.setMessage(LocaleController.getString("ChannelCantOpenPrivate", R.string.ChannelCantOpenPrivate)); + } else { + builder.setMessage(LocaleController.getString("ChannelCantOpenBannedByAdmin", R.string.ChannelCantOpenBannedByAdmin)); } } else if (reason == 1) { builder.setMessage(LocaleController.getString("ChannelCantOpenNa", R.string.ChannelCantOpenNa)); @@ -16504,6 +16631,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (chatActivityEnterView != null) { chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, true); + hasBotWebView = getMessagesController().getUser(info.user_id).bot_menu_webview; + chatActivityEnterView.updateBotWebView(true); } } updateBotButtons(); @@ -16761,7 +16890,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - checkActionBarMenu(false); + checkActionBarMenu(fragmentOpened); if (!inMenuMode && !loadingPinnedMessagesList && !pinnedMessageIds.isEmpty() && userInfo.pinned_msg_id > pinnedMessageIds.get(0)) { getMediaDataController().loadPinnedMessages(dialog_id, 0, userInfo.pinned_msg_id); loadingPinnedMessagesList = true; @@ -17101,16 +17230,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (BuildVars.LOGS_ENABLED) { FileLog.d("clear history by overwrite firstLoading=" + firstLoading + " minMessage=" + minMessageId[0] + " topMessage=" + differenceTooLong.dialog.top_message); } - if (firstLoading) { - waitingForLoad.clear(); - chatWasReset = true; - last_message_id = differenceTooLong.dialog.top_message; - createUnreadMessageAfterId = 0; - } else { - if (differenceTooLong.dialog.top_message > minMessageId[0]) { - createUnreadMessageAfterId = Math.max(minMessageId[0] + 1, differenceTooLong.dialog.read_inbox_max_id); - } + + if (differenceTooLong.dialog.top_message > minMessageId[0]) { + createUnreadMessageAfterId = Math.max(minMessageId[0] + 1, differenceTooLong.dialog.read_inbox_max_id); } + forwardEndReached[0] = false; hideForwardEndReached = false; if (chatAdapter != null && chatAdapter.loadingDownRow < 0) { @@ -17457,7 +17581,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } TLRPC.MessageAction action = obj.messageOwner.action; if (avatarContainer != null && currentEncryptedChat != null && action instanceof TLRPC.TL_messageEncryptedAction && action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { - avatarContainer.setTime(action.encryptedAction.ttl_seconds); + avatarContainer.setTime(action.encryptedAction.ttl_seconds, true); } if (action instanceof TLRPC.TL_messageActionChatMigrateTo) { migrateToNewChat(obj); @@ -17578,7 +17702,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } TLRPC.MessageAction action = obj.messageOwner.action; if (avatarContainer != null && currentEncryptedChat != null && action instanceof TLRPC.TL_messageEncryptedAction && action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { - avatarContainer.setTime(action.encryptedAction.ttl_seconds); + avatarContainer.setTime(action.encryptedAction.ttl_seconds, true); } if (obj.type < 0 || messagesDict[0].indexOfKey(messageId) >= 0) { continue; @@ -18656,6 +18780,66 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().onAnimationFinish(transitionAnimationIndex); } contentView.invalidate(); + + if (!TextUtils.isEmpty(attachMenuBotToOpen)) { + if (getCurrentUser() != null) { + TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); + req.username = attachMenuBotToOpen; + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(()->{ + if (response != null) { + TLRPC.TL_contacts_resolvedPeer resolvedPeer = (TLRPC.TL_contacts_resolvedPeer) response; + if (!resolvedPeer.users.isEmpty()) { + TLRPC.User user = resolvedPeer.users.get(0); + if (user.bot && user.bot_attach_menu) { + TLRPC.TL_messages_getAttachMenuBot getAttachMenuBot = new TLRPC.TL_messages_getAttachMenuBot(); + getAttachMenuBot.bot = MessagesController.getInstance(currentAccount).getInputUser(user.id); + ConnectionsManager.getInstance(currentAccount).sendRequest(getAttachMenuBot, (response1, error1) -> AndroidUtilities.runOnUIThread(()-> { + if (response1 instanceof TLRPC.TL_attachMenuBotsBot) { + TLRPC.TL_attachMenuBotsBot attachMenuBotsBot = (TLRPC.TL_attachMenuBotsBot) response1; + MessagesController.getInstance(currentAccount).putUsers(attachMenuBotsBot.users, false); + TLRPC.TL_attachMenuBot attachMenuBot = attachMenuBotsBot.bot; + + if (!attachMenuBot.inactive) { + openAttachBotLayout(user.id, attachMenuBotStartCommand); + } else { + AttachBotIntroTopView introTopView = new AttachBotIntroTopView(getParentActivity()); + introTopView.setColor(Theme.getColor(Theme.key_chat_attachContactIcon)); + introTopView.setBackgroundColor(Theme.getColor(Theme.key_dialogTopBackground)); + introTopView.setAttachBot(attachMenuBot); + new AlertDialog.Builder(getParentActivity()) + .setTopView(introTopView) + .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("BotRequestAttachPermission", R.string.BotRequestAttachPermission, UserObject.getUserName(user)))) + .setPositiveButton(LocaleController.getString(R.string.BotAddToMenu), (dialog, which) -> { + TLRPC.TL_messages_toggleBotInAttachMenu botRequest = new TLRPC.TL_messages_toggleBotInAttachMenu(); + botRequest.bot = MessagesController.getInstance(currentAccount).getInputUser(user.id); + botRequest.enabled = true; + ConnectionsManager.getInstance(currentAccount).sendRequest(botRequest, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + MediaDataController.getInstance(currentAccount).loadAttachMenuBots(false, true); + + openAttachBotLayout(user.id, attachMenuBotStartCommand); + } + }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + } + } + })); + } + } + } + })); + } else { + BulletinFactory.of(this).createErrorBulletin(LocaleController.getString(ChatObject.isChannelAndNotMegaGroup(currentChat) ? R.string.BotCantOpenAttachMenuChannel : R.string.BotCantOpenAttachMenuGroup)).show(); + } + attachMenuBotToOpen = null; + } + } + + public void openAttachBotLayout(long botId, String startCommand) { + openAttachMenu(); + chatAttachAlert.showBotLayout(botId, startCommand); } @Override @@ -18860,8 +19044,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (muteItem != null) { if (currentChat != null && ChatObject.isNotInChat(currentChat)) { muteItem.setVisibility(View.GONE); + muteItemGap.setVisibility(View.GONE); } else { muteItem.setVisibility(View.VISIBLE); + muteItemGap.setVisibility(View.VISIBLE); } } if (reportType >= 0) { @@ -19094,25 +19280,28 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (isThreadChat() || pinnedListButton == null || inMenuMode) { return; } - boolean show = pinnedMessageIds.size() > 1; + boolean show = pinnedMessageIds.size() > 1 && !pinnedMessageButtonShown; boolean visible = pinnedListButton.getTag() != null; boolean progressIsVisible = pinnedProgress.getTag() != null; + boolean closeIsVisible = closePinned.getTag() != null; - if (show != visible || progressIsVisible != pinnedPorgressIsShowing) { + boolean showClosed = !show && !pinnedProgressIsShowing && !pinnedMessageButtonShown; + boolean showPinned = show && !pinnedProgressIsShowing && !pinnedMessageButtonShown; + boolean showProgress = pinnedProgressIsShowing && !pinnedMessageButtonShown; + + if (visible != show || progressIsVisible != showProgress || closeIsVisible != showClosed) { if (pinnedListAnimator != null) { pinnedListAnimator.cancel(); pinnedListAnimator = null; } - boolean showClosed = !show && !pinnedPorgressIsShowing; - boolean showPinned = show && !pinnedPorgressIsShowing; if (animated) { if (show) { pinnedListButton.setVisibility(View.VISIBLE); - } else { + } else if (showClosed) { closePinned.setVisibility(View.VISIBLE); } - if (pinnedPorgressIsShowing) { + if (showProgress) { pinnedProgress.setVisibility(View.VISIBLE); pinnedProgress.setAlpha(0); pinnedProgress.setScaleX(0.4f); @@ -19127,9 +19316,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ObjectAnimator.ofFloat(closePinned, View.ALPHA, showClosed ? 1.0f : 0.0f), ObjectAnimator.ofFloat(closePinned, View.SCALE_X, showClosed ? 1.0f : 0.4f), ObjectAnimator.ofFloat(closePinned, View.SCALE_Y, showClosed ? 1.0f : 0.4f), - ObjectAnimator.ofFloat(pinnedProgress, View.ALPHA, !pinnedPorgressIsShowing ? 0.0f : 1.0f), - ObjectAnimator.ofFloat(pinnedProgress, View.SCALE_X, !pinnedPorgressIsShowing ? 0.4f : 1.0f), - ObjectAnimator.ofFloat(pinnedProgress, View.SCALE_Y, !pinnedPorgressIsShowing ? 0.4f : 1.0f) + ObjectAnimator.ofFloat(pinnedProgress, View.ALPHA, !showProgress ? 0.0f : 1.0f), + ObjectAnimator.ofFloat(pinnedProgress, View.SCALE_X, !showProgress ? 0.4f : 1.0f), + ObjectAnimator.ofFloat(pinnedProgress, View.SCALE_Y, !showProgress ? 0.4f : 1.0f) ); pinnedListAnimator.setDuration(180); @@ -19140,7 +19329,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not closePinned.setVisibility(showClosed ? View.VISIBLE : View.INVISIBLE); pinnedListButton.setVisibility(showPinned ? View.VISIBLE : View.INVISIBLE); - pinnedProgress.setVisibility(pinnedPorgressIsShowing ? View.VISIBLE : View.INVISIBLE); + pinnedProgress.setVisibility(showProgress ? View.VISIBLE : View.INVISIBLE); } }); pinnedListAnimator.start(); @@ -19153,14 +19342,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedListButton.setScaleX(showPinned ? 1.0f : 0.4f); pinnedListButton.setScaleY(showPinned ? 1.0f : 0.4f); pinnedListButton.setVisibility(showPinned ? View.VISIBLE : View.INVISIBLE); - - pinnedProgress.setAlpha(pinnedPorgressIsShowing ? 1.0f : 0.0f); - pinnedProgress.setScaleX(pinnedPorgressIsShowing ? 1.0f : 0.4f); - pinnedProgress.setScaleY(pinnedPorgressIsShowing ? 1.0f : 0.4f); - pinnedProgress.setVisibility(pinnedPorgressIsShowing ? View.VISIBLE : View.GONE); + pinnedProgress.setAlpha(showProgress ? 1.0f : 0.0f); + pinnedProgress.setScaleX(showProgress ? 1.0f : 0.4f); + pinnedProgress.setScaleY(showProgress ? 1.0f : 0.4f); + pinnedProgress.setVisibility(showProgress ? View.VISIBLE : View.GONE); } + closePinned.setTag(showClosed ? 1 : null); pinnedListButton.setTag(show ? 1 : null); - pinnedProgress.setTag(pinnedPorgressIsShowing ? 1 : null); + pinnedProgress.setTag(showProgress ? 1 : null); } if (pinnedLineView != null) { if (isThreadChat()) { @@ -19172,6 +19361,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private TLRPC.KeyboardButton pinnedButton(MessageObject message) { + return (message != null && message.messageOwner != null && message.messageOwner.reply_markup != null && + message.messageOwner.reply_markup.rows != null && message.messageOwner.reply_markup.rows.size() == 1 && + message.messageOwner.reply_markup.rows.get(0) != null && message.messageOwner.reply_markup.rows.get(0).buttons != null && + message.messageOwner.reply_markup.rows.get(0).buttons.size() == 1 ? + message.messageOwner.reply_markup.rows.get(0).buttons.get(0) : + null + ); + } + private void updatePinnedMessageView(boolean animated, int animateToNext) { if (pinnedMessageView == null || chatMode != 0 || inMenuMode) { return; @@ -19197,6 +19396,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageObject = null; pinned_msg_id = 0; } + TLRPC.KeyboardButton botButton = pinnedButton(pinnedMessageObject); + pinnedMessageButtonShown = botButton != null; SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); if (threadMessageObject == null && (chatInfo == null && userInfo == null || pinned_msg_id == 0 || !pinnedMessageIds.isEmpty() && pinnedMessageIds.get(0) == preferences.getInt("pin_" + dialog_id, 0)) || reportType >= 0 || actionBar != null && (actionBar.isActionModeShowed() || actionBar.isSearchFieldVisible())) { changed = hidePinnedMessageView(animated); @@ -19254,9 +19455,45 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedNextAnimation[a] = null; } } + setPinnedTextTranslationX = false; - SimpleTextView nameTextView = pinnedNameTextView[animateToNext != 0 && loadedPinnedMessagesCount == 2 ? 1 : 0]; + TrackingWidthSimpleTextView nameTextView = pinnedNameTextView[animateToNext != 0 ? 1 : 0]; SimpleTextView messageTextView = pinnedMessageTextView[animateToNext != 0 ? 1 : 0]; + PinnedMessageButton buttonTextView = pinnedMessageButton[animateToNext != 0 ? 1 : 0]; + + buttonTextView.setVisibility(botButton != null ? View.VISIBLE : View.GONE); + pinnedMessageButton[animateToNext != 0 ? 0 : 1].setOnClickListener(null); + if (botButton == null) { + buttonTextView.setText(null); + buttonTextView.setOnClickListener(null); + } else { + SpannableString string = new SpannableString(botButton.text); + Emoji.replaceEmoji(string, buttonTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); + buttonTextView.setText(string); + final MessageObject buttonMessage = pinnedMessageObject; + buttonTextView.setOnClickListener(e -> { + if (getParentActivity() == null || bottomOverlayChat.getVisibility() == View.VISIBLE && + !(botButton instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(botButton instanceof TLRPC.TL_keyboardButtonCallback) && + !(botButton instanceof TLRPC.TL_keyboardButtonGame) && !(botButton instanceof TLRPC.TL_keyboardButtonUrl) && + !(botButton instanceof TLRPC.TL_keyboardButtonBuy) && !(botButton instanceof TLRPC.TL_keyboardButtonUrlAuth) && + !(botButton instanceof TLRPC.TL_keyboardButtonUserProfile)) { + return; + } + chatActivityEnterView.didPressedBotButton(botButton, buttonMessage, buttonMessage); + }); + } + buttonTextView.measure(View.MeasureSpec.makeMeasureSpec(999999, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(28), View.MeasureSpec.EXACTLY)); + if (messageTextView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { + ((ViewGroup.MarginLayoutParams) messageTextView.getLayoutParams()).rightMargin = ( + (botButton == null ? AndroidUtilities.dp(44) : buttonTextView.getMeasuredWidth() + AndroidUtilities.dp(14 + 8)) + ); + } + if (nameTextView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { + ((ViewGroup.MarginLayoutParams) nameTextView.getLayoutParams()).rightMargin = ( + (botButton == null ? AndroidUtilities.dp(44) : buttonTextView.getMeasuredWidth() + AndroidUtilities.dp(14 + 8)) + ); + } + FrameLayout.LayoutParams layoutParams1 = (FrameLayout.LayoutParams) pinnedNameTextView[0].getLayoutParams(); FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) pinnedNameTextView[1].getLayoutParams(); FrameLayout.LayoutParams layoutParams3 = (FrameLayout.LayoutParams) pinnedCounterTextView.getLayoutParams(); @@ -19318,6 +19555,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[0].setLayoutParams(layoutParams4); pinnedMessageTextView[1].setLayoutParams(layoutParams5); + boolean showCounter = false; + boolean shouldAnimateName = loadedPinnedMessagesCount == 2 || !pinnedNameTextView[animateToNext != 0 ? 0 : 1].getTrackWidth(); + nameTextView.setTrackWidth(true); if (threadMessageId != 0) { MessagesController messagesController = getMessagesController(); TLRPC.MessageFwdHeader fwd_from = threadMessageObject.messageOwner.fwd_from; @@ -19362,14 +19602,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not nameTextView.setText(chat.title); } } else { - if (currentPinnedMessageIndex[0] == 0 || loadedPinnedMessagesCount != 2) { - nameTextView.setText(LocaleController.getString("PinnedMessage", R.string.PinnedMessage)); + if (pinnedMessageObject.isInvoice() && + pinnedMessageObject.messageOwner != null && pinnedMessageObject.messageOwner.media != null && + pinnedMessageObject.messageOwner.media.title != null) { + nameTextView.setTrackWidth(false); + nameTextView.setText(pinnedMessageObject.messageOwner.media.title); + shouldAnimateName = true; + showCounter = false; } else { - nameTextView.setText(LocaleController.getString("PreviousPinnedMessage", R.string.PreviousPinnedMessage)); - } - if (currentPinnedMessageIndex[0] != 0) { - int total = getPinnedMessagesCount(); - pinnedCounterTextView.setNumber(Math.min(total - 1, Math.max(1, total - currentPinnedMessageIndex[0])), animated && pinnedCounterTextView.getTag() == null); + if (currentPinnedMessageIndex[0] == 0 || loadedPinnedMessagesCount != 2) { + nameTextView.setText(LocaleController.getString("PinnedMessage", R.string.PinnedMessage)); + } else { + nameTextView.setText(LocaleController.getString("PreviousPinnedMessage", R.string.PreviousPinnedMessage)); + } + if (currentPinnedMessageIndex[0] != 0) { + int total = getPinnedMessagesCount(); + pinnedCounterTextView.setNumber(Math.min(total - 1, Math.max(1, total - currentPinnedMessageIndex[0])), animated && pinnedCounterTextView.getTag() == null); + showCounter = true; + } } } CharSequence pinnedText = null; @@ -19401,9 +19651,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedText = Emoji.replaceEmoji(mess, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); } if (pinnedText != null) { - if (pinnedText instanceof Spannable) + if (pinnedText instanceof Spannable) { MediaDataController.addTextStyleRuns(pinnedMessageObject, (Spannable) pinnedText); - + } messageTextView.setText(pinnedText); } if (animateToNext != 0) { @@ -19413,8 +19663,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ArrayList animators2 = new ArrayList<>(); messageTextView.setVisibility(View.VISIBLE); nameTextView.setVisibility(View.VISIBLE); + if (botButton != null) { + buttonTextView.setVisibility(View.VISIBLE); + } - if (loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0) { + if (!showCounter) { if (pinnedCounterTextView.getTag() == null) { animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.ALPHA, 1.0f, 0.0f)); animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.TRANSLATION_Y, 0.0f, -AndroidUtilities.dp(4))); @@ -19430,13 +19683,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - if (loadedPinnedMessagesCount == 2 && !TextUtils.equals(nameTextView.getText(), pinnedNameTextView[0].getText())) { + boolean animateName; + if (shouldAnimateName && !TextUtils.equals(nameTextView.getText(), pinnedNameTextView[0].getText())) { nameTextView.setAlpha(0); animators.add(ObjectAnimator.ofFloat(nameTextView, View.ALPHA, 0.0f, 1.0f)); animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[0], View.ALPHA, 1.0f, 0.0f)); animators.add(ObjectAnimator.ofFloat(nameTextView, View.TRANSLATION_Y, AndroidUtilities.dp(animateToNext == 2 ? 4 : -4), 0.0f)); + if (animateName = forceScrollToFirst && loadedPinnedMessagesCount > 5) { + animators2.add(ObjectAnimator.ofFloat(nameTextView, View.TRANSLATION_Y, AndroidUtilities.dp(4), AndroidUtilities.dp(-2))); + } else { + animators.add(ObjectAnimator.ofFloat(nameTextView, View.TRANSLATION_Y, AndroidUtilities.dp(animateToNext == 2 ? 4 : -4), 0.0f)); + } animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[0], View.TRANSLATION_Y, 0.0f, AndroidUtilities.dp(animateToNext == 2 ? -4 : 4))); } else { + animateName = false; if (nameTextView != pinnedNameTextView[0]) { nameTextView.setAlpha(1.0f); pinnedNameTextView[0].setAlpha(0.0f); @@ -19469,6 +19729,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[0].setTranslationY(0.0f); } + boolean animateButton; + if (!TextUtils.equals(buttonTextView.getText(), pinnedMessageButton[0].getText())) { + buttonTextView.setAlpha(0); + animators.add(ObjectAnimator.ofFloat(buttonTextView, View.ALPHA, 0.0f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageButton[0], View.ALPHA, 1.0f, 0.0f)); + if (animateButton = forceScrollToFirst && loadedPinnedMessagesCount > 5) { + animators2.add(ObjectAnimator.ofFloat(buttonTextView, View.TRANSLATION_Y, AndroidUtilities.dp(4), AndroidUtilities.dp(-2))); + } else { + animators.add(ObjectAnimator.ofFloat(buttonTextView, View.TRANSLATION_Y, AndroidUtilities.dp(animateToNext == 2 ? 4 : -4), 0.0f)); + } + animators.add(ObjectAnimator.ofFloat(pinnedMessageButton[0], View.TRANSLATION_Y, 0.0f, AndroidUtilities.dp(animateToNext == 2 ? -4 : 4))); + } else { + animateButton = false; + buttonTextView.setAlpha(1.0f); + pinnedMessageButton[0].setAlpha(0.0f); + buttonTextView.setTranslationY(0.0f); + pinnedMessageButton[0].setTranslationY(0.0f); + } + BackupImageView animateImage; if (layoutParams1.leftMargin != prevMargin) { animateImage = null; @@ -19478,6 +19757,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not animators.add(ObjectAnimator.ofFloat(pinnedMessageTextView[1], View.TRANSLATION_X, diff, 0.0f)); animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[0], View.TRANSLATION_X, diff, 0.0f)); animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[1], View.TRANSLATION_X, diff, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageButton[0], View.TRANSLATION_X, diff, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageButton[1], View.TRANSLATION_X, diff, 0.0f)); animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.TRANSLATION_X, pinnedCounterTextViewX + diff, pinnedCounterTextViewX)); if (diff > 0) { pinnedMessageImageView[0].setAlpha(1f); @@ -19495,6 +19776,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[0].setTranslationX(0); nameTextView.setTranslationX(0); pinnedNameTextView[0].setTranslationX(0); + buttonTextView.setTranslationX(0); + pinnedMessageButton[0].setTranslationX(0); pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); pinnedMessageImageView[1].setAlpha(1.0f); if (!noImage) { @@ -19524,23 +19807,35 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onAnimationEnd(Animator animation) { if (animation.equals(pinnedNextAnimation[1])) { - if (animateText || animateImage != null) { + if (animateName || animateText || animateImage != null) { pinnedNextAnimation[1] = new AnimatorSet(); pinnedNextAnimation[1].setInterpolator(CubicBezierInterpolator.EASE_OUT); pinnedNextAnimation[1].setDuration(180); ArrayList animators1 = new ArrayList<>(); + if (animateName) { + animators1.add(ObjectAnimator.ofFloat(nameTextView, View.TRANSLATION_Y, 0.0f)); + } if (animateText) { animators1.add(ObjectAnimator.ofFloat(messageTextView, View.TRANSLATION_Y, 0.0f)); } + if (animateButton) { + animators1.add(ObjectAnimator.ofFloat(buttonTextView, View.TRANSLATION_Y, 0.0f)); + } if (animateImage != null) { animators1.add(ObjectAnimator.ofFloat(animateImage, View.TRANSLATION_Y, 0.0f)); } pinnedNextAnimation[1].addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { + if (animateName) { + nameTextView.setTranslationY(0.0f); + } if (animateText) { messageTextView.setTranslationY(0.0f); } + if (animateButton) { + buttonTextView.setTranslationY(0.0f); + } if (animateImage != null) { animateImage.setTranslationY(0.0f); } @@ -19577,10 +19872,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[0].setTranslationX(0); pinnedMessageTextView[1].setTranslationX(0); pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); + nameTextView.setTranslationY(0.0f); + if (!animateText) { + nameTextView.setTranslationY(0.0f); + } if (!animateText) { messageTextView.setTranslationY(0.0f); } - nameTextView.setTranslationY(0.0f); + if (!animateButton) { + buttonTextView.setTranslationY(0.0f); + } pinnedNameTextView[0].setTranslationX(0); pinnedNameTextView[1].setTranslationX(0); pinnedMessageImageView[1].setAlpha(1.0f); @@ -19592,6 +19893,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[1] = pinnedMessageTextView[0]; pinnedMessageTextView[0] = messageTextView; pinnedMessageTextView[1].setVisibility(View.INVISIBLE); + pinnedMessageButton[1] = pinnedMessageButton[0]; + pinnedMessageButton[0] = buttonTextView; + pinnedMessageButton[1].setVisibility(View.INVISIBLE); if (nameTextView != pinnedNameTextView[0]) { pinnedNameTextView[1] = pinnedNameTextView[0]; pinnedNameTextView[0] = nameTextView; @@ -19619,12 +19923,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedNextAnimation[1].start(); } } else { - if (loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0) { + if (!showCounter || currentPinnedMessageIndex[0] == 0) { if (pinnedCounterTextView.getTag() == null) { pinnedCounterTextView.setAlpha(0.0f); pinnedCounterTextView.setVisibility(View.INVISIBLE); pinnedCounterTextView.setTag(1); - } } else { if (pinnedCounterTextView.getTag() != null) { @@ -19636,7 +19939,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedCounterTextView.setTranslationY(0.0f); pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); - pinnedCounterTextView.setAlpha(loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); + pinnedCounterTextView.setAlpha(shouldAnimateName || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); messageTextView.setVisibility(View.VISIBLE); messageTextView.setAlpha(1.0f); @@ -19649,6 +19952,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[1].setVisibility(View.INVISIBLE); pinnedMessageTextView[1].setTranslationX(0); pinnedMessageTextView[1].setTranslationY(0); + pinnedMessageButton[1].setVisibility(View.INVISIBLE); + pinnedMessageButton[1].setTranslationX(0); + pinnedMessageButton[1].setTranslationY(0); pinnedNameTextView[1].setVisibility(View.INVISIBLE); pinnedNameTextView[1].setTranslationX(0); pinnedNameTextView[1].setTranslationY(0); @@ -19690,6 +19996,32 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private class TrackingWidthSimpleTextView extends SimpleTextView { + public TrackingWidthSimpleTextView(Context context) { + super(context); + } + + private boolean trackWidth = true; + public void setTrackWidth(boolean value) { + this.trackWidth = value; + } + public boolean getTrackWidth() { + return this.trackWidth; + } + + @Override + protected boolean createLayout(int width) { + boolean result = super.createLayout(width); + if (trackWidth && getVisibility() == View.VISIBLE && pinnedCounterTextView != null) { + int newX = getTextWidth() + AndroidUtilities.dp(4); + if (newX != pinnedCounterTextViewX) { + pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX = newX); + } + } + return result; + } + } + private void updateTopPanel(boolean animated) { if (topChatPanelView == null || chatMode != 0 || inMenuMode) { return; @@ -20607,13 +20939,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void createDeleteMessagesAlert(final MessageObject finalSelectedObject, final MessageObject.GroupedMessages finalSelectedGroup, int loadParticipant) { + createDeleteMessagesAlert(finalSelectedObject, finalSelectedGroup, loadParticipant, false); + } + + private void createDeleteMessagesAlert(final MessageObject finalSelectedObject, final MessageObject.GroupedMessages finalSelectedGroup, int loadParticipant, boolean hideDimAfter) { if (finalSelectedObject == null && (selectedMessagesIds[0].size() + selectedMessagesIds[1].size()) == 0) { return; } AlertsCreator.createDeleteMessagesAlert(this, currentUser, currentChat, currentEncryptedChat, chatInfo, mergeDialogId, finalSelectedObject, selectedMessagesIds, finalSelectedGroup, chatMode == MODE_SCHEDULED, loadParticipant, () -> { hideActionMode(); updatePinnedMessageView(true); - }, () -> dimBehindView(false), themeDelegate); + }, hideDimAfter ? () -> dimBehindView(false) : null, themeDelegate); } private void hideActionMode() { @@ -20650,8 +20986,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not textSelectionHintWasShowed = false; } - private void createMenu(View v, boolean single, boolean listView, float x, float y) { - createMenu(v, single, listView, x, y, true); + private boolean createMenu(View v, boolean single, boolean listView, float x, float y) { + return createMenu(v, single, listView, x, y, true); } private CharSequence getMessageCaption(MessageObject messageObject, MessageObject.GroupedMessages group) { @@ -20692,9 +21028,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not "[\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA]\uFE0F?)+"); } @SuppressLint("ClickableViewAccessibility") - private void createMenu(View v, boolean single, boolean listView, float x, float y, boolean searchGroup) { + private boolean createMenu(View v, boolean single, boolean listView, float x, float y, boolean searchGroup) { if (actionBar.isActionModeShowed() || reportType >= 0) { - return; + return false; } MessageObject message; @@ -20710,7 +21046,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not message = null; } if (message == null) { - return; + return false; } final int type = getMessageType(message); if (single) { @@ -20720,12 +21056,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { Toast.makeText(getParentActivity(), LocaleController.getString("MessageNotFound", R.string.MessageNotFound), Toast.LENGTH_SHORT).show(); } - return; - } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL) { - if (avatarContainer.openSetTimer()) { - return; - } - } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent && message.replyMessageObject != null && message.replyMessageObject.isInvoice()) { + return true; + } 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); @@ -20734,10 +21066,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not presentFragment(new PaymentFormActivity((TLRPC.TL_payments_paymentReceipt) response)); } }), ConnectionsManager.RequestFlagFailOnServerErrors); - return; + return true; } 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; + return false; } VoIPService sharedInstance = VoIPService.getSharedInstance(); if (sharedInstance != null) { @@ -20753,25 +21085,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not createGroupCall = getGroupCall() == null; VoIPHelper.startCall(currentChat, null, null, createGroupCall, getParentActivity(), ChatActivity.this, getAccountInstance()); } - return; + return true; } else if (fragmentContextView != null && getGroupCall() != null) { if (VoIPService.getSharedInstance() != null) { GroupCallActivity.create((LaunchActivity) getParentActivity(), AccountInstance.getInstance(VoIPService.getSharedInstance().getAccount()), null, null, false, null); } else { ChatObject.Call call = getGroupCall(); if (call == null) { - return; + return false; } VoIPHelper.startCall(getMessagesController().getChat(call.chatId), null, null, false, getParentActivity(), ChatActivity.this, getAccountInstance()); } - return; + return true; } else if (ChatObject.canManageCalls(currentChat)) { VoIPHelper.showGroupCallAlert(ChatActivity.this, currentChat, null, true, getAccountInstance()); - return; + return true; } } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionSetChatTheme) { showChatThemeBottomSheet(); - return; + return true; } } if (message.isSponsored() || threadMessageObjects != null && threadMessageObjects.contains(message)) { @@ -20843,14 +21175,34 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (single || type < 2 || type == 20) { if (getParentActivity() == null) { - return; + return false; } ArrayList icons = new ArrayList<>(); ArrayList items = new ArrayList<>(); final ArrayList options = new ArrayList<>(); + View optionsView = null; CharSequence messageText = null; - if (type >= 0 || type == -1 && single && (message.isSending() || message.isEditing()) && currentEncryptedChat == null) { + if (message.messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL && single && (dialog_id >= 0 || (currentChat != null && ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_DELETE_MESSAGES)))) { + AutoDeletePopupWrapper autoDeletePopupWrapper = new AutoDeletePopupWrapper(contentView.getContext(), null, new AutoDeletePopupWrapper.Callback() { + @Override + public void dismiss() { + if (scrimPopupWindow != null) { + scrimPopupWindow.dismiss(); + } + } + + @Override + public void setAutoDeleteHistory(int time, int action) { + getMessagesController().setDialogHistoryTTL(dialog_id, time); + if (userInfo != null || chatInfo != null) { + undoView.showWithAction(dialog_id, action, currentUser, userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period, null, null); + } + } + }, true, getResourceProvider()); + autoDeletePopupWrapper.updateItems(userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period); + optionsView = autoDeletePopupWrapper.windowLayout; + } else if (type >= 0 || type == -1 && single && (message.isSending() || message.isEditing()) && currentEncryptedChat == null) { selectedObject = message; selectedObjectGroup = groupedMessages; messageText = getMessageCaption(selectedObject, selectedObjectGroup); // used only in translations @@ -20867,8 +21219,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messageText == null) messageText = getMessageContent(selectedObject, 0, false); if (messageText != null) { - if (isEmoji(messageText.toString())) + if (isEmoji(messageText.toString())) { messageText = null; // message fully consists of emojis, do not translate + } } if (type == -1) { @@ -20908,7 +21261,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(OPTION_PIN); icons.add(R.drawable.msg_pin); } - if (selectedObject != null && selectedObject.contentType == 0 && (messageText != null && messageText.length() > 0 && !selectedObject.isAnimatedEmoji() && !selectedObject.isDice()) && MessagesController.getGlobalMainSettings().getBoolean("translate_button", false)) { + if (selectedObject != null && selectedObject.contentType == 0 && (messageText != null && messageText.length() > 0 && !selectedObject.isAnimatedEmoji() && !selectedObject.isDice())) { items.add(LocaleController.getString("TranslateMessage", R.string.TranslateMessage)); options.add(29); icons.add(R.drawable.msg_translate); @@ -21167,7 +21520,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(13); icons.add(R.drawable.msg_pin); } - if (selectedObject != null && selectedObject.contentType == 0 && (messageText != null && messageText.length() > 0 && !selectedObject.isAnimatedEmoji() && !selectedObject.isDice()) && MessagesController.getGlobalMainSettings().getBoolean("translate_button", false)) { + if (selectedObject != null && selectedObject.contentType == 0 && (messageText != null && messageText.length() > 0 && !selectedObject.isAnimatedEmoji() && !selectedObject.isDice())) { items.add(LocaleController.getString("TranslateMessage", R.string.TranslateMessage)); options.add(29); icons.add(R.drawable.msg_translate); @@ -21286,15 +21639,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - if (options.isEmpty()) { - return; + if (options.isEmpty() && optionsView == null) { + return false; } if (scrimPopupWindow != null) { closeMenu(); menuDeleteItem = null; scrimPopupWindowItems = null; - return; + return false; } final AtomicBoolean waitForLangDetection = new AtomicBoolean(false); @@ -21328,427 +21681,461 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Drawable shadowDrawable = getParentActivity().getResources().getDrawable(R.drawable.popup_fixed_alert).mutate(); shadowDrawable.getPadding(backgroundPaddings); popupLayout.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); + MessageSeenView messageSeenView = null; - if (isReactionsViewAvailable) { - ReactedHeaderView reactedView = new ReactedHeaderView(contentView.getContext(), currentAccount, message, dialog_id); + boolean addGap = false; - int count = 0; - if (message.messageOwner.reactions != null) { - for (TLRPC.TL_reactionCount r : message.messageOwner.reactions.results) { - count += r.count; - } - } - boolean hasHeader = count > 10 && message.messageOwner.reactions.results.size() > 1; - LinearLayout linearLayout = new LinearLayout(contentView.getContext()) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int size = MeasureSpec.getSize(widthMeasureSpec); - if (size < AndroidUtilities.dp(240)) { - size = AndroidUtilities.dp(240); + if (optionsView == null) { + if (isReactionsViewAvailable) { + ReactedHeaderView reactedView = new ReactedHeaderView(contentView.getContext(), currentAccount, message, dialog_id); + + int count = 0; + if (message.messageOwner.reactions != null) { + for (TLRPC.TL_reactionCount r : message.messageOwner.reactions.results) { + count += r.count; } - if (size < 0) { - size = 0; - } - super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY), heightMeasureSpec); } - }; - linearLayout.setOrientation(LinearLayout.VERTICAL); - linearLayout.setLayoutParams(new FrameLayout.LayoutParams(AndroidUtilities.dp(200), AndroidUtilities.dp(6 * 48 + (hasHeader ? 44 * 2 + 8 : 44)) + (!hasHeader ? 1 : 0))); - ActionBarMenuSubItem backCell = new ActionBarMenuSubItem(getParentActivity(), true, false, themeDelegate); - backCell.setItemHeight(44); - backCell.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.msg_arrow_back); - backCell.getTextView().setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), 0, LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0); - backCell.setOnClickListener(v1 -> popupLayout.getSwipeBack().closeForeground()); - linearLayout.addView(backCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - - int[] foregroundIndex = new int[1]; - - if (hasHeader) { - List counters = message.messageOwner.reactions.results; - LinearLayout tabsView = new LinearLayout(contentView.getContext()); - tabsView.setOrientation(LinearLayout.HORIZONTAL); - ViewPager pager = new ViewPager(contentView.getContext()); - HorizontalScrollView tabsScrollView = new HorizontalScrollView(contentView.getContext()); - - AtomicBoolean suppressTabsScroll = new AtomicBoolean(); - boolean showAllReactionsTab = counters.size() > 1; - int size = counters.size() + (showAllReactionsTab ? 1 : 0); - for (int i = 0; i < size; i++) { - ReactionTabHolderView hv = new ReactionTabHolderView(contentView.getContext()); - int index = i; - if (showAllReactionsTab) { - index--; - } - if (index < 0) { - hv.setCounter(count); - } else { - hv.setCounter(currentAccount, counters.get(index)); - } - int finalI = i; - hv.setOnClickListener(v1 -> { - int from = pager.getCurrentItem(); - if (finalI == from) return; - - ReactionTabHolderView fv = (ReactionTabHolderView) tabsView.getChildAt(from); - suppressTabsScroll.set(true); - pager.setCurrentItem(finalI, true); - float fSX = tabsScrollView.getScrollX(), tSX = hv.getX() - (tabsScrollView.getWidth() - hv.getWidth()) / 2f; - ValueAnimator a = ValueAnimator.ofFloat(0, 1).setDuration(150); - a.setInterpolator(CubicBezierInterpolator.DEFAULT); - a.addUpdateListener(animation -> { - float f = (float) animation.getAnimatedValue(); - tabsScrollView.setScrollX((int) (fSX + (tSX - fSX) * f)); - fv.setOutlineProgress(1f - f); - hv.setOutlineProgress(f); - }); - a.start(); - }); - tabsView.addView(hv, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL, i == 0 ? 6 : 0, 6, 6, 6)); - } - tabsScrollView.setHorizontalScrollBarEnabled(false); - tabsScrollView.addView(tabsView); - linearLayout.addView(tabsScrollView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44)); - - View divider = new FrameLayout(contentView.getContext()); - divider.setBackgroundColor(Theme.getColor(Theme.key_graySection)); - linearLayout.addView(divider, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) Theme.dividerPaint.getStrokeWidth())); - - int head = AndroidUtilities.dp(44 * 2) + 1; - SparseArray cachedViews = new SparseArray<>(); - SparseIntArray cachedHeights = new SparseIntArray(); - for (int i = 0; i < counters.size() + 1; i++) { - cachedHeights.put(i, head + AndroidUtilities.dp(ReactedUsersListView.ITEM_HEIGHT_DP * ReactedUsersListView.VISIBLE_ITEMS)); - } - pager.setAdapter(new PagerAdapter() { + boolean hasHeader = count > 10 && message.messageOwner.reactions.results.size() > 1; + LinearLayout linearLayout = new LinearLayout(contentView.getContext()) { @Override - public int getCount() { - return size; - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return view == object; - } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - View cached = cachedViews.get(position); - if (cached != null) { - container.addView(cached); - return cached; + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int size = MeasureSpec.getSize(widthMeasureSpec); + if (size < AndroidUtilities.dp(240)) { + size = AndroidUtilities.dp(240); } - int index = position; + if (size < 0) { + size = 0; + } + super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY), heightMeasureSpec); + } + }; + linearLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout.setLayoutParams(new FrameLayout.LayoutParams(AndroidUtilities.dp(200), AndroidUtilities.dp(6 * 48 + (hasHeader ? 44 * 2 + 8 : 44)) + (!hasHeader ? 1 : 0))); + ActionBarMenuSubItem backCell = new ActionBarMenuSubItem(getParentActivity(), true, false, themeDelegate); + backCell.setItemHeight(44); + backCell.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.msg_arrow_back); + backCell.getTextView().setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), 0, LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0); + backCell.setOnClickListener(v1 -> popupLayout.getSwipeBack().closeForeground()); + linearLayout.addView(backCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + int[] foregroundIndex = new int[1]; + + if (hasHeader) { + List counters = message.messageOwner.reactions.results; + LinearLayout tabsView = new LinearLayout(contentView.getContext()); + tabsView.setOrientation(LinearLayout.HORIZONTAL); + ViewPager pager = new ViewPager(contentView.getContext()); + HorizontalScrollView tabsScrollView = new HorizontalScrollView(contentView.getContext()); + + AtomicBoolean suppressTabsScroll = new AtomicBoolean(); + boolean showAllReactionsTab = counters.size() > 1; + int size = counters.size() + (showAllReactionsTab ? 1 : 0); + for (int i = 0; i < size; i++) { + ReactionTabHolderView hv = new ReactionTabHolderView(contentView.getContext()); + int index = i; if (showAllReactionsTab) { index--; } - TLRPC.TL_reactionCount reactionCount = null; - if (index >= 0) { - reactionCount = counters.get(index); - } - ReactedUsersListView v = new ReactedUsersListView(container.getContext(), themeDelegate, currentAccount, message, reactionCount, true) - .setSeenUsers(reactedView.getSeenUsers()) - .setOnProfileSelectedListener((view, userId) -> { - Bundle args = new Bundle(); - args.putLong("user_id", userId); - ProfileActivity fragment = new ProfileActivity(args); - presentFragment(fragment); - closeMenu(); - }).setOnHeightChangedListener((view, newHeight) -> { - cachedHeights.put(position, head + newHeight); - if (pager.getCurrentItem() == position) - popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], head + newHeight); - }); if (index < 0) { - reactedView.setSeenCallback(v::setSeenUsers); + hv.setCounter(count); + } else { + hv.setCounter(currentAccount, counters.get(index)); + } + int finalI = i; + hv.setOnClickListener(v1 -> { + int from = pager.getCurrentItem(); + if (finalI == from) return; + + ReactionTabHolderView fv = (ReactionTabHolderView) tabsView.getChildAt(from); + suppressTabsScroll.set(true); + pager.setCurrentItem(finalI, true); + float fSX = tabsScrollView.getScrollX(), tSX = hv.getX() - (tabsScrollView.getWidth() - hv.getWidth()) / 2f; + ValueAnimator a = ValueAnimator.ofFloat(0, 1).setDuration(150); + a.setInterpolator(CubicBezierInterpolator.DEFAULT); + a.addUpdateListener(animation -> { + float f = (float) animation.getAnimatedValue(); + tabsScrollView.setScrollX((int) (fSX + (tSX - fSX) * f)); + fv.setOutlineProgress(1f - f); + hv.setOutlineProgress(f); + }); + a.start(); + }); + tabsView.addView(hv, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL, i == 0 ? 6 : 0, 6, 6, 6)); + } + tabsScrollView.setHorizontalScrollBarEnabled(false); + tabsScrollView.addView(tabsView); + linearLayout.addView(tabsScrollView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44)); + + View divider = new FrameLayout(contentView.getContext()); + divider.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + linearLayout.addView(divider, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) Theme.dividerPaint.getStrokeWidth())); + + int head = AndroidUtilities.dp(44 * 2) + 1; + SparseArray cachedViews = new SparseArray<>(); + SparseIntArray cachedHeights = new SparseIntArray(); + for (int i = 0; i < counters.size() + 1; i++) { + cachedHeights.put(i, head + AndroidUtilities.dp(ReactedUsersListView.ITEM_HEIGHT_DP * ReactedUsersListView.VISIBLE_ITEMS)); + } + pager.setAdapter(new PagerAdapter() { + @Override + public int getCount() { + return size; } - container.addView(v); - cachedViews.put(position, v); - return v; - } + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } - @Override - public void destroyItem(ViewGroup container, int position, Object object) { - container.removeView((View) object); - } - }); - pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - if (!suppressTabsScroll.get()) { - float fX = -1, tX = -1; - for (int i = 0; i < tabsView.getChildCount(); i++) { - ReactionTabHolderView ch = (ReactionTabHolderView) tabsView.getChildAt(i); - ch.setOutlineProgress(i == position ? 1f - positionOffset : i == (position + 1) % size ? positionOffset : 0); - if (i == position) { - fX = ch.getX() - (tabsScrollView.getWidth() - ch.getWidth()) / 2f; - } - if (i == position + 1) { - tX = ch.getX() - (tabsScrollView.getWidth() - ch.getWidth()) / 2f; - } + @Override + public Object instantiateItem(ViewGroup container, int position) { + View cached = cachedViews.get(position); + if (cached != null) { + container.addView(cached); + return cached; + } + int index = position; + if (showAllReactionsTab) { + index--; + } + TLRPC.TL_reactionCount reactionCount = null; + if (index >= 0) { + reactionCount = counters.get(index); + } + ReactedUsersListView v = new ReactedUsersListView(container.getContext(), themeDelegate, currentAccount, message, reactionCount, true) + .setSeenUsers(reactedView.getSeenUsers()) + .setOnProfileSelectedListener((view, userId) -> { + Bundle args = new Bundle(); + args.putLong("user_id", userId); + ProfileActivity fragment = new ProfileActivity(args); + presentFragment(fragment); + closeMenu(); + }).setOnHeightChangedListener((view, newHeight) -> { + cachedHeights.put(position, head + newHeight); + if (pager.getCurrentItem() == position) + popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], head + newHeight); + }); + if (index < 0) { + reactedView.setSeenCallback(v::setSeenUsers); } - if (fX != -1 && tX != -1) - tabsScrollView.setScrollX((int) (fX + (tX - fX) * positionOffset)); + container.addView(v); + cachedViews.put(position, v); + return v; } - } - @Override - public void onPageSelected(int position) { - int h = cachedHeights.get(position); - popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], h); - } - - @Override - public void onPageScrollStateChanged(int state) { - if (state == ViewPager.SCROLL_STATE_IDLE) { - suppressTabsScroll.set(false); + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); } + }); + pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (!suppressTabsScroll.get()) { + float fX = -1, tX = -1; + for (int i = 0; i < tabsView.getChildCount(); i++) { + ReactionTabHolderView ch = (ReactionTabHolderView) tabsView.getChildAt(i); + ch.setOutlineProgress(i == position ? 1f - positionOffset : i == (position + 1) % size ? positionOffset : 0); + if (i == position) { + fX = ch.getX() - (tabsScrollView.getWidth() - ch.getWidth()) / 2f; + } + if (i == position + 1) { + tX = ch.getX() - (tabsScrollView.getWidth() - ch.getWidth()) / 2f; + } + } + + if (fX != -1 && tX != -1) + tabsScrollView.setScrollX((int) (fX + (tX - fX) * positionOffset)); + } + } + + @Override + public void onPageSelected(int position) { + int h = cachedHeights.get(position); + popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], h); + } + + @Override + public void onPageScrollStateChanged(int state) { + if (state == ViewPager.SCROLL_STATE_IDLE) { + suppressTabsScroll.set(false); + } + } + }); + linearLayout.addView(pager, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); + } else { + View gap = new FrameLayout(contentView.getContext()); + gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + linearLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + + ReactedUsersListView lv = new ReactedUsersListView(contentView.getContext(), themeDelegate, currentAccount, message, null, true) + .setSeenUsers(reactedView.getSeenUsers()) + .setOnProfileSelectedListener((view, userId) -> { + Bundle args = new Bundle(); + args.putLong("user_id", userId); + ProfileActivity fragment = new ProfileActivity(args); + presentFragment(fragment); + closeMenu(); + }).setOnHeightChangedListener((view, newHeight) -> popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], AndroidUtilities.dp(44 + 8) + newHeight)); + reactedView.setSeenCallback(lv::setSeenUsers); + linearLayout.addView(lv, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); + } + + foregroundIndex[0] = popupLayout.addViewToSwipeBack(linearLayout); + + reactedView.setOnClickListener(v1 -> { + popupLayout.getSwipeBack().openForeground(foregroundIndex[0]); + }); + popupLayout.addView(reactedView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + addGap = true; + } + + if (showMessageSeen) { + messageSeenView = new MessageSeenView(contentView.getContext(), currentAccount, message, currentChat); + FrameLayout messageSeenLayout = new FrameLayout(contentView.getContext()); + messageSeenLayout.addView(messageSeenView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + MessageSeenView finalMessageSeenView = messageSeenView; + + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); + cell.setItemHeight(44); + cell.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.msg_arrow_back); + cell.getTextView().setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), 0, LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0); + + FrameLayout backContainer = new FrameLayout(contentView.getContext()); + + LinearLayout linearLayout = new LinearLayout(contentView.getContext()); + linearLayout.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); + linearLayout.setOrientation(LinearLayout.VERTICAL); + RecyclerListView listView2 = finalMessageSeenView.createListView(); + backContainer.addView(cell); + linearLayout.addView(backContainer); + backContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + popupLayout.getSwipeBack().closeForeground(); } }); - linearLayout.addView(pager, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); - } else { - View gap = new FrameLayout(contentView.getContext()); - gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); - linearLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); - ReactedUsersListView lv = new ReactedUsersListView(contentView.getContext(), themeDelegate, currentAccount, message, null, true) - .setSeenUsers(reactedView.getSeenUsers()) - .setOnProfileSelectedListener((view, userId) -> { + int[] foregroundIndex = new int[1]; + messageSeenView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (scrimPopupWindow == null || finalMessageSeenView.users.isEmpty()) { + return; + } + if (finalMessageSeenView.users.size() == 1) { + TLRPC.User user = finalMessageSeenView.users.get(0); + if (user == null) { + return; + } Bundle args = new Bundle(); - args.putLong("user_id", userId); + args.putLong("user_id", user.id); ProfileActivity fragment = new ProfileActivity(args); presentFragment(fragment); closeMenu(); - }).setOnHeightChangedListener((view, newHeight) -> popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], AndroidUtilities.dp(44 + 8) + newHeight)); - reactedView.setSeenCallback(lv::setSeenUsers); - linearLayout.addView(lv, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); - } - - foregroundIndex[0] = popupLayout.addViewToSwipeBack(linearLayout); - - reactedView.setOnClickListener(v1 -> { - popupLayout.getSwipeBack().openForeground(foregroundIndex[0]); - }); - popupLayout.addView(reactedView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); - - View gap = new FrameLayout(contentView.getContext()); - gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); - popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); - } - - MessageSeenView messageSeenView = null; - if (showMessageSeen) { - messageSeenView = new MessageSeenView(contentView.getContext(), currentAccount, message, currentChat); - FrameLayout messageSeenLayout = new FrameLayout(contentView.getContext()); - messageSeenLayout.addView(messageSeenView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - MessageSeenView finalMessageSeenView = messageSeenView; - - ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); - cell.setItemHeight(44); - cell.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.msg_arrow_back); - cell.getTextView().setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), 0, LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0); - - FrameLayout backContainer = new FrameLayout(contentView.getContext()); - - LinearLayout linearLayout = new LinearLayout(contentView.getContext()); - linearLayout.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); - linearLayout.setOrientation(LinearLayout.VERTICAL); - RecyclerListView listView2 = finalMessageSeenView.createListView(); - backContainer.addView(cell); - linearLayout.addView(backContainer); - backContainer.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - popupLayout.getSwipeBack().closeForeground(); - } - }); - - int[] foregroundIndex = new int[1]; - messageSeenView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (scrimPopupWindow == null || finalMessageSeenView.users.isEmpty()) { - return; - } - if (finalMessageSeenView.users.size() == 1) { - TLRPC.User user = finalMessageSeenView.users.get(0); - if (user == null) { return; } - Bundle args = new Bundle(); - args.putLong("user_id", user.id); - ProfileActivity fragment = new ProfileActivity(args); - presentFragment(fragment); - closeMenu(); - return; - } - int totalHeight = contentView.getHeightWithKeyboard(); - int availableHeight = totalHeight - scrimPopupY - AndroidUtilities.dp(46 + 16) - (isReactionsAvailable ? AndroidUtilities.dp(52) : 0); + int totalHeight = contentView.getHeightWithKeyboard(); + int availableHeight = totalHeight - scrimPopupY - AndroidUtilities.dp(46 + 16) - (isReactionsAvailable ? AndroidUtilities.dp(52) : 0); - if (SharedConfig.messageSeenHintCount > 0 && contentView.getKeyboardHeight() < AndroidUtilities.dp(20)) { - availableHeight -= AndroidUtilities.dp(52); - Bulletin bulletin = BulletinFactory.of(ChatActivity.this).createErrorBulletin(AndroidUtilities.replaceTags(LocaleController.getString("MessageSeenTooltipMessage", R.string.MessageSeenTooltipMessage))); - bulletin.tag = 1; - bulletin.setDuration(4000); - bulletin.show(); - SharedConfig.updateMessageSeenHintCount(SharedConfig.messageSeenHintCount - 1); - } else if (contentView.getKeyboardHeight() > AndroidUtilities.dp(20)) { - availableHeight -=contentView.getKeyboardHeight() / 3f; - } - - int listViewTotalHeight = AndroidUtilities.dp(8) + AndroidUtilities.dp(44) * listView2.getAdapter().getItemCount(); - - if (listViewTotalHeight > availableHeight) { - if (availableHeight > AndroidUtilities.dp(620)) { - listView2.getLayoutParams().height = AndroidUtilities.dp(620); - } else { - listView2.getLayoutParams().height = availableHeight; + if (SharedConfig.messageSeenHintCount > 0 && contentView.getKeyboardHeight() < AndroidUtilities.dp(20)) { + availableHeight -= AndroidUtilities.dp(52); + Bulletin bulletin = BulletinFactory.of(ChatActivity.this).createErrorBulletin(AndroidUtilities.replaceTags(LocaleController.getString("MessageSeenTooltipMessage", R.string.MessageSeenTooltipMessage))); + bulletin.tag = 1; + bulletin.setDuration(4000); + bulletin.show(); + SharedConfig.updateMessageSeenHintCount(SharedConfig.messageSeenHintCount - 1); + } else if (contentView.getKeyboardHeight() > AndroidUtilities.dp(20)) { + availableHeight -= contentView.getKeyboardHeight() / 3f; } - } else { - listView2.getLayoutParams().height = listViewTotalHeight; + + int listViewTotalHeight = AndroidUtilities.dp(8) + AndroidUtilities.dp(44) * listView2.getAdapter().getItemCount(); + + if (listViewTotalHeight > availableHeight) { + if (availableHeight > AndroidUtilities.dp(620)) { + listView2.getLayoutParams().height = AndroidUtilities.dp(620); + } else { + listView2.getLayoutParams().height = availableHeight; + } + } else { + listView2.getLayoutParams().height = listViewTotalHeight; + } + linearLayout.getLayoutParams().height = AndroidUtilities.dp(44) + listView2.getLayoutParams().height; + listView2.requestLayout(); + linearLayout.requestLayout(); + listView2.getAdapter().notifyDataSetChanged(); + popupLayout.getSwipeBack().openForeground(foregroundIndex[0]); } - linearLayout.getLayoutParams().height = AndroidUtilities.dp(44) + listView2.getLayoutParams().height; - listView2.requestLayout(); - linearLayout.requestLayout(); - listView2.getAdapter().notifyDataSetChanged(); - popupLayout.getSwipeBack().openForeground(foregroundIndex[0]); - } - }); - linearLayout.addView(listView2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 320)); + }); + linearLayout.addView(listView2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 320)); - listView2.setOnItemClickListener((view1, position) -> { - TLRPC.User user = finalMessageSeenView.users.get(position); - if (user == null) { - return; - } - Bundle args = new Bundle(); - args.putLong("user_id", user.id); - ProfileActivity fragment = new ProfileActivity(args); - presentFragment(fragment); - }); - - foregroundIndex[0] = popupLayout.addViewToSwipeBack(linearLayout); - - popupLayout.addView(messageSeenLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44)); - - View gap = new FrameLayout(contentView.getContext()); - gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); - popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); - } - - if (popupLayout.getSwipeBack() != null) { - popupLayout.getSwipeBack().setOnClickListener(e -> closeMenu()); - } - - scrimPopupWindowItems = new ActionBarMenuSubItem[items.size() + (selectedObject.isSponsored() ? 1 : 0)]; - for (int a = 0, N = items.size(); a < N; a++) { - if (a == 0 && selectedObject.isSponsored()) { - ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); - cell.setTextAndIcon(LocaleController.getString("SponsoredMessageInfo", R.string.SponsoredMessageInfo), R.drawable.menu_info); - cell.setItemHeight(56); - cell.setTag(R.id.width_tag, 240); - cell.setMultiline(); - scrimPopupWindowItems[scrimPopupWindowItems.length - 1] = cell; - popupLayout.addView(cell); - cell.setOnClickListener(v1 -> { - if (contentView == null || getParentActivity() == null) { + listView2.setOnItemClickListener((view1, position) -> { + TLRPC.User user = finalMessageSeenView.users.get(position); + if (user == null) { return; } - BottomSheet.Builder builder = new BottomSheet.Builder(contentView.getContext()); - builder.setCustomView(new SponsoredMessageInfoView(getParentActivity(), themeDelegate)); - builder.show(); + Bundle args = new Bundle(); + args.putLong("user_id", user.id); + ProfileActivity fragment = new ProfileActivity(args); + presentFragment(fragment); }); - View gap = new View(getParentActivity()); - gap.setMinimumWidth(AndroidUtilities.dp(196)); - gap.setTag(1000); - gap.setTag(R.id.object_tag, 1); - popupLayout.addView(gap); - LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams(); - if (LocaleController.isRTL) { - layoutParams.gravity = Gravity.RIGHT; - } - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(6); - gap.setLayoutParams(layoutParams); + foregroundIndex[0] = popupLayout.addViewToSwipeBack(linearLayout); + + popupLayout.addView(messageSeenLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44)); + addGap = true; } - ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), a == 0, a == N - 1, themeDelegate); - cell.setMinimumWidth(AndroidUtilities.dp(200)); - cell.setTextAndIcon(items.get(a), icons.get(a)); - Integer option = options.get(a); - if (option == 1 && selectedObject.messageOwner.ttl_period != 0) { - menuDeleteItem = cell; - updateDeleteItemRunnable.run(); - cell.setSubtextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText6)); + + if (message.probablyRingtone()) { + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, false, themeDelegate); + cell.setMinimumWidth(AndroidUtilities.dp(200)); + cell.setTextAndIcon(LocaleController.getString("SaveForNotifications", R.string.SaveForNotifications), R.drawable.msg_tone_add); + popupLayout.addView(cell); + cell.setOnClickListener(v1 -> { + if (getMediaDataController().saveToRingtones(message.getDocument())) { + getUndoView().showWithAction(dialog_id, UndoView.ACTION_RINGTONE_ADDED, new Runnable() { + boolean clicked; + + @Override + public void run() { + if (clicked || dialog_id == 0 || getUserConfig().clientUserId == dialog_id) { + return; + } + clicked = true; + presentFragment(new NotificationsSettingsActivity()); + } + }); + } + closeMenu(true); + }); + addGap = true; } - scrimPopupWindowItems[a] = cell; - popupLayout.addView(cell); - final int i = a; - cell.setOnClickListener(v1 -> { - if (selectedObject == null || i >= options.size()) { - return; - } - processSelectedOption(options.get(i)); - }); - if (option == 29) { // "Translate" button - String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); - final CharSequence finalMessageText = messageText; - TranslateAlert.OnLinkPress onLinkPress = (link) -> { - didPressMessageUrl(link, false, selectedObject, v instanceof ChatMessageCell ? (ChatMessageCell) v : null); - }; - TLRPC.InputPeer inputPeer = getMessagesController().getInputPeer(dialog_id); - int messageId = selectedObject.messageOwner.id; - if (LanguageDetector.hasSupport()) { - final String[] fromLang = { null }; - cell.setVisibility(View.GONE); - waitForLangDetection.set(true); - LanguageDetector.detectLanguage( - finalMessageText.toString(), - (String lang) -> { - fromLang[0] = lang; - if (fromLang[0] != null && (!fromLang[0].equals(toLang) || fromLang[0].equals("und")) && - !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(fromLang[0])) { - cell.setVisibility(View.VISIBLE); - } - waitForLangDetection.set(false); - if (onLangDetectionDone.get() != null) { - onLangDetectionDone.get().run(); - onLangDetectionDone.set(null); - } - }, - (Exception e) -> { - FileLog.e("mlkit: failed to detect language in message"); - waitForLangDetection.set(false); - if (onLangDetectionDone.get() != null) { - onLangDetectionDone.get().run(); - onLangDetectionDone.set(null); - } - } - ); - cell.setOnClickListener(e -> { - if (selectedObject == null || i >= options.size() || getParentActivity() == null) { + + if (addGap) { + View gap = new FrameLayout(contentView.getContext()); + gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + } + + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().setOnClickListener(e -> closeMenu()); + } + + final boolean translateButtonEnabled = MessagesController.getGlobalMainSettings().getBoolean("translate_button", false); + scrimPopupWindowItems = new ActionBarMenuSubItem[items.size() + (selectedObject.isSponsored() ? 1 : 0)]; + for (int a = 0, N = items.size(); a < N; a++) { + if (a == 0 && selectedObject.isSponsored()) { + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); + cell.setTextAndIcon(LocaleController.getString("SponsoredMessageInfo", R.string.SponsoredMessageInfo), R.drawable.menu_info); + cell.setItemHeight(56); + cell.setTag(R.id.width_tag, 240); + cell.setMultiline(); + scrimPopupWindowItems[scrimPopupWindowItems.length - 1] = cell; + popupLayout.addView(cell); + cell.setOnClickListener(v1 -> { + if (contentView == null || getParentActivity() == null) { return; } - TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageId, fromLang[0], toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); - alert.showDim(false); - closeMenu(false); - }); - cell.postDelayed(() -> { - if (onLangDetectionDone.get() != null) { - onLangDetectionDone.getAndSet(null).run(); - } - }, 250); - } else { - cell.setOnClickListener(e -> { - if (selectedObject == null || i >= options.size() || getParentActivity() == null) { - return; - } - TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageId, "und", toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); - alert.showDim(false); - closeMenu(false); + BottomSheet.Builder builder = new BottomSheet.Builder(contentView.getContext()); + builder.setCustomView(new SponsoredMessageInfoView(getParentActivity(), themeDelegate)); + builder.show(); }); + + View gap = new View(getParentActivity()); + gap.setMinimumWidth(AndroidUtilities.dp(196)); + gap.setTag(1000); + gap.setTag(R.id.object_tag, 1); + popupLayout.addView(gap); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams(); + if (LocaleController.isRTL) { + layoutParams.gravity = Gravity.RIGHT; + } + layoutParams.width = LayoutHelper.MATCH_PARENT; + layoutParams.height = AndroidUtilities.dp(6); + gap.setLayoutParams(layoutParams); + } + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), a == 0, a == N - 1, themeDelegate); + cell.setMinimumWidth(AndroidUtilities.dp(200)); + cell.setTextAndIcon(items.get(a), icons.get(a)); + Integer option = options.get(a); + if (option == 1 && selectedObject.messageOwner.ttl_period != 0) { + menuDeleteItem = cell; + updateDeleteItemRunnable.run(); + cell.setSubtextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText6)); + } + scrimPopupWindowItems[a] = cell; + popupLayout.addView(cell); + final int i = a; + cell.setOnClickListener(v1 -> { + if (selectedObject == null || i >= options.size()) { + return; + } + processSelectedOption(options.get(i)); + }); + if (option == 29) { // "Translate" button + String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); + final CharSequence finalMessageText = messageText; + TranslateAlert.OnLinkPress onLinkPress = (link) -> { + didPressMessageUrl(link, false, selectedObject, v instanceof ChatMessageCell ? (ChatMessageCell) v : null); + }; + TLRPC.InputPeer inputPeer = getMessagesController().getInputPeer(dialog_id); + int messageId = selectedObject.messageOwner.id; + if (LanguageDetector.hasSupport()) { + final String[] fromLang = {null}; + cell.setVisibility(View.GONE); + waitForLangDetection.set(true); + LanguageDetector.detectLanguage( + finalMessageText.toString(), + (String lang) -> { + fromLang[0] = lang; + if (fromLang[0] != null && (!fromLang[0].equals(toLang) || fromLang[0].equals("und")) && ( + translateButtonEnabled && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(fromLang[0]) || + (currentChat != null && (currentChat.has_link || currentChat.username != null)) && ("uk".equals(fromLang[0]) || "ru".equals(fromLang[0])) + )) { + cell.setVisibility(View.VISIBLE); + } + waitForLangDetection.set(false); + if (onLangDetectionDone.get() != null) { + onLangDetectionDone.get().run(); + onLangDetectionDone.set(null); + } + }, + (Exception e) -> { + FileLog.e("mlkit: failed to detect language in message"); + waitForLangDetection.set(false); + if (onLangDetectionDone.get() != null) { + onLangDetectionDone.get().run(); + onLangDetectionDone.set(null); + } + } + ); + cell.setOnClickListener(e -> { + if (selectedObject == null || i >= options.size() || getParentActivity() == null) { + return; + } + TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageId, fromLang[0], toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); + alert.showDim(false); + closeMenu(false); + }); + cell.postDelayed(() -> { + if (onLangDetectionDone.get() != null) { + onLangDetectionDone.getAndSet(null).run(); + } + }, 250); + } else if (translateButtonEnabled) { + cell.setOnClickListener(e -> { + if (selectedObject == null || i >= options.size() || getParentActivity() == null) { + return; + } + TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageId, "und", toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); + alert.showDim(false); + closeMenu(false); + }); + } else { + cell.setVisibility(View.GONE); + } } } } @@ -21793,58 +22180,64 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); - ReactionsContainerLayout reactionsLayout = new ReactionsContainerLayout(contentView.getContext(), currentAccount, getResourceProvider()); - if (isReactionsAvailable) { - int pad = 22; - int sPad = 24; - reactionsLayout.setPadding(AndroidUtilities.dp(4) + (LocaleController.isRTL ? 0 : sPad), AndroidUtilities.dp(4), AndroidUtilities.dp(4) + (LocaleController.isRTL ? sPad : 0), AndroidUtilities.dp(pad)); + ReactionsContainerLayout reactionsLayout = null; + if (optionsView != null) { + scrimPopupContainerLayout.addView(optionsView); + } else { + reactionsLayout = new ReactionsContainerLayout(contentView.getContext(), currentAccount, getResourceProvider()); + if (isReactionsAvailable) { + int pad = 22; + int sPad = 24; + reactionsLayout.setPadding(AndroidUtilities.dp(4) + (LocaleController.isRTL ? 0 : sPad), AndroidUtilities.dp(4), AndroidUtilities.dp(4) + (LocaleController.isRTL ? sPad : 0), AndroidUtilities.dp(pad)); - reactionsLayout.setDelegate((rView, reaction, longress) -> { - selectReaction(primaryMessage, reactionsLayout, 0, 0, reaction, false, longress); - }); - - LinearLayout.LayoutParams params = LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 52 + pad, Gravity.RIGHT, 0, 50, 0, -20); - scrimPopupContainerLayout.addView(reactionsLayout, params); - scrimPopupContainerLayout.setReactionsLayout(reactionsLayout); - scrimPopupContainerLayout.setClipChildren(false); - reactionsLayout.setMessage(message, chatInfo); - - reactionsLayout.setTransitionProgress(0); - if (popupLayout.getSwipeBack() != null) { - popupLayout.getSwipeBack().addOnSwipeBackProgressListener((layout, toProgress, progress) -> { - if (toProgress == 0) { - reactionsLayout.startEnterAnimation(); - } else if (toProgress == 1) - reactionsLayout.setAlpha(1f - progress); + ReactionsContainerLayout finalReactionsLayout = reactionsLayout; + reactionsLayout.setDelegate((rView, reaction, longress) -> { + selectReaction(primaryMessage, finalReactionsLayout, 0, 0, reaction, false, longress); }); + + LinearLayout.LayoutParams params = LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 52 + pad, Gravity.RIGHT, 0, 50, 0, -20); + scrimPopupContainerLayout.addView(reactionsLayout, params); + scrimPopupContainerLayout.setReactionsLayout(reactionsLayout); + scrimPopupContainerLayout.setClipChildren(false); + reactionsLayout.setMessage(message, chatInfo); + + reactionsLayout.setTransitionProgress(0); + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().addOnSwipeBackProgressListener((layout, toProgress, progress) -> { + if (toProgress == 0) { + finalReactionsLayout.startEnterAnimation(); + } else if (toProgress == 1) + finalReactionsLayout.setAlpha(1f - progress); + }); + } } - } - boolean showNoForwards = noforwards && message.messageOwner.action == null && message.isSent() && !message.isEditing() && chatMode != MODE_SCHEDULED; - scrimPopupContainerLayout.addView(popupLayout, LayoutHelper.createLinearRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, isReactionsAvailable ? 16 : 0, 0, isReactionsAvailable ? 36 : 0, 0)); - scrimPopupContainerLayout.setPopupWindowLayout(popupLayout); - if (showNoForwards) { - popupLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); - boolean isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; - TextView tv = new TextView(contentView.getContext()); - tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - tv.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem)); - if (getMessagesController().isChatNoForwards(currentChat)) { - tv.setText(isChannel ? LocaleController.getString("ForwardsRestrictedInfoChannel", R.string.ForwardsRestrictedInfoChannel) : - LocaleController.getString("ForwardsRestrictedInfoGroup", R.string.ForwardsRestrictedInfoGroup)); - } else { - tv.setText(LocaleController.getString("ForwardsRestrictedInfoBot", R.string.ForwardsRestrictedInfoBot)); + boolean showNoForwards = noforwards && message.messageOwner.action == null && message.isSent() && !message.isEditing() && chatMode != MODE_SCHEDULED; + scrimPopupContainerLayout.addView(popupLayout, LayoutHelper.createLinearRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, isReactionsAvailable ? 16 : 0, 0, isReactionsAvailable ? 36 : 0, 0)); + scrimPopupContainerLayout.setPopupWindowLayout(popupLayout); + if (showNoForwards) { + popupLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); + boolean isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; + TextView tv = new TextView(contentView.getContext()); + tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + tv.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem)); + if (getMessagesController().isChatNoForwards(currentChat)) { + tv.setText(isChannel ? LocaleController.getString("ForwardsRestrictedInfoChannel", R.string.ForwardsRestrictedInfoChannel) : + LocaleController.getString("ForwardsRestrictedInfoGroup", R.string.ForwardsRestrictedInfoGroup)); + } else { + tv.setText(LocaleController.getString("ForwardsRestrictedInfoBot", R.string.ForwardsRestrictedInfoBot)); + } + tv.setMaxWidth(popupLayout.getMeasuredWidth() - AndroidUtilities.dp(38)); + + Drawable shadowDrawable2 = ContextCompat.getDrawable(contentView.getContext(), R.drawable.popup_fixed_alert).mutate(); + shadowDrawable2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground), PorterDuff.Mode.MULTIPLY)); + + FrameLayout fl = new FrameLayout(contentView.getContext()); + fl.setBackground(shadowDrawable2); + fl.addView(tv, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 11, 11, 11, 11)); + scrimPopupContainerLayout.addView(fl, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, isReactionsAvailable ? 16 : 0, -8, isReactionsAvailable ? 36 : 0, 0)); + scrimPopupContainerLayout.applyViewBottom(fl); } - tv.setMaxWidth(popupLayout.getMeasuredWidth() - AndroidUtilities.dp(38)); - - Drawable shadowDrawable2 = ContextCompat.getDrawable(contentView.getContext(), R.drawable.popup_fixed_alert).mutate(); - shadowDrawable2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground), PorterDuff.Mode.MULTIPLY)); - - FrameLayout fl = new FrameLayout(contentView.getContext()); - fl.setBackground(shadowDrawable2); - fl.addView(tv, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 11, 11, 11, 11)); - scrimPopupContainerLayout.addView(fl, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, isReactionsAvailable ? 16 : 0, -8, isReactionsAvailable ? 36 : 0, 0)); - scrimPopupContainerLayout.applyViewBottom(fl); } scrimPopupWindow = new ActionBarPopupWindow(scrimPopupContainerLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { @@ -21913,13 +22306,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } final int finalPopupX = scrimPopupX = popupX; final int finalPopupY = scrimPopupY = popupY; + ReactionsContainerLayout finalReactionsLayout = reactionsLayout; Runnable showMenu = () -> { if (scrimPopupWindow == null || fragmentView == null) { return; } scrimPopupWindow.showAtLocation(chatListView, Gravity.LEFT | Gravity.TOP, finalPopupX, finalPopupY); - if (isReactionsAvailable) { - reactionsLayout.startEnterAnimation(); + if (isReactionsAvailable && finalReactionsLayout != null) { + finalReactionsLayout.startEnterAnimation(); } }; if (waitForLangDetection.get()) { @@ -21940,11 +22334,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatActivityEnterView != null) { chatActivityEnterView.getEditField().setAllowDrawCursor(false); } - return; + return true; } if (chatActivityEnterView != null && (chatActivityEnterView.isRecordingAudioVideo() || chatActivityEnterView.isRecordLocked())) { - return; + return false; } final ActionBarMenu actionMode = actionBar.createActionMode(); @@ -22001,6 +22395,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatActivityEnterView != null) { chatActivityEnterView.hideBotCommands(); } + return false; } private void closeMenu() { closeMenu(true); @@ -22034,6 +22429,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Runnable updateReactionRunnable; private void selectReaction(MessageObject primaryMessage, ReactionsContainerLayout reactionsLayout, float x, float y, TLRPC.TL_availableReaction reaction, boolean fromDoubleTap, boolean bigEmoji) { + if (isInScheduleMode()) { + return; + } ReactionsEffectOverlay.removeCurrent(false); boolean added = primaryMessage.selectReaction(reaction.reaction, bigEmoji, fromDoubleTap); int messageIdForCell = primaryMessage.getId(); @@ -22339,7 +22737,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } preserveDim = true; - createDeleteMessagesAlert(selectedObject, selectedObjectGroup); + createDeleteMessagesAlert(selectedObject, selectedObjectGroup, 1,true); break; } case 2: { @@ -22623,7 +23021,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), themeDelegate); builder.setTitle(LocaleController.getString("PinMessageAlertTitle", R.string.PinMessageAlertTitle)); preserveDim = true; - builder.setDimEnabled(false); + builder.setDimAlpha(.5f); builder.setOnPreDismissListener(di -> dimBehindView(false)); final boolean[] checks; @@ -22879,7 +23277,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not presentFragment(new MessageStatisticActivity(selectedObject)); break; } - case 100: { + case OPTION_SEND_NOW: { if (!checkSlowMode(chatActivityEnterView.getSendButton())) { if (getMediaController().isPlayingMessage(selectedObject)) { getMediaController().cleanupPlayer(true, true); @@ -23897,11 +24295,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ((URLSpanMono) url).copyToClipboard(); getUndoView().showWithAction(0, UndoView.ACTION_TEXT_COPIED, null); } + if (longPress) { + cell.resetPressedLink(-1); + } } else if (url instanceof URLSpanUserMention) { TLRPC.User user = getMessagesController().getUser(Utilities.parseLong(((URLSpanUserMention) url).getURL())); if (user != null) { MessagesController.openChatOrProfileWith(user, null, ChatActivity.this, 0, false); } + if (longPress) { + cell.resetPressedLink(-1); + } } else if (url instanceof URLSpanNoUnderline) { String str = ((URLSpanNoUnderline) url).getURL(); if (messageObject != null && str.startsWith("/")) { @@ -23911,6 +24315,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not hideFieldPanel(false); } } + if (longPress) { + cell.resetPressedLink(-1); + } } else if (messageObject != null && str.startsWith("video") && !longPress) { int seekTime = Utilities.parseInt(str); TLRPC.WebPage webPage; @@ -23954,7 +24361,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not messageObject.forceSeekTo = seekTime / (float) messageObject.getDuration(); mediaController.playMessage(messageObject); } + if (longPress) { + cell.resetPressedLink(-1); + } } else if (str.startsWith("card:")) { + final ChatMessageCell finalCell = cell; String number = str.substring(5); final AlertDialog[] progressDialog = new AlertDialog[]{new AlertDialog(getParentActivity(), 3, themeDelegate)}; TLRPC.TL_payments_getBankCardData req = new TLRPC.TL_payments_getBankCardData(); @@ -23986,14 +24397,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Toast.makeText(ApplicationLoader.applicationContext, LocaleController.getString("CardNumberCopied", R.string.CardNumberCopied), Toast.LENGTH_SHORT).show(); } }); + builder.setOnPreDismissListener(di -> finalCell.resetPressedLink(-1)); + builder.fixNavigationBar(); showDialog(builder.create()); + } else { + finalCell.resetPressedLink(-1); } }), null, null, 0, getMessagesController().webFileDatacenterId, ConnectionsManager.ConnectionTypeGeneric, true); AndroidUtilities.runOnUIThread(() -> { if (progressDialog[0] == null) { return; } - progressDialog[0].setOnCancelListener(dialog -> getConnectionsManager().cancelRequest(requestId, true)); + progressDialog[0].setOnCancelListener(dialog -> { + getConnectionsManager().cancelRequest(requestId, true); + finalCell.resetPressedLink(-1); + }); showDialog(progressDialog[0]); }, 500); } else { @@ -24067,14 +24485,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); + builder.setOnPreDismissListener(di -> { + finalCell.resetPressedLink(-1); + }); + builder.fixNavigationBar(); showDialog(builder.create()); } else { openClickableLink(str); + if (longPress) { + cell.resetPressedLink(-1); + } } } } else { final String urlFinal = ((URLSpan) url).getURL(); if (longPress) { + final ChatMessageCell finalCell = cell; BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity(), false, themeDelegate); builder.setTitle(urlFinal); builder.setItems(noforwards ? new CharSequence[] {LocaleController.getString("Open", R.string.Open)} : new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { @@ -24101,6 +24527,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } }); + builder.setOnPreDismissListener(di -> { + finalCell.resetPressedLink(-1); + }); + builder.fixNavigationBar(); showDialog(builder.create()); } else { boolean forceAlert = url instanceof URLSpanReplacement; @@ -24898,6 +25328,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + public void didPressViaBotNotInline(ChatMessageCell cell, long botId) { + Bundle args = new Bundle(); + args.putLong("user_id", botId); + if (getMessagesController().checkCanOpenChat(args, ChatActivity.this, cell.getMessageObject())) { + presentFragment(new ChatActivity(args)); + } + } + @Override public void didPressViaBot(ChatMessageCell cell, String username) { if (bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE || bottomOverlay != null && bottomOverlay.getVisibility() == View.VISIBLE) { @@ -25183,8 +25622,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public void didLongPress(ChatActionCell cell, float x, float y) { - createMenu(cell, false, false, x, y); + public boolean didLongPress(ChatActionCell cell, float x, float y) { + return createMenu(cell, false, false, x, y); } @Override @@ -25780,12 +26219,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } public void updateRowAtPosition(int index) { - if (chatLayoutManager == null) { + if (chatLayoutManager == null || isFrozen) { return; } int lastVisibleItem = RecyclerView.NO_POSITION; int top = 0; - ArrayList messages = isFrozen ? frozenMessages : ChatActivity.this.messages; if (!wasManualScroll && unreadMessageObject != null) { int n = chatListView.getChildCount(); @@ -26359,7 +26797,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{ChatActionCell.class}, getThemedPaint(Theme.key_paint_chatActionText), null, null, Theme.key_chat_serviceText)); themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_LINKCOLOR, new Class[]{ChatActionCell.class}, getThemedPaint(Theme.key_paint_chatActionText), null, null, Theme.key_chat_serviceLink)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_botCardDrawalbe, getThemedDrawable(Theme.key_drawable_shareIcon), getThemedDrawable(Theme.key_drawable_replyIcon), getThemedDrawable(Theme.key_drawable_botInline), getThemedDrawable(Theme.key_drawable_botLink), getThemedDrawable(Theme.key_drawable_goIcon), getThemedDrawable(Theme.key_drawable_commentSticker)}, null, Theme.key_chat_serviceIcon)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_botCardDrawable, getThemedDrawable(Theme.key_drawable_shareIcon), getThemedDrawable(Theme.key_drawable_replyIcon), getThemedDrawable(Theme.key_drawable_botInline), getThemedDrawable(Theme.key_drawable_botLink), getThemedDrawable(Theme.key_drawable_botInvite), getThemedDrawable(Theme.key_drawable_goIcon), getThemedDrawable(Theme.key_drawable_commentSticker)}, 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)); @@ -26500,6 +26938,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outVenueInfoSelectedText)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_mediaInfoText)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, Theme.chat_urlPaint, null, null, Theme.key_chat_linkSelectBackground)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, Theme.chat_outUrlPaint, null, null, Theme.key_chat_outLinkSelectBackground)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, Theme.chat_textSearchSelectionPaint, null, null, Theme.key_chat_textSelectBackground)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outLoader)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outMediaIcon)); @@ -27023,7 +27462,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public int getThemedColor(String key) { - Integer color = themeDelegate.getColor(key); + Integer color = themeDelegate != null ? themeDelegate.getColor(key) : null; return color != null ? color : super.getThemedColor(key); } @@ -27264,6 +27703,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not animationSettings.animationProgress = new ActionBarLayout.ThemeAnimationSettings.onAnimationProgress() { @Override public void setProgress(float p) { + chatListView.invalidate(); animatingMessageDrawable.crossfadeProgress = p; animatingMessageMediaDrawable.crossfadeProgress = p; updateServiceMessageColor(p); @@ -27286,6 +27726,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not animatingColors = null; updateServiceMessageColor(1f); }; + } else { + if (contentView != null) { + contentView.setBackgroundImage(Theme.getCachedWallpaper(), Theme.isWallpaperMotion()); + } } animationSettings.onlyTopFragment = true; animationSettings.resourcesProvider = this; @@ -27384,7 +27828,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not initServiceMessageColors(backgroundDrawable); updateServiceMessageColor(1f); } - } } @@ -27598,6 +28041,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Theme.setDrawableColor(getDrawable(Theme.key_drawable_botInline), serviceIconColor); Theme.setDrawableColor(getDrawable(Theme.key_drawable_botLink), serviceIconColor); + Theme.setDrawableColor(getDrawable(Theme.key_drawable_botInvite), serviceIconColor); Theme.setDrawableColor(getDrawable(Theme.key_drawable_commentSticker), serviceIconColor); Theme.setDrawableColor(getDrawable(Theme.key_drawable_goIcon), serviceIconColor); Theme.setDrawableColor(getDrawable(Theme.key_drawable_replyIcon), serviceIconColor); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index 46d91ffdb..fe178c691 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -929,7 +929,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image deleteCell.setText(LocaleController.getString("DeleteAndExitButton", R.string.DeleteAndExitButton), false); } deleteContainer.addView(deleteCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - deleteCell.setOnClickListener(v -> AlertsCreator.createClearOrDeleteDialogAlert(ChatEditActivity.this, false, true, false, currentChat, null, false, true, (param) -> { + deleteCell.setOnClickListener(v -> AlertsCreator.createClearOrDeleteDialogAlert(ChatEditActivity.this, false, true, false, currentChat, null, false, true, false, (param) -> { if (AndroidUtilities.isTablet()) { getNotificationCenter().postNotificationName(NotificationCenter.closeChats, -chatId); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatReactionsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatReactionsEditActivity.java index 8ec0d785d..4f62abb80 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatReactionsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatReactionsEditActivity.java @@ -104,7 +104,6 @@ public class ChatReactionsEditActivity extends BaseFragment implements Notificat enableReactionsCell.setTextAndCheck(LocaleController.getString("EnableReactions", R.string.EnableReactions), !chatReactions.isEmpty(), false); enableReactionsCell.setBackgroundColor(Theme.getColor(enableReactionsCell.isChecked() ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked)); enableReactionsCell.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - enableReactionsCell.setAnimatingToThumbInsteadOfTouch(true); enableReactionsCell.setOnClickListener(v -> { setCheckedEnableReactionCell(!enableReactionsCell.isChecked()); }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index 5a34f7110..a882f6789 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -8,19 +8,27 @@ package org.telegram.ui; +import android.animation.ValueAnimator; import android.app.DatePickerDialog; import android.app.TimePickerDialog; import android.content.Context; import android.content.DialogInterface; +import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.os.Vibrator; import android.text.Editable; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; import android.text.TextWatcher; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; @@ -58,6 +66,10 @@ import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Cells.UserCell2; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CircularProgressDrawable; +import org.telegram.ui.Components.CrossfadeDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; @@ -72,15 +84,25 @@ public class ChatRightsEditActivity extends BaseFragment { private ListAdapter listViewAdapter; private RecyclerListView listView; + private LinearLayoutManager linearLayoutManager; + + private FrameLayout addBotButtonContainer; + private FrameLayout addBotButton; + private PollEditTextCell rankEditTextCell; + private CrossfadeDrawable doneDrawable; private long chatId; private TLRPC.User currentUser; private TLRPC.Chat currentChat; private int currentType; private boolean isChannel; + private boolean loading = false; private boolean canEdit; + private float asAdminT = 0; + private boolean asAdmin = false; + private boolean initialAsAdmin = false; private TLRPC.TL_chatAdminRights adminRights; private TLRPC.TL_chatAdminRights myAdminRights; private TLRPC.TL_chatBannedRights bannedRights; @@ -90,6 +112,9 @@ public class ChatRightsEditActivity extends BaseFragment { private String initialRank; private int rowCount; + private int manageRow; + private int permissionsStartRow; + private int permissionsEndRow; private int changeInfoRow; private int postMessagesRow; private int editMesagesRow; @@ -108,6 +133,7 @@ public class ChatRightsEditActivity extends BaseFragment { private int rankHeaderRow; private int rankRow; private int rankInfoRow; + private int addBotButtonRow; private int sendMessagesRow; private int sendMediaRow; @@ -120,11 +146,15 @@ public class ChatRightsEditActivity extends BaseFragment { private ChatRightsEditActivityDelegate delegate; + private String botHash; private boolean isAddingNew; private boolean initialIsSet; public static final int TYPE_ADMIN = 0; public static final int TYPE_BANNED = 1; + public static final int TYPE_ADD_BOT = 2; + + private boolean closingKeyboardAfterFinish = false; public interface ChatRightsEditActivityDelegate { void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank); @@ -133,13 +163,14 @@ public class ChatRightsEditActivity extends BaseFragment { private final static int done_button = 1; - public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBannedDefault, TLRPC.TL_chatBannedRights rightsBanned, String rank, int type, boolean edit, boolean addingNew) { + public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBannedDefault, TLRPC.TL_chatBannedRights rightsBanned, String rank, int type, boolean edit, boolean addingNew, String addingNewBotHash) { super(); isAddingNew = addingNew; chatId = channelId; currentUser = MessagesController.getInstance(currentAccount).getUser(userId); currentType = type; canEdit = edit; + botHash = addingNewBotHash; currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); if (rank == null) { rank = ""; @@ -150,24 +181,31 @@ public class ChatRightsEditActivity extends BaseFragment { myAdminRights = currentChat.admin_rights; } if (myAdminRights == null) { - myAdminRights = new TLRPC.TL_chatAdminRights(); - myAdminRights.change_info = myAdminRights.post_messages = myAdminRights.edit_messages = - myAdminRights.delete_messages = myAdminRights.ban_users = myAdminRights.invite_users = - myAdminRights.pin_messages = myAdminRights.add_admins = myAdminRights.manage_call = true; + myAdminRights = emptyAdminRights(currentType != TYPE_ADD_BOT || (currentChat != null && currentChat.creator)); } - if (type == TYPE_ADMIN) { - adminRights = new TLRPC.TL_chatAdminRights(); + if (type == TYPE_ADMIN || type == TYPE_ADD_BOT) { if (rightsAdmin == null) { - adminRights.change_info = myAdminRights.change_info; - adminRights.post_messages = myAdminRights.post_messages; - adminRights.edit_messages = myAdminRights.edit_messages; - adminRights.delete_messages = myAdminRights.delete_messages; - adminRights.manage_call = myAdminRights.manage_call; - adminRights.ban_users = myAdminRights.ban_users; - adminRights.invite_users = myAdminRights.invite_users; - adminRights.pin_messages = myAdminRights.pin_messages; - initialIsSet = false; + initialAsAdmin = false; + if (type == TYPE_ADD_BOT) { + adminRights = emptyAdminRights(false); + asAdmin = isChannel; + asAdminT = asAdmin ? 1 : 0; + initialIsSet = false; + } else { + adminRights = new TLRPC.TL_chatAdminRights(); + adminRights.change_info = myAdminRights.change_info; + adminRights.post_messages = myAdminRights.post_messages; + adminRights.edit_messages = myAdminRights.edit_messages; + adminRights.delete_messages = myAdminRights.delete_messages; + adminRights.manage_call = myAdminRights.manage_call; + adminRights.ban_users = myAdminRights.ban_users; + adminRights.invite_users = myAdminRights.invite_users; + adminRights.pin_messages = myAdminRights.pin_messages; + initialIsSet = false; + } } else { + initialAsAdmin = true; + adminRights = new TLRPC.TL_chatAdminRights(); adminRights.change_info = rightsAdmin.change_info; adminRights.post_messages = rightsAdmin.post_messages; adminRights.edit_messages = rightsAdmin.edit_messages; @@ -182,8 +220,32 @@ public class ChatRightsEditActivity extends BaseFragment { initialIsSet = adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || adminRights.pin_messages || adminRights.add_admins || adminRights.manage_call || adminRights.anonymous; + + if (type == TYPE_ADD_BOT) { + asAdmin = isChannel || initialIsSet; + asAdminT = asAdmin ? 1 : 0; + initialIsSet = false; + } } - } else { + + if (currentChat != null) { + defaultBannedRights = currentChat.default_banned_rights; + } + if (defaultBannedRights == null) { + defaultBannedRights = new TLRPC.TL_chatBannedRights(); + defaultBannedRights.view_messages = defaultBannedRights.send_media = defaultBannedRights.send_messages = + defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = + defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = + defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = true; + } + + if (!defaultBannedRights.change_info) { + adminRights.change_info = true; + } + if (!defaultBannedRights.pin_messages) { + adminRights.pin_messages = true; + } + } else if (type == TYPE_BANNED) { defaultBannedRights = rightsBannedDefault; if (defaultBannedRights == null) { defaultBannedRights = new TLRPC.TL_chatBannedRights(); @@ -258,12 +320,24 @@ public class ChatRightsEditActivity extends BaseFragment { updateRows(false); } + public static TLRPC.TL_chatAdminRights emptyAdminRights(boolean value) { + TLRPC.TL_chatAdminRights adminRights = new TLRPC.TL_chatAdminRights(); + adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = + adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = + adminRights.pin_messages = adminRights.add_admins = adminRights.manage_call = value; + return adminRights; + } + + @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); + if (currentType == TYPE_ADMIN) { actionBar.setTitle(LocaleController.getString("EditAdmin", R.string.EditAdmin)); + } else if (currentType == TYPE_ADD_BOT) { + actionBar.setTitle(LocaleController.getString("AddBot", R.string.AddBot)); } else { actionBar.setTitle(LocaleController.getString("UserRestrictions", R.string.UserRestrictions)); } @@ -283,19 +357,60 @@ public class ChatRightsEditActivity extends BaseFragment { if (canEdit || !isChannel && currentChat.creator && UserObject.isUserSelf(currentUser)) { ActionBarMenu menu = actionBar.createMenu(); - menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); + doneDrawable = new CrossfadeDrawable(context.getResources().getDrawable(R.drawable.ic_done), new CircularProgressDrawable(Theme.getColor(Theme.key_actionBarDefaultIcon))); + menu.addItemWithWidth(done_button, 0, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); + menu.getItem(done_button).setIcon(doneDrawable); } - fragmentView = new FrameLayout(context); + fragmentView = new FrameLayout(context) { + private int previousHeight = -1; + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + int height = bottom - top; + if (previousHeight != -1 && Math.abs(previousHeight - height) > AndroidUtilities.dp(20)) { + listView.smoothScrollToPosition(rowCount - 1); + } + previousHeight = height; + } + }; fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); FrameLayout frameLayout = (FrameLayout) fragmentView; fragmentView.setFocusableInTouchMode(true); - listView = new RecyclerListView(context); - LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); - ((DefaultItemAnimator) listView.getItemAnimator()).setDelayAnimations(false); + listView = new RecyclerListView(context) { + @Override + public boolean onTouchEvent(MotionEvent e) { + if (loading) { + return false; + } + return super.onTouchEvent(e); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + if (loading) { + return false; + } + return super.onInterceptTouchEvent(e); + } + }; + listView.setClipChildren(currentType != TYPE_ADD_BOT); + linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) { + @Override + protected int getExtraLayoutSpace(RecyclerView.State state) { + return 5000; + } + }; + linearLayoutManager.setInitialPrefetchItemCount(100); listView.setLayoutManager(linearLayoutManager); listView.setAdapter(listViewAdapter = new ListAdapter(context)); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + if (currentType == TYPE_ADD_BOT) { + listView.setResetSelectorOnChanged(false); + } + itemAnimator.setDelayAnimations(false); + listView.setItemAnimator(itemAnimator); listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -318,7 +433,7 @@ public class ChatRightsEditActivity extends BaseFragment { presentFragment(new ProfileActivity(args)); } else if (position == removeAdminRow) { if (currentType == TYPE_ADMIN) { - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), currentRank, isChannel, getFragmentForAlert(0), isAddingNew); + MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), currentRank, isChannel, getFragmentForAlert(0), isAddingNew, false, null,null); if (delegate != null) { delegate.didSetRights(0, adminRights, bannedRights, currentRank); } @@ -481,57 +596,81 @@ public class ChatRightsEditActivity extends BaseFragment { } else if (view instanceof TextCheckCell2) { TextCheckCell2 checkCell = (TextCheckCell2) view; if (checkCell.hasIcon()) { - Toast.makeText(getParentActivity(), LocaleController.getString("UserRestrictionsDisabled", R.string.UserRestrictionsDisabled), Toast.LENGTH_SHORT).show(); + if (currentType != TYPE_ADD_BOT) { + new AlertDialog.Builder(getParentActivity()) + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyDisabled", R.string.UserRestrictionsCantModifyDisabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); + } return; } + if (!checkCell.isEnabled()) { + if ((currentType == TYPE_ADD_BOT || currentType == TYPE_ADMIN) && + (position == changeInfoRow && defaultBannedRights != null && !defaultBannedRights.change_info || + position == pinMessagesRow && defaultBannedRights != null && !defaultBannedRights.pin_messages)) { + new AlertDialog.Builder(getParentActivity()) + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); + } return; } - checkCell.setChecked(!checkCell.isChecked()); - if (position == changeInfoRow) { - if (currentType == TYPE_ADMIN) { - adminRights.change_info = !adminRights.change_info; + if (currentType != TYPE_ADD_BOT) { + checkCell.setChecked(!checkCell.isChecked()); + } + boolean value = checkCell.isChecked(); + if (position == manageRow) { + value = asAdmin = !asAdmin; + updateAsAdmin(true); + } else if (position == changeInfoRow) { + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { + value = adminRights.change_info = !adminRights.change_info; } else { - bannedRights.change_info = !bannedRights.change_info; + value = bannedRights.change_info = !bannedRights.change_info; } } else if (position == postMessagesRow) { - adminRights.post_messages = !adminRights.post_messages; + value = adminRights.post_messages = !adminRights.post_messages; } else if (position == editMesagesRow) { - adminRights.edit_messages = !adminRights.edit_messages; + value = adminRights.edit_messages = !adminRights.edit_messages; } else if (position == deleteMessagesRow) { - adminRights.delete_messages = !adminRights.delete_messages; + value = adminRights.delete_messages = !adminRights.delete_messages; } else if (position == addAdminsRow) { - adminRights.add_admins = !adminRights.add_admins; + value = adminRights.add_admins = !adminRights.add_admins; } else if (position == anonymousRow) { - adminRights.anonymous = !adminRights.anonymous; + value = adminRights.anonymous = !adminRights.anonymous; } else if (position == banUsersRow) { - adminRights.ban_users = !adminRights.ban_users; + value = adminRights.ban_users = !adminRights.ban_users; } else if (position == startVoiceChatRow) { - adminRights.manage_call = !adminRights.manage_call; + value = adminRights.manage_call = !adminRights.manage_call; } else if (position == addUsersRow) { - if (currentType == TYPE_ADMIN) { - adminRights.invite_users = !adminRights.invite_users; + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { + value = adminRights.invite_users = !adminRights.invite_users; } else { - bannedRights.invite_users = !bannedRights.invite_users; + value = bannedRights.invite_users = !bannedRights.invite_users; } } else if (position == pinMessagesRow) { - if (currentType == TYPE_ADMIN) { - adminRights.pin_messages = !adminRights.pin_messages; + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { + value = adminRights.pin_messages = !adminRights.pin_messages; } else { - bannedRights.pin_messages = !bannedRights.pin_messages; + value = bannedRights.pin_messages = !bannedRights.pin_messages; } - } else if (bannedRights != null) { + } else if (currentType == TYPE_BANNED && bannedRights != null) { boolean disabled = !checkCell.isChecked(); if (position == sendMessagesRow) { - bannedRights.send_messages = !bannedRights.send_messages; + value = bannedRights.send_messages = !bannedRights.send_messages; } else if (position == sendMediaRow) { - bannedRights.send_media = !bannedRights.send_media; + value = bannedRights.send_media = !bannedRights.send_media; } else if (position == sendStickersRow) { - bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = !bannedRights.send_stickers; + value = bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = !bannedRights.send_stickers; } else if (position == embedLinksRow) { - bannedRights.embed_links = !bannedRights.embed_links; + value = bannedRights.embed_links = !bannedRights.embed_links; } else if (position == sendPollsRow) { - bannedRights.send_polls = !bannedRights.send_polls; + value = bannedRights.send_polls = !bannedRights.send_polls; } if (disabled) { if (bannedRights.view_messages && !bannedRights.send_messages) { @@ -582,9 +721,13 @@ public class ChatRightsEditActivity extends BaseFragment { } } } + if (currentType == TYPE_ADD_BOT) { + checkCell.setChecked(asAdmin && value); + } updateRows(true); } }); + return fragmentView; } @@ -770,6 +913,7 @@ public class ChatRightsEditActivity extends BaseFragment { private void updateRows(boolean update) { int transferOwnerShadowRowPrev = Math.min(transferOwnerShadowRow, transferOwnerRow); + manageRow = -1; changeInfoRow = -1; postMessagesRow = -1; editMesagesRow = -1; @@ -797,9 +941,11 @@ public class ChatRightsEditActivity extends BaseFragment { startVoiceChatRow = -1; untilSectionRow = -1; untilDateRow = -1; + addBotButtonRow = -1; rowCount = 3; - if (currentType == TYPE_ADMIN) { + permissionsStartRow = rowCount; + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { if (isChannel) { changeInfoRow = rowCount++; postMessagesRow = rowCount++; @@ -809,6 +955,9 @@ public class ChatRightsEditActivity extends BaseFragment { startVoiceChatRow = rowCount++; addAdminsRow = rowCount++; } else { + if (currentType == TYPE_ADD_BOT) { + manageRow = rowCount++; + } changeInfoRow = rowCount++; deleteMessagesRow = rowCount++; banUsersRow = rowCount++; @@ -830,9 +979,10 @@ public class ChatRightsEditActivity extends BaseFragment { untilSectionRow = rowCount++; untilDateRow = rowCount++; } + permissionsEndRow = rowCount; if (canEdit) { - if (!isChannel && currentType == TYPE_ADMIN) { + if (!isChannel && (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT && asAdmin)) { rightsShadowRow = rowCount++; rankHeaderRow = rowCount++; rankRow = rowCount++; @@ -856,7 +1006,7 @@ public class ChatRightsEditActivity extends BaseFragment { } } else { if (currentType == TYPE_ADMIN) { - if (!isChannel && currentType == TYPE_ADMIN && (!currentRank.isEmpty() || currentChat.creator && UserObject.isUserSelf(currentUser))) { + if (!isChannel && (!currentRank.isEmpty() || currentChat.creator && UserObject.isUserSelf(currentUser))) { rightsShadowRow = rowCount++; rankHeaderRow = rowCount++; rankRow = rowCount++; @@ -872,6 +1022,10 @@ public class ChatRightsEditActivity extends BaseFragment { rightsShadowRow = rowCount++; } } + if (currentType == TYPE_ADD_BOT) { + addBotButtonRow = rowCount++; + } + if (update) { if (transferOwnerShadowRowPrev == -1 && transferOwnerShadowRow != -1) { listViewAdapter.notifyItemRangeInserted(Math.min(transferOwnerShadowRow, transferOwnerRow), 2); @@ -882,7 +1036,10 @@ public class ChatRightsEditActivity extends BaseFragment { } private void onDonePressed() { - if (!ChatObject.isChannel(currentChat) && (currentType == TYPE_BANNED || currentType == TYPE_ADMIN && (!isDefaultAdminRights() || rankRow != -1 && currentRank.codePointCount(0, currentRank.length()) > MAX_RANK_LENGTH))) { + if (loading) { + return; + } + if (!ChatObject.isChannel(currentChat) && (currentType == TYPE_BANNED || currentType == TYPE_ADMIN && (!isDefaultAdminRights() || rankRow != -1 && currentRank.codePointCount(0, currentRank.length()) > MAX_RANK_LENGTH) || currentType == TYPE_ADD_BOT && (currentRank != null || !isDefaultAdminRights()))) { MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, this, param -> { if (param != 0) { chatId = param; @@ -892,7 +1049,7 @@ public class ChatRightsEditActivity extends BaseFragment { }); return; } - if (currentType == TYPE_ADMIN) { + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { if (rankRow != -1 && currentRank.codePointCount(0, currentRank.length()) > MAX_RANK_LENGTH) { listView.smoothScrollToPosition(rankRow); Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); @@ -917,14 +1074,23 @@ public class ChatRightsEditActivity extends BaseFragment { } else { adminRights.other = false; } - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, adminRights, currentRank, isChannel, getFragmentForAlert(1), isAddingNew); - if (delegate != null) { - delegate.didSetRights( + } + boolean finishFragment = true; + if (currentType == TYPE_ADMIN) { + finishFragment = delegate == null; + setLoading(true); + MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, adminRights, currentRank, isChannel, this, isAddingNew, false, null, () -> { + if (delegate != null) { + delegate.didSetRights( adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || adminRights.pin_messages || adminRights.add_admins || adminRights.anonymous || adminRights.manage_call || adminRights.other ? 1 : 0, adminRights, bannedRights, currentRank); - } + finishFragment(); + } + }, () -> { + setLoading(false); + }); } else if (currentType == TYPE_BANNED) { MessagesController.getInstance(currentAccount).setParticipantBannedRole(chatId, currentUser, null, bannedRights, isChannel, getFragmentForAlert(1)); int rights; @@ -938,8 +1104,78 @@ public class ChatRightsEditActivity extends BaseFragment { if (delegate != null) { delegate.didSetRights(rights, adminRights, bannedRights, currentRank); } + } else if (currentType == TYPE_ADD_BOT) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(asAdmin ? + LocaleController.getString("AddBotAdmin", R.string.AddBotAdmin) : + LocaleController.getString("AddBot", R.string.AddBot) + ); + boolean isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; + String chatName = currentChat == null ? "" : currentChat.title; + builder.setMessage(AndroidUtilities.replaceTags( + asAdmin ? ( + isChannel ? + LocaleController.formatString("AddBotMessageAdminChannel", R.string.AddBotMessageAdminChannel, chatName) : + LocaleController.formatString("AddBotMessageAdminGroup", R.string.AddBotMessageAdminGroup, chatName) + ) : LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(currentUser), chatName) + )); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setPositiveButton(asAdmin ? LocaleController.getString("AddAsAdmin", R.string.AddAsAdmin) : LocaleController.getString("AddBot", R.string.AddBot), (di, i) -> { + setLoading(true); + Runnable onFinish = () -> { + if (delegate != null) { + delegate.didSetRights(0, asAdmin ? adminRights : null, null, currentRank); + } + closingKeyboardAfterFinish = true; + + Bundle args1 = new Bundle(); + args1.putBoolean("scrollToTopOnResume", true); + args1.putLong("chat_id", currentChat.id); + if (!getMessagesController().checkCanOpenChat(args1, this)) { + setLoading(false); + return; + } + ChatActivity chatActivity = new ChatActivity(args1); + presentFragment(chatActivity, true); + if (BulletinFactory.canShowBulletin(chatActivity)) { + if (isAddingNew && asAdmin) { + BulletinFactory.createAddedAsAdminBulletin(chatActivity, currentUser.first_name).show(); + } else if (!isAddingNew && !initialAsAdmin && asAdmin) { + BulletinFactory.createPromoteToAdminBulletin(chatActivity, currentUser.first_name).show(); + } + } + }; + if (asAdmin || initialAsAdmin) { + getMessagesController().setUserAdminRole(currentChat.id, currentUser, asAdmin ? adminRights : emptyAdminRights(false), currentRank, false, this, isAddingNew, asAdmin, botHash, onFinish, () -> setLoading(false)); + } else { + getMessagesController().addUserToChat(currentChat.id, currentUser, 0, botHash, this, true, onFinish, () -> setLoading(false)); + } + }); + showDialog(builder.create()); + finishFragment = false; + } + if (finishFragment) { + finishFragment(); + } + } + + private ValueAnimator doneDrawableAnimator; + + public void setLoading(boolean enable) { + if (doneDrawableAnimator != null) { + doneDrawableAnimator.cancel(); + } + loading = !enable; + actionBar.getBackButton().setEnabled(!enable); + if (doneDrawable != null) { + doneDrawableAnimator = ValueAnimator.ofFloat(doneDrawable.getProgress(), enable ? 1f : 0f); + doneDrawableAnimator.addUpdateListener(a -> { + doneDrawable.setProgress((float) a.getAnimatedValue()); + doneDrawable.invalidateSelf(); + }); + doneDrawableAnimator.setDuration((long) (150 * Math.abs(doneDrawable.getProgress() - (enable ? 1 : 0)))); + doneDrawableAnimator.start(); } - finishFragment(); } public void setDelegate(ChatRightsEditActivityDelegate channelRightsEditActivityDelegate) { @@ -947,6 +1183,9 @@ public class ChatRightsEditActivity extends BaseFragment { } private boolean checkDiscard() { + if (currentType == TYPE_ADD_BOT) { + return true; + } boolean changed; if (currentType == TYPE_BANNED) { String newBannedRights = ChatObject.getBannedRightsString(bannedRights); @@ -992,47 +1231,104 @@ public class ChatRightsEditActivity extends BaseFragment { private class ListAdapter extends RecyclerListView.SelectionAdapter { + private final int VIEW_TYPE_USER_CELL = 0; + private final int VIEW_TYPE_INFO_CELL = 1; + private final int VIEW_TYPE_TRANSFER_CELL = 2; + private final int VIEW_TYPE_HEADER_CELL = 3; + private final int VIEW_TYPE_SWITCH_CELL = 4; + private final int VIEW_TYPE_SHADOW_CELL = 5; + private final int VIEW_TYPE_UNTIL_DATE_CELL = 6; + private final int VIEW_TYPE_RANK_CELL = 7; + private final int VIEW_TYPE_ADD_BOT_CELL = 8; + private Context mContext; private boolean ignoreTextChange; public ListAdapter(Context context) { + if (currentType == TYPE_ADD_BOT) { + setHasStableIds(true); + } mContext = context; } + @Override + public long getItemId(int position) { + if (currentType == TYPE_ADD_BOT) { + if (position == manageRow) return 1; + if (position == changeInfoRow) return 2; + if (position == postMessagesRow) return 3; + if (position == editMesagesRow) return 4; + if (position == deleteMessagesRow) return 5; + if (position == addAdminsRow) return 6; + if (position == anonymousRow) return 7; + if (position == banUsersRow) return 8; + if (position == addUsersRow) return 9; + if (position == pinMessagesRow) return 10; + if (position == rightsShadowRow) return 11; + if (position == removeAdminRow) return 12; + if (position == removeAdminShadowRow) return 13; + if (position == cantEditInfoRow) return 14; + if (position == transferOwnerShadowRow) return 15; + if (position == transferOwnerRow) return 16; + if (position == rankHeaderRow) return 17; + if (position == rankRow) return 18; + if (position == rankInfoRow) return 19; + if (position == sendMessagesRow) return 20; + if (position == sendMediaRow) return 21; + if (position == sendStickersRow) return 22; + if (position == sendPollsRow) return 23; + if (position == embedLinksRow) return 24; + if (position == startVoiceChatRow) return 25; + if (position == untilSectionRow) return 26; + if (position == untilDateRow) return 27; + if (position == addBotButtonRow) return 28; + return 0; + } else { + return super.getItemId(position); + } + } + @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int type = holder.getItemViewType(); - if (currentChat.creator && currentType == TYPE_ADMIN && type == 4 && holder.getAdapterPosition() == anonymousRow) { + if (currentChat.creator && (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT && asAdmin) && type == VIEW_TYPE_SWITCH_CELL && holder.getAdapterPosition() == anonymousRow) { return true; } if (!canEdit) { return false; } - if (currentType == TYPE_ADMIN && type == 4) { + if ((currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) && type == VIEW_TYPE_SWITCH_CELL) { int position = holder.getAdapterPosition(); - if (position == changeInfoRow) { - return myAdminRights.change_info; - } else if (position == postMessagesRow) { - return myAdminRights.post_messages; - } else if (position == editMesagesRow) { - return myAdminRights.edit_messages; - } else if (position == deleteMessagesRow) { - return myAdminRights.delete_messages; - } else if (position == startVoiceChatRow) { - return myAdminRights.manage_call; - } else if (position == addAdminsRow) { - return myAdminRights.add_admins; - } else if (position == anonymousRow) { - return myAdminRights.anonymous; - } else if (position == banUsersRow) { - return myAdminRights.ban_users; - } else if (position == addUsersRow) { - return myAdminRights.invite_users; - } else if (position == pinMessagesRow) { - return myAdminRights.pin_messages; + if (position == manageRow) { + return myAdminRights.add_admins || (currentChat != null && currentChat.creator); + } else { + if (currentType == TYPE_ADD_BOT && !asAdmin) { + return false; + } + if (position == changeInfoRow) { + return myAdminRights.change_info && (defaultBannedRights == null || defaultBannedRights.change_info); + } else if (position == postMessagesRow) { + return myAdminRights.post_messages; + } else if (position == editMesagesRow) { + return myAdminRights.edit_messages; + } else if (position == deleteMessagesRow) { + return myAdminRights.delete_messages; + } else if (position == startVoiceChatRow) { + return myAdminRights.manage_call; + } else if (position == addAdminsRow) { + return myAdminRights.add_admins; + } else if (position == anonymousRow) { + return myAdminRights.anonymous; + } else if (position == banUsersRow) { + return myAdminRights.ban_users; + } else if (position == addUsersRow) { + return myAdminRights.invite_users; + } else if (position == pinMessagesRow) { + return myAdminRights.pin_messages && (defaultBannedRights == null || defaultBannedRights.pin_messages); + } } } - return type != 3 && type != 1 && type != 5; + return type != VIEW_TYPE_HEADER_CELL && type != VIEW_TYPE_INFO_CELL && type != VIEW_TYPE_SHADOW_CELL && type != VIEW_TYPE_ADD_BOT_CELL; } @Override @@ -1044,36 +1340,112 @@ public class ChatRightsEditActivity extends BaseFragment { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_USER_CELL: view = new UserCell2(mContext, 4, 0); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 1: + case VIEW_TYPE_INFO_CELL: view = new TextInfoPrivacyCell(mContext); view.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); break; - case 2: + case VIEW_TYPE_TRANSFER_CELL: + default: view = new TextSettingsCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 3: + case VIEW_TYPE_HEADER_CELL: view = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlueHeader, 21, 15, true); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 4: + case VIEW_TYPE_SWITCH_CELL: view = new TextCheckCell2(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 5: + case VIEW_TYPE_SHADOW_CELL: view = new ShadowSectionCell(mContext); break; - case 6: + case VIEW_TYPE_UNTIL_DATE_CELL: view = new TextDetailCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 7: - default: - PollEditTextCell cell = new PollEditTextCell(mContext, null); + case VIEW_TYPE_ADD_BOT_CELL: + addBotButtonContainer = new FrameLayout(mContext); + addBotButtonContainer.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + addBotButton = new FrameLayout(mContext) { + + private TextPaint textPaint; + private StaticLayout mainText; + private StaticLayout asMemberText; + private StaticLayout asAdminText; { + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textPaint.setTextSize(AndroidUtilities.dp(14)); + textPaint.setColor(0xffffffff); + mainText = new StaticLayout(LocaleController.getString("AddBotButton", R.string.AddBotButton) + " ", textPaint, 9999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + asMemberText = new StaticLayout(LocaleController.getString("AddBotButtonAsMember", R.string.AddBotButtonAsMember), textPaint, 9999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + asAdminText = new StaticLayout(LocaleController.getString("AddBotButtonAsAdmin", R.string.AddBotButtonAsAdmin), textPaint, 9999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + } + + private long lastFrame; + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + float t = CubicBezierInterpolator.EASE_BOTH.getInterpolation(asAdminT); + + float mainWidth = mainText.getLineWidth(0); + float asWidth; + if (asAdminT <= 0) { + asWidth = asMemberText.getLineWidth(0); + } else if (asAdminT >= 1) { + asWidth = asAdminText.getLineWidth(0); + } else { + asWidth = AndroidUtilities.lerp(asMemberText.getLineWidth(0), asAdminText.getLineWidth(0), t); + } + float width = mainWidth + asWidth; + + canvas.save(); + canvas.translate((getWidth() - width) / 2, (getHeight() - mainText.getHeight()) / 2); + textPaint.setAlpha(255); + mainText.draw(canvas); + canvas.translate(mainWidth, 0); + if (t <= 0) { + asMemberText.draw(canvas); + } else { + canvas.save(); + canvas.translate(0, AndroidUtilities.dp(8) * t); + canvas.scale(1, 1 - 0.2f * t); + textPaint.setAlpha((int) (255 * (1f - t))); + asMemberText.draw(canvas); + canvas.restore(); + } + if (t >= 1) { + textPaint.setAlpha(255); + asAdminText.draw(canvas); + } else { + canvas.save(); + canvas.translate(0, -AndroidUtilities.dp(8) * (1f - t)); + canvas.scale(1, 1 - 0.2f * (1f - t)); + textPaint.setAlpha((int) (255 * t)); + asAdminText.draw(canvas); + canvas.restore(); + } + canvas.restore(); + } + }; + addBotButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_featuredStickers_addButton), 0x40ffffff)); + addBotButton.setOnClickListener(e -> onDonePressed()); + addBotButtonContainer.addView(addBotButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.FILL, 14, 28, 14, 14)); + addBotButtonContainer.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + View bg = new View(mContext); + bg.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + addBotButtonContainer.setClipChildren(false); + addBotButtonContainer.setClipToPadding(false); + addBotButtonContainer.addView(bg, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 800, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, -800)); + view = addBotButtonContainer; + break; + case VIEW_TYPE_RANK_CELL: + PollEditTextCell cell = rankEditTextCell = new PollEditTextCell(mContext, null); cell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); cell.addTextWatcher(new TextWatcher() { @Override @@ -1107,11 +1479,15 @@ public class ChatRightsEditActivity extends BaseFragment { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: + case VIEW_TYPE_USER_CELL: UserCell2 userCell2 = (UserCell2) holder.itemView; - userCell2.setData(currentUser, null, null, 0); + String status = null; + if (currentType == TYPE_ADD_BOT) { + status = LocaleController.getString("Bot", R.string.Bot); + } + userCell2.setData(currentUser, null, status, 0); break; - case 1: + case VIEW_TYPE_INFO_CELL: TextInfoPrivacyCell privacyCell = (TextInfoPrivacyCell) holder.itemView; if (position == cantEditInfoRow) { privacyCell.setText(LocaleController.getString("EditAdminCantEdit", R.string.EditAdminCantEdit)); @@ -1125,7 +1501,7 @@ public class ChatRightsEditActivity extends BaseFragment { privacyCell.setText(LocaleController.formatString("EditAdminRankInfo", R.string.EditAdminRankInfo, hint)); } break; - case 2: + case VIEW_TYPE_TRANSFER_CELL: TextSettingsCell actionCell = (TextSettingsCell) holder.itemView; if (position == removeAdminRow) { actionCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText5)); @@ -1145,10 +1521,12 @@ public class ChatRightsEditActivity extends BaseFragment { } } break; - case 3: + case VIEW_TYPE_HEADER_CELL: HeaderCell headerCell = (HeaderCell) holder.itemView; if (position == 2) { - if (currentType == TYPE_ADMIN) { + if (currentType == TYPE_ADD_BOT || (currentUser != null && currentUser.bot)) { + headerCell.setText(LocaleController.getString("BotRestrictionsCanDo", R.string.BotRestrictionsCanDo)); + } else if (currentType == TYPE_ADMIN) { headerCell.setText(LocaleController.getString("EditAdminWhatCanDo", R.string.EditAdminWhatCanDo)); } else if (currentType == TYPE_BANNED) { headerCell.setText(LocaleController.getString("UserRestrictionsCanDo", R.string.UserRestrictionsCanDo)); @@ -1157,37 +1535,66 @@ public class ChatRightsEditActivity extends BaseFragment { headerCell.setText(LocaleController.getString("EditAdminRank", R.string.EditAdminRank)); } break; - case 4: + case VIEW_TYPE_SWITCH_CELL: TextCheckCell2 checkCell = (TextCheckCell2) holder.itemView; - if (position == changeInfoRow) { - if (currentType == TYPE_ADMIN) { + boolean asAdminValue = currentType != TYPE_ADD_BOT || asAdmin; + boolean isCreator = (currentChat != null && currentChat.creator); + if (position == manageRow) { + checkCell.setTextAndCheck(LocaleController.getString("ManageGroup", R.string.ManageGroup), asAdmin, true); + checkCell.setIcon(myAdminRights.add_admins || isCreator ? 0 : R.drawable.permission_locked); + } else if (position == changeInfoRow) { + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { if (isChannel) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminChangeChannelInfo", R.string.EditAdminChangeChannelInfo), adminRights.change_info, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminChangeChannelInfo", R.string.EditAdminChangeChannelInfo), asAdminValue && adminRights.change_info || !defaultBannedRights.change_info, true); } else { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminChangeGroupInfo", R.string.EditAdminChangeGroupInfo), adminRights.change_info, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminChangeGroupInfo", R.string.EditAdminChangeGroupInfo), asAdminValue && adminRights.change_info || !defaultBannedRights.change_info, true); + } + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.change_info || isCreator ? 0 : R.drawable.permission_locked); } } else if (currentType == TYPE_BANNED) { checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsChangeInfo", R.string.UserRestrictionsChangeInfo), !bannedRights.change_info && !defaultBannedRights.change_info, false); checkCell.setIcon(defaultBannedRights.change_info ? R.drawable.permission_locked : 0); } } else if (position == postMessagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminPostMessages", R.string.EditAdminPostMessages), adminRights.post_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminPostMessages", R.string.EditAdminPostMessages), asAdminValue && adminRights.post_messages, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.post_messages || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == editMesagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminEditMessages", R.string.EditAdminEditMessages), adminRights.edit_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminEditMessages", R.string.EditAdminEditMessages), asAdminValue && adminRights.edit_messages, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.edit_messages || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == deleteMessagesRow) { if (isChannel) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminDeleteMessages", R.string.EditAdminDeleteMessages), adminRights.delete_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminDeleteMessages", R.string.EditAdminDeleteMessages), asAdminValue && adminRights.delete_messages, true); } else { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminGroupDeleteMessages", R.string.EditAdminGroupDeleteMessages), adminRights.delete_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminGroupDeleteMessages", R.string.EditAdminGroupDeleteMessages), asAdminValue && adminRights.delete_messages, true); + } + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.delete_messages || isCreator ? 0 : R.drawable.permission_locked); } } else if (position == addAdminsRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminAddAdmins", R.string.EditAdminAddAdmins), adminRights.add_admins, anonymousRow != -1); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminAddAdmins", R.string.EditAdminAddAdmins), asAdminValue && adminRights.add_admins, anonymousRow != -1); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.add_admins || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == anonymousRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminSendAnonymously", R.string.EditAdminSendAnonymously), adminRights.anonymous, false); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminSendAnonymously", R.string.EditAdminSendAnonymously), asAdminValue && adminRights.anonymous, false); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.anonymous || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == banUsersRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminBanUsers", R.string.EditAdminBanUsers), adminRights.ban_users, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminBanUsers", R.string.EditAdminBanUsers), asAdminValue && adminRights.ban_users, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.ban_users || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == startVoiceChatRow) { - checkCell.setTextAndCheck(LocaleController.getString("StartVoipChatPermission", R.string.StartVoipChatPermission), adminRights.manage_call, true); + checkCell.setTextAndCheck(LocaleController.getString("StartVoipChatPermission", R.string.StartVoipChatPermission), asAdminValue && adminRights.manage_call, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.manage_call || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == addUsersRow) { if (currentType == TYPE_ADMIN) { if (ChatObject.isActionBannedByDefault(currentChat, ChatObject.ACTION_INVITE)) { @@ -1198,10 +1605,16 @@ public class ChatRightsEditActivity extends BaseFragment { } else if (currentType == TYPE_BANNED) { checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsInviteUsers", R.string.UserRestrictionsInviteUsers), !bannedRights.invite_users && !defaultBannedRights.invite_users, true); checkCell.setIcon(defaultBannedRights.invite_users ? R.drawable.permission_locked : 0); + } else if (currentType == TYPE_ADD_BOT) { + checkCell.setTextAndCheck(LocaleController.getString("EditAdminAddUsersViaLink", R.string.EditAdminAddUsersViaLink), asAdminValue && adminRights.invite_users, true); + checkCell.setIcon(myAdminRights.invite_users || isCreator ? 0 : R.drawable.permission_locked); } } else if (position == pinMessagesRow) { - if (currentType == TYPE_ADMIN) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminPinMessages", R.string.EditAdminPinMessages), adminRights.pin_messages, true); + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { + checkCell.setTextAndCheck(LocaleController.getString("EditAdminPinMessages", R.string.EditAdminPinMessages), asAdminValue && adminRights.pin_messages || !defaultBannedRights.pin_messages, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.pin_messages || isCreator ? 0 : R.drawable.permission_locked); + } } else if (currentType == TYPE_BANNED) { checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsPinMessages", R.string.UserRestrictionsPinMessages), !bannedRights.pin_messages && !defaultBannedRights.pin_messages, true); checkCell.setIcon(defaultBannedRights.pin_messages ? R.drawable.permission_locked : 0); @@ -1223,14 +1636,23 @@ public class ChatRightsEditActivity extends BaseFragment { checkCell.setIcon(defaultBannedRights.send_polls ? R.drawable.permission_locked : 0); } - if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { - checkCell.setEnabled(!bannedRights.send_messages && !bannedRights.view_messages && !defaultBannedRights.send_messages && !defaultBannedRights.view_messages); - } else if (position == sendMessagesRow) { - checkCell.setEnabled(!bannedRights.view_messages && !defaultBannedRights.view_messages); + if (currentType == TYPE_ADD_BOT) { +// checkCell.setEnabled((asAdmin || position == manageRow) && !checkCell.hasIcon(), false); + } else { + if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { + checkCell.setEnabled(!bannedRights.send_messages && !bannedRights.view_messages && !defaultBannedRights.send_messages && !defaultBannedRights.view_messages); + } else if (position == sendMessagesRow) { + checkCell.setEnabled(!bannedRights.view_messages && !defaultBannedRights.view_messages); + } } break; - case 5: + case VIEW_TYPE_SHADOW_CELL: ShadowSectionCell shadowCell = (ShadowSectionCell) holder.itemView; + if (currentType == TYPE_ADD_BOT && (position == rightsShadowRow || position == rankInfoRow)) { + shadowCell.setAlpha(asAdminT); + } else { + shadowCell.setAlpha(1); + } if (position == rightsShadowRow) { shadowCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, removeAdminRow == -1 && rankRow == -1 ? R.drawable.greydivider_bottom : R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } else if (position == removeAdminShadowRow) { @@ -1241,7 +1663,7 @@ public class ChatRightsEditActivity extends BaseFragment { shadowCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } break; - case 6: + case VIEW_TYPE_UNTIL_DATE_CELL: TextDetailCell detailCell = (TextDetailCell) holder.itemView; if (position == untilDateRow) { String value; @@ -1253,7 +1675,7 @@ public class ChatRightsEditActivity extends BaseFragment { detailCell.setTextAndValue(LocaleController.getString("UserRestrictionsDuration", R.string.UserRestrictionsDuration), value, false); } break; - case 7: + case VIEW_TYPE_RANK_CELL: PollEditTextCell textCell = (PollEditTextCell) holder.itemView; String hint; if (UserObject.isUserSelf(currentUser) && currentChat.creator) { @@ -1288,24 +1710,118 @@ public class ChatRightsEditActivity extends BaseFragment { @Override public int getItemViewType(int position) { if (position == 0) { - return 0; + return VIEW_TYPE_USER_CELL; } else if (position == 1 || position == rightsShadowRow || position == removeAdminShadowRow || position == untilSectionRow || position == transferOwnerShadowRow) { - return 5; + return VIEW_TYPE_SHADOW_CELL; } else if (position == 2 || position == rankHeaderRow) { - return 3; + return VIEW_TYPE_HEADER_CELL; } else if (position == changeInfoRow || position == postMessagesRow || position == editMesagesRow || position == deleteMessagesRow || position == addAdminsRow || position == banUsersRow || position == addUsersRow || position == pinMessagesRow || position == sendMessagesRow || position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || - position == sendPollsRow || position == anonymousRow || position == startVoiceChatRow) { - return 4; + position == sendPollsRow || position == anonymousRow || position == startVoiceChatRow || position == manageRow) { + return VIEW_TYPE_SWITCH_CELL; } else if (position == cantEditInfoRow || position == rankInfoRow) { - return 1; + return VIEW_TYPE_INFO_CELL; } else if (position == untilDateRow) { - return 6; + return VIEW_TYPE_UNTIL_DATE_CELL; } else if (position == rankRow) { - return 7; + return VIEW_TYPE_RANK_CELL; + } else if (position == addBotButtonRow) { + return VIEW_TYPE_ADD_BOT_CELL; } else { - return 2; + return VIEW_TYPE_TRANSFER_CELL; + } + } + } + + private ValueAnimator asAdminAnimator; + private void updateAsAdmin(boolean animated) { + if (addBotButton != null) { + addBotButton.invalidate(); + } + final int count = listView.getChildCount(); + for (int i = 0; i < count; ++i) { + View child = listView.getChildAt(i); + int childPosition = listView.getChildAdapterPosition(child); + if (child instanceof TextCheckCell2) { + if (!asAdmin) { + if (childPosition == changeInfoRow && !defaultBannedRights.change_info || + childPosition == pinMessagesRow && !defaultBannedRights.pin_messages) { + ((TextCheckCell2) child).setChecked(true); + ((TextCheckCell2) child).setEnabled(false, false); + } else { + ((TextCheckCell2) child).setChecked(false); + ((TextCheckCell2) child).setEnabled(childPosition == manageRow, animated); + } + } else { + boolean childValue = false, childEnabled = false; + if (childPosition == manageRow) { + childValue = asAdmin; + childEnabled = myAdminRights.add_admins || (currentChat != null && currentChat.creator); + } else if (childPosition == changeInfoRow) { + childValue = adminRights.change_info; + childEnabled = myAdminRights.change_info && defaultBannedRights.change_info; + } else if (childPosition == postMessagesRow) { + childValue = adminRights.post_messages; + childEnabled = myAdminRights.post_messages; + } else if (childPosition == editMesagesRow) { + childValue = adminRights.edit_messages; + childEnabled = myAdminRights.edit_messages; + } else if (childPosition == deleteMessagesRow) { + childValue = adminRights.delete_messages; + childEnabled = myAdminRights.delete_messages; + } else if (childPosition == banUsersRow) { + childValue = adminRights.ban_users; + childEnabled = myAdminRights.ban_users; + } else if (childPosition == addUsersRow) { + childValue = adminRights.invite_users; + childEnabled = myAdminRights.invite_users; + } else if (childPosition == pinMessagesRow) { + childValue = adminRights.pin_messages; + childEnabled = myAdminRights.pin_messages && defaultBannedRights.pin_messages; + } else if (childPosition == startVoiceChatRow) { + childValue = adminRights.manage_call; + childEnabled = myAdminRights.manage_call; + } else if (childPosition == addAdminsRow) { + childValue = adminRights.add_admins; + childEnabled = myAdminRights.add_admins; + } else if (childPosition == anonymousRow) { + childValue = adminRights.anonymous; + childEnabled = myAdminRights.anonymous || (currentChat != null && currentChat.creator); + } + ((TextCheckCell2) child).setChecked(childValue); + ((TextCheckCell2) child).setEnabled(childEnabled, animated); + } + } + } +// listViewAdapter.notifyItemRangeChanged(permissionsStartRow, permissionsEndRow - permissionsStartRow); +// if (asAdmin) { +// listViewAdapter.notifyItemMoved(addBotButtonRow, rightsShadowRow + 1); +// listViewAdapter.notifyItemRangeInserted(rightsShadowRow, rankInfoRow - rightsShadowRow + 1); +// } else { +// listViewAdapter.notifyItemRangeRemoved(rightsShadowRow, rankInfoRow - rightsShadowRow + 1); +// listViewAdapter.notifyItemMoved(addBotButtonRow, permissionsEndRow + 1); +// } + listViewAdapter.notifyDataSetChanged(); + + if (asAdminAnimator != null) { + asAdminAnimator.cancel(); + asAdminAnimator = null; + } + if (animated) { + asAdminAnimator = ValueAnimator.ofFloat(asAdminT, asAdmin ? 1f : 0f); + asAdminAnimator.addUpdateListener(a -> { + asAdminT = (float) a.getAnimatedValue(); + if (addBotButton != null) { + addBotButton.invalidate(); + } + }); + asAdminAnimator.setDuration((long) (Math.abs(asAdminT - (asAdmin ? 1f : 0f)) * 200)); + asAdminAnimator.start(); + } else { + asAdminT = asAdmin ? 1f : 0f; + if (addBotButton != null) { + addBotButton.invalidate(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index d878e280f..a5b57b345 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -23,7 +23,6 @@ import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; -import android.util.Log; import android.util.SparseIntArray; import android.util.TypedValue; import android.view.Gravity; @@ -86,7 +85,6 @@ import org.telegram.ui.Components.UndoView; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; public class ChatUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { @@ -1045,9 +1043,11 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } }); } else if (position == addNew2Row) { - ManageLinksActivity fragment = new ManageLinksActivity(chatId, 0, 0); - fragment.setInfo(info, info.exported_invite); - presentFragment(fragment); + if (info != null) { + ManageLinksActivity fragment = new ManageLinksActivity(chatId, 0, 0); + fragment.setInfo(info, info.exported_invite); + presentFragment(fragment); + } return; } else if (position > permissionsSectionRow && position <= changeInfoRow) { TextCheckCell2 checkCell = (TextCheckCell2) view; @@ -1257,7 +1257,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente bannedRights.invite_users = true; bannedRights.change_info = true; } - ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type == TYPE_ADMIN ? ChatRightsEditActivity.TYPE_ADMIN : ChatRightsEditActivity.TYPE_BANNED, canEdit, participant == null); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type == TYPE_ADMIN ? ChatRightsEditActivity.TYPE_ADMIN : ChatRightsEditActivity.TYPE_BANNED, canEdit, participant == null, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -1482,7 +1482,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private void openRightsEdit2(long peerId, int date, TLObject participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean canEditAdmin, int type, boolean removeFragment) { boolean[] needShowBulletin = new boolean[1]; final boolean isAdmin = participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_chatParticipantAdmin; - ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, true, false) { + ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, true, false, null) { @Override protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { if (!isOpen && backward && needShowBulletin[0] && BulletinFactory.canShowBulletin(ChatUsersActivity.this)) { @@ -1573,7 +1573,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } private void openRightsEdit(long user_id, TLObject participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean canEditAdmin, int type, boolean removeFragment) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, canEditAdmin, participant == null); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, canEditAdmin, participant == null, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -1662,7 +1662,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente map.remove(peerId); arrayList.remove(p); updated = true; - if (type == TYPE_BANNED) { + if (type == TYPE_BANNED && info != null) { info.kicked_count--; } } @@ -1870,7 +1870,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente builder.setItems(items, icons, (dialogInterface, i) -> { if (type == TYPE_ADMIN) { if (i == 0 && items.length == 2) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, null, null, rank, ChatRightsEditActivity.TYPE_ADMIN, true, false); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, null, null, rank, ChatRightsEditActivity.TYPE_ADMIN, true, false, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -1890,13 +1890,13 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente }); presentFragment(fragment); } else { - getMessagesController().setUserAdminRole(chatId, getMessagesController().getUser(peerId), new TLRPC.TL_chatAdminRights(), "", !isChannel, ChatUsersActivity.this, false); + getMessagesController().setUserAdminRole(chatId, getMessagesController().getUser(peerId), new TLRPC.TL_chatAdminRights(), "", !isChannel, ChatUsersActivity.this, false, false, null,null); removeParticipants(peerId); } } else if (type == TYPE_BANNED || type == TYPE_KICKED) { if (i == 0) { if (type == TYPE_KICKED) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, null, defaultBannedRights, bannedRights, rank, ChatRightsEditActivity.TYPE_BANNED, true, false); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, null, defaultBannedRights, bannedRights, rank, ChatRightsEditActivity.TYPE_BANNED, true, false, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { 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 ca6db7107..b38a4e755 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -42,7 +42,6 @@ import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.URLSpan; import android.util.Base64; -import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; @@ -60,7 +59,9 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.RawRes; import androidx.annotation.RequiresApi; +import androidx.core.util.Consumer; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; @@ -119,6 +120,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; public class AlertsCreator { public final static int PERMISSIONS_REQUEST_TOP_ICON_SIZE = 72; @@ -168,6 +170,48 @@ public class AlertsCreator { .create(); } + public static Dialog createWebViewPermissionsRequestDialog(Context ctx, Theme.ResourcesProvider resourcesProvider, String[] systemPermissions, @RawRes int animationId, String title, String titleWithHint, Consumer callback) { + boolean showSettings = false; + if (systemPermissions != null && ctx instanceof Activity && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + Activity activity = (Activity) ctx; + for (String perm : systemPermissions) { + if (activity.checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED && activity.shouldShowRequestPermissionRationale(perm)) { + showSettings = true; + break; + } + } + } + AtomicBoolean gotCallback = new AtomicBoolean(); + boolean finalShowSettings = showSettings; + return new AlertDialog.Builder(ctx, resourcesProvider) + .setTopAnimation(animationId, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)) + .setMessage(AndroidUtilities.replaceTags(showSettings ? titleWithHint : title)) + .setPositiveButton(LocaleController.getString(showSettings ? R.string.PermissionOpenSettings : R.string.BotWebViewRequestAllow), (dialogInterface, i) -> { + if (finalShowSettings) { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); + ctx.startActivity(intent); + } catch (Exception e) { + FileLog.e(e); + } + } else { + gotCallback.set(true); + callback.accept(true); + } + }) + .setNegativeButton(LocaleController.getString(R.string.BotWebViewRequestDontAllow), (dialog, which) -> { + gotCallback.set(true); + callback.accept(false); + }) + .setOnDismissListener(dialog -> { + if (!gotCallback.get()) { + callback.accept(false); + } + }) + .create(); + } + @RequiresApi(api = Build.VERSION_CODES.O) public static Dialog createApkRestrictedDialog(Context ctx, Theme.ResourcesProvider resourcesProvider) { return new AlertDialog.Builder(ctx, resourcesProvider) @@ -884,49 +928,17 @@ public class AlertsCreator { } else if (i == 4) { untilTime = Integer.MAX_VALUE; } - - if (did != 0) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - long flags; - if (i == 4) { - if (!defaultEnabled) { - editor.remove("notify2_" + did); - flags = 0; - } else { - editor.putInt("notify2_" + did, 2); - flags = 1; - } + NotificationsController.getInstance(currentAccount).muteUntil(did, untilTime); + if (did != 0 && resultCallback != null) { + if (i == 4 && !defaultEnabled) { + resultCallback.run(0); } else { - editor.putInt("notify2_" + did, 3); - editor.putInt("notifyuntil_" + did, untilTime); - flags = ((long) untilTime << 32) | 1; - } - NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(did); - MessagesStorage.getInstance(currentAccount).setDialogFlags(did, flags); - editor.commit(); - TLRPC.Dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); - if (dialog != null) { - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - if (i != 4 || defaultEnabled) { - dialog.notify_settings.mute_until = untilTime; - } - } - NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(did); - if (resultCallback != null) { - if (i == 4 && !defaultEnabled) { - resultCallback.run(0); - } else { - resultCallback.run(1); - } - } - } else { - if (i == 4) { - NotificationsController.getInstance(currentAccount).setGlobalNotificationsEnabled(globalType, Integer.MAX_VALUE); - } else { - NotificationsController.getInstance(currentAccount).setGlobalNotificationsEnabled(globalType, untilTime); + resultCallback.run(1); } } + if (did == 0) { + NotificationsController.getInstance(currentAccount).setGlobalNotificationsEnabled(globalType, Integer.MAX_VALUE); + } } if (callback != null) { @@ -1279,20 +1291,20 @@ public class AlertsCreator { fragment.showDialog(alertDialog); } - public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, MessagesStorage.BooleanCallback onProcessRunnable) { - createClearOrDeleteDialogAlert(fragment, clear, false, false, chat, user, secret, false, onProcessRunnable, null); + public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable) { + createClearOrDeleteDialogAlert(fragment, clear, false, false, chat, user, secret, false, canDeleteHistory, onProcessRunnable, null); } - public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, MessagesStorage.BooleanCallback onProcessRunnable) { - createClearOrDeleteDialogAlert(fragment, clear, chat != null && chat.creator, false, chat, user, secret, checkDeleteForAll, onProcessRunnable, null); + public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable) { + createClearOrDeleteDialogAlert(fragment, clear, chat != null && chat.creator, false, chat, user, secret, checkDeleteForAll, canDeleteHistory, onProcessRunnable, null); } - public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { - createClearOrDeleteDialogAlert(fragment, clear, chat != null && chat.creator, false, chat, user, secret, checkDeleteForAll, onProcessRunnable, resourcesProvider); + public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { + createClearOrDeleteDialogAlert(fragment, clear, chat != null && chat.creator, false, chat, user, secret, checkDeleteForAll, canDeleteHistory, onProcessRunnable, resourcesProvider); } - public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, boolean admin, boolean second, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { - if (fragment == null || fragment.getParentActivity() == null || chat == null && user == null) { + public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, boolean admin, boolean second, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { + if (fragment == null || fragment.getParentActivity() == null || (chat == null && user == null)) { return; } int account = fragment.getCurrentAccount(); @@ -1308,7 +1320,7 @@ public class AlertsCreator { messageTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); messageTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); - boolean clearingCache = ChatObject.isChannel(chat) && !TextUtils.isEmpty(chat.username); + boolean clearingCache = !canDeleteHistory && ChatObject.isChannel(chat) && !TextUtils.isEmpty(chat.username); FrameLayout frameLayout = new FrameLayout(context) { @Override @@ -1529,12 +1541,12 @@ public class AlertsCreator { builder.setPositiveButton(actionText, (dialogInterface, i) -> { if (!clearingCache && !second && !secret) { if (UserObject.isUserSelf(user)) { - createClearOrDeleteDialogAlert(fragment, clear, admin, true, chat, user, false, checkDeleteForAll, onProcessRunnable, resourcesProvider); + createClearOrDeleteDialogAlert(fragment, clear, admin, true, chat, user, false, checkDeleteForAll, canDeleteHistory, onProcessRunnable, resourcesProvider); return; } else if (user != null && deleteForAll[0]) { MessagesStorage.getInstance(fragment.getCurrentAccount()).getMessagesCount(user.id, (count) -> { if (count >= 50) { - createClearOrDeleteDialogAlert(fragment, clear, admin, true, chat, user, false, checkDeleteForAll, onProcessRunnable, resourcesProvider); + createClearOrDeleteDialogAlert(fragment, clear, admin, true, chat, user, false, checkDeleteForAll, canDeleteHistory, onProcessRunnable, resourcesProvider); } else { if (onProcessRunnable != null) { onProcessRunnable.run(deleteForAll[0]); @@ -1557,8 +1569,8 @@ public class AlertsCreator { } } - public static void createClearDaysDialogAlert(BaseFragment fragment, int days, TLRPC.User user, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { - if (fragment == null || fragment.getParentActivity() == null || user == null) { + public static void createClearDaysDialogAlert(BaseFragment fragment, int days, TLRPC.User user, TLRPC.Chat chat, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { + if (fragment == null || fragment.getParentActivity() == null || (user == null && chat == null)) { return; } int account = fragment.getCurrentAccount(); @@ -1595,18 +1607,40 @@ public class AlertsCreator { textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); textView.setEllipsize(TextUtils.TruncateAt.END); - textView.setText(LocaleController.formatPluralString("DeleteDays", days)); - frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 24, 11, 24, 0)); frameLayout.addView(messageTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 24, 48, 24, 18)); - messageTextView.setText(LocaleController.getString("DeleteHistoryByDaysMessage", R.string.DeleteHistoryByDaysMessage)); + + if (days == -1) { + textView.setText(LocaleController.formatString("ClearHistory", R.string.ClearHistory)); + if (user != null) { + messageTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("AreYouSureClearHistoryWithUser", R.string.AreYouSureClearHistoryWithUser, UserObject.getUserName(user)))); + } else { + if (chat != null && canDeleteHistory) { + messageTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("AreYouSureClearHistoryWithChat", R.string.AreYouSureClearHistoryWithChat, chat.title))); + } else if (chat.megagroup) { + messageTextView.setText(LocaleController.getString("AreYouSureClearHistoryGroup", R.string.AreYouSureClearHistoryGroup)); + } else { + messageTextView.setText(LocaleController.getString("AreYouSureClearHistoryChannel", R.string.AreYouSureClearHistoryChannel)); + } + } + } else { + textView.setText(LocaleController.formatPluralString("DeleteDays", days)); + messageTextView.setText(LocaleController.getString("DeleteHistoryByDaysMessage", R.string.DeleteHistoryByDaysMessage)); + } final boolean[] deleteForAll = new boolean[]{false}; - if (user.id != selfUserId) { + if (chat != null && canDeleteHistory && !TextUtils.isEmpty(chat.username)) { + deleteForAll[0] = true; + } + if ((user != null && user.id != selfUserId) || (chat != null && canDeleteHistory && TextUtils.isEmpty(chat.username))) { cell[0] = new CheckBoxCell(context, 1, resourcesProvider); cell[0].setBackgroundDrawable(Theme.getSelectorDrawable(false)); - cell[0].setText(LocaleController.formatString("DeleteMessagesOptionAlso", R.string.DeleteMessagesOptionAlso, UserObject.getFirstName(user)), "", false, false); + if (chat != null) { + cell[0].setText(LocaleController.getString("DeleteMessagesOptionAlsoChat", R.string.DeleteMessagesOptionAlsoChat), "", false, false); + } else { + cell[0].setText(LocaleController.formatString("DeleteMessagesOptionAlso", R.string.DeleteMessagesOptionAlso, UserObject.getFirstName(user)), "", false, false); + } cell[0].setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); frameLayout.addView(cell[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 0)); @@ -2369,9 +2403,9 @@ public class AlertsCreator { 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; + dayPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + hourPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutePicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -2435,7 +2469,7 @@ public class AlertsCreator { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); linearLayout.setWeightSum(1.0f); - container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); long currentTime = System.currentTimeMillis(); Calendar calendar = Calendar.getInstance(); @@ -2589,9 +2623,9 @@ public class AlertsCreator { 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; + dayPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + hourPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutePicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -2621,7 +2655,7 @@ public class AlertsCreator { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); linearLayout.setWeightSum(1.0f); - container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); long currentTime = System.currentTimeMillis(); Calendar calendar = Calendar.getInstance(); @@ -2720,6 +2754,483 @@ public class AlertsCreator { return builder; } + public static BottomSheet.Builder createAutoDeleteDatePickerDialog(Context context, final ScheduleDatePickerDelegate datePickerDelegate) { + if (context == null) { + return null; + } + + ScheduleDatePickerColors datePickerColors = new ScheduleDatePickerColors(); + BottomSheet.Builder builder = new BottomSheet.Builder(context, false); + builder.setApplyBottomPadding(false); + + int[] values = new int[]{ + 0, + 60 * 24, + 2 * 60 * 24, + 3 * 60 * 24, + 4 * 60 * 24, + 5 * 60 * 24, + 6 * 60 * 24, + 7 * 60 * 24, + 2 * 7 * 60 * 24, + 3 * 7 * 60 * 24, + 31 * 60 * 24, + 2 * 31 * 60 * 24, + 3 * 31 * 60 * 24, + 4 * 31 * 60 * 24, + 5 * 31 * 60 * 24, + 6 * 31 * 60 * 24, + 365 * 60 * 24 + }; + + final NumberPicker numberPicker = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int index) { + if (values[index] == 0) { + return LocaleController.getString("AutoDeleteNever", R.string.AutoDeleteNever); + } else if (values[index] < 7 * 60 * 24) { + return LocaleController.formatPluralString("Days", values[index] / (60 * 24)); + } else if (values[index] < 31 * 60 * 24) { + return LocaleController.formatPluralString("Weeks", values[index] / (60 * 24)); + } else if (values[index] < 365 * 60 * 24) { + return LocaleController.formatPluralString("Months", values[index] / (7 * 60 * 24)); + } else { + return LocaleController.formatPluralString("Years", values[index] * 5 / 31 * 60 * 24); + } + } + }; + numberPicker.setMinValue(0); + numberPicker.setMaxValue(values.length - 1); + numberPicker.setTextColor(datePickerColors.textColor); + numberPicker.setValue(0); + numberPicker.setWrapSelectorWheel(false); + numberPicker.setFormatter(index -> { + if (values[index] == 0) { + return LocaleController.getString("AutoDeleteNever", R.string.AutoDeleteNever); + } else if (values[index] < 7 * 60 * 24) { + return LocaleController.formatPluralString("Days", values[index] / (60 * 24)); + } else if (values[index] < 31 * 60 * 24) { + return LocaleController.formatPluralString("Weeks", values[index] / (7 * 60 * 24)); + } else if (values[index] < 365 * 60 * 24) { + return LocaleController.formatPluralString("Months", values[index] / (31 * 60 * 24)); + } else { + return LocaleController.formatPluralString("Years", values[index] / (365 * 60 * 24)); + } + }); + + LinearLayout container = new LinearLayout(context) { + + boolean ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + int count; + if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + count = 3; + } else { + count = 5; + } + numberPicker.setItemCount(count); + numberPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + ignoreLayout = false; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + container.setOrientation(LinearLayout.VERTICAL); + + FrameLayout titleLayout = new FrameLayout(context); + container.addView(titleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 22, 0, 0, 4)); + + TextView titleView = new TextView(context); + titleView.setText(LocaleController.getString("AutoDeleteAfteTitle", R.string.AutoDeleteAfteTitle)); + + titleView.setTextColor(datePickerColors.textColor); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 12, 0, 0)); + titleView.setOnTouchListener((v, event) -> true); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(1.0f); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); + + TextView buttonTextView = new TextView(context) { + @Override + public CharSequence getAccessibilityClassName() { + return Button.class.getName(); + } + }; + + linearLayout.addView(numberPicker, LayoutHelper.createLinear(0, 54 * 5, 1f)); + + buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setGravity(Gravity.CENTER); + buttonTextView.setTextColor(datePickerColors.buttonTextColor); + buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); + container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); + + final NumberPicker.OnValueChangeListener onValueChangeListener = (picker, oldVal, newVal) -> { + try { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + + } + }; + numberPicker.setOnValueChangedListener(onValueChangeListener); + + buttonTextView.setOnClickListener(v -> { + int time = values[numberPicker.getValue()]; + datePickerDelegate.didSelectDate(true, time); + builder.getDismissRunnable().run(); + }); + + builder.setCustomView(container); + BottomSheet bottomSheet = builder.show(); + bottomSheet.setBackgroundColor(datePickerColors.backgroundColor); + return builder; + } + + public static BottomSheet.Builder createSoundFrequencyPickerDialog(Context context, int notifyMaxCount, int notifyDelay, final SoundFrequencyDelegate delegate) { + if (context == null) { + return null; + } + + ScheduleDatePickerColors datePickerColors = new ScheduleDatePickerColors(); + BottomSheet.Builder builder = new BottomSheet.Builder(context, false); + builder.setApplyBottomPadding(false); + + final NumberPicker times = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int index) { + return LocaleController.formatPluralString("Times", index + 1); + } + }; + times.setMinValue(0); + times.setMaxValue(10); + times.setTextColor(datePickerColors.textColor); + times.setValue(notifyMaxCount - 1); + times.setWrapSelectorWheel(false); + times.setFormatter(index -> LocaleController.formatPluralString("Times", index + 1)); + + final NumberPicker minutes = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int index) { + return LocaleController.formatPluralString("Times", index + 1); + } + }; + minutes.setMinValue(0); + minutes.setMaxValue(10); + minutes.setTextColor(datePickerColors.textColor); + minutes.setValue(notifyDelay / 60 - 1); + minutes.setWrapSelectorWheel(false); + minutes.setFormatter(index -> LocaleController.formatPluralString("Minutes", index + 1)); + + NumberPicker divider = new NumberPicker(context); + divider.setMinValue(0); + divider.setMaxValue(0); + divider.setTextColor(datePickerColors.textColor); + divider.setValue(0); + divider.setWrapSelectorWheel(false); + divider.setFormatter(index -> LocaleController.getString("NotificationsFrequencyDivider", R.string.NotificationsFrequencyDivider)); + + LinearLayout container = new LinearLayout(context) { + + boolean ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + int count; + if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + count = 3; + } else { + count = 5; + } + times.setItemCount(count); + times.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutes.setItemCount(count); + minutes.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + divider.setItemCount(count); + divider.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + ignoreLayout = false; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + container.setOrientation(LinearLayout.VERTICAL); + + FrameLayout titleLayout = new FrameLayout(context); + container.addView(titleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 22, 0, 0, 4)); + + TextView titleView = new TextView(context); + titleView.setText(LocaleController.getString("NotfificationsFrequencyTitle", R.string.NotfificationsFrequencyTitle)); + + titleView.setTextColor(datePickerColors.textColor); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 12, 0, 0)); + titleView.setOnTouchListener((v, event) -> true); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(1.0f); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); + + TextView buttonTextView = new TextView(context) { + @Override + public CharSequence getAccessibilityClassName() { + return Button.class.getName(); + } + }; + + linearLayout.addView(times, LayoutHelper.createLinear(0, 54 * 5, 0.4f)); + linearLayout.addView(divider, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 0.2f, Gravity.CENTER_VERTICAL)); + linearLayout.addView(minutes, LayoutHelper.createLinear(0, 54 * 5, 0.4f)); + + buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setGravity(Gravity.CENTER); + buttonTextView.setTextColor(datePickerColors.buttonTextColor); + buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); + container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); + + final NumberPicker.OnValueChangeListener onValueChangeListener = (picker, oldVal, newVal) -> { + try { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + + } + }; + times.setOnValueChangedListener(onValueChangeListener); + minutes.setOnValueChangedListener(onValueChangeListener); + + buttonTextView.setOnClickListener(v -> { + int time = times.getValue() + 1; + int minute = (minutes.getValue() + 1) * 60; + delegate.didSelectValues(time, minute); + builder.getDismissRunnable().run(); + }); + + builder.setCustomView(container); + BottomSheet bottomSheet = builder.show(); + bottomSheet.setBackgroundColor(datePickerColors.backgroundColor); + return builder; + } + + public static BottomSheet.Builder createMuteForPickerDialog(Context context, final ScheduleDatePickerDelegate datePickerDelegate) { + if (context == null) { + return null; + } + + ScheduleDatePickerColors datePickerColors = new ScheduleDatePickerColors(); + BottomSheet.Builder builder = new BottomSheet.Builder(context, false); + builder.setApplyBottomPadding(false); + + final NumberPicker dayPicker = new NumberPicker(context); + dayPicker.setTextColor(datePickerColors.textColor); + 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(datePickerColors.textColor); + + LinearLayout container = new LinearLayout(context) { + + boolean ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + int count; + if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + count = 3; + } else { + count = 5; + } + dayPicker.setItemCount(count); + hourPicker.setItemCount(count); + dayPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + hourPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + ignoreLayout = false; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + container.setOrientation(LinearLayout.VERTICAL); + + FrameLayout titleLayout = new FrameLayout(context); + container.addView(titleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 22, 0, 0, 4)); + + TextView titleView = new TextView(context); + titleView.setText(LocaleController.getString("MuteForAlert", R.string.MuteForAlert)); + titleView.setTextColor(datePickerColors.textColor); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 12, 0, 0)); + titleView.setOnTouchListener((v, event) -> true); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(1.0f); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); + + TextView buttonTextView = new TextView(context) { + @Override + public CharSequence getAccessibilityClassName() { + return Button.class.getName(); + } + }; + + linearLayout.addView(dayPicker, LayoutHelper.createLinear(0, 54 * 5, 0.5f)); + dayPicker.setMinValue(0); + dayPicker.setMaxValue(365); + dayPicker.setWrapSelectorWheel(false); + dayPicker.setFormatter(value -> LocaleController.formatPluralString("Days", value)); + final NumberPicker.OnValueChangeListener onValueChangeListener = (picker, oldVal, newVal) -> { + try { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + + } + checkMuteForButton(dayPicker, hourPicker, buttonTextView, true); + }; + dayPicker.setOnValueChangedListener(onValueChangeListener); + + hourPicker.setMinValue(0); + hourPicker.setMaxValue(23); + linearLayout.addView(hourPicker, LayoutHelper.createLinear(0, 54 * 5, 0.5f)); + hourPicker.setFormatter(value -> LocaleController.formatPluralString("Hours", value)); + hourPicker.setOnValueChangedListener(onValueChangeListener); + + buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setGravity(Gravity.CENTER); + buttonTextView.setTextColor(datePickerColors.buttonTextColor); + buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + 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 -> { + int time = hourPicker.getValue() * 60 + dayPicker.getValue() * 60 * 24; + datePickerDelegate.didSelectDate(true, time); + builder.getDismissRunnable().run(); + }); + + builder.setCustomView(container); + BottomSheet bottomSheet = builder.show(); + bottomSheet.setBackgroundColor(datePickerColors.backgroundColor); + checkMuteForButton(dayPicker, hourPicker, buttonTextView, false); + return builder; + } + + private static void checkMuteForButton(NumberPicker dayPicker, NumberPicker hourPicker, TextView buttonTextView, boolean animated) { + StringBuilder stringBuilder = new StringBuilder(); + if (dayPicker.getValue() != 0) { + stringBuilder.append(dayPicker.getValue()).append(LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays)); + } + if (hourPicker.getValue() != 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + stringBuilder.append(hourPicker.getValue()).append(LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours)); + } + if (stringBuilder.length() == 0) { + buttonTextView.setText(LocaleController.getString("ChooseTimeForMute", R.string.ChooseTimeForMute)); + if (buttonTextView.isEnabled()) { + buttonTextView.setEnabled(false); + if (animated) { + buttonTextView.animate().alpha(0.5f); + } else { + buttonTextView.setAlpha(0.5f); + } + } + } else { + buttonTextView.setText(LocaleController.formatString("MuteForButton", R.string.MuteForButton, stringBuilder.toString())); + if (!buttonTextView.isEnabled()) { + buttonTextView.setEnabled(true); + if (animated) { + buttonTextView.animate().alpha(1f); + } else { + buttonTextView.setAlpha(1f); + } + } + } + } + + private static void checkAutoDeleteButton(NumberPicker dayPicker, NumberPicker hourPicker, NumberPicker minutePicker, TextView buttonTextView, boolean animated) { + StringBuilder stringBuilder = new StringBuilder(); + if (dayPicker.getValue() != 0) { + stringBuilder.append(dayPicker.getValue()).append(LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays)); + } + if (hourPicker.getValue() != 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + stringBuilder.append(hourPicker.getValue()).append(LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours)); + } + if (minutePicker.getValue() != 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + stringBuilder.append(minutePicker.getValue() * 5).append(LocaleController.getString("SecretChatTimerMinutes", R.string.SecretChatTimerMinutes)); + } + if (stringBuilder.length() == 0) { + buttonTextView.setText(LocaleController.formatString("ChooseTimeForAutoDelete", R.string.ChooseTimeForAutoDelete)); + if (buttonTextView.isEnabled()) { + buttonTextView.setEnabled(false); + if (animated) { + buttonTextView.animate().alpha(0.5f); + } else { + buttonTextView.setAlpha(0.5f); + } + } + } else { + buttonTextView.setText(LocaleController.formatString("AutoDeleteAfter", R.string.AutoDeleteAfter, stringBuilder.toString())); + if (!buttonTextView.isEnabled()) { + buttonTextView.setEnabled(true); + if (animated) { + buttonTextView.animate().alpha(1f); + } else { + buttonTextView.setAlpha(1f); + } + } + } + } + private static void checkCalendarDate(long minDate, NumberPicker dayPicker, NumberPicker monthPicker, NumberPicker yearPicker) { int day = dayPicker.getValue(); int month = monthPicker.getValue(); @@ -2808,9 +3319,9 @@ public class AlertsCreator { dayPicker.setItemCount(count); monthPicker.setItemCount(count); yearPicker.setItemCount(count); - dayPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; - monthPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; - yearPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; + dayPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + monthPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + yearPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -2839,7 +3350,7 @@ public class AlertsCreator { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); linearLayout.setWeightSum(1.0f); - container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); long currentTime = System.currentTimeMillis(); @@ -2981,7 +3492,7 @@ public class AlertsCreator { } NotificationsController.getInstance(UserConfig.selectedAccount).setDialogNotificationsSettings(dialog_id, setting); if (BulletinFactory.canShowBulletin(fragment)) { - BulletinFactory.createMuteBulletin(fragment, setting, resourcesProvider).show(); + BulletinFactory.createMuteBulletin(fragment, setting, 0, resourcesProvider).show(); } } ); @@ -4169,42 +4680,6 @@ public class AlertsCreator { return alertDialog[0] = builder.create(); } -// public static AlertDialog createExpireDateAlert(final Context context, final boolean month, final int[] result, final Runnable callback) { -// AlertDialog.Builder builder = new AlertDialog.Builder(context); -// builder.setTitle(month ? LocaleController.getString("PaymentCardExpireDateMonth", R.string.PaymentCardExpireDateMonth) : LocaleController.getString("PaymentCardExpireDateYear", R.string.PaymentCardExpireDateYear)); -// final NumberPicker numberPicker = new NumberPicker(context); -// final int currentYear; -// if (month) { -// numberPicker.setMinValue(1); -// numberPicker.setMaxValue(12); -// currentYear = 0; -// } else { -// Calendar rightNow = Calendar.getInstance(); -// currentYear = rightNow.get(Calendar.YEAR); -// numberPicker.setMinValue(0); -// numberPicker.setMaxValue(30); -// } -// numberPicker.setFormatter(new NumberPicker.Formatter() { -// @Override -// public String format(int value) { -// if (month) { -// return String.format(Locale.US, "%02d", value); -// } else { -// return String.format(Locale.US, "%02d", value + currentYear); -// } -// } -// }); -// builder.setView(numberPicker); -// builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { -// @Override -// public void onClick(DialogInterface dialog, int which) { -// result[0] = month ? numberPicker.getValue() : ((numberPicker.getValue() + currentYear) % 100); -// callback.run(); -// } -// }); -// return builder.create(); -// } - public interface PaymentAlertDelegate { void didPressedNewCard(); } @@ -4220,7 +4695,7 @@ public class AlertsCreator { int currentAccount = fragment.getCurrentAccount(); AlertDialog.Builder builder = new AlertDialog.Builder(activity, resourcesProvider); - builder.setDimEnabled(hideDim == null); + builder.setDimAlpha(hideDim != null ? .5f : .6f); int count; if (selectedGroup != null) { count = selectedGroup.messages.size(); @@ -5092,4 +5567,8 @@ public class AlertsCreator { }); return popupWindow; } + + public interface SoundFrequencyDelegate { + void didSelectValues(int time, int minute); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java index 0fcc486b9..47cf91eab 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -136,18 +136,6 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(8, new ThreadPoolExecutor.DiscardPolicy()); - protected final Runnable mInvalidateTask = () -> { - invalidateTaskIsRunning = false; - if (!secondParentViews.isEmpty()) { - for (int a = 0, N = secondParentViews.size(); a < N; a++) { - secondParentViews.get(a).invalidate(); - } - } - if ((secondParentViews.isEmpty() || invalidateParentViewWithSecond) && parentView != null) { - parentView.invalidate(); - } - }; - private Runnable uiRunnableNoFrame = new Runnable() { @Override public void run() { @@ -832,4 +820,12 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { public boolean isRecycled() { return isRecycled; } + + public Bitmap getNextFrame() { + if (backgroundBitmap == null) { + backgroundBitmap = Bitmap.createBitmap((int) (metaData[0] * scaleFactor), (int) (metaData[1] * scaleFactor), Bitmap.Config.ARGB_8888); + } + getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime) ; + return backgroundBitmap; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimationProperties.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimationProperties.java index e8cebf3b5..c07ae1882 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimationProperties.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimationProperties.java @@ -53,6 +53,18 @@ public class AnimationProperties { } }; + public static final Property PAINT_COLOR = new IntProperty("color") { + @Override + public void setValue(Paint object, int value) { + object.setColor(value); + } + + @Override + public Integer get(Paint object) { + return object.getColor(); + } + }; + public static final Property COLOR_DRAWABLE_ALPHA = new IntProperty("alpha") { @Override public void setValue(ColorDrawable object, int value) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java new file mode 100644 index 000000000..875acaf2a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java @@ -0,0 +1,101 @@ +package org.telegram.ui.Components; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.view.View; + +import androidx.core.content.ContextCompat; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; + +public class AttachBotIntroTopView extends View { + private final static int ICONS_SIZE_DP = 42; + private final static int ICONS_SIDE_PADDING = 24; + + private ImageReceiver imageReceiver; + private Drawable attachDrawable; + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public AttachBotIntroTopView(Context context) { + super(context); + + imageReceiver = new ImageReceiver(this) { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + boolean set = super.setImageBitmapByKey(drawable, key, type, memCache, guid); + ValueAnimator anim = ValueAnimator.ofFloat(0, 1).setDuration(150); + anim.addUpdateListener(animation -> { + imageReceiver.setAlpha((Float) animation.getAnimatedValue()); + invalidate(); + }); + anim.start(); + return set; + } + }; + imageReceiver.setAlpha(0); + + attachDrawable = ContextCompat.getDrawable(context, R.drawable.input_attach).mutate().getConstantState().newDrawable(); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(AndroidUtilities.dp(3)); + paint.setStrokeCap(Paint.Cap.ROUND); + } + + public void setAttachBot(TLRPC.TL_attachMenuBot bot) { + TLRPC.TL_attachMenuBotIcon icon = MediaDataController.getStaticAttachMenuBotIcon(bot); + if (icon != null) { + imageReceiver.setImage(ImageLocation.getForDocument(icon.icon), "42_42", DocumentObject.getSvgThumb(icon.icon, Theme.key_dialogTextGray2, 1.0f), "svg", bot, 0); + } + } + + public void setBackgroundColor(int color) { + backgroundPaint.setColor(color); + } + + public void setColor(int color) { + attachDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); + paint.setColor(color); + imageReceiver.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + imageReceiver.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + imageReceiver.onDetachedFromWindow(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight() + AndroidUtilities.dp(6)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), backgroundPaint); + + imageReceiver.setImageCoords(getWidth() / 2f - AndroidUtilities.dp(ICONS_SIDE_PADDING + ICONS_SIZE_DP), getHeight() / 2f - AndroidUtilities.dp(ICONS_SIZE_DP) / 2f, AndroidUtilities.dp(ICONS_SIZE_DP), AndroidUtilities.dp(ICONS_SIZE_DP)); + imageReceiver.draw(canvas); + + canvas.drawLine(getWidth() / 2f - AndroidUtilities.dp(8), getHeight() / 2f, getWidth() / 2f + AndroidUtilities.dp(8), getHeight() / 2f, paint); + canvas.drawLine(getWidth() / 2f, getHeight() / 2f - AndroidUtilities.dp(8), getWidth() / 2f, getHeight() / 2f + AndroidUtilities.dp(8), paint); + + attachDrawable.setBounds(getWidth() / 2 + AndroidUtilities.dp(ICONS_SIDE_PADDING), getHeight() / 2 - AndroidUtilities.dp(ICONS_SIZE_DP) / 2, getWidth() / 2 + AndroidUtilities.dp(ICONS_SIDE_PADDING + ICONS_SIZE_DP), getHeight() / 2 + AndroidUtilities.dp(ICONS_SIZE_DP) / 2); + attachDrawable.draw(canvas); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java new file mode 100644 index 000000000..b526a38b4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java @@ -0,0 +1,105 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.util.TypedValue; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.Theme; + +public class AutoDeletePopupWrapper { + + View backItem; + public ActionBarPopupWindow.ActionBarPopupWindowLayout windowLayout; + private final ActionBarMenuSubItem disableItem; + Callback callback; + long lastDismissTime; + + public AutoDeletePopupWrapper(Context context, PopupSwipeBackLayout swipeBackLayout, Callback callback, boolean createBackground, Theme.ResourcesProvider resourcesProvider) { + windowLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(context, createBackground ? R.drawable.popup_fixed_alert : 0, resourcesProvider); + windowLayout.setFitItems(true); + this.callback = callback; + + if (swipeBackLayout != null) { + backItem = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_arrow_back, LocaleController.getString("Back", R.string.Back), false, resourcesProvider); + backItem.setOnClickListener(view -> { + swipeBackLayout.closeForeground(); + }); + } + + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_autodelete_1d, LocaleController.getString("AutoDelete1Day", R.string.AutoDelete1Day), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + callback.setAutoDeleteHistory(24 * 60 * 60, UndoView.ACTION_AUTO_DELETE_ON); + }); + item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_autodelete_1w, LocaleController.getString("AutoDelete7Days", R.string.AutoDelete7Days), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + callback.setAutoDeleteHistory(7 * 24 * 60 * 60, UndoView.ACTION_AUTO_DELETE_ON); + }); + item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_autodelete_1m, LocaleController.getString("AutoDelete1Month", R.string.AutoDelete1Month), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + callback.setAutoDeleteHistory(31 * 24 * 60 * 60, UndoView.ACTION_AUTO_DELETE_ON); + }); + item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_customize, LocaleController.getString("AutoDeleteCustom", R.string.AutoDeleteCustom), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + AlertsCreator.createAutoDeleteDatePickerDialog(context, (notify, timeInMinutes) -> { + callback.setAutoDeleteHistory(timeInMinutes * 60, timeInMinutes == 0 ? UndoView.ACTION_AUTO_DELETE_OFF : UndoView.ACTION_AUTO_DELETE_ON); + }); + }); + disableItem = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_disable, LocaleController.getString("AutoDeleteDisable", R.string.AutoDeleteDisable), false, resourcesProvider); + disableItem.setOnClickListener(view -> { + dismiss(); + callback.setAutoDeleteHistory(0, UndoView.ACTION_AUTO_DELETE_OFF); + }); + disableItem.setColors(Theme.getColor(Theme.key_dialogTextRed2), Theme.getColor(Theme.key_dialogTextRed2)); + + + View gap = new FrameLayout(context); + gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + gap.setTag(R.id.fit_width_tag, 1); + windowLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + + TextView textView = new TextView(context); + textView.setTag(R.id.fit_width_tag, 1); + textView.setPadding(AndroidUtilities.dp(13), AndroidUtilities.dp(8), AndroidUtilities.dp(13), AndroidUtilities.dp(8)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem)); + textView.setText(LocaleController.getString("AutoDeletePopupDescription", R.string.AutoDeletePopupDescription)); + windowLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + + private void dismiss() { + callback.dismiss(); + lastDismissTime = System.currentTimeMillis(); + } + + public void updateItems(int ttl) { + if (System.currentTimeMillis() - lastDismissTime < 200) { + AndroidUtilities.runOnUIThread(() -> { + updateItems(ttl); + }); + return; + } + if (ttl == 0) { + disableItem.setVisibility(View.GONE); + } else { + disableItem.setVisibility(View.VISIBLE); + } + } + + + public interface Callback { + void dismiss(); + void setAutoDeleteHistory(int time, int action); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java index d9f1f36ea..00d5713c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java @@ -11,6 +11,7 @@ package org.telegram.ui.Components; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.ColorFilter; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.BitmapDrawable; @@ -164,6 +165,7 @@ public class BackupImageView extends View { public void setSize(int w, int h) { width = w; height = h; + invalidate(); } @Override @@ -187,4 +189,8 @@ public class BackupImageView extends View { } imageReceiver.draw(canvas); } + + public void setColorFilter(ColorFilter colorFilter) { + imageReceiver.setColorFilter(colorFilter); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java index 99b67b2d0..acf1394ed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java @@ -42,13 +42,31 @@ public class BotCommandsMenuView extends View { invalidate(); } }; + RLottieDrawable webViewAnimation = new RLottieDrawable(R.raw.bot_webview_sheet_to_cross, String.valueOf(R.raw.bot_webview_sheet_to_cross) + hashCode(), AndroidUtilities.dp(20), AndroidUtilities.dp(20)) { + @Override + public void invalidateSelf() { + super.invalidateSelf(); + invalidate(); + } + + @Override + protected void invalidateInternal() { + super.invalidateInternal(); + invalidate(); + } + }; boolean expanded; float expandProgress; - StaticLayout menuText; + private String menuText = LocaleController.getString(R.string.BotsMenuTitle); + StaticLayout menuTextLayout; boolean isOpened; + boolean isWebView; + boolean isWebViewOpened; + Drawable backgroundDrawable; + boolean drawBackgroundDrawable = true; public BotCommandsMenuView(Context context) { super(context); @@ -59,10 +77,35 @@ public class BotCommandsMenuView extends View { backDrawable.setCallback(this); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); backDrawable.setRoundCap(); - backgroundDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(16), Color.TRANSPARENT, Theme.getColor(Theme.key_windowBackgroundWhite)); + backgroundDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(16), Color.TRANSPARENT, Theme.getColor(Theme.key_featuredStickers_addButtonPressed)); backgroundDrawable.setCallback(this); } + public void setDrawBackgroundDrawable(boolean drawBackgroundDrawable) { + this.drawBackgroundDrawable = drawBackgroundDrawable; + invalidate(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + webViewAnimation.addParentView(this); + webViewAnimation.setCurrentParentView(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + webViewAnimation.removeParentView(this); + } + + public void setWebView(boolean webView) { + isWebView = webView; + invalidate(); + } + private void updateColors() { paint.setColor(Theme.getColor(Theme.key_chat_messagePanelVoiceBackground)); int textColor = Theme.getColor(Theme.key_chat_messagePanelVoicePressed); @@ -76,18 +119,17 @@ public class BotCommandsMenuView extends View { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int size = MeasureSpec.getSize(widthMeasureSpec) + MeasureSpec.getSize(heightMeasureSpec) << 16; - if (lastSize != size || menuText == null) { + if (lastSize != size || menuTextLayout == null) { backDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); textPaint.setTextSize(AndroidUtilities.dp(15)); lastSize = size; - String string = LocaleController.getString("BotsMenuTitle", R.string.BotsMenuTitle); - int w = (int) textPaint.measureText(string); - menuText = StaticLayoutEx.createStaticLayout(string, textPaint, w, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, false, TextUtils.TruncateAt.END, w, 1); + int w = (int) textPaint.measureText(menuText); + menuTextLayout = StaticLayoutEx.createStaticLayout(menuText, textPaint, w, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, false, TextUtils.TruncateAt.END, w, 1); } - onTranslationChanged((menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress); + onTranslationChanged((menuTextLayout.getWidth() + AndroidUtilities.dp(4)) * expandProgress); int width = AndroidUtilities.dp(40); if (expanded) { - width += menuText.getWidth() + AndroidUtilities.dp(4); + width += menuTextLayout.getWidth() + AndroidUtilities.dp(4); } super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(32), MeasureSpec.EXACTLY)); @@ -95,7 +137,7 @@ public class BotCommandsMenuView extends View { @Override protected void dispatchDraw(Canvas canvas) { - if (menuText != null) { + if (menuTextLayout != null) { boolean update = false; if (expanded && expandProgress != 1f) { expandProgress += 16f / 150f; @@ -119,24 +161,41 @@ public class BotCommandsMenuView extends View { if (update && expandProgress > 0) { textPaint.setAlpha((int) (255 * expandProgress)); } - rectTmp.set(0, 0, AndroidUtilities.dp(40) + (menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress, getMeasuredHeight()); - canvas.drawRoundRect(rectTmp, AndroidUtilities.dp(16), AndroidUtilities.dp(16), paint); - backgroundDrawable.setBounds((int) rectTmp.left, (int) rectTmp.top, (int) rectTmp.right, (int) rectTmp.bottom); - backgroundDrawable.draw(canvas); - canvas.save(); - canvas.translate(AndroidUtilities.dp(8), AndroidUtilities.dp(4)); - backDrawable.draw(canvas); - canvas.restore(); + + if (drawBackgroundDrawable) { + rectTmp.set(0, 0, AndroidUtilities.dp(40) + (menuTextLayout.getWidth() + AndroidUtilities.dp(4)) * expandProgress, getMeasuredHeight()); + canvas.drawRoundRect(rectTmp, AndroidUtilities.dp(16), AndroidUtilities.dp(16), paint); + backgroundDrawable.setBounds((int) rectTmp.left, (int) rectTmp.top, (int) rectTmp.right, (int) rectTmp.bottom); + backgroundDrawable.draw(canvas); + } + + if (isWebView) { + canvas.save(); + canvas.translate(AndroidUtilities.dp(9.5f), AndroidUtilities.dp(6)); + RLottieDrawable drawable = webViewAnimation; + drawable.setBounds(0, 0, drawable.width, drawable.height); + drawable.draw(canvas); + canvas.restore(); + + if (drawable.isRunning()) { + invalidate(); + } + } else { + canvas.save(); + canvas.translate(AndroidUtilities.dp(8), AndroidUtilities.dp(4)); + backDrawable.draw(canvas); + canvas.restore(); + } if (expandProgress > 0) { canvas.save(); - canvas.translate(AndroidUtilities.dp(34), (getMeasuredHeight() - menuText.getHeight()) / 2f); - menuText.draw(canvas); + canvas.translate(AndroidUtilities.dp(34), (getMeasuredHeight() - menuTextLayout.getHeight()) / 2f); + menuTextLayout.draw(canvas); canvas.restore(); } if (update) { - onTranslationChanged((menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress); + onTranslationChanged((menuTextLayout.getWidth() + AndroidUtilities.dp(4)) * expandProgress); } } super.dispatchDraw(canvas); @@ -146,6 +205,12 @@ public class BotCommandsMenuView extends View { } + public void setMenuText(String menuText) { + this.menuText = menuText; + menuTextLayout = null; + requestLayout(); + } + public void setExpanded(boolean expanded, boolean animated) { if (this.expanded != expanded) { this.expanded = expanded; @@ -225,7 +290,21 @@ public class BotCommandsMenuView extends View { if (isOpened != opened) { isOpened = opened; } - backDrawable.setRotation(opened ? 1f : 0f, true); + if (isWebView) { + if (isWebViewOpened != opened) { + RLottieDrawable drawable = webViewAnimation; + if (!drawable.hasParentView()) { + drawable.addParentView(this); + } + drawable.stop(); + drawable.setPlayInDirectionOfCustomEndFrame(true); + drawable.setCustomEndFrame(opened ? drawable.getFramesCount() : 1); + drawable.start(); + isWebViewOpened = opened; + } + } else { + backDrawable.setRotation(opened ? 1f : 0f, true); + } } public static class BotCommandView extends LinearLayout { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java index 53fb3d62b..6a34acdef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java @@ -12,12 +12,15 @@ import android.content.Context; import android.util.TypedValue; import android.view.Gravity; import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; +import org.telegram.messenger.R; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; @@ -33,6 +36,7 @@ public class BotKeyboardView extends LinearLayout { private boolean isFullSize; private int buttonHeight; private ArrayList buttonViews = new ArrayList<>(); + private ArrayList buttonIcons = new ArrayList<>(); private ScrollView scrollView; public interface BotKeyboardViewDelegate { @@ -58,7 +62,8 @@ public class BotKeyboardView extends LinearLayout { setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelBackground)); for (int i = 0; i < buttonViews.size(); i++) { buttonViews.get(i).setTextColor(getThemedColor(Theme.key_chat_botKeyboardButtonText)); - buttonViews.get(i).setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); + buttonViews.get(i).setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); + buttonIcons.get(i).setColorFilter(getThemedColor(Theme.key_chat_botKeyboardButtonText)); } invalidate(); } @@ -87,6 +92,7 @@ public class BotKeyboardView extends LinearLayout { public void invalidateViews() { for (int a = 0; a < buttonViews.size(); a++) { buttonViews.get(a).invalidate(); + buttonIcons.get(a).invalidate(); } } @@ -98,6 +104,7 @@ public class BotKeyboardView extends LinearLayout { botButtons = buttons; container.removeAllViews(); buttonViews.clear(); + buttonIcons.clear(); scrollView.scrollTo(0, 0); if (buttons != null && botButtons.rows.size() != 0) { @@ -116,15 +123,29 @@ public class BotKeyboardView extends LinearLayout { TextView textView = new TextView(getContext()); textView.setTag(button); textView.setTextColor(getThemedColor(Theme.key_chat_botKeyboardButtonText)); - textView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); + textView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); textView.setGravity(Gravity.CENTER); + FrameLayout frame = new FrameLayout(getContext()); + frame.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + textView.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); textView.setText(Emoji.replaceEmoji(button.text, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(16), false)); - layout.addView(textView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, weight, 0, 0, b != row.buttons.size() - 1 ? 10 : 0, 0)); + layout.addView(frame, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, weight, 0, 0, b != row.buttons.size() - 1 ? 10 : 0, 0)); textView.setOnClickListener(v -> delegate.didPressedButton((TLRPC.KeyboardButton) v.getTag())); buttonViews.add(textView); + + ImageView icon = new ImageView(getContext()); + icon.setColorFilter(getThemedColor(Theme.key_chat_botKeyboardButtonText)); + if (button instanceof TLRPC.TL_keyboardButtonWebView || button instanceof TLRPC.TL_keyboardButtonSimpleWebView) { + icon.setImageResource(R.drawable.bot_webview); + icon.setVisibility(VISIBLE); + } else { + icon.setVisibility(GONE); + } + buttonIcons.add(icon); + frame.addView(icon, LayoutHelper.createFrame(12, 12, Gravity.RIGHT | Gravity.TOP, 0, 8, 8, 0)); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewContainer.java new file mode 100644 index 000000000..ce812854f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewContainer.java @@ -0,0 +1,800 @@ +package org.telegram.ui.Components; + +import android.Manifest; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.webkit.GeolocationPermissions; +import android.webkit.JavascriptInterface; +import android.webkit.PermissionRequest; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.core.util.Consumer; + +import org.json.JSONException; +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.browser.Browser; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.voip.CellFlickerDrawable; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class BotWebViewContainer extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { + private final static String DURGER_KING_USERNAME = "DurgerKingBot"; + private final static int REQUEST_CODE_WEB_VIEW_FILE = 3000, REQUEST_CODE_WEB_PERMISSION = 4000; + + private final static List WHITELISTED_SCHEMES = Arrays.asList("http", "https"); + + private WebView webView; + private String mUrl; + private Delegate delegate; + private WebViewScrollListener webViewScrollListener; + private Theme.ResourcesProvider resourcesProvider; + + private CellFlickerDrawable flickerDrawable = new CellFlickerDrawable(); + private BackupImageView flickerView; + private boolean isFlickeringCenter; + + private Consumer webViewProgressListener; + + private ValueCallback mFilePathCallback; + + private int lastButtonColor = Theme.getColor(Theme.key_featuredStickers_addButton); + private int lastButtonTextColor = Theme.getColor(Theme.key_featuredStickers_buttonText); + private String lastButtonText = ""; + private String buttonData; + + private boolean isPageLoaded; + private int viewPortOffset; + private boolean lastExpanded; + + private boolean hasUserPermissions; + private TLRPC.User botUser; + private Runnable onPermissionsRequestResultCallback; + + private Activity parentActivity; + + @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"}) + public BotWebViewContainer(@NonNull Context context, Theme.ResourcesProvider resourcesProvider, int backgroundColor) { + super(context); + this.resourcesProvider = resourcesProvider; + + if (context instanceof Activity) { + this.parentActivity = (Activity) context; + } + + flickerDrawable.drawFrame = false; + flickerDrawable.setColors(backgroundColor, 0x99, 0xCC); + flickerView = new BackupImageView(context) { + { + imageReceiver = new ImageReceiver(this) { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + boolean set = super.setImageBitmapByKey(drawable, key, type, memCache, guid); + ValueAnimator anim = ValueAnimator.ofFloat(0, 1).setDuration(300); + anim.addUpdateListener(animation -> { + imageReceiver.setAlpha((Float) animation.getAnimatedValue()); + invalidate(); + }); + anim.start(); + return set; + } + }; + } + + @Override + protected void onDraw(Canvas canvas) { + if (isFlickeringCenter) { + super.onDraw(canvas); + } else { + Drawable drawable = imageReceiver.getDrawable(); + if (drawable != null) { + imageReceiver.setImageCoords(0, 0, getWidth(), drawable.getIntrinsicHeight() * ((float) getWidth() / drawable.getIntrinsicWidth())); + imageReceiver.draw(canvas); + } + } + } + }; + flickerView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundGray), PorterDuff.Mode.SRC_IN)); + flickerView.getImageReceiver().setAspectFit(true); + addView(flickerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); + + webView = new WebView(context) { + private int prevScrollX, prevScrollY; + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + + if (webViewScrollListener != null) { + webViewScrollListener.onWebViewScrolled(this, getScrollX() - prevScrollX, getScrollY() - prevScrollY); + } + + prevScrollX = getScrollX(); + prevScrollY = getScrollY(); + } + + @Override + public void setScrollX(int value) { + super.setScrollX(value); + prevScrollX = value; + } + + @Override + public void setScrollY(int value) { + super.setScrollY(value); + prevScrollY = value; + } + + @Override + public boolean onCheckIsTextEditor() { + return true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY)); + } + }; + webView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + WebSettings settings = webView.getSettings(); + settings.setJavaScriptEnabled(true); + settings.setGeolocationEnabled(true); + GeolocationPermissions.getInstance().clearAll(); + + webView.setWebViewClient(new WebViewClient() { + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Uri uriOrig = Uri.parse(mUrl); + Uri uriNew = Uri.parse(url); + + boolean override; + if (isPageLoaded && (!Objects.equals(uriOrig.getHost(), uriNew.getHost()) || !Objects.equals(uriOrig.getPath(), uriNew.getPath()))) { + override = true; + + if (WHITELISTED_SCHEMES.contains(uriNew.getScheme())) { + new AlertDialog.Builder(context, resourcesProvider) + .setTitle(LocaleController.getString(R.string.OpenUrlTitle)) + .setMessage(LocaleController.formatString(R.string.OpenUrlAlert2, uriNew.toString())) + .setPositiveButton(LocaleController.getString(R.string.Open), (dialog, which) -> { + boolean[] forceBrowser = {false}; + boolean internal = Browser.isInternalUri(uriNew, forceBrowser); + Browser.openUrl(getContext(), uriNew, true, false); + if (internal && delegate != null) { + delegate.onCloseRequested(); + } + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + } + } else { + override = false; + } + + return override; + } + + @Override + public void onPageFinished(WebView view, String url) { + setPageLoaded(url); + } + }); + webView.setWebChromeClient(new WebChromeClient() { + private Dialog lastPermissionsDialog; + + @Override + public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { + Context ctx = getContext(); + if (!(ctx instanceof Activity)) { + return false; + } + Activity activity = (Activity) ctx; + + if (mFilePathCallback != null) { + mFilePathCallback.onReceiveValue(null); + } + + mFilePathCallback = filePathCallback; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + activity.startActivityForResult(fileChooserParams.createIntent(), REQUEST_CODE_WEB_VIEW_FILE); + } else { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + activity.startActivityForResult(Intent.createChooser(intent, LocaleController.getString(R.string.BotWebViewFileChooserTitle)), REQUEST_CODE_WEB_VIEW_FILE); + } + + return true; + } + + @Override + public void onProgressChanged(WebView view, int newProgress) { + if (webViewProgressListener != null) { + webViewProgressListener.accept(newProgress / 100f); + } + } + + @Override + public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { + if (parentActivity == null) { + callback.invoke(origin, false, false); + return; + } + lastPermissionsDialog = AlertsCreator.createWebViewPermissionsRequestDialog(parentActivity, resourcesProvider, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, R.raw.permission_request_location, LocaleController.formatString(R.string.BotWebViewRequestGeolocationPermission, UserObject.getUserName(botUser)), LocaleController.formatString(R.string.BotWebViewRequestGeolocationPermissionWithHint, UserObject.getUserName(botUser)), allow -> { + if (lastPermissionsDialog != null) { + lastPermissionsDialog = null; + + if (allow) { + runWithPermissions(new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, allowSystem -> { + callback.invoke(origin, allowSystem, false); + if (allowSystem) { + hasUserPermissions = true; + } + }); + } else { + callback.invoke(origin, false, false); + } + } + }); + lastPermissionsDialog.show(); + } + + @Override + public void onGeolocationPermissionsHidePrompt() { + if (lastPermissionsDialog != null){ + lastPermissionsDialog.dismiss(); + lastPermissionsDialog = null; + } + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public void onPermissionRequest(PermissionRequest request) { + if (lastPermissionsDialog != null){ + lastPermissionsDialog.dismiss(); + lastPermissionsDialog = null; + } + + String[] resources = request.getResources(); + if (resources.length == 1) { + String resource = resources[0]; + + if (parentActivity == null) { + request.deny(); + return; + } + + switch (resource) { + case PermissionRequest.RESOURCE_AUDIO_CAPTURE: { + lastPermissionsDialog = AlertsCreator.createWebViewPermissionsRequestDialog(parentActivity, resourcesProvider, new String[] {Manifest.permission.RECORD_AUDIO}, R.raw.permission_request_microphone, LocaleController.formatString(R.string.BotWebViewRequestMicrophonePermission, UserObject.getUserName(botUser)), LocaleController.formatString(R.string.BotWebViewRequestMicrophonePermissionWithHint, UserObject.getUserName(botUser)), allow -> { + if (lastPermissionsDialog != null) { + lastPermissionsDialog = null; + + if (allow) { + runWithPermissions(new String[] {Manifest.permission.RECORD_AUDIO}, allowSystem -> { + if (allowSystem) { + request.grant(new String[] {resource}); + hasUserPermissions = true; + } else { + request.deny(); + } + }); + } else { + request.deny(); + } + } + }); + lastPermissionsDialog.show(); + break; + } + case PermissionRequest.RESOURCE_VIDEO_CAPTURE: { + lastPermissionsDialog = AlertsCreator.createWebViewPermissionsRequestDialog(parentActivity, resourcesProvider, new String[] {Manifest.permission.CAMERA}, R.raw.permission_request_camera, LocaleController.formatString(R.string.BotWebViewRequestCameraPermission, UserObject.getUserName(botUser)), LocaleController.formatString(R.string.BotWebViewRequestCameraPermissionWithHint, UserObject.getUserName(botUser)), allow -> { + if (lastPermissionsDialog != null) { + lastPermissionsDialog = null; + + if (allow) { + runWithPermissions(new String[] {Manifest.permission.CAMERA}, allowSystem -> { + if (allowSystem) { + request.grant(new String[] {resource}); + hasUserPermissions = true; + } else { + request.deny(); + } + }); + } else { + request.deny(); + } + } + }); + lastPermissionsDialog.show(); + break; + } + } + } + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public void onPermissionRequestCanceled(PermissionRequest request) { + if (lastPermissionsDialog != null){ + lastPermissionsDialog.dismiss(); + lastPermissionsDialog = null; + } + } + }); + webView.setAlpha(0f); + addView(webView); + + // We can't use javascript interface because of minSDK 16, it can be exploited because of reflection access + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + webView.addJavascriptInterface(new WebViewProxy(), "TelegramWebviewProxy"); + } + } + + private void setPageLoaded(String url) { + if (isPageLoaded) { + return; + } + AnimatorSet set = new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofFloat(webView, View.ALPHA, 1f), + ObjectAnimator.ofFloat(flickerView, View.ALPHA, 0f) + ); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + flickerView.setVisibility(GONE); + } + }); + set.start(); + mUrl = url; + isPageLoaded = true; + } + + public boolean hasUserPermissions() { + return hasUserPermissions; + } + + public void setBotUser(TLRPC.User botUser) { + this.botUser = botUser; + } + + private void runWithPermissions(String[] permissions, Consumer callback) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + callback.accept(true); + } else { + if (checkPermissions(permissions)) { + callback.accept(true); + } else { + onPermissionsRequestResultCallback = ()-> callback.accept(checkPermissions(permissions)); + + if (parentActivity != null) { + parentActivity.requestPermissions(permissions, REQUEST_CODE_WEB_PERMISSION); + } + } + } + } + + public void setParentActivity(Activity parentActivity) { + this.parentActivity = parentActivity; + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private boolean checkPermissions(String[] permissions) { + for (String perm : permissions) { + if (getContext().checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } + + public void restoreButtonData() { + if (buttonData != null) { + onEventReceived("web_app_setup_main_button", buttonData); + } + } + + public void onMainButtonPressed() { + evaluateJs("window.Telegram.WebView.receiveEvent('main_button_pressed', null);"); + } + + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == REQUEST_CODE_WEB_PERMISSION) { + if (onPermissionsRequestResultCallback != null) { + onPermissionsRequestResultCallback.run(); + onPermissionsRequestResultCallback = null; + } + } + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_WEB_VIEW_FILE && mFilePathCallback != null) { + Uri[] results = null; + + if (resultCode == Activity.RESULT_OK) { + if (data != null && data.getDataString() != null) { + results = new Uri[] {Uri.parse(data.getDataString())}; + } + } + + mFilePathCallback.onReceiveValue(results); + mFilePathCallback = null; + } + } + + public void setViewPortOffset(int viewPortOffset) { + this.viewPortOffset = viewPortOffset; + invalidateViewPortHeight(true); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + invalidateViewPortHeight(true); + } + + public void invalidateViewPortHeight() { + invalidateViewPortHeight(false); + } + + public void invalidateViewPortHeight(boolean isStable) { + invalidateViewPortHeight(isStable, false); + } + + public void invalidateViewPortHeight(boolean isStable, boolean force) { + if (!isPageLoaded && !force) { + return; + } + + if (getParent() instanceof ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer) { + ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer swipeContainer = (ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer) getParent(); + + if (isStable) { + lastExpanded = swipeContainer.getSwipeOffsetY() == -swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY(); + } + + int viewPortHeight = (int) (swipeContainer.getMeasuredHeight() - swipeContainer.getOffsetY() - swipeContainer.getSwipeOffsetY() + swipeContainer.getTopActionBarOffsetY() + viewPortOffset); + try { + JSONObject data = new JSONObject(); + data.put("height", viewPortHeight / AndroidUtilities.density); + data.put("is_state_stable", isStable); + data.put("is_expanded", lastExpanded); + evaluateJs("window.Telegram.WebView.receiveEvent('viewport_changed', " + data + ");"); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == flickerView) { + if (isFlickeringCenter) { + canvas.save(); + View parent = (View) BotWebViewContainer.this.getParent(); + canvas.translate(0, (ActionBar.getCurrentActionBarHeight() - parent.getTranslationY()) / 2f); + } + boolean draw = super.drawChild(canvas, child, drawingTime); + if (isFlickeringCenter) { + canvas.restore(); + } + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + flickerDrawable.draw(canvas, AndroidUtilities.rectTmp, 0); + invalidate(); + return draw; + } + return super.drawChild(canvas, child, drawingTime); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + flickerDrawable.setParentWidth(BotWebViewContainer.this.getMeasuredWidth()); + } + + public void setWebViewProgressListener(Consumer webViewProgressListener) { + this.webViewProgressListener = webViewProgressListener; + } + + public WebView getWebView() { + return webView; + } + + public void loadFlicker(int currentAccount, long botId) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(botId); + if (user.username != null && Objects.equals(user.username, DURGER_KING_USERNAME)) { + flickerView.setVisibility(VISIBLE); + flickerView.setAlpha(1f); + flickerView.setImageDrawable(SvgHelper.getDrawable(R.raw.durgerking_placeholder, Theme.getColor(Theme.key_windowBackgroundGray))); + setupFlickerParams(false); + return; + } + + TLRPC.TL_attachMenuBot cachedBot = null; + for (TLRPC.TL_attachMenuBot bot : MediaDataController.getInstance(currentAccount).getAttachMenuBots().bots) { + if (bot.bot_id == botId) { + cachedBot = bot; + break; + } + } + + if (cachedBot != null) { + boolean center = false; + TLRPC.TL_attachMenuBotIcon botIcon = MediaDataController.getPlaceholderStaticAttachMenuBotIcon(cachedBot); + if (botIcon == null) { + botIcon = MediaDataController.getStaticAttachMenuBotIcon(cachedBot); + center = true; + } + if (botIcon != null) { + flickerView.setVisibility(VISIBLE); + flickerView.setAlpha(1f); + flickerView.setImage(ImageLocation.getForDocument(botIcon.icon), null, (Drawable) null, cachedBot); + setupFlickerParams(center); + } + } else { + TLRPC.TL_messages_getAttachMenuBot req = new TLRPC.TL_messages_getAttachMenuBot(); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_attachMenuBotsBot) { + TLRPC.TL_attachMenuBot bot = ((TLRPC.TL_attachMenuBotsBot) response).bot; + + boolean center = false; + TLRPC.TL_attachMenuBotIcon botIcon = MediaDataController.getPlaceholderStaticAttachMenuBotIcon(bot); + if (botIcon == null) { + botIcon = MediaDataController.getStaticAttachMenuBotIcon(bot); + center = true; + } + if (botIcon != null) { + flickerView.setVisibility(VISIBLE); + flickerView.setAlpha(1f); + flickerView.setImage(ImageLocation.getForDocument(botIcon.icon), null, (Drawable) null, bot); + setupFlickerParams(center); + } + } + })); + } + } + + private void setupFlickerParams(boolean center) { + isFlickeringCenter = center; + FrameLayout.LayoutParams params = (LayoutParams) flickerView.getLayoutParams(); + params.gravity = center ? Gravity.CENTER : Gravity.TOP; + if (center) { + params.width = params.height = AndroidUtilities.dp(64); + } else { + params.width = LayoutParams.MATCH_PARENT; + params.height = LayoutParams.WRAP_CONTENT; + } + + flickerView.requestLayout(); + } + + public void loadUrl(String url) { + isPageLoaded = false; + hasUserPermissions = false; + mUrl = url; + webView.loadUrl(url); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didSetNewTheme); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.onActivityResultReceived); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.onRequestPermissionResultReceived); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewTheme); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.onActivityResultReceived); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.onRequestPermissionResultReceived); + } + + public void destroyWebView() { + webView.destroy(); + } + + @SuppressWarnings("deprecation") + public void evaluateJs(String script) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + webView.evaluateJavascript(script, value -> {}); + } else { + try { + webView.loadUrl("javascript:" + URLEncoder.encode(script, "UTF-8")); + } catch (UnsupportedEncodingException e) { + webView.loadUrl("javascript:" + URLEncoder.encode(script)); + } + } + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.didSetNewTheme) { + evaluateJs("window.Telegram.WebView.receiveEvent('theme_changed', {theme_params: " + buildThemeParams() + "});"); + } else if (id == NotificationCenter.onActivityResultReceived) { + onActivityResult((int) args[0], (int) args[1], (Intent) args[2]); + } else if (id == NotificationCenter.onRequestPermissionResultReceived) { + onRequestPermissionsResult((int) args[0], (String[]) args[1], (int[]) args[2]); + } + } + + public void setWebViewScrollListener(WebViewScrollListener webViewScrollListener) { + this.webViewScrollListener = webViewScrollListener; + } + + public void setDelegate(Delegate delegate) { + this.delegate = delegate; + } + + private void onEventReceived(String eventType, String eventData) { + switch (eventType) { + case "web_app_close": { + delegate.onCloseRequested(); + break; + } + case "web_app_data_send": { + delegate.onSendWebViewData(eventData); + break; + } + case "web_app_expand": { + delegate.onWebAppExpand(); + break; + } + case "web_app_request_viewport": { + boolean hasSwipeInProgress = getParent() instanceof ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer && ((ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer) getParent()).isSwipeInProgress(); + invalidateViewPortHeight(!hasSwipeInProgress, true); + break; + } + case "web_app_ready": { + setPageLoaded(webView.getUrl()); + break; + } + case "web_app_setup_main_button": { + try { + JSONObject info = new JSONObject(eventData); + boolean isActive = info.optBoolean("is_active", false); + String text = info.optString("text", lastButtonText).trim(); + boolean isVisible = info.optBoolean("is_visible", false) && !TextUtils.isEmpty(text); + int color = info.has("color") ? Color.parseColor(info.optString("color")) : lastButtonColor; + int textColor = info.has("text_color") ? Color.parseColor(info.optString("text_color")) : lastButtonTextColor; + boolean isProgressVisible = info.optBoolean("is_progress_visible", false) && isVisible; + + lastButtonColor = color; + lastButtonTextColor = textColor; + lastButtonText = text; + buttonData = eventData; + + delegate.onSetupMainButton(isVisible, isActive, text, color, textColor, isProgressVisible); + } catch (JSONException | IllegalArgumentException e) { + FileLog.e(e); + } + break; + } + } + } + + private String buildThemeParams() { + try { + JSONObject object = new JSONObject(); + object.put("bg_color", formatColor(Theme.key_windowBackgroundWhite)); + object.put("text_color", formatColor(Theme.key_windowBackgroundWhiteBlackText)); + object.put("hint_color", formatColor(Theme.key_windowBackgroundWhiteHintText)); + object.put("link_color", formatColor(Theme.key_windowBackgroundWhiteLinkText)); + object.put("button_color", formatColor(Theme.key_featuredStickers_addButton)); + object.put("button_text_color", formatColor(Theme.key_featuredStickers_buttonText)); + return object.toString(); + } catch (Exception e) { + FileLog.e(e); + return "{}"; + } + } + + private String formatColor(String colorKey) { + Integer color = resourcesProvider != null ? resourcesProvider.getColor(colorKey) : Theme.getColor(colorKey); + if (color == null) { + color = Theme.getColor(colorKey); + } + return "#" + hexFixed(Color.red(color)) + hexFixed(Color.green(color)) + hexFixed(Color.blue(color)); + } + + private String hexFixed(int h) { + String hex = Integer.toHexString(h); + if (hex.length() < 2) { + hex = "0" + hex; + } + return hex; + } + + private class WebViewProxy { + @JavascriptInterface + public void postEvent(String eventType, String eventData) { + AndroidUtilities.runOnUIThread(() -> onEventReceived(eventType, eventData)); + } + } + + public interface WebViewScrollListener { + /** + * Called when WebView scrolls + * + * @param webView WebView that scrolled + * @param dx Delta X + * @param dy Delta Y + */ + void onWebViewScrolled(WebView webView, int dx, int dy); + } + + public interface Delegate { + /** + * Called when WebView requests to close itself + */ + void onCloseRequested(); + + /** + * Called when WebView requests to send custom data + * + * @param data Custom data to send + */ + void onSendWebViewData(String data); + + /** + * Called when WebView requests to expand viewport + */ + void onWebAppExpand(); + + /** + * Setups main button + */ + void onSetupMainButton(boolean isVisible, boolean isActive, String text, int color, int textColor, boolean isProgressVisible); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewMenuContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewMenuContainer.java new file mode 100644 index 000000000..5f90713d3 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewMenuContainer.java @@ -0,0 +1,657 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Build; +import android.text.Editable; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; +import androidx.recyclerview.widget.ChatListItemAnimator; + +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; + +import java.util.Objects; + +public class BotWebViewMenuContainer extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { + private final static int POLL_PERIOD = 60000; + + private final static SimpleFloatPropertyCompat ACTION_BAR_TRANSITION_PROGRESS_VALUE = new SimpleFloatPropertyCompat("actionBarTransitionProgress", obj -> obj.actionBarTransitionProgress, (obj, value) -> { + obj.actionBarTransitionProgress = value; + obj.invalidate(); + + int subtitleColor = ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefaultSubtitle), obj.getColor(Theme.key_windowBackgroundWhiteGrayText), value); + ChatActivity chatActivity = obj.parentEnterView.getParentFragment(); + ActionBar actionBar = chatActivity.getActionBar(); + actionBar.setBackgroundColor(ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefault), obj.getColor(Theme.key_windowBackgroundWhite), value)); + actionBar.setItemsColor(ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefaultIcon), obj.getColor(Theme.key_windowBackgroundWhiteBlackText), value), false); + actionBar.setItemsBackgroundColor(ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefaultSelector), obj.getColor(Theme.key_actionBarWhiteSelector), value), false); + actionBar.setSubtitleColor(subtitleColor); + + ChatAvatarContainer chatAvatarContainer = chatActivity.getAvatarContainer(); + chatAvatarContainer.getTitleTextView().setTextColor(ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefaultTitle), obj.getColor(Theme.key_windowBackgroundWhiteBlackText), value)); + chatAvatarContainer.getSubtitleTextView().setTextColor(subtitleColor); + chatAvatarContainer.setOverrideSubtitleColor(value == 0 ? null : subtitleColor); + + obj.updateLightStatusBar(); + }).setMultiplier(100f); + + private float actionBarTransitionProgress; + private SpringAnimation springAnimation; + private ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer swipeContainer; + private ChatAttachAlertBotWebViewLayout.WebProgressView progressView; + private boolean ignoreLayout; + private BotWebViewContainer webViewContainer; + private BotWebViewContainer.Delegate webViewDelegate; + private ValueAnimator webViewScrollAnimator; + private boolean ignoreMeasure; + + private Paint dimPaint = new Paint(); + private Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint linePaint = new Paint(); + + private ChatActivityEnterView parentEnterView; + private boolean botWebViewButtonWasVisible; + private SpringAnimation botWebViewButtonAnimator; + + private long lastSwipeTime; + + private int currentAccount; + private long botId; + private String botUrl; + + private boolean isLoaded; + private boolean dismissed; + + private Boolean wasLightStatusBar; + private long queryId; + + private ActionBarMenuItem botMenuItem; + private ActionBar.ActionBarMenuOnItemClick actionBarOnItemClick; + + private Editable savedEditText; + private MessageObject savedReplyMessageObject; + private MessageObject savedEditMessageObject; + + private Runnable pollRunnable = () -> { + if (!dismissed) { + TLRPC.TL_messages_prolongWebView prolongWebView = new TLRPC.TL_messages_prolongWebView(); + prolongWebView.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + prolongWebView.peer = MessagesController.getInstance(currentAccount).getInputPeer(botId); + prolongWebView.query_id = queryId; + + ConnectionsManager.getInstance(currentAccount).sendRequest(prolongWebView, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (dismissed) { + return; + } + if (error != null) { + dismiss(); + } else { + AndroidUtilities.runOnUIThread(this.pollRunnable, POLL_PERIOD); + } + })); + } + }; + + public BotWebViewMenuContainer(@NonNull Context context, ChatActivityEnterView parentEnterView) { + super(context); + + this.parentEnterView = parentEnterView; + ChatActivity chatActivity = parentEnterView.getParentFragment(); + ActionBar actionBar = chatActivity.getActionBar(); + ActionBarMenu menu = actionBar.createMenu(); + botMenuItem = menu.addItem(1000, R.drawable.ic_ab_other); + botMenuItem.setVisibility(GONE); + + botMenuItem.addSubItem(R.id.menu_reload_page, R.drawable.msg_retry, LocaleController.getString(R.string.BotWebViewReloadPage)); + actionBarOnItemClick = actionBar.getActionBarMenuOnItemClick(); + + webViewContainer = new BotWebViewContainer(context, parentEnterView.getParentFragment().getResourceProvider(), getColor(Theme.key_windowBackgroundWhite)); + webViewContainer.setViewPortOffset(-AndroidUtilities.dp(5)); + webViewContainer.setDelegate(webViewDelegate = new BotWebViewContainer.Delegate() { + private boolean sentWebViewData; + + @Override + public void onCloseRequested() { + dismiss(); + } + + @Override + public void onSendWebViewData(String data) { + if (sentWebViewData) { + return; + } + sentWebViewData = true; + + TLRPC.TL_messages_sendWebViewData sendWebViewData = new TLRPC.TL_messages_sendWebViewData(); + sendWebViewData.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + sendWebViewData.random_id = Utilities.random.nextLong(); + sendWebViewData.button_text = "Menu"; + sendWebViewData.data = data; + ConnectionsManager.getInstance(currentAccount).sendRequest(sendWebViewData, (response, error) -> AndroidUtilities.runOnUIThread(()-> dismiss())); + } + + @Override + public void onWebAppExpand() { + if (System.currentTimeMillis() - lastSwipeTime <= 1000 || swipeContainer.isSwipeInProgress()) { + return; + } + swipeContainer.stickTo(-swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY()); + } + + @Override + public void onSetupMainButton(boolean isVisible, boolean isActive, String text, int color, int textColor, boolean isProgressVisible) { + ChatActivityBotWebViewButton botWebViewButton = parentEnterView.getBotWebViewButton(); + botWebViewButton.setupButtonParams(isActive, text, color, textColor, isProgressVisible); + botWebViewButton.setOnClickListener(v -> webViewContainer.onMainButtonPressed()); + if (isVisible != botWebViewButtonWasVisible) { + animateBotButton(isVisible); + } + } + }); + + linePaint.setStyle(Paint.Style.FILL_AND_STROKE); + linePaint.setStrokeWidth(AndroidUtilities.dp(4)); + linePaint.setStrokeCap(Paint.Cap.ROUND); + + dimPaint.setColor(0x40000000); + backgroundPaint.setColor(getColor(Theme.key_windowBackgroundWhite)); + + swipeContainer = new ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int availableHeight = MeasureSpec.getSize(heightMeasureSpec); + + int padding; + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + padding = (int) (availableHeight / 3.5f); + } else { + padding = (availableHeight / 5 * 2); + } + if (padding < 0) { + padding = 0; + } + + if (getOffsetY() != padding) { + ignoreLayout = true; + setOffsetY(padding); + ignoreLayout = false; + } + + if (AndroidUtilities.isTablet() && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isSmallTablet()) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.8f), MeasureSpec.EXACTLY); + } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.statusBarHeight + AndroidUtilities.dp(24), MeasureSpec.EXACTLY)); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + swipeContainer.setWebView(webViewContainer.getWebView()); + swipeContainer.setScrollListener(() -> { + if (swipeContainer.getSwipeOffsetY() > 0) { + dimPaint.setAlpha((int) (0x40 * (1f - Math.min(swipeContainer.getSwipeOffsetY(), swipeContainer.getHeight()) / (float)swipeContainer.getHeight()))); + } else { + dimPaint.setAlpha(0x40); + } + invalidate(); + webViewContainer.invalidateViewPortHeight(); + + if (springAnimation != null) { + float progress = (1f - Math.min(swipeContainer.getTopActionBarOffsetY(), swipeContainer.getTranslationY() - swipeContainer.getTopActionBarOffsetY()) / swipeContainer.getTopActionBarOffsetY()); + float newPos = (progress > 0.5f ? 1 : 0) * 100f; + if (springAnimation.getSpring().getFinalPosition() != newPos) { + springAnimation.getSpring().setFinalPosition(newPos); + springAnimation.start(); + } + } + lastSwipeTime = System.currentTimeMillis(); + }); + swipeContainer.setScrollEndListener(()-> webViewContainer.invalidateViewPortHeight(true)); + swipeContainer.addView(webViewContainer); + swipeContainer.setDelegate(this::dismiss); + swipeContainer.setTopActionBarOffsetY(ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight - AndroidUtilities.dp(24)); + swipeContainer.setSwipeOffsetAnimationDisallowed(true); + addView(swipeContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, 24, 0, 0)); + + addView(progressView = new ChatAttachAlertBotWebViewLayout.WebProgressView(context, parentEnterView.getParentFragment().getResourceProvider()), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 0, 0, 0, 5)); + webViewContainer.setWebViewProgressListener(progress -> { + progressView.setLoadProgressAnimated(progress); + if (progress == 1f) { + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> progressView.setAlpha((Float) animation.getAnimatedValue())); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressView.setVisibility(GONE); + } + }); + animator.start(); + } + }); + + setWillNotDraw(false); + } + + private void animateBotButton(boolean isVisible) { + ChatActivityBotWebViewButton botWebViewButton = parentEnterView.getBotWebViewButton(); + if (botWebViewButtonAnimator != null) { + botWebViewButtonAnimator.cancel(); + botWebViewButtonAnimator = null; + } + + botWebViewButton.setProgress(isVisible ? 0f : 1f); + if (isVisible) { + botWebViewButton.setVisibility(VISIBLE); + } + + botWebViewButtonAnimator = new SpringAnimation(botWebViewButton, ChatActivityBotWebViewButton.PROGRESS_PROPERTY) + .setSpring(new SpringForce((isVisible ? 1f : 0f) * ChatActivityBotWebViewButton.PROGRESS_PROPERTY.getMultiplier()) + .setStiffness(isVisible ? 600f : 750f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY) + ) + .addUpdateListener((animation, value, velocity) -> { + float v = value / ChatActivityBotWebViewButton.PROGRESS_PROPERTY.getMultiplier(); + parentEnterView.setBotWebViewButtonOffsetX(AndroidUtilities.dp(64) * v); + parentEnterView.setComposeShadowAlpha(1f - v); + }) + .addEndListener((animation, canceled, value, velocity) -> { + if (!isVisible) { + botWebViewButton.setVisibility(GONE); + } + if (botWebViewButtonAnimator == animation) { + botWebViewButtonAnimator = null; + } + }); + botWebViewButtonAnimator.start(); + botWebViewButtonWasVisible = isVisible; + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (springAnimation == null) { + springAnimation = new SpringAnimation(this, ACTION_BAR_TRANSITION_PROGRESS_VALUE) + .setSpring(new SpringForce() + .setStiffness(1200f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY) + ) + .addEndListener((animation, canceled, value, velocity) -> { + ChatActivity chatActivity = parentEnterView.getParentFragment(); + ChatAvatarContainer chatAvatarContainer = chatActivity.getAvatarContainer(); + chatAvatarContainer.setClickable(value == 0); + chatAvatarContainer.getAvatarImageView().setClickable(value == 0); + + ActionBar actionBar = chatActivity.getActionBar(); + if (value == 100) { + chatActivity.showHeaderItem(false); + botMenuItem.setVisibility(VISIBLE); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + dismiss(); + } else if (id == R.id.menu_reload_page) { + webViewContainer.getWebView().animate().cancel(); + webViewContainer.getWebView().animate().alpha(0).start(); + + isLoaded = false; + loadWebView(); + } + } + }); + } else { + chatActivity.showHeaderItem(true); + botMenuItem.setVisibility(GONE); + actionBar.setActionBarMenuOnItemClick(actionBarOnItemClick); + } + }); + } + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.webViewResultSent); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + if (springAnimation != null) { + springAnimation.cancel(); + springAnimation = null; + } + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.webViewResultSent); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (ignoreMeasure) { + setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight()); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + public void onPanTransitionStart(boolean keyboardVisible, int contentHeight) { + if (!keyboardVisible) { + return; + } + + int oldh = contentHeight + parentEnterView.getSizeNotifierLayout().measureKeyboardHeight(); + setMeasuredDimension(getMeasuredWidth(), contentHeight); + ignoreMeasure = true; + + if (webViewScrollAnimator != null) { + webViewScrollAnimator.cancel(); + webViewScrollAnimator = null; + } + + int fromY = webViewContainer.getWebView().getScrollY(); + int toY = fromY + (oldh - contentHeight); + webViewScrollAnimator = ValueAnimator.ofInt(fromY, toY).setDuration(250); + webViewScrollAnimator.setInterpolator(ChatListItemAnimator.DEFAULT_INTERPOLATOR); + webViewScrollAnimator.addUpdateListener(animation -> { + int val = (int) animation.getAnimatedValue(); + webViewContainer.getWebView().setScrollY(val); + }); + webViewScrollAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + webViewContainer.getWebView().setScrollY(toY); + if (animation == webViewScrollAnimator) { + webViewScrollAnimator = null; + } + } + }); + webViewScrollAnimator.start(); + } + + public void onPanTransitionEnd() { + ignoreMeasure = false; + requestLayout(); + } + + private void updateLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + boolean lightStatusBar = ColorUtils.calculateLuminance(color) >= 0.9 && actionBarTransitionProgress >= 0.85f; + + if (wasLightStatusBar != null && wasLightStatusBar == lightStatusBar) { + return; + } + wasLightStatusBar = lightStatusBar; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + int flags = getSystemUiVisibility(); + if (lightStatusBar) { + flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else { + flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } + setSystemUiVisibility(flags); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.drawRect(AndroidUtilities.rectTmp, dimPaint); + + float radius = AndroidUtilities.dp(16) * (1f - actionBarTransitionProgress); + AndroidUtilities.rectTmp.set(0, AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress), getWidth(), getHeight() + radius); + canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, backgroundPaint); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN && event.getY() <= AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress)) { + dismiss(); + return true; + } + return super.onTouchEvent(event); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + linePaint.setColor(Theme.getColor(Theme.key_dialogGrayLine)); + linePaint.setAlpha((int) (linePaint.getAlpha() * (1f - Math.min(0.5f, actionBarTransitionProgress) / 0.5f))); + + canvas.save(); + float scale = 1f - actionBarTransitionProgress; + float y = AndroidUtilities.lerp(swipeContainer.getTranslationY(), AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight() / 2f, actionBarTransitionProgress) + AndroidUtilities.dp(12); + canvas.scale(scale, scale, getWidth() / 2f, y); + canvas.drawLine(getWidth() / 2f - AndroidUtilities.dp(16), y, getWidth() / 2f + AndroidUtilities.dp(16), y, linePaint); + canvas.restore(); + } + + /** + * Shows menu for the bot + */ + public void show(int currentAccount, long botId, String botUrl) { + dismissed = false; + if (this.currentAccount != currentAccount || this.botId != botId || !Objects.equals(this.botUrl, botUrl)) { + isLoaded = false; + } + this.currentAccount = currentAccount; + this.botId = botId; + this.botUrl = botUrl; + + savedEditText = parentEnterView.getEditField().getText(); + parentEnterView.getEditField().setText(null); + savedReplyMessageObject = parentEnterView.getReplyingMessageObject(); + savedEditMessageObject = parentEnterView.getEditingMessageObject(); + ChatActivity chatActivity = parentEnterView.getParentFragment(); + if (chatActivity != null) { + chatActivity.hideFieldPanel(true); + } + + if (!isLoaded) { + loadWebView(); + } + + setVisibility(VISIBLE); + setAlpha(0f); + addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + v.removeOnLayoutChangeListener(this); + + swipeContainer.setSwipeOffsetY(swipeContainer.getHeight()); + setAlpha(1f); + + new SpringAnimation(swipeContainer, ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer.SWIPE_OFFSET_Y, 0) + .setSpring(new SpringForce(0) + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(500.0f) + ) + .addEndListener((animation, canceled, value, velocity) -> webViewContainer.restoreButtonData()) + .start(); + } + }); + } + + private void loadWebView() { + progressView.setLoadProgress(0); + progressView.setAlpha(1f); + progressView.setVisibility(VISIBLE); + + webViewContainer.setBotUser(MessagesController.getInstance(currentAccount).getUser(botId)); + webViewContainer.loadFlicker(currentAccount, botId); + + TLRPC.TL_messages_requestWebView req = new TLRPC.TL_messages_requestWebView(); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(botId); + + req.url = botUrl; + req.flags |= 2; + + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("bg_color", getColor(Theme.key_windowBackgroundWhite)); + jsonObject.put("text_color", getColor(Theme.key_windowBackgroundWhiteBlackText)); + jsonObject.put("hint_color", getColor(Theme.key_windowBackgroundWhiteHintText)); + jsonObject.put("link_color", getColor(Theme.key_windowBackgroundWhiteLinkText)); + jsonObject.put("button_color", getColor(Theme.key_featuredStickers_addButton)); + jsonObject.put("button_text_color", getColor(Theme.key_featuredStickers_buttonText)); + + req.theme_params = new TLRPC.TL_dataJSON(); + req.theme_params.data = jsonObject.toString(); + req.flags |= 4; + } catch (Exception e) { + FileLog.e(e); + } + req.from_bot_menu = true; + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_webViewResultUrl) { + isLoaded = true; + + TLRPC.TL_webViewResultUrl resultUrl = (TLRPC.TL_webViewResultUrl) response; + queryId = resultUrl.query_id; + webViewContainer.loadUrl(resultUrl.url); + + AndroidUtilities.runOnUIThread(pollRunnable, POLL_PERIOD); + } + })); + } + + private int getColor(String key) { + Integer color; + Theme.ResourcesProvider resourcesProvider = parentEnterView.getParentFragment().getResourceProvider(); + if (resourcesProvider != null) { + color = resourcesProvider.getColor(key); + } else { + color = Theme.getColor(key); + } + return color != null ? color : Theme.getColor(key); + } + + /** + * Dismisses menu + */ + public void dismiss() { + dismiss(null); + } + + /** + * Dismisses menu + */ + public void dismiss(Runnable callback) { + if (dismissed) { + return; + } + dismissed = true; + swipeContainer.stickTo(swipeContainer.getHeight() + parentEnterView.getSizeNotifierLayout().measureKeyboardHeight(), ()->{ + onDismiss(); + if (callback != null) { + callback.run(); + } + }); + } + + /** + * Called when menu is fully dismissed + */ + public void onDismiss() { + setVisibility(GONE); + + webViewContainer.destroyWebView(); + swipeContainer.removeView(webViewContainer); + + webViewContainer = new BotWebViewContainer(getContext(), parentEnterView.getParentFragment().getResourceProvider(), getColor(Theme.key_windowBackgroundWhite)); + webViewContainer.setViewPortOffset(-AndroidUtilities.dp(5)); + webViewContainer.setDelegate(webViewDelegate); + webViewContainer.setWebViewProgressListener(progress -> { + progressView.setLoadProgressAnimated(progress); + if (progress == 1f) { + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> progressView.setAlpha((Float) animation.getAnimatedValue())); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressView.setVisibility(GONE); + } + }); + animator.start(); + } + }); + swipeContainer.addView(webViewContainer); + swipeContainer.setWebView(webViewContainer.getWebView()); + isLoaded = false; + + AndroidUtilities.cancelRunOnUIThread(pollRunnable); + boolean delayRestoreText = botWebViewButtonWasVisible; + if (botWebViewButtonWasVisible) { + botWebViewButtonWasVisible = false; + animateBotButton(false); + } + + AndroidUtilities.runOnUIThread(()->{ + if (savedEditText != null) { + parentEnterView.getEditField().setText(savedEditText); + savedEditText = null; + } + if (savedReplyMessageObject != null) { + ChatActivity chatActivity = parentEnterView.getParentFragment(); + if (chatActivity != null) { + chatActivity.showFieldPanelForReply(savedReplyMessageObject); + } + savedReplyMessageObject = null; + } + if (savedEditMessageObject != null) { + ChatActivity chatActivity = parentEnterView.getParentFragment(); + if (chatActivity != null) { + chatActivity.showFieldPanelForEdit(true, savedEditMessageObject); + } + savedEditMessageObject = null; + } + }, delayRestoreText ? 200 : 0); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.webViewResultSent) { + long queryId = (long) args[0]; + + if (this.queryId == queryId) { + dismiss(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java new file mode 100644 index 000000000..a0dcc7ba2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java @@ -0,0 +1,639 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; + +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.LaunchActivity; + +public class BotWebViewSheet extends Dialog implements NotificationCenter.NotificationCenterDelegate { + private final static int POLL_PERIOD = 60000; + + private final static SimpleFloatPropertyCompat ACTION_BAR_TRANSITION_PROGRESS_VALUE = new SimpleFloatPropertyCompat("actionBarTransitionProgress", obj -> obj.actionBarTransitionProgress, (obj, value) -> { + obj.actionBarTransitionProgress = value; + obj.frameLayout.invalidate(); + + obj.actionBar.setAlpha(value); + + obj.updateLightStatusBar(); + }).setMultiplier(100f); + private float actionBarTransitionProgress = 0f; + private SpringAnimation springAnimation; + + private Boolean wasLightStatusBar; + + private SizeNotifierFrameLayout frameLayout; + + private long lastSwipeTime; + + private ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer swipeContainer; + private BotWebViewContainer webViewContainer; + private ChatAttachAlertBotWebViewLayout.WebProgressView progressView; + private Theme.ResourcesProvider resourcesProvider; + private boolean ignoreLayout; + + private int currentAccount; + private long botId; + private long peerId; + private long queryId; + private int replyToMsgId; + private boolean silent; + private String buttonText; + + private Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint dimPaint = new Paint(); + private Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private ActionBar actionBar; + private Drawable actionBarShadow; + + private boolean dismissed; + + private Activity parentActivity; + + private boolean mainButtonWasVisible, mainButtonProgressWasVisible; + private TextView mainButton; + private RadialProgressView radialProgressView; + + private VerticalPositionAutoAnimator mainButtonAutoAnimator, radialProgressAutoAnimator; + + private Runnable pollRunnable = () -> { + if (!dismissed) { + TLRPC.TL_messages_prolongWebView prolongWebView = new TLRPC.TL_messages_prolongWebView(); + prolongWebView.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + prolongWebView.peer = MessagesController.getInstance(currentAccount).getInputPeer(peerId); + prolongWebView.query_id = queryId; + prolongWebView.silent = silent; + if (replyToMsgId != 0) { + prolongWebView.reply_to_msg_id = replyToMsgId; + prolongWebView.flags |= 1; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(prolongWebView, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (dismissed) { + return; + } + if (error != null) { + dismiss(); + } else { + AndroidUtilities.runOnUIThread(this.pollRunnable, POLL_PERIOD); + } + })); + } + }; + + public BotWebViewSheet(@NonNull Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, R.style.TransparentDialog); + this.resourcesProvider = resourcesProvider; + + swipeContainer = new ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int availableHeight = MeasureSpec.getSize(heightMeasureSpec); + + int padding; + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + padding = (int) (availableHeight / 3.5f); + } else { + padding = (availableHeight / 5 * 2); + } + if (padding < 0) { + padding = 0; + } + + if (getOffsetY() != padding && !dismissed) { + ignoreLayout = true; + setOffsetY(padding); + ignoreLayout = false; + } + + if (AndroidUtilities.isTablet() && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isSmallTablet()) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.8f), MeasureSpec.EXACTLY); + } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.statusBarHeight + AndroidUtilities.dp(24) - (mainButtonWasVisible ? mainButton.getLayoutParams().height : 0), MeasureSpec.EXACTLY)); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + webViewContainer = new BotWebViewContainer(context, resourcesProvider, getColor(Theme.key_windowBackgroundWhite)); + + webViewContainer.getWebView().setVerticalScrollBarEnabled(false); + webViewContainer.setDelegate(new BotWebViewContainer.Delegate() { + private boolean sentWebViewData; + + @Override + public void onCloseRequested() { + dismiss(); + } + + @Override + public void onSendWebViewData(String data) { + if (sentWebViewData) { + return; + } + sentWebViewData = true; + + TLRPC.TL_messages_sendWebViewData sendWebViewData = new TLRPC.TL_messages_sendWebViewData(); + sendWebViewData.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + sendWebViewData.random_id = Utilities.random.nextLong(); + sendWebViewData.button_text = buttonText; + sendWebViewData.data = data; + ConnectionsManager.getInstance(currentAccount).sendRequest(sendWebViewData, (response, error) -> AndroidUtilities.runOnUIThread(()-> dismiss())); + } + + @Override + public void onWebAppExpand() { + if (System.currentTimeMillis() - lastSwipeTime <= 1000 || swipeContainer.isSwipeInProgress()) { + return; + } + swipeContainer.stickTo(-swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY()); + } + + @Override + public void onSetupMainButton(boolean isVisible, boolean isActive, String text, int color, int textColor, boolean isProgressVisible) { + mainButton.setClickable(isActive); + mainButton.setText(text); + mainButton.setTextColor(textColor); + mainButton.setBackground(Theme.createSelectorWithBackgroundDrawable(color, Theme.getColor(Theme.key_listSelector))); + if (isVisible != mainButtonWasVisible) { + mainButtonWasVisible = isVisible; + mainButton.animate().cancel(); + if (isVisible) { + mainButton.setAlpha(0f); + mainButton.setVisibility(View.VISIBLE); + } + mainButton.animate().alpha(isVisible ? 1f : 0f).setDuration(150).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!isVisible) { + mainButton.setVisibility(View.GONE); + } + swipeContainer.requestLayout(); + } + }).start(); + } + radialProgressView.setProgressColor(textColor); + if (isProgressVisible != mainButtonProgressWasVisible) { + mainButtonProgressWasVisible = isProgressVisible; + radialProgressView.animate().cancel(); + if (isProgressVisible) { + radialProgressView.setAlpha(0f); + radialProgressView.setVisibility(View.VISIBLE); + } + radialProgressView.animate().alpha(isProgressVisible ? 1f : 0f) + .scaleX(isProgressVisible ? 1f : 0.1f) + .scaleY(isProgressVisible ? 1f : 0.1f) + .setDuration(250) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!isProgressVisible) { + radialProgressView.setVisibility(View.GONE); + } + } + }).start(); + } + } + }); + + linePaint.setStyle(Paint.Style.FILL_AND_STROKE); + linePaint.setStrokeWidth(AndroidUtilities.dp(4)); + linePaint.setStrokeCap(Paint.Cap.ROUND); + + backgroundPaint.setColor(getColor(Theme.key_windowBackgroundWhite)); + dimPaint.setColor(0x40000000); + frameLayout = new SizeNotifierFrameLayout(context) { + { + setWillNotDraw(false); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.drawRect(AndroidUtilities.rectTmp, dimPaint); + + float radius = AndroidUtilities.dp(16) * (1f - actionBarTransitionProgress); + AndroidUtilities.rectTmp.set(0, AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress), getWidth(), getHeight() + radius); + canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, backgroundPaint); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + linePaint.setColor(Theme.getColor(Theme.key_dialogGrayLine)); + linePaint.setAlpha((int) (linePaint.getAlpha() * (1f - Math.min(0.5f, actionBarTransitionProgress) / 0.5f))); + + canvas.save(); + float scale = 1f - actionBarTransitionProgress; + float y = AndroidUtilities.lerp(swipeContainer.getTranslationY(), AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight() / 2f, actionBarTransitionProgress) + AndroidUtilities.dp(12); + canvas.scale(scale, scale, getWidth() / 2f, y); + canvas.drawLine(getWidth() / 2f - AndroidUtilities.dp(16), y, getWidth() / 2f + AndroidUtilities.dp(16), y, linePaint); + canvas.restore(); + + actionBarShadow.setAlpha((int) (actionBar.getAlpha() * 0xFF)); + y = actionBar.getY() + actionBar.getTranslationY() + actionBar.getHeight(); + actionBarShadow.setBounds(0, (int)y, getWidth(), (int)(y + actionBarShadow.getIntrinsicHeight())); + actionBarShadow.draw(canvas); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress)) { + dismiss(); + return true; + } + return super.onTouchEvent(event); + } + }; + frameLayout.setDelegate((keyboardHeight, isWidthGreater) -> { + if (keyboardHeight > AndroidUtilities.dp(20)) { + swipeContainer.stickTo(-swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY()); + } + }); + frameLayout.addView(swipeContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, 24, 0, 0)); + + mainButton = new TextView(context); + mainButton.setVisibility(View.GONE); + mainButton.setAlpha(0f); + mainButton.setSingleLine(); + mainButton.setGravity(Gravity.CENTER); + mainButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + int padding = AndroidUtilities.dp(16); + mainButton.setPadding(padding, 0, padding, 0); + mainButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + mainButton.setOnClickListener(v -> webViewContainer.onMainButtonPressed()); + frameLayout.addView(mainButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); + mainButtonAutoAnimator = VerticalPositionAutoAnimator.attach(mainButton); + + radialProgressView = new RadialProgressView(context); + radialProgressView.setSize(AndroidUtilities.dp(18)); + radialProgressView.setAlpha(0f); + radialProgressView.setScaleX(0.1f); + radialProgressView.setScaleY(0.1f); + radialProgressView.setVisibility(View.GONE); + frameLayout.addView(radialProgressView, LayoutHelper.createFrame(28, 28, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, 10, 10)); + radialProgressAutoAnimator = VerticalPositionAutoAnimator.attach(radialProgressView); + + actionBarShadow = ContextCompat.getDrawable(getContext(), R.drawable.header_shadow).mutate(); + + actionBar = new ActionBar(context, resourcesProvider); + actionBar.setBackgroundColor(Color.TRANSPARENT); + actionBar.setTitleColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarWhiteSelector), false); + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + dismiss(); + } + } + }); + actionBar.setAlpha(0f); + frameLayout.addView(actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); + + frameLayout.addView(progressView = new ChatAttachAlertBotWebViewLayout.WebProgressView(context, resourcesProvider), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 0, 0, 0, 0)); + webViewContainer.setWebViewProgressListener(progress -> { + progressView.setLoadProgressAnimated(progress); + if (progress == 1f) { + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> progressView.setAlpha((Float) animation.getAnimatedValue())); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressView.setVisibility(View.GONE); + } + }); + animator.start(); + } + }); + + swipeContainer.addView(webViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + swipeContainer.setWebView(webViewContainer.getWebView()); + swipeContainer.setScrollListener(()->{ + if (swipeContainer.getSwipeOffsetY() > 0) { + dimPaint.setAlpha((int) (0x40 * (1f - swipeContainer.getSwipeOffsetY() / (float)swipeContainer.getHeight()))); + } else { + dimPaint.setAlpha(0x40); + } + frameLayout.invalidate(); + webViewContainer.invalidateViewPortHeight(); + + if (springAnimation != null) { + float progress = (1f - Math.min(swipeContainer.getTopActionBarOffsetY(), swipeContainer.getTranslationY() - swipeContainer.getTopActionBarOffsetY()) / swipeContainer.getTopActionBarOffsetY()); + float newPos = (progress > 0.5f ? 1 : 0) * 100f; + if (springAnimation.getSpring().getFinalPosition() != newPos) { + springAnimation.getSpring().setFinalPosition(newPos); + springAnimation.start(); + } + } + float offsetY = Math.max(0, swipeContainer.getSwipeOffsetY()); + mainButtonAutoAnimator.setOffsetY(offsetY); + radialProgressAutoAnimator.setOffsetY(offsetY); + lastSwipeTime = System.currentTimeMillis(); + }); + swipeContainer.setScrollEndListener(()-> webViewContainer.invalidateViewPortHeight(true)); + swipeContainer.setDelegate(this::dismiss); + swipeContainer.setTopActionBarOffsetY(ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight - AndroidUtilities.dp(24)); + + setContentView(frameLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + + public void setParentActivity(Activity parentActivity) { + this.parentActivity = parentActivity; + } + + private void updateLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + boolean lightStatusBar = ColorUtils.calculateLuminance(color) >= 0.9 && actionBarTransitionProgress >= 0.85f; + + if (wasLightStatusBar != null && wasLightStatusBar == lightStatusBar) { + return; + } + wasLightStatusBar = lightStatusBar; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + int flags = frameLayout.getSystemUiVisibility(); + if (lightStatusBar) { + flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else { + flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } + frameLayout.setSystemUiVisibility(flags); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Window window = getWindow(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + } + window.setWindowAnimations(R.style.DialogNoAnimation); + + WindowManager.LayoutParams params = window.getAttributes(); + params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.gravity = Gravity.TOP | Gravity.LEFT; + params.dimAmount = 0; + params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; + params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; + params.height = ViewGroup.LayoutParams.MATCH_PARENT; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; + } + window.setAttributes(params); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + window.setStatusBarColor(Color.TRANSPARENT); + } + + frameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + frameLayout.setOnApplyWindowInsetsListener((v, insets) -> { + v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + return insets; + }); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + AndroidUtilities.setLightNavigationBar(window, ColorUtils.calculateLuminance(color) >= 0.9); + } + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (springAnimation == null) { + springAnimation = new SpringAnimation(this, ACTION_BAR_TRANSITION_PROGRESS_VALUE) + .setSpring(new SpringForce() + .setStiffness(1200f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY) + ); + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + if (springAnimation != null) { + springAnimation.cancel(); + springAnimation = null; + } + } + + public void requestWebView(int currentAccount, long peerId, long botId, String buttonText, String buttonUrl, boolean simple, int replyToMsgId, boolean silent) { + this.currentAccount = currentAccount; + this.peerId = peerId; + this.botId = botId; + this.replyToMsgId = replyToMsgId; + this.silent = silent; + this.buttonText = buttonText; + + actionBar.setTitle(UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(botId))); + ActionBarMenu menu = actionBar.createMenu(); + menu.removeAllViews(); + + ActionBarMenuItem otherItem = menu.addItem(0, R.drawable.ic_ab_other); + otherItem.addSubItem(R.id.menu_open_bot, R.drawable.msg_bot, LocaleController.getString(R.string.BotWebViewOpenBot)); + otherItem.addSubItem(R.id.menu_reload_page, R.drawable.msg_retry, LocaleController.getString(R.string.BotWebViewReloadPage)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + dismiss(); + } else if (id == R.id.menu_open_bot) { + Bundle bundle = new Bundle(); + bundle.putLong("user_id", botId); + if (parentActivity instanceof LaunchActivity) { + ((LaunchActivity) parentActivity).presentFragment(new ChatActivity(bundle)); + } + dismiss(); + } else if (id == R.id.menu_reload_page) { + webViewContainer.getWebView().animate().cancel(); + webViewContainer.getWebView().animate().alpha(0).start(); + requestWebView(currentAccount, peerId, botId, buttonText, buttonUrl, simple, replyToMsgId, silent); + } + } + }); + + boolean hasThemeParams = true; + String themeParams = null; + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("bg_color", getColor(Theme.key_windowBackgroundWhite)); + jsonObject.put("text_color", getColor(Theme.key_windowBackgroundWhiteBlackText)); + jsonObject.put("hint_color", getColor(Theme.key_windowBackgroundWhiteHintText)); + jsonObject.put("link_color", getColor(Theme.key_windowBackgroundWhiteLinkText)); + jsonObject.put("button_color", getColor(Theme.key_featuredStickers_addButton)); + jsonObject.put("button_text_color", getColor(Theme.key_featuredStickers_buttonText)); + themeParams = jsonObject.toString(); + } catch (Exception e) { + FileLog.e(e); + hasThemeParams = false; + } + + webViewContainer.setBotUser(MessagesController.getInstance(currentAccount).getUser(botId)); + webViewContainer.loadFlicker(currentAccount, botId); + if (simple) { + TLRPC.TL_messages_requestSimpleWebView req = new TLRPC.TL_messages_requestSimpleWebView(); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + if (hasThemeParams) { + req.theme_params = new TLRPC.TL_dataJSON(); + req.theme_params.data = themeParams; + req.flags |= 1; + } + req.url = buttonUrl; + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(()->{ + if (response instanceof TLRPC.TL_simpleWebViewResultUrl) { + TLRPC.TL_simpleWebViewResultUrl resultUrl = (TLRPC.TL_simpleWebViewResultUrl) response; + webViewContainer.loadUrl(resultUrl.url); + } + })); + } else { + TLRPC.TL_messages_requestWebView req = new TLRPC.TL_messages_requestWebView(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(peerId); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + if (buttonUrl != null) { + req.url = buttonUrl; + req.flags |= 2; + } + + if (replyToMsgId != 0) { + req.reply_to_msg_id = replyToMsgId; + req.flags |= 1; + } + + if (hasThemeParams) { + req.theme_params = new TLRPC.TL_dataJSON(); + req.theme_params.data = themeParams; + req.flags |= 4; + } + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_webViewResultUrl) { + TLRPC.TL_webViewResultUrl resultUrl = (TLRPC.TL_webViewResultUrl) response; + queryId = resultUrl.query_id; + webViewContainer.loadUrl(resultUrl.url); + + AndroidUtilities.runOnUIThread(pollRunnable, POLL_PERIOD); + } + })); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.webViewResultSent); + } + } + + private int getColor(String key) { + Integer color; + if (resourcesProvider != null) { + color = resourcesProvider.getColor(key); + } else { + color = Theme.getColor(key); + } + return color != null ? color : Theme.getColor(key); + } + + @Override + public void show() { + frameLayout.setAlpha(0f); + frameLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + v.removeOnLayoutChangeListener(this); + + swipeContainer.setSwipeOffsetY(swipeContainer.getHeight()); + frameLayout.setAlpha(1f); + + new SpringAnimation(swipeContainer, ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer.SWIPE_OFFSET_Y, 0) + .setSpring(new SpringForce(0) + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(500.0f) + ).start(); + } + }); + super.show(); + } + + @Override + public void dismiss() { + if (dismissed) { + return; + } + dismissed = true; + AndroidUtilities.cancelRunOnUIThread(pollRunnable); + + webViewContainer.destroyWebView(); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.webViewResultSent); + + swipeContainer.stickTo(swipeContainer.getHeight() + frameLayout.measureKeyboardHeight(), super::dismiss); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.webViewResultSent) { + long queryId = (long) args[0]; + + if (this.queryId == queryId) { + dismiss(); + } + } + } +} 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 d6e5ae053..ea80522df 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -62,6 +62,7 @@ public class Bulletin { 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 final int TYPE_ERROR_SUBTITLE = 4; public int tag; @@ -1004,6 +1005,7 @@ public class Bulletin { addView(imageView, LayoutHelper.createFrameRelatively(56, 48, Gravity.START | Gravity.CENTER_VERTICAL)); final int undoInfoColor = getThemedColor(Theme.key_undo_infoColor); + final int undoLinkColor = getThemedColor(Theme.key_voipgroup_overlayBlue1); final LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.VERTICAL); @@ -1018,6 +1020,7 @@ public class Bulletin { subtitleTextView = new TextView(context); subtitleTextView.setTextColor(undoInfoColor); + subtitleTextView.setLinkTextColor(undoLinkColor); subtitleTextView.setTypeface(Typeface.SANS_SERIF); subtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); linearLayout.addView(subtitleTextView); 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 1ad7d82c0..f61597ab3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -1,7 +1,6 @@ package org.telegram.ui.Components; import android.content.Context; -import android.os.Build; import android.widget.FrameLayout; import androidx.annotation.CheckResult; @@ -128,6 +127,14 @@ public final class BulletinFactory { return create(layout, Bulletin.DURATION_SHORT); } + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, CharSequence subtext) { + final Bulletin.TwoLineLottieLayout layout = new Bulletin.TwoLineLottieLayout(getContext(), resourcesProvider); + layout.setAnimation(iconRawId, 36, 36); + layout.titleTextView.setText(text); + layout.subtitleTextView.setText(subtext); + return create(layout, Bulletin.DURATION_SHORT); + } + @CheckResult public Bulletin createDownloadBulletin(FileType fileType) { return createDownloadBulletin(fileType, resourcesProvider); @@ -184,6 +191,14 @@ public final class BulletinFactory { return create(layout, Bulletin.DURATION_SHORT); } + public Bulletin createErrorBulletinSubtitle(CharSequence errorMessage, CharSequence errorDescription, Theme.ResourcesProvider resourcesProvider) { + Bulletin.TwoLineLottieLayout layout = new Bulletin.TwoLineLottieLayout(getContext(), resourcesProvider); + layout.setAnimation(R.raw.chats_infotip); + layout.titleTextView.setText(errorMessage); + layout.subtitleTextView.setText(errorDescription); + return create(layout, Bulletin.DURATION_SHORT); + } + @CheckResult public Bulletin createCopyLinkBulletin() { return createCopyLinkBulletin(false, resourcesProvider); @@ -191,7 +206,7 @@ public final class BulletinFactory { @CheckResult public Bulletin createCopyBulletin(String message) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (!AndroidUtilities.shouldShowClipboardToast()) { return new Bulletin.EmptyBulletin(); } final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), null); @@ -202,7 +217,7 @@ public final class BulletinFactory { @CheckResult public Bulletin createCopyLinkBulletin(boolean isPrivate, Theme.ResourcesProvider resourcesProvider) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (!AndroidUtilities.shouldShowClipboardToast()) { return new Bulletin.EmptyBulletin(); } if (isPrivate) { @@ -235,17 +250,23 @@ public final class BulletinFactory { @CheckResult public static Bulletin createMuteBulletin(BaseFragment fragment, int setting) { - return createMuteBulletin(fragment, setting, null); + return createMuteBulletin(fragment, setting, 0, null); } @CheckResult - public static Bulletin createMuteBulletin(BaseFragment fragment, int setting, Theme.ResourcesProvider resourcesProvider) { + public static Bulletin createMuteBulletin(BaseFragment fragment, int setting, int timeInSeconds, Theme.ResourcesProvider resourcesProvider) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), resourcesProvider); final String text; final boolean mute; + boolean muteFor = false; switch (setting) { + case NotificationsController.SETTING_MUTE_CUSTOM: + text = LocaleController.formatString("NotificationsMutedForHint", R.string.NotificationsMutedForHint, LocaleController.formatTTLString(timeInSeconds)); + mute = true; + muteFor = true; + break; case NotificationsController.SETTING_MUTE_HOUR: text = LocaleController.formatString("NotificationsMutedForHint", R.string.NotificationsMutedForHint, LocaleController.formatPluralString("Hours", 1)); mute = true; @@ -270,7 +291,9 @@ public final class BulletinFactory { throw new IllegalArgumentException(); } - if (mute) { + if (muteFor) { + layout.setAnimation(R.raw.mute_for); + } else if (mute) { layout.setAnimation(R.raw.ic_mute, "Body Main", "Body Top", "Line", "Curve Big", "Curve Small"); } else { layout.setAnimation(R.raw.ic_unmute, "BODY", "Wibe Big", "Wibe Big 3", "Wibe Small"); @@ -282,7 +305,7 @@ public final class BulletinFactory { @CheckResult public static Bulletin createMuteBulletin(BaseFragment fragment, boolean muted, Theme.ResourcesProvider resourcesProvider) { - return createMuteBulletin(fragment, muted ? NotificationsController.SETTING_MUTE_FOREVER : NotificationsController.SETTING_MUTE_UNMUTE, resourcesProvider); + return createMuteBulletin(fragment, muted ? NotificationsController.SETTING_MUTE_FOREVER : NotificationsController.SETTING_MUTE_UNMUTE, 0, resourcesProvider); } @CheckResult @@ -336,6 +359,14 @@ public final class BulletinFactory { return Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT); } + @CheckResult + public static Bulletin createAddedAsAdminBulletin(BaseFragment fragment, String userFirstName) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), null); + layout.setAnimation(R.raw.ic_admin, "Shield"); + layout.textView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("UserAddedAsAdminHint", R.string.UserAddedAsAdminHint, userFirstName))); + return Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT); + } + @CheckResult public static Bulletin createRemoveFromChatBulletin(BaseFragment fragment, TLRPC.User user, String chatName) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), null); @@ -395,5 +426,35 @@ public final class BulletinFactory { } return Bulletin.make(fragment, layout, pinned ? Bulletin.DURATION_SHORT : 5000); } + + @CheckResult + public static Bulletin createSoundEnabledBulletin(BaseFragment fragment, int setting, Theme.ResourcesProvider resourcesProvider) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), resourcesProvider); + + final String text; + final boolean soundOn; + + switch (setting) { + case NotificationsController.SETTING_SOUND_ON: + text = LocaleController.getString("SoundOnHint", R.string.SoundOnHint); + soundOn = true; + break; + case NotificationsController.SETTING_SOUND_OFF: + text = LocaleController.getString("SoundOffHint", R.string.SoundOffHint); + soundOn = false; + break; + default: + throw new IllegalArgumentException(); + } + + if (soundOn) { + layout.setAnimation(R.raw.sound_on); + } else { + layout.setAnimation(R.raw.sound_off); + } + + layout.textView.setText(text); + return Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT); + } //endregion } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityBotWebViewButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityBotWebViewButton.java new file mode 100644 index 000000000..234e51027 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityBotWebViewButton.java @@ -0,0 +1,135 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Path; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.ActionBar.Theme; + +public class ChatActivityBotWebViewButton extends FrameLayout { + public final static SimpleFloatPropertyCompat PROGRESS_PROPERTY = new SimpleFloatPropertyCompat<>("progress", obj -> obj.progress, ChatActivityBotWebViewButton::setProgress) + .setMultiplier(100f); + + private Path path = new Path(); + private float progress; + private int buttonColor = Theme.getColor(Theme.key_featuredStickers_addButton); + private int backgroundColor; + private int menuButtonWidth; + + private TextView textView; + private RadialProgressView progressView; + private View rippleView; + + private boolean progressWasVisible; + private BotCommandsMenuView menuButton; + + public ChatActivityBotWebViewButton(Context context) { + super(context); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setSingleLine(); + textView.setAlpha(0f); + textView.setGravity(Gravity.CENTER); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT, 0, 0, 0, 4)); + + progressView = new RadialProgressView(context); + progressView.setSize(AndroidUtilities.dp(18)); + progressView.setAlpha(0f); + progressView.setScaleX(0); + progressView.setScaleY(0); + addView(progressView, LayoutHelper.createFrame(28, 28, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 0, 12, 4)); + + rippleView = new View(context); + rippleView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector), 2)); + addView(rippleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT, 0, -4, 0, 0)); + + setWillNotDraw(false); + } + + public void setBotMenuButton(BotCommandsMenuView menuButton) { + this.menuButton = menuButton; + invalidate(); + } + + public void setupButtonParams(boolean isActive, String text, int color, int textColor, boolean isProgressVisible) { + setClickable(isActive); + rippleView.setVisibility(isActive ? VISIBLE : GONE); + textView.setText(text); + textView.setTextColor(textColor); + buttonColor = color; + + progressView.setProgressColor(textColor); + if (progressWasVisible != isProgressVisible) { + progressWasVisible = isProgressVisible; + progressView.animate().cancel(); + if (isProgressVisible) { + progressView.setAlpha(0f); + progressView.setVisibility(VISIBLE); + } + progressView.animate().alpha(isProgressVisible ? 1f : 0f) + .scaleX(isProgressVisible ? 1f : 0.1f) + .scaleY(isProgressVisible ? 1f : 0.1f) + .setDuration(250) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!isProgressVisible) { + progressView.setVisibility(GONE); + } + } + }).start(); + } + } + + public void setProgress(float progress) { + this.progress = progress; + backgroundColor = ColorUtils.blendARGB(Theme.getColor(Theme.key_chat_messagePanelVoiceBackground), buttonColor, progress); + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).setAlpha(progress); + } + invalidate(); + } + + public void setMeasuredButtonWidth(int width) { + menuButtonWidth = width; + invalidate(); + } + + @Override + public void draw(Canvas canvas) { + canvas.save(); + float offset = Math.max(getWidth() - menuButtonWidth - AndroidUtilities.dp(4), getHeight()) * progress; + float rad = AndroidUtilities.dp(16) + offset; + AndroidUtilities.rectTmp.set(AndroidUtilities.dp(14) - offset, AndroidUtilities.dp(8) - offset, AndroidUtilities.dp(6) + menuButtonWidth + offset, getHeight() - AndroidUtilities.dp(12) + offset); + + path.rewind(); + path.addRoundRect(AndroidUtilities.rectTmp, rad, rad, Path.Direction.CW); + canvas.clipPath(path); + canvas.drawColor(backgroundColor); + + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) ((1f - Math.min(0.5f, progress) / 0.5f) * 0xFF), Canvas.ALL_SAVE_FLAG); + canvas.translate(AndroidUtilities.dp(10), AndroidUtilities.dp(4)); + if (menuButton != null) { + menuButton.setDrawBackgroundDrawable(false); + menuButton.draw(canvas); + menuButton.setDrawBackgroundDrawable(true); + } + canvas.restore(); + + canvas.translate(-AndroidUtilities.dp(8) * (1f - progress), 0); + super.draw(canvas); + canvas.restore(); + } +} 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 356880815..ac087c863 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -118,6 +118,7 @@ import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.SharedPrefsHelper; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; @@ -272,6 +273,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific boolean messageTransitionIsRunning; boolean textTransitionIsRunning; + private BotMenuButtonType botMenuButtonType = BotMenuButtonType.NO_BUTTON; + private String botMenuWebViewTitle; + private String botMenuWebViewUrl; + + private BotWebViewMenuContainer botWebViewMenuContainer; + private ChatActivityBotWebViewButton botWebViewButton; + private BotCommandsMenuView botCommandsMenuButton; public BotCommandsMenuContainer botCommandsMenuContainer; private BotCommandsMenuView.BotCommandsAdapter botCommandsAdapter; @@ -518,6 +526,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private Runnable openKeyboardRunnable = new Runnable() { @Override public void run() { + if (hasBotWebView() && botCommandsMenuIsShowing()) { + return; + } + if (!destroyed && messageEditText != null && waitingForKeyboardOpen && !keyboardVisible && !AndroidUtilities.usingHardwareInput && !AndroidUtilities.isInMultiwindow) { messageEditText.requestFocus(); AndroidUtilities.showKeyboard(messageEditText); @@ -1721,7 +1733,15 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific sendByEnter = preferences.getBoolean("send_by_enter", false); configAnimationsEnabled = preferences.getBoolean("view_animations", true); - textFieldContainer = new FrameLayout(context); + textFieldContainer = new FrameLayout(context) { + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (botWebViewButton.getVisibility() == VISIBLE) { + return botWebViewButton.dispatchTouchEvent(ev); + } + return super.dispatchTouchEvent(ev); + } + }; textFieldContainer.setClipChildren(false); textFieldContainer.setClipToPadding(false); textFieldContainer.setPadding(0, AndroidUtilities.dp(1), 0, 0); @@ -1785,6 +1805,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (adjustPanLayoutHelper != null && adjustPanLayoutHelper.animationInProgress()) { return; } + if (hasBotWebView() && botCommandsMenuIsShowing()) { + botWebViewMenuContainer.dismiss(view::callOnClick); + return; + } + if (!isPopupShowing() || currentPopupContentType != 0) { showPopup(1, 0); emojiView.onOpen(messageEditText.length() > 0); @@ -2079,6 +2104,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific messageEditText.setPadding(0, AndroidUtilities.dp(11), 0, AndroidUtilities.dp(12)); messageEditText.setBackgroundDrawable(null); messageEditText.setTextColor(getThemedColor(Theme.key_chat_messagePanelText)); + messageEditText.setLinkTextColor(getThemedColor(Theme.key_chat_messageLinkOut)); messageEditText.setHintColor(getThemedColor(Theme.key_chat_messagePanelHint)); messageEditText.setHintTextColor(getThemedColor(Theme.key_chat_messagePanelHint)); messageEditText.setCursorColor(getThemedColor(Theme.key_chat_messagePanelCursor)); @@ -2316,6 +2342,21 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignore) {} + if (hasBotWebView()) { + if (open) { + if (emojiViewVisible || botKeyboardViewVisible) { + AndroidUtilities.runOnUIThread(this::openWebViewMenu, 275); + hidePopup(false); + return; + } + + openWebViewMenu(); + } else { + botWebViewMenuContainer.dismiss(); + } + return; + } + if (open) { botCommandsMenuContainer.show(); } else { @@ -2379,6 +2420,15 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific sizeNotifierLayout.addView(botCommandsMenuContainer, 14, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); botCommandsMenuContainer.setVisibility(View.GONE); + botWebViewMenuContainer = new BotWebViewMenuContainer(context, this) { + @Override + public void onDismiss() { + super.onDismiss(); + botCommandsMenuButton.setOpened(false); + } + }; + sizeNotifierLayout.addView(botWebViewMenuContainer, 15, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); + botWebViewMenuContainer.setVisibility(GONE); botButton = new ImageView(context); botButton.setImageDrawable(botButtonDrawable = new ReplaceableIconDrawable(context)); @@ -2391,6 +2441,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific botButton.setVisibility(GONE); attachLayout.addView(botButton, LayoutHelper.createLinear(48, 48)); botButton.setOnClickListener(v -> { + if (hasBotWebView() && botCommandsMenuIsShowing()) { + botWebViewMenuContainer.dismiss(v::callOnClick); + return; + } if (searchingType != 0) { setSearchingTypeInternal(0, false); emojiView.closeSearch(false); @@ -3366,6 +3420,63 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific setRecordVideoButtonVisible(false, false); checkSendButton(false); checkChannelRights(); + + botWebViewButton = new ChatActivityBotWebViewButton(context); + botWebViewButton.setVisibility(GONE); + botWebViewButton.setBotMenuButton(botCommandsMenuButton); + frameLayout.addView(botWebViewButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); + } + + private void openWebViewMenu() { + Runnable onRequestWebView = () -> { + AndroidUtilities.hideKeyboard(this); + botWebViewMenuContainer.show(currentAccount, dialog_id, botMenuWebViewUrl); + }; + + if (SharedPrefsHelper.isWebViewConfirmShown(currentAccount, dialog_id)) { + onRequestWebView.run(); + } else { + new AlertDialog.Builder(parentFragment.getParentActivity()) + .setTitle(LocaleController.getString(R.string.BotOpenPageTitle)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString(R.string.BotOpenPageMessage, UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(dialog_id))))) + .setPositiveButton(LocaleController.getString(R.string.OK), (dialog, which) -> { + onRequestWebView.run(); + SharedPrefsHelper.setWebViewConfirmShown(currentAccount, dialog_id, true); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .setOnDismissListener(dialog -> { + if (!SharedPrefsHelper.isWebViewConfirmShown(currentAccount, dialog_id)) { + botCommandsMenuButton.setOpened(false); + } + }) + .show(); + } + } + + public void setBotWebViewButtonOffsetX(float offset) { + for (ImageView imageView : emojiButton) { + imageView.setTranslationX(offset); + } + messageEditText.setTranslationX(offset); + attachButton.setTranslationX(offset); + audioSendButton.setTranslationX(offset); + videoSendButton.setTranslationX(offset); + if (botButton != null) { + botButton.setTranslationX(offset); + } + } + + public void setComposeShadowAlpha(float alpha) { + composeShadowAlpha = alpha; + invalidate(); + } + + public ChatActivityBotWebViewButton getBotWebViewButton() { + return botWebViewButton; + } + + public ChatActivity getParentFragment() { + return parentFragment; } private void checkBotMenu() { @@ -3434,14 +3545,17 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public boolean allowBlur = true; Paint backgroundPaint = new Paint(); + private float composeShadowAlpha = 1f; @Override protected void onDraw(Canvas canvas) { int top = animatedTop; + top += Theme.chat_composeShadowDrawable.getIntrinsicHeight() * (1f - composeShadowAlpha); if (topView != null && topView.getVisibility() == View.VISIBLE) { top += (1f - topViewEnterProgress) * topView.getLayoutParams().height; } int bottom = top + Theme.chat_composeShadowDrawable.getIntrinsicHeight(); + Theme.chat_composeShadowDrawable.setAlpha((int) (composeShadowAlpha * 0xFF)); Theme.chat_composeShadowDrawable.setBounds(0, top, getMeasuredWidth(), bottom); Theme.chat_composeShadowDrawable.draw(canvas); if (allowBlur) { @@ -3971,14 +4085,20 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return topView != null && topView.getVisibility() == VISIBLE; } + public void onAdjustPanTransitionUpdate(float y, float progress, boolean keyboardVisible) { + botWebViewMenuContainer.setTranslationY(y); + } + public void onAdjustPanTransitionEnd() { + botWebViewMenuContainer.onPanTransitionEnd(); if (onKeyboardClosed != null) { onKeyboardClosed.run(); onKeyboardClosed = null; } } - public void onAdjustPanTransitionStart(boolean keyboardVisible) { + public void onAdjustPanTransitionStart(boolean keyboardVisible, int contentHeight) { + botWebViewMenuContainer.onPanTransitionStart(keyboardVisible, contentHeight); if (keyboardVisible && showTopViewRunnable != null) { AndroidUtilities.cancelRunOnUIThread(showTopViewRunnable); showTopViewRunnable.run(); @@ -3988,6 +4108,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AndroidUtilities.cancelRunOnUIThread(setTextFieldRunnable); setTextFieldRunnable.run(); } + + if (keyboardVisible && messageEditText.hasFocus() && hasBotWebView() && botCommandsMenuIsShowing()) { + botWebViewMenuContainer.dismiss(); + } } private void onWindowSizeChanged() { @@ -4135,6 +4259,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AndroidUtilities.cancelRunOnUIThread(hideKeyboardRunnable); hideKeyboardRunnable = null; } + + if (hasBotWebView() && botCommandsMenuIsShowing()) { + return; + } + int visibility = getVisibility(); if (showKeyboardOnResume && parentFragment.isLastFragment()) { showKeyboardOnResume = false; @@ -4243,6 +4372,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return hasRecordVideo; } + public MessageObject getReplyingMessageObject() { + return replyingMessageObject; + } + public void updateFieldHint(boolean animated) { if (replyingMessageObject != null && replyingMessageObject.messageOwner.reply_markup != null && !TextUtils.isEmpty(replyingMessageObject.messageOwner.reply_markup.placeholder)) { messageEditText.setHintText(replyingMessageObject.messageOwner.reply_markup.placeholder, animated); @@ -6749,6 +6882,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } + private boolean hasBotWebView() { + return botMenuButtonType == BotMenuButtonType.WEB_VIEW; + } + private void updateBotButton(boolean animated) { if (botButton == null) { return; @@ -6756,13 +6893,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (!parentFragment.openAnimationEnded) { animated = false; } - boolean canShowBotsMenu = hasBotCommands && dialog_id > 0; + boolean hasBotWebView = hasBotWebView(); + boolean canShowBotsMenu = botMenuButtonType != BotMenuButtonType.NO_BUTTON && dialog_id > 0; // if (canShowBotsMenu && ) { // TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); // canShowBotsMenu = chat == null || !chat.megagroup; // } - if (hasBotCommands || botReplyMarkup != null) { + if (hasBotWebView || hasBotCommands || botReplyMarkup != null) { if (botReplyMarkup != null) { if (botButton.getVisibility() != VISIBLE) { botButton.setVisibility(VISIBLE); @@ -6786,7 +6924,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else { botButton.setVisibility(GONE); } - AndroidUtilities.updateViewVisibilityAnimated(botCommandsMenuButton, canShowBotsMenu && hasBotCommands, 0.5f, animated); + botCommandsMenuButton.setWebView(botMenuButtonType == BotMenuButtonType.WEB_VIEW); + botCommandsMenuButton.setMenuText(botMenuButtonType == BotMenuButtonType.COMMANDS ? LocaleController.getString(R.string.BotsMenuTitle) : botMenuWebViewTitle); + AndroidUtilities.updateViewVisibilityAnimated(botCommandsMenuButton, canShowBotsMenu, 0.5f, animated); if (animated) { beginDelayedTransition(); } @@ -6803,6 +6943,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return false; } + public void updateBotWebView(boolean animated) { + botCommandsMenuButton.setWebView(hasBotWebView()); + updateBotButton(animated); + } + public void setBotsCount(int count, boolean hasCommands, boolean animated) { botCount = count; if (hasBotCommands != hasCommands) { @@ -6900,6 +7045,37 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else if (button instanceof TLRPC.TL_keyboardButtonRequestPoll) { parentFragment.openPollCreate((button.flags & 1) != 0 ? button.quiz : null); return false; + } else if (button instanceof TLRPC.TL_keyboardButtonWebView || button instanceof TLRPC.TL_keyboardButtonSimpleWebView) { + long botId = messageObject.messageOwner.via_bot_id != 0 ? messageObject.messageOwner.via_bot_id : messageObject.messageOwner.from_id.user_id; + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(botId); + Runnable onRequestWebView = new Runnable() { + @Override + public void run() { + if (sizeNotifierLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { + AndroidUtilities.hideKeyboard(ChatActivityEnterView.this); + AndroidUtilities.runOnUIThread(this, 150); + return; + } + + BotWebViewSheet webViewSheet = new BotWebViewSheet(getContext(), resourcesProvider); + webViewSheet.setParentActivity(parentActivity); + webViewSheet.requestWebView(currentAccount, messageObject.messageOwner.dialog_id, botId, button.text, button.url, button instanceof TLRPC.TL_keyboardButtonSimpleWebView, replyMessageObject != null ? replyMessageObject.messageOwner.id : 0, false); + webViewSheet.show(); + } + }; + if (SharedPrefsHelper.isWebViewConfirmShown(currentAccount, botId)) { + onRequestWebView.run(); + } else { + new AlertDialog.Builder(parentFragment.getParentActivity()) + .setTitle(LocaleController.getString(R.string.BotOpenPageTitle)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("BotOpenPageMessage", R.string.BotOpenPageMessage, UserObject.getUserName(user)))) + .setPositiveButton(LocaleController.getString(R.string.OK), (dialog, which) -> { + onRequestWebView.run(); + SharedPrefsHelper.setWebViewConfirmShown(currentAccount, botId, true); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + } } else if (button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation) { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("ShareYouLocationTitle", R.string.ShareYouLocationTitle)); @@ -6995,6 +7171,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return view == recordCircle; } + public SizeNotifierFrameLayout getSizeNotifierLayout() { + return sizeNotifierLayout; + } + private void createEmojiView() { if (emojiView != null) { return; @@ -7771,6 +7951,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } private void openKeyboardInternal() { + if (hasBotWebView() && botCommandsMenuIsShowing()) { + return; + } showPopup(AndroidUtilities.usingHardwareInput || AndroidUtilities.isInMultiwindow || parentFragment != null && parentFragment.isInBubbleMode() || isPaused ? 0 : 2, 0); messageEditText.requestFocus(); AndroidUtilities.showKeyboard(messageEditText); @@ -7803,6 +7986,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } public void openKeyboard() { + if (hasBotWebView() && botCommandsMenuIsShowing()) { + return; + } if (!AndroidUtilities.showKeyboard(messageEditText)) { messageEditText.clearFocus(); messageEditText.requestFocus(); @@ -8387,6 +8573,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if ((videoSendButton != null) && isInVideoMode() && recordedAudioPanel != null && recordedAudioPanel.getVisibility() == View.VISIBLE) { return false; } + if (hasBotWebView() && botCommandsMenuButton.isOpened()) { + return false; + } return true; } @@ -8993,6 +9182,19 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + if (botWebViewButton != null) { + if (botCommandsMenuButton != null) { + botWebViewButton.setMeasuredButtonWidth(botCommandsMenuButton.getMeasuredWidth()); + } + botWebViewButton.getLayoutParams().height = messageEditText.getMeasuredHeight(); + measureChild(botWebViewButton, widthMeasureSpec, heightMeasureSpec); + } + if (botWebViewMenuContainer != null) { + MarginLayoutParams params = (MarginLayoutParams) botWebViewMenuContainer.getLayoutParams(); + params.bottomMargin = messageEditText.getMeasuredHeight(); + measureChild(botWebViewMenuContainer, widthMeasureSpec, heightMeasureSpec); + } } @Override @@ -9014,6 +9216,23 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } public void setBotInfo(LongSparseArray botInfo) { + if (botInfo.size() == 1 && botInfo.valueAt(0).user_id == dialog_id) { + TLRPC.BotInfo info = botInfo.valueAt(0); + TLRPC.BotMenuButton menuButton = info.menu_button; + if (menuButton instanceof TLRPC.TL_botMenuButtonCommands || menuButton instanceof TLRPC.TL_botMenuButtonDefault) { + botMenuButtonType = info.commands.isEmpty() ? BotMenuButtonType.NO_BUTTON : BotMenuButtonType.COMMANDS; + } else if (menuButton instanceof TLRPC.TL_botMenuButton) { + TLRPC.TL_botMenuButton webViewButton = (TLRPC.TL_botMenuButton) menuButton; + botMenuWebViewTitle = webViewButton.text; + botMenuWebViewUrl = webViewButton.url; + botMenuButtonType = BotMenuButtonType.WEB_VIEW; + } else { + botMenuButtonType = BotMenuButtonType.NO_BUTTON; + } + } else { + botMenuButtonType = BotMenuButtonType.NO_BUTTON; + } + if (botCommandsAdapter != null) { botCommandsAdapter.setBotInfo(botInfo); } @@ -9025,7 +9244,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public void hideBotCommands() { botCommandsMenuButton.setOpened(false); - botCommandsMenuContainer.dismiss(); + + if (hasBotWebView()) { + botWebViewMenuContainer.dismiss(); + } else { + botCommandsMenuContainer.dismiss(); + } } public void setTextTransitionIsRunning(boolean b) { @@ -9071,4 +9295,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific Paint paint = resourcesProvider != null ? resourcesProvider.getPaint(paintKey) : null; return paint != null ? paint : Theme.getThemePaint(paintKey); } + + public enum BotMenuButtonType { + NO_BUTTON, + COMMANDS, + WEB_VIEW + } } 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 7838edba8..006717e92 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -35,6 +35,7 @@ import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ImageSpan; +import android.util.LongSparseArray; import android.util.Property; import android.util.TypedValue; import android.view.Gravity; @@ -55,6 +56,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.Keep; +import androidx.annotation.NonNull; import androidx.core.graphics.ColorUtils; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.FloatValueHolder; @@ -67,6 +69,8 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; @@ -78,6 +82,7 @@ import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; 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.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenuItem; @@ -97,6 +102,7 @@ import org.telegram.ui.PhotoPickerSearchActivity; import java.util.ArrayList; import java.util.HashMap; +import java.util.Objects; public class ChatAttachAlert extends BottomSheet implements NotificationCenter.NotificationCenterDelegate, BottomSheet.BottomSheetDelegateInterface { @@ -107,9 +113,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private int codepointCount; public boolean canOpenPreview = false; + private boolean isSoundPicker = false; + public void setCanOpenPreview(boolean canOpenPreview) { this.canOpenPreview = canOpenPreview; - selectedArrowImageView.setVisibility(canOpenPreview ? View.VISIBLE : View.GONE); + selectedArrowImageView.setVisibility(canOpenPreview && avatarPicker != 2 ? View.VISIBLE : View.GONE); } public float getClipLayoutBottom() { @@ -117,13 +125,142 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return frameLayout2.getMeasuredHeight() - alphaOffset; } + public void showBotLayout(long id) { + showBotLayout(id, null); + } + + public void showBotLayout(long id, String startCommand) { + if (botAttachLayouts.get(id) == null || !Objects.equals(startCommand, botAttachLayouts.get(id).getStartCommand()) || botAttachLayouts.get(id).needReload()) { + if (baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).getCurrentUser() != null) { + ChatAttachAlertBotWebViewLayout webViewLayout = new ChatAttachAlertBotWebViewLayout(this, getContext(), resourcesProvider); + botAttachLayouts.put(id, webViewLayout); + botAttachLayouts.get(id).setDelegate(new BotWebViewContainer.Delegate() { + @Override + public void onCloseRequested() { + if (currentAttachLayout != webViewLayout) { + return; + } + dismiss(); + } + + @Override + public void onSendWebViewData(String data) { + // Empty as it's delegate from attachments menu. Data is only available for buttons + } + + @Override + public void onWebAppExpand() { + if (currentAttachLayout != webViewLayout) { + return; + } + + if (webViewLayout.canExpandByRequest()) { + webViewLayout.scrollToTop(); + } + } + + @Override + public void onSetupMainButton(boolean isVisible, boolean isActive, String text, int color, int textColor, boolean isProgressVisible) { + if (currentAttachLayout != webViewLayout || !webViewLayout.isBotButtonAvailable()) { + return; + } + botMainButtonTextView.setClickable(isActive); + botMainButtonTextView.setText(text); + botMainButtonTextView.setTextColor(textColor); + botMainButtonTextView.setBackground(Theme.createSelectorWithBackgroundDrawable(color, Theme.getColor(Theme.key_listSelector))); + if (botButtonWasVisible != isVisible) { + ValueAnimator animator = ValueAnimator.ofFloat(isVisible ? 0 : 1, isVisible ? 1 : 0).setDuration(250); + animator.addUpdateListener(animation -> { + float value = (float) animation.getAnimatedValue(); + buttonsRecyclerView.setAlpha(1f - value); + botMainButtonTextView.setAlpha(value); + botMainButtonOffsetY = value * AndroidUtilities.dp(36); + shadow.setTranslationY(botMainButtonOffsetY); + buttonsRecyclerView.setTranslationY(botMainButtonOffsetY); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + if (isVisible) { + botMainButtonTextView.setAlpha(0f); + botMainButtonTextView.setVisibility(View.VISIBLE); + } else { + buttonsRecyclerView.setAlpha(0f); + buttonsRecyclerView.setVisibility(View.VISIBLE); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + botButtonWasVisible = isVisible; + if (!isVisible) { + botMainButtonTextView.setVisibility(View.GONE); + } else { + buttonsRecyclerView.setVisibility(View.GONE); + } + + int offsetY = isVisible ? AndroidUtilities.dp(36) : 0; + for (int i = 0; i < botAttachLayouts.size(); i++) { + botAttachLayouts.valueAt(i).setMeasureOffsetY(offsetY); + } + } + }); + animator.start(); + } + botProgressView.setProgressColor(textColor); + if (botButtonProgressWasVisible != isProgressVisible) { + botProgressView.animate().cancel(); + if (isProgressVisible) { + botProgressView.setAlpha(0f); + botProgressView.setVisibility(View.VISIBLE); + } + botProgressView.animate().alpha(isProgressVisible ? 1f : 0f) + .scaleX(isProgressVisible ? 1f : 0.1f) + .scaleY(isProgressVisible ? 1f : 0.1f) + .setDuration(250) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + botButtonProgressWasVisible = isProgressVisible; + if (!isProgressVisible) { + botProgressView.setVisibility(View.GONE); + } + } + }).start(); + } + } + }); + MessageObject replyingObject = ((ChatActivity) baseFragment).getChatActivityEnterView().getReplyingMessageObject(); + botAttachLayouts.get(id).requestWebView(currentAccount, ((ChatActivity) baseFragment).getCurrentUser().id, id, false, replyingObject != null ? replyingObject.messageOwner.id : 0, startCommand); + } + } + if (botAttachLayouts.get(id) != null) { + botAttachLayouts.get(id).disallowSwipeOffsetAnimation(); + showLayout(botAttachLayouts.get(id), -id); + } + } + public interface ChatAttachViewDelegate { void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument); - View getRevealView(); - void didSelectBot(TLRPC.User user); + void onCameraOpened(); - boolean needEnterComment(); - void doOnIdle(Runnable runnable); + + default View getRevealView() { + return null; + } + + default void didSelectBot(TLRPC.User user) { + + } + + default boolean needEnterComment() { + return false; + } + + default void doOnIdle(Runnable runnable) { + runnable.run(); + } + default void openAvatarsSearch() { } @@ -330,7 +467,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return color != null ? color : Theme.getColor(key); } - boolean shouldHideBottomButtons() { return true; } + boolean shouldHideBottomButtons() { + return true; + } + + public void onPanTransitionStart(boolean keyboardVisible, int contentHeight) {} + + public void onPanTransitionEnd() {} } protected BaseFragment baseFragment; @@ -349,6 +492,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private ChatAttachAlertDocumentLayout documentLayout; private ChatAttachAlertPhotoLayoutPreview photoPreviewLayout; private AttachAlertLayout[] layouts = new AttachAlertLayout[7]; + private LongSparseArray botAttachLayouts = new LongSparseArray<>(); private AttachAlertLayout currentAttachLayout; private AttachAlertLayout nextAttachLayout; @@ -371,7 +515,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private float sendButtonEnabledProgress = 1f; private ValueAnimator sendButtonColorAnimator; - private int selectedId; + private long selectedId; protected float cornerRadius = 1.0f; @@ -401,6 +545,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private LinearLayoutManager buttonsLayoutManager; private ButtonsAdapter buttonsAdapter; + private boolean botButtonProgressWasVisible = false; + private RadialProgressView botProgressView; + + private boolean botButtonWasVisible = false; + private TextView botMainButtonTextView; + private float botMainButtonOffsetY; + protected MessageObject editingMessageObject; private boolean buttonPressed; @@ -536,8 +687,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N float scale = imageView.getScaleX() + 0.06f * checkedState; float radius = AndroidUtilities.dp(23) * scale; - float cx = imageView.getLeft() + imageView.getMeasuredWidth() / 2; - float cy = imageView.getTop() + imageView.getMeasuredWidth() / 2; + float cx = imageView.getLeft() + imageView.getMeasuredWidth() / 2f; + float cy = imageView.getTop() + imageView.getMeasuredWidth() / 2f; attachButtonPaint.setColor(getThemedColor(backgroundKey)); attachButtonPaint.setStyle(Paint.Style.STROKE); @@ -557,23 +708,56 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private class AttachBotButton extends FrameLayout { - private BackupImageView imageView; private TextView nameTextView; private AvatarDrawable avatarDrawable = new AvatarDrawable(); private TLRPC.User currentUser; + private TLRPC.TL_attachMenuBot attachMenuBot; + + private float checkedState; + private Boolean checked; + private ValueAnimator checkAnimator; + + private int textColor; + private int iconBackgroundColor; + + private View selector; public AttachBotButton(Context context) { super(context); - imageView = new BackupImageView(context); + setWillNotDraw(false); + setFocusable(true); + setFocusableInTouchMode(true); + + imageView = new BackupImageView(context) { + { + imageReceiver = new ImageReceiver(this) { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + if (drawable instanceof RLottieDrawable) { + ((RLottieDrawable) drawable).setCustomEndFrame(0); + ((RLottieDrawable) drawable).stop(); + ((RLottieDrawable) drawable).setProgress(0, false); + } + return super.setImageBitmapByKey(drawable, key, type, memCache, guid); + } + }; + } + + @Override + public void setScaleX(float scaleX) { + super.setScaleX(scaleX); + AttachBotButton.this.invalidate(); + } + }; imageView.setRoundRadius(AndroidUtilities.dp(25)); addView(imageView, LayoutHelper.createFrame(46, 46, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 9, 0, 0)); - if (Build.VERSION.SDK_INT >= 21) { - View selector = new View(context); - selector.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_dialogButtonSelector), 1, AndroidUtilities.dp(23))); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + selector = new View(context); + selector.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_dialogButtonSelector), 1, AndroidUtilities.dp(23))); addView(selector, LayoutHelper.createFrame(46, 46, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 9, 0, 0)); } @@ -591,6 +775,80 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N super.onMeasure(MeasureSpec.makeMeasureSpec(attachItemSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), MeasureSpec.EXACTLY)); } + public void setCheckedState(float state) { + checkedState = state; + imageView.setScaleX(1.0f - 0.06f * state); + imageView.setScaleY(1.0f - 0.06f * state); + nameTextView.setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_dialogTextGray2), textColor, checkedState)); + invalidate(); + } + + private void updateMargins() { + MarginLayoutParams params = (MarginLayoutParams) nameTextView.getLayoutParams(); + params.topMargin = AndroidUtilities.dp(attachMenuBot != null ? 62 : 60); + params = (MarginLayoutParams) imageView.getLayoutParams(); + params.topMargin = AndroidUtilities.dp(attachMenuBot != null ? 11 : 9); + } + + @Override + protected void onDraw(Canvas canvas) { + if (attachMenuBot != null) { + float imageScale = imageView.getScaleX(); + float scale = imageScale + 0.06f * checkedState; + float radius = AndroidUtilities.dp(23) * scale; + + float cx = imageView.getLeft() + imageView.getMeasuredWidth() / 2f; + float cy = imageView.getTop() + imageView.getMeasuredWidth() / 2f; + + attachButtonPaint.setColor(iconBackgroundColor); + attachButtonPaint.setStyle(Paint.Style.STROKE); + attachButtonPaint.setStrokeWidth(AndroidUtilities.dp(3) * scale); + attachButtonPaint.setAlpha(Math.round(255f * checkedState)); + canvas.drawCircle(cx, cy, radius - 0.5f * attachButtonPaint.getStrokeWidth(), attachButtonPaint); + + attachButtonPaint.setAlpha(255); + attachButtonPaint.setStyle(Paint.Style.FILL); + canvas.drawCircle(cx, cy, radius - AndroidUtilities.dp(5) * checkedState, attachButtonPaint); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + updateCheckedState(false); + } + + void updateCheckedState(boolean animate) { + boolean newChecked = attachMenuBot != null && -currentUser.id == selectedId; + if (checked != null && checked == newChecked && animate) { + return; + } + checked = newChecked; + if (checkAnimator != null) { + checkAnimator.cancel(); + } + RLottieDrawable drawable = imageView.getImageReceiver().getLottieAnimation(); + if (animate) { + if (checked && drawable != null) { + drawable.setAutoRepeat(0); + drawable.setCustomEndFrame(-1); + drawable.setProgress(0, false); + drawable.start(); + } + + checkAnimator = ValueAnimator.ofFloat(checked ? 0f : 1f, checked ? 1f : 0f); + checkAnimator.addUpdateListener(animation -> setCheckedState((float)animation.getAnimatedValue())); + checkAnimator.setDuration(200); + checkAnimator.start(); + } else { + if (drawable != null) { + drawable.stop(); + drawable.setProgress(0, false); + } + setCheckedState(checked ? 1f : 0f); + } + } + public void setUser(TLRPC.User user) { if (user == null) { return; @@ -600,7 +858,73 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); avatarDrawable.setInfo(user); imageView.setForUserOrChat(user, avatarDrawable); - requestLayout(); + imageView.setSize(-1, -1); + imageView.setColorFilter(null); + attachMenuBot = null; + selector.setVisibility(VISIBLE); + updateMargins(); + setCheckedState(0f); + invalidate(); + } + + public void setAttachBot(TLRPC.User user, TLRPC.TL_attachMenuBot bot) { + if (user == null || bot == null) { + return; + } + nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); + currentUser = user; + nameTextView.setText(bot.short_name); + avatarDrawable.setInfo(user); + + boolean animated = true; + TLRPC.TL_attachMenuBotIcon icon = MediaDataController.getAnimatedAttachMenuBotIcon(bot); + if (icon == null) { + icon = MediaDataController.getStaticAttachMenuBotIcon(bot); + animated = false; + } + if (icon != null) { + textColor = getThemedColor(Theme.key_chat_attachContactText); + iconBackgroundColor = getThemedColor(Theme.key_chat_attachContactBackground); + + for (TLRPC.TL_attachMenuBotIconColor color : icon.colors) { + switch (color.name) { + case MediaDataController.ATTACH_MENU_BOT_COLOR_LIGHT_ICON: + if (!Theme.getCurrentTheme().isDark()) { + iconBackgroundColor = color.color; + } + break; + case MediaDataController.ATTACH_MENU_BOT_COLOR_LIGHT_TEXT: + if (!Theme.getCurrentTheme().isDark()) { + textColor = color.color; + } + break; + case MediaDataController.ATTACH_MENU_BOT_COLOR_DARK_ICON: + if (Theme.getCurrentTheme().isDark()) { + iconBackgroundColor = color.color; + } + break; + case MediaDataController.ATTACH_MENU_BOT_COLOR_DARK_TEXT: + if (Theme.getCurrentTheme().isDark()) { + textColor = color.color; + } + break; + } + } + textColor = ColorUtils.setAlphaComponent(textColor, 0xFF); + iconBackgroundColor = ColorUtils.setAlphaComponent(iconBackgroundColor, 0xFF); + + TLRPC.Document iconDoc = icon.icon; + imageView.getImageReceiver().setAllowStartLottieAnimation(false); + imageView.setImage(ImageLocation.getForDocument(iconDoc), "32_32", animated ? "tgs" : "svg", null, icon); + } + + imageView.setSize(AndroidUtilities.dp(28), AndroidUtilities.dp(28)); + imageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_attachContactIcon), PorterDuff.Mode.SRC_IN)); + attachMenuBot = bot; + selector.setVisibility(GONE); + updateMargins(); + setCheckedState(0f); + invalidate(); } } @@ -625,6 +949,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N useSmoothKeyboard = true; setDelegate(this); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.reloadInlineHints); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.attachMenuBotsDidLoad); exclusionRects.add(exclustionRect); sizeNotifierFrameLayout = new SizeNotifierFrameLayout(context) { @@ -646,6 +971,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N fromScrollY = -1; } invalidate(); + + currentAttachLayout.onPanTransitionStart(keyboardVisible, contentHeight); } @Override @@ -653,6 +980,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N super.onTransitionEnd(); updateLayout(currentAttachLayout, false, 0); previousScrollOffsetY = scrollOffsetY[0]; + currentAttachLayout.onPanTransitionEnd(); } @Override @@ -1206,8 +1534,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N buttonsRecyclerView.setTranslationY(AndroidUtilities.dp(44) * alpha); } frameLayout2.setTranslationY(AndroidUtilities.dp(48) * alpha); - shadow.setTranslationY(AndroidUtilities.dp(84) * alpha); - } else if (currentAttachLayout == null || currentAttachLayout.shouldHideBottomButtons()) { + shadow.setTranslationY(AndroidUtilities.dp(84) * alpha + botMainButtonOffsetY); + } else if (currentAttachLayout == null) { float value = alpha == 0.0f ? 1.0f : 0.0f; if (buttonsRecyclerView.getAlpha() != value) { buttonsRecyclerView.setAlpha(value); @@ -1381,6 +1709,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N Drawable arrowRight = getContext().getResources().getDrawable(R.drawable.attach_arrow_right).mutate(); arrowRight.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); selectedArrowImageView.setImageDrawable(arrowRight); + selectedArrowImageView.setVisibility(View.GONE); selectedView.addView(selectedArrowImageView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 4, 1, 0, 0)); headerView.addView(selectedView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT)); @@ -1511,8 +1840,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } else if (view instanceof AttachBotButton) { AttachBotButton button = (AttachBotButton) view; - delegate.didSelectBot(button.currentUser); - dismiss(); + if (button.attachMenuBot != null) { + showBotLayout(button.attachMenuBot.bot_id); + } else { + delegate.didSelectBot(button.currentUser); + dismiss(); + } } if (view.getX() + view.getWidth() >= buttonsRecyclerView.getMeasuredWidth() - AndroidUtilities.dp(32)) { @@ -1525,17 +1858,39 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (baseFragment == null || button.currentUser == null) { return false; } - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.formatString("ChatHintsDelete", R.string.ChatHintsDelete, ContactsController.formatName(button.currentUser.first_name, button.currentUser.last_name))); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MediaDataController.getInstance(currentAccount).removeInline(button.currentUser.id)); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.show(); + onLongClickBotButton(button.attachMenuBot, button.currentUser); return true; } return false; }); + botMainButtonTextView = new TextView(context); + botMainButtonTextView.setVisibility(View.GONE); + botMainButtonTextView.setAlpha(0f); + botMainButtonTextView.setSingleLine(); + botMainButtonTextView.setGravity(Gravity.CENTER); + botMainButtonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + int padding = AndroidUtilities.dp(16); + botMainButtonTextView.setPadding(padding, 0, padding, 0); + botMainButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + botMainButtonTextView.setOnClickListener(v -> { + if (selectedId < 0) { + ChatAttachAlertBotWebViewLayout webViewLayout = botAttachLayouts.get(-selectedId); + if (webViewLayout != null) { + webViewLayout.getWebViewContainer().onMainButtonPressed(); + } + } + }); + containerView.addView(botMainButtonTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); + + botProgressView = new RadialProgressView(context); + botProgressView.setSize(AndroidUtilities.dp(18)); + botProgressView.setAlpha(0f); + botProgressView.setScaleX(0.1f); + botProgressView.setScaleY(0.1f); + botProgressView.setVisibility(View.GONE); + containerView.addView(botProgressView, LayoutHelper.createFrame(28, 28, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, 10, 10)); + frameLayout2 = new FrameLayout(context) { private final Paint p = new Paint(); @@ -1567,7 +1922,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } float alphaOffset = (frameLayout2.getMeasuredHeight() - AndroidUtilities.dp(84)) * (1f - getAlpha()); - shadow.setTranslationY(-(frameLayout2.getMeasuredHeight() - AndroidUtilities.dp(84)) + captionEditTextTopOffset + currentPanTranslationY + bottomPannelTranslation + alphaOffset); + shadow.setTranslationY(-(frameLayout2.getMeasuredHeight() - AndroidUtilities.dp(84)) + captionEditTextTopOffset + currentPanTranslationY + bottomPannelTranslation + alphaOffset + botMainButtonOffsetY); int newColor = getThemedColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground); if (color != newColor) { @@ -1969,6 +2324,35 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } + public void onLongClickBotButton(TLRPC.TL_attachMenuBot attachMenuBot, TLRPC.User currentUser) { + String botName = attachMenuBot != null ? attachMenuBot.short_name : UserObject.getUserName(currentUser); + new AlertDialog.Builder(getContext()) + .setTitle(LocaleController.getString(attachMenuBot != null ? R.string.BotRemoveFromMenuTitle : R.string.AppName)) + .setMessage(AndroidUtilities.replaceTags(attachMenuBot != null ? LocaleController.formatString("BotRemoveFromMenu", R.string.BotRemoveFromMenu, botName) : LocaleController.formatString("ChatHintsDelete", R.string.ChatHintsDelete, botName))) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (attachMenuBot != null) { + TLRPC.TL_messages_toggleBotInAttachMenu req = new TLRPC.TL_messages_toggleBotInAttachMenu(); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(currentUser); + req.enabled = false; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(()-> { + MediaDataController.getInstance(currentAccount).loadAttachMenuBots(false, true); + if (currentAttachLayout == botAttachLayouts.get(attachMenuBot.bot_id)) { + showLayout(photoLayout); + } + }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); + } else { + MediaDataController.getInstance(currentAccount).removeInline(currentUser.id); + } + }) + .setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null) + .show(); + } + + @Override + protected boolean shouldOverlayCameraViewOverNavBar() { + return currentAttachLayout == photoLayout && photoLayout.cameraExpanded; + } + @Override public void show() { super.show(); @@ -1980,7 +2364,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N openTransitionFinished = false; if (Build.VERSION.SDK_INT >= 30) { int color = getThemedColor(Theme.key_windowBackgroundGray); - getWindow().setNavigationBarColor(color); + AndroidUtilities.setNavigationBarColor(getWindow(), color, false, tcolor -> { + navBarColorKey = null; + navBarColor = tcolor; + containerView.invalidate(); + }); AndroidUtilities.setLightNavigationBar(getWindow(), AndroidUtilities.computePerceivedBrightness(color) > 0.721); } } @@ -2029,6 +2417,24 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private void showLayout(AttachAlertLayout layout) { + long newId = selectedId; + if (layout == photoLayout) { + newId = 1; + } else if (layout == audioLayout) { + newId = 3; + } else if (layout == documentLayout) { + newId = 4; + } else if (layout == contactsLayout) { + newId = 5; + } else if (layout == locationLayout) { + newId = 6; + } else if (layout == pollLayout) { + newId = 9; + } + showLayout(layout, newId); + } + + private void showLayout(AttachAlertLayout layout, long newId) { if (viewChangeAnimator != null || commentsAnimator != null) { return; } @@ -2036,25 +2442,31 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N currentAttachLayout.scrollToTop(); return; } - if (layout == photoLayout) { - selectedId = 1; - } else if (layout == audioLayout) { - selectedId = 3; - } else if (layout == documentLayout) { - selectedId = 4; - } else if (layout == contactsLayout) { - selectedId = 5; - } else if (layout == locationLayout) { - selectedId = 6; - } else if (layout == pollLayout) { - selectedId = 9; + + botButtonWasVisible = false; + botButtonProgressWasVisible = false; + botMainButtonOffsetY = 0; + botMainButtonTextView.setVisibility(View.GONE); + botProgressView.setAlpha(0f); + botProgressView.setScaleX(0.1f); + botProgressView.setScaleY(0.1f); + botProgressView.setVisibility(View.GONE); + buttonsRecyclerView.setAlpha(1f); + buttonsRecyclerView.setTranslationY(botMainButtonOffsetY); + for (int i = 0; i < botAttachLayouts.size(); i++) { + botAttachLayouts.valueAt(i).setMeasureOffsetY(0); } + + selectedId = newId; int count = buttonsRecyclerView.getChildCount(); for (int a = 0; a < count; a++) { View child = buttonsRecyclerView.getChildAt(a); if (child instanceof AttachButton) { AttachButton attachButton = (AttachButton) child; attachButton.updateCheckedState(true); + } else if (child instanceof AttachBotButton) { + AttachBotButton attachButton = (AttachBotButton) child; + attachButton.updateCheckedState(true); } } int t = currentAttachLayout.getFirstOffset() - AndroidUtilities.dp(11) - scrollOffsetY[0]; @@ -2104,7 +2516,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N nextAttachLayout.setTranslationY(AndroidUtilities.dp(78)); animator.playTogether( ObjectAnimator.ofFloat(currentAttachLayout, View.TRANSLATION_Y, AndroidUtilities.dp(78) + t), - ObjectAnimator.ofFloat(currentAttachLayout, ATTACH_ALERT_LAYOUT_TRANSLATION, 0.0f, 1.0f) + ObjectAnimator.ofFloat(currentAttachLayout, ATTACH_ALERT_LAYOUT_TRANSLATION, 0.0f, 1.0f), + ObjectAnimator.ofFloat(actionBar, View.ALPHA, actionBar.getAlpha(), 0f) ); animator.setDuration(180); animator.setStartDelay(20); @@ -2158,10 +2571,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N currentAttachLayout.setAlpha(1); ATTACH_ALERT_LAYOUT_TRANSLATION.set(currentAttachLayout, 0.0f); + float fromActionBarAlpha = actionBar.getAlpha(); SpringAnimation springAnimation = new SpringAnimation(new FloatValueHolder(0)); springAnimation.addUpdateListener((animation, value, velocity) -> { float f = value / 500f; ATTACH_ALERT_LAYOUT_TRANSLATION.set(currentAttachLayout, f); + actionBar.setAlpha(AndroidUtilities.lerp(fromActionBarAlpha, 0, f)); mediaPreviewView.setAlpha(nextAttachLayout instanceof ChatAttachAlertPhotoLayoutPreview ? f : 1f - f); }); springAnimation.addEndListener((animation, canceled, value, velocity) -> { @@ -2229,12 +2644,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private void openDocumentsLayout(boolean show) { if (documentLayout == null) { - layouts[4] = documentLayout = new ChatAttachAlertDocumentLayout(this, getContext(), false, resourcesProvider); + int type = isSoundPicker ? ChatAttachAlertDocumentLayout.TYPE_RINGTONE : ChatAttachAlertDocumentLayout.TYPE_DEFAULT; + layouts[4] = documentLayout = new ChatAttachAlertDocumentLayout(this, getContext(), type, resourcesProvider); documentLayout.setDelegate(new ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate() { @Override public void didSelectFiles(ArrayList files, String caption, ArrayList fmessages, boolean notify, int scheduleDate) { - if (baseFragment instanceof ChatActivity) { - ((ChatActivity) baseFragment).didSelectFiles(files, caption, fmessages, notify, scheduleDate); + if (baseFragment instanceof ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate) { + ((ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate) baseFragment).didSelectFiles(files, caption, fmessages, notify, scheduleDate); } else if (baseFragment instanceof PassportActivity) { ((PassportActivity) baseFragment).didSelectFiles(files, caption, notify, scheduleDate); } @@ -2251,8 +2667,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void startDocumentSelectActivity() { - if (baseFragment instanceof ChatActivity) { - ((ChatActivity) baseFragment).startDocumentSelectActivity(); + if (baseFragment instanceof ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate) { + ((ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate) baseFragment).startDocumentSelectActivity(); } else if (baseFragment instanceof PassportActivity) { ((PassportActivity) baseFragment).startDocumentSelectActivity(); } @@ -2270,8 +2686,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N documentLayout.setMaxSelectedFiles(currentChat != null && !ChatObject.hasAdminRights(currentChat) && currentChat.slowmode_enabled || editingMessageObject != null ? 1 : -1); } else { documentLayout.setMaxSelectedFiles(maxSelectedPhotos); - documentLayout.setCanSelectOnlyImageFiles(true); + documentLayout.setCanSelectOnlyImageFiles(!isSoundPicker); } + documentLayout.isSoundPicker = isSoundPicker; if (show) { showLayout(documentLayout); } @@ -2290,9 +2707,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } commentTextView.hidePopup(true); if (show) { - frameLayout2.setVisibility(View.VISIBLE); + if (!isSoundPicker) { + frameLayout2.setVisibility(View.VISIBLE); + } writeButtonContainer.setVisibility(View.VISIBLE); - if (!typeButtonsAvailable) { + if (!typeButtonsAvailable && !isSoundPicker) { shadow.setVisibility(View.VISIBLE); } } else if (typeButtonsAvailable) { @@ -2313,12 +2732,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N animators.add(ObjectAnimator.ofFloat(shadow, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : AndroidUtilities.dp(48 + 36))); animators.add(ObjectAnimator.ofFloat(shadow, View.ALPHA, show ? 1.0f : 0.0f)); } else if (typeButtonsAvailable) { - if (currentAttachLayout == null || currentAttachLayout.shouldHideBottomButtons()) { - animators.add(ObjectAnimator.ofFloat(buttonsRecyclerView, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : 0)); - } + animators.add(ObjectAnimator.ofFloat(buttonsRecyclerView, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : 0)); animators.add(ObjectAnimator.ofFloat(shadow, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : 0)); - } else { - shadow.setTranslationY(AndroidUtilities.dp(36)); + } else if (!isSoundPicker) { + shadow.setTranslationY(AndroidUtilities.dp(36) + botMainButtonOffsetY); animators.add(ObjectAnimator.ofFloat(shadow, View.ALPHA, show ? 1.0f : 0.0f)); } @@ -2330,9 +2747,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public void onAnimationEnd(Animator animation) { if (animation.equals(commentsAnimator)) { if (!show) { - frameLayout2.setVisibility(View.INVISIBLE); + if (!isSoundPicker) { + frameLayout2.setVisibility(View.INVISIBLE); + } writeButtonContainer.setVisibility(View.INVISIBLE); - if (!typeButtonsAvailable) { + if (!typeButtonsAvailable && !isSoundPicker) { shadow.setVisibility(View.INVISIBLE); } } else if (typeButtonsAvailable) { @@ -2362,15 +2781,15 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N selectedCountView.setAlpha(show ? 1.0f : 0.0f); if (actionBar.getTag() != null) { frameLayout2.setTranslationY(show ? 0.0f : AndroidUtilities.dp(48)); - shadow.setTranslationY(show ? AndroidUtilities.dp(36) : AndroidUtilities.dp(48 + 36)); + shadow.setTranslationY((show ? AndroidUtilities.dp(36) : AndroidUtilities.dp(48 + 36)) + botMainButtonOffsetY); shadow.setAlpha(show ? 1.0f : 0.0f); } else if (typeButtonsAvailable) { if (currentAttachLayout == null || currentAttachLayout.shouldHideBottomButtons()) { buttonsRecyclerView.setTranslationY(show ? AndroidUtilities.dp(36) : 0); } - shadow.setTranslationY(show ? AndroidUtilities.dp(36) : 0); + shadow.setTranslationY((show ? AndroidUtilities.dp(36) : 0) + botMainButtonOffsetY); } else { - shadow.setTranslationY(AndroidUtilities.dp(36)); + shadow.setTranslationY(AndroidUtilities.dp(36) + botMainButtonOffsetY); shadow.setAlpha(show ? 1.0f : 0.0f); } if (!show) { @@ -2539,6 +2958,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } protected void makeFocusable(EditTextBoldCursor editText, boolean showKeyboard) { + if (delegate == null) { + return; + } if (!enterCommentEventSent) { boolean keyboardVisible = delegate.needEnterComment(); enterCommentEventSent = true; @@ -2558,7 +2980,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N button.textView.setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_dialogTextGray2), getThemedColor(button.textKey), button.checkedState)); } else if (view instanceof AttachBotButton) { AttachBotButton button = (AttachBotButton) view; - button.nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); + button.nameTextView.setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_dialogTextGray2), button.textColor, button.checkedState)); } } @@ -2686,7 +3108,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void didReceivedNotification(int id, int account, Object... args) { - if (id == NotificationCenter.reloadInlineHints) { + if (id == NotificationCenter.reloadInlineHints || id == NotificationCenter.attachMenuBotsDidLoad) { if (buttonsAdapter != null) { buttonsAdapter.notifyDataSetChanged(); } @@ -2767,7 +3189,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (needMoreItem) { selectedMenuItem.setVisibility(View.VISIBLE); } - } else if (typeButtonsAvailable) { + } else if (typeButtonsAvailable && frameLayout2.getTag() == null) { buttonsRecyclerView.setVisibility(View.VISIBLE); } if (animated) { @@ -2961,6 +3383,21 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (baseFragment == null) { return; } + + botButtonWasVisible = false; + botButtonProgressWasVisible = false; + botMainButtonOffsetY = 0; + botMainButtonTextView.setVisibility(View.GONE); + botProgressView.setAlpha(0f); + botProgressView.setScaleX(0.1f); + botProgressView.setScaleY(0.1f); + botProgressView.setVisibility(View.GONE); + buttonsRecyclerView.setAlpha(1f); + buttonsRecyclerView.setTranslationY(0); + for (int i = 0; i < botAttachLayouts.size(); i++) { + botAttachLayouts.valueAt(i).setMeasureOffsetY(0); + } + if (baseFragment instanceof ChatActivity && avatarPicker != 2) { TLRPC.Chat chat = ((ChatActivity) baseFragment).getCurrentChat(); TLRPC.User user = ((ChatActivity) baseFragment).getCurrentUser(); @@ -2978,7 +3415,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N enterCommentEventSent = false; setFocusable(false); ChatAttachAlert.AttachAlertLayout layoutToSet; - if (editingMessageObject != null && (editingMessageObject.isMusic() || (editingMessageObject.isDocument() && !editingMessageObject.isGif()))) { + if (isSoundPicker) { + openDocumentsLayout(false); + layoutToSet = documentLayout; + selectedId = 4; + } else if (editingMessageObject != null && (editingMessageObject.isMusic() || (editingMessageObject.isDocument() && !editingMessageObject.isGif()))) { if (editingMessageObject.isMusic()) { openAudioLayout(false); layoutToSet = audioLayout; @@ -3034,6 +3475,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.reloadInlineHints); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.attachMenuBotsDidLoad); baseFragment = null; if (commentTextView != null) { commentTextView.onDestroy(); @@ -3077,7 +3519,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N avatarSearch = search; if (avatarPicker != 0) { typeButtonsAvailable = false; - if (currentAttachLayout == null || currentAttachLayout.shouldHideBottomButtons()) { + if (currentAttachLayout == null) { buttonsRecyclerView.setVisibility(View.GONE); shadow.setVisibility(View.GONE); } @@ -3091,6 +3533,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } + public void setSoundPicker() { + isSoundPicker = true; + buttonsRecyclerView.setVisibility(View.GONE); + shadow.setVisibility(View.GONE); + selectedTextView.setText(LocaleController.getString("ChoosePhotoOrVideo", R.string.ChoosePhotoOrVideo)); + } + public void setMaxSelectedPhotos(int value, boolean order) { if (editingMessageObject != null) { return; @@ -3108,9 +3557,14 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private class ButtonsAdapter extends RecyclerListView.SelectionAdapter { + private final static int VIEW_TYPE_BUTTON = 0, VIEW_TYPE_BOT_BUTTON = 1; private Context mContext; private int galleryButton; + + private int attachBotsStartRow; + private int attachBotsEndRow; + private int documentButton; private int musicButton; private int pollButton; @@ -3122,14 +3576,15 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N mContext = context; } + @NonNull @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_BUTTON: view = new AttachButton(mContext); break; - case 1: + case VIEW_TYPE_BOT_BUTTON: default: view = new AttachBotButton(mContext); break; @@ -3140,7 +3595,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: + case VIEW_TYPE_BUTTON: AttachButton attachButton = (AttachButton) holder.itemView; if (position == galleryButton) { attachButton.setTextAndIcon(1, LocaleController.getString("ChatGallery", R.string.ChatGallery), Theme.chat_attachButtonDrawables[0], Theme.key_chat_attachGalleryBackground, Theme.key_chat_attachGalleryText); @@ -3162,9 +3617,17 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N attachButton.setTag(5); } break; - case 1: - position -= buttonsCount; + case VIEW_TYPE_BOT_BUTTON: AttachBotButton child = (AttachBotButton) holder.itemView; + if (position >= attachBotsStartRow && position < attachBotsEndRow) { + position -= attachBotsStartRow; + child.setTag(position); + TLRPC.TL_attachMenuBot bot = MediaDataController.getInstance(currentAccount).getAttachMenuBots().bots.get(position); + child.setAttachBot(MessagesController.getInstance(currentAccount).getUser(bot.bot_id), bot); + break; + } + + position -= buttonsCount; child.setTag(position); child.setUser(MessagesController.getInstance(currentAccount).getUser(MediaDataController.getInstance(currentAccount).inlineBots.get(position).peer.user_id)); break; @@ -3199,6 +3662,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N pollButton = -1; contactButton = -1; locationButton = -1; + attachBotsStartRow = -1; + attachBotsEndRow = -1; if (!(baseFragment instanceof ChatActivity)) { galleryButton = buttonsCount++; documentButton = buttonsCount++; @@ -3217,6 +3682,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { if (mediaEnabled) { galleryButton = buttonsCount++; + + if (baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).getCurrentUser() != null && !((ChatActivity) baseFragment).isInScheduleMode() && !((ChatActivity) baseFragment).isSecretChat()) { + attachBotsStartRow = buttonsCount; + buttonsCount += MediaDataController.getInstance(currentAccount).getAttachMenuBots().bots.size(); + attachBotsEndRow = buttonsCount; + } + documentButton = buttonsCount++; } locationButton = buttonsCount++; @@ -3243,15 +3715,22 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public int getItemViewType(int position) { if (position < buttonsCount) { - return 0; + if (position >= attachBotsStartRow && position < attachBotsEndRow) { + return VIEW_TYPE_BOT_BUTTON; + } + return VIEW_TYPE_BUTTON; } - return 1; + return VIEW_TYPE_BOT_BUTTON; } } @Override public void dismissInternal() { - delegate.doOnIdle(this::removeFromRoot); + if (delegate != null) { + delegate.doOnIdle(this::removeFromRoot); + } else { + removeFromRoot(); + } } private void removeFromRoot() { @@ -3323,6 +3802,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (commentTextView != null) { AndroidUtilities.hideKeyboard(commentTextView.getEditText()); } + botAttachLayouts.clear(); if (!allowPassConfirmationAlert && baseFragment != null && currentAttachLayout.getSelectedItemsCount() > 0) { if (confirmationAlertShown) { return; @@ -3362,6 +3842,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N layouts[a].onDismiss(); } } + AndroidUtilities.setNavigationBarColor(getWindow(), ColorUtils.setAlphaComponent(navBarColor, 0), true, tcolor -> { + navBarColorKey = null; + navBarColor = tcolor; + containerView.invalidate(); + }); super.dismiss(); allowPassConfirmationAlert = false; } @@ -3386,4 +3871,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public EditTextEmoji getCommentTextView() { return commentTextView; } + + public ChatAttachAlertDocumentLayout getDocumentLayout() { + return documentLayout; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java new file mode 100644 index 000000000..e90fd7403 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java @@ -0,0 +1,812 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Build; +import android.os.Bundle; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.WindowManager; +import android.webkit.WebView; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.core.math.MathUtils; +import androidx.core.view.GestureDetectorCompat; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; +import androidx.recyclerview.widget.ChatListItemAnimator; + +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserObject; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; + +public class ChatAttachAlertBotWebViewLayout extends ChatAttachAlert.AttachAlertLayout implements NotificationCenter.NotificationCenterDelegate { + private final static int POLL_PERIOD = 60000; + + private BotWebViewContainer webViewContainer; + private ValueAnimator webViewScrollAnimator; + + private boolean ignoreLayout; + + private long botId; + private long peerId; + private long queryId; + private boolean silent; + private int replyToMsgId; + private int currentAccount; + private String startCommand; + + private boolean needReload; + private WebProgressView progressView; + private WebViewSwipeContainer swipeContainer; + private ActionBarMenuItem otherItem; + + private int measureOffsetY; + + private long lastSwipeTime; + + private boolean ignoreMeasure; + private boolean isBotButtonAvailable; + + private boolean destroyed; + private Runnable pollRunnable = () -> { + if (!destroyed) { + TLRPC.TL_messages_prolongWebView prolongWebView = new TLRPC.TL_messages_prolongWebView(); + prolongWebView.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + prolongWebView.peer = MessagesController.getInstance(currentAccount).getInputPeer(peerId); + prolongWebView.query_id = queryId; + prolongWebView.silent = silent; + if (replyToMsgId != 0) { + prolongWebView.reply_to_msg_id = replyToMsgId; + prolongWebView.flags |= 1; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(prolongWebView, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (destroyed) { + return; + } + if (error != null) { + parentAlert.dismiss(); + } else { + AndroidUtilities.runOnUIThread(this.pollRunnable, POLL_PERIOD); + } + })); + } + }; + + public ChatAttachAlertBotWebViewLayout(ChatAttachAlert alert, Context context, Theme.ResourcesProvider resourcesProvider) { + super(alert, context, resourcesProvider); + + ActionBarMenu menu = parentAlert.actionBar.createMenu(); + otherItem = menu.addItem(0, R.drawable.ic_ab_other); + otherItem.addSubItem(R.id.menu_open_bot, R.drawable.msg_bot, LocaleController.getString(R.string.BotWebViewOpenBot)); + otherItem.addSubItem(R.id.menu_reload_page, R.drawable.msg_retry, LocaleController.getString(R.string.BotWebViewReloadPage)); + otherItem.addSubItem(R.id.menu_delete_bot, R.drawable.msg_delete, LocaleController.getString(R.string.BotWebViewDeleteBot)); + parentAlert.actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + parentAlert.dismiss(); + } else if (id == R.id.menu_open_bot) { + Bundle bundle = new Bundle(); + bundle.putLong("user_id", botId); + parentAlert.baseFragment.presentFragment(new ChatActivity(bundle)); + parentAlert.dismiss(); + } else if (id == R.id.menu_reload_page) { + webViewContainer.getWebView().animate().cancel(); + webViewContainer.getWebView().animate().alpha(0).start(); + requestWebView(currentAccount, peerId, botId, silent, replyToMsgId, startCommand); + } else if (id == R.id.menu_delete_bot) { + for (TLRPC.TL_attachMenuBot bot : MediaDataController.getInstance(currentAccount).getAttachMenuBots().bots) { + if (bot.bot_id == botId) { + parentAlert.onLongClickBotButton(bot, MessagesController.getInstance(currentAccount).getUser(botId)); + break; + } + } + } + } + }); + + webViewContainer = new BotWebViewContainer(context, resourcesProvider, getThemedColor(Theme.key_dialogBackground)) { + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + if (!isBotButtonAvailable) { + isBotButtonAvailable = true; + webViewContainer.restoreButtonData(); + } + } + return super.dispatchTouchEvent(ev); + } + }; + webViewContainer.getWebView().setVerticalScrollBarEnabled(false); + swipeContainer = new WebViewSwipeContainer(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(84) + measureOffsetY, MeasureSpec.EXACTLY)); + } + }; + swipeContainer.addView(webViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + swipeContainer.setWebView(webViewContainer.getWebView()); + swipeContainer.setScrollListener(() -> { + parentAlert.updateLayout(this, true, 0); + webViewContainer.invalidateViewPortHeight(); + lastSwipeTime = System.currentTimeMillis(); + }); + swipeContainer.setScrollEndListener(()-> webViewContainer.invalidateViewPortHeight(true)); + swipeContainer.setDelegate(() -> parentAlert.dismiss()); + + addView(swipeContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + addView(progressView = new WebProgressView(context, resourcesProvider), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 0, 0, 0, 84)); + + webViewContainer.setWebViewProgressListener(progress -> { + progressView.setLoadProgressAnimated(progress); + if (progress == 1f) { + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> progressView.setAlpha((Float) animation.getAnimatedValue())); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressView.setVisibility(GONE); + } + }); + animator.start(); + } + }); + } + + public boolean canExpandByRequest() { + return System.currentTimeMillis() - lastSwipeTime > 1000 && !swipeContainer.isSwipeInProgress(); + } + + public void setMeasureOffsetY(int measureOffsetY) { + this.measureOffsetY = measureOffsetY; + swipeContainer.requestLayout(); + } + + public void disallowSwipeOffsetAnimation() { + swipeContainer.setSwipeOffsetAnimationDisallowed(true); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (ignoreMeasure) { + setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight()); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + @Override + public void onPanTransitionStart(boolean keyboardVisible, int contentHeight) { + if (!keyboardVisible) { + return; + } + + int oldh = contentHeight + parentAlert.sizeNotifierFrameLayout.measureKeyboardHeight(); + setMeasuredDimension(getMeasuredWidth(), contentHeight); + ignoreMeasure = true; + + if (webViewScrollAnimator != null) { + webViewScrollAnimator.cancel(); + webViewScrollAnimator = null; + } + + int fromY = webViewContainer.getWebView().getScrollY(); + int toY = fromY + (oldh - contentHeight); + webViewScrollAnimator = ValueAnimator.ofInt(fromY, toY).setDuration(250); + webViewScrollAnimator.setInterpolator(ChatListItemAnimator.DEFAULT_INTERPOLATOR); + webViewScrollAnimator.addUpdateListener(animation -> { + int val = (int) animation.getAnimatedValue(); + webViewContainer.getWebView().setScrollY(val); + }); + webViewScrollAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + webViewContainer.getWebView().setScrollY(toY); + if (animation == webViewScrollAnimator) { + webViewScrollAnimator = null; + } + } + }); + webViewScrollAnimator.start(); + } + + @Override + public void onPanTransitionEnd() { + ignoreMeasure = false; + requestLayout(); + } + + @Override + void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + parentAlert.actionBar.setTitle(UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(botId))); + swipeContainer.setSwipeOffsetY(0); + webViewContainer.getWebView().scrollTo(0, 0); + if (parentAlert.getBaseFragment() != null) { + webViewContainer.setParentActivity(parentAlert.getBaseFragment().getParentActivity()); + } + otherItem.setVisibility(VISIBLE); + } + + @Override + void onShown() { + requestEnableKeyboard(); + + swipeContainer.setSwipeOffsetAnimationDisallowed(false); + AndroidUtilities.runOnUIThread(() -> webViewContainer.restoreButtonData()); + } + + private void requestEnableKeyboard() { + BaseFragment fragment = parentAlert.getBaseFragment(); + if (fragment instanceof ChatActivity && ((ChatActivity) fragment).contentView.measureKeyboardHeight() > AndroidUtilities.dp(20)) { + AndroidUtilities.hideKeyboard(parentAlert.baseFragment.getFragmentView()); + AndroidUtilities.runOnUIThread(this::requestEnableKeyboard, 150); + return; + } + + setFocusable(true); + parentAlert.setFocusable(true); + parentAlert.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } + + @Override + void onHidden() { + super.onHidden(); + + parentAlert.setFocusable(false); + parentAlert.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); + } + + @Override + int getCurrentItemTop() { + return (int) (swipeContainer.getSwipeOffsetY() + swipeContainer.getOffsetY()); + } + + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + parentAlert.getSheetContainer().invalidate(); + } + + public String getStartCommand() { + return startCommand; + } + + public void requestWebView(int currentAccount, long peerId, long botId, boolean silent, int replyToMsgId) { + requestWebView(currentAccount, peerId, botId, silent, replyToMsgId, null); + } + + public void requestWebView(int currentAccount, long peerId, long botId, boolean silent, int replyToMsgId, String startCommand) { + this.currentAccount = currentAccount; + this.peerId = peerId; + this.botId = botId; + this.silent = silent; + this.replyToMsgId = replyToMsgId; + this.startCommand = startCommand; + + webViewContainer.setBotUser(MessagesController.getInstance(currentAccount).getUser(botId)); + webViewContainer.loadFlicker(currentAccount, botId); + + TLRPC.TL_messages_requestWebView req = new TLRPC.TL_messages_requestWebView(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(peerId); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + req.silent = silent; + if (startCommand != null) { + req.start_param = startCommand; + req.flags |= 8; + } + + if (replyToMsgId != 0) { + req.reply_to_msg_id = replyToMsgId; + req.flags |= 1; + } + + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("bg_color", getThemedColor(Theme.key_dialogBackground)); + jsonObject.put("text_color", getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + jsonObject.put("hint_color", getThemedColor(Theme.key_windowBackgroundWhiteHintText)); + jsonObject.put("link_color", getThemedColor(Theme.key_windowBackgroundWhiteLinkText)); + jsonObject.put("button_color", getThemedColor(Theme.key_featuredStickers_addButton)); + jsonObject.put("button_text_color", getThemedColor(Theme.key_featuredStickers_buttonText)); + + req.theme_params = new TLRPC.TL_dataJSON(); + req.theme_params.data = jsonObject.toString(); + req.flags |= 4; + } catch (Exception e) { + FileLog.e(e); + } + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_webViewResultUrl) { + TLRPC.TL_webViewResultUrl resultUrl = (TLRPC.TL_webViewResultUrl) response; + queryId = resultUrl.query_id; + webViewContainer.loadUrl(resultUrl.url); + + AndroidUtilities.runOnUIThread(pollRunnable); + } + })); + + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.webViewResultSent); + } + + @Override + void onDestroy() { + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.webViewResultSent); + + ActionBarMenu menu = parentAlert.actionBar.createMenu(); + otherItem.removeAllSubItems(); + menu.removeView(otherItem); + + webViewContainer.destroyWebView(); + destroyed = true; + + AndroidUtilities.cancelRunOnUIThread(pollRunnable); + } + + @Override + void onHide() { + super.onHide(); + otherItem.setVisibility(GONE); + isBotButtonAvailable = false; + + if (webViewContainer.hasUserPermissions()) { + webViewContainer.destroyWebView(); + needReload = true; + } + } + + public boolean needReload() { + if (needReload) { + needReload = false; + return true; + } + return false; + } + + @Override + int getListTopPadding() { + return (int) swipeContainer.getOffsetY(); + } + + @Override + int getFirstOffset() { + return getListTopPadding() + AndroidUtilities.dp(56); + } + + @Override + void onPreMeasure(int availableWidth, int availableHeight) { + int padding; + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + padding = (int) (availableHeight / 3.5f); + } else { + padding = (availableHeight / 5 * 2); + } + parentAlert.setAllowNestedScroll(true); + + if (padding < 0) { + padding = 0; + } + if (swipeContainer.getOffsetY() != padding) { + ignoreLayout = true; + swipeContainer.setOffsetY(padding); + ignoreLayout = false; + } + } + + @Override + int getButtonsHideOffset() { + return AndroidUtilities.dp(56); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + + @Override + void scrollToTop() { + swipeContainer.stickTo(-swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY()); + } + + @Override + boolean shouldHideBottomButtons() { + return false; + } + + @Override + int needsActionBar() { + return 1; + } + + public BotWebViewContainer getWebViewContainer() { + return webViewContainer; + } + + public void setDelegate(BotWebViewContainer.Delegate delegate) { + webViewContainer.setDelegate(delegate); + } + + public boolean isBotButtonAvailable() { + return isBotButtonAvailable; + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.webViewResultSent) { + long queryId = (long) args[0]; + + if (this.queryId == queryId) { + webViewContainer.destroyWebView(); + needReload = true; + parentAlert.dismiss(); + } + } + } + + public static class WebViewSwipeContainer extends FrameLayout { + public final static SimpleFloatPropertyCompat SWIPE_OFFSET_Y = new SimpleFloatPropertyCompat<>("swipeOffsetY", WebViewSwipeContainer::getSwipeOffsetY, WebViewSwipeContainer::setSwipeOffsetY); + + private GestureDetectorCompat gestureDetector; + private boolean isScrolling; + private boolean isSwipeDisallowed; + + private float topActionBarOffsetY = ActionBar.getCurrentActionBarHeight(); + private float offsetY = -1; + private float swipeOffsetY; + private boolean isSwipeOffsetAnimationDisallowed; + + private boolean flingInProgress; + + private WebView webView; + + private Runnable scrollListener; + private Runnable scrollEndListener; + private Delegate delegate; + + private SpringAnimation scrollAnimator; + + public WebViewSwipeContainer(@NonNull Context context) { + super(context); + + int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + gestureDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (isSwipeDisallowed) { + return false; + } + if (velocityY >= 700 && webView.getScrollY() == 0) { + flingInProgress = true; + + if (swipeOffsetY >= AndroidUtilities.dp(64)) { + if (delegate != null) { + delegate.onDismiss(); + } + } else { + stickTo(0); + } + return true; + } else if (velocityY <= -700 && swipeOffsetY > -offsetY + topActionBarOffsetY) { + flingInProgress = true; + stickTo(-offsetY + topActionBarOffsetY); + return true; + } + return true; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (!isScrolling && !isSwipeDisallowed) { + if (Math.abs(distanceY) >= touchSlop && Math.abs(distanceY) * 1.5f >= Math.abs(distanceX) && (swipeOffsetY != -offsetY + topActionBarOffsetY || distanceY < 0 && webView.getScrollY() == 0)) { + isScrolling = true; + + MotionEvent ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).dispatchTouchEvent(ev); + } + ev.recycle(); + + return true; + } else if (webView.canScrollHorizontally(distanceX >= 0 ? 1 : -1)) { + isSwipeDisallowed = true; + } + } + if (isScrolling) { + if (distanceY < 0) { + if (swipeOffsetY > -offsetY + topActionBarOffsetY) { + swipeOffsetY -= distanceY; + } else { + float newWebScrollY = webView.getScrollY() + distanceY; + webView.setScrollY((int) MathUtils.clamp(newWebScrollY, 0, Math.max(webView.getContentHeight(), webView.getHeight()) - topActionBarOffsetY)); + + if (newWebScrollY < 0) { + swipeOffsetY -= newWebScrollY; + } + } + } else { + swipeOffsetY = swipeOffsetY - distanceY; + + if (swipeOffsetY < -offsetY + topActionBarOffsetY) { + float newWebScrollY = webView.getScrollY() - (swipeOffsetY + offsetY - topActionBarOffsetY); + webView.setScrollY((int) MathUtils.clamp(newWebScrollY, 0, Math.max(webView.getContentHeight(), webView.getHeight()) - topActionBarOffsetY)); + } + } + + swipeOffsetY = MathUtils.clamp(swipeOffsetY, -offsetY + topActionBarOffsetY, getHeight() - offsetY + topActionBarOffsetY); + invalidateTranslation(); + return true; + } + + return true; + } + }); + } + + @Override + public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { + super.requestDisallowInterceptTouchEvent(disallowIntercept); + + if (disallowIntercept) { + isSwipeDisallowed = true; + isScrolling = false; + } + } + + public void setSwipeOffsetAnimationDisallowed(boolean swipeOffsetAnimationDisallowed) { + isSwipeOffsetAnimationDisallowed = swipeOffsetAnimationDisallowed; + } + + public void setScrollListener(Runnable scrollListener) { + this.scrollListener = scrollListener; + } + + public void setScrollEndListener(Runnable scrollEndListener) { + this.scrollEndListener = scrollEndListener; + } + + public void setWebView(WebView webView) { + this.webView = webView; + } + + public void setTopActionBarOffsetY(float topActionBarOffsetY) { + this.topActionBarOffsetY = topActionBarOffsetY; + invalidateTranslation(); + } + + public void setSwipeOffsetY(float swipeOffsetY) { + this.swipeOffsetY = swipeOffsetY; + invalidateTranslation(); + } + + public void setOffsetY(float offsetY) { + float wasOffsetY = this.offsetY; + boolean wasOnTop = swipeOffsetY == -wasOffsetY + topActionBarOffsetY; + if (wasOffsetY != -1 && !isSwipeOffsetAnimationDisallowed) { + ValueAnimator animator = ValueAnimator.ofFloat(wasOffsetY, offsetY).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> { + this.offsetY = (float) animation.getAnimatedValue(); + if (wasOnTop) { + swipeOffsetY = -this.offsetY + topActionBarOffsetY; + } else { + swipeOffsetY = MathUtils.clamp(swipeOffsetY, -this.offsetY + topActionBarOffsetY, getHeight() - this.offsetY + topActionBarOffsetY); + } + invalidateTranslation(); + }); + animator.start(); + } else { + this.offsetY = offsetY; + if (wasOnTop) { + this.swipeOffsetY = -this.offsetY + topActionBarOffsetY; + } + invalidateTranslation(); + } + } + + private void invalidateTranslation() { + setTranslationY(Math.max(topActionBarOffsetY, offsetY + swipeOffsetY)); + if (scrollListener != null) { + scrollListener.run(); + } + } + + public float getTopActionBarOffsetY() { + return topActionBarOffsetY; + } + + public float getOffsetY() { + return offsetY; + } + + public float getSwipeOffsetY() { + return swipeOffsetY; + } + + public void setDelegate(Delegate delegate) { + this.delegate = delegate; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (isScrolling && ev.getActionIndex() != 0) { + return false; + } + + MotionEvent rawEvent = MotionEvent.obtain(ev); + int index = ev.getActionIndex(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + rawEvent.setLocation(ev.getRawX(index), ev.getRawY(index)); + } else { + float offsetX = ev.getRawX() - ev.getX(), offsetY = ev.getRawY() - ev.getY(); + rawEvent.setLocation(ev.getX(index) + offsetX, ev.getY(index) + offsetY); + } + boolean detector = gestureDetector.onTouchEvent(rawEvent); + rawEvent.recycle(); + + if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + isSwipeDisallowed = false; + isScrolling = false; + + if (flingInProgress) { + flingInProgress = false; + } else { + if (swipeOffsetY <= -AndroidUtilities.dp(64)) { + stickTo(-offsetY + topActionBarOffsetY); + } else if (swipeOffsetY > -AndroidUtilities.dp(64) && swipeOffsetY <= AndroidUtilities.dp(64)) { + stickTo(0); + } else { + if (delegate != null) { + delegate.onDismiss(); + } + } + } + } + + boolean superTouch = super.dispatchTouchEvent(ev); + if (!superTouch && !detector && ev.getAction() == MotionEvent.ACTION_DOWN) { + return true; + } + return superTouch || detector; + } + + public void stickTo(float offset) { + stickTo(offset, null); + } + + public void stickTo(float offset, Runnable callback) { + if (swipeOffsetY == offset) { + if (callback != null) { + callback.run(); + } + if (scrollEndListener != null) { + scrollEndListener.run(); + } + return; + } + + if (scrollAnimator != null) { + scrollAnimator.cancel(); + } + scrollAnimator = new SpringAnimation(this, SWIPE_OFFSET_Y, offset) + .setSpring(new SpringForce(offset) + .setStiffness(1400) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)) + .addEndListener((animation, canceled, value, velocity) -> { + if (animation == scrollAnimator) { + scrollAnimator = null; + + if (callback != null) { + callback.run(); + } + + if (scrollEndListener != null) { + scrollEndListener.run(); + } + } + }); + scrollAnimator.start(); + } + + public boolean isSwipeInProgress() { + return isScrolling; + } + + public interface Delegate { + /** + * Called to dismiss parent layout + */ + void onDismiss(); + } + } + + public final static class WebProgressView extends View { + private final SimpleFloatPropertyCompat LOAD_PROGRESS_PROPERTY = new SimpleFloatPropertyCompat<>("loadProgress", obj -> obj.loadProgress, WebProgressView::setLoadProgress).setMultiplier(100f); + + private Paint bluePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private float loadProgress; + private SpringAnimation springAnimation; + private Theme.ResourcesProvider resourcesProvider; + + public WebProgressView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + + bluePaint.setColor(getThemedColor(Theme.key_featuredStickers_addButton)); + bluePaint.setStyle(Paint.Style.STROKE); + bluePaint.setStrokeWidth(AndroidUtilities.dp(2)); + bluePaint.setStrokeCap(Paint.Cap.ROUND); + } + + protected int getThemedColor(String key) { + Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null; + return color != null ? color : Theme.getColor(key); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + springAnimation = new SpringAnimation(this, LOAD_PROGRESS_PROPERTY) + .setSpring(new SpringForce() + .setStiffness(400f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + springAnimation.cancel(); + springAnimation = null; + } + + public void setLoadProgressAnimated(float loadProgress) { + if (springAnimation == null) { + setLoadProgress(loadProgress); + return; + } + springAnimation.getSpring().setFinalPosition(loadProgress * 100f); + springAnimation.start(); + } + + public void setLoadProgress(float loadProgress) { + this.loadProgress = loadProgress; + invalidate(); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + float y = getHeight() - bluePaint.getStrokeWidth() / 2f; + canvas.drawLine(0, y, getWidth() * loadProgress, y, bluePaint); + } + } +} 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 b1882d7fd..f763975e5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java @@ -396,7 +396,7 @@ public class ChatAttachAlertContactsLayout extends ChatAttachAlert.AttachAlertLa PhonebookShareAlert phonebookShareAlert = new PhonebookShareAlert(parentAlert.baseFragment, contact, null, null, null, firstName, lastName, resourcesProvider); phonebookShareAlert.setDelegate((user, notify, scheduleDate) -> { - parentAlert.dismiss(); + parentAlert.dismiss(true); delegate.didSelectContact(user, notify, scheduleDate); }); phonebookShareAlert.show(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java index 8863b9603..78568a44e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java @@ -17,17 +17,22 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.database.Cursor; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.media.MediaMetadataRetriever; +import android.net.Uri; import android.os.Build; import android.os.Environment; import android.os.StatFs; +import android.provider.MediaStore; import android.text.TextUtils; import android.util.SparseArray; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.webkit.MimeTypeMap; import android.widget.EditText; import android.widget.FrameLayout; @@ -44,11 +49,13 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.messenger.ringtone.RingtoneDataStore; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -81,14 +88,24 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa public interface DocumentSelectActivityDelegate { void didSelectFiles(ArrayList files, String caption, ArrayList fmessages, boolean notify, int scheduleDate); - void didSelectPhotos(ArrayList photos, boolean notify, int scheduleDate); + default void didSelectPhotos(ArrayList photos, boolean notify, int scheduleDate) { - void startDocumentSelectActivity(); + } + + default void startDocumentSelectActivity() { + + } default void startMusicSelectActivity() { } } + public final static int TYPE_DEFAULT = 0; + public final static int TYPE_MUSIC = 1; + public final static int TYPE_RINGTONE = 2; + + private int type; + private RecyclerListView listView; private ListAdapter listAdapter; private SearchAdapter searchAdapter; @@ -129,6 +146,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa private final static int search_button = 0; private final static int sort_button = 6; + public boolean isSoundPicker; private static class ListItem { public int icon; @@ -168,9 +186,10 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa } }; - public ChatAttachAlertDocumentLayout(ChatAttachAlert alert, Context context, boolean music, Theme.ResourcesProvider resourcesProvider) { + public ChatAttachAlertDocumentLayout(ChatAttachAlert alert, Context context, int type, Theme.ResourcesProvider resourcesProvider) { super(alert, context, resourcesProvider); - allowMusic = music; + allowMusic = type == TYPE_MUSIC; + isSoundPicker = type == TYPE_RINGTONE; sortByName = SharedConfig.sortFilesByName; loadRecentFiles(); @@ -371,7 +390,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa }); fragment.setMaxSelectedPhotos(maxSelectedFiles, false); parentAlert.baseFragment.presentFragment(fragment); - parentAlert.dismiss(); + parentAlert.dismiss(true); } else if (item.icon == R.drawable.files_music) { if (delegate != null) { delegate.startMusicSelectActivity(); @@ -565,7 +584,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa ArrayList files = new ArrayList<>(selectedFilesOrder); delegate.didSelectFiles(files, parentAlert.commentTextView.getText().toString(), fmessages, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); } private boolean onItemClick(View view, Object object) { @@ -597,6 +616,9 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa showErrorBox(LocaleController.formatString("PassportUploadMaxReached", R.string.PassportUploadMaxReached, LocaleController.formatPluralString("Files", maxSelectedFiles))); return false; } + if (isSoundPicker && !isRingtone(item.file)) { + return false; + } if (item.file.length() == 0) { return false; } @@ -628,12 +650,45 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa return true; } + public boolean isRingtone(File file) { + String mimeType = null; + String extension = FileLoader.getFileExtension(file); + if (extension != null) { + mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + } + if (file.length() == 0 || mimeType == null || !RingtoneDataStore.ringtoneSupportedMimeType.contains(mimeType)) { + BulletinFactory.of(parentAlert.getContainer(), null).createErrorBulletinSubtitle(LocaleController.formatString("InvalidFormatError", R.string.InvalidFormatError), LocaleController.formatString("ErrorInvalidRingtone", R.string.ErrorRingtoneInvalidFormat), null).show(); + return false; + } + if (file.length() > MessagesController.getInstance(UserConfig.selectedAccount).ringtoneSizeMax) { + BulletinFactory.of(parentAlert.getContainer(), null).createErrorBulletinSubtitle(LocaleController.formatString("TooLargeError", R.string.TooLargeError), LocaleController.formatString("ErrorRingtoneSizeTooBig", R.string.ErrorRingtoneSizeTooBig, (MessagesController.getInstance(UserConfig.selectedAccount).ringtoneSizeMax / 1024)), null).show(); + return false; + } + + int millSecond; + try { + MediaMetadataRetriever mmr = new MediaMetadataRetriever(); + mmr.setDataSource(ApplicationLoader.applicationContext, Uri.fromFile(file)); + String durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + millSecond = Integer.parseInt(durationStr); + } catch (Exception e) { + millSecond = Integer.MAX_VALUE; + } + + if (millSecond > MessagesController.getInstance(UserConfig.selectedAccount).ringtoneDurationMax * 1000) { + BulletinFactory.of(parentAlert.getContainer(), null).createErrorBulletinSubtitle(LocaleController.formatString("TooLongError", R.string.TooLongError), LocaleController.formatString("ErrorRingtoneDurationTooLong", R.string.ErrorRingtoneDurationTooLong, MessagesController.getInstance(UserConfig.selectedAccount).ringtoneDurationMax), null).show(); + return false; + } + + return true; + } + public void setMaxSelectedFiles(int value) { maxSelectedFiles = value; } public void setCanSelectOnlyImageFiles(boolean value) { - canSelectOnlyImageFiles = true; + canSelectOnlyImageFiles = value; } private void sendSelectedPhotos(HashMap photos, ArrayList order, boolean notify, int scheduleDate) { @@ -667,33 +722,75 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa public void loadRecentFiles() { try { - File[] files = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).listFiles(); - if (files != null) { - for (int a = 0; a < files.length; a++) { - File file = files[a]; - if (file.isDirectory()) { - continue; + if (isSoundPicker) { + String[] projection = { + MediaStore.Audio.Media._ID, + MediaStore.Audio.Media.DATA, + MediaStore.Audio.Media.DURATION, + MediaStore.Audio.Media.SIZE, + MediaStore.Audio.Media.MIME_TYPE + }; + try (Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, MediaStore.Audio.Media.IS_MUSIC + " != 0", null, MediaStore.Audio.Media.DATE_ADDED + " DESC")) { + while (cursor.moveToNext()) { + File file = new File(cursor.getString(1)); + long duration = cursor.getLong(2); + long fileSize = cursor.getLong(3); + String mimeType = cursor.getString(4); + + if (duration > MessagesController.getInstance(UserConfig.selectedAccount).ringtoneDurationMax * 1000 || fileSize > MessagesController.getInstance(UserConfig.selectedAccount).ringtoneSizeMax || (!TextUtils.isEmpty(mimeType) && !("audio/mpeg".equals(mimeType) || !"audio/mpeg4".equals(mimeType)))) { + continue; + } + + ListItem item = new ListItem(); + item.title = file.getName(); + item.file = file; + String fname = file.getName(); + String[] sp = fname.split("\\."); + item.ext = sp.length > 1 ? sp[sp.length - 1] : "?"; + item.subtitle = AndroidUtilities.formatFileSize(file.length()); + fname = fname.toLowerCase(); + if (fname.endsWith(".jpg") || fname.endsWith(".png") || fname.endsWith(".gif") || fname.endsWith(".jpeg")) { + item.thumb = file.getAbsolutePath(); + } + recentItems.add(item); } - ListItem item = new ListItem(); - item.title = file.getName(); - item.file = file; - String fname = file.getName(); - String[] sp = fname.split("\\."); - item.ext = sp.length > 1 ? sp[sp.length - 1] : "?"; - item.subtitle = AndroidUtilities.formatFileSize(file.length()); - fname = fname.toLowerCase(); - if (fname.endsWith(".jpg") || fname.endsWith(".png") || fname.endsWith(".gif") || fname.endsWith(".jpeg")) { - item.thumb = file.getAbsolutePath(); - } - recentItems.add(item); + } catch (Exception e) { + FileLog.e(e); } + } else { + checkDirectory(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)); + sortRecentItems(); } - sortRecentItems(); } catch (Exception e) { FileLog.e(e); } } + private void checkDirectory(File rootDir) { + File[] files = rootDir.listFiles(); + if (files != null) { + for (int a = 0; a < files.length; a++) { + File file = files[a]; + if (file.isDirectory() && file.getName().equals("Telegram")) { + checkDirectory(file); + continue; + } + ListItem item = new ListItem(); + item.title = file.getName(); + item.file = file; + String fname = file.getName(); + String[] sp = fname.split("\\."); + item.ext = sp.length > 1 ? sp[sp.length - 1] : "?"; + item.subtitle = AndroidUtilities.formatFileSize(file.length()); + fname = fname.toLowerCase(); + if (fname.endsWith(".jpg") || fname.endsWith(".png") || fname.endsWith(".gif") || fname.endsWith(".jpeg")) { + item.thumb = file.getAbsolutePath(); + } + recentItems.add(item); + } + } + } + private void sortRecentItems() { Collections.sort(recentItems, (o1, o2) -> { if (sortByName) { @@ -1049,12 +1146,14 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa FileLog.e(e); } - fs = new ListItem(); - fs.title = LocaleController.getString("Gallery", R.string.Gallery); - fs.subtitle = LocaleController.getString("GalleryInfo", R.string.GalleryInfo); - fs.icon = R.drawable.files_gallery; - fs.file = null; - items.add(fs); + if (!isSoundPicker) { + fs = new ListItem(); + fs.title = LocaleController.getString("Gallery", R.string.Gallery); + fs.subtitle = LocaleController.getString("GalleryInfo", R.string.GalleryInfo); + fs.icon = R.drawable.files_gallery; + fs.file = null; + items.add(fs); + } if (allowMusic) { fs = new ListItem(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java index aa8029b12..56476a43b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java @@ -265,11 +265,11 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.didSelectLocation(location.venue, locationType, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider); } else { delegate.didSelectLocation(location.venue, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } }); @@ -759,11 +759,11 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.didSelectLocation(location, locationType, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider); } else { delegate.didSelectLocation(location, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } } } else if (locationDenied) { @@ -772,7 +772,7 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa } else if (position == 2 && locationType == LOCATION_TYPE_SEND_WITH_LIVE) { if (getLocationController().isSharingLocation(dialogId)) { getLocationController().removeSharingLocation(dialogId); - parentAlert.dismiss(); + parentAlert.dismiss(true); } else { if (myLocation == null && locationDenied) { AlertsCreator.createLocationRequiredDialog(getParentActivity(), true).show(); @@ -786,11 +786,11 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.didSelectLocation((TLRPC.TL_messageMediaVenue) object, locationType, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider); } else { delegate.didSelectLocation((TLRPC.TL_messageMediaVenue) object, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } } else if (object instanceof LiveLocation) { LiveLocation liveLocation = (LiveLocation) object; @@ -932,11 +932,11 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.didSelectLocation(object, locationType, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider); } else { delegate.didSelectLocation(object, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } } }); @@ -1170,7 +1170,7 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa location.geo._long = AndroidUtilities.fixLocationCoord(myLocation.getLongitude()); location.period = param; delegate.didSelectLocation(location, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider).show(); } 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 0c44f0e23..3e99d0c39 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -34,6 +34,7 @@ import android.os.Build; import android.provider.MediaStore; import android.provider.Settings; import android.text.TextUtils; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.KeyEvent; @@ -831,14 +832,6 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou flashModeButton[a].layout(cx3 - flashModeButton[a].getMeasuredWidth() / 2, cy3 - flashModeButton[a].getMeasuredHeight() / 2, cx3 + flashModeButton[a].getMeasuredWidth() / 2, cy3 + flashModeButton[a].getMeasuredHeight() / 2); } } - - @Override - public void setAlpha(float alpha) { - super.setAlpha(alpha); - if (parentAlert != null) { - parentAlert.setOverlayNavBarColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (alpha * 255))); - } - } }; cameraPanel.setVisibility(View.GONE); cameraPanel.setAlpha(0.0f); @@ -1472,7 +1465,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou selectedPhotos.clear(); adapter.notifyDataSetChanged(); cameraAttachAdapter.notifyDataSetChanged(); - parentAlert.dismiss(); + parentAlert.dismiss(true); } @Override @@ -1688,9 +1681,6 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou cameraView.setFpsLimit(-1); AndroidUtilities.hideKeyboard(this); AndroidUtilities.setLightNavigationBar(parentAlert.getWindow(), false); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - parentAlert.getWindow().setNavigationBarColor(0xff000000); - } if (animated) { setCameraOpenProgress(0); cameraAnimationInProgress = true; @@ -1793,9 +1783,6 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou cameraView.setFocusable(true); cameraView.setFpsLimit(30); if (Build.VERSION.SDK_INT >= 21) { - Path path = new Path(); - float[] radii = new float[8]; - cameraView.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { @@ -2085,6 +2072,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou AndroidUtilities.cancelRunOnUIThread(zoomControlHideRunnable); zoomControlHideRunnable = null; } + AndroidUtilities.setLightNavigationBar(parentAlert.getWindow(), AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_windowBackgroundGray)) > 0.721); if (animated) { additionCloseCameraY = cameraView.getTranslationY(); @@ -2186,7 +2174,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou float startHeight = animateCameraValues[2]; boolean isPortrait = AndroidUtilities.displaySize.x < AndroidUtilities.displaySize.y; float endWidth = parentAlert.getContainer().getWidth() - parentAlert.getLeftInset() - parentAlert.getRightInset(); - float endHeight = parentAlert.getContainer().getHeight() - parentAlert.getBottomInset(); + float endHeight = parentAlert.getContainer().getHeight(); float fromX = cameraViewLocation[0]; float fromY = cameraViewLocation[1]; @@ -2252,6 +2240,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou cameraIcon.setAlpha(0.0f); } + Log.i("caapl", "cameraViewH=" + cameraViewH + " (endHeight=" + endHeight + ") value=" + value); if (layoutParams.width != cameraViewW || layoutParams.height != cameraViewH) { layoutParams.width = cameraViewW; layoutParams.height = cameraViewH; @@ -2429,9 +2418,11 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou return selectedPhotosOrder; } - public void updateSelected(HashMap selectedPhotos, ArrayList photosOrder, boolean updateLayout) { - this.selectedPhotos = selectedPhotos; - this.selectedPhotosOrder = photosOrder; + public void updateSelected(HashMap newSelectedPhotos, ArrayList newPhotosOrder, boolean updateLayout) { + selectedPhotos.clear(); + selectedPhotos.putAll(newSelectedPhotos); + selectedPhotosOrder.clear(); + selectedPhotosOrder.addAll(newPhotosOrder); if (updateLayout) { updatePhotosCounter(false); updateCheckedPhotoIndices(); @@ -2543,7 +2534,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou parentAlert.baseFragment.startActivityForResult(photoPickerIntent, 1); } } - parentAlert.dismiss(); + parentAlert.dismiss(true); } catch (Exception e) { FileLog.e(e); } @@ -3081,7 +3072,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou return true; } else if (view == cameraView) { if (cameraOpened && !cameraAnimationInProgress) { - cameraView.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); + cameraView.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height + parentAlert.getBottomInset(), View.MeasureSpec.EXACTLY)); return true; } } else if (view == cameraPanel) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java index 6a931f79e..e44307268 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java @@ -369,7 +369,8 @@ public class ChatAttachAlertPhotoLayoutPreview extends ChatAttachAlert.AttachAle MessageObject.GroupedMessagePosition position = new MessageObject.GroupedMessagePosition(); position.last = a == count - 1; - int w = photo.width, h = photo.height; + int w = photo.cropState != null ? photo.cropState.width : photo.width, + h = photo.cropState != null ? photo.cropState.height : photo.height; boolean rotate; if (photoRotate.containsKey(photo)) { rotate = photoRotate.get(photo); @@ -868,7 +869,7 @@ public class ChatAttachAlertPhotoLayoutPreview extends ChatAttachAlert.AttachAle paddingTop = Math.max(0, paddingTop); canvas.save(); canvas.clipRect(0, paddingTop, getWidth(), getHeight()); - chatBackgroundDrawable.setBounds(0, paddingTop, getWidth(), AndroidUtilities.displaySize.y); + chatBackgroundDrawable.setBounds(0, paddingTop, getWidth(), paddingTop + AndroidUtilities.displaySize.y); chatBackgroundDrawable.draw(canvas); restore = true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java index 0336bc03e..756ff9073 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java @@ -433,11 +433,11 @@ public class ChatAttachAlertPollLayout extends ChatAttachAlert.AttachAlertLayout if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(chatActivity.getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.sendPoll(poll, params, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }); } else { delegate.sendPoll(poll, params, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } } } 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 9a2b8804a..6eb972fc0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -40,6 +40,7 @@ import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; @@ -70,6 +71,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent private int currentConnectionState; private CharSequence lastSubtitle; private String lastSubtitleColorKey; + private Integer overrideSubtitleColor; private SharedMediaLayout.SharedMediaPreloader sharedMediaPreloader; private Theme.ResourcesProvider resourcesProvider; @@ -134,7 +136,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent timeItem.setScaleY(0.0f); timeItem.setScaleX(0.0f); timeItem.setVisibility(GONE); - timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context)); + timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context, resourcesProvider)); addView(timeItem); secretChatTimer = needTime; @@ -170,6 +172,10 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } } + public void setOverrideSubtitleColor(Integer overrideSubtitleColor) { + this.overrideSubtitleColor = overrideSubtitleColor; + } + public boolean openSetTimer() { if (parentFragment.getParentActivity() == null) { return false; @@ -181,19 +187,60 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } return false; } - ClearHistoryAlert alert = new ClearHistoryAlert(parentFragment.getParentActivity(), parentFragment.getCurrentUser(), parentFragment.getCurrentChat(), false, null); - alert.setDelegate(new ClearHistoryAlert.ClearHistoryAlertDelegate() { + TLRPC.ChatFull chatInfo = parentFragment.getCurrentChatInfo(); + TLRPC.UserFull userInfo = parentFragment.getCurrentUserInfo(); + int ttl = 0; + if (userInfo != null) { + ttl = userInfo.ttl_period; + } else if (chatInfo != null) { + ttl = chatInfo.ttl_period; + } + + ActionBarPopupWindow[] scrimPopupWindow = new ActionBarPopupWindow[1]; + AutoDeletePopupWrapper autoDeletePopupWrapper = new AutoDeletePopupWrapper(getContext(), null, new AutoDeletePopupWrapper.Callback() { @Override - public void onAutoDeleteHistory(int ttl, int action) { - parentFragment.getMessagesController().setDialogHistoryTTL(parentFragment.getDialogId(), ttl); + public void dismiss() { + if (scrimPopupWindow[0] != null) { + scrimPopupWindow[0].dismiss(); + } + } + + @Override + public void setAutoDeleteHistory(int time, int action) { + if (parentFragment == null) { + return; + } + parentFragment.getMessagesController().setDialogHistoryTTL(parentFragment.getDialogId(), time); TLRPC.ChatFull chatInfo = parentFragment.getCurrentChatInfo(); TLRPC.UserFull userInfo = parentFragment.getCurrentUserInfo(); if (userInfo != null || chatInfo != null) { parentFragment.getUndoView().showWithAction(parentFragment.getDialogId(), action, parentFragment.getCurrentUser(), userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period, null, null); } + } - }); - parentFragment.showDialog(alert); + }, true, resourcesProvider); + autoDeletePopupWrapper.updateItems(ttl); + + scrimPopupWindow[0] = new ActionBarPopupWindow(autoDeletePopupWrapper.windowLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { + @Override + public void dismiss() { + super.dismiss(); + if (parentFragment != null) { + parentFragment.dimBehindView(false); + } + } + }; + scrimPopupWindow[0].setPauseNotifications(true); + scrimPopupWindow[0].setDismissAnimationDuration(220); + scrimPopupWindow[0].setOutsideTouchable(true); + scrimPopupWindow[0].setClippingEnabled(true); + scrimPopupWindow[0].setAnimationStyle(R.style.PopupContextAnimation); + scrimPopupWindow[0].setFocusable(true); + autoDeletePopupWrapper.windowLayout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + scrimPopupWindow[0].setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + scrimPopupWindow[0].getContentView().setFocusableInTouchMode(true); + scrimPopupWindow[0].showAtLocation(avatarImageView, 0, (int) (avatarImageView.getX() + getX()), (int) avatarImageView.getY()); + parentFragment.dimBehindView(true); return true; } @@ -289,7 +336,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } public void showTimeItem(boolean animated) { - if (timeItem == null || timeItem.getTag() != null) { + if (timeItem == null || timeItem.getTag() != null || avatarImageView.getVisibility() != View.VISIBLE) { return; } timeItem.clearAnimation(); @@ -326,14 +373,21 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } } - public void setTime(int value) { + public void setTime(int value, boolean animated) { if (timerDrawable == null) { return; } + boolean show = true; if (value == 0 && !secretChatTimer) { + show = false; return; } - timerDrawable.setTime(value); + if (show) { + showTimeItem(animated); + timerDrawable.setTime(value); + } else { + hideTimeItem(animated); + } } public void setTitleIcons(Drawable leftIcon, Drawable rightIcon) { @@ -601,8 +655,12 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent lastSubtitleColorKey = useOnlineColor ? Theme.key_chat_status : Theme.key_actionBarDefaultSubtitle; if (lastSubtitle == null) { subtitleTextView.setText(newSubtitle); - subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); - subtitleTextView.setTag(lastSubtitleColorKey); + if (overrideSubtitleColor == null) { + subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); + subtitleTextView.setTag(lastSubtitleColorKey); + } else { + subtitleTextView.setTextColor(overrideSubtitleColor); + } } else { lastSubtitle = newSubtitle; } @@ -742,7 +800,9 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (lastSubtitle != null) { subtitleTextView.setText(lastSubtitle); lastSubtitle = null; - if (lastSubtitleColorKey != null) { + if (overrideSubtitleColor != null) { + subtitleTextView.setTextColor(overrideSubtitleColor); + } else if (lastSubtitleColorKey != null) { subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); subtitleTextView.setTag(lastSubtitleColorKey); } @@ -752,8 +812,12 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent lastSubtitle = subtitleTextView.getText(); } subtitleTextView.setText(title); - subtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); - subtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); + if (overrideSubtitleColor != null) { + subtitleTextView.setTextColor(overrideSubtitleColor); + } else { + subtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); + subtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java new file mode 100644 index 000000000..ace816cb2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java @@ -0,0 +1,233 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.content.SharedPreferences; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; + +public class ChatNotificationsPopupWrapper { + + View backItem; + ActionBarMenuSubItem soundToggle; + ActionBarMenuSubItem muteUnmuteButton; + ActionBarMenuSubItem muteForLastSelected; + ActionBarMenuSubItem muteForLastSelected2; + public ActionBarPopupWindow.ActionBarPopupWindowLayout windowLayout; + int currentAccount; + ActionBarPopupWindow popupWindow; + Callback callback; + long lastDismissTime; + + private final static String LAST_SELECTED_TIME_KEY_1 = "last_selected_mute_until_time"; + private final static String LAST_SELECTED_TIME_KEY_2 = "last_selected_mute_until_time2"; + private final boolean isProfile; + private int muteForLastSelected2Time; + private int muteForLastSelected1Time; + + public ChatNotificationsPopupWrapper(Context context, int currentAccount, PopupSwipeBackLayout swipeBackLayout, boolean createBackground, boolean isProfile, Callback callback, Theme.ResourcesProvider resourcesProvider) { + this.currentAccount = currentAccount; + this.callback = callback; + this.isProfile = isProfile; + windowLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(context, createBackground ? R.drawable.popup_fixed_alert : 0, resourcesProvider); + windowLayout.setFitItems(true); + + if (swipeBackLayout != null) { + backItem = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_arrow_back, LocaleController.getString("Back", R.string.Back), false, resourcesProvider); + backItem.setOnClickListener(view -> { + swipeBackLayout.closeForeground(); + }); + } + + + soundToggle = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_tone_on, LocaleController.getString("SoundOn", R.string.SoundOn), false, resourcesProvider); + soundToggle.setOnClickListener(view -> { + dismiss(); + callback.toggleSound(); + }); + + muteForLastSelected = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_mute_1h, LocaleController.getString("MuteFor1h", R.string.MuteFor1h), false, resourcesProvider); + muteForLastSelected.setOnClickListener(view -> { + dismiss(); + callback.muteFor(muteForLastSelected1Time); + }); + + muteForLastSelected2 = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_mute_1h, LocaleController.getString("MuteFor1h", R.string.MuteFor1h), false, resourcesProvider); + muteForLastSelected2.setOnClickListener(view -> { + dismiss(); + callback.muteFor(muteForLastSelected2Time); + }); + + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_mute_period, LocaleController.getString("MuteForPopup", R.string.MuteForPopup), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + AlertsCreator.createMuteForPickerDialog(context, (notify, inMinutes) -> { + AndroidUtilities.runOnUIThread(() -> { + SharedPreferences sharedPreferences = MessagesController.getNotificationsSettings(currentAccount); + int time1 = sharedPreferences.getInt(LAST_SELECTED_TIME_KEY_1, 0); + int time2; + int timeInSeconds = inMinutes * 60; + time2 = time1; + time1 = timeInSeconds; + sharedPreferences.edit() + .putInt(LAST_SELECTED_TIME_KEY_1, time1) + .putInt(LAST_SELECTED_TIME_KEY_2, time2) + .apply(); + callback.muteFor(timeInSeconds); + }, 16); + }); + }); + + item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_customize, LocaleController.getString("NotificationsCustomize", R.string.NotificationsCustomize), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + callback.showCustomize(); + }); + + + muteUnmuteButton = ActionBarMenuItem.addItem(windowLayout, 0, "", false, resourcesProvider); + muteUnmuteButton.setOnClickListener(view -> { + dismiss(); + AndroidUtilities.runOnUIThread(() -> { + callback.toggleMute(); + }); + + }); + } + + private void dismiss() { + if (popupWindow != null) { + popupWindow.dismiss(); + popupWindow.dismiss(); + } + callback.dismiss(); + lastDismissTime = System.currentTimeMillis(); + } + + public void update(long dialogId) { + if (System.currentTimeMillis() - lastDismissTime < 200) { + AndroidUtilities.runOnUIThread(() -> { + update(dialogId); + }); + return; + } + boolean muted = MessagesController.getInstance(currentAccount).isDialogMuted(dialogId); + + int color; + if (muted) { + muteUnmuteButton.setTextAndIcon(LocaleController.getString("UnmuteNotifications", R.string.UnmuteNotifications), R.drawable.msg_unmute); + color = Theme.getColor(Theme.key_wallet_greenText); + soundToggle.setVisibility(View.GONE); + } else { + muteUnmuteButton.setTextAndIcon(LocaleController.getString("MuteNotifications", R.string.MuteNotifications), R.drawable.msg_mute); + color = Theme.getColor(Theme.key_dialogTextRed); + soundToggle.setVisibility(View.VISIBLE); + boolean soundOn = MessagesController.getInstance(currentAccount).isDialogNotificationsSoundEnabled(dialogId); + if (soundOn) { + soundToggle.setTextAndIcon(LocaleController.getString("SoundOff", R.string.SoundOff), R.drawable.msg_tone_off); + } else { + soundToggle.setTextAndIcon(LocaleController.getString("SoundOn", R.string.SoundOn), R.drawable.msg_tone_on); + } + } + + int time1; + int time2; + if (muted) { + time1 = 0; + time2 = 0; + } else { + SharedPreferences sharedPreferences = MessagesController.getNotificationsSettings(currentAccount); + time1 = sharedPreferences.getInt(LAST_SELECTED_TIME_KEY_1, 0); + time2 = sharedPreferences.getInt(LAST_SELECTED_TIME_KEY_2, 0); + } + if (time1 != 0) { + muteForLastSelected1Time = time1; + muteForLastSelected.setVisibility(View.VISIBLE); + muteForLastSelected.getImageView().setImageDrawable(TimerDrawable.getTtlIcon(time1)); + muteForLastSelected.setText(formatMuteForTime(time1)); + } else { + muteForLastSelected.setVisibility(View.GONE); + } + + if (time2 != 0) { + muteForLastSelected2Time = time2; + muteForLastSelected2.setVisibility(View.VISIBLE); + muteForLastSelected2.getImageView().setImageDrawable(TimerDrawable.getTtlIcon(time2)); + muteForLastSelected2.setText(formatMuteForTime(time2)); + } else { + muteForLastSelected2.setVisibility(View.GONE); + } + + + muteUnmuteButton.setColors(color, color); + + } + + private String formatMuteForTime(int time) { + StringBuilder stringBuilder = new StringBuilder(); + int days = time / (60 * 60 * 24); + time -= days * (60 * 60 * 24); + int hours = time / (60 * 60); + + if (days != 0) { + stringBuilder.append(days).append(LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays)); + } + if (hours != 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + stringBuilder.append(hours).append(LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours)); + } + return LocaleController.formatString("MuteForButton", R.string.MuteForButton, stringBuilder.toString()); + } + + public void showAsOptions(BaseFragment parentFragment, View anchorView, float touchedX, float touchedY) { + if (parentFragment == null || parentFragment.getFragmentView() == null) { + return; + } + popupWindow = new ActionBarPopupWindow(windowLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + popupWindow.setPauseNotifications(true); + popupWindow.setDismissAnimationDuration(220); + popupWindow.setOutsideTouchable(true); + popupWindow.setClippingEnabled(true); + popupWindow.setAnimationStyle(R.style.PopupContextAnimation); + popupWindow.setFocusable(true); + windowLayout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + popupWindow.getContentView().setFocusableInTouchMode(true); + + float x = touchedX, y = touchedY; + View view = anchorView; + while (view != parentFragment.getFragmentView()) { + x += view.getX(); + y += view.getY(); + view = (View) view.getParent(); + } + x -= windowLayout.getMeasuredWidth() / 2f; + y -= windowLayout.getMeasuredHeight() / 2f; + popupWindow.showAtLocation(parentFragment.getFragmentView(), 0, (int) x, (int) y); + popupWindow.dimBehind(); + // parentFragment.dimBehindView(true); + } + + public interface Callback { + void dismiss(); + + void toggleSound(); + + void muteFor(int timeInSecond); + + void showCustomize(); + + void toggleMute(); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java index 1b6a29e96..a6c78aa53 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java @@ -65,6 +65,7 @@ import java.util.Objects; public class ChatThemeBottomSheet extends BottomSheet implements NotificationCenter.NotificationCenterDelegate { + private FrameLayout rootLayout; private final Adapter adapter; private final ChatActivity.ThemeDelegate themeDelegate; private final EmojiThemes originalTheme; @@ -100,8 +101,9 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen setDimBehind(false); setCanDismissWithSwipe(false); setApplyBottomPadding(false); + drawNavigationBar = true; - FrameLayout rootLayout = new FrameLayout(getContext()); + rootLayout = new FrameLayout(getContext()); setCustomView(rootLayout); titleView = new TextView(getContext()); @@ -333,7 +335,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen isAnimationStarted = true; } darkThemeDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_featuredStickers_addButton), PorterDuff.Mode.MULTIPLY)); - setOverlayNavBarColor(getThemedColor(Theme.key_dialogBackground)); + setOverlayNavBarColor(getThemedColor(Theme.key_windowBackgroundGray)); if (isLightDarkChangeAnimation) { setItemsAnimationProgress(progress); } @@ -392,7 +394,6 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen Shader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); bitmapPaint.setShader(bitmapShader); changeDayNightView = new View(getContext()) { - @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -413,10 +414,16 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen changeDayNightViewProgress = 0f; changeDayNightViewAnimator = ValueAnimator.ofFloat(0, 1f); changeDayNightViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + boolean changedNavigationBarColor = false; @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { changeDayNightViewProgress = (float) valueAnimator.getAnimatedValue(); changeDayNightView.invalidate(); + if (!changedNavigationBarColor && changeDayNightViewProgress > .5f) { + changedNavigationBarColor = true; + AndroidUtilities.setLightNavigationBar(getWindow(), !isDark); + AndroidUtilities.setNavigationBarColor(getWindow(), getThemedColor(Theme.key_windowBackgroundGray)); + } } }); changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { @@ -563,8 +570,6 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } private void setForceDark(boolean isDark, boolean playAnimation) { - useLightNavBar = isDark; - useLightStatusBar = isDark; if (forceDark == isDark) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java new file mode 100644 index 000000000..dce400dc1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java @@ -0,0 +1,96 @@ +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.SystemClock; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; + +import org.telegram.messenger.AndroidUtilities; + +public class CircularProgressDrawable extends Drawable { + + public CircularProgressDrawable() { + this(0xffffffff); + } + public CircularProgressDrawable(int color) { + setColor(color); + } + + private long start = -1; + private final FastOutSlowInInterpolator interpolator = new FastOutSlowInInterpolator(); + private float segmentFrom, segmentTo; + private void updateSegment() { + final float t = (SystemClock.elapsedRealtime() - start) % 5400f / 667f; + segmentFrom = + t * 187.748148f + 250 * ( + interpolator.getInterpolation(t - 1f) + + interpolator.getInterpolation(t - 3.024f) + + interpolator.getInterpolation(t - 5.048f) + + interpolator.getInterpolation(t - 7.072f) + ) - 20; + segmentTo = + t * 187.748148f + 250 * ( + interpolator.getInterpolation(t) + + interpolator.getInterpolation(t - 2.024f) + + interpolator.getInterpolation(t - 4.048f) + + interpolator.getInterpolation(t - 6.072f) + ); + } + + private final Paint paint = new Paint(); { + paint.setStyle(Paint.Style.STROKE); + } + + private final RectF bounds = new RectF(); + @Override + public void draw(@NonNull Canvas canvas) { + if (start < 0) { + start = SystemClock.elapsedRealtime(); + } + updateSegment(); + canvas.drawArc( + bounds, + segmentFrom, + segmentTo - segmentFrom, + false, + paint + ); + invalidateSelf(); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + final float radius = AndroidUtilities.dp(9); + final float thickness = AndroidUtilities.dp(2.25f); + int width = right - left, height = bottom - top; + bounds.set( + left + (width - thickness / 2f) / 2f - radius, + top + (height - thickness / 2f) / 2f - radius, + left + (width + thickness / 2f) / 2f + radius, + top + (height + thickness / 2f) / 2f + radius + ); + super.setBounds(left, top, right, bottom); + paint.setStrokeWidth(thickness); + } + + public void setColor(int color) { + paint.setColor(color); + } + + @Override + public void setAlpha(int i) {} + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) {} + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropTransform.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropTransform.java index 71c382192..2f5235fff 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropTransform.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropTransform.java @@ -8,6 +8,8 @@ package org.telegram.ui.Components.Crop; +import androidx.annotation.NonNull; + public class CropTransform { private boolean hasTransform; @@ -24,6 +26,10 @@ public class CropTransform { private float trueCropScale; private float minScale; + public void setViewTransform(boolean set) { + hasTransform = set; + } + public void setViewTransform(boolean set, float px, float py, float rotate, int orientation, float scale, float cs, float ms, float pw, float ph, float cx, float cy, boolean mirrored) { hasTransform = set; cropPx = px; @@ -97,4 +103,23 @@ public class CropTransform { public boolean isMirrored () { return isMirrored; } + + @Override + public CropTransform clone() { + CropTransform cloned = new CropTransform(); + cloned.hasTransform = this.hasTransform; + cloned.cropPx = this.cropPx; + cloned.cropPy = this.cropPy; + cloned.cropAreaX = this.cropAreaX; + cloned.cropAreaY = this.cropAreaY; + cloned.cropScale = this.cropScale; + cloned.cropRotation = this.cropRotation; + cloned.isMirrored = this.isMirrored; + cloned.cropOrientation = this.cropOrientation; + cloned.cropPw = this.cropPw; + cloned.cropPh = this.cropPh; + cloned.trueCropScale = this.trueCropScale; + cloned.minScale = this.minScale; + return cloned; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java index f4929a149..23fe1433b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java @@ -6,6 +6,8 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import androidx.annotation.NonNull; + public class CrossfadeDrawable extends Drawable { private final Drawable topDrawable; @@ -16,6 +18,35 @@ public class CrossfadeDrawable extends Drawable { public CrossfadeDrawable(Drawable topDrawable, Drawable bottomDrawable) { this.topDrawable = topDrawable; this.bottomDrawable = bottomDrawable; + + if (topDrawable != null) { + topDrawable.setCallback(new Callback() { + @Override + public void invalidateDrawable(@NonNull Drawable drawable) { + if (progress < 1.0f) { + CrossfadeDrawable.this.invalidateSelf(); + } + } + @Override + public void scheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable, long l) {} + @Override + public void unscheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable) {} + }); + } + if (bottomDrawable != null) { + bottomDrawable.setCallback(new Callback() { + @Override + public void invalidateDrawable(@NonNull Drawable drawable) { + if (progress > 0.0f) { + CrossfadeDrawable.this.invalidateSelf(); + } + } + @Override + public void scheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable, long l) {} + @Override + public void unscheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable) {} + }); + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java index df5289576..4c5b9a6dc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java @@ -66,6 +66,7 @@ import org.telegram.ui.PhotoViewer; import java.util.HashMap; import java.util.Locale; +@SuppressLint("WrongConstant") public class EmbedBottomSheet extends BottomSheet { private WebView webView; @@ -76,7 +77,6 @@ public class EmbedBottomSheet extends BottomSheet { private View progressBarBlackBackground; private RadialProgressView progressBar; private Activity parentActivity; - private PipVideoView pipVideoView; private LinearLayout imageButtonsContainer; private TextView copyTextButton; private FrameLayout containerLayout; @@ -204,7 +204,7 @@ public class EmbedBottomSheet extends BottomSheet { private OnShowListener onShowListener = new OnShowListener() { @Override public void onShow(DialogInterface dialog) { - if (pipVideoView != null && videoView.isInline()) { + if (PipVideoOverlay.isVisible() && videoView.isInline()) { videoView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { @@ -275,14 +275,14 @@ public class EmbedBottomSheet extends BottomSheet { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); try { - if ((pipVideoView == null || webView.getVisibility() != VISIBLE) && webView.getParent() != null) { + if ((!PipVideoOverlay.isVisible() || webView.getVisibility() != VISIBLE) && webView.getParent() != null) { removeView(webView); webView.stopLoading(); webView.loadUrl("about:blank"); webView.destroy(); } - if (!videoView.isInline() && pipVideoView == null) { + if (!videoView.isInline() && !PipVideoOverlay.isVisible()) { if (instance == EmbedBottomSheet.this) { instance = null; } @@ -340,7 +340,7 @@ public class EmbedBottomSheet extends BottomSheet { @Override public void onShowCustomView(View view, CustomViewCallback callback) { - if (customView != null || pipVideoView != null) { + if (customView != null || PipVideoOverlay.isVisible()) { callback.onCustomViewHidden(); return; } @@ -496,12 +496,12 @@ public class EmbedBottomSheet extends BottomSheet { } setOnShowListener(null); - if (animated) { + if (animated && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { TextureView textureView = videoView.getTextureView(); View controlsView = videoView.getControlsView(); ImageView textureImageView = videoView.getTextureImageView(); - Rect rect = PipVideoView.getPipRect(aspectRatio); + Rect rect = PipVideoOverlay.getPipRect(true, aspectRatio); float scale = rect.width / textureView.getWidth(); @@ -550,9 +550,9 @@ public class EmbedBottomSheet extends BottomSheet { } } - if (animated) { + if (animated && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { setOnShowListener(onShowListener); - Rect rect = PipVideoView.getPipRect(aspectRatio); + Rect rect = PipVideoOverlay.getPipRect(false, aspectRatio); TextureView textureView = videoView.getTextureView(); ImageView textureImageView = videoView.getTextureImageView(); @@ -566,8 +566,7 @@ public class EmbedBottomSheet extends BottomSheet { textureView.setTranslationX(rect.x); textureView.setTranslationY(rect.y); } else { - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(); } setShowWithoutAnimation(true); show(); @@ -580,11 +579,16 @@ public class EmbedBottomSheet extends BottomSheet { } @Override - public TextureView onSwitchInlineMode(View controlsView, boolean inline, float aspectRatio, int rotation, boolean animated) { + public TextureView onSwitchInlineMode(View controlsView, boolean inline, int videoWidth, int videoHeight, int rotation, boolean animated) { if (inline) { controlsView.setTranslationY(0); - pipVideoView = new PipVideoView(false); - return pipVideoView.show(parentActivity, EmbedBottomSheet.this, controlsView, aspectRatio, rotation, null); + + TextureView textureView = new TextureView(parentActivity); + if (PipVideoOverlay.show(false, parentActivity, textureView, videoWidth, videoHeight)) { + PipVideoOverlay.setParentSheet(EmbedBottomSheet.this); + return textureView; + } + return null; } if (animated) { @@ -733,6 +737,12 @@ public class EmbedBottomSheet extends BottomSheet { pipButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 0)); imageButtonsContainer.addView(pipButton, LayoutHelper.createFrame(48, 48, Gravity.TOP | Gravity.LEFT, 0, 0, 4, 0)); pipButton.setOnClickListener(v -> { + if (PipVideoOverlay.isVisible()) { + PipVideoOverlay.dismiss(); + AndroidUtilities.runOnUIThread(v::callOnClick, 300); + return; + } + boolean inAppOnly = isYouTube && "inapp".equals(MessagesController.getInstance(currentAccount).youtubePipType); if (!inAppOnly && !checkInlinePermissions()) { return; @@ -741,12 +751,14 @@ public class EmbedBottomSheet extends BottomSheet { return; } boolean animated = false; - pipVideoView = new PipVideoView(inAppOnly); - pipVideoView.show(parentActivity, EmbedBottomSheet.this, null, width != 0 && height != 0 ? width / (float) height : 1.0f, 0, webView); + if (PipVideoOverlay.show(inAppOnly, parentActivity, webView, width, height)) { + PipVideoOverlay.setParentSheet(EmbedBottomSheet.this); + } + if (isYouTube) { runJsCode("hideControls();"); } - if (animated) { + if (animated && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { animationInProgress = true; View view = videoView.getAspectRatioView(); @@ -1011,9 +1023,6 @@ public class EmbedBottomSheet extends BottomSheet { } } } - if (pipVideoView != null) { - pipVideoView.onConfigurationChanged(); - } } public void destroy() { @@ -1023,10 +1032,7 @@ public class EmbedBottomSheet extends BottomSheet { webView.loadUrl("about:blank"); webView.destroy(); } - if (pipVideoView != null) { - pipVideoView.close(); - pipVideoView = null; - } + PipVideoOverlay.dismiss(); if (videoView != null) { videoView.destroy(); } @@ -1044,7 +1050,7 @@ public class EmbedBottomSheet extends BottomSheet { } public void exitFromPip() { - if (webView == null || pipVideoView == null) { + if (webView == null || !PipVideoOverlay.isVisible()) { return; } if (ApplicationLoader.mainInterfacePaused) { @@ -1064,8 +1070,7 @@ public class EmbedBottomSheet extends BottomSheet { containerLayout.addView(webView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 48 + 36 + (hasDescription ? 22 : 0))); setShowWithoutAnimation(true); show(); - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(true); } public static EmbedBottomSheet getInstance() { @@ -1135,8 +1140,7 @@ public class EmbedBottomSheet extends BottomSheet { waitingForDraw--; if (waitingForDraw == 0) { videoView.updateTextureImageView(); - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(); } else { container.invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java index fb091dc0f..60a46803d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -448,9 +448,15 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); - stickersSearchField.searchEditText.setEnabled(enabled); - gifSearchField.searchEditText.setEnabled(enabled); - emojiSearchField.searchEditText.setEnabled(enabled); + if (stickersSearchField != null) { + stickersSearchField.searchEditText.setEnabled(enabled); + } + if (gifSearchField != null) { + gifSearchField.searchEditText.setEnabled(enabled); + } + if (emojiSearchField != null) { + emojiSearchField.searchEditText.setEnabled(enabled); + } } private class SearchField extends FrameLayout { 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 e534cc65b..635856964 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java @@ -855,7 +855,8 @@ public class FilterTabsView extends FrameLayout { }; itemAnimator.setDelayAnimations(false); listView.setItemAnimator(itemAnimator); - listView.setSelectorType(7); + listView.setSelectorType(8); + listView.setSelectorRadius(6); listView.setSelectorDrawableColor(Theme.getColor(selectorColorKey)); listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java index de2c40e00..3fc21b44c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java @@ -47,6 +47,12 @@ import java.util.ArrayList; public class ForwardingPreviewView extends FrameLayout { + TLRPC.Peer sendAsPeer; + public void setSendAsPeer(TLRPC.Peer defPeer) { + sendAsPeer = defPeer; + updateMessages(); + } + public interface ResourcesDelegate extends Theme.ResourcesProvider { Drawable getWallpaperDrawable(); @@ -108,7 +114,7 @@ public class ForwardingPreviewView extends FrameLayout { private final ResourcesDelegate resourcesProvider; @SuppressLint("ClickableViewAccessibility") - public ForwardingPreviewView(@NonNull Context context, ForwardingMessagesParams params, TLRPC.User user, TLRPC.Chat chat, int currentAccount, ResourcesDelegate resourcesProvider) { + public ForwardingPreviewView(@NonNull Context context, ForwardingMessagesParams params, TLRPC.User user, TLRPC.Chat chat, int currentAccount, ResourcesDelegate resourcesProvider) { super(context); this.currentAccount = currentAccount; currentUser = user; @@ -168,7 +174,7 @@ public class ForwardingPreviewView extends FrameLayout { if ((cell.getCurrentPosition() != null && cell.getCurrentPosition().last) || cell.getTransitionParams().animateBackgroundBoundsInner) { cell.drawTime(canvas, 1f, true); } - if ((cell.getCurrentPosition() != null && cell.getCurrentPosition().last) || cell.getCurrentPosition() == null) { + if (cell.getCurrentPosition() == null || (cell.getCurrentPosition().last || cell.getCurrentMessagesGroup().isDocuments)) { cell.drawCaptionLayout(canvas, false, 1f); } cell.getTransitionParams().recordDrawingStatePreview(); @@ -779,10 +785,13 @@ public class ForwardingPreviewView extends FrameLayout { for (int i = 0; i < forwardingMessagesParams.previewMessages.size(); i++) { MessageObject messageObject = forwardingMessagesParams.previewMessages.get(i); messageObject.forceUpdate = true; + messageObject.sendAsPeer = sendAsPeer; if (!forwardingMessagesParams.hideForwardSendersName) { messageObject.messageOwner.flags |= TLRPC.MESSAGE_FLAG_FWD; + messageObject.hideSendersName = false; } else { messageObject.messageOwner.flags &= ~TLRPC.MESSAGE_FLAG_FWD; + messageObject.hideSendersName = true; } if (forwardingMessagesParams.hideCaption) { messageObject.caption = null; 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 520343a92..d3a1a275d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java @@ -389,9 +389,12 @@ public class FragmentContextView extends FrameLayout implements NotificationCent public void draw(Canvas canvas) { super.draw(canvas); - AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); - joinButtonFlicker.draw(canvas, AndroidUtilities.rectTmp, AndroidUtilities.dp(4)); - invalidate(); + final int halfOutlineWidth = AndroidUtilities.dp(1); + AndroidUtilities.rectTmp.set(halfOutlineWidth, halfOutlineWidth, getWidth() - halfOutlineWidth, getHeight() - halfOutlineWidth); + joinButtonFlicker.draw(canvas, AndroidUtilities.rectTmp, AndroidUtilities.dp(16)); + if (joinButtonFlicker.getProgress() < 1f && !joinButtonFlicker.repeatEnabled) { + invalidate(); + } } @Override @@ -403,7 +406,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent }; joinButton.setText(LocaleController.getString("VoipChatJoin", R.string.VoipChatJoin)); joinButton.setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText)); - joinButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_featuredStickers_addButton), getThemedColor(Theme.key_featuredStickers_addButtonPressed))); + joinButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(16), getThemedColor(Theme.key_featuredStickers_addButton), getThemedColor(Theme.key_featuredStickers_addButtonPressed))); joinButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); joinButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); joinButton.setGravity(Gravity.CENTER); @@ -1999,7 +2002,10 @@ public class FragmentContextView extends FrameLayout implements NotificationCent private void startJoinFlickerAnimation() { if (joinButtonFlicker.getProgress() > 1) { - AndroidUtilities.runOnUIThread(()-> joinButtonFlicker.setProgress(0), 150); + AndroidUtilities.runOnUIThread(() -> { + joinButtonFlicker.setProgress(0); + joinButton.invalidate(); + }, 150); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java index 13ceb10ea..f4af0f052 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java @@ -29,6 +29,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.SurfaceTexture; +import android.graphics.drawable.AnimatedVectorDrawable; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaCodec; @@ -58,6 +59,7 @@ import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; +import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import com.google.android.exoplayer2.ExoPlayer; @@ -118,6 +120,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private Paint paint; private RectF rect; private ImageView switchCameraButton; + AnimatedVectorDrawable switchCameraDrawable = null; private ImageView muteImageView; private float progress; private CameraInfo selectedCamera; @@ -204,6 +207,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private FloatBuffer textureBuffer; private float scaleX; private float scaleY; + private boolean flipAnimationInProgress; private View parentView; public boolean opened; @@ -305,7 +309,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter cameraContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null); } - addView(cameraContainer, new FrameLayout.LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER)); + addView(cameraContainer, new LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER)); switchCameraButton = new ImageView(context); switchCameraButton.setScaleType(ImageView.ScaleType.CENTER); @@ -316,15 +320,42 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return; } switchCamera(); - ObjectAnimator animator = ObjectAnimator.ofFloat(switchCameraButton, View.SCALE_X, 0.0f).setDuration(100); - animator.addListener(new AnimatorListenerAdapter() { + if (switchCameraDrawable != null) { + switchCameraDrawable.start(); + } + flipAnimationInProgress = true; + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); + valueAnimator.setDuration(300); + valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override - public void onAnimationEnd(Animator animator) { - switchCameraButton.setImageResource(isFrontface ? R.drawable.camera_revert1 : R.drawable.camera_revert2); - ObjectAnimator.ofFloat(switchCameraButton, View.SCALE_X, 1.0f).setDuration(100).start(); + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float p = (float) valueAnimator.getAnimatedValue(); + if (p < 0.5f) { + p = (1f - p / 0.5f); + } else { + p = (p - 0.5f) / 0.5f; + } + float scaleDown = 0.9f + 0.1f * p; + cameraContainer.setScaleX(p * scaleDown); + cameraContainer.setScaleY(scaleDown); + textureOverlayView.setScaleX(p * scaleDown); + textureOverlayView.setScaleY(scaleDown); } }); - animator.start(); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + cameraContainer.setScaleX(1f); + cameraContainer.setScaleY(1f); + textureOverlayView.setScaleY(1f); + textureOverlayView.setScaleX(1f); + flipAnimationInProgress = false; + invalidate(); + } + }); + valueAnimator.start(); }); muteImageView = new ImageView(context); @@ -353,10 +384,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } }; - addView(textureOverlayView, new FrameLayout.LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER)); + addView(textureOverlayView, new LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER)); setVisibility(INVISIBLE); - blurBehindDrawable = new BlurBehindDrawable(parentView, this, 0, null); + blurBehindDrawable = new BlurBehindDrawable(parentView, this, 0, resourcesProvider); } @Override @@ -463,7 +494,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter if (progress != 0) { canvas.save(); - canvas.scale(cameraContainer.getScaleX(), cameraContainer.getScaleY(), rect.centerX(), rect.centerY()); + if (!flipAnimationInProgress) { + canvas.scale(cameraContainer.getScaleX(), cameraContainer.getScaleY(), rect.centerX(), rect.centerY()); + } canvas.drawArc(rect, -90, 360 * progress, false, paint); canvas.restore(); } @@ -521,7 +554,15 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return; } - switchCameraButton.setImageResource(R.drawable.camera_revert1); + + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + switchCameraDrawable = (AnimatedVectorDrawable) ContextCompat.getDrawable(getContext(), R.drawable.avd_flip); + switchCameraButton.setImageDrawable(switchCameraDrawable); + } else { + switchCameraButton.setImageResource(R.drawable.vd_flip); + } + textureOverlayView.setAlpha(1.0f); textureOverlayView.invalidate(); if (lastBitmap == null) { @@ -1958,7 +1999,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } private void createKeyframeThumb() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW && frameCount % 33 == 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH && frameCount % 33 == 0) { GenerateKeyframeThumbTask task = new GenerateKeyframeThumbTask(); generateKeyframeThumbsQueue.postRunnable(task); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java index 6110e7e95..7bb73610b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java @@ -29,9 +29,18 @@ public class LinkPath extends Path { private int baselineShift; private int lineHeight; - private static final int radius = AndroidUtilities.dp(4); - private static final int halfRadius = radius >> 1; - public static final CornerPathEffect roundedEffect = new CornerPathEffect(radius); + public static int getRadius() { + return AndroidUtilities.dp(4); + } + + private static CornerPathEffect roundedEffect; + private static int roundedEffectRadius; + public static CornerPathEffect getRoundedEffect() { + if (roundedEffect == null || roundedEffectRadius != getRadius()) { + roundedEffect = new CornerPathEffect(roundedEffectRadius = getRadius()); + } + return roundedEffect; + } public LinkPath() { super(); @@ -108,7 +117,7 @@ public class LinkPath extends Path { y += baselineShift; } if (useRoundRect) { - super.addRect(left - halfRadius, y, right + halfRadius, y2, dir); + super.addRect(left - getRadius() / 2f, y, right + getRadius() / 2f, y2, dir); } else { super.addRect(left, y, right, y2, dir); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java new file mode 100644 index 000000000..8ea4a6375 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java @@ -0,0 +1,364 @@ +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.CornerPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.Region; +import android.os.Build; +import android.os.SystemClock; +import android.text.style.CharacterStyle; +import android.util.Log; +import android.util.Pair; +import android.view.View; +import android.view.ViewConfiguration; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ArticleViewer; + +import java.util.ArrayList; + +public class LinkSpanDrawable { + + private int cornerRadius; + private int color; + private Paint mSelectionPaint, mRipplePaint; + private int mSelectionAlpha, mRippleAlpha; + + private static final ArrayList pathCache = new ArrayList<>(); + private final ArrayList mPathes = new ArrayList<>(); + private int mPathesCount = 0; + + private final S mSpan; + private final Theme.ResourcesProvider mResourcesProvider; + private final float mTouchX; + private final float mTouchY; + private final Path circlePath = new Path(); + + private Rect mBounds; + private float mMaxRadius; + private long mStart = -1; + private long mReleaseStart = -1; + private final long mDuration; + private final long mLongPressDuration; + private final boolean mSupportsLongPress; + private static final long mReleaseDelay = 75; + private static final long mReleaseDuration = 100; + + private final float selectionAlpha = 0.2f; + private final float rippleAlpha = 0.8f; + + public LinkSpanDrawable(S span, Theme.ResourcesProvider resourcesProvider, float touchX, float touchY) { + this(span, resourcesProvider, touchX, touchY, true); + } + + public LinkSpanDrawable(S span, Theme.ResourcesProvider resourcesProvider, float touchX, float touchY, boolean supportsLongPress) { + mSpan = span; + mResourcesProvider = resourcesProvider; + setColor(getThemedColor(Theme.key_chat_linkSelectBackground)); + mTouchX = touchX; + mTouchY = touchY; + final long tapTimeout = ViewConfiguration.getTapTimeout(); + mLongPressDuration = ViewConfiguration.getLongPressTimeout(); + mDuration = (long) Math.min(tapTimeout * 1.8f, mLongPressDuration * 0.8f); + mSupportsLongPress = false; + } + + public void setColor(int color) { + this.color = color; + if (mSelectionPaint != null) { + mSelectionPaint.setColor(color); + mSelectionAlpha = mSelectionPaint.getAlpha(); + } + if (mRipplePaint != null) { + mRipplePaint.setColor(color); + mRippleAlpha = mRipplePaint.getAlpha(); + } + } + + public void release() { + mReleaseStart = Math.max(mStart + mDuration, SystemClock.elapsedRealtime()); + } + + public LinkPath obtainNewPath() { + LinkPath linkPath; + if (!pathCache.isEmpty()) { + linkPath = pathCache.remove(0); + } else { + linkPath = new LinkPath(true); + } + linkPath.reset(); + mPathes.add(linkPath); + mPathesCount = mPathes.size(); + return linkPath; + } + + public void reset() { + if (mPathes.isEmpty()) { + return; + } + pathCache.addAll(mPathes); + mPathes.clear(); + mPathesCount = 0; + } + + public S getSpan() { + return mSpan; + } + + public boolean draw(Canvas canvas) { + boolean cornerRadiusUpdate = cornerRadius != AndroidUtilities.dp(4); + if (mSelectionPaint == null || cornerRadiusUpdate) { + mSelectionPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mSelectionPaint.setStyle(Paint.Style.FILL_AND_STROKE); + mSelectionPaint.setColor(color); + mSelectionAlpha = mSelectionPaint.getAlpha(); + mSelectionPaint.setPathEffect(new CornerPathEffect(cornerRadius = AndroidUtilities.dp(4))); + } + if (mRipplePaint == null || cornerRadiusUpdate) { + mRipplePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mRipplePaint.setStyle(Paint.Style.FILL_AND_STROKE); + mRipplePaint.setColor(color); + mRippleAlpha = mRipplePaint.getAlpha(); + mRipplePaint.setPathEffect(new CornerPathEffect(cornerRadius = AndroidUtilities.dp(4))); + } + if (mBounds == null && mPathesCount > 0) { + mPathes.get(0).computeBounds(AndroidUtilities.rectTmp, false); + mBounds = new Rect( + (int) AndroidUtilities.rectTmp.left, + (int) AndroidUtilities.rectTmp.top, + (int) AndroidUtilities.rectTmp.right, + (int) AndroidUtilities.rectTmp.bottom + ); + for (int i = 1; i < mPathesCount; ++i) { + mPathes.get(i).computeBounds(AndroidUtilities.rectTmp, false); + mBounds.left = Math.min(mBounds.left, (int) AndroidUtilities.rectTmp.left); + mBounds.top = Math.min(mBounds.top, (int) AndroidUtilities.rectTmp.top); + mBounds.right = Math.max(mBounds.right, (int) AndroidUtilities.rectTmp.right); + mBounds.bottom = Math.max(mBounds.bottom, (int) AndroidUtilities.rectTmp.bottom); + } + mMaxRadius = (float) Math.sqrt( + Math.max( + Math.max( + Math.pow(mBounds.left - mTouchX, 2) + Math.pow(mBounds.top - mTouchY, 2), + Math.pow(mBounds.right - mTouchX, 2) + Math.pow(mBounds.top - mTouchY, 2) + ), + Math.max( + Math.pow(mBounds.left - mTouchX, 2) + Math.pow(mBounds.bottom - mTouchY, 2), + Math.pow(mBounds.right - mTouchX, 2) + Math.pow(mBounds.bottom - mTouchY, 2) + ) + ) + ); + } + + final long now = SystemClock.elapsedRealtime(); + if (mStart < 0) { + mStart = now; + } + float pressT = CubicBezierInterpolator.DEFAULT.getInterpolation(Math.min(1, (now - mStart) / (float) mDuration)), + releaseT = mReleaseStart < 0 ? 0 : Math.min(1, Math.max(0, (now - mReleaseDelay - mReleaseStart) / (float) mReleaseDuration)); + float longPress; + if (mSupportsLongPress) { + longPress = Math.max(0, (now - mStart - mDuration * 2) / (float) (mLongPressDuration - mDuration * 2)); + if (longPress > 1f) { + longPress = 1f - ((now - mStart - mLongPressDuration) / (float) mDuration); + } else { + longPress *= .5f; + } + longPress *= (1f - releaseT); + } else { + longPress = 1f; + } + + mSelectionPaint.setAlpha((int) (mSelectionAlpha * selectionAlpha * Math.min(1, pressT * 5f) * (1f - releaseT))); + mSelectionPaint.setStrokeWidth(Math.min(1, 1f - longPress) * AndroidUtilities.dp(5)); + for (int i = 0; i < mPathesCount; ++i) { + canvas.drawPath(mPathes.get(i), mSelectionPaint); + } + + mRipplePaint.setAlpha((int) (mRippleAlpha * rippleAlpha * (1f - releaseT))); + mRipplePaint.setStrokeWidth(Math.min(1, 1f - longPress) * AndroidUtilities.dp(5)); + if (pressT < 1f) { + float r = pressT * mMaxRadius; + canvas.save(); + circlePath.reset(); + circlePath.addCircle(mTouchX, mTouchY, r, Path.Direction.CW); + canvas.clipPath(circlePath); + for (int i = 0; i < mPathesCount; ++i) { + canvas.drawPath(mPathes.get(i), mRipplePaint); + } + canvas.restore(); + } else { + for (int i = 0; i < mPathesCount; ++i) { + canvas.drawPath(mPathes.get(i), mRipplePaint); + } + } + + return pressT < 1f || mReleaseStart >= 0 || (mSupportsLongPress && now - mStart < mLongPressDuration + mDuration); + } + + private int getThemedColor(String key) { + Integer color = mResourcesProvider != null ? mResourcesProvider.getColor(key) : null; + return color != null ? color : Theme.getColor(key); + } + + public static class LinkCollector { + + private View mParent; + + public LinkCollector() {} + public LinkCollector(View parentView) { + mParent = parentView; + } + + private ArrayList> mLinks = new ArrayList<>(); + private int mLinksCount = 0; + + public void addLink(LinkSpanDrawable link) { + addLink(link, null); + } + + public void addLink(LinkSpanDrawable link, Object obj) { + mLinks.add(new Pair<>(link, obj)); + mLinksCount++; + invalidate(obj); + } + + public void removeLink(LinkSpanDrawable link) { + removeLink(link, true); + } + + public void removeLink(LinkSpanDrawable link, boolean animated) { + if (link == null) { + return; + } + Pair pair = null; + for (int i = 0; i < mLinksCount; ++i) { + if (mLinks.get(i).first == link) { + pair = mLinks.get(i); + break; + } + } + if (pair == null) { + return; + } + if (animated) { + if (link.mReleaseStart < 0) { + link.release(); + invalidate(pair.second); + final long now = SystemClock.elapsedRealtime(); + AndroidUtilities.runOnUIThread( + () -> removeLink(link, false), + Math.max(0, (link.mReleaseStart - now) + mReleaseDelay + mReleaseDuration) + ); + } + } else { + mLinks.remove(pair); + link.reset(); + mLinksCount = mLinks.size(); + invalidate(pair.second); + } + } + + private void removeLink(int index, boolean animated) { + if (index < 0 || index >= mLinksCount) { + return; + } + if (animated) { + Pair pair = mLinks.get(index); + LinkSpanDrawable link = pair.first; + if (link.mReleaseStart < 0) { + link.release(); + invalidate(pair.second); + final long now = SystemClock.elapsedRealtime(); + AndroidUtilities.runOnUIThread( + () -> removeLink(link, false), + Math.max(0, (link.mReleaseStart - now) + mReleaseDelay + mReleaseDuration) + ); + } + } else { + Pair pair = mLinks.remove(index); + LinkSpanDrawable link = pair.first; + link.reset(); + mLinksCount = mLinks.size(); + invalidate(pair.second); + } + } + + public void clear() { + clear(true); + } + + public void clear(boolean animated) { + if (animated) { + for (int i = 0; i < mLinksCount; ++i) { + removeLink(i, true); + } + } else if (mLinksCount > 0) { + for (int i = 0; i < mLinksCount; ++i) { + mLinks.get(i).first.reset(); + invalidate(mLinks.get(i).second, false); + } + mLinks.clear(); + mLinksCount = 0; + invalidate(); + } + } + + public void removeLinks(Object obj) { + removeLinks(obj, true); + } + + public void removeLinks(Object obj, boolean animated) { + for (int i = 0; i < mLinksCount; ++i) { + if (mLinks.get(i).second == obj) { + removeLink(i, animated); + } + } + } + + public boolean draw(Canvas canvas) { + boolean invalidate = false; + for (int i = 0; i < mLinksCount; ++i) { + invalidate = mLinks.get(i).first.draw(canvas) || invalidate; + } + return invalidate; + } + + public boolean draw(Canvas canvas, Object obj) { + boolean invalidate = false; + for (int i = 0; i < mLinksCount; ++i) { + if (mLinks.get(i).second == obj) { + invalidate = mLinks.get(i).first.draw(canvas) || invalidate; + } + } + invalidate(obj, false); + return invalidate; + } + + public boolean isEmpty() { + return mLinksCount <= 0; + } + + private void invalidate() { + invalidate(null, true); + } + private void invalidate(Object obj) { + invalidate(obj, true); + } + private void invalidate(Object obj, boolean tryParent) { + if (obj instanceof View) { + ((View) obj).invalidate(); + } else if (obj instanceof ArticleViewer.DrawingText) { + ArticleViewer.DrawingText text = (ArticleViewer.DrawingText) obj; + if (text.latestParentView != null) { + text.latestParentView.invalidate(); + } + } else if (tryParent && mParent != null) { + mParent.invalidate(); + } + } + } +} 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 ed1fe3cf6..29f8077be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java @@ -39,12 +39,14 @@ import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Utilities; import org.telegram.ui.ActionBar.Theme; import java.util.Locale; public class NumberPicker extends LinearLayout { + public static final int DEFAULT_SIZE_PER_COUNT = 42; private int SELECTOR_WHEEL_ITEM_COUNT = 3; private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300; private int SELECTOR_MIDDLE_ITEM_INDEX = SELECTOR_WHEEL_ITEM_COUNT / 2; @@ -265,8 +267,8 @@ public class NumberPicker extends LinearLayout { if (changed) { initializeSelectorWheel(); initializeFadingEdges(); - mTopSelectionDividerTop = (getHeight() - mSelectionDividersDistance) / 2 - mSelectionDividerHeight; - mBottomSelectionDividerBottom = mTopSelectionDividerTop + 2 * mSelectionDividerHeight + mSelectionDividersDistance; + mTopSelectionDividerTop = (getHeight() - mTextSize - mSelectorTextGapHeight) / 2; + mBottomSelectionDividerBottom = (getHeight() + mTextSize + mSelectorTextGapHeight) / 2; } } @@ -517,7 +519,6 @@ public class NumberPicker extends LinearLayout { while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) { mCurrentScrollOffset -= mSelectorElementHeight; decrementSelectorIndices(selectorIndices); - setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue && mCurrentScrollOffset > mInitialScrollOffset) { mCurrentScrollOffset = mInitialScrollOffset; } @@ -525,11 +526,11 @@ public class NumberPicker extends LinearLayout { while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) { mCurrentScrollOffset += mSelectorElementHeight; incrementSelectorIndices(selectorIndices); - setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue && mCurrentScrollOffset < mInitialScrollOffset) { mCurrentScrollOffset = mInitialScrollOffset; } } + setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); } @Override @@ -712,6 +713,7 @@ public class NumberPicker extends LinearLayout { removeAllCallbacks(); } + private final static CubicBezierInterpolator interpolator = new CubicBezierInterpolator(0, 0.5f, 0.5f, 1f); @Override protected void onDraw(Canvas canvas) { float x = (getRight() - getLeft()) / 2 + textOffset; @@ -728,7 +730,40 @@ public class NumberPicker extends LinearLayout { // IME he may see a dimmed version of the old value intermixed // with the new one. if (scrollSelectorValue != null && (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE)) { - canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); + if (SELECTOR_WHEEL_ITEM_COUNT > 3) { + float p; + float cY = getMeasuredHeight() / 2f; + float r = getMeasuredHeight() * 0.5f; + float localY = y - mSelectorWheelPaint.getTextSize() / 2f; + boolean top = true; + if (localY < cY) { + p = localY / r; + } else { + p = (getMeasuredHeight() - localY) / r; + top = false; + } + p = interpolator.getInterpolation(Utilities.clamp(p, 1f, 0)); + float yOffset = (1f - p) * mSelectorWheelPaint.getTextSize(); + if (!top) { + yOffset = -yOffset; + } + int oldAlpha = -1; + + canvas.save(); + canvas.translate(0, yOffset); + canvas.scale(0.8f + p * 0.2f, p, x, localY); + if (p < 0.1f) { + oldAlpha = mSelectorWheelPaint.getAlpha(); + mSelectorWheelPaint.setAlpha((int) (oldAlpha * p / 0.1f)); + } + canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); + canvas.restore(); + if (oldAlpha != -1) { + mSelectorWheelPaint.setAlpha(oldAlpha); + } + } else { + canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); + } } y += mSelectorElementHeight; } @@ -846,7 +881,7 @@ public class NumberPicker extends LinearLayout { initializeSelectorWheelIndices(); int[] selectorIndices = mSelectorIndices; int totalTextHeight = selectorIndices.length * mTextSize; - float totalTextGapHeight = (getBottom() - getTop()) - totalTextHeight; + float totalTextGapHeight = (getBottom() - getTop() + mTextSize) - totalTextHeight; float textGapCount = selectorIndices.length; mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f); mSelectorElementHeight = mTextSize + mSelectorTextGapHeight; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java index 26f5df890..6c77ffa27 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java @@ -12,6 +12,7 @@ import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Point; import org.telegram.ui.Components.RLottieDrawable; @@ -144,11 +145,16 @@ public class StickerView extends EntityView { } public long getDuration() { - RLottieDrawable drawable = centerImage.getLottieAnimation(); - if (drawable == null) { - return 0; + RLottieDrawable rLottieDrawable = centerImage.getLottieAnimation(); + if (rLottieDrawable != null) { + return rLottieDrawable.getDuration(); } - return drawable.getDuration(); + AnimatedFileDrawable animatedFileDrawable = centerImage.getAnimation(); + if (animatedFileDrawable != null) { + return animatedFileDrawable.getDurationMs(); + } + return 0; + } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java index 511d65ed5..aec222dbd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java @@ -485,8 +485,10 @@ public class PhotoPaintView extends FrameLayout implements EntityView.EntityView lcm = BigInteger.ONE; if (bitmap != null && entitiesView.entitiesCount() > 0) { Canvas canvas = null; + Canvas thumbCanvas = null; int count = entitiesView.getChildCount(); for (int i = 0; i < count; i++) { + boolean skipDrawToBitmap = false; View v = entitiesView.getChildAt(i); if (!(v instanceof EntityView)) { continue; @@ -517,13 +519,20 @@ public class PhotoPaintView extends FrameLayout implements EntityView.EntityView mediaEntity.parentObject = stickerView.getParentObject(); TLRPC.Document document = stickerView.getSticker(); mediaEntity.text = FileLoader.getPathToAttach(document, true).getAbsolutePath(); - if (MessageObject.isAnimatedStickerDocument(document, true)) { - mediaEntity.subType |= 1; - long duration = stickerView.getDuration(); + if (MessageObject.isAnimatedStickerDocument(document, true) || MessageObject.isVideoStickerDocument(document)) { + boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(document, true); + mediaEntity.subType |= isAnimatedSticker ? 1 : 4; + long duration; + if (isAnimatedSticker) { + duration = stickerView.getDuration(); + } else { + duration = 5000; + } if (duration != 0) { BigInteger x = BigInteger.valueOf(duration); lcm = lcm.multiply(x).divide(lcm.gcd(x)); } + skipDrawToBitmap = true; } if (stickerView.isMirrored()) { mediaEntity.subType |= 2; @@ -552,33 +561,37 @@ public class PhotoPaintView extends FrameLayout implements EntityView.EntityView if (thumbBitmap[0] == null) { thumbBitmap[0] = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); - canvas = new Canvas(thumbBitmap[0]); - canvas.drawBitmap(bitmap, 0, 0, null); + thumbCanvas = new Canvas(thumbBitmap[0]); + thumbCanvas.drawBitmap(bitmap, 0, 0, null); } } - if (canvas == null) { - canvas = new Canvas(bitmap); - } - canvas.save(); - canvas.translate(position.x, position.y); - canvas.scale(v.getScaleX(), v.getScaleY()); - canvas.rotate(v.getRotation()); - canvas.translate(-entity.getWidth() / 2, -entity.getHeight() / 2); - if (v instanceof TextPaintView) { - Bitmap b = Bitmaps.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(b); - v.draw(c); - canvas.drawBitmap(b, null, new Rect(0, 0, b.getWidth(), b.getHeight()), null); - try { - c.setBitmap(null); - } catch (Exception e) { - FileLog.e(e); + canvas = new Canvas(bitmap); + for (int k = 0; k < 2; k++) { + Canvas currentCanvas = k == 0 ? canvas : thumbCanvas; + if (currentCanvas == null || (k == 0 && skipDrawToBitmap)) { + continue; } - b.recycle(); - } else { - v.draw(canvas); + currentCanvas.save(); + currentCanvas.translate(position.x, position.y); + currentCanvas.scale(v.getScaleX(), v.getScaleY()); + currentCanvas.rotate(v.getRotation()); + currentCanvas.translate(-entity.getWidth() / 2, -entity.getHeight() / 2); + if (v instanceof TextPaintView) { + Bitmap b = Bitmaps.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(b); + v.draw(c); + currentCanvas.drawBitmap(b, null, new Rect(0, 0, b.getWidth(), b.getHeight()), null); + try { + c.setBitmap(null); + } catch (Exception e) { + FileLog.e(e); + } + b.recycle(); + } else { + v.draw(currentCanvas); + } + currentCanvas.restore(); } - canvas.restore(); } } return bitmap; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java index 42862fab7..708ec63a7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java @@ -69,6 +69,7 @@ public class PhotoViewerCaptionEnterView extends FrameLayout implements Notifica void onWindowSizeChanged(int size); void onEmojiViewCloseStart(); void onEmojiViewCloseEnd(); + void onEmojiViewOpen(); } private EditTextCaption messageEditText; @@ -645,6 +646,7 @@ public class PhotoViewerCaptionEnterView extends FrameLayout implements Notifica } emojiView.setVisibility(VISIBLE); + delegate.onEmojiViewOpen(); if (keyboardHeight <= 0) { keyboardHeight = MessagesController.getGlobalEmojiSettings().getInt("kbd_height", AndroidUtilities.dp(200)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerWebView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerWebView.java index a51a781e0..9e6fb69f6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerWebView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerWebView.java @@ -36,7 +36,6 @@ import java.util.Locale; public class PhotoViewerWebView extends FrameLayout { private int currentAccount = UserConfig.selectedAccount; - private PipVideoView pipVideoView; private WebView webView; private View progressBarBlackBackground; @@ -253,18 +252,24 @@ public class PhotoViewerWebView extends FrameLayout { return progressBar.getVisibility() != View.VISIBLE; } - public PipVideoView openInPip() { + public boolean openInPip() { boolean inAppOnly = isYouTube && "inapp".equals(MessagesController.getInstance(currentAccount).youtubePipType); if (!inAppOnly && !checkInlinePermissions()) { - return null; + return false; } if (progressBar.getVisibility() == View.VISIBLE) { - return null; + return false; } - boolean animated = false; - pipVideoView = new PipVideoView(inAppOnly); - pipVideoView.show((Activity) getContext(), PhotoViewer.getInstance(), currentWebpage.embed_width != 0 && currentWebpage.embed_height != 0 ? currentWebpage.embed_width / (float) currentWebpage.embed_height : 1.0f, 0, webView); - return pipVideoView; + if (PipVideoOverlay.isVisible()) { + PipVideoOverlay.dismiss(); + AndroidUtilities.runOnUIThread(this::openInPip, 300); + return true; + } + + if (PipVideoOverlay.show(inAppOnly, (Activity) getContext(), webView, currentWebpage.embed_width, currentWebpage.embed_height)) { + PipVideoOverlay.setPhotoViewer(PhotoViewer.getInstance()); + } + return true; } public void setPlaybackSpeed(float speed) { @@ -349,7 +354,7 @@ public class PhotoViewerWebView extends FrameLayout { } public void exitFromPip() { - if (webView == null || pipVideoView == null) { + if (webView == null) { return; } if (ApplicationLoader.mainInterfacePaused) { @@ -364,8 +369,7 @@ public class PhotoViewerWebView extends FrameLayout { parent.removeView(webView); } addView(webView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(); } public void release() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java new file mode 100644 index 000000000..95396a278 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java @@ -0,0 +1,941 @@ +package org.telegram.ui.Components; + +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ActivityManager; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.os.Build; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.view.WindowManager; +import android.webkit.WebView; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import androidx.core.math.MathUtils; +import androidx.core.view.GestureDetectorCompat; +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.dynamicanimation.animation.FloatPropertyCompat; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PhotoViewer; + +import java.util.ArrayList; +import java.util.List; + +public class PipVideoOverlay { + public final static boolean IS_TRANSITION_ANIMATION_SUPPORTED = true; + public final static float ROUNDED_CORNERS_DP = 10; + + private final static float SIDE_PADDING_DP = 16; + private final static FloatPropertyCompat PIP_X_PROPERTY = new SimpleFloatPropertyCompat<>("pipX", obj -> obj.pipX, (obj, value) -> { + obj.windowLayoutParams.x = (int) (obj.pipX = value); + try { + obj.windowManager.updateViewLayout(obj.contentView, obj.windowLayoutParams); + } catch (IllegalArgumentException e) { + obj.pipXSpring.cancel(); + } + }), PIP_Y_PROPERTY = new SimpleFloatPropertyCompat<>("pipY", obj -> obj.pipY, (obj, value) -> { + obj.windowLayoutParams.y = (int) (obj.pipY = value); + + try { + obj.windowManager.updateViewLayout(obj.contentView, obj.windowLayoutParams); + } catch (IllegalArgumentException e) { + obj.pipYSpring.cancel(); + } + }); + + @SuppressLint("StaticFieldLeak") + private static PipVideoOverlay instance = new PipVideoOverlay(); + + private float minScaleFactor = 0.75f, maxScaleFactor = 1.4f; + + private WindowManager windowManager; + private WindowManager.LayoutParams windowLayoutParams; + private ViewGroup contentView; + private FrameLayout contentFrameLayout; + private View innerView; + private FrameLayout controlsView; + + private ScaleGestureDetector scaleGestureDetector; + private GestureDetectorCompat gestureDetector; + private boolean isScrolling; + private boolean isScrollDisallowed; + private View consumingChild; + private boolean isShowingControls; + private ValueAnimator controlsAnimator; + + private PipConfig pipConfig; + private int pipWidth, pipHeight; + private float scaleFactor = 1f; + private float pipX, pipY; + private SpringAnimation pipXSpring, pipYSpring; + private Float aspectRatio; + + private boolean isVisible; + + private boolean postedDismissControls; + private Runnable dismissControlsCallback = () -> { + toggleControls(isShowingControls = false); + postedDismissControls = false; + }; + + private int mVideoWidth, mVideoHeight; + private EmbedBottomSheet parentSheet; + private PhotoViewer photoViewer; + private ImageView playPauseButton; + private boolean isVideoCompleted; + private float videoProgress, bufferProgress; + private VideoProgressView videoProgressView; + private boolean isDismissing; + private boolean onSideToDismiss; + private Runnable progressRunnable = () -> { + if (photoViewer == null) { + return; + } + VideoPlayer videoPlayer = photoViewer.getVideoPlayer(); + if (videoPlayer == null) { + return; + } + videoProgress = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration(); + if (photoViewer == null) { + bufferProgress = videoPlayer.getBufferedPosition() / (float) videoPlayer.getDuration(); + } + videoProgressView.invalidate(); + + AndroidUtilities.runOnUIThread(this.progressRunnable, 500); + }; + + private PipConfig getPipConfig() { + if (pipConfig == null) { + pipConfig = new PipConfig(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y); + } + return pipConfig; + } + + public static boolean isVisible() { + return instance.isVisible; + } + + private int getSuggestedWidth() { + return getSuggestedWidth(getRatio()); + } + + private static int getSuggestedWidth(float ratio) { + if (ratio >= 1) { + return (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.35f); + } + return (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.6f); + } + + private int getSuggestedHeight() { + return getSuggestedHeight(getRatio()); + } + + private static int getSuggestedHeight(float ratio) { + return (int) (getSuggestedWidth(ratio) * ratio); + } + + private float getRatio() { + if (aspectRatio == null) { + aspectRatio = mVideoHeight / (float) mVideoWidth; + + maxScaleFactor = (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(SIDE_PADDING_DP * 2)) / (float) getSuggestedWidth(); + } + return aspectRatio; + } + + private void toggleControls(boolean show) { + controlsAnimator = ValueAnimator.ofFloat(show ? 0 : 1, show ? 1 : 0f).setDuration(200); + controlsAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + controlsAnimator.addUpdateListener(animation -> { + float value = (float) animation.getAnimatedValue(); + controlsView.setAlpha(value); + }); + controlsAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + controlsAnimator = null; + } + }); + controlsAnimator.start(); + } + + public static void dimissAndDestroy() { + if (instance.parentSheet != null) { + instance.parentSheet.destroy(); + } else if (instance.photoViewer != null) { + instance.photoViewer.destroyPhotoViewer(); + } + dismiss(); + } + + public static void dismiss() { + dismiss(false); + } + + public static void dismiss(boolean animate) { + instance.dismissInternal(animate); + } + + private void dismissInternal(boolean animate) { + if (isDismissing) { + return; + } + isDismissing = true; + + if (controlsAnimator != null) { + controlsAnimator.cancel(); + } + + if (postedDismissControls) { + AndroidUtilities.cancelRunOnUIThread(dismissControlsCallback); + postedDismissControls = false; + } + + if (pipXSpring != null) { + pipXSpring.cancel(); + pipYSpring.cancel(); + } + + // Animate is a flag for PhotoViewer transition, not ours + if (animate) { + AndroidUtilities.runOnUIThread(this::onDismissedInternal, 100); + } else { + AnimatorSet set = new AnimatorSet(); + set.setDuration(250); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + set.playTogether( + ObjectAnimator.ofFloat(contentView, View.ALPHA, 0f), + ObjectAnimator.ofFloat(contentView, View.SCALE_X, 0.1f), + ObjectAnimator.ofFloat(contentView, View.SCALE_Y, 0.1f) + ); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + onDismissedInternal(); + } + }); + set.start(); + } + } + + private void onDismissedInternal() { + try { + if (controlsView.getParent() != null) { + windowManager.removeViewImmediate(contentView); + } + } catch (IllegalArgumentException ignored) {} + + videoProgressView = null; + innerView = null; + photoViewer = null; + parentSheet = null; + consumingChild = null; + isScrolling = false; + isVisible = false; + isDismissing = false; + } + + public static void updatePlayButton() { + instance.updatePlayButtonInternal(); + } + + private void updatePlayButtonInternal() { + if (photoViewer == null) { + return; + } + VideoPlayer videoPlayer = photoViewer.getVideoPlayer(); + if (videoPlayer == null || playPauseButton == null) { + return; + } + AndroidUtilities.cancelRunOnUIThread(progressRunnable); + if (!videoPlayer.isPlaying()) { + if (isVideoCompleted) { + playPauseButton.setImageResource(R.drawable.pip_replay_large); + } else { + playPauseButton.setImageResource(R.drawable.pip_play_large); + } + } else { + playPauseButton.setImageResource(R.drawable.pip_pause_large); + AndroidUtilities.runOnUIThread(progressRunnable, 500); + } + } + + public static void onVideoCompleted() { + instance.onVideoCompletedInternal(); + } + + private void onVideoCompletedInternal() { + if (!isVisible || videoProgressView == null) { + return; + } + isVideoCompleted = true; + videoProgress = 0f; + bufferProgress = 0f; + if (videoProgressView != null) { + videoProgressView.invalidate(); + } + + updatePlayButtonInternal(); + AndroidUtilities.cancelRunOnUIThread(progressRunnable); + if (!isShowingControls) { + toggleControls(true); + AndroidUtilities.cancelRunOnUIThread(dismissControlsCallback); + } + } + + public static void setBufferedProgress(float progress) { + instance.bufferProgress = progress; + if (instance.videoProgressView != null) { + instance.videoProgressView.invalidate(); + } + } + + public static void setParentSheet(EmbedBottomSheet parentSheet) { + instance.parentSheet = parentSheet; + } + + public static void setPhotoViewer(PhotoViewer photoViewer) { + instance.photoViewer = photoViewer; + instance.updatePlayButtonInternal(); + } + + public static Rect getPipRect(boolean inAnimation, float aspectRatio) { + Rect rect = new Rect(); + float ratio = 1f / aspectRatio; + if (!instance.isVisible || inAnimation) { + float savedPipX = instance.getPipConfig().getPipX(), savedPipY = instance.getPipConfig().getPipY(); + float scaleFactor = instance.getPipConfig().getScaleFactor(); + + rect.width = getSuggestedWidth(ratio) * scaleFactor; + rect.height = getSuggestedHeight(ratio) * scaleFactor; + if (savedPipX != -1) { + rect.x = savedPipX + rect.width / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - rect.width - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP); + } else { + rect.x = AndroidUtilities.displaySize.x - rect.width - AndroidUtilities.dp(SIDE_PADDING_DP); + } + if (savedPipY != -1) { + rect.y = MathUtils.clamp(savedPipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - AndroidUtilities.dp(SIDE_PADDING_DP) - rect.height) + AndroidUtilities.statusBarHeight; + } else { + rect.y = AndroidUtilities.dp(SIDE_PADDING_DP) + AndroidUtilities.statusBarHeight; + } + return rect; + } + + rect.x = instance.pipX; + rect.y = instance.pipY + AndroidUtilities.statusBarHeight; + rect.width = instance.pipWidth; + rect.height = instance.pipHeight; + return rect; + } + + public static boolean show(boolean inAppOnly, Activity activity, View pipContentView, int videoWidth, int videoHeight) { + return show(inAppOnly, activity, pipContentView, videoWidth, videoHeight, false); + } + + public static boolean show(boolean inAppOnly, Activity activity, View pipContentView, int videoWidth, int videoHeight, boolean animate) { + return instance.showInternal(inAppOnly, activity, pipContentView, videoWidth, videoHeight, animate); + } + + private boolean showInternal(boolean inAppOnly, Activity activity, View pipContentView, int videoWidth, int videoHeight, boolean animate) { + if (isVisible) { + return false; + } + isVisible = true; + + mVideoWidth = videoWidth; + mVideoHeight = videoHeight; + aspectRatio = null; + + float savedPipX = getPipConfig().getPipX(), savedPipY = getPipConfig().getPipY(); + scaleFactor = getPipConfig().getScaleFactor(); + + pipWidth = (int) (getSuggestedWidth() * scaleFactor); + pipHeight = (int) (getSuggestedHeight() * scaleFactor); + isShowingControls = false; + + float stiffness = 650f; + pipXSpring = new SpringAnimation(this, PIP_X_PROPERTY) + .setSpring(new SpringForce() + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(stiffness)) + .addEndListener((animation, canceled, value, velocity) -> getPipConfig().setPipX(value)); + pipYSpring = new SpringAnimation(this, PIP_Y_PROPERTY) + .setSpring(new SpringForce() + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(stiffness)) + .addEndListener((animation, canceled, value, velocity) -> getPipConfig().setPipY(value)); + + Context context = ApplicationLoader.applicationContext; + int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() { + @Override + public boolean onScale(ScaleGestureDetector detector) { + scaleFactor = MathUtils.clamp(scaleFactor * detector.getScaleFactor(), minScaleFactor, maxScaleFactor); + pipWidth = (int) (getSuggestedWidth() * scaleFactor); + pipHeight = (int) (getSuggestedHeight() * scaleFactor); + AndroidUtilities.runOnUIThread(()->{ + contentView.invalidate(); + contentFrameLayout.requestLayout(); + }); + + float finalX = detector.getFocusX() >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP); + if (!pipXSpring.isRunning()) { + pipXSpring.setStartValue(pipX) + .getSpring() + .setFinalPosition(finalX); + } else { + pipXSpring.getSpring().setFinalPosition(finalX); + } + pipXSpring.start(); + + float finalY = MathUtils.clamp(detector.getFocusY() - pipHeight / 2f, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - pipHeight - AndroidUtilities.dp(SIDE_PADDING_DP)); + if (!pipYSpring.isRunning()) { + pipYSpring.setStartValue(pipY) + .getSpring() + .setFinalPosition(finalY); + } else { + pipYSpring.getSpring().setFinalPosition(finalY); + } + pipYSpring.start(); + + return true; + } + + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + if (isScrolling) { + isScrolling = false; + } + isScrollDisallowed = true; + windowLayoutParams.width = (int) (getSuggestedWidth() * maxScaleFactor); + windowLayoutParams.height = (int) (getSuggestedHeight() * maxScaleFactor); + windowManager.updateViewLayout(contentView, windowLayoutParams); + + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + if (pipXSpring.isRunning() || pipYSpring.isRunning()) { + List springs = new ArrayList<>(); + DynamicAnimation.OnAnimationEndListener endListener = new DynamicAnimation.OnAnimationEndListener() { + @Override + public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) { + animation.removeEndListener(this); + + springs.add((SpringAnimation) animation); + if (springs.size() == 2) { + updateLayout(); + } + } + }; + if (!pipXSpring.isRunning()) { + springs.add(pipXSpring); + } else { + pipXSpring.addEndListener(endListener); + } + if (!pipYSpring.isRunning()) { + springs.add(pipYSpring); + } else { + pipYSpring.addEndListener(endListener); + } + return; + } + updateLayout(); + } + + private void updateLayout() { + pipWidth = windowLayoutParams.width = (int) (getSuggestedWidth() * scaleFactor); + pipHeight = windowLayoutParams.height = (int) (getSuggestedHeight() * scaleFactor); + try { + windowManager.updateViewLayout(contentView, windowLayoutParams); + } catch (IllegalArgumentException ignored) {} + } + }); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + scaleGestureDetector.setQuickScaleEnabled(false); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + scaleGestureDetector.setStylusScaleEnabled(false); + } + gestureDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() { + private float startPipX, startPipY; + + @Override + public boolean onDown(MotionEvent e) { + if (isShowingControls) { + for (int i = 1; i < contentFrameLayout.getChildCount(); i++) { + View child = contentFrameLayout.getChildAt(i); + boolean consumed = child.dispatchTouchEvent(e); + if (consumed) { + consumingChild = child; + return true; + } + } + } + startPipX = pipX; + startPipY = pipY; + return true; + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (controlsAnimator != null) { + return true; + } + + if (postedDismissControls) { + AndroidUtilities.cancelRunOnUIThread(dismissControlsCallback); + postedDismissControls = false; + } + + isShowingControls = !isShowingControls; + toggleControls(isShowingControls); + + if (isShowingControls && !postedDismissControls) { + AndroidUtilities.runOnUIThread(dismissControlsCallback, 2500); + postedDismissControls = true; + } + + return true; + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (isScrolling && !isScrollDisallowed) { + pipXSpring.setStartVelocity(velocityX) + .setStartValue(pipX) + .getSpring() + .setFinalPosition(pipX + pipWidth / 2f + velocityX / 7f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + pipXSpring.start(); + + pipYSpring.setStartVelocity(velocityX) + .setStartValue(pipY) + .getSpring() + .setFinalPosition(MathUtils.clamp(pipY + velocityY / 10f, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - pipHeight - AndroidUtilities.dp(SIDE_PADDING_DP))); + pipYSpring.start(); + return true; + } + return false; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (!isScrolling && controlsAnimator == null && !isScrollDisallowed) { + if (Math.abs(distanceX) >= touchSlop || Math.abs(distanceY) >= touchSlop) { + isScrolling = true; + + pipXSpring.cancel(); + pipYSpring.cancel(); + } + } + if (isScrolling) { + float wasPipX = pipX; + float newPipX = startPipX + e2.getRawX() - e1.getRawX(); + pipY = startPipY + e2.getRawY() - e1.getRawY(); + if (newPipX <= -pipWidth * 0.25f || newPipX >= AndroidUtilities.displaySize.x - pipWidth * 0.75f) { + if (!onSideToDismiss) { + pipXSpring.setStartValue(wasPipX) + .getSpring() + .setFinalPosition(newPipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP) - pipWidth); + pipXSpring.start(); + } + onSideToDismiss = true; + } else if (onSideToDismiss) { + if (onSideToDismiss) { + pipXSpring.addEndListener((animation, canceled, value, velocity) -> { + if (!canceled) { + pipXSpring.getSpring().setFinalPosition(newPipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + } + }); + + pipXSpring.setStartValue(wasPipX) + .getSpring() + .setFinalPosition(newPipX); + pipXSpring.start(); + } + onSideToDismiss = false; + } else { + if (pipXSpring.isRunning()) { + pipXSpring.getSpring().setFinalPosition(newPipX); + } else { + windowLayoutParams.x = (int) (pipX = newPipX); + getPipConfig().setPipX(newPipX); + } + windowLayoutParams.y = (int) pipY; + getPipConfig().setPipY(pipY); + windowManager.updateViewLayout(contentView, windowLayoutParams); + } + } + return true; + } + }); + contentFrameLayout = new FrameLayout(context) { + private Path path = new Path(); + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + int action = ev.getAction(); + if (consumingChild != null) { + MotionEvent newEvent = MotionEvent.obtain(ev); + newEvent.offsetLocation(consumingChild.getX(), consumingChild.getY()); + boolean consumed = consumingChild.dispatchTouchEvent(ev); + newEvent.recycle(); + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + consumingChild = null; + } + + if (consumed) { + return true; + } + } + MotionEvent temp = MotionEvent.obtain(ev); + temp.offsetLocation(ev.getRawX() - ev.getX(), ev.getRawY() - ev.getY()); + boolean scaleDetector = scaleGestureDetector.onTouchEvent(temp); + temp.recycle(); + boolean detector = !scaleGestureDetector.isInProgress() && gestureDetector.onTouchEvent(ev); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + isScrolling = false; + isScrollDisallowed = false; + + if (onSideToDismiss) { + onSideToDismiss = false; + + dimissAndDestroy(); + } else { + if (!pipXSpring.isRunning()) { + pipXSpring.setStartValue(pipX) + .getSpring() + .setFinalPosition(pipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + pipXSpring.start(); + } + + if (!pipYSpring.isRunning()) { + pipYSpring.setStartValue(pipY) + .getSpring() + .setFinalPosition(MathUtils.clamp(pipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - pipHeight - AndroidUtilities.dp(SIDE_PADDING_DP))); + pipYSpring.start(); + } + } + } + return scaleDetector || detector; + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + AndroidUtilities.checkDisplaySize(getContext(), newConfig); + pipConfig = null; + + if (pipWidth != getSuggestedWidth() * scaleFactor || pipHeight != getSuggestedHeight() * scaleFactor) { + windowLayoutParams.width = pipWidth = (int) (getSuggestedWidth() * scaleFactor); + windowLayoutParams.height = pipHeight = (int) (getSuggestedHeight() * scaleFactor); + windowManager.updateViewLayout(contentView, windowLayoutParams); + + pipXSpring.setStartValue(pipX) + .getSpring() + .setFinalPosition(pipX + (getSuggestedWidth() * scaleFactor) / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - (getSuggestedWidth() * scaleFactor) - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + pipXSpring.start(); + + pipYSpring.setStartValue(pipY) + .getSpring() + .setFinalPosition(MathUtils.clamp(pipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - (getSuggestedHeight() * scaleFactor) - AndroidUtilities.dp(SIDE_PADDING_DP))); + pipYSpring.start(); + } + } + + @Override + public void draw(Canvas canvas) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + super.draw(canvas); + } else { + canvas.save(); + canvas.clipPath(path); + super.draw(canvas); + canvas.restore(); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + path.rewind(); + AndroidUtilities.rectTmp.set(0, 0, w, h); + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(ROUNDED_CORNERS_DP), AndroidUtilities.dp(ROUNDED_CORNERS_DP), Path.Direction.CW); + } + }; + contentView = new ViewGroup(context) { + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + contentFrameLayout.layout(0, 0, pipWidth, pipHeight); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); + contentFrameLayout.measure(MeasureSpec.makeMeasureSpec(pipWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(pipHeight, MeasureSpec.EXACTLY)); + } + + @Override + public void draw(Canvas canvas) { + canvas.save(); + canvas.scale(pipWidth / (float)contentFrameLayout.getWidth(), pipHeight / (float)contentFrameLayout.getHeight()); + super.draw(canvas); + canvas.restore(); + } + }; + contentView.addView(contentFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + contentFrameLayout.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), AndroidUtilities.dp(ROUNDED_CORNERS_DP)); + } + }); + contentFrameLayout.setClipToOutline(true); + } + contentFrameLayout.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_actionBar)); + + innerView = pipContentView; + if (innerView.getParent() != null) { + ((ViewGroup)innerView.getParent()).removeView(innerView); + } + contentFrameLayout.addView(innerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + controlsView = new FrameLayout(context); + controlsView.setAlpha(0f); + View scrim = new View(context); + scrim.setBackgroundColor(0x4C000000); + controlsView.addView(scrim, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + int padding = AndroidUtilities.dp(8); + int margin = 4; + int buttonSize = 38; + + ImageView closeButton = new ImageView(context); + closeButton.setImageResource(R.drawable.pip_video_close); + closeButton.setColorFilter(Theme.getColor(Theme.key_voipgroup_actionBarItems), PorterDuff.Mode.MULTIPLY); + closeButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); + closeButton.setPadding(padding, padding, padding, padding); + closeButton.setOnClickListener(v -> dimissAndDestroy()); + controlsView.addView(closeButton, LayoutHelper.createFrame(buttonSize, buttonSize, Gravity.RIGHT, 0, margin, margin, 0)); + + ImageView expandButton = new ImageView(context); + expandButton.setImageResource(R.drawable.pip_video_expand); + expandButton.setColorFilter(Theme.getColor(Theme.key_voipgroup_actionBarItems), PorterDuff.Mode.MULTIPLY); + expandButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); + expandButton.setPadding(padding, padding, padding, padding); + expandButton.setOnClickListener(v -> { + boolean isResumedByActivityManager = true; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ActivityManager activityManager = (ActivityManager) v.getContext().getSystemService(Context.ACTIVITY_SERVICE); + List appProcessInfos = activityManager.getRunningAppProcesses(); + if (!appProcessInfos.isEmpty()) { + isResumedByActivityManager = appProcessInfos.get(0).importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; + } + } + + if (!inAppOnly && (!isResumedByActivityManager || !LaunchActivity.isResumed)) { + LaunchActivity.onResumeStaticCallback = v::callOnClick; + + Context ctx = ApplicationLoader.applicationContext; + Intent intent = new Intent(ctx, LaunchActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + ctx.startActivity(intent); + } else { + if (parentSheet != null) { + parentSheet.exitFromPip(); + } else if (photoViewer != null) { + photoViewer.exitFromPip(); + } + } + }); + controlsView.addView(expandButton, LayoutHelper.createFrame(buttonSize, buttonSize, Gravity.RIGHT, 0, margin, buttonSize + margin + 6, 0)); + + playPauseButton = new ImageView(context); + playPauseButton.setColorFilter(Theme.getColor(Theme.key_voipgroup_actionBarItems), PorterDuff.Mode.MULTIPLY); + playPauseButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); + playPauseButton.setOnClickListener(v -> { + if (photoViewer == null) { + return; + } + VideoPlayer videoPlayer = photoViewer.getVideoPlayer(); + if (videoPlayer == null) { + return; + } + if (videoPlayer.isPlaying()) { + videoPlayer.pause(); + } else { + videoPlayer.play(); + } + updatePlayButton(); + }); + playPauseButton.setVisibility(innerView instanceof WebView ? View.GONE : View.VISIBLE); + controlsView.addView(playPauseButton, LayoutHelper.createFrame(buttonSize, buttonSize, Gravity.CENTER)); + + videoProgressView = new VideoProgressView(context); + controlsView.addView(videoProgressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + contentFrameLayout.addView(controlsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + windowManager = (WindowManager) (inAppOnly ? activity : ApplicationLoader.applicationContext).getSystemService(Context.WINDOW_SERVICE); + + windowLayoutParams = createWindowLayoutParams(inAppOnly); + windowLayoutParams.width = pipWidth; + windowLayoutParams.height = pipHeight; + if (savedPipX != -1) { + windowLayoutParams.x = (int) (pipX = savedPipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + } else { + windowLayoutParams.x = (int) (pipX = AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP)); + } + if (savedPipY != -1) { + windowLayoutParams.y = (int) (pipY = MathUtils.clamp(savedPipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - AndroidUtilities.dp(SIDE_PADDING_DP) - pipHeight)); + } else { + windowLayoutParams.y = (int) (pipY = AndroidUtilities.dp(SIDE_PADDING_DP)); + } + windowLayoutParams.dimAmount = 0f; + windowLayoutParams.flags = FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + + // Animate is a flag for PhotoViewer transition, not ours + if (animate) { + windowManager.addView(contentView, windowLayoutParams); + } else { + contentView.setAlpha(0f); + contentView.setScaleX(0.1f); + contentView.setScaleY(0.1f); + windowManager.addView(contentView, windowLayoutParams); + + AnimatorSet set = new AnimatorSet(); + set.setDuration(250); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + set.playTogether( + ObjectAnimator.ofFloat(contentView, View.ALPHA, 1f), + ObjectAnimator.ofFloat(contentView, View.SCALE_X, 1f), + ObjectAnimator.ofFloat(contentView, View.SCALE_Y, 1f) + ); + set.start(); + } + return true; + } + + @SuppressLint("WrongConstant") + private WindowManager.LayoutParams createWindowLayoutParams(boolean inAppOnly) { + WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(); + windowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT; + windowLayoutParams.format = PixelFormat.TRANSLUCENT; + + if (!inAppOnly && AndroidUtilities.checkInlinePermissions(ApplicationLoader.applicationContext)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + windowLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + } else { + windowLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; + } + } else { + windowLayoutParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; + } + + windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + + return windowLayoutParams; + } + + private final class VideoProgressView extends View { + private Paint progressPaint = new Paint(), bufferPaint = new Paint(); + + public VideoProgressView(Context context) { + super(context); + + progressPaint.setColor(Color.WHITE); + progressPaint.setStyle(Paint.Style.STROKE); + progressPaint.setStrokeCap(Paint.Cap.ROUND); + progressPaint.setStrokeWidth(AndroidUtilities.dp(2)); + bufferPaint.setColor(progressPaint.getColor()); + bufferPaint.setAlpha((int) (progressPaint.getAlpha() * 0.3f)); + bufferPaint.setStyle(Paint.Style.STROKE); + bufferPaint.setStrokeCap(Paint.Cap.ROUND); + bufferPaint.setStrokeWidth(AndroidUtilities.dp(2)); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int width = getWidth(); + + int progressSidePadding = AndroidUtilities.dp(10); + + int progressLeft = progressSidePadding; + int progressRight = progressLeft + (int) ((width - progressLeft - progressSidePadding) * videoProgress); + float y = getHeight() - AndroidUtilities.dp(8); + if (bufferProgress != 0) { + canvas.drawLine(progressLeft, y, progressLeft + (width - progressLeft - progressSidePadding) * bufferProgress, y, bufferPaint); + } + canvas.drawLine(progressLeft, y, progressRight, y, progressPaint); + } + } + + private final static class PipConfig { + private SharedPreferences mPrefs; + + private PipConfig(int width, int height) { + mPrefs = ApplicationLoader.applicationContext.getSharedPreferences("pip_layout_" + width + "_" + height, Context.MODE_PRIVATE); + } + + private void setPipX(float x) { + mPrefs.edit().putFloat("x", x).apply(); + } + + private void setPipY(float y) { + mPrefs.edit().putFloat("y", y).apply(); + } + + private void setScaleFactor(float scaleFactor) { + mPrefs.edit().putFloat("scale_factor", scaleFactor).apply(); + } + + private float getScaleFactor() { + return mPrefs.getFloat("scale_factor", 1f); + } + + private float getPipX() { + return mPrefs.getFloat("x", -1); + } + + private float getPipY() { + return mPrefs.getFloat("y", -1); + } + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupSwipeBackLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupSwipeBackLayout.java index 96b6c14ac..00ff98ead 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupSwipeBackLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupSwipeBackLayout.java @@ -33,7 +33,7 @@ public class PopupSwipeBackLayout extends FrameLayout { private final static int DURATION = 300; SparseIntArray overrideHeightIndex = new SparseIntArray(); - private float transitionProgress; + public float transitionProgress; private float toProgress = -1; private GestureDetectorCompat detector; private boolean isProcessingSwipe; @@ -140,10 +140,7 @@ public class PopupSwipeBackLayout extends FrameLayout { return b; } - /** - * Invalidates transformations - */ - private void invalidateTransforms() { + public void invalidateTransforms() { if (!onSwipeBackProgressListeners.isEmpty()) { for (int i = 0; i < onSwipeBackProgressListeners.size(); i++) { @@ -151,28 +148,28 @@ public class PopupSwipeBackLayout extends FrameLayout { } } - View bg = getChildAt(0); - View fg = null; + View backgroundView = getChildAt(0); + View foregroundView = null; if (currentForegroundIndex >= 0 && currentForegroundIndex < getChildCount()) { - fg = getChildAt(currentForegroundIndex); + foregroundView = getChildAt(currentForegroundIndex); } - bg.setTranslationX(-transitionProgress * getWidth() * 0.5f); + backgroundView.setTranslationX(-transitionProgress * getWidth() * 0.5f); float bSc = 0.95f + (1f - transitionProgress) * 0.05f; - bg.setScaleX(bSc); - bg.setScaleY(bSc); - if (fg != null) { - fg.setTranslationX((1f - transitionProgress) * getWidth()); + backgroundView.setScaleX(bSc); + backgroundView.setScaleY(bSc); + if (foregroundView != null) { + foregroundView.setTranslationX((1f - transitionProgress) * getWidth()); } invalidateVisibility(); - float fW = bg.getMeasuredWidth(), fH = bg.getMeasuredHeight(); + float fW = backgroundView.getMeasuredWidth(), fH = backgroundView.getMeasuredHeight(); float tW = 0; float tH = 0; - if (fg != null) { - tW = fg.getMeasuredWidth(); - tH = overrideForegroundHeight != 0 ? overrideForegroundHeight : fg.getMeasuredHeight(); + if (foregroundView != null) { + tW = foregroundView.getMeasuredWidth(); + tH = overrideForegroundHeight != 0 ? overrideForegroundHeight : foregroundView.getMeasuredHeight(); } - if (bg.getMeasuredWidth() == 0 || bg.getMeasuredHeight() == 0) { + if (backgroundView.getMeasuredWidth() == 0 || backgroundView.getMeasuredHeight() == 0) { return; } @@ -181,8 +178,10 @@ public class PopupSwipeBackLayout extends FrameLayout { float h = fH + (tH - fH) * transitionProgress; w += p.getPaddingLeft() + p.getPaddingRight(); h += p.getPaddingTop() + p.getPaddingBottom(); + p.updateAnimation = false; p.setBackScaleX(w / p.getMeasuredWidth()); p.setBackScaleY(h / p.getMeasuredHeight()); + p.updateAnimation = true; for (int i = 0; i < getChildCount(); i++) { View ch = getChildAt(i); @@ -304,12 +303,20 @@ public class PopupSwipeBackLayout extends FrameLayout { animateToState(1, 0); } - /** - * Closes foreground view - */ public void closeForeground() { + closeForeground(true); + } + + public void closeForeground(boolean animated) { if (isAnimationInProgress) return; - animateToState(0, 0); + if (!animated) { + currentForegroundIndex = -1; + transitionProgress = 0; + invalidateTransforms(); + return; + } else { + animateToState(0, 0); + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java index 799bed639..90ec9dd18 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java @@ -35,6 +35,7 @@ import org.telegram.ui.ActionBar.Theme; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; public class ReactedUsersListView extends FrameLayout { @@ -190,7 +191,7 @@ public class ReactedUsersListView extends FrameLayout { } if (onlySeenNow) { - Collections.sort(userReactions, (o1, o2) -> Integer.compare(o1.reaction != null ? 1 : 0, o2.reaction != null ? 1 : 0)); + Collections.sort(userReactions, Comparator.comparingInt(o -> o.reaction != null ? 0 : 1)); } if (onlySeenNow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java index f1136a8df..65e95d52c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -110,6 +110,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio private float pressedViewScale; private float otherViewsScale; private boolean clicked; + long lastReactionSentTime; public ReactionsContainerLayout(@NonNull Context context, int currentAccount, Theme.ResourcesProvider resourcesProvider) { super(context); @@ -299,7 +300,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio canvas.scale(sc, sc, pivotX, getHeight() / 2f); } - if (transitionProgress != 0) { + if (transitionProgress != 0 && getAlpha() == 1f) { int delay = 0; for (int i = 0; i < recyclerListView.getChildCount(); i++) { ReactionHolderView view = (ReactionHolderView) recyclerListView.getChildAt(i); @@ -352,6 +353,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio canvas.restore(); } + private void checkPressedProgress(Canvas canvas, ReactionHolderView view) { if (view.currentReaction.reaction.equals(pressedReaction)) { view.setPivotX(view.getMeasuredWidth() >> 1); @@ -372,16 +374,19 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } if (pressedProgress == 1f) { clicked = true; - delegate.onReactionClicked(view, view.currentReaction, true); + if (System.currentTimeMillis() - lastReactionSentTime > 300) { + lastReactionSentTime = System.currentTimeMillis(); + delegate.onReactionClicked(view, view.currentReaction, true); + } } } canvas.save(); float x = recyclerListView.getX() + view.getX(); float additionalWidth = (view.getMeasuredWidth() * view.getScaleX() - view.getMeasuredWidth()) / 2f; - if (x - additionalWidth < 0) { + if (x - additionalWidth < 0 && view.getTranslationX() >= 0) { view.setTranslationX(-(x - additionalWidth)); - } else if (x + view.getMeasuredWidth() + additionalWidth > getMeasuredWidth()) { + } else if (x + view.getMeasuredWidth() + additionalWidth > getMeasuredWidth() && view.getTranslationX() <= 0) { view.setTranslationX(getMeasuredWidth() - x - view.getMeasuredWidth() - additionalWidth); } else { view.setTranslationX(0); @@ -653,7 +658,11 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio if (cancelByMove || event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { if (event.getAction() == MotionEvent.ACTION_UP && pressed && (pressedReaction == null || pressedProgress > 0.8f) && delegate != null) { clicked = true; - delegate.onReactionClicked(this, currentReaction, pressedProgress > 0.8f); + if (System.currentTimeMillis() - lastReactionSentTime > 300) { + lastReactionSentTime = System.currentTimeMillis(); + delegate.onReactionClicked(this, currentReaction, pressedProgress > 0.8f); + } + } if (!clicked) { cancelPressed(); @@ -723,4 +732,15 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } } + @Override + public void setAlpha(float alpha) { + if (getAlpha() != alpha && alpha == 0) { + lastVisibleViews.clear(); + for (int i = 0; i < recyclerListView.getChildCount(); i++) { + ReactionHolderView view = (ReactionHolderView) recyclerListView.getChildAt(i); + view.resetAnimation(); + } + } + super.setAlpha(alpha); + } } \ No newline at end of file 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 8d4c3aaf3..6c0ca8d2b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java @@ -1243,13 +1243,20 @@ public class RecyclerListView extends RecyclerView { interceptedByChild = false; } + private boolean resetSelectorOnChanged = true; + public void setResetSelectorOnChanged(boolean value) { + resetSelectorOnChanged = value; + } + private AdapterDataObserver observer = new AdapterDataObserver() { @Override public void onChanged() { checkIfEmpty(true); - currentFirst = -1; - if (removeHighlighSelectionRunnable == null) { - selectorRect.setEmpty(); + if (resetSelectorOnChanged) { + currentFirst = -1; + if (removeHighlighSelectionRunnable == null) { + selectorRect.setEmpty(); + } } invalidate(); } @@ -1418,7 +1425,9 @@ public class RecyclerListView extends RecyclerView { if (selectorDrawable != null) { selectorDrawable.setCallback(null); } - if (topBottomSelectorRadius > 0) { + if (selectorType == 8) { + selectorDrawable = Theme.createRadSelectorDrawable(color, selectorRadius, 0); + } else if (topBottomSelectorRadius > 0) { selectorDrawable = Theme.createRadSelectorDrawable(color, topBottomSelectorRadius, topBottomSelectorRadius); } else if (selectorRadius > 0) { selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(selectorRadius, 0, color, 0xff000000); @@ -1972,7 +1981,9 @@ public class RecyclerListView extends RecyclerView { if (position != NO_POSITION) { selectorPosition = position; } - if (topBottomSelectorRadius > 0 && getAdapter() != null) { + if (selectorType == 8) { + Theme.setMaskDrawableRad(selectorDrawable, selectorRadius, 0); + } else if (topBottomSelectorRadius > 0 && getAdapter() != null) { Theme.setMaskDrawableRad(selectorDrawable, position == 0 ? topBottomSelectorRadius : 0, position == getAdapter().getItemCount() - 2 ? topBottomSelectorRadius : 0); } selectorRect.set(sel.getLeft(), sel.getTop(), sel.getRight(), sel.getBottom() - bottomPadding); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java index caa892aa4..d761f4626 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.text.SpannableStringBuilder; +import android.text.TextUtils; import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; @@ -185,12 +186,15 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie } public void onTextChanged(String text) { - lastSearchString = text; View view = getCurrentView(); boolean reset = false; if (!attached) { reset = true; } + if (TextUtils.isEmpty(lastSearchString)) { + reset = true; + } + lastSearchString = text; search(view, getCurrentPosition(), text, reset); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectPopup.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectPopup.java index a335d834d..36292bae2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectPopup.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectPopup.java @@ -12,6 +12,7 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; @@ -65,6 +66,7 @@ public class SenderSelectPopup extends ActionBarPopupWindow { private boolean clicked; protected List springAnimations = new ArrayList<>(); + private boolean dismissed; public SenderSelectPopup(Context context, ChatActivity parentFragment, MessagesController messagesController, TLRPC.ChatFull chatFull, TLRPC.TL_channels_sendAsPeers sendAsPeers, OnSelectCallback selectCallback) { super(context); @@ -76,6 +78,9 @@ public class SenderSelectPopup extends ActionBarPopupWindow { scrimPopupContainerLayout.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); setContentView(scrimPopupContainerLayout); + setWidth(WindowManager.LayoutParams.WRAP_CONTENT); + setHeight(WindowManager.LayoutParams.WRAP_CONTENT); + setBackgroundDrawable(null); Drawable shadowDrawable = ContextCompat.getDrawable(context, R.drawable.popup_fixed_alert).mutate(); @@ -198,6 +203,15 @@ public class SenderSelectPopup extends ActionBarPopupWindow { scrimPopupContainerLayout.addView(recyclerContainer); } + @Override + public void dismiss() { + if (dismissed) { + return; + } + dismissed = true; + super.dismiss(); + } + public void startShowAnimation() { for (SpringAnimation springAnimation : springAnimations) { springAnimation.cancel(); 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 63b7cbc78..2f001df6e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -3973,10 +3973,12 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (child instanceof SharedDocumentCell) { SharedDocumentCell cell = (SharedDocumentCell) child; messageId = cell.getMessage().getId(); + offset = cell.getTop(); } if (child instanceof SharedAudioCell) { SharedAudioCell cell = (SharedAudioCell) child; messageId = cell.getMessage().getId(); + offset = cell.getTop(); } if (messageId != 0) { break; @@ -5118,8 +5120,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public void getPositionForScrollProgress(RecyclerListView listView, float progress, int[] position) { int viewHeight = listView.getChildAt(0).getMeasuredHeight(); int totalHeight = (int) getTotalItemsCount() * viewHeight; - position[0] = (int) ((progress * (totalHeight - listView.getMeasuredHeight())) / viewHeight); - position[1] = (int) (progress * (totalHeight - listView.getMeasuredHeight())) % viewHeight; + int listViewHeight = listView.getMeasuredHeight() - listView.getPaddingTop(); + position[0] = (int) ((progress * (totalHeight - listViewHeight)) / viewHeight); + position[1] = (int) (progress * (totalHeight - listViewHeight)) % viewHeight; } @Override @@ -5402,8 +5405,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public void getPositionForScrollProgress(RecyclerListView listView, float progress, int[] position) { int viewHeight = listView.getChildAt(0).getMeasuredHeight(); int totalHeight = (int) (Math.ceil(getTotalItemsCount() / (float) mediaColumnsCount) * viewHeight); - position[0] = (int) ((progress * (totalHeight - listView.getMeasuredHeight())) / viewHeight) * mediaColumnsCount; - position[1] = (int) (progress * (totalHeight - listView.getMeasuredHeight())) % viewHeight; + int listHeight = listView.getMeasuredHeight() - listView.getPaddingTop(); + position[0] = (int) ((progress * (totalHeight -listHeight)) / viewHeight) * mediaColumnsCount; + position[1] = (int) (progress * (totalHeight - listHeight)) % viewHeight; } @Override @@ -5456,8 +5460,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (firstPosition < 0) { return 0; } - float scrollY = (firstPosition / parentCount) * cellHeight - firstChild.getTop(); - return scrollY / (((float) cellCount) * cellHeight - listView.getMeasuredHeight()); + float childTop = firstChild.getTop() - listView.getPaddingTop(); + float listH = listView.getMeasuredHeight() - listView.getPaddingTop(); + float scrollY = (firstPosition / parentCount) * cellHeight - childTop; + return scrollY / (((float) cellCount) * cellHeight - listH); } public boolean fastScrollIsVisible(RecyclerListView listView) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleFloatPropertyCompat.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleFloatPropertyCompat.java index 27d6881b7..91c869e00 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleFloatPropertyCompat.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleFloatPropertyCompat.java @@ -18,6 +18,10 @@ public class SimpleFloatPropertyCompat extends FloatPropertyCompat { return this; } + public float getMultiplier() { + return multiplier; + } + @Override public float getValue(T object) { return getter.get(object) * multiplier; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java index b859725a8..3434c3d4f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java @@ -50,6 +50,10 @@ public class SizeNotifierFrameLayoutPhoto extends FrameLayout { } public int getKeyboardHeight() { + return keyboardHeight; + } + + public int measureKeyboardHeight() { View rootView = getRootView(); getWindowVisibleDisplayFrame(rect); if (withoutWindow) { @@ -66,7 +70,7 @@ public class SizeNotifierFrameLayoutPhoto extends FrameLayout { public void notifyHeightChanged() { if (delegate != null) { - keyboardHeight = getKeyboardHeight(); + keyboardHeight = measureKeyboardHeight(); final boolean isWidthGreater = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y; post(() -> { if (delegate != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TableLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TableLayout.java index abaec1605..0bd7b37f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TableLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TableLayout.java @@ -192,7 +192,7 @@ public class TableLayout extends View { } } - public void draw(Canvas canvas) { + public void draw(Canvas canvas, View view) { if (cell == null) { return; } @@ -249,7 +249,7 @@ public class TableLayout extends View { if (selectionIndex >= 0) { textSelectionHelper.draw(canvas, (TextSelectionHelper.ArticleSelectableView) getParent().getParent(), selectionIndex); } - textLayout.draw(canvas); + textLayout.draw(canvas, view); canvas.restore(); } if (drawLines) { @@ -705,7 +705,7 @@ public class TableLayout extends View { protected void onDraw(Canvas canvas) { for (int i = 0, N = getChildCount(); i < N; i++) { Child c = getChildAt(i); - c.draw(canvas); + c.draw(canvas, this); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerDrawable.java index 75d7b95cb..e2f95ab66 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerDrawable.java @@ -13,12 +13,17 @@ import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; +import androidx.core.content.ContextCompat; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; @@ -32,64 +37,94 @@ public class TimerDrawable extends Drawable { private StaticLayout timeLayout; private float timeWidth = 0; private int timeHeight = 0; - private int time = 0; + private int time = -1; + private Drawable currentTtlIcon; + private int iconColor; + private int currentTtlIconId; + Context context; + Theme.ResourcesProvider resourcesProvider; + private boolean overrideColor; + private boolean isStaticIcon; - public TimerDrawable(Context context) { - timePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - timePaint.setTextSize(AndroidUtilities.dp(11)); + public TimerDrawable(Context context, Theme.ResourcesProvider resourcesProvider) { + this.context = context; + this.resourcesProvider = resourcesProvider; + timePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rcondensedbold.ttf")); linePaint.setStrokeWidth(AndroidUtilities.dp(1)); linePaint.setStyle(Paint.Style.STROKE); } public void setTime(int value) { - time = value; + if (time != value) { + time = value; - String timeString; - if (time >= 1 && time < 60) { - timeString = "" + value; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerSeconds", R.string.SecretChatTimerSeconds); + currentTtlIcon = ContextCompat.getDrawable(context, time == 0 ? R.drawable.msg_mini_autodelete : R.drawable.msg_mini_autodelete_empty).mutate(); + currentTtlIcon.setColorFilter(currentColorFilter); + invalidateSelf(); + + String timeString; + if (time >= 1 && time < 60) { + timeString = "" + value; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerSeconds", R.string.SecretChatTimerSeconds); + } + } else if (time >= 60 && time < 60 * 60) { + timeString = "" + value / 60; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerMinutes", R.string.SecretChatTimerMinutes); + } + } else if (time >= 60 * 60 && time < 60 * 60 * 24) { + timeString = "" + value / 60 / 60; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours); + } + } else if (time >= 60 * 60 * 24 && time < 60 * 60 * 24 * 7) { + timeString = "" + value / 60 / 60 / 24; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays); + } + } else if (time < 60 * 60 * 24 * 31) { + timeString = "" + value / 60 / 60 / 24 / 7; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerWeeks", R.string.SecretChatTimerWeeks); + } else if (timeString.length() > 2) { + timeString = "c"; + } + } else { + timeString = "" + value / 60 / 60 / 24 / 30; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerMonths", R.string.SecretChatTimerMonths); + } } - } else if (time >= 60 && time < 60 * 60) { - timeString = "" + value / 60; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerMinutes", R.string.SecretChatTimerMinutes); + + timePaint.setTextSize(AndroidUtilities.dp(11)); + timeWidth = timePaint.measureText(timeString); + if (timeWidth > AndroidUtilities.dp(13)) { + timePaint.setTextSize(AndroidUtilities.dp(9)); + timeWidth = timePaint.measureText(timeString); } - } else if (time >= 60 * 60 && time < 60 * 60 * 24) { - timeString = "" + value / 60 / 60; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours); + if (timeWidth > AndroidUtilities.dp(13)) { + timePaint.setTextSize(AndroidUtilities.dp(6)); + timeWidth = timePaint.measureText(timeString); } - } else if (time >= 60 * 60 * 24 && time < 60 * 60 * 24 * 7) { - timeString = "" + value / 60 / 60 / 24; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays); - } - } else if (time >= 30 * 60 * 60 * 24 && time <= 60 * 60 * 24 * 31) { - timeString = "" + value / 60 / 60 / 24 / 30; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerMonths", R.string.SecretChatTimerMonths); - } - } else { - timeString = "" + value / 60 / 60 / 24 / 7; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerWeeks", R.string.SecretChatTimerWeeks); - } else if (timeString.length() > 2) { - timeString = "c"; + try { + timeLayout = new StaticLayout(timeString, timePaint, (int) Math.ceil(timeWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + timeHeight = timeLayout.getHeight(); + } catch (Exception e) { + timeLayout = null; + FileLog.e(e); } + + invalidateSelf(); } + } - timeWidth = timePaint.measureText(timeString); - try { - timeLayout = new StaticLayout(timeString, timePaint, (int)Math.ceil(timeWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - timeHeight = timeLayout.getHeight(); - } catch (Exception e) { - timeLayout = null; - FileLog.e(e); - } - - invalidateSelf(); + public static TimerDrawable getTtlIcon(int ttl) { + TimerDrawable timerDrawable = new TimerDrawable(ApplicationLoader.applicationContext, null); + timerDrawable.setTime(ttl); + timerDrawable.isStaticIcon = true; + return timerDrawable; } @Override @@ -97,32 +132,38 @@ public class TimerDrawable extends Drawable { int width = getIntrinsicWidth(); int height = getIntrinsicHeight(); - - if (time == 0) { - paint.setColor(Theme.getColor(Theme.key_chat_secretTimerBackground)); - linePaint.setColor(Theme.getColor(Theme.key_chat_secretTimerText)); - - canvas.drawCircle(AndroidUtilities.dpf2(9), AndroidUtilities.dpf2(9), AndroidUtilities.dpf2(7.5f), paint); - canvas.drawCircle(AndroidUtilities.dpf2(9), AndroidUtilities.dpf2(9), AndroidUtilities.dpf2(8), linePaint); - - paint.setColor(Theme.getColor(Theme.key_chat_secretTimerText)); - canvas.drawLine(AndroidUtilities.dp(9), AndroidUtilities.dp(9), AndroidUtilities.dp(13), AndroidUtilities.dp(9), linePaint); - canvas.drawLine(AndroidUtilities.dp(9), AndroidUtilities.dp(5), AndroidUtilities.dp(9), AndroidUtilities.dp(9.5f), linePaint); - - canvas.drawRect(AndroidUtilities.dpf2(7), AndroidUtilities.dpf2(0), AndroidUtilities.dpf2(11), AndroidUtilities.dpf2(1.5f), paint); + if (!isStaticIcon) { + if (!overrideColor) { + paint.setColor(Theme.getColor(Theme.key_actionBarDefault, resourcesProvider)); + } + timePaint.setColor(Theme.getColor(Theme.key_actionBarDefaultTitle, resourcesProvider)); } else { - paint.setColor(Theme.getColor(Theme.key_chat_secretTimerBackground)); - timePaint.setColor(Theme.getColor(Theme.key_chat_secretTimerText)); - canvas.drawCircle(AndroidUtilities.dp(9.5f), AndroidUtilities.dp(9.5f), AndroidUtilities.dp(9.5f), paint); + timePaint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon, resourcesProvider)); } - if (time != 0 && timeLayout != null) { - int xOffxet = 0; - if (AndroidUtilities.density == 3) { - xOffxet = -1; + if (currentTtlIcon != null) { + if (!isStaticIcon) { + canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), getBounds().width() / 2f, paint); + int iconColor = Theme.getColor(Theme.key_actionBarDefaultTitle, resourcesProvider); + if (this.iconColor != iconColor) { + this.iconColor = iconColor; + currentTtlIcon.setColorFilter(new PorterDuffColorFilter(iconColor, PorterDuff.Mode.MULTIPLY)); + } + } + AndroidUtilities.rectTmp2.set(getBounds()); + AndroidUtilities.rectTmp2.inset(AndroidUtilities.dp(1f), AndroidUtilities.dp(1f)); + currentTtlIcon.setBounds(AndroidUtilities.rectTmp2); + currentTtlIcon.draw(canvas); + } + if (time != 0) { + if (timeLayout != null) { + int xOffxet = 0; + if (AndroidUtilities.density == 3) { + xOffxet = -1; + } + canvas.translate((int) (width / 2 - Math.ceil(timeWidth / 2)) + xOffxet, (height - timeHeight) / 2); + timeLayout.draw(canvas); } - canvas.translate((int)(width / 2 - Math.ceil(timeWidth / 2)) + xOffxet, (height - timeHeight) / 2); - timeLayout.draw(canvas); } } @@ -131,9 +172,13 @@ public class TimerDrawable extends Drawable { } + ColorFilter currentColorFilter; @Override public void setColorFilter(ColorFilter cf) { - + currentColorFilter = cf; + if (isStaticIcon) { + currentTtlIcon.setColorFilter(cf); + } } @Override @@ -143,11 +188,16 @@ public class TimerDrawable extends Drawable { @Override public int getIntrinsicWidth() { - return AndroidUtilities.dp(19); + return AndroidUtilities.dp(23); } @Override public int getIntrinsicHeight() { - return AndroidUtilities.dp(19); + return AndroidUtilities.dp(23); + } + + public void setBackgroundColor(int currentActionBarColor) { + overrideColor = true; + paint.setColor(currentActionBarColor); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java index f67036850..3be2543f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java @@ -459,32 +459,12 @@ public class TranslateAlert extends Dialog { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MOST_SPEC); } - private Paint pressedLinkPaint = null; - private Path pressedLinkPath = new Path() { - private RectF rectF = new RectF(); - @Override - public void addRect(float left, float top, float right, float bottom, @NonNull Direction dir) { - rectF.set(left - LoadingTextView2.paddingHorizontal / 2, top - LoadingTextView2.paddingVertical, right + LoadingTextView2.paddingHorizontal / 2, bottom + LoadingTextView2.paddingVertical); - addRoundRect(rectF, dp(4), dp(4), Direction.CW); - } - }; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(getPaddingLeft(), getPaddingTop()); - if (pressedLink != null) { - try { - Layout layout = getLayout(); - int start = allTexts.getSpanStart(pressedLink); - int end = allTexts.getSpanEnd(pressedLink); - layout.getSelectionPath(start, end, pressedLinkPath); - - if (pressedLinkPaint == null) { - pressedLinkPaint = new Paint(); - pressedLinkPaint.setColor(Theme.getColor(Theme.key_chat_linkSelectBackground)); - } - canvas.drawPath(pressedLinkPath, pressedLinkPaint); - } catch (Exception e) { } + if (links != null && links.draw(canvas)) { + invalidate(); } } @Override @@ -502,10 +482,12 @@ public class TranslateAlert extends Dialog { BulletinFactory.of(bulletinContainer, null).createCopyBulletin(LocaleController.getString("TextCopied", R.string.TextCopied)).show(); clearFocus(); return true; - } else + } else { return super.onTextContextMenuItem(id); + } } }; + links = new LinkSpanDrawable.LinkCollector(allTextsView); allTextsView.setTextColor(0x00000000); allTextsView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); allTextsView.setTextIsSelectable(!noforwards); @@ -621,7 +603,9 @@ public class TranslateAlert extends Dialog { private boolean fromTranslateMoreView = false; private float fromScrollViewY = 0; private Spannable allTexts = null; - private ClickableSpan pressedLink; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links; + @Override public boolean dispatchTouchEvent(@NonNull MotionEvent event) { try { @@ -647,20 +631,31 @@ public class TranslateAlert extends Dialog { if (textRect.contains((int) x, (int) y) && !maybeScrolling) { Layout allTextsLayout = allTextsView.getLayout(); int tx = (int) (x - allTextsView.getLeft() - container.getLeft()), - ty = (int) (y - allTextsView.getTop() - container.getTop() - scrollView.getTop() + scrollView.getScrollY()); + ty = (int) (y - allTextsView.getTop() - container.getTop() - scrollView.getTop() + scrollView.getScrollY()); final int line = allTextsLayout.getLineForVertical(ty); final int off = allTextsLayout.getOffsetForHorizontal(line, tx); final float left = allTextsLayout.getLineLeft(line); - if (allTexts != null && allTexts instanceof Spannable && left <= tx && left + allTextsLayout.getLineWidth(line) >= tx) { - ClickableSpan[] links = allTexts.getSpans(off, off, ClickableSpan.class); - if (links != null && links.length >= 1) { - if (event.getAction() == MotionEvent.ACTION_UP && pressedLink == links[0]) { - pressedLink.onClick(allTextsView); + if (allTexts instanceof Spannable && left <= tx && left + allTextsLayout.getLineWidth(line) >= tx) { + ClickableSpan[] linkSpans = allTexts.getSpans(off, off, ClickableSpan.class); + if (linkSpans != null && linkSpans.length >= 1) { + if (event.getAction() == MotionEvent.ACTION_UP && pressedLink.getSpan() == linkSpans[0]) { + ((ClickableSpan) pressedLink.getSpan()).onClick(allTextsView); + if (links != null) { + links.removeLink(pressedLink); + } pressedLink = null; allTextsView.setTextIsSelectable(!noforwards); } else if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressedLink = links[0]; + pressedLink = new LinkSpanDrawable(linkSpans[0], fragment.getResourceProvider(), tx, ty, false); + if (links != null) { + links.addLink(pressedLink); + } + LinkPath path = pressedLink.obtainNewPath(); + int start = allTexts.getSpanStart(pressedLink.getSpan()); + int end = allTexts.getSpanEnd(pressedLink.getSpan()); + path.setCurrentLayout(allTextsLayout, start, 0); + allTextsLayout.getSelectionPath(start, end, path); } allTextsView.invalidate(); return true; @@ -668,7 +663,9 @@ public class TranslateAlert extends Dialog { } } if (pressedLink != null) { - allTextsView.invalidate(); + if (links != null) { + links.clear(); + } pressedLink = null; } } catch (Exception e2) { @@ -904,6 +901,7 @@ public class TranslateAlert extends Dialog { if (n == -1) n = maxBlockStr.lastIndexOf("\n\n"); if (n == -1) n = maxBlockStr.lastIndexOf("\n"); if (n == -1) n = maxBlockStr.lastIndexOf(". "); + if (n == -1) n = Math.min(maxBlockStr.length(), maxBlockSize); blocks.add(full.subSequence(0, n + 1)); full = full.subSequence(n + 1, full.length()); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java index d891fb588..0bd1c0d0a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java @@ -18,6 +18,7 @@ import org.telegram.tgnet.TLObject; public class URLSpanNoUnderline extends URLSpan { + private boolean forceNoUnderline = false; private TextStyleSpan.TextStyleRun style; private TLObject object; @@ -25,6 +26,11 @@ public class URLSpanNoUnderline extends URLSpan { this(url, null); } + public URLSpanNoUnderline(String url, boolean forceNoUnderline) { + this(url, null); + this.forceNoUnderline = forceNoUnderline; + } + public URLSpanNoUnderline(String url, TextStyleSpan.TextStyleRun run) { super(url != null ? url.replace('\u202E', ' ') : url); style = run; @@ -49,7 +55,7 @@ public class URLSpanNoUnderline extends URLSpan { if (style != null) { style.applyStyle(p); } - p.setUnderlineText(l == c); + p.setUnderlineText(l == c && !forceNoUnderline); } public void setObject(TLObject spanObject) { 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 f339afbee..a7872f174 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -176,6 +176,7 @@ public class UndoView extends FrameLayout { public final static int ACTION_CLEAR_DATES = 81; public final static int ACTION_PREVIEW_MEDIA_DESELECTED = 82; + public static int ACTION_RINGTONE_ADDED = 83; private CharSequence infoText; private int hideAnimationType = 1; @@ -327,17 +328,18 @@ public class UndoView extends FrameLayout { 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_PAYMENT_SUCCESS || currentAction == ACTION_VOIP_USER_JOINED || currentAction == ACTION_PIN_DIALOGS || currentAction == ACTION_UNPIN_DIALOGS || currentAction == ACTION_VOIP_VIDEO_RECORDING_STARTED || - currentAction == ACTION_VOIP_VIDEO_RECORDING_FINISHED; + currentAction == ACTION_VOIP_VIDEO_RECORDING_FINISHED || currentAction == ACTION_RINGTONE_ADDED; } private boolean hasSubInfo() { return currentAction == ACTION_QR_SESSION_ACCEPTED || currentAction == ACTION_PROXIMITY_SET || currentAction == ACTION_ARCHIVE_HIDDEN || currentAction == ACTION_ARCHIVE_HINT || currentAction == ACTION_ARCHIVE_FEW_HINT || currentAction == ACTION_QUIZ_CORRECT || currentAction == ACTION_QUIZ_INCORRECT || - currentAction == ACTION_REPORT_SENT || currentAction == ACTION_ARCHIVE_PINNED && MessagesController.getInstance(currentAccount).dialogFilters.isEmpty(); + currentAction == ACTION_REPORT_SENT || currentAction == ACTION_ARCHIVE_PINNED && MessagesController.getInstance(currentAccount).dialogFilters.isEmpty() || currentAction == ACTION_RINGTONE_ADDED; } public boolean isMultilineSubInfo() { - return currentAction == ACTION_THEME_CHANGED || currentAction == ACTION_FILTERS_AVAILABLE || currentAction == ACTION_PROXIMITY_SET || currentAction == ACTION_REPORT_SENT; + return currentAction == ACTION_THEME_CHANGED || currentAction == ACTION_FILTERS_AVAILABLE || currentAction == ACTION_PROXIMITY_SET || currentAction == ACTION_REPORT_SENT + || currentAction == ACTION_RINGTONE_ADDED; } public void setAdditionalTranslationY(float value) { @@ -436,7 +438,7 @@ public class UndoView extends FrameLayout { } public void showWithAction(ArrayList dialogIds, int action, Object infoObject, Object infoObject2, Runnable actionRunnable, Runnable cancelRunnable) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && currentAction == ACTION_MESSAGE_COPIED || currentAction == ACTION_USERNAME_COPIED || currentAction == ACTION_HASHTAG_COPIED || currentAction == ACTION_TEXT_COPIED || currentAction == ACTION_LINK_COPIED || currentAction == ACTION_PHONE_COPIED || currentAction == ACTION_EMAIL_COPIED || currentAction == ACTION_VOIP_LINK_COPIED) { + if (!AndroidUtilities.shouldShowClipboardToast() && currentAction == ACTION_MESSAGE_COPIED || currentAction == ACTION_USERNAME_COPIED || currentAction == ACTION_HASHTAG_COPIED || currentAction == ACTION_TEXT_COPIED || currentAction == ACTION_LINK_COPIED || currentAction == ACTION_PHONE_COPIED || currentAction == ACTION_EMAIL_COPIED || currentAction == ACTION_VOIP_LINK_COPIED) { return; } if (currentActionRunnable != null) { @@ -475,7 +477,7 @@ public class UndoView extends FrameLayout { boolean infoOnly = false; boolean reversedPlay = false; int reversedPlayEndFrame = 0; - if (actionRunnable == null && cancelRunnable == null) { + if ((actionRunnable == null && cancelRunnable == null) || action == ACTION_RINGTONE_ADDED) { setOnClickListener(view -> hide(false, 1)); setOnTouchListener(null); } else { @@ -487,12 +489,19 @@ public class UndoView extends FrameLayout { if (isTooltipAction()) { CharSequence infoText; - String subInfoText; + CharSequence subInfoText; int icon; int size = 36; boolean iconIsDrawable = false; - if (action == ACTION_REPORT_SENT) { + if (action == ACTION_RINGTONE_ADDED) { + subinfoTextView.setSingleLine(false); + infoText = LocaleController.getString("SoundAdded", R.string.SoundAdded); + subInfoText = AndroidUtilities.replaceSingleTag(LocaleController.getString("SoundAddedSubtitle", R.string.SoundAddedSubtitle), actionRunnable); + currentActionRunnable = null; + icon = R.raw.sound_download; + timeLeft = 4000; + } else if (action == ACTION_REPORT_SENT) { subinfoTextView.setSingleLine(false); infoText = LocaleController.getString("ReportChatSent", R.string.ReportChatSent); subInfoText = LocaleController.formatString("ReportSentInfo", R.string.ReportSentInfo); @@ -906,19 +915,8 @@ public class UndoView extends FrameLayout { } else if (action == ACTION_AUTO_DELETE_ON) { TLRPC.User user = (TLRPC.User) infoObject; int ttl = (Integer) infoObject2; - String time; subinfoTextView.setSingleLine(false); - if (ttl >= 30 * 24 * 60 * 60) { - time = LocaleController.formatPluralString("Months", ttl / (30 * 24 * 60 * 60)); - } else if (ttl > 24 * 60 * 60) { - time = LocaleController.formatPluralString("Days", ttl / (24 * 60 * 60)); - } else if (ttl >= 60 * 60) { - time = LocaleController.formatPluralString("Hours", ttl / (60 * 60)); - } else if (ttl >= 60) { - time = LocaleController.formatPluralString("Minutes", ttl / 60); - } else { - time = LocaleController.formatPluralString("Seconds", ttl); - } + String time = LocaleController.formatTTLString(ttl); infoTextView.setText(LocaleController.formatString("AutoDeleteHintOnText", R.string.AutoDeleteHintOnText, time)); leftImageView.setAnimation(R.raw.fire_on, 36, 36); layoutParams.topMargin = AndroidUtilities.dp(9); @@ -961,7 +959,7 @@ public class UndoView extends FrameLayout { timeLeft = 3000; infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); } else if (currentAction == ACTION_MESSAGE_COPIED || currentAction == ACTION_USERNAME_COPIED || currentAction == ACTION_HASHTAG_COPIED || currentAction == ACTION_TEXT_COPIED || currentAction == ACTION_LINK_COPIED || currentAction == ACTION_PHONE_COPIED || currentAction == ACTION_EMAIL_COPIED) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (!AndroidUtilities.shouldShowClipboardToast()) { return; } int iconRawId = R.raw.copy; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java index 0c94a4d01..8649537da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java @@ -70,7 +70,6 @@ import java.net.URLConnection; import java.net.URLDecoder; import java.net.URLEncoder; import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; @@ -84,7 +83,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD public interface WebPlayerViewDelegate { void onInitFailed(); TextureView onSwitchToFullscreen(View controlsView, boolean fullscreen, float aspectRatio, int rotation, boolean byButton); - TextureView onSwitchInlineMode(View controlsView, boolean inline, float aspectRatio, int rotation, boolean animated); + TextureView onSwitchInlineMode(View controlsView, boolean inline, int width, int height, int rotation, boolean animated); void onInlineSurfaceTextureReady(); void prepareToSwitchInlineMode(boolean inline, Runnable switchInlineModeRunnable, float aspectRatio, boolean animated); void onSharePressed(); @@ -156,6 +155,8 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD private ControlsView controlsView; + private int videoWidth, videoHeight; + private Runnable progressRunnable = new Runnable() { @Override public void run() { @@ -552,7 +553,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD if (result == null) { result = new StringBuilder(); } - result.append(new String(data, 0, read, StandardCharsets.UTF_8)); + result.append(new String(data, 0, read, "UTF-8")); } else if (read == -1) { done = true; break; @@ -799,7 +800,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } else { try { String javascript = ""; - byte[] data = javascript.getBytes(StandardCharsets.UTF_8); + byte[] data = javascript.getBytes("UTF-8"); final String base64 = Base64.encodeToString(data, Base64.DEFAULT); webView.loadUrl("data:text/html;charset=utf-8;base64," + base64); } catch (Exception e) { @@ -1094,7 +1095,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD source.setCharAt(a, c == lower ? Character.toUpperCase(c) : lower); } try { - return new String(Base64.decode(source.toString(), Base64.DEFAULT), StandardCharsets.UTF_8); + return new String(Base64.decode(source.toString(), Base64.DEFAULT), "UTF-8"); } catch (Exception ignore) { return null; } @@ -1230,7 +1231,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD if (viewGroup != null) { viewGroup.removeView(controlsView); } - changedTextureView = delegate.onSwitchInlineMode(controlsView, isInline, aspectRatioFrameLayout.getAspectRatio(), aspectRatioFrameLayout.getVideoRotation(), allowInlineAnimation); + changedTextureView = delegate.onSwitchInlineMode(controlsView, isInline, videoWidth, videoHeight, aspectRatioFrameLayout.getVideoRotation(), allowInlineAnimation); changedTextureView.setVisibility(INVISIBLE); ViewGroup parent = (ViewGroup) textureView.getParent(); if (parent != null) { @@ -1775,6 +1776,8 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD width = height; height = temp; } + videoWidth = (int) (width * pixelWidthHeightRatio); + videoHeight = height; float ratio = height == 0 ? 1 : (width * pixelWidthHeightRatio) / height; aspectRatioFrameLayout.setAspectRatio(ratio, unappliedRotationDegrees); if (inFullscreen) { @@ -1819,7 +1822,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } } switchingInlineMode = false; - delegate.onSwitchInlineMode(controlsView, false, aspectRatioFrameLayout.getAspectRatio(), aspectRatioFrameLayout.getVideoRotation(), allowInlineAnimation); + delegate.onSwitchInlineMode(controlsView, false, videoWidth, videoHeight, aspectRatioFrameLayout.getVideoRotation(), allowInlineAnimation); waitingForFirstTextureUpload = 0; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/CellFlickerDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/CellFlickerDrawable.java index 4cd465788..7fca1f3fe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/CellFlickerDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/CellFlickerDrawable.java @@ -14,11 +14,11 @@ import org.telegram.messenger.AndroidUtilities; public class CellFlickerDrawable { - private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Shader gradientShader; + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Shader gradientShader; - private final Paint paintOutline = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Shader gradientShader2; + private Paint paintOutline = new Paint(Paint.ANTI_ALIAS_FLAG); + private Shader gradientShader2; int size; int parentWidth; @@ -45,6 +45,17 @@ public class CellFlickerDrawable { paintOutline.setStrokeWidth(AndroidUtilities.dp(2)); } + public void setColors(int color) { + setColors(color, 64, 204); + } + + public void setColors(int color, int alpha1, int alpha2) { + gradientShader = new LinearGradient(0, 0, size, 0, new int[]{Color.TRANSPARENT, ColorUtils.setAlphaComponent(color, alpha1), Color.TRANSPARENT}, null, Shader.TileMode.CLAMP); + gradientShader2 = new LinearGradient(0, 0, size, 0, new int[]{Color.TRANSPARENT, ColorUtils.setAlphaComponent(color, alpha2), Color.TRANSPARENT}, null, Shader.TileMode.CLAMP); + paint.setShader(gradientShader); + paintOutline.setShader(gradientShader2); + } + public float getProgress() { return progress; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RTMPStreamPipOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RTMPStreamPipOverlay.java index a582c92d1..5ef37d138 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RTMPStreamPipOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RTMPStreamPipOverlay.java @@ -86,8 +86,6 @@ public class RTMPStreamPipOverlay implements NotificationCenter.NotificationCent private VoIPTextureView textureView; private FrameLayout controlsView; - private int textureWidth, textureHeight; - private CellFlickerDrawable cellFlickerDrawable = new CellFlickerDrawable(); private BackupImageView avatarImageView; private View flickerView; @@ -527,16 +525,11 @@ public class RTMPStreamPipOverlay implements NotificationCenter.NotificationCent AndroidUtilities.runOnUIThread(()-> bindTextureView()); } - @SuppressWarnings("SuspiciousNameCombination") @Override public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) { if ((rotation / 90) % 2 == 0) { - textureWidth = videoWidth; - textureHeight = videoHeight; aspectRatio = (float) videoHeight / videoWidth; } else { - textureWidth = videoHeight; - textureHeight = videoWidth; aspectRatio = (float) videoWidth / videoHeight; } AndroidUtilities.runOnUIThread(()-> bindTextureView()); 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 7557e1610..245164214 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 @@ -725,7 +725,11 @@ public class VoIPHelper { } } } - return new File(logsDir, callId + ".log").getAbsolutePath(); + if (stats) { + return new File(logsDir, callId + "_stats.log").getAbsolutePath(); + } else { + return new File(logsDir, callId + ".log").getAbsolutePath(); + } } public static void showGroupCallAlert(BaseFragment fragment, TLRPC.Chat currentChat, TLRPC.InputPeer peer, boolean recreate, AccountInstance accountInstance) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index bd2b43e96..d208f9e81 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -114,6 +114,7 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; @@ -135,6 +136,7 @@ import org.telegram.ui.Cells.DrawerProfileCell; import org.telegram.ui.Cells.DrawerUserCell; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.HashtagSearchCell; +import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.HintDialogCell; import org.telegram.ui.Cells.LoadingCell; import org.telegram.ui.Cells.ProfileSearchCell; @@ -300,6 +302,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private RecyclerView sideMenu; private ChatActivityEnterView commentView; + private View commentViewBg; private ImageView[] writeButton; private FrameLayout writeButtonContainer; private View selectedCountView; @@ -358,6 +361,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private boolean afterSignup; private boolean showSetPasswordConfirm; private int otherwiseReloginDays; + private boolean closeFragment; private FrameLayout updateLayout; private AnimatorSet updateLayoutAnimator; @@ -777,6 +781,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } else { h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - (onlySelect ? 0 : actionBar.getMeasuredHeight()) - topPadding; } + int paddingBottom = 0; + if (keyboardSize > AndroidUtilities.dp(20)) { + h += (paddingBottom = inputFieldHeight + keyboardSize); + } + if (((ViewPage) child).listView != null) { + ((ViewPage) child).listView.setPadding(0, 0, 0, paddingBottom); + } if (filtersTabAnimator != null && filterTabsView != null && filterTabsView.getVisibility() == VISIBLE) { h += filterTabsMoveFrom; @@ -811,10 +822,39 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } + private int previousHeight = -1; + private AnimatorSet keyboardAnimator; + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); + int layoutHeight = b - t; + if (previousHeight != -1 && commentView != null) { + if (Math.abs(previousHeight - layoutHeight) > AndroidUtilities.dp(20)) { + if (keyboardAnimator != null) { + keyboardAnimator.cancel(); + } + keyboardAnimator = new AnimatorSet(); + ArrayList animators = new ArrayList<>(); + animators.add(ObjectAnimator.ofFloat(commentView, TRANSLATION_Y, previousHeight - layoutHeight, 0)); + if (commentViewBg != null) { + animators.add(ObjectAnimator.ofFloat(commentViewBg, TRANSLATION_Y, previousHeight - layoutHeight, 0)); + } + if (writeButtonContainer != null) { + animators.add(ObjectAnimator.ofFloat(writeButtonContainer, TRANSLATION_Y, previousHeight - layoutHeight, 0)); + } + if (selectedCountView != null) { + animators.add(ObjectAnimator.ofFloat(selectedCountView, TRANSLATION_Y, previousHeight - layoutHeight, 0)); + } + keyboardAnimator.playTogether(animators); + keyboardAnimator.setDuration(AdjustPanLayoutHelper.keyboardDuration); + keyboardAnimator.setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator); + keyboardAnimator.start(); + } + } + previousHeight = layoutHeight; + int paddingBottom; Object tag = commentView != null ? commentView.getTag() : null; int keyboardSize = measureKeyboardHeight(); @@ -1536,6 +1576,14 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } return super.onInterceptTouchEvent(e); } + + @Override + protected boolean allowSelectChildAtPosition(View child) { + if (child instanceof HeaderCell && !child.isClickable()) { + return false; + } + return true; + } } private class SwipeController extends ItemTouchHelper.Callback { @@ -1840,6 +1888,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. hasInvoice = arguments.getBoolean("hasInvoice", false); showSetPasswordConfirm = arguments.getBoolean("showSetPasswordConfirm", showSetPasswordConfirm); otherwiseReloginDays = arguments.getInt("otherwiseRelogin"); + closeFragment = arguments.getBoolean("closeFragment", true); } if (initialDialogsType == 0) { @@ -1916,6 +1965,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. accountInstance.getMediaDataController().loadRecents(MediaDataController.TYPE_GREETINGS, false, true, false); accountInstance.getMediaDataController().checkFeaturedStickers(); accountInstance.getMediaDataController().checkReactions(); + accountInstance.getMediaDataController().checkMenuBots(); AndroidUtilities.runOnUIThread(() -> accountInstance.getDownloadController().loadDownloadingFiles(), 200); for (String emoji : messagesController.diceEmojies) { accountInstance.getMediaDataController().loadStickersByEmojiOrName(emoji, true, true); @@ -2062,6 +2112,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (proxyItem != null && proxyItemVisible) { proxyItem.setVisibility(View.GONE); } + if (downloadsItem != null && downloadsItemVisible) { + downloadsItem.setVisibility(View.GONE); + } if (viewPages[0] != null) { if (searchString != null) { viewPages[0].listView.hide(); @@ -2089,6 +2142,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (proxyItem != null && proxyItemVisible) { proxyItem.setVisibility(View.VISIBLE); } + if (downloadsItem != null && downloadsItemVisible) { + downloadsItem.setVisibility(View.VISIBLE); + } if (searchString != null) { finishFragment(); return false; @@ -2493,7 +2549,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } }; - tabView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(6), Theme.getColor(Theme.key_actionBarDefault))); + tabView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(6), 0, Theme.getColor(Theme.key_actionBarDefault))); scrimPopupWindow.setDismissAnimationDuration(220); scrimPopupWindow.setOutsideTouchable(true); scrimPopupWindow.setClippingEnabled(true); @@ -2856,7 +2912,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ArrayList arrayList = new ArrayList<>(); arrayList.add(-chatId); DialogsActivityDelegate dialogsActivityDelegate = delegate; - removeSelfFromStack(); + if (closeFragment) { + removeSelfFromStack(); + } dialogsActivityDelegate.didSelectDialogs(DialogsActivity.this, arrayList, null, true); } @@ -3317,6 +3375,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. commentView.setVisibility(View.GONE); commentView.getSendButton().setAlpha(0); contentView.addView(commentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM)); + commentViewBg = new View(getParentActivity()); + commentViewBg.setBackgroundColor(getThemedColor(Theme.key_chat_messagePanelBackground)); + contentView.addView(commentViewBg, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1600, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, -1600)); commentView.setDelegate(new ChatActivityEnterView.ChatActivityEnterViewDelegate() { @Override public void onMessageSend(CharSequence message, boolean notify, int scheduleDate) { @@ -5217,6 +5278,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } addOrRemoveSelectedDialog(dialog.id, view); updateSelectedCount(); + return true; } else { if (dialog instanceof TLRPC.TL_dialogFolder) { view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); @@ -5257,7 +5319,6 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. showOrUpdateActionMode(dialog.id, view); return true; } - return false; } private boolean showChatPreview(DialogCell cell) { @@ -6469,7 +6530,8 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } private boolean isNextButton = false; - + private AnimatorSet commentViewAnimator; + private void updateSelectedCount() { if (commentView != null) { if (selectedDialogs.isEmpty()) { @@ -6481,9 +6543,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (commentView.getTag() != null) { commentView.hidePopup(false); commentView.closeKeyboard(); - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether( - ObjectAnimator.ofFloat(commentView, View.TRANSLATION_Y, 0, commentView.getMeasuredHeight()), + if (commentViewAnimator != null) { + commentViewAnimator.cancel(); + } + commentViewAnimator = new AnimatorSet(); + commentView.setTranslationY(0); + commentViewAnimator.playTogether( + ObjectAnimator.ofFloat(commentView, View.TRANSLATION_Y, commentView.getMeasuredHeight()), ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_X, .2f), ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_Y, .2f), ObjectAnimator.ofFloat(writeButtonContainer, View.ALPHA, 0), @@ -6491,16 +6557,16 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ObjectAnimator.ofFloat(selectedCountView, View.SCALE_Y, 0.2f), ObjectAnimator.ofFloat(selectedCountView, View.ALPHA, 0.0f) ); - animatorSet.setDuration(180); - animatorSet.setInterpolator(new DecelerateInterpolator()); - animatorSet.addListener(new AnimatorListenerAdapter() { + commentViewAnimator.setDuration(180); + commentViewAnimator.setInterpolator(new DecelerateInterpolator()); + commentViewAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { commentView.setVisibility(View.GONE); writeButtonContainer.setVisibility(View.GONE); } }); - animatorSet.start(); + commentViewAnimator.start(); commentView.setTag(null); fragmentView.requestLayout(); } @@ -6508,11 +6574,14 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. selectedCountView.invalidate(); if (commentView.getTag() == null) { commentView.setFieldText(""); + if (commentViewAnimator != null) { + commentViewAnimator.cancel(); + } commentView.setVisibility(View.VISIBLE); writeButtonContainer.setVisibility(View.VISIBLE); - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether( - ObjectAnimator.ofFloat(commentView, View.TRANSLATION_Y, commentView.getMeasuredHeight(), 0), + commentViewAnimator = new AnimatorSet(); + commentViewAnimator.playTogether( + ObjectAnimator.ofFloat(commentView, View.TRANSLATION_Y, commentView.getMeasuredHeight(),0), ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_X, 1f), ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_Y, 1f), ObjectAnimator.ofFloat(writeButtonContainer, View.ALPHA, 1f), @@ -6520,16 +6589,16 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ObjectAnimator.ofFloat(selectedCountView, View.SCALE_Y, 1f), ObjectAnimator.ofFloat(selectedCountView, View.ALPHA, 1f) ); - animatorSet.setDuration(180); - animatorSet.setInterpolator(new DecelerateInterpolator()); - animatorSet.addListener(new AnimatorListenerAdapter() { + commentViewAnimator.setDuration(180); + commentViewAnimator.setInterpolator(new DecelerateInterpolator()); + commentViewAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { commentView.setTag(2); commentView.requestLayout(); } }); - animatorSet.start(); + commentViewAnimator.start(); commentView.setTag(1); } actionBar.setTitle(LocaleController.formatPluralString("Recipient", selectedDialogs.size())); @@ -6538,7 +6607,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. hideFloatingButton(selectedDialogs.isEmpty()); } - isNextButton = shouldShowNextButton(this, selectedDialogs, commentView.getFieldText(), false); + isNextButton = shouldShowNextButton(this, selectedDialogs, commentView != null ? commentView.getFieldText() : "", false); AndroidUtilities.updateViewVisibilityAnimated(writeButton[0], !isNextButton, 0.5f, true); AndroidUtilities.updateViewVisibilityAnimated(writeButton[1], isNextButton, 0.5f, true); } @@ -7025,7 +7094,20 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } else if (dialogsType == 1 || dialogsType == 10 || dialogsType == 13) { return messagesController.dialogsServerOnly; } else if (dialogsType == 2) { - return messagesController.dialogsCanAddUsers; + ArrayList dialogs = new ArrayList<>(messagesController.dialogsCanAddUsers.size() + messagesController.dialogsMyChannels.size() + messagesController.dialogsMyGroups.size() + 2); + if (messagesController.dialogsMyChannels.size() > 0) { + dialogs.add(null); + dialogs.addAll(messagesController.dialogsMyChannels); + } + if (messagesController.dialogsMyGroups.size() > 0) { + dialogs.add(null); + dialogs.addAll(messagesController.dialogsMyGroups); + } + if (messagesController.dialogsCanAddUsers.size() > 0) { + dialogs.add(null); + dialogs.addAll(messagesController.dialogsCanAddUsers); + } + return dialogs; } else if (dialogsType == 3) { return messagesController.dialogsForward; } else if (dialogsType == 4 || dialogsType == 12) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index acf3daeb8..04fe5a858 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -22,7 +22,6 @@ import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; @@ -120,6 +119,7 @@ import org.telegram.ui.Cells.DrawerProfileCell; import org.telegram.ui.Cells.DrawerUserCell; import org.telegram.ui.Cells.LanguageCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AttachBotIntroTopView; import org.telegram.ui.Components.AudioPlayerAlert; import org.telegram.ui.Components.BlockingUpdateView; import org.telegram.ui.Components.Bulletin; @@ -167,6 +167,8 @@ import java.util.Set; import java.util.regex.Pattern; public class LaunchActivity extends BasePermissionsActivity implements ActionBarLayout.ActionBarLayoutDelegate, NotificationCenter.NotificationCenterDelegate, DialogsActivity.DialogsActivityDelegate { + public static boolean isResumed; + public static Runnable onResumeStaticCallback; private static final String EXTRA_ACTION_TOKEN = "actions.fulfillment.extra.ACTION_TOKEN"; @@ -248,21 +250,6 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar @Override protected void onCreate(Bundle savedInstanceState) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - getSplashScreen().setOnExitAnimationListener(splashScreenView -> { - ObjectAnimator animator = ObjectAnimator.ofFloat(splashScreenView, View.ALPHA, 1f, 0f); - animator.setInterpolator(CubicBezierInterpolator.DEFAULT); - animator.setDuration(150L); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - splashScreenView.remove(); - } - }); - animator.start(); - }); - } - ApplicationLoader.postInitApplication(); AndroidUtilities.checkDisplaySize(this, getResources().getConfiguration()); currentAccount = UserConfig.selectedAccount; @@ -519,7 +506,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar sideMenu.setBackgroundColor(Theme.getColor(Theme.key_chats_menuBackground)); sideMenu.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); sideMenu.setAllowItemsInteractionDuringAnimation(false); - sideMenu.setAdapter(drawerLayoutAdapter = new DrawerLayoutAdapter(this, itemAnimator)); + sideMenu.setAdapter(drawerLayoutAdapter = new DrawerLayoutAdapter(this, itemAnimator, drawerLayoutContainer)); sideMenuContainer.addView(sideMenu, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); drawerLayoutContainer.setDrawerLayout(sideMenuContainer); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) sideMenuContainer.getLayoutParams(); @@ -1604,6 +1591,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar String unsupportedUrl = null; String botUser = null; String botChat = null; + String botChatAdminParams = null; String message = null; String phone = null; String game = null; @@ -1620,6 +1608,8 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar Integer commentId = null; int videoTimestamp = -1; boolean hasUrl = false; + String setAsAttachBot = null; + String attachMenuBotToOpen = null; final String scheme = data.getScheme(); if (scheme != null) { switch (scheme) { @@ -1789,9 +1779,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } botUser = data.getQueryParameter("start"); botChat = data.getQueryParameter("startgroup"); + botChatAdminParams = data.getQueryParameter("admin"); game = data.getQueryParameter("game"); voicechat = data.getQueryParameter("voicechat"); livestream = data.getQueryParameter("livestream"); + setAsAttachBot = data.getQueryParameter("startattach"); + attachMenuBotToOpen = data.getQueryParameter("attach"); threadId = Utilities.parseInt(data.getQueryParameter("thread")); if (threadId == 0) { threadId = null; @@ -1827,9 +1820,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } else { botUser = data.getQueryParameter("start"); botChat = data.getQueryParameter("startgroup"); + botChatAdminParams = data.getQueryParameter("admin"); game = data.getQueryParameter("game"); voicechat = data.getQueryParameter("voicechat"); livestream = data.getQueryParameter("livestream"); + setAsAttachBot = data.getQueryParameter("startattach"); + attachMenuBotToOpen = data.getQueryParameter("attach"); messageId = Utilities.parseInt(data.getQueryParameter("post")); if (messageId == 0) { messageId = null; @@ -2154,7 +2150,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar if (message != null && message.startsWith("@")) { message = " " + message; } - runLinkRequest(intentAccount[0], username, group, sticker, botUser, botChat, message, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, login, wallPaper, theme, voicechat, livestream, 0, videoTimestamp); + runLinkRequest(intentAccount[0], username, group, sticker, botUser, botChat, botChatAdminParams, message, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, login, wallPaper, theme, voicechat, livestream, 0, videoTimestamp, setAsAttachBot, attachMenuBotToOpen); } else { try (Cursor cursor = getContentResolver().query(intent.getData(), null, null, null, null)) { if (cursor != null) { @@ -2831,6 +2827,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar final String sticker, final String botUser, final String botChat, + final String botChatAdminParams, final String message, final boolean hasUrl, final Integer messageId, @@ -2848,13 +2845,15 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar final String voicechat, final String livestream, final int state, - final int videoTimestamp) { + final int videoTimestamp, + final String setAsAttachBot, + final String attachMenuBotToOpen) { if (state == 0 && UserConfig.getActivatedAccountsCount() >= 2 && auth != null) { AlertsCreator.createAccountSelectDialog(this, account -> { if (account != intentAccount) { switchToAccount(account, true); } - runLinkRequest(account, username, group, sticker, botUser, botChat, message, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, theme, voicechat, livestream, 1, videoTimestamp); + runLinkRequest(account, username, group, sticker, botUser, botChat, botChatAdminParams, message, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, theme, voicechat, livestream, 1, videoTimestamp, setAsAttachBot, attachMenuBotToOpen); }).show(); return; } else if (code != null) { @@ -2894,12 +2893,63 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (!LaunchActivity.this.isFinishing()) { boolean hideProgressDialog = true; - final TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; + TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; if (error == null && actionBarLayout != null && (game == null && voicechat == null || game != null && !res.users.isEmpty() || voicechat != null && !res.chats.isEmpty() || livestream != null && !res.chats.isEmpty())) { MessagesController.getInstance(intentAccount).putUsers(res.users, false); MessagesController.getInstance(intentAccount).putChats(res.chats, false); MessagesStorage.getInstance(intentAccount).putUsersAndChats(res.users, res.chats, false, true); - if (messageId != null && (commentId != null || threadId != null) && !res.chats.isEmpty()) { + if (setAsAttachBot != null && attachMenuBotToOpen == null) { + TLRPC.User user = MessagesController.getInstance(intentAccount).getUser(res.peer.user_id); + if (user != null && user.bot) { + if (user.bot_attach_menu) { + TLRPC.TL_messages_getAttachMenuBot getAttachMenuBot = new TLRPC.TL_messages_getAttachMenuBot(); + getAttachMenuBot.bot = MessagesController.getInstance(intentAccount).getInputUser(res.peer.user_id); + ConnectionsManager.getInstance(intentAccount).sendRequest(getAttachMenuBot, (response1, error1) -> AndroidUtilities.runOnUIThread(()->{ + if (response1 instanceof TLRPC.TL_attachMenuBotsBot) { + TLRPC.TL_attachMenuBotsBot attachMenuBotsBot = (TLRPC.TL_attachMenuBotsBot) response1; + MessagesController.getInstance(intentAccount).putUsers(attachMenuBotsBot.users, false); + TLRPC.TL_attachMenuBot attachMenuBot = attachMenuBotsBot.bot; + BaseFragment lastFragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); + if (!attachMenuBot.inactive) { + if (lastFragment instanceof ChatActivity) { + ((ChatActivity) lastFragment).openAttachBotLayout(user.id, setAsAttachBot); + } else { + BulletinFactory.of(lastFragment).createErrorBulletin(LocaleController.getString(R.string.BotAlreadyAddedToAttachMenu)).show(); + } + } else { + AttachBotIntroTopView introTopView = new AttachBotIntroTopView(LaunchActivity.this); + introTopView.setColor(Theme.getColor(Theme.key_chat_attachContactIcon)); + introTopView.setBackgroundColor(Theme.getColor(Theme.key_dialogTopBackground)); + introTopView.setAttachBot(attachMenuBot); + new AlertDialog.Builder(LaunchActivity.this) + .setTopView(introTopView) + .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("BotRequestAttachPermission", R.string.BotRequestAttachPermission, UserObject.getUserName(user)))) + .setPositiveButton(LocaleController.getString(R.string.BotAddToMenu), (dialog, which) -> { + TLRPC.TL_messages_toggleBotInAttachMenu botRequest = new TLRPC.TL_messages_toggleBotInAttachMenu(); + botRequest.bot = MessagesController.getInstance(intentAccount).getInputUser(res.peer.user_id); + botRequest.enabled = true; + ConnectionsManager.getInstance(intentAccount).sendRequest(botRequest, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + MediaDataController.getInstance(intentAccount).loadAttachMenuBots(false, true); + + if (lastFragment instanceof ChatActivity) { + ((ChatActivity) lastFragment).openAttachBotLayout(user.id, setAsAttachBot); + } + } + }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + } + } + })); + } else { + BulletinFactory.of(mainFragmentsStack.get(mainFragmentsStack.size() - 1)).createErrorBulletin(LocaleController.getString(R.string.BotCantAddToAttachMenu)).show(); + } + } else { + BulletinFactory.of(mainFragmentsStack.get(mainFragmentsStack.size() - 1)).createErrorBulletin(LocaleController.getString(R.string.BotSetAttachLinkNotBot)).show(); + } + } else if (messageId != null && (commentId != null || threadId != null) && !res.chats.isEmpty()) { requestId[0] = runCommentRequest(intentAccount, progressDialog, messageId, commentId, threadId, res.chats.get(0)); if (requestId[0] != 0) { hideProgressDialog = false; @@ -2973,17 +3023,107 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putInt("dialogsType", 2); - args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); + args.putBoolean("resetDelegate", false); + args.putBoolean("closeFragment", false); +// args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment12, dids, message1, param) -> { long did = dids.get(0); - Bundle args12 = new Bundle(); - args12.putBoolean("scrollToTopOnResume", true); - args12.putLong("chat_id", -did); - if (mainFragmentsStack.isEmpty() || MessagesController.getInstance(intentAccount).checkCanOpenChat(args12, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { - NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); - MessagesController.getInstance(intentAccount).addUserToChat(-did, user, 0, botChat, null, null); - actionBarLayout.presentFragment(new ChatActivity(args12), true, false, true, false); + + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); + if (chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.add_admins)) { + MessagesController.getInstance(intentAccount).checkIsInChat(chat, user, (isInChatAlready, currentRights, currentRank) -> AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_chatAdminRights requestingRights = null; + if (botChatAdminParams != null) { + String[] adminParams = botChatAdminParams.split("\\+"); + requestingRights = new TLRPC.TL_chatAdminRights(); + final int count = adminParams.length; + for (int i = 0; i < count; ++i) { + String adminParam = adminParams[i]; + switch (adminParam) { + case "change_info": + requestingRights.change_info = true; + break; + case "post_messages": + requestingRights.post_messages = true; + break; + case "edit_messages": + requestingRights.edit_messages = true; + break; + case "add_admins": + requestingRights.add_admins = true; + break; + case "delete_messages": + requestingRights.delete_messages = true; + break; + case "ban_users": + requestingRights.ban_users = true; + break; + case "invite_users": + requestingRights.invite_users = true; + break; + case "pin_messages": + requestingRights.pin_messages = true; + break; + case "manage_call": + requestingRights.manage_call = true; + break; + case "anonymous": + requestingRights.anonymous = true; + break; + } + } + } + TLRPC.TL_chatAdminRights editRights = null; + if (requestingRights != null || currentRights != null) { + if (requestingRights == null) { + editRights = currentRights; + } else if (currentRights == null) { + editRights = requestingRights; + } else { + editRights = currentRights; + editRights.change_info = requestingRights.change_info || editRights.change_info; + editRights.post_messages = requestingRights.post_messages || editRights.post_messages; + editRights.edit_messages = requestingRights.edit_messages || editRights.edit_messages; + editRights.add_admins = requestingRights.add_admins || editRights.add_admins; + editRights.delete_messages = requestingRights.delete_messages || editRights.delete_messages; + editRights.ban_users = requestingRights.ban_users || editRights.ban_users; + editRights.invite_users = requestingRights.invite_users || editRights.invite_users; + editRights.pin_messages = requestingRights.pin_messages || editRights.pin_messages; + editRights.manage_call = requestingRights.manage_call || editRights.manage_call; + editRights.anonymous = requestingRights.anonymous || editRights.anonymous; + } + } + ChatRightsEditActivity editRightsActivity = new ChatRightsEditActivity(user.id, -did, editRights, null, null, currentRank, ChatRightsEditActivity.TYPE_ADD_BOT, true, !isInChatAlready, null); + editRightsActivity.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { + @Override + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { + fragment.removeSelfFromStack(); + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + } + + @Override + public void didChangeOwner(TLRPC.User user) {} + }); + actionBarLayout.presentFragment(editRightsActivity, false); + })); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(LocaleController.getString("AddBot", R.string.AddBot)); + String chatName = chat == null ? "" : chat.title; + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(user), chatName))); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setPositiveButton(LocaleController.getString("AddBot", R.string.AddBot), (di, i) -> { + Bundle args12 = new Bundle(); + args12.putBoolean("scrollToTopOnResume", true); + args12.putLong("chat_id", -did); + + ChatActivity chatActivity = new ChatActivity(args12); + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + MessagesController.getInstance(intentAccount).addUserToChat(-did, user, 0, TextUtils.isEmpty(botChat) ? null : botChat, chatActivity, null); + actionBarLayout.presentFragment(chatActivity, true, false, true, false); + }); + builder.show(); } }); presentFragment(fragment); @@ -3014,6 +3154,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar if (videoTimestamp >= 0) { args.putInt("video_timestamp", videoTimestamp); } + if (attachMenuBotToOpen != null) { + args.putString("attach_bot", attachMenuBotToOpen); + } + if (setAsAttachBot != null) { + args.putString("attach_bot_start_command", setAsAttachBot); + } BaseFragment lastFragment = !mainFragmentsStack.isEmpty() && voicechat == null ? mainFragmentsStack.get(mainFragmentsStack.size() - 1) : null; if (lastFragment == null || MessagesController.getInstance(intentAccount).checkCanOpenChat(args, lastFragment)) { if (isBot && lastFragment instanceof ChatActivity && ((ChatActivity) lastFragment).getDialogId() == dialog_id) { @@ -3028,20 +3174,35 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar FileLog.e(e); } if (!LaunchActivity.this.isFinishing()) { - ChatActivity fragment = new ChatActivity(args); - actionBarLayout.presentFragment(fragment); + BaseFragment voipLastFragment; + if (livestream == null || !(lastFragment instanceof ChatActivity) || ((ChatActivity) lastFragment).getDialogId() != dialog_id) { + ChatActivity fragment = new ChatActivity(args); + actionBarLayout.presentFragment(fragment); + voipLastFragment = fragment; + } else { + voipLastFragment = lastFragment; + } AndroidUtilities.runOnUIThread(()->{ if (livestream != null) { AccountInstance accountInstance = AccountInstance.getInstance(currentAccount); ChatObject.Call cachedCall = accountInstance.getMessagesController().getGroupCall(-dialog_id, false); if (cachedCall != null) { - VoIPHelper.startCall(accountInstance.getMessagesController().getChat(-dialog_id), accountInstance.getMessagesController().getInputPeer(dialog_id), null, false, cachedCall == null || !cachedCall.call.rtmp_stream, LaunchActivity.this, fragment, accountInstance); + VoIPHelper.startCall(accountInstance.getMessagesController().getChat(-dialog_id), accountInstance.getMessagesController().getInputPeer(dialog_id), null, false, cachedCall == null || !cachedCall.call.rtmp_stream, LaunchActivity.this, voipLastFragment, accountInstance); } else { - accountInstance.getMessagesController().getGroupCall(-dialog_id, true, () -> AndroidUtilities.runOnUIThread(() -> { - ChatObject.Call call = accountInstance.getMessagesController().getGroupCall(-dialog_id, false); - VoIPHelper.startCall(accountInstance.getMessagesController().getChat(-dialog_id), accountInstance.getMessagesController().getInputPeer(dialog_id), null, false, call == null || !call.call.rtmp_stream, LaunchActivity.this, fragment, accountInstance); - })); + TLRPC.ChatFull chatFull = accountInstance.getMessagesController().getChatFull(-dialog_id); + if (chatFull != null) { + if (chatFull.call == null) { + if (voipLastFragment.getParentActivity() != null) { + BulletinFactory.of(voipLastFragment).createSimpleBulletin(R.raw.linkbroken, LocaleController.getString("InviteExpired", R.string.InviteExpired)).show(); + } + } else { + accountInstance.getMessagesController().getGroupCall(-dialog_id, true, () -> AndroidUtilities.runOnUIThread(() -> { + ChatObject.Call call = accountInstance.getMessagesController().getGroupCall(-dialog_id, false); + VoIPHelper.startCall(accountInstance.getMessagesController().getChat(-dialog_id), accountInstance.getMessagesController().getInputPeer(dialog_id), null, false, call == null || !call.call.rtmp_stream, LaunchActivity.this, voipLastFragment, accountInstance); + })); + } + } } } }, 150); @@ -4208,6 +4369,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar fragment.onActivityResultFragment(requestCode, resultCode, data); } } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.onActivityResultReceived, requestCode, resultCode, data); } } @@ -4232,11 +4394,13 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } VoIPFragment.onRequestPermissionsResult(requestCode, permissions, grantResults); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.onRequestPermissionResultReceived, requestCode, permissions, grantResults); } @Override protected void onPause() { super.onPause(); + isResumed = false; NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 4096); ApplicationLoader.mainInterfacePaused = true; int account = currentAccount; @@ -4346,6 +4510,11 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar @Override protected void onResume() { super.onResume(); + isResumed = true; + if (onResumeStaticCallback != null) { + onResumeStaticCallback.run(); + onResumeStaticCallback = null; + } if (Theme.selectedAutoNightType == Theme.AUTO_NIGHT_TYPE_SYSTEM) { Theme.checkAutoNightThemeConditions(); } @@ -4848,6 +5017,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } else { BulletinFactory.of(container, null).createErrorBulletin((String) args[1]).show(); } + } if (type == Bulletin.TYPE_ERROR_SUBTITLE) { + if (fragment != null) { + BulletinFactory.of(fragment).createErrorBulletinSubtitle((String) args[1], (String) args[2], fragment.getResourceProvider()).show(); + } else { + BulletinFactory.of(container, null).createErrorBulletinSubtitle((String) args[1], (String) args[2], null).show(); + } } } } else if (id == NotificationCenter.groupCallUpdated) { @@ -5470,7 +5645,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } } } - return super.dispatchKeyEvent(event); + try { + super.dispatchKeyEvent(event); + } catch (Exception e) { + FileLog.e(e); + } + return false; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ManageLinksActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ManageLinksActivity.java index 1b7bc509e..72524c5fe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ManageLinksActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ManageLinksActivity.java @@ -51,9 +51,9 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; -import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Cells.CreationTextCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ManageChatTextCell; import org.telegram.ui.Cells.ManageChatUserCell; @@ -68,9 +68,9 @@ import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.InviteLinkBottomSheet; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkActionView; +import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.TimerParticles; -import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import java.util.ArrayList; import java.util.HashMap; @@ -764,7 +764,7 @@ public class ManageLinksActivity extends BaseFragment { view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 3: - view = new TextCell(mContext); + view = new CreationTextCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 4: @@ -851,7 +851,7 @@ public class ManageLinksActivity extends BaseFragment { } break; case 3: - TextCell textCell = (TextCell) holder.itemView; + CreationTextCell textCell = (CreationTextCell) holder.itemView; Drawable drawable1 = mContext.getResources().getDrawable(R.drawable.poll_add_circle); Drawable drawable2 = mContext.getResources().getDrawable(R.drawable.poll_add_plus); drawable1.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_switchTrackChecked), PorterDuff.Mode.MULTIPLY)); @@ -973,71 +973,6 @@ public class ManageLinksActivity extends BaseFragment { } } - public static class TextCell extends FrameLayout { - - private SimpleTextView textView; - private ImageView imageView; - boolean divider; - - public TextCell(Context context) { - super(context); - - textView = new SimpleTextView(context); - textView.setTextSize(16); - textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText2)); - textView.setTag(Theme.key_windowBackgroundWhiteBlueText2); - addView(textView); - - imageView = new ImageView(context); - imageView.setScaleType(ImageView.ScaleType.CENTER); - addView(imageView); - setWillNotDraw(false); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = MeasureSpec.getSize(widthMeasureSpec); - int height = AndroidUtilities.dp(48); - - textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + 23), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); - setMeasuredDimension(width, AndroidUtilities.dp(50)); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int height = bottom - top; - int width = right - left; - - int viewLeft; - int viewTop = (height - textView.getTextHeight()) / 2; - if (LocaleController.isRTL) { - viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? 70 : 25); - } else { - viewLeft = AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? 70 : 25); - } - textView.layout(viewLeft, viewTop, viewLeft + textView.getMeasuredWidth(), viewTop + textView.getMeasuredHeight()); - - viewLeft = !LocaleController.isRTL ? (AndroidUtilities.dp(70) - imageView.getMeasuredWidth()) / 2 : width - imageView.getMeasuredWidth() - AndroidUtilities.dp(25); - imageView.layout(viewLeft, 0, viewLeft + imageView.getMeasuredWidth(), imageView.getMeasuredHeight()); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (divider) { - canvas.drawLine(AndroidUtilities.dp(70), getMeasuredHeight() - 1, getMeasuredWidth() + AndroidUtilities.dp(23), getMeasuredHeight(), Theme.dividerPaint); - } - } - - public void setTextAndIcon(String text, Drawable icon, boolean divider) { - textView.setText(text); - imageView.setImageDrawable(icon); - this.divider = divider; - } - } - private class LinkCell extends FrameLayout { private final static int LINK_STATE_BLUE = 0; @@ -1693,7 +1628,7 @@ public class ManageLinksActivity extends BaseFragment { } }; - themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, TextCell.class, LinkActionView.class, LinkCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, CreationTextCell.class, LinkActionView.class, LinkCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); themeDescriptions.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND | ThemeDescription.FLAG_CHECKTAG, null, null, null, null, Theme.key_windowBackgroundGray)); themeDescriptions.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND | ThemeDescription.FLAG_CHECKTAG, null, null, null, null, Theme.key_windowBackgroundWhite)); @@ -1729,9 +1664,9 @@ public class ManageLinksActivity extends BaseFragment { themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueButton)); themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueIcon)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueText2)); - themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_switchTrackChecked)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_checkboxCheck)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{CreationTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueText2)); + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{CreationTextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_switchTrackChecked)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{CreationTextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_checkboxCheck)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{LinkCell.class}, new String[]{"titleView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java index de1eaf95d..d9f09fe2c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java @@ -30,6 +30,9 @@ import android.widget.EditText; import android.widget.FrameLayout; import android.widget.TextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; @@ -68,10 +71,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -public class NotificationsCustomSettingsActivity extends BaseFragment { +public class NotificationsCustomSettingsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private RecyclerListView listView; private ListAdapter adapter; @@ -435,39 +435,42 @@ public class NotificationsCustomSettingsActivity extends BaseFragment { return; } try { - SharedPreferences preferences = getNotificationsSettings(); - Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); - Uri currentSound = null; - - String defaultPath = null; - Uri defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI; - if (defaultUri != null) { - defaultPath = defaultUri.getPath(); - } - - String path; - if (currentType == NotificationsController.TYPE_PRIVATE) { - path = preferences.getString("GlobalSoundPath", defaultPath); - } else if (currentType == NotificationsController.TYPE_GROUP) { - path = preferences.getString("GroupSoundPath", defaultPath); - } else { - path = preferences.getString("ChannelSoundPath", defaultPath); - } - - if (path != null && !path.equals("NoSound")) { - if (path.equals(defaultPath)) { - currentSound = defaultUri; - } else { - currentSound = Uri.parse(path); - } - } - - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound); - startActivityForResult(tmpIntent, position); + Bundle bundle = new Bundle(); + bundle.putInt("type", currentType); + presentFragment(new NotificationsSoundActivity(bundle)); +// SharedPreferences preferences = getNotificationsSettings(); +// Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION); +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); +// Uri currentSound = null; +// +// String defaultPath = null; +// Uri defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI; +// if (defaultUri != null) { +// defaultPath = defaultUri.getPath(); +// } +// +// String path; +// if (currentType == NotificationsController.TYPE_PRIVATE) { +// path = preferences.getString("GlobalSoundPath", defaultPath); +// } else if (currentType == NotificationsController.TYPE_GROUP) { +// path = preferences.getString("GroupSoundPath", defaultPath); +// } else { +// path = preferences.getString("ChannelSoundPath", defaultPath); +// } +// +// if (path != null && !path.equals("NoSound")) { +// if (path.equals(defaultPath)) { +// currentSound = defaultUri; +// } else { +// currentSound = Uri.parse(path); +// } +// } +// +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound); +// startActivityForResult(tmpIntent, position); } catch (Exception e) { FileLog.e(e); } @@ -863,6 +866,22 @@ public class NotificationsCustomSettingsActivity extends BaseFragment { if (adapter != null) { adapter.notifyDataSetChanged(); } + getNotificationCenter().addObserver(this, NotificationCenter.notificationsSettingsUpdated); + } + + @Override + public void onPause() { + super.onPause(); + getNotificationCenter().removeObserver(this, NotificationCenter.notificationsSettingsUpdated); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.notificationsSettingsUpdated) { + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } } private class SearchAdapter extends RecyclerListView.SelectionAdapter { @@ -1215,15 +1234,24 @@ public class NotificationsCustomSettingsActivity extends BaseFragment { SharedPreferences preferences = getNotificationsSettings(); if (position == messageSoundRow) { String value; + long documentId; if (currentType == NotificationsController.TYPE_PRIVATE) { value = preferences.getString("GlobalSound", LocaleController.getString("SoundDefault", R.string.SoundDefault)); + documentId = preferences.getLong("GlobalSoundDocId", 0); } else if (currentType == NotificationsController.TYPE_GROUP) { value = preferences.getString("GroupSound", LocaleController.getString("SoundDefault", R.string.SoundDefault)); + documentId = preferences.getLong("GroupSoundDocId", 0); } else { value = preferences.getString("ChannelSound", LocaleController.getString("SoundDefault", R.string.SoundDefault)); + documentId = preferences.getLong("ChannelDocId", 0); } - if (value.equals("NoSound")) { + if (documentId != 0) { + TLRPC.Document document = getMediaDataController().ringtoneDataStore.getDocument(documentId); + value = NotificationsSoundActivity.trimTitle(document, document.file_name_fixed); + } else if (value.equals("NoSound")) { value = LocaleController.getString("NoSound", R.string.NoSound); + } else if (value.equals("Default")) { + value = LocaleController.getString("SoundDefault", R.string.SoundDefault); } textCell.setTextAndValue(LocaleController.getString("Sound", R.string.Sound), value, true); } else if (position == messageVibrateRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java index 80d4df5bf..86d61b3d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java @@ -26,23 +26,28 @@ import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; +import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; -import org.telegram.messenger.NotificationsController; import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.HeaderCell; @@ -50,8 +55,6 @@ import org.telegram.ui.Cells.NotificationsCheckCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextDetailSettingsCell; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.AlertsCreator; @@ -61,9 +64,6 @@ import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; import java.util.Map; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - public class NotificationsSettingsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { public static class NotificationException { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java new file mode 100644 index 000000000..4678b8d6e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java @@ -0,0 +1,956 @@ +package org.telegram.ui; + +import android.app.NotificationManager; +import android.content.ClipData; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.R; +import org.telegram.messenger.ringtone.RingtoneDataStore; +import org.telegram.messenger.ringtone.RingtoneUploader; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.CreationTextCell; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Components.ChatAttachAlert; +import org.telegram.ui.Components.ChatAttachAlertDocumentLayout; +import org.telegram.ui.Components.ChatAvatarContainer; +import org.telegram.ui.Components.CheckBox2; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.NumberTextView; +import org.telegram.ui.Components.RadioButton; +import org.telegram.ui.Components.RecyclerListView; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +public class NotificationsSoundActivity extends BaseFragment implements ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate, NotificationCenter.NotificationCenterDelegate { + + ArrayList serverTones = new ArrayList<>(); + ArrayList systemTones = new ArrayList<>(); + ArrayList uploadingTones = new ArrayList<>(); + + NumberTextView selectedTonesCountTextView; + RecyclerListView listView; + Adapter adapter; + + int rowCount; + int serverTonesHeaderRow; + int serverTonesStartRow; + int serverTonesEndRow; + + int uploadRow; + + int dividerRow; + int dividerRow2; + + int systemTonesHeaderRow; + int systemTonesStartRow; + int systemTonesEndRow; + + private int stableIds = 100; + + Tone selectedTone; + boolean selectedToneChanged; + + SparseArray selectedTones = new SparseArray<>(); + private final static int deleteId = 1; + private final static int shareId = 2; + + ChatAvatarContainer avatarContainer; + long dialogId; + int currentType = -1; + + + private Tone startSelectedTone; + ChatAttachAlert chatAttachAlert; + Ringtone lastPlayedRingtone; + + private final int tonesStreamType = AudioManager.STREAM_ALARM; + + public NotificationsSoundActivity(Bundle args) { + super(args); + } + + @Override + public boolean onFragmentCreate() { + if (getArguments() != null) { + dialogId = getArguments().getLong("dialog_id", 0); + currentType = getArguments().getInt("type", -1); + } + String prefPath; + String prefDocId; + if (dialogId != 0) { + prefDocId = "sound_document_id_" + dialogId; + prefPath = "sound_path_" + dialogId; + } else { + if (currentType == NotificationsController.TYPE_PRIVATE) { + prefPath = "GlobalSoundPath"; + prefDocId = "GlobalSoundDocId"; + } else if (currentType == NotificationsController.TYPE_GROUP) { + prefPath = "GroupSoundPath"; + prefDocId = "GroupSoundDocId"; + } else if (currentType == NotificationsController.TYPE_CHANNEL) { + prefPath = "ChannelSoundPath"; + prefDocId = "ChannelSoundDocId"; + } else { + throw new RuntimeException("Unsupported type"); + } + } + + SharedPreferences preferences = getNotificationsSettings(); + long documentId = preferences.getLong(prefDocId, 0); + String localUri = preferences.getString(prefPath, "NoSound"); + + startSelectedTone = new Tone(); + if (documentId != 0) { + startSelectedTone.document = new TLRPC.TL_document(); + startSelectedTone.document.id = documentId; + } else { + startSelectedTone.uri = localUri; + } + return super.onFragmentCreate(); + } + + @Override + public View createView(final Context context) { + actionBar.setBackButtonDrawable(new BackDrawable(false)); + actionBar.setAllowOverlayTitle(false); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (actionBar.isActionModeShowed()) { + hideActionMode(); + } else { + finishFragment(); + } + } else if (id == deleteId) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.formatPluralString("DeleteTones", selectedTones.size())); + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatPluralString("DeleteTonesMessage", selectedTones.size()))); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + dialog.dismiss(); + }); + builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), (dialog, which) -> { + deleteSelectedMessages(); + dialog.dismiss(); + }); + AlertDialog dialog = builder.show(); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_dialogTextRed2)); + } + } else if (id == shareId) { + if (selectedTones.size() == 1) { + Intent intent = new Intent(context, LaunchActivity.class); + intent.setAction(Intent.ACTION_SEND); + + Uri uri = selectedTones.valueAt(0).getUriForShare(currentAccount); + if (uri != null) { + intent.putExtra(Intent.EXTRA_STREAM, uri); + context.startActivity(intent); + } + } else { + Intent intent = new Intent(context, LaunchActivity.class); + intent.setAction(Intent.ACTION_SEND_MULTIPLE); + + ArrayList uries = new ArrayList<>(); + for(int i = 0; i < selectedTones.size(); i++) { + Uri uri = selectedTones.valueAt(i).getUriForShare(currentAccount); + if (uri != null) { + uries.add(uri); + } + + } + if (!uries.isEmpty()) { + intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uries); + context.startActivity(intent); + } + } + + hideActionMode(); + updateRows(); + adapter.notifyDataSetChanged(); + } + } + + private void deleteSelectedMessages() { + ArrayList documentsToRemove = new ArrayList<>(); + for (int i = 0; i < selectedTones.size(); i++) { + Tone tone = selectedTones.valueAt(i); + if (tone.document != null) { + documentsToRemove.add(tone.document); + getMediaDataController().ringtoneDataStore.remove(tone.document); + } + if (tone.uri != null) { + RingtoneUploader ringtoneUploader = getMediaDataController().ringtoneUploaderHashMap.get(tone.uri); + if (ringtoneUploader != null) { + ringtoneUploader.cancel(); + } + } + if (tone == selectedTone) { + startSelectedTone = null; + selectedTone = systemTones.get(0); + selectedToneChanged = true; + } + serverTones.remove(tone); + uploadingTones.remove(tone); + } + getMediaDataController().ringtoneDataStore.saveTones(); + + for (int i = 0; i < documentsToRemove.size(); i++) { + TLRPC.Document document = documentsToRemove.get(i); + TLRPC.TL_account_saveRingtone req = new TLRPC.TL_account_saveRingtone(); + req.id = new TLRPC.TL_inputDocument(); + req.id.id = document.id; + req.id.access_hash = document.access_hash; + req.id.file_reference = document.file_reference; + if (req.id.file_reference == null) { + req.id.file_reference = new byte[0]; + } + req.unsave = true; + getConnectionsManager().sendRequest(req, (response, error) -> { + + }); + } + hideActionMode(); + updateRows(); + adapter.notifyDataSetChanged(); + } + }); + + if (dialogId == 0) { + if (currentType == NotificationsController.TYPE_PRIVATE) { + actionBar.setTitle(LocaleController.getString("NotificationsSoundPrivate", R.string.NotificationsSoundPrivate)); + } else if (currentType == NotificationsController.TYPE_GROUP) { + actionBar.setTitle(LocaleController.getString("NotificationsSoundGroup", R.string.NotificationsSoundGroup)); + } else if (currentType == NotificationsController.TYPE_CHANNEL) { + actionBar.setTitle(LocaleController.getString("NotificationsSoundChannels", R.string.NotificationsSoundChannels)); + } + } else { + avatarContainer = new ChatAvatarContainer(context, null, false); + avatarContainer.setOccupyStatusBar(!AndroidUtilities.isTablet()); + actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : 0, 0, 40, 0)); + if (dialogId < 0) { + TLRPC.Chat chatLocal = getMessagesController().getChat(-dialogId); + avatarContainer.setChatAvatar(chatLocal); + avatarContainer.setTitle(chatLocal.title); + } else { + TLRPC.User user = getMessagesController().getUser(dialogId); + avatarContainer.setUserAvatar(user); + avatarContainer.setTitle(ContactsController.formatName(user.first_name, user.last_name)); + } + avatarContainer.setSubtitle(LocaleController.getString("NotificationsSound", R.string.NotificationsSound)); + } + + final ActionBarMenu actionMode = actionBar.createActionMode(); + + selectedTonesCountTextView = new NumberTextView(actionMode.getContext()); + selectedTonesCountTextView.setTextSize(18); + selectedTonesCountTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + selectedTonesCountTextView.setTextColor(Theme.getColor(Theme.key_actionBarActionModeDefaultIcon)); + actionMode.addView(selectedTonesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 72, 0, 0, 0)); + selectedTonesCountTextView.setOnTouchListener((v, event) -> true); + + actionMode.addItemWithWidth(shareId, R.drawable.msg_forward, AndroidUtilities.dp(54), LocaleController.getString("ShareFile", R.string.ShareFile)); + actionMode.addItemWithWidth(deleteId, R.drawable.msg_delete, AndroidUtilities.dp(54), LocaleController.getString("Delete", R.string.Delete)); + + fragmentView = new FrameLayout(context); + FrameLayout frameLayout = (FrameLayout) fragmentView; + frameLayout.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + listView = new RecyclerListView(context); + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + adapter = new Adapter(); + adapter.setHasStableIds(true); + listView.setAdapter(adapter); + ((DefaultItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); + ((DefaultItemAnimator) listView.getItemAnimator()).setDelayAnimations(false); + listView.setLayoutManager(new LinearLayoutManager(context)); + listView.setOnItemClickListener((view, position) -> { + if (position == uploadRow) { + chatAttachAlert = new ChatAttachAlert(context, NotificationsSoundActivity.this, false, false); + chatAttachAlert.setSoundPicker(); + chatAttachAlert.init(); + chatAttachAlert.show(); + } + if (view instanceof ToneCell) { + ToneCell cell = (ToneCell) view; + if (actionBar.isActionModeShowed()) { + checkSelection(cell.tone); + return; + } + if (lastPlayedRingtone != null) { + lastPlayedRingtone.stop(); + } + if (cell.tone.isSystemDefault) { + Ringtone r = RingtoneManager.getRingtone(context.getApplicationContext(), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); + r.setStreamType(tonesStreamType); + lastPlayedRingtone = r; + r.play(); + } else if (cell.tone.uri != null && !cell.tone.fromServer) { + Ringtone r = RingtoneManager.getRingtone(context.getApplicationContext(), Uri.parse(cell.tone.uri)); + r.setStreamType(tonesStreamType); + lastPlayedRingtone = r; + r.play(); + } else if (cell.tone.fromServer) { + File file = null; + if (!TextUtils.isEmpty(cell.tone.uri)) { + File localUriFile = new File(cell.tone.uri); + if (localUriFile.exists()) { + file = localUriFile; + } + } + if (file == null) { + file = FileLoader.getPathToAttach(cell.tone.document); + } + if (file != null && file.exists()) { + Ringtone r = RingtoneManager.getRingtone(context.getApplicationContext(), Uri.parse(file.toString())); + r.setStreamType(tonesStreamType); + lastPlayedRingtone = r; + r.play(); + } else { + getFileLoader().loadFile(cell.tone.document, null, 2, 0); + } + } + startSelectedTone = null; + selectedTone = cell.tone; + selectedToneChanged = true; + adapter.notifyItemRangeChanged(0, adapter.getItemCount()); + checkDisabledBySystem(); + } + + }); + + listView.setOnItemLongClickListener((view, position) -> { + if (view instanceof ToneCell) { + ToneCell cell = (ToneCell) view; + checkSelection(cell.tone); + cell.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + } + return false; + }); + + loadTones(); + updateRows(); + return fragmentView; + } + + private void hideActionMode() { + selectedTones.clear(); + adapter.notifyItemRangeChanged(0, adapter.getItemCount()); + updateActionMode(); + } + + private void checkSelection(Tone tone) { + boolean changed = false; + if (selectedTones.get(tone.stableId) != null) { + selectedTones.remove(tone.stableId); + changed = true; + } else if (tone.fromServer) { + selectedTones.put(tone.stableId, tone); + changed = true; + } + if (changed) { + updateActionMode(); + adapter.notifyItemRangeChanged(0, adapter.getItemCount()); + } + } + + private void updateActionMode() { + if (selectedTones.size() > 0) { + selectedTonesCountTextView.setNumber(selectedTones.size(), actionBar.isActionModeShowed()); + actionBar.showActionMode(); + } else { + actionBar.hideActionMode(); + } + } + + private void loadTones() { + getMediaDataController().ringtoneDataStore.loadUserRingtones(); + for (int i = 0; i < getMediaDataController().ringtoneDataStore.userRingtones.size(); i++) { + RingtoneDataStore.CachedTone cachedTone = getMediaDataController().ringtoneDataStore.userRingtones.get(i); + Tone tone = new Tone(); + tone.stableId = stableIds++; + tone.fromServer = true; + tone.localId = cachedTone.localId; + tone.title = cachedTone.document.file_name_fixed; + tone.document = cachedTone.document; + trimTitle(tone); + + tone.uri = cachedTone.localUri; + + if (startSelectedTone != null && startSelectedTone.document != null && cachedTone.document != null && startSelectedTone.document.id == cachedTone.document.id) { + startSelectedTone = null; + selectedTone = tone; + } + + serverTones.add(tone); + } + + RingtoneManager manager = new RingtoneManager(ApplicationLoader.applicationContext); + manager.setType(RingtoneManager.TYPE_NOTIFICATION); + Cursor cursor = manager.getCursor(); + + systemTones.clear(); + + + Tone noSoundTone = new Tone(); + noSoundTone.stableId = stableIds++; + noSoundTone.title = LocaleController.getString("NoSound", R.string.NoSound); + noSoundTone.isSystemNoSound = true; + systemTones.add(noSoundTone); + + + Tone defaultTone = new Tone(); + defaultTone.stableId = stableIds++; + defaultTone.title = LocaleController.getString("DefaultRingtone", R.string.DefaultRingtone); + defaultTone.isSystemDefault = true; + systemTones.add(defaultTone); + + if (startSelectedTone != null && startSelectedTone.document == null && startSelectedTone.uri.equals("NoSound")) { + startSelectedTone = null; + selectedTone = noSoundTone; + } + + if (startSelectedTone != null && startSelectedTone.document == null && startSelectedTone.uri.equals("Default")) { + startSelectedTone = null; + selectedTone = defaultTone; + } + + while (cursor.moveToNext()) { + String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX); + String notificationUri = cursor.getString(RingtoneManager.URI_COLUMN_INDEX) + "/" + cursor.getString(RingtoneManager.ID_COLUMN_INDEX); + + Tone tone = new Tone(); + tone.stableId = stableIds++; + tone.title = notificationTitle; + tone.uri = notificationUri; + + if (startSelectedTone != null && startSelectedTone.document == null && startSelectedTone.uri.equals(notificationUri)) { + startSelectedTone = null; + selectedTone = tone; + } + + systemTones.add(tone); + } + if (getMediaDataController().ringtoneDataStore.isLoaded() && selectedTone == null) { + selectedTone = defaultTone; + selectedToneChanged = true; + } + updateRows(); + } + + private void updateRows() { + serverTonesHeaderRow = -1; + serverTonesStartRow = -1; + serverTonesEndRow = -1; + uploadRow = -1; + dividerRow = -1; + systemTonesHeaderRow = -1; + systemTonesStartRow = -1; + systemTonesEndRow = -1; + + rowCount = 0; + + serverTonesHeaderRow = rowCount++; + if (!serverTones.isEmpty()) { + serverTonesStartRow = rowCount; + rowCount += serverTones.size(); + serverTonesEndRow = rowCount; + } + uploadRow = rowCount++; + dividerRow = rowCount++; + + if (!systemTones.isEmpty()) { + systemTonesHeaderRow = rowCount++; + systemTonesStartRow = rowCount; + rowCount += systemTones.size(); + systemTonesEndRow = rowCount; + } + dividerRow2 = rowCount++; + } + + @Override + public void didSelectFiles(ArrayList files, String caption, ArrayList fmessages, boolean notify, int scheduleDate) { + for (int i = 0; i < files.size(); i++) { + getMediaDataController().uploadRingtone(files.get(i)); + } + getNotificationCenter().postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + + private class Adapter extends RecyclerListView.SelectionAdapter { + + @Override + public long getItemId(int position) { + Tone tone = getTone(position); + if (tone != null) { + return tone.stableId; + } + if (position == serverTonesHeaderRow) { + return 1; + } else if (position == systemTonesHeaderRow) { + return 2; + } else if (position == uploadRow) { + return 3; + } else if (position == dividerRow) { + return 4; + } else if (position == dividerRow2) { + return 5; + } else { + throw new RuntimeException(); + } + } + + private Tone getTone(int position) { + if (position >= systemTonesStartRow && position < systemTonesEndRow) { + return systemTones.get(position - systemTonesStartRow); + } + if (position >= serverTonesStartRow && position < serverTonesEndRow) { + return serverTones.get(position - serverTonesStartRow); + } + return null; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + Context context = parent.getContext(); + switch (viewType) { + case 0: + view = new ToneCell(context); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + default: + case 1: + view = new HeaderCell(context); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case 2: + CreationTextCell creationTextCell = new CreationTextCell(context); + creationTextCell.startPadding = 61; + view = creationTextCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case 3: + view = new ShadowSectionCell(context); + break; + } + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + switch (holder.getItemViewType()) { + case 0: + ToneCell toneCell = (ToneCell) holder.itemView; + Tone tone = null; + if (position >= systemTonesStartRow && position < systemTonesEndRow) { + tone = systemTones.get(position - systemTonesStartRow); + } + if (position >= serverTonesStartRow && position < serverTonesEndRow) { + tone = serverTones.get(position - serverTonesStartRow); + } + + if (tone != null) { + boolean animated = toneCell.tone == tone; + boolean checked = tone == selectedTone; + boolean selected = selectedTones.get(tone.stableId) != null; + toneCell.tone = tone; + toneCell.textView.setText(tone.title); + toneCell.needDivider = position != systemTonesEndRow - 1; + toneCell.radioButton.setChecked(checked, animated); + toneCell.checkBox.setChecked(selected, animated); + } + break; + case 1: + HeaderCell headerCell = (HeaderCell) holder.itemView; + if (position == serverTonesHeaderRow) { + headerCell.setText(LocaleController.getString("TelegramTones", R.string.TelegramTones)); + } else if (position == systemTonesHeaderRow) { + headerCell.setText(LocaleController.getString("SystemTones", R.string.SystemTones)); + } + break; + case 2: + CreationTextCell textCell = (CreationTextCell) holder.itemView; + Drawable drawable1 = textCell.getContext().getResources().getDrawable(R.drawable.poll_add_circle); + Drawable drawable2 = textCell.getContext().getResources().getDrawable(R.drawable.poll_add_plus); + drawable1.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_switchTrackChecked), PorterDuff.Mode.MULTIPLY)); + drawable2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_checkboxCheck), PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable = new CombinedDrawable(drawable1, drawable2); + textCell.setTextAndIcon(LocaleController.getString("UploadSound", R.string.UploadSound), combinedDrawable, false); + break; + } + } + + @Override + public int getItemViewType(int position) { + if (position >= systemTonesStartRow && position < systemTonesEndRow) { + return 0; + } else if (position == serverTonesHeaderRow || position == systemTonesHeaderRow) { + return 1; + } else if (position == uploadRow) { + return 2; + } else if (position == dividerRow || position == dividerRow2) { + return 3; + } + + return super.getItemViewType(position); + } + + @Override + public int getItemCount() { + return rowCount; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == 0 || holder.getItemViewType() == 2; + } + } + + private static class ToneCell extends FrameLayout { + private TextView textView; + public TextView valueTextView; + private RadioButton radioButton; + private CheckBox2 checkBox; + private boolean needDivider; + + Tone tone; + + public ToneCell(Context context) { + super(context); + + radioButton = new RadioButton(context); + radioButton.setSize(AndroidUtilities.dp(20)); + radioButton.setColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_radioBackgroundChecked)); + addView(radioButton, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, (LocaleController.isRTL ? 0 : 20), 0, (LocaleController.isRTL ? 20 : 0), 0)); + + + checkBox = new CheckBox2(context, 24); + checkBox.setColor(null, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck); + checkBox.setDrawUnchecked(false); + checkBox.setDrawBackgroundAsArc(3); + addView(checkBox, LayoutHelper.createFrame(26, 26, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, (LocaleController.isRTL ? 0 : 18), 0, (LocaleController.isRTL ? 18 : 0), 0)); + checkBox.setChecked(true, false); + + textView = new TextView(context); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, (LocaleController.isRTL ? 23 : 61), 0, (LocaleController.isRTL ? 61 : 23), 0)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); + } + + @Override + protected void onDraw(Canvas canvas) { + if (needDivider) { + canvas.drawLine(AndroidUtilities.dp(LocaleController.isRTL ? 0 : 60), getHeight() - 1, getMeasuredWidth() - AndroidUtilities.dp(LocaleController.isRTL ? 60 : 0), getHeight() - 1, Theme.dividerPaint); + } + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName("android.widget.RadioButton"); + info.setCheckable(true); + info.setChecked(radioButton.isChecked()); + } + } + + @Override + public void onResume() { + super.onResume(); + getNotificationCenter().addObserver(this, NotificationCenter.onUserRingtonesUpdated); + } + + @Override + public void onPause() { + super.onPause(); + getNotificationCenter().removeObserver(this, NotificationCenter.onUserRingtonesUpdated); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.onUserRingtonesUpdated) { + HashMap currentTones = new HashMap<>(); + for (int i = 0; i < serverTones.size(); i++) { + currentTones.put(serverTones.get(i).localId, serverTones.get(i)); + } + serverTones.clear(); + for (int i = 0; i < getMediaDataController().ringtoneDataStore.userRingtones.size(); i++) { + RingtoneDataStore.CachedTone cachedTone = getMediaDataController().ringtoneDataStore.userRingtones.get(i); + Tone tone = new Tone(); + Tone currentTone = currentTones.get(cachedTone.localId); + if (currentTone != null) { + if (currentTone == selectedTone) { + selectedTone = tone; + } + tone.stableId = currentTone.stableId; + } else { + tone.stableId = stableIds++; + } + tone.fromServer = true; + tone.localId = cachedTone.localId; + if (cachedTone.document != null) { + tone.title = cachedTone.document.file_name_fixed; + } else { + tone.title = new File(cachedTone.localUri).getName(); + } + tone.document = cachedTone.document; + trimTitle(tone); + tone.uri = cachedTone.localUri; + + if (startSelectedTone != null && startSelectedTone.document != null && cachedTone.document != null && startSelectedTone.document.id == cachedTone.document.id) { + startSelectedTone = null; + selectedTone = tone; + } + + serverTones.add(tone); + } + updateRows(); + adapter.notifyDataSetChanged(); + + if (getMediaDataController().ringtoneDataStore.isLoaded() && selectedTone == null && systemTones.size() > 0) { + startSelectedTone = null; + selectedTone = systemTones.get(0); + } + } + } + + private void trimTitle(Tone tone) { + tone.title = trimTitle(tone.document, tone.title); + } + + public static String trimTitle(TLRPC.Document document, String title) { + if (title != null) { + int idx = title.lastIndexOf('.'); + if (idx != -1) { + title = title.substring(0, idx); + } + } + if (TextUtils.isEmpty(title) && document != null) { + title = LocaleController.formatString("SoundNameEmpty", R.string.SoundNameEmpty, LocaleController.formatDateChat(document.date, true)); + } + return title; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + if (selectedTone != null && selectedToneChanged) { + SharedPreferences preferences = getNotificationsSettings(); + SharedPreferences.Editor editor = preferences.edit(); + + String prefName; + String prefPath; + String prefDocId; + + if (dialogId != 0) { + prefName = "sound_" + dialogId; + prefPath = "sound_path_" + dialogId; + prefDocId = "sound_document_id_" + dialogId; + editor.putBoolean("sound_enabled_" + dialogId, true); + } else { + if (currentType == NotificationsController.TYPE_PRIVATE) { + prefName = "GlobalSound"; + prefPath = "GlobalSoundPath"; + prefDocId = "GlobalSoundDocId"; + } else if (currentType == NotificationsController.TYPE_GROUP) { + prefName = "GroupSound"; + prefPath = "GroupSoundPath"; + prefDocId = "GroupSoundDocId"; + } else if (currentType == NotificationsController.TYPE_CHANNEL) { + prefName = "ChannelSound"; + prefPath = "ChannelSoundPath"; + prefDocId = "ChannelSoundDocId"; + } else { + throw new RuntimeException("Unsupported type"); + } + } + + if (selectedTone.fromServer && selectedTone.document != null) { + editor.putLong(prefDocId, selectedTone.document.id); + editor.putString(prefName, selectedTone.title); + editor.putString(prefPath, "NoSound"); + } else if (selectedTone.uri != null) { + editor.putString(prefName, selectedTone.title); + editor.putString(prefPath, selectedTone.uri); + editor.remove(prefDocId); + } else if (selectedTone.isSystemDefault) { + editor.putString(prefName, "Default"); + editor.putString(prefPath, "Default"); + editor.remove(prefDocId); + } else { + editor.putString(prefName, "NoSound"); + editor.putString(prefPath, "NoSound"); + editor.remove(prefDocId); + } + + editor.apply(); + if (dialogId != 0) { + getNotificationsController().updateServerNotificationsSettings(dialogId); + } else { + getNotificationsController().updateServerNotificationsSettings(currentType); + getNotificationCenter().postNotificationName(NotificationCenter.notificationsSettingsUpdated); + } + } + } + + public void startDocumentSelectActivity() { + try { + Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT); + if (Build.VERSION.SDK_INT >= 18) { + photoPickerIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); + } + photoPickerIntent.setType("audio/mpeg"); + startActivityForResult(photoPickerIntent, 21); + } catch (Exception e) { + FileLog.e(e); + } + } + + @Override + public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { + if (requestCode == 21) { + if (data == null) { + return; + } + + if (chatAttachAlert != null) { + boolean apply = false; + if (data.getData() != null) { + String path = AndroidUtilities.getPath(data.getData()); + if (path != null) { + File file = new File(path); + if (chatAttachAlert.getDocumentLayout().isRingtone(file)) { + apply = true; + getMediaDataController().uploadRingtone(path); + getNotificationCenter().postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + } + } else if (data.getClipData() != null) { + ClipData clipData = data.getClipData(); + for (int i = 0; i < clipData.getItemCount(); i++) { + String path = clipData.getItemAt(i).getUri().toString(); + if (chatAttachAlert.getDocumentLayout().isRingtone(new File(path))) { + apply = true; + getMediaDataController().uploadRingtone(path); + getNotificationCenter().postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + } + } + if (apply) { + chatAttachAlert.dismiss(); + } + } + } + } + + private static class Tone { + public boolean fromServer; + boolean isSystemDefault; + boolean isSystemNoSound; + int stableId; + int localId; + TLRPC.Document document; + String title; + String uri; + + public Uri getUriForShare(int currentAccount) { + if (! TextUtils.isEmpty(uri)) { + return Uri.fromFile(new File(uri)); + } + if (document != null) { + String fileName = document.file_name_fixed; + String ext = FileLoader.getDocumentExtension(document); + if (ext != null) { + ext = ext.toLowerCase(); + if (!fileName.endsWith(ext)) { + fileName += "." + ext; + } + File file = new File(AndroidUtilities.getCacheDir(), fileName); + if (!file.exists()) { + try { + AndroidUtilities.copyFile(FileLoader.getPathToAttach(document), file); + } catch (IOException e) { + e.printStackTrace(); + } + } + return Uri.fromFile(file); + } + } + + return null; + } + } + + private void checkDisabledBySystem() { + NotificationManager manager = (NotificationManager) ApplicationLoader.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); + boolean notificationsEnabled = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + notificationsEnabled = manager.areNotificationsEnabled(); + } +// if (!notificationsEnabled) { +// BulletinFactory.of(this).createErrorBulletin(LocaleController.getString()).show(); +// } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java index 6997a3a0b..0f8f6bfdb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java @@ -6861,30 +6861,11 @@ public class PassportActivity extends BaseFragment implements NotificationCenter processSelectedAttach(button); } - @Override - public View getRevealView() { - return null; - } - - @Override - public void didSelectBot(TLRPC.User user) { - - } - @Override public void onCameraOpened() { AndroidUtilities.hideKeyboard(fragmentView.findFocus()); } - @Override - public boolean needEnterComment() { - return false; - } - - @Override - public void doOnIdle(Runnable runnable) { - runnable.run(); - } }); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java index 69d6b545e..f348b4d8e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java @@ -1223,6 +1223,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen public final String[] PREFIXES_14 = {"300", "301", "302", "303", "304", "305", "309", "36", "38", "39"}; public final String[] PREFIXES_16 = { "2221", "2222", "2223", "2224", "2225", "2226", "2227", "2228", "2229", + "2200", "2201", "2202", "2203", "2204", "223", "224", "225", "226", "227", "228", "229", "23", "24", "25", "26", "270", "271", "2720", diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java index 04bba9e58..1d7a50805 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java @@ -28,6 +28,12 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; @@ -58,11 +64,6 @@ import org.telegram.ui.Components.UndoView; import java.util.ArrayList; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.DiffUtil; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - public class PeopleNearbyActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, LocationController.LocationFetchCallback { private ListAdapter listViewAdapter; @@ -314,9 +315,6 @@ public class PeopleNearbyActivity extends BaseFragment implements NotificationCe actionBar.setOccupyStatusBar(Build.VERSION.SDK_INT >= 21 && !AndroidUtilities.isTablet()); actionBar.setTitle(LocaleController.getString("PeopleNearby", R.string.PeopleNearby)); actionBar.getTitleTextView().setAlpha(0.0f); - if (!AndroidUtilities.isTablet()) { - actionBar.showActionModeTop(); - } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -1053,6 +1051,12 @@ public class PeopleNearbyActivity extends BaseFragment implements NotificationCe } } + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + return ColorUtils.calculateLuminance(color) > 0.7f; + } + @Override public ArrayList getThemeDescriptions() { ArrayList themeDescriptions = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 9e59065f8..a5a8eaa60 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -29,6 +29,7 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; +import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; @@ -48,28 +49,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.os.Vibrator; import android.provider.Settings; -import androidx.annotation.Keep; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.collection.ArrayMap; -import androidx.core.content.ContextCompat; -import androidx.core.content.FileProvider; -import androidx.core.graphics.ColorUtils; -import androidx.core.graphics.Insets; -import androidx.core.view.ViewCompat; -import androidx.core.view.WindowInsetsCompat; -import androidx.core.widget.NestedScrollView; -import androidx.dynamicanimation.animation.DynamicAnimation; -import androidx.dynamicanimation.animation.SpringAnimation; -import androidx.dynamicanimation.animation.SpringForce; -import androidx.exifinterface.media.ExifInterface; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.LinearSmoothScrollerEnd; -import androidx.recyclerview.widget.RecyclerView; - import android.text.Layout; -import android.text.Selection; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; @@ -77,8 +57,6 @@ import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; -import android.text.method.LinkMovementMethod; -import android.text.method.Touch; import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.transition.ChangeBounds; @@ -88,7 +66,6 @@ import android.transition.TransitionManager; import android.transition.TransitionSet; import android.transition.TransitionValues; import android.util.FloatProperty; -import android.util.Log; import android.util.Property; import android.util.Range; import android.util.SparseArray; @@ -107,7 +84,7 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.ViewPropertyAnimator; +import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.WindowManager; @@ -125,6 +102,24 @@ import android.widget.Scroller; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.collection.ArrayMap; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import androidx.core.graphics.ColorUtils; +import androidx.core.view.ViewCompat; +import androidx.core.widget.NestedScrollView; +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; +import androidx.exifinterface.media.ExifInterface; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScrollerEnd; +import androidx.recyclerview.widget.RecyclerView; + import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.analytics.AnalyticsListener; @@ -134,6 +129,7 @@ import com.google.android.gms.vision.face.Face; import com.google.android.gms.vision.face.FaceDetector; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Bitmaps; import org.telegram.messenger.BringAppForegroundService; import org.telegram.messenger.BuildConfig; @@ -142,33 +138,36 @@ import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.DownloadController; -import org.telegram.messenger.MediaDataController; import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; import org.telegram.messenger.SecureDocument; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.WebFile; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.FileLoader; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.R; import org.telegram.messenger.browser.Browser; import org.telegram.messenger.video.VideoPlayerRewinder; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.UserConfig; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; @@ -178,9 +177,6 @@ import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.MentionsAdapter; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.ActionBarMenu; -import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.PhotoPickerPhotoCell; import org.telegram.ui.Components.AlertsCreator; @@ -192,7 +188,6 @@ import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.CheckBox; import org.telegram.ui.Components.ClippingImageView; -import org.telegram.messenger.ImageReceiver; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.Crop.CropTransform; import org.telegram.ui.Components.Crop.CropView; @@ -204,6 +199,8 @@ import org.telegram.ui.Components.GestureDetector2; import org.telegram.ui.Components.GroupedPhotosListView; import org.telegram.ui.Components.HideViewAfterAnimation; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.NumberPicker; import org.telegram.ui.Components.OtherDocumentPlaceholderDrawable; @@ -214,7 +211,7 @@ import org.telegram.ui.Components.PhotoPaintView; import org.telegram.ui.Components.PhotoViewerCaptionEnterView; import org.telegram.ui.Components.PhotoViewerWebView; import org.telegram.ui.Components.PickerBottomLayoutViewer; -import org.telegram.ui.Components.PipVideoView; +import org.telegram.ui.Components.PipVideoOverlay; import org.telegram.ui.Components.PlayPauseDrawable; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RadialProgressView; @@ -250,6 +247,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +@SuppressLint("WrongConstant") @SuppressWarnings("unchecked") public class PhotoViewer implements NotificationCenter.NotificationCenterDelegate, GestureDetector2.OnGestureListener, GestureDetector2.OnDoubleTapListener { @@ -288,6 +286,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private static final int PROGRESS_PAUSE = 4; private static Drawable[] progressDrawables; + private static final int EDIT_MODE_NONE = 0; + private static final int EDIT_MODE_CROP = 1; + private static final int EDIT_MODE_FILTER = 2; + private static final int EDIT_MODE_PAINT = 3; + + private int videoWidth, videoHeight; + private float inlineOutAnimationProgress; + private WindowManager.LayoutParams windowLayoutParams; private FrameLayoutDrawer containerView; private PhotoViewerWebView photoViewerWebView; @@ -359,6 +365,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private AnimatorSet currentListViewAnimation; private PhotoCropView photoCropView; private CropTransform cropTransform = new CropTransform(); + private CropTransform leftCropTransform = new CropTransform(); + private CropTransform rightCropTransform = new CropTransform(); + private MediaController.CropState leftCropState; + private MediaController.CropState rightCropState; private PhotoFilterView photoFilterView; private PhotoPaintView photoPaintView; private AlertDialog visibleDialog; @@ -465,7 +475,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private VideoSeekPreviewImage videoPreviewFrame; private AnimatorSet videoPreviewFrameAnimation; private boolean needShowOnReady; - private PipVideoView pipVideoView; private int waitingForDraw; private TextureView changedTextureView; private ImageView textureImageView; @@ -571,6 +580,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public void setCaption(CharSequence caption) { hasCaptionForAllMedia = true; captionForAllMedia = caption; + setCurrentCaption(null, caption, false); + updateCaptionTextForCurrentPhoto(null); } private static class SavedVideoPosition { @@ -584,194 +595,130 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - private class CaptionLinkMovementMethod extends LinkMovementMethod { - ClickableSpan selectedLink; - TextView selectedWidget; - Runnable longPressRunnable = new Runnable() { - @Override - public void run() { - if (selectedWidget != null && selectedLink instanceof URLSpan) { - onLongClick((URLSpan) selectedLink); - selectedLink = null; - } - } - }; - - @Override - public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer, @NonNull MotionEvent event) { - try { - if (!imagesArrLocals.isEmpty()) { - return false; - } - int action = event.getAction(); - boolean result = false; - - if (action == MotionEvent.ACTION_CANCEL) { - AndroidUtilities.cancelRunOnUIThread(longPressRunnable); - selectedLink = null; - } - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class); - - if (links.length != 0) { - ClickableSpan link = links[0]; - if (action == MotionEvent.ACTION_UP) { - if (selectedLink != link) { - selectedLink = null; - return false; - } - onClick(link, widget); - AndroidUtilities.cancelRunOnUIThread(longPressRunnable); - selectedLink = null; - } else { // action == MotionEvent.ACTION_DOWN - Selection.setSelection(buffer, buffer.getSpanStart(link), buffer.getSpanEnd(link)); - AndroidUtilities.runOnUIThread(longPressRunnable, ViewConfiguration.getLongPressTimeout()); - selectedLink = link; - selectedWidget = widget; - } - result = true; + private void onLinkClick(ClickableSpan link, TextView widget) { + if (widget != null && link instanceof URLSpan) { + String url = ((URLSpan) link).getURL(); + if (url.startsWith("video")) { + if (videoPlayer != null && currentMessageObject != null) { + int seconds = Utilities.parseInt(url); + if (videoPlayer.getDuration() == C.TIME_UNSET) { + seekToProgressPending = seconds / (float) currentMessageObject.getDuration(); } else { - Selection.removeSelection(buffer); - AndroidUtilities.cancelRunOnUIThread(longPressRunnable); - selectedLink = null; + videoPlayer.seekTo(seconds * 1000L); + videoPlayerSeekbar.setProgress(seconds * 1000L / (float) videoPlayer.getDuration(), true); + videoPlayerSeekbarView.invalidate(); } } - - return result || Touch.onTouchEvent(widget, buffer, event); - } catch (Exception e) { - FileLog.e(e); - } - return false; - } - - private void onClick(ClickableSpan link, TextView widget) { - if (widget != null && link instanceof URLSpan) { - String url = ((URLSpan) link).getURL(); - if (url.startsWith("video")) { - if (videoPlayer != null && currentMessageObject != null) { - int seconds = Utilities.parseInt(url); - if (videoPlayer.getDuration() == C.TIME_UNSET) { - seekToProgressPending = seconds / (float) currentMessageObject.getDuration(); - } else { - videoPlayer.seekTo(seconds * 1000L); - videoPlayerSeekbar.setProgress(seconds * 1000L / (float) videoPlayer.getDuration(), true); - videoPlayerSeekbarView.invalidate(); - } - } - } else if (url.startsWith("#")) { - if (parentActivity instanceof LaunchActivity) { - DialogsActivity fragment = new DialogsActivity(null); - fragment.setSearchString(url); - ((LaunchActivity) parentActivity).presentFragment(fragment, false, true); - closePhoto(false, false); - } - } else if (parentChatActivity != null && (link instanceof URLSpanReplacement || AndroidUtilities.shouldShowUrlInAlert(url))) { - AlertsCreator.showOpenUrlAlert(parentChatActivity, url, true, true); - } else { - link.onClick(widget); + } else if (url.startsWith("#")) { + if (parentActivity instanceof LaunchActivity) { + DialogsActivity fragment = new DialogsActivity(null); + fragment.setSearchString(url); + ((LaunchActivity) parentActivity).presentFragment(fragment, false, true); + closePhoto(false, false); } + } else if (parentChatActivity != null && (link instanceof URLSpanReplacement || AndroidUtilities.shouldShowUrlInAlert(url))) { + AlertsCreator.showOpenUrlAlert(parentChatActivity, url, true, true); } else { link.onClick(widget); } + } else { + link.onClick(widget); } + } - private void onLongClick(URLSpan link) { - int timestamp = -1; - BottomSheet.Builder builder = new BottomSheet.Builder(parentActivity, false, resourcesProvider); - if (link.getURL().startsWith("video?")) { - try { - String timestampStr = link.getURL().substring(link.getURL().indexOf('?') + 1); - timestamp = Integer.parseInt(timestampStr); - } catch (Throwable ignore) { + private void onLinkLongPress(URLSpan link, TextView widget, Runnable onDismiss) { + int timestamp = -1; + BottomSheet.Builder builder = new BottomSheet.Builder(parentActivity, false, resourcesProvider); + if (link.getURL().startsWith("video?")) { + try { + String timestampStr = link.getURL().substring(link.getURL().indexOf('?') + 1); + timestamp = Integer.parseInt(timestampStr); + } catch (Throwable ignore) { - } } - if (timestamp >= 0) { - builder.setTitle(AndroidUtilities.formatDuration(timestamp, false)); - } else { - builder.setTitle(link.getURL()); - } - final int finalTimestamp = timestamp; - builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { - if (which == 0) { - onClick(link, selectedWidget); - } else if (which == 1) { - String url1 = link.getURL(); - boolean tel = false; - if (url1.startsWith("mailto:")) { - url1 = url1.substring(7); - } else if (url1.startsWith("tel:")) { - url1 = url1.substring(4); - tel = true; - } else if (finalTimestamp >= 0) { - if (currentMessageObject != null && !currentMessageObject.scheduled) { - MessageObject messageObject1 = currentMessageObject; - boolean isMedia = currentMessageObject.isVideo() || currentMessageObject.isRoundVideo() || currentMessageObject.isVoice() || currentMessageObject.isMusic(); - if (!isMedia && currentMessageObject.replyMessageObject != null) { - messageObject1 = currentMessageObject.replyMessageObject; - } - long dialogId = messageObject1.getDialogId(); - int messageId = messageObject1.getId(); + } + if (timestamp >= 0) { + builder.setTitle(AndroidUtilities.formatDuration(timestamp, false)); + } else { + builder.setTitle(link.getURL()); + } + final int finalTimestamp = timestamp; + builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { + if (which == 0) { + onLinkClick(link, widget); + } else if (which == 1) { + String url1 = link.getURL(); + boolean tel = false; + if (url1.startsWith("mailto:")) { + url1 = url1.substring(7); + } else if (url1.startsWith("tel:")) { + url1 = url1.substring(4); + tel = true; + } else if (finalTimestamp >= 0) { + if (currentMessageObject != null && !currentMessageObject.scheduled) { + MessageObject messageObject1 = currentMessageObject; + boolean isMedia = currentMessageObject.isVideo() || currentMessageObject.isRoundVideo() || currentMessageObject.isVoice() || currentMessageObject.isMusic(); + if (!isMedia && currentMessageObject.replyMessageObject != null) { + messageObject1 = currentMessageObject.replyMessageObject; + } + long dialogId = messageObject1.getDialogId(); + int messageId = messageObject1.getId(); - if (messageObject1.messageOwner.fwd_from != null) { - if (messageObject1.messageOwner.fwd_from.saved_from_peer != null) { - dialogId = MessageObject.getPeerId(messageObject1.messageOwner.fwd_from.saved_from_peer); - messageId = messageObject1.messageOwner.fwd_from.saved_from_msg_id; - } else if (messageObject1.messageOwner.fwd_from.from_id != null) { - dialogId = MessageObject.getPeerId(messageObject1.messageOwner.fwd_from.from_id); - messageId = messageObject1.messageOwner.fwd_from.channel_post; - } + if (messageObject1.messageOwner.fwd_from != null) { + if (messageObject1.messageOwner.fwd_from.saved_from_peer != null) { + dialogId = MessageObject.getPeerId(messageObject1.messageOwner.fwd_from.saved_from_peer); + messageId = messageObject1.messageOwner.fwd_from.saved_from_msg_id; + } else if (messageObject1.messageOwner.fwd_from.from_id != null) { + dialogId = MessageObject.getPeerId(messageObject1.messageOwner.fwd_from.from_id); + messageId = messageObject1.messageOwner.fwd_from.channel_post; } + } - if (DialogObject.isChatDialog(dialogId)) { - TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - if (currentChat != null && currentChat.username != null) { - url1 = "https://t.me/" + currentChat.username + "/" + messageId + "?t=" + finalTimestamp; - } - } else { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - if (user != null && user.username != null) { - url1 = "https://t.me/" + user.username + "/" + messageId + "?t=" + finalTimestamp; - } + if (DialogObject.isChatDialog(dialogId)) { + TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (currentChat != null && currentChat.username != null) { + url1 = "https://t.me/" + currentChat.username + "/" + messageId + "?t=" + finalTimestamp; + } + } else { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (user != null && user.username != null) { + url1 = "https://t.me/" + user.username + "/" + messageId + "?t=" + finalTimestamp; } } } - AndroidUtilities.addToClipboard(url1); - String bulletinMessage; - if (tel) { - bulletinMessage = LocaleController.getString("PhoneCopied", R.string.PhoneCopied); - } else if (url1.startsWith("#")) { - bulletinMessage = LocaleController.getString("HashtagCopied", R.string.HashtagCopied); - } else if (url1.startsWith("@")) { - bulletinMessage = LocaleController.getString("UsernameCopied", R.string.UsernameCopied); - } else { - bulletinMessage = LocaleController.getString("LinkCopied", R.string.LinkCopied); - } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { - BulletinFactory.of(containerView, resourcesProvider).createSimpleBulletin(R.raw.voip_invite, bulletinMessage).show(); - } } - }); - BottomSheet bottomSheet = builder.create(); - bottomSheet.show(); - bottomSheet.setItemColor(0,0xffffffff, 0xffffffff); - bottomSheet.setItemColor(1,0xffffffff, 0xffffffff); - bottomSheet.setBackgroundColor(0xff1C2229); - bottomSheet.setTitleColor(0xff8A8A8A); - } + AndroidUtilities.addToClipboard(url1); + String bulletinMessage; + if (tel) { + bulletinMessage = LocaleController.getString("PhoneCopied", R.string.PhoneCopied); + } else if (url1.startsWith("#")) { + bulletinMessage = LocaleController.getString("HashtagCopied", R.string.HashtagCopied); + } else if (url1.startsWith("@")) { + bulletinMessage = LocaleController.getString("UsernameCopied", R.string.UsernameCopied); + } else { + bulletinMessage = LocaleController.getString("LinkCopied", R.string.LinkCopied); + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + BulletinFactory.of(containerView, resourcesProvider).createSimpleBulletin(R.raw.voip_invite, bulletinMessage).show(); + } + } + }); + builder.setOnPreDismissListener(di -> onDismiss.run()); + BottomSheet bottomSheet = builder.create(); + bottomSheet.scrollNavBar = true; + bottomSheet.show(); + try { + containerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) {} + bottomSheet.setItemColor(0,0xffffffff, 0xffffffff); + bottomSheet.setItemColor(1,0xffffffff, 0xffffffff); + bottomSheet.setBackgroundColor(0xff1C2229); + bottomSheet.setTitleColor(0xff8A8A8A); + bottomSheet.setCalcMandatoryInsets(true); + bottomSheet.setOverlayNavBarColor(0xff1C2229); + AndroidUtilities.setNavigationBarColor(bottomSheet.getWindow(), 0xff1C2229, false); + AndroidUtilities.setLightNavigationBar(bottomSheet.getWindow(), false); + bottomSheet.scrollNavBar = true; } private void cancelFlashAnimations() { @@ -805,13 +752,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (shownControlsByEnd && !actionBarWasShownBeforeByEnd) { progress = 0; } - if (!inPreview && (currentEditMode != 0 || videoTimelineView.getVisibility() == View.VISIBLE)) { + if (!inPreview && (currentEditMode != EDIT_MODE_NONE || videoTimelineView.getVisibility() == View.VISIBLE)) { if (progress >= videoTimelineView.getRightProgress()) { videoTimelineView.setProgress(videoTimelineView.getLeftProgress()); videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); manuallyPaused = false; cancelVideoPlayRunnable(); - if (muteVideo || sendPhotoType == SELECT_TYPE_AVATAR || currentEditMode != 0 || switchingToMode > 0) { + if (muteVideo || sendPhotoType == SELECT_TYPE_AVATAR || currentEditMode != EDIT_MODE_NONE || switchingToMode > 0) { videoPlayer.play(); } else { videoPlayer.pause(); @@ -866,9 +813,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (bufferedProgress != -1) { videoPlayerSeekbar.setBufferedProgress(bufferedProgress); - if (pipVideoView != null) { - pipVideoView.setBufferedProgress(bufferedProgress); - } + PipVideoOverlay.setBufferedProgress(bufferedProgress); } } videoPlayerSeekbarView.invalidate(); @@ -911,6 +856,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private Runnable switchToInlineRunnable = new Runnable() { @Override public void run() { + if (PipVideoOverlay.isVisible()) { + PipVideoOverlay.dismiss(); + AndroidUtilities.runOnUIThread(this, 250); + return; + } + switchingInlineMode = false; if (currentBitmap != null) { currentBitmap.recycle(); @@ -940,8 +891,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat isInline = true; - pipVideoView = new PipVideoView(false); - changedTextureView = pipVideoView.show(parentActivity, PhotoViewer.this, aspectRatioFrameLayout.getAspectRatio(), aspectRatioFrameLayout.getVideoRotation()); + changedTextureView = new TextureView(parentActivity); + if (PipVideoOverlay.show(false, parentActivity, changedTextureView, videoWidth, videoHeight, true)) { + PipVideoOverlay.setPhotoViewer(PhotoViewer.this); + } changedTextureView.setVisibility(View.INVISIBLE); aspectRatioFrameLayout.removeView(videoTextureView); } @@ -984,11 +937,22 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public boolean onPreDraw() { changedTextureView.getViewTreeObserver().removeOnPreDrawListener(this); if (textureImageView != null) { - textureImageView.setVisibility(View.INVISIBLE); - textureImageView.setImageDrawable(null); - if (currentBitmap != null) { - currentBitmap.recycle(); - currentBitmap = null; + if (isInline) { + AndroidUtilities.runOnUIThread(()-> { + textureImageView.setVisibility(View.INVISIBLE); + textureImageView.setImageDrawable(null); + if (currentBitmap != null) { + currentBitmap.recycle(); + currentBitmap = null; + } + }, 300); + } else { + textureImageView.setVisibility(View.INVISIBLE); + textureImageView.setImageDrawable(null); + if (currentBitmap != null) { + currentBitmap.recycle(); + currentBitmap = null; + } } } AndroidUtilities.runOnUIThread(() -> { @@ -1094,11 +1058,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private int currentImageHasFace; private String currentImageFaceKey; private PaintingOverlay paintingOverlay; + private PaintingOverlay leftPaintingOverlay; + private PaintingOverlay rightPaintingOverlay; private ImageReceiver leftImage = new ImageReceiver(); private ImageReceiver centerImage = new ImageReceiver(); + private ImageReceiver rightImage = new ImageReceiver(); + private boolean leftImageIsVideo; + private boolean centerImageIsVideo; + private boolean rightImageIsVideo; private Paint videoFrameBitmapPaint = new Paint(); private Bitmap videoFrameBitmap = null; - private ImageReceiver rightImage = new ImageReceiver(); private int currentIndex; private int switchingToIndex; private MessageObject currentMessageObject; @@ -1991,7 +1960,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onPanTranslationUpdate(float y, float progress, boolean keyboardVisible) { currentPanTranslationY = y; - if (currentEditMode != 3) { + if (currentEditMode != EDIT_MODE_PAINT) { actionBar.setTranslationY(y); } if (miniProgressView != null) { @@ -2029,7 +1998,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat pickerViewSendButton.setTranslationY(y); } - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { if (captionEditText != null) { captionEditText.setTranslationY(y); } @@ -2065,7 +2034,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onTransitionStart(boolean keyboardVisible, int contentHeight) { - windowView.setClipChildren(false); + navigationBar.setVisibility(View.INVISIBLE); + animateNavBarColorTo(0xff000000); if (captionEditText.getTag() != null && keyboardVisible) { if (isCurrentVideo) { CharSequence title = muteVideo ? LocaleController.getString("GifCaption", R.string.GifCaption) : LocaleController.getString("VideoCaption", R.string.VideoCaption); @@ -2093,7 +2063,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onTransitionEnd() { super.onTransitionEnd(); - windowView.setClipChildren(false); + navigationBar.setVisibility(currentEditMode == EDIT_MODE_NONE || currentEditMode == EDIT_MODE_CROP ? View.VISIBLE : View.INVISIBLE); if (captionEditText.getTag() == null) { captionEditText.setVisibility(View.GONE); } @@ -2109,8 +2079,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public FrameLayoutDrawer(Context context) { super(context, false); setWillNotDraw(false); - setClipChildren(false); - setClipToPadding(false); paint.setColor(0x33000000); } @@ -2233,7 +2201,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onLayout(boolean changed, int _l, int t, int _r, int _b) { final int count = getChildCount(); - int keyboardHeight = getKeyboardHeight(); + int keyboardHeight = measureKeyboardHeight(); keyboardSize = keyboardHeight; int paddingBottom = keyboardHeight <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow ? captionEditText.getEmojiPadding() : 0; @@ -2348,9 +2316,28 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + canvas.clipRect(0, 0, getWidth(), getHeight()); + super.dispatchDraw(canvas); + canvas.restore(); + } + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child != navigationBar) { + canvas.save(); + canvas.clipRect(0, 0, getWidth(), getHeight()); + } + boolean result = this.drawChildInternal(canvas, child, drawingTime); + if (child != navigationBar) { + canvas.restore(); + } + return result; + } + + protected boolean drawChildInternal(Canvas canvas, View child, long drawingTime) { if (child == mentionListView || child == captionEditText) { - if (currentEditMode != 0 && currentPanTranslationY == 0) { + if (currentEditMode != EDIT_MODE_NONE && currentPanTranslationY == 0) { return false; } else if (AndroidUtilities.isInMultiwindow || AndroidUtilities.usingHardwareInput) { if (!captionEditText.isPopupShowing() && captionEditText.getEmojiPadding() == 0 && captionEditText.getTag() == null) { @@ -2368,7 +2355,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canvas.restore(); return r; } - } else if (child == cameraItem || child == muteItem || child == pickerView || child == videoTimelineView || child == pickerViewSendButton || child == captionLimitView || child == captionTextViewSwitcher || muteItem.getVisibility() == VISIBLE && child == bottomLayout || child == navigationBar) { + } else if (child == cameraItem || child == muteItem || child == pickerView || child == videoTimelineView || child == pickerViewSendButton || child == captionLimitView || child == captionTextViewSwitcher || muteItem.getVisibility() == VISIBLE && child == bottomLayout) { if (captionEditText.isPopupAnimating()) { child.setTranslationY(captionEditText.getEmojiPadding()); bottomTouchEnabled = false; @@ -3124,9 +3111,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (bufferedProgress != -1) { videoPlayerSeekbar.setBufferedProgress(bufferedProgress); - if (pipVideoView != null) { - pipVideoView.setBufferedProgress(bufferedProgress); - } + PipVideoOverlay.setBufferedProgress(bufferedProgress); videoPlayerSeekbarView.invalidate(); } checkBufferedProgress(loadProgress); @@ -3676,6 +3661,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ViewGroup.LayoutParams layoutParams = animatingImageView.getLayoutParams(); animatingImageView.measure(MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.AT_MOST)); containerView.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY)); + navigationBar.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(navigationBarHeight, MeasureSpec.EXACTLY)); } @SuppressWarnings("DrawAllocation") @@ -3683,6 +3669,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat protected void onLayout(boolean changed, int left, int top, int right, int bottom) { animatingImageView.layout(getPaddingLeft(), 0, getPaddingLeft() + animatingImageView.getMeasuredWidth(), animatingImageView.getMeasuredHeight()); containerView.layout(getPaddingLeft(), 0, getPaddingLeft() + containerView.getMeasuredWidth(), containerView.getMeasuredHeight()); + navigationBar.layout(getPaddingLeft(), containerView.getMeasuredHeight(), navigationBar.getMeasuredWidth(), containerView.getMeasuredHeight() + navigationBar.getMeasuredHeight()); wasLayout = true; if (changed) { if (!dontResetZoomOnFirstLayout) { @@ -3721,12 +3708,18 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + centerImage.onAttachedToWindow(); + leftImage.onAttachedToWindow(); + rightImage.onAttachedToWindow(); attachedToWindow = true; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + centerImage.onDetachedFromWindow(); + leftImage.onDetachedFromWindow(); + rightImage.onDetachedFromWindow(); attachedToWindow = false; wasLayout = false; } @@ -3780,11 +3773,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView = new FrameLayoutDrawer(activity); containerView.setFocusable(false); - //TODO uncomment when fix transparent navigation -// containerView.setClipChildren(false); -// containerView.setClipToPadding(false); -// windowView.setClipChildren(false); -// windowView.setClipToPadding(false); + containerView.setClipChildren(true); + containerView.setClipToPadding(true); + windowView.setClipChildren(false); + windowView.setClipToPadding(false); windowView.addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); if (Build.VERSION.SDK_INT >= 21) { @@ -3811,7 +3803,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat navigationBarHeight = insets.getSystemWindowInsetBottom(); ViewGroup.MarginLayoutParams navigationBarLayoutParams = (ViewGroup.MarginLayoutParams) navigationBar.getLayoutParams(); navigationBarLayoutParams.height = navigationBarHeight; - navigationBarLayoutParams.bottomMargin = -navigationBarHeight; + navigationBarLayoutParams.bottomMargin = -navigationBarHeight / 2; navigationBar.setLayoutParams(navigationBarLayoutParams); } containerView.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0); @@ -4259,8 +4251,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } if (isEmbedVideo) { - pipVideoView = photoViewerWebView.openInPip(); - if (pipVideoView != null) { + if (photoViewerWebView.openInPip()) { if (PipInstance != null) { PipInstance.destroyPhotoViewer(); } @@ -4540,7 +4531,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat navigationBar = new View(activityContext); navigationBar.setBackgroundColor(0x7f000000); - containerView.addView(navigationBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, navigationBarHeight / AndroidUtilities.density, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, -navigationBarHeight / AndroidUtilities.density)); + windowView.addView(navigationBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, navigationBarHeight / AndroidUtilities.density, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); pressedDrawable[0] = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, new int[] {0x32000000, 0}); pressedDrawable[0].setShape(GradientDrawable.RECTANGLE); @@ -4654,9 +4645,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }); } - final LinkMovementMethod captionLinkMovementMethod = new CaptionLinkMovementMethod(); captionTextViewSwitcher = new CaptionTextViewSwitcher(containerView.getContext()); - captionTextViewSwitcher.setFactory(() -> createCaptionTextView(captionLinkMovementMethod)); + captionTextViewSwitcher.setFactory(() -> createCaptionTextView()); captionTextViewSwitcher.setVisibility(View.INVISIBLE); setCaptionHwLayerEnabled(true); @@ -5322,7 +5312,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } } - switchToEditMode(1); + switchToEditMode(EDIT_MODE_CROP); }); cropItem.setContentDescription(LocaleController.getString("CropImage", R.string.CropImage)); @@ -5382,7 +5372,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } } - switchToEditMode(3); + switchToEditMode(EDIT_MODE_PAINT); }); paintItem.setContentDescription(LocaleController.getString("AccDescrPhotoEditor", R.string.AccDescrPhotoEditor)); @@ -5443,7 +5433,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } } - switchToEditMode(2); + switchToEditMode(EDIT_MODE_FILTER); }); tuneItem.setContentDescription(LocaleController.getString("AccDescrPhotoAdjust", R.string.AccDescrPhotoAdjust)); @@ -5522,6 +5512,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat titleView.setOnTouchListener((v12, event) -> true); final BottomSheet bottomSheet = builder.create(); + bottomSheet.setCalcMandatoryInsets(true); + bottomSheet.setOverlayNavBarColor(0xff000000); + bottomSheet.scrollNavBar = true; final NumberPicker numberPicker = new NumberPicker(parentActivity, resourcesProvider); numberPicker.setMinValue(0); numberPicker.setMaxValue(28); @@ -5628,6 +5621,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat textView.setOnClickListener(v14 -> bottomSheet.dismiss()); bottomSheet.show(); bottomSheet.setBackgroundColor(0xff000000); + AndroidUtilities.setNavigationBarColor(bottomSheet.getWindow(), 0xff000000, false); + AndroidUtilities.setLightNavigationBar(bottomSheet.getWindow(), false); }); editorDoneLayout = new PickerBottomLayoutViewer(activityContext); @@ -5637,14 +5632,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView.addView(editorDoneLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM)); editorDoneLayout.cancelButton.setOnClickListener(view -> { cropTransform.setViewTransform(previousHasTransform, previousCropPx, previousCropPy, previousCropRotation, previousCropOrientation, previousCropScale, 1.0f, 1.0f, previousCropPw, previousCropPh, 0, 0, previousCropMirrored); - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); }); editorDoneLayout.doneButton.setOnClickListener(view -> { - if (currentEditMode == 1 && !photoCropView.isReady()) { + if (currentEditMode == EDIT_MODE_CROP && !photoCropView.isReady()) { return; } applyCurrentEditMode(); - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); }); resetButton = new TextView(activityContext); @@ -5665,7 +5660,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ImageReceiver.ImageReceiverDelegate imageReceiverDelegate = (imageReceiver, set, thumb, memCache) -> { if (imageReceiver == centerImage && set && !thumb) { - if (!isCurrentVideo && (currentEditMode == 1 || sendPhotoType == SELECT_TYPE_AVATAR) && photoCropView != null) { + if (!isCurrentVideo && (currentEditMode == EDIT_MODE_CROP || sendPhotoType == SELECT_TYPE_AVATAR) && photoCropView != null) { Bitmap bitmap = imageReceiver.getBitmap(); if (bitmap != null) { photoCropView.setBitmap(bitmap, imageReceiver.getOrientation(), sendPhotoType != SELECT_TYPE_AVATAR, true, paintingOverlay, cropTransform, null, null); @@ -5847,8 +5842,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + @Override + public void onEmojiViewOpen() { + navigationBar.setVisibility(View.INVISIBLE); + animateNavBarColorTo(getThemedColor(Theme.key_chat_emojiPanelBackground), false); + } + @Override public void onEmojiViewCloseStart() { + navigationBar.setVisibility(currentEditMode == EDIT_MODE_NONE || currentEditMode == EDIT_MODE_CROP ? View.VISIBLE : View.INVISIBLE); + animateNavBarColorTo(0xff000000); setOffset(captionEditText.getEmojiPadding()); if (captionEditText.getTag() != null) { if (isCurrentVideo) { @@ -6055,6 +6058,40 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + private ValueAnimator navBarAnimator; + private void animateNavBarColorTo(int color) { + animateNavBarColorTo(color, true); + } + private void animateNavBarColorTo(int color, boolean animated) { + if (navBarAnimator != null) { + navBarAnimator.cancel(); + } + int fromColor = blackPaint.getColor(), + toColor = color; + AndroidUtilities.setLightNavigationBar(windowView, AndroidUtilities.computePerceivedBrightness(toColor) >= 0.721); + if (animated) { + navBarAnimator = ValueAnimator.ofFloat(0, 1); + navBarAnimator.addUpdateListener(a -> { + blackPaint.setColor(ColorUtils.blendARGB(fromColor, toColor, (float) a.getAnimatedValue())); + windowView.invalidate(); + }); + navBarAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + blackPaint.setColor(toColor); + windowView.invalidate(); + } + }); + navBarAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + navBarAnimator.setDuration(200); + navBarAnimator.start(); + } else { + navBarAnimator = null; + blackPaint.setColor(toColor); + windowView.invalidate(); + } + } + private void showScheduleDatePickerDialog() { if (parentChatActivity == null) { return; @@ -6177,33 +6214,69 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }).start(); } - private TextView createCaptionTextView(LinkMovementMethod linkMovementMethod) { + private TextView createCaptionTextView() { TextView textView = new SpoilersTextView(activityContext) { - private boolean handleClicks; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); @Override public boolean onTouchEvent(MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - handleClicks = needCaptionLayout; + + boolean linkResult = false; + if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) { + int x = (int) (event.getX() - getPaddingLeft()); + int y = (int) (event.getY() - getPaddingTop()); + final int line = getLayout().getLineForVertical(y); + final int off = getLayout().getOffsetForHorizontal(line, x); + final float left = getLayout().getLineLeft(line); + + ClickableSpan touchLink = null; + if (left <= x && left + getLayout().getLineWidth(line) >= x && y >= 0 && y <= getLayout().getHeight()) { + Spannable buffer = new SpannableString(getText()); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + touchLink = link[0]; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + linkResult = true; + links.clear(); + pressedLink = new LinkSpanDrawable<>(link[0], null, event.getX(), event.getY()); + pressedLink.setColor(0x6662a9e3); + links.addLink(pressedLink); + int start = buffer.getSpanStart(pressedLink.getSpan()); + int end = buffer.getSpanEnd(pressedLink.getSpan()); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(getLayout(), start, getPaddingTop()); + getLayout().getSelectionPath(start, end, path); + + final LinkSpanDrawable savedPressedLink = pressedLink; + postDelayed(() -> { + if (savedPressedLink == pressedLink && pressedLink != null && pressedLink.getSpan() instanceof URLSpan) { + onLinkLongPress((URLSpan) pressedLink.getSpan(), this, () -> links.clear()); + pressedLink = null; + } + }, ViewConfiguration.getLongPressTimeout()); + } + } + } + if (event.getAction() == MotionEvent.ACTION_UP) { + links.clear(); + if (pressedLink != null && pressedLink.getSpan() == touchLink) { + onLinkClick(pressedLink.getSpan(), this); + } + pressedLink = null; + linkResult = true; + } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + links.clear(); + pressedLink = null; + linkResult = true; } - boolean b = super.onTouchEvent(event); + + boolean b = linkResult || super.onTouchEvent(event); return bottomTouchEnabled && b; } - @Override - public void scrollTo(int x, int y) { - if (getParent().getParent() == pickerView) { - super.scrollTo(x, y); - handleClicks = false; - } - } - - @Override - public boolean performClick() { - return handleClicks && super.performClick(); - } - @Override public void setPressed(boolean pressed) { final boolean needsRefresh = pressed != isPressed(); @@ -6212,15 +6285,30 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat invalidate(); } } + + @Override + protected void onDraw(Canvas canvas) { + canvas.save(); + canvas.translate(getPaddingLeft(), 0); + if (links.draw(canvas)) { + invalidate(); + } + canvas.restore(); + super.onDraw(canvas); + } }; - textView.setMovementMethod(linkMovementMethod); ViewHelper.setPadding(textView, 16, 8, 16, 8); - textView.setLinkTextColor(0xff76c2f1); + textView.setLinkTextColor(0xff79c4fc); textView.setTextColor(0xffffffff); textView.setHighlightColor(0x33ffffff); textView.setGravity(Gravity.CENTER_VERTICAL | LayoutHelper.getAbsoluteGravityStart()); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - textView.setOnClickListener((v) -> openCaptionEnter()); + textView.setOnClickListener((v) -> { + if (!needCaptionLayout) { + return; + } + openCaptionEnter(); + }); return textView; } @@ -6299,9 +6387,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat currentPlaceObject.imageReceiver.startAnimation(); } } - if (Build.VERSION.SDK_INT >= 21) { + if (Build.VERSION.SDK_INT >= 21 && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { pipAnimationInProgress = true; - org.telegram.ui.Components.Rect rect = PipVideoView.getPipRect(aspectRatioFrameLayout.getAspectRatio()); + org.telegram.ui.Components.Rect rect = PipVideoOverlay.getPipRect(true, aspectRatioFrameLayout.getAspectRatio()); float scale = rect.width / videoTextureView.getWidth(); @@ -6334,20 +6422,38 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { interpolator = null; } + ViewOutlineProvider outlineProvider = new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), (float) valueAnimator.getAnimatedValue() * AndroidUtilities.dp(PipVideoOverlay.ROUNDED_CORNERS_DP) * (1f / scale)); + } + }; + videoTextureView.setOutlineProvider(outlineProvider); + videoTextureView.setClipToOutline(true); + textureImageView.setOutlineProvider(outlineProvider); + textureImageView.setClipToOutline(true); + if (firstFrameView != null) { + firstFrameView.setOutlineProvider(outlineProvider); + firstFrameView.setClipToOutline(true); + } + valueAnimator.addUpdateListener(animation -> { float xValue = (float) animation.getAnimatedValue(); float yValue = interpolator == null ? xValue : interpolator.getInterpolation(xValue); textureImageView.setTranslationX(fromX * (1f - xValue) + toX * xValue); textureImageView.setTranslationY(fromY2 * (1f - yValue) + toY * yValue); + textureImageView.invalidateOutline(); videoTextureView.setTranslationX(fromX * (1f - xValue) + (toX2) * xValue); videoTextureView.setTranslationY(fromY * (1f - yValue) + (toY2) * yValue); + videoTextureView.invalidateOutline(); if (firstFrameView != null) { firstFrameView.setTranslationX(videoTextureView.getTranslationX()); firstFrameView.setTranslationY(videoTextureView.getTranslationY()); firstFrameView.setScaleX(videoTextureView.getScaleX()); firstFrameView.setScaleY(videoTextureView.getScaleY()); + firstFrameView.invalidateOutline(); } }); @@ -6372,6 +6478,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public void onAnimationEnd(Animator animation) { pipAnimationInProgress = false; switchToInlineRunnable.run(); + AndroidUtilities.runOnUIThread(()->{ + videoTextureView.setOutlineProvider(null); + textureImageView.setOutlineProvider(null); + if (firstFrameView != null) { + firstFrameView.setOutlineProvider(null); + } + }, 100); } }); animatorSet.start(); @@ -6415,6 +6528,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat isInline = false; if (photoViewerWebView == null && videoTextureView != null) { + if (videoTextureView.getParent() != null) { + ((ViewGroup) videoTextureView.getParent()).removeView(videoTextureView); + } videoTextureView.setVisibility(View.INVISIBLE); aspectRatioFrameLayout.addView(videoTextureView); } @@ -6428,9 +6544,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (photoViewerWebView == null) { - if (Build.VERSION.SDK_INT >= 21 && videoTextureView != null) { + if (Build.VERSION.SDK_INT >= 21 && videoTextureView != null && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { pipAnimationInProgress = true; - org.telegram.ui.Components.Rect rect = PipVideoView.getPipRect(aspectRatioFrameLayout.getAspectRatio()); + org.telegram.ui.Components.Rect rect = PipVideoOverlay.getPipRect(false, aspectRatioFrameLayout.getAspectRatio()); float scale = rect.width / textureImageView.getLayoutParams().width; textureImageView.setScaleX(scale); @@ -6447,9 +6563,24 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat firstFrameView.setTranslationX(videoTextureView.getTranslationX()); firstFrameView.setTranslationY(videoTextureView.getTranslationY()); } + + inlineOutAnimationProgress = 0f; + ViewOutlineProvider outlineProvider = new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), (1f - inlineOutAnimationProgress) * AndroidUtilities.dp(PipVideoOverlay.ROUNDED_CORNERS_DP) * (1f / scale)); + } + }; + videoTextureView.setOutlineProvider(outlineProvider); + videoTextureView.setClipToOutline(true); + textureImageView.setOutlineProvider(outlineProvider); + textureImageView.setClipToOutline(true); + if (firstFrameView != null) { + firstFrameView.setOutlineProvider(outlineProvider); + firstFrameView.setClipToOutline(true); + } } else { - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(true); } } @@ -6622,7 +6753,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } private void openCaptionEnter() { - if (imageMoveAnimation != null || changeModeAnimation != null || currentEditMode != 0 || sendPhotoType == SELECT_TYPE_AVATAR || sendPhotoType == SELECT_TYPE_WALLPAPER || sendPhotoType == SELECT_TYPE_QR) { + if (imageMoveAnimation != null || changeModeAnimation != null || currentEditMode != EDIT_MODE_NONE || sendPhotoType == SELECT_TYPE_AVATAR || sendPhotoType == SELECT_TYPE_WALLPAPER || sendPhotoType == SELECT_TYPE_QR) { return; } if (!windowView.isFocusable()) { @@ -7084,7 +7215,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat AndroidUtilities.runOnUIThread(updateProgressRunnable); } } else if (isPlaying || playbackState == ExoPlayer.STATE_ENDED) { - if (currentEditMode != 3) { + if (currentEditMode != EDIT_MODE_PAINT) { photoProgressViews[0].setIndexedAlpha(1, 1f, playbackState == ExoPlayer.STATE_ENDED); photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false, photoProgressViews[0].animAlphas[1] > 0f); } @@ -7094,14 +7225,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (isCurrentVideo) { if (!videoTimelineView.isDragging()) { videoTimelineView.setProgress(videoTimelineView.getLeftProgress()); - if (!inPreview && (currentEditMode != 0 || videoTimelineView.getVisibility() == View.VISIBLE)) { + if (!inPreview && (currentEditMode != EDIT_MODE_NONE || videoTimelineView.getVisibility() == View.VISIBLE)) { videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); } else { videoPlayer.seekTo(0); } manuallyPaused = false; cancelVideoPlayRunnable(); - if (sendPhotoType != SELECT_TYPE_AVATAR && currentEditMode == 0 && switchingToMode <= 0) { + if (sendPhotoType != SELECT_TYPE_AVATAR && currentEditMode == EDIT_MODE_NONE && switchingToMode <= 0) { videoPlayer.pause(); } else { videoPlayer.play(); @@ -7122,14 +7253,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat toggleActionBar(true, true); } } - if (pipVideoView != null) { - pipVideoView.onVideoCompleted(); - } + PipVideoOverlay.onVideoCompleted(); } } - if (pipVideoView != null) { - pipVideoView.updatePlayButton(); - } + PipVideoOverlay.updatePlayButton(); updateVideoPlayerTime(); } @@ -7227,7 +7354,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override public void pause() { super.pause(); - if (currentEditMode == 0) { + if (currentEditMode == EDIT_MODE_NONE) { playOrStopAnimatedStickers(false); } } @@ -7286,6 +7413,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat width = height; height = temp; } + videoWidth = (int) (width * pixelWidthHeightRatio); + videoHeight = (int) (height * pixelWidthHeightRatio); + aspectRatioFrameLayout.setAspectRatio(height == 0 ? 1 : (width * pixelWidthHeightRatio) / height, unappliedRotationDegrees); if (videoTextureView instanceof VideoEditTextureView) { ((VideoEditTextureView) videoTextureView).setVideoSize((int) (width * pixelWidthHeightRatio), height); @@ -7346,8 +7476,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat aspectRatioFrameLayout.getLocationInWindow(pipPosition); //pipPosition[0] -= getLeftInset(); pipPosition[1] -= containerView.getTranslationY(); - textureImageView.setTranslationX(textureImageView.getTranslationX() + getLeftInset()); - videoTextureView.setTranslationX(videoTextureView.getTranslationX() + getLeftInset() - aspectRatioFrameLayout.getX()); + if (textureImageView != null) { + textureImageView.setTranslationX(textureImageView.getTranslationX() + getLeftInset()); + } + if (videoTextureView != null) { + videoTextureView.setTranslationX(videoTextureView.getTranslationX() + getLeftInset() - aspectRatioFrameLayout.getX()); + } if (firstFrameView != null) { firstFrameView.setTranslationX(videoTextureView.getTranslationX()); } @@ -7369,6 +7503,24 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animators.add(ObjectAnimator.ofFloat(firstFrameView, View.TRANSLATION_X, pipPosition[0] - aspectRatioFrameLayout.getX())); animators.add(ObjectAnimator.ofFloat(firstFrameView, View.TRANSLATION_Y, pipPosition[1] - aspectRatioFrameLayout.getY())); } + + org.telegram.ui.Components.Rect pipRect = PipVideoOverlay.getPipRect(false, aspectRatioFrameLayout.getAspectRatio()); + float scale = pipRect.width / videoTextureView.getWidth(); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); + valueAnimator.addUpdateListener(animation -> { + inlineOutAnimationProgress = (float) animation.getAnimatedValue(); + if (videoTextureView != null) { + videoTextureView.invalidateOutline(); + } + if (textureImageView != null) { + textureImageView.invalidateOutline(); + } + if (firstFrameView != null) { + firstFrameView.invalidateOutline(); + } + }); + animators.add(valueAnimator); + animatorSet.playTogether(animators); final DecelerateInterpolator interpolator = new DecelerateInterpolator(); animatorSet.setInterpolator(interpolator); @@ -7377,6 +7529,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override public void onAnimationEnd(Animator animation) { pipAnimationInProgress = false; + if (videoTextureView != null) { + videoTextureView.setOutlineProvider(null); + } + if (textureImageView != null) { + textureImageView.setOutlineProvider(null); + } + if (firstFrameView != null) { + firstFrameView.setOutlineProvider(null); + } } }); animatorSet.start(); @@ -7863,7 +8024,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (editState.mediaEntities != null) { for (int a = 0, N = editState.mediaEntities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = editState.mediaEntities.get(a); - if (entity.type == 0 && (entity.subType & 1) != 0) { + if (entity.type == 0 && ((entity.subType & 1) != 0 || (entity.subType & 4) != 0)) { count++; if (single) { break; @@ -7931,7 +8092,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat int[] orientation = null; boolean hasChanged = false; MediaController.MediaEditState entry = (MediaController.MediaEditState) imagesArrLocals.get(currentIndex); - if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.makeCrop(entry); if (entry.cropState == null) { return; @@ -7951,10 +8112,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat bitmap = centerImage.getBitmap(); orientation = new int[]{centerImage.getOrientation()}; } - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { bitmap = photoFilterView.getBitmap(); savedFilterState = photoFilterView.getSavedFilterState(); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { if (Build.VERSION.SDK_INT >= 18 && (sendPhotoType == 0 || sendPhotoType == SELECT_TYPE_AVATAR || sendPhotoType == 2)) { entities = new ArrayList<>(); } @@ -7975,7 +8136,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat entry.imagePath = null; } - if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { editState.cropState = entry.cropState; editState.croppedPaintPath = entry.croppedPaintPath; editState.croppedMediaEntities = entry.croppedMediaEntities; @@ -8010,11 +8171,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(croppedBitmap, thumbSize, thumbSize, 70, false, 101, 101); entry.thumbPath = FileLoader.getPathToAttach(size, true).toString(); } - if (currentEditMode == 0 && isCurrentVideo) { + if (currentEditMode == EDIT_MODE_NONE && isCurrentVideo) { bitmap.recycle(); bitmap = croppedBitmap; } - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { if (entry.filterPath != null) { new File(entry.filterPath).delete(); } @@ -8064,7 +8225,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (entry.cropState != null) { b.recycle(); } - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { if (entry.paintPath != null) { new File(entry.paintPath).delete(); if (!entry.paintPath.equals(entry.fullPaintPath)) { @@ -8190,13 +8351,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (savedFilterState != null) { entry.savedFilterState = editState.savedFilterState = savedFilterState; } - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { entry.isCropped = true; cropItem.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.MULTIPLY)); - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { entry.isFiltered = true; tuneItem.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.MULTIPLY)); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { if (hasChanged) { entry.isPainted = true; paintItem.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.MULTIPLY)); @@ -8209,7 +8370,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat setPhotoChecked(); } } - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { float scaleX = photoCropView.getRectSizeX() / (float) getContainerViewWidth(); float scaleY = photoCropView.getRectSizeY() / (float) getContainerViewHeight(); scale = Math.max(scaleX, scaleY); @@ -8224,9 +8385,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ignoreDidSetImage = true; boolean setImage; if (isCurrentVideo) { - setImage = currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR; + setImage = currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR; } else { - setImage = currentEditMode == 2; + setImage = currentEditMode == EDIT_MODE_FILTER; } if (setImage) { centerImage.setImageBitmap(bitmap); @@ -8391,8 +8552,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (currentEditMode == mode || (isCurrentVideo && photoProgressViews[0].backgroundState != 3) && !isCurrentVideo && (centerImage.getBitmap() == null || photoProgressViews[0].backgroundState != -1) || changeModeAnimation != null || imageMoveAnimation != null || captionEditText.getTag() != null) { return; } + windowView.setClipChildren(mode != EDIT_MODE_NONE && mode != EDIT_MODE_CROP); + navigationBar.setBackgroundColor(mode == EDIT_MODE_CROP ? 0xcc000000 : 0x7f000000); + navigationBar.setVisibility(mode == EDIT_MODE_NONE || mode == EDIT_MODE_CROP ? View.VISIBLE : View.INVISIBLE); switchingToMode = mode; - if (mode == 0) { // no edit mode + if (mode == EDIT_MODE_NONE) { Bitmap bitmap = centerImage.getBitmap(); if (bitmap != null) { int bitmapWidth = centerImage.getBitmapWidth(); @@ -8400,7 +8564,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat float newScale; float oldScale; - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { if (sendPhotoType != SELECT_TYPE_AVATAR) { if (cropTransform.getOrientation() == 90 || cropTransform.getOrientation() == 270) { int temp = bitmapWidth; @@ -8421,7 +8585,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat newScale = Math.min(getContainerViewWidth(0) / (float) bitmapWidth, getContainerViewHeight(0) / (float) bitmapHeight); oldScale = Math.min(getContainerViewWidth() / (float) bitmapWidth, getContainerViewHeight() / (float) bitmapHeight); } else { - if (currentEditMode != 1 && editState.cropState != null && (editState.cropState.transformRotation == 90 || editState.cropState.transformRotation == 270)) { + if (currentEditMode != EDIT_MODE_CROP && editState.cropState != null && (editState.cropState.transformRotation == 90 || editState.cropState.transformRotation == 270)) { float scaleToFitX = getContainerViewWidth() / (float) bitmapHeight; if (scaleToFitX * bitmapWidth > getContainerViewHeight()) { scaleToFitX = getContainerViewHeight() / (float) bitmapWidth; @@ -8462,17 +8626,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animateToX = 0; translationX = getLeftInset() / 2 - getRightInset() / 2; if (sendPhotoType == SELECT_TYPE_AVATAR) { - if (currentEditMode == 2) { + if (currentEditMode == EDIT_MODE_FILTER) { animateToY = AndroidUtilities.dp(36); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { animateToY = -AndroidUtilities.dp(12); } } else { - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { animateToY = AndroidUtilities.dp(24 + 32); - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { animateToY = AndroidUtilities.dp(93); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { animateToY = AndroidUtilities.dp(44); } if (isStatusBarVisible()) { @@ -8486,17 +8650,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imageMoveAnimation = new AnimatorSet(); ArrayList animators = new ArrayList<>(4); - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { animators.add(ObjectAnimator.ofFloat(editorDoneLayout, View.TRANSLATION_Y, AndroidUtilities.dp(48))); animators.add(ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1)); animators.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0)); - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { photoFilterView.shutdown(); animators.add(ObjectAnimator.ofFloat(photoFilterView.getToolsView(), View.TRANSLATION_Y, AndroidUtilities.dp(186))); animators.add(ObjectAnimator.ofFloat(photoFilterView.getCurveControl(), View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(photoFilterView.getBlurControl(), View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1)); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { paintingOverlay.showAll(); containerView.invalidate(); photoPaintView.shutdown(); @@ -8509,19 +8673,19 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imageMoveAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { photoCropView.onDisappear(); photoCropView.onHide(); editorDoneLayout.setVisibility(View.GONE); photoCropView.setVisibility(View.GONE); - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { try { containerView.removeView(photoFilterView); } catch (Exception e) { FileLog.e(e); } photoFilterView = null; - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { try { containerView.removeView(photoPaintView); } catch (Exception e) { @@ -8576,6 +8740,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat muteItem.setVisibility(View.VISIBLE); arrayList.add(ObjectAnimator.ofFloat(muteItem, View.ALPHA, 1)); } + if (navigationBar != null) { + navigationBar.setVisibility(View.VISIBLE); + arrayList.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 1)); + } animatorSet.playTogether(arrayList); animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapter() { @@ -8597,7 +8765,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); imageMoveAnimation.start(); - } else if (mode == 1) { // crop + } else if (mode == EDIT_MODE_CROP) { startVideoPlayer(); createCropView(); previousHasTransform = cropTransform.hasViewTransform(); @@ -8635,6 +8803,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (muteItem.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(muteItem, View.ALPHA, 1, 0)); } + if (navigationBar != null) { + arrayList.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 1)); + } changeModeAnimation.playTogether(arrayList); changeModeAnimation.setDuration(200); changeModeAnimation.addListener(new AnimatorListenerAdapter() { @@ -8730,7 +8901,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); changeModeAnimation.start(); - } else if (mode == 2) { // filter + } else if (mode == EDIT_MODE_FILTER) { startVideoPlayer(); if (photoFilterView == null) { MediaController.SavedFilterState state = null; @@ -8770,7 +8941,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView.addView(photoFilterView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); photoFilterView.getDoneTextView().setOnClickListener(v -> { applyCurrentEditMode(); - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); }); photoFilterView.getCancelTextView().setOnClickListener(v -> { if (photoFilterView.hasChanges()) { @@ -8784,7 +8955,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showAlertDialog(builder); } else { - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); } }); photoFilterView.getToolsView().setTranslationY(AndroidUtilities.dp(186)); @@ -8894,7 +9065,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); changeModeAnimation.start(); - } else if (mode == 3) { + } else if (mode == EDIT_MODE_PAINT) { startVideoPlayer(); createPaintView(); @@ -8995,7 +9166,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat photoPaintView.getDoneTextView().setOnClickListener(v -> { savedState = null; applyCurrentEditMode(); - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); }); photoPaintView.getCancelTextView().setOnClickListener(v -> closePaintMode()); photoPaintView.getColorPicker().setTranslationY(AndroidUtilities.dp(126)); @@ -9004,7 +9175,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } private void closePaintMode() { - photoPaintView.maybeShowDismissalAlert(PhotoViewer.this, parentActivity, () -> switchToEditMode(0)); + photoPaintView.maybeShowDismissalAlert(PhotoViewer.this, parentActivity, () -> switchToEditMode(EDIT_MODE_NONE)); } private void switchToPaintMode() { @@ -9064,6 +9235,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat zoomAnimation = true; } + windowView.setClipChildren(true); + navigationBar.setVisibility(View.INVISIBLE); imageMoveAnimation = new AnimatorSet(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1), @@ -9082,7 +9255,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat photoPaintView.init(); paintingOverlay.hideEntities(); imageMoveAnimation = null; - currentEditMode = 3; + currentEditMode = EDIT_MODE_PAINT; switchingToMode = -1; animateToScale = 1; animateToX = 0; @@ -9290,11 +9463,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (navigationBar != null) { arrayList.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, show ? 1.0f : 0.0f)); - if (params.enableTranslationAnimation) { - arrayList.add(ObjectAnimator.ofFloat(navigationBar, View.TRANSLATION_Y, show ? 0 : offsetY)); - } else { - navigationBar.setTranslationY(0); - } } if (videoPlayerControlVisible) { arrayList.add(ObjectAnimator.ofFloat(videoPlayerControlFrameLayout, VPC_PROGRESS, show ? 1.0f : 0.0f)); @@ -9366,7 +9534,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat bottomLayout.setAlpha(show ? 1.0f : 0.0f); bottomLayout.setTranslationY(show ? 0 : offsetY); navigationBar.setAlpha(show ? 1.0f : 0.0f); - navigationBar.setTranslationY(show ? 0 : offsetY); groupedPhotosListView.setAlpha(show ? 1.0f : 0.0f); groupedPhotosListView.setTranslationY(show ? 0 : offsetY); if (!needCaptionLayout && captionScrollView != null) { @@ -9735,7 +9902,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canEditAvatar = false; totalImagesCount = 0; totalImagesCountMerge = 0; - currentEditMode = 0; + currentEditMode = EDIT_MODE_NONE; isFirstLoading = true; needSearchImageInArr = false; loadingMoreImages = false; @@ -10075,6 +10242,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat pickerViewSendButton.setVisibility(View.VISIBLE); pickerViewSendButton.setTranslationY(0); pickerViewSendButton.setAlpha(1.0f); + if (navigationBar != null) { + navigationBar.setVisibility(View.VISIBLE); + navigationBar.setAlpha(1.0f); + } bottomLayout.setVisibility(View.GONE); bottomLayout.setTag(null); containerView.setTag(null); @@ -10142,9 +10313,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private void setImages() { if (animationInProgress == 0) { - setIndexToImage(centerImage, currentIndex); - setIndexToImage(rightImage, currentIndex + 1); - setIndexToImage(leftImage, currentIndex - 1); + setIndexToImage(centerImage, currentIndex, null, paintingOverlay); + setIndexToImage(rightImage, currentIndex + 1, rightCropTransform, rightPaintingOverlay); + setIndexToImage(leftImage, currentIndex - 1, leftCropTransform, leftPaintingOverlay); } } @@ -10788,6 +10959,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat boolean isVideo = false; boolean sameImage = false; Uri videoPath = null; + + CropTransform prevCropTransform = cropTransform.clone(); + MediaController.CropState prevCropState = editState == null || editState.cropState == null ? null : editState.cropState.clone(); + boolean prevIsVideo = centerImageIsVideo; + editState.reset(); if (!imagesArr.isEmpty()) { @@ -11015,6 +11191,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat editState.reset(); } + centerImageIsVideo = isVideo; + if (prevIndex == -1) { setImages(); @@ -11029,6 +11207,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat centerImage = leftImage; leftImage = temp; + rightImageIsVideo = prevIsVideo; + rightCropTransform = prevCropTransform; + rightCropState = prevCropState; + PhotoProgressView tempProgress = photoProgressViews[0]; photoProgressViews[0] = photoProgressViews[2]; photoProgressViews[2] = tempProgress; @@ -11038,7 +11220,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat fullscreenButton[2] = tmp; fullscreenButton[0].setTranslationY(tmp.getTranslationY()); - setIndexToImage(leftImage, currentIndex - 1); + leftCropState = null; + setIndexToImage(leftImage, currentIndex - 1, leftCropTransform, leftPaintingOverlay); updateAccessibilityOverlayVisibility(); checkProgress(1, true, false); @@ -11049,6 +11232,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat centerImage = rightImage; rightImage = temp; + leftImageIsVideo = prevIsVideo; + leftCropTransform = prevCropTransform; + leftCropState = prevCropState; + PhotoProgressView tempProgress = photoProgressViews[0]; photoProgressViews[0] = photoProgressViews[1]; photoProgressViews[1] = tempProgress; @@ -11058,7 +11245,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat fullscreenButton[1] = tmp; fullscreenButton[0].setTranslationY(tmp.getTranslationY()); - setIndexToImage(rightImage, currentIndex + 1); + rightCropState = null; + setIndexToImage(rightImage, currentIndex + 1, rightCropTransform, rightPaintingOverlay); updateAccessibilityOverlayVisibility(); checkProgress(1, true, false); @@ -11481,7 +11669,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return captionEditText != null ? captionEditText.getSelectionLength() : 0; } - private void setIndexToImage(ImageReceiver imageReceiver, int index) { + private void setIndexToImage(ImageReceiver imageReceiver, int index, CropTransform cropTransform, PaintingOverlay paintingOverlay) { imageReceiver.setOrientation(0, false); if (!secureDocuments.isEmpty()) { if (index >= 0 && index < secureDocuments.size()) { @@ -11515,12 +11703,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ImageLocation videoThumb = null; TLRPC.PhotoSize photo = null; TLObject photoObject = null; + MediaController.CropState cropState = null; int imageSize = 0; String filter = null; boolean isVideo = false; int cacheType = 0; if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; + cropState = photoEntry.cropState; isVideo = photoEntry.isVideo; if (photoEntry.isVideo) { if (photoEntry.thumbPath != null) { @@ -11596,6 +11786,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat path = photoEntry.imageUrl; imageSize = photoEntry.size; } + cropState = photoEntry.cropState; filter = "d"; } if (document != null) { @@ -11616,6 +11807,22 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { imageReceiver.setImage(path, filter, placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : (isVideo && parentActivity != null ? parentActivity.getResources().getDrawable(R.drawable.nophotos) : null), null, imageSize); } + + if (cropTransform != null) { + if (cropState != null) { + cropTransform.setViewTransform(true, cropState.cropPx, cropState.cropPy, cropState.cropRotate, cropState.transformRotation, cropState.cropScale, 1.0f, 1.0f, cropState.cropPw, cropState.cropPh, 0, 0, cropState.mirrored); + } else { + cropTransform.setViewTransform(false); + } + } + + if (imageReceiver == leftImage) { + leftCropState = cropState; + leftImageIsVideo = isVideo; + } else if (imageReceiver == rightImage) { + rightCropState = cropState; + rightImageIsVideo = isVideo; + } } else { imageReceiver.setImageBitmap((Bitmap) null); } @@ -11755,7 +11962,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat parentObject = null; } if (videoThumb != null) { - imageReceiver.setImage(imageLocation, null, videoThumb, null, placeHolder == null ? ImageLocation.getForObject(thumbLocation, photoObject) : null, "b", placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, size[0], null, parentObject, cacheOnly ? 1 : 0); + String filter = sharedMediaType == MediaDataController.MEDIA_GIF ? ImageLoader.AUTOPLAY_FILTER : null; + imageReceiver.setImage(imageLocation, filter, videoThumb, null, placeHolder == null ? ImageLocation.getForObject(thumbLocation, photoObject) : null, "b", placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, size[0], null, parentObject, cacheOnly ? 1 : 0); + imageReceiver.setAllowStartAnimation(true); } else { String filter; if (avatarsDialogId != 0) { @@ -12231,6 +12440,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + windowView.setClipChildren(false); + navigationBar.setVisibility(View.VISIBLE); + seekToProgressPending2 = 0; skipFirstBufferingProgress = false; playerInjected = false; @@ -12402,6 +12614,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } backgroundDrawable.setAlpha(0); containerView.setAlpha(0); + navigationBar.setAlpha(0); animationEndRunnable = () -> { animationEndRunnable = null; @@ -12450,6 +12663,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } animators.add(ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0, 255)); animators.add(ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0.0f, 1.0f)); if (sendPhotoType == SELECT_TYPE_AVATAR) { animators.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0, 1.0f)); } @@ -12551,11 +12765,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animationInProgress = 4; containerView.invalidate(); AnimatorSet animatorSet = new AnimatorSet(); - ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(containerView, View.ALPHA, 0f, 1f).setDuration(220); ObjectAnimator a2 = ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, pickerView.getTranslationY(), 0f).setDuration(220); a2.setInterpolator(CubicBezierInterpolator.DEFAULT); animatorSet.playTogether( - alphaAnimator, + ObjectAnimator.ofFloat(containerView, View.ALPHA, 0f, 1f).setDuration(220), + ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0f, 1f).setDuration(220), a2 ); animatorSet.addListener(new AnimatorListenerAdapter() { @@ -12652,15 +12866,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } public void closePhoto(boolean animated, boolean fromEditMode) { - if (!fromEditMode && currentEditMode != 0) { - if (currentEditMode == 3 && photoPaintView != null) { + if (!fromEditMode && currentEditMode != EDIT_MODE_NONE) { + if (currentEditMode == EDIT_MODE_PAINT && photoPaintView != null) { closePaintMode(); return; } - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { cropTransform.setViewTransform(previousHasTransform, previousCropPx, previousCropPy, previousCropRotation, previousCropOrientation, previousCropScale, 1.0f, 1.0f, previousCropPw, previousCropPh, 0, 0, previousCropMirrored); } - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); return; } if (qualityChooseView != null && qualityChooseView.getTag() != null) { @@ -12680,21 +12894,28 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat AndroidUtilities.cancelRunOnUIThread(updateContainerFlagsRunnable); updateContainerFlags(true); } - if (currentEditMode != 0) { - if (currentEditMode == 2) { + if (currentEditMode != EDIT_MODE_NONE) { + if (currentEditMode == EDIT_MODE_FILTER) { photoFilterView.shutdown(); containerView.removeView(photoFilterView); photoFilterView = null; - } else if (currentEditMode == 1) { + } else if (currentEditMode == EDIT_MODE_CROP) { editorDoneLayout.setVisibility(View.GONE); photoCropView.setVisibility(View.GONE); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { photoPaintView.shutdown(); containerView.removeView(photoPaintView); photoPaintView = null; savedState = null; } - currentEditMode = 0; + currentEditMode = EDIT_MODE_NONE; + } + + if (navigationBar != null) { + navigationBar.setVisibility(View.VISIBLE); + } + if (windowView != null) { + windowView.setClipChildren(false); } if (parentActivity == null || !isInline && !isVisible || checkAnimation() || placeProvider == null) { @@ -12906,6 +13127,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } animators.add(ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0)); animators.add(ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0.0f)); if (sendPhotoType == SELECT_TYPE_AVATAR) { animators.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0.0f)); } @@ -12916,7 +13138,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0), ObjectAnimator.ofFloat(animatingImageView, View.ALPHA, 0.0f), ObjectAnimator.ofFloat(animatingImageView, View.TRANSLATION_Y, translationY >= 0 ? h : -h), - ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f) + ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0.0f) ); } @@ -12952,7 +13175,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ObjectAnimator.ofFloat(containerView, View.SCALE_X, 0.9f), ObjectAnimator.ofFloat(containerView, View.SCALE_Y, 0.9f), ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0), - ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f) + ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0.0f) ); animationInProgress = 2; animationEndRunnable = () -> { @@ -13035,9 +13259,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (parentActivity == null || windowView == null) { return; } - if (pipVideoView != null) { - pipVideoView.close(); - pipVideoView = null; + if (PipVideoOverlay.isVisible()) { + PipVideoOverlay.dismiss(); } removeObservers(); releasePlayer(false); @@ -13169,11 +13392,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - public void onConfigurationChanged(Configuration newConfig) { - if (pipVideoView != null) { - pipVideoView.onConfigurationChanged(); - } - } + public void onConfigurationChanged(Configuration newConfig) {} public void onPause() { if (currentAnimation != null) { @@ -13193,7 +13412,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } private void updateMinMax(float scale) { - if (currentEditMode == 3 && aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == View.VISIBLE && textureUploaded) { + if (aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == View.VISIBLE && textureUploaded) { scale *= Math.min(getContainerViewWidth() / (float) videoTextureView.getMeasuredWidth(), getContainerViewHeight() / (float) videoTextureView.getMeasuredHeight()); } float w = centerImage.getImageWidth(); @@ -13220,20 +13439,20 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } private int getAdditionX() { - if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { return AndroidUtilities.dp(16); - } else if (currentEditMode != 0 && currentEditMode != 3) { + } else if (currentEditMode != EDIT_MODE_NONE && currentEditMode != EDIT_MODE_PAINT) { return AndroidUtilities.dp(14); } return 0; } private int getAdditionY() { - if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { return AndroidUtilities.dp(16) + (isStatusBarVisible() ? AndroidUtilities.statusBarHeight : 0); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { return AndroidUtilities.dp(8) + (isStatusBarVisible() ? AndroidUtilities.statusBarHeight : 0); - } else if (currentEditMode != 0) { + } else if (currentEditMode != EDIT_MODE_NONE) { return AndroidUtilities.dp(14) + (isStatusBarVisible() ? AndroidUtilities.statusBarHeight : 0); } return 0; @@ -13285,7 +13504,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat Runnable longPressRunnable = this::onLongPress; private boolean onTouchEvent(MotionEvent ev) { - if (currentEditMode == 3 && animationStartTime != 0 && (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN)) { + if (currentEditMode == EDIT_MODE_PAINT && animationStartTime != 0 && (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN)) { if (ev.getPointerCount() >= 2) { cancelMoveZoomAnimation(); } else { @@ -13304,10 +13523,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return true; } - if (currentEditMode == 2) { + if (currentEditMode == EDIT_MODE_FILTER) { photoFilterView.onTouch(ev); return true; - } else if (currentEditMode == 1 || currentEditMode != 3 && sendPhotoType == SELECT_TYPE_AVATAR) { + } else if (currentEditMode == EDIT_MODE_CROP || currentEditMode != EDIT_MODE_PAINT && sendPhotoType == SELECT_TYPE_AVATAR) { return true; } @@ -13318,7 +13537,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return true; } - if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR && ev.getPointerCount() == 1 && gestureDetector.onTouchEvent(ev)) { + if (currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR && ev.getPointerCount() == 1 && gestureDetector.onTouchEvent(ev)) { if (doubleTap) { doubleTap = false; moving = false; @@ -13353,7 +13572,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat pinchStartY = translationY; zooming = true; moving = false; - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { moveStartX = pinchCenterX; moveStartY = pinchCenterY; draggingDown = false; @@ -13364,7 +13583,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat velocityTracker.clear(); } } else if (ev.getPointerCount() == 1) { - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { if (paintViewTouched == 0) { photoPaintView.getHitRect(hitRect); if (hitRect.contains((int) ev.getX(), (int) ev.getY())) { @@ -13396,7 +13615,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (canZoom && ev.getPointerCount() == 2 && !draggingDown && zooming && !changingPage) { discardTap = true; - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { float newPinchCenterX = (ev.getX(0) + ev.getX(1)) / 2.0f; float newPinchCenterY = (ev.getY(0) + ev.getY(1)) / 2.0f; float moveDx = moveStartX - newPinchCenterX; @@ -13440,7 +13659,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return true; } } - if (placeProvider.canScrollAway() && currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR && canDragDown && !draggingDown && scale == 1 && dy >= AndroidUtilities.dp(30) && dy / 2 > dx) { + if (placeProvider.canScrollAway() && currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR && canDragDown && !draggingDown && scale == 1 && dy >= AndroidUtilities.dp(30) && dy / 2 > dx) { draggingDown = true; hidePressedDrawables(); moving = false; @@ -13459,7 +13678,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else if (!invalidCoords && animationStartTime == 0) { float moveDx = moveStartX - ev.getX(); float moveDy = moveStartY - ev.getY(); - if (moving || currentEditMode != 0 || scale == 1 && Math.abs(moveDy) + AndroidUtilities.dp(12) < Math.abs(moveDx) || scale != 1) { + if (moving || currentEditMode != EDIT_MODE_NONE || scale == 1 && Math.abs(moveDy) + AndroidUtilities.dp(12) < Math.abs(moveDx) || scale != 1) { if (!moving) { moveDx = 0; moveDy = 0; @@ -13471,10 +13690,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat moveStartX = ev.getX(); moveStartY = ev.getY(); updateMinMax(scale); - if (translationX < minX && (currentEditMode != 0 || !rightImage.hasImageSet()) || translationX > maxX && (currentEditMode != 0 || !leftImage.hasImageSet())) { + if (translationX < minX && (currentEditMode != EDIT_MODE_NONE || !rightImage.hasImageSet()) || translationX > maxX && (currentEditMode != EDIT_MODE_NONE || !leftImage.hasImageSet())) { moveDx /= 3.0f; } - if (maxY == 0 && minY == 0 && currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { + if (maxY == 0 && minY == 0 && currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR) { if (translationY - moveDy < minY) { translationY = minY; moveDy = 0; @@ -13489,7 +13708,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } translationX -= moveDx; - if (scale != 1 || currentEditMode != 0) { + if (scale != 1 || currentEditMode != EDIT_MODE_NONE) { translationY -= moveDy; } containerView.invalidate(); @@ -13535,7 +13754,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animateTo(3.0f, atx, aty, true); } else { checkMinMax(true); - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { float moveToX = translationX; float moveToY = translationY; updateMinMax(scale); @@ -13581,7 +13800,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat velocity = velocityTracker.getXVelocity(); } - if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR) { if ((translationX < minX - getContainerViewWidth() / 3 || velocity < -AndroidUtilities.dp(650)) && rightImage.hasImageSet()) { goToNext(); return true; @@ -13869,7 +14088,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat int containerWidth = getContainerViewWidth(); int containerHeight = getContainerViewHeight(); if (animationInProgress != 2 && animationInProgress != 4 && !pipAnimationInProgress && !isInline) { - if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR && scale == 1 && aty != -1 && !zoomAnimation) { + if (currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR && scale == 1 && aty != -1 && !zoomAnimation) { float maxValue = containerWidth / 4.0f; backgroundDrawable.setAlpha((int) Math.max(127, 255 * (1.0f - (Math.min(Math.abs(aty), maxValue) / maxValue)))); } else { @@ -13880,7 +14099,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } sideImage = null; - if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR) { if (scale >= 1.0f && !zoomAnimation && !zooming) { if (currentTranslationX > maxX + AndroidUtilities.dp(5)) { sideImage = leftImage; @@ -13922,6 +14141,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canvas.scale(1.0f - scaleDiff, 1.0f - scaleDiff); int bitmapWidth = sideImage.getBitmapWidth(); int bitmapHeight = sideImage.getBitmapHeight(); + if (!rightImageIsVideo && rightCropTransform.hasViewTransform()) { + applyCrop(canvas, containerWidth, containerHeight, bitmapWidth, bitmapHeight, currentScale, rightCropTransform, rightCropState); + } float scaleX = containerWidth / (float) bitmapWidth; float scaleY = containerHeight / (float) bitmapHeight; @@ -13958,7 +14180,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat float translateX = currentTranslationX; float scaleDiff = 0; float alpha = 1; - if (!zoomAnimation && translateX > maxX && currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { + if (!zoomAnimation && translateX > maxX && currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR) { alpha = Math.min(1.0f, (translateX - maxX) / containerWidth); scaleDiff = alpha * 0.3f; alpha = 1.0f - alpha; @@ -13968,9 +14190,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (centerImage.hasBitmapImage() || drawTextureView && textureUploaded) { canvas.save(); canvas.translate(containerWidth / 2 + getAdditionX(), containerHeight / 2 + getAdditionY()); - canvas.translate(translateX, currentTranslationY + (currentEditMode != 3 ? currentPanTranslationY : currentPanTranslationY / 2)); + canvas.translate(translateX, currentTranslationY + (currentEditMode != EDIT_MODE_PAINT ? currentPanTranslationY : currentPanTranslationY / 2)); canvas.scale(currentScale - scaleDiff, currentScale - scaleDiff); - if (currentEditMode == 3 && keyboardSize > AndroidUtilities.dp(20)) { + if (currentEditMode == EDIT_MODE_PAINT && keyboardSize > AndroidUtilities.dp(20)) { int trueH = getContainerViewHeight(true, 0); int h = getContainerViewHeight(false, 0); if (trueH != h) { @@ -13994,7 +14216,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat int width = centerImage.getBitmapWidth(); int height = centerImage.getBitmapHeight(); float scale; - if (isCurrentVideo && currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (isCurrentVideo && currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { scale = getCropFillScale(false); } else { scale = Math.min(containerWidth / (float) width, containerHeight / (float) height); @@ -14027,12 +14249,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat boolean applyCrop; float scaleToFitX = 1.0f; if (!imagesArrLocals.isEmpty()) { - if (currentEditMode == 3 || switchingToMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT || switchingToMode == 3) { applyCrop = true; } else if (sendPhotoType == SELECT_TYPE_AVATAR) { - applyCrop = (switchingToMode == 0 || currentEditMode != 3 && currentEditMode != 2); + applyCrop = (switchingToMode == 0 || currentEditMode != EDIT_MODE_PAINT && currentEditMode != EDIT_MODE_FILTER); } else { - applyCrop = imageMoveAnimation != null && switchingToMode != -1 || currentEditMode == 0 || currentEditMode == 1 || switchingToMode != -1; + applyCrop = imageMoveAnimation != null && switchingToMode != -1 || currentEditMode == EDIT_MODE_NONE || currentEditMode == EDIT_MODE_CROP || switchingToMode != -1; } } else { applyCrop = false; @@ -14145,7 +14367,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } } - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { float add = containerView.adjustPanLayoutHelper.animationInProgress() ? keyboardSize / 2f + currentPanTranslationY / 2 : 0; photoPaintView.setTransform(currentScale, currentTranslationX, currentTranslationY + add, bitmapWidth * scaleToFitX, bitmapHeight * scaleToFitX); } @@ -14153,7 +14375,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (drawCenterImage) { boolean mirror = false; if (!imagesArrLocals.isEmpty()) { - if (currentEditMode == 1 || sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || sendPhotoType == SELECT_TYPE_AVATAR) { mirror = cropTransform.isMirrored(); } else { mirror = editState.cropState != null && editState.cropState.mirrored; @@ -14196,7 +14418,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } paintingOverlay.setAlpha(alpha); } - if (paintingOverlay.getVisibility() == View.VISIBLE && (isCurrentVideo || currentEditMode != 2 || switchingToMode != -1)) { + if (paintingOverlay.getVisibility() == View.VISIBLE && (isCurrentVideo || currentEditMode != EDIT_MODE_FILTER || switchingToMode != -1)) { canvas.clipRect(0, 0, paintingOverlay.getMeasuredWidth(), paintingOverlay.getMeasuredHeight()); paintingOverlay.draw(canvas); } @@ -14275,7 +14497,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canvas.translate(-(containerWidth * (scale + 1) + AndroidUtilities.dp(30)) / 2 + currentTranslationX, 0); int bitmapWidth = sideImage.getBitmapWidth(); int bitmapHeight = sideImage.getBitmapHeight(); - + if (!leftImageIsVideo && leftCropTransform.hasViewTransform()) { + applyCrop(canvas, containerWidth, containerHeight, bitmapWidth, bitmapHeight, currentScale, leftCropTransform, leftCropState); + } float scaleX = containerWidth / (float) bitmapWidth; float scaleY = containerHeight / (float) bitmapHeight; float scale = Math.min(scaleX, scaleY); @@ -14328,10 +14552,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat textureImageView.setImageDrawable(null); } } - if (pipVideoView != null) { - pipVideoView.close(); - pipVideoView = null; - } + PipVideoOverlay.dismiss(true); } else { containerView.invalidate(); } @@ -14348,6 +14569,102 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + private int[] tempInt = new int[2]; + + private int[] applyCrop(Canvas canvas, int containerWidth, int containerHeight, int bitmapWidth, int bitmapHeight, float currentScale, CropTransform cropTransform, MediaController.CropState cropState) { + int originalWidth = bitmapWidth; + int originalHeight = bitmapHeight; + float scale = Math.min(containerWidth / (float) originalWidth, containerHeight / (float) originalHeight); + int rotatedWidth = originalWidth; + int rotatedHeight = originalHeight; + int orientation = cropTransform.getOrientation(); + if (orientation == 90 || orientation == 270) { + int temp = bitmapWidth; + bitmapWidth = bitmapHeight; + bitmapHeight = temp; + + temp = rotatedWidth; + rotatedWidth = rotatedHeight; + rotatedHeight = temp; + } + float cropAnimationValue; + if (sendPhotoType != SELECT_TYPE_AVATAR && (currentEditMode == EDIT_MODE_PAINT || switchingToMode == EDIT_MODE_PAINT)) { + cropAnimationValue = 1.0f; + } else if (imageMoveAnimation != null && switchingToMode != -1) { + if (currentEditMode == 1 || switchingToMode == 1 || (currentEditMode == EDIT_MODE_FILTER || currentEditMode == EDIT_MODE_PAINT) && switchingToMode == -1) { + cropAnimationValue = 1.0f; + } else if (switchingToMode == 0) { + cropAnimationValue = animationValue; + } else { + cropAnimationValue = 1.0f - animationValue; + } + } else { + cropAnimationValue = currentEditMode == EDIT_MODE_FILTER || currentEditMode == EDIT_MODE_PAINT ? 0.0f : 1.0f; + } + float cropPw = cropTransform.getCropPw(); + float cropPh = cropTransform.getCropPh(); + bitmapWidth *= cropPw + (1.0f - cropPw) * (1.0f - cropAnimationValue); + bitmapHeight *= cropPh + (1.0f - cropPh) * (1.0f - cropAnimationValue); + float scaleToFitX = containerWidth / (float) bitmapWidth; + if (scaleToFitX * bitmapHeight > containerHeight) { + scaleToFitX = containerHeight / (float) bitmapHeight; + } + if (sendPhotoType != SELECT_TYPE_AVATAR && (currentEditMode != EDIT_MODE_CROP || switchingToMode == EDIT_MODE_NONE) && cropState != null) { + float startW = bitmapWidth * scaleToFitX; + float startH = bitmapHeight * scaleToFitX; + float originalScaleToFitX = containerWidth / (float) originalWidth; + if (originalScaleToFitX * originalHeight > containerHeight) { + originalScaleToFitX = containerHeight / (float) originalHeight; + } + float finalW = originalWidth * originalScaleToFitX / currentScale; + float finalH = originalHeight * originalScaleToFitX / currentScale; + + float w = startW + (finalW - startW) * (1.0f - cropAnimationValue); + float h = startH + (finalH - startH) * (1.0f - cropAnimationValue); + + canvas.clipRect(-w / 2, -h / 2, w / 2, h / 2); + } + if (sendPhotoType == SELECT_TYPE_AVATAR || cropTransform.hasViewTransform()) { + float cropScale; + if (currentEditMode == EDIT_MODE_CROP || sendPhotoType == SELECT_TYPE_AVATAR) { + float trueScale = 1.0f + (cropTransform.getTrueCropScale() - 1.0f) * (1.0f - cropAnimationValue); + cropScale = cropTransform.getScale() / trueScale; + float scaleToFit = containerWidth / (float) rotatedWidth; + if (scaleToFit * rotatedHeight > containerHeight) { + scaleToFit = containerHeight / (float) rotatedHeight; + } + cropScale *= scaleToFit / scale; + if (sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == 3 || switchingToMode == 3) { + cropScale /= 1.0f + (cropTransform.getMinScale() - 1.0f) * (1.0f - cropAnimationValue); + } else if (switchingToMode == 0) { + cropScale /= cropTransform.getMinScale(); + } + } + } else { + cropScale = cropState != null ? cropState.cropScale : 1.0f; + float trueScale = 1.0f + (cropScale - 1.0f) * (1.0f - cropAnimationValue); + cropScale *= scaleToFitX / scale / trueScale; + } + + canvas.translate(cropTransform.getCropAreaX() * cropAnimationValue, cropTransform.getCropAreaY() * cropAnimationValue); + canvas.scale(cropScale, cropScale); + canvas.translate(cropTransform.getCropPx() * rotatedWidth * scale * cropAnimationValue, cropTransform.getCropPy() * rotatedHeight * scale * cropAnimationValue); + float rotation = (cropTransform.getRotation() + orientation); + if (rotation > 180) { + rotation -= 360; + } + if (sendPhotoType == SELECT_TYPE_AVATAR && (currentEditMode == 3 || switchingToMode == 3)) { + canvas.rotate(rotation); + } else { + canvas.rotate(rotation * cropAnimationValue); + } + } + tempInt[0] = bitmapWidth; + tempInt[1] = bitmapHeight; + return tempInt; + } + private void onActionClick(boolean download) { if (currentMessageObject == null && currentBotInlineResult == null && pageBlocksAdapter == null || currentFileNames[0] == null) { return; @@ -14736,11 +15053,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean enableSwipeToPiP() { return false; -// if (!BuildVars.DEBUG_PRIVATE_VERSION) { -// return false; -// } -// boolean permissionsEnabled = Build.VERSION.SDK_INT < 23 || Settings.canDrawOverlays(parentActivity); -// return pipAvailable && textureUploaded && videoPlayer != null && videoPlayer.getRepeatCount() == 0 && permissionsEnabled && !(changingTextureView || switchingInlineMode || isInline); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 62c6f7bdb..cb150e18a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -59,6 +59,7 @@ import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; +import android.webkit.WebStorage; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; @@ -117,6 +118,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; @@ -140,11 +142,13 @@ import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.AudioPlayerAlert; +import org.telegram.ui.Components.AutoDeletePopupWrapper; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackButtonMenu; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatAvatarContainer; +import org.telegram.ui.Components.ChatNotificationsPopupWrapper; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CrossfadeDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -226,6 +230,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private AvatarDrawable avatarDrawable; private ImageUpdater imageUpdater; private int avatarColor; + TimerDrawable autoDeleteItemDrawable; private View scrimView = null; private Paint scrimPaint = new Paint(Paint.ANTI_ALIAS_FLAG) { @@ -260,7 +265,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private ActionBarMenuItem editItem; private ActionBarMenuItem otherItem; private ActionBarMenuItem searchItem; + private ImageView ttlIconView; private ActionBarMenuItem qrItem; + private ActionBarMenuSubItem autoDeleteItem; + AutoDeletePopupWrapper autoDeletePopupWrapper; protected float headerShadowAlpha = 1.0f; private TopView topView; private long userId; @@ -289,6 +297,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private int playProfileAnimation; private boolean needTimerImage; private boolean allowProfileAnimation = true; + private boolean disableProfileAnimation = false; private float extraHeight; private float initialAnimationExtraHeight; private float animationProgress; @@ -416,6 +425,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private int infoSectionRow; private int sendMessageRow; private int reportRow; + private int addToGroupButtonRow; + private int addToGroupInfoRow; private int settingsTimerRow; private int settingsKeyRow; @@ -1664,22 +1675,54 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putInt("dialogsType", 2); - args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); + args.putBoolean("resetDelegate", false); + args.putBoolean("closeFragment", false); +// args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { long did = dids.get(0); - Bundle args1 = new Bundle(); - args1.putBoolean("scrollToTopOnResume", true); - args1.putLong("chat_id", -did); - if (!getMessagesController().checkCanOpenChat(args1, fragment1)) { - return; - } - getNotificationCenter().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); - getNotificationCenter().postNotificationName(NotificationCenter.closeChats); - getMessagesController().addUserToChat(-did, user, 0, null, ProfileActivity.this, null); - presentFragment(new ChatActivity(args1), true); - removeSelfFromStack(); + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); + if (chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.add_admins)) { + getMessagesController().checkIsInChat(chat, user, (isInChatAlready, rightsAdmin, currentRank) -> AndroidUtilities.runOnUIThread(() -> { + ChatRightsEditActivity editRightsActivity = new ChatRightsEditActivity(userId, -did, rightsAdmin, null, null, currentRank, ChatRightsEditActivity.TYPE_ADD_BOT, true, !isInChatAlready, null); + editRightsActivity.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { + @Override + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { + disableProfileAnimation = true; + fragment.removeSelfFromStack(); + getNotificationCenter().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + getNotificationCenter().postNotificationName(NotificationCenter.closeChats); + } + + @Override + public void didChangeOwner(TLRPC.User user) {} + }); + presentFragment(editRightsActivity); + })); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AddBot", R.string.AddBot)); + String chatName = chat == null ? "" : chat.title; + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(user), chatName))); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setPositiveButton(LocaleController.getString("AddBot", R.string.AddBot), (di, i) -> { + disableProfileAnimation = true; + + Bundle args1 = new Bundle(); + args1.putBoolean("scrollToTopOnResume", true); + args1.putLong("chat_id", -did); + if (!getMessagesController().checkCanOpenChat(args1, fragment1)) { + return; + } + ChatActivity chatActivity = new ChatActivity(args1); + getNotificationCenter().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + getNotificationCenter().postNotificationName(NotificationCenter.closeChats); + getMessagesController().addUserToChat(-did, user, 0, null, chatActivity, true, null, null); + presentFragment(chatActivity, true); + }); + showDialog(builder.create()); + } }); presentFragment(fragment); } else if (id == share) { @@ -2388,6 +2431,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. editItem = menu.addItem(edit_channel, R.drawable.group_edit_profile); editItem.setContentDescription(LocaleController.getString("Edit", R.string.Edit)); otherItem = menu.addItem(10, R.drawable.ic_ab_other); + ttlIconView = new ImageView(context); + AndroidUtilities.updateViewVisibilityAnimated(ttlIconView, false, 0.8f, false); + ttlIconView.setImageResource(R.drawable.msg_mini_autodelete_timer); + otherItem.addView(ttlIconView, LayoutHelper.createFrame(12, 12, Gravity.CENTER_VERTICAL | Gravity.LEFT, 8, 2, 0, 0)); otherItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); int scrollTo; @@ -2512,7 +2559,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override protected void onAllAnimationsDone() { super.onAllAnimationsDone(); - getNotificationCenter().onAnimationFinish(animationIndex); + AndroidUtilities.runOnUIThread(() -> { + getNotificationCenter().onAnimationFinish(animationIndex); + }); } @Override @@ -2603,6 +2652,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (getParentActivity() == null) { return; } + listView.stopScroll(); if (position == settingsKeyRow) { Bundle args = new Bundle(); args.putInt("chat_id", DialogObject.getEncryptedChatId(dialogId)); @@ -2661,12 +2711,65 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } return; } - AlertsCreator.showCustomNotificationsDialog(ProfileActivity.this, did, -1, null, currentAccount, param -> listAdapter.notifyItemChanged(notificationsRow)); + ChatNotificationsPopupWrapper chatNotificationsPopupWrapper = new ChatNotificationsPopupWrapper(context, currentAccount, null, true, true, new ChatNotificationsPopupWrapper.Callback() { + @Override + public void dismiss() { + + } + + @Override + public void toggleSound() { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + boolean enabled = !preferences.getBoolean("sound_enabled_" + did, true); + preferences.edit().putBoolean("sound_enabled_" + did, enabled).apply(); + if (BulletinFactory.canShowBulletin(ProfileActivity.this)) { + BulletinFactory.createSoundEnabledBulletin(ProfileActivity.this, enabled ? NotificationsController.SETTING_SOUND_ON : NotificationsController.SETTING_SOUND_OFF, getResourceProvider()).show(); + } + } + + @Override + public void muteFor(int timeInSeconds) { + getNotificationsController().muteUntil(did, timeInSeconds); + if (BulletinFactory.canShowBulletin(ProfileActivity.this)) { + BulletinFactory.createMuteBulletin(ProfileActivity.this, NotificationsController.SETTING_MUTE_CUSTOM, timeInSeconds, getResourceProvider()).show(); + } + if (notificationsRow >= 0) { + listAdapter.notifyItemChanged(notificationsRow); + } + } + + @Override + public void showCustomize() { + if (did != 0) { + Bundle args = new Bundle(); + args.putLong("dialog_id", did); + presentFragment(new ProfileNotificationsActivity(args)); + } + } + + @Override + public void toggleMute() { + boolean muted = getMessagesController().isDialogMuted(did); + getNotificationsController().muteDialog(did, !muted); + BulletinFactory.createMuteBulletin(ProfileActivity.this, getMessagesController().isDialogMuted(dialogId), null).show(); + if (notificationsRow >= 0) { + listAdapter.notifyItemChanged(notificationsRow); + } + } + }, getResourceProvider()); + chatNotificationsPopupWrapper.update(did); + chatNotificationsPopupWrapper.showAsOptions(ProfileActivity.this, view, x, y); } else if (position == unblockRow) { getMessagesController().unblockPeer(userId); if (BulletinFactory.canShowBulletin(ProfileActivity.this)) { BulletinFactory.createBanBulletin(ProfileActivity.this, false).show(); } + } else if (position == addToGroupButtonRow) { + try { + actionBar.getActionBarMenuOnItemClick().onItemClick(invite_to_group); + } catch (Exception e) { + FileLog.e(e); + } } else if (position == sendMessageRow) { onWriteButtonClick(); } else if (position == reportRow) { @@ -2815,7 +2918,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. Build.VERSION.SDK_INT >= 21 ? (SharedConfig.noStatusBar ? "Show status bar background" : "Hide status bar background") : null, BuildVars.DEBUG_PRIVATE_VERSION ? "Clean app update" : null, BuildVars.DEBUG_PRIVATE_VERSION ? "Reset suggestions" : null, - BuildVars.DEBUG_PRIVATE_VERSION ? LocaleController.getString(SharedConfig.forceRtmpStream ? R.string.DebugMenuDisableForceRtmpStreamFlag : R.string.DebugMenuEnableForceRtmpStreamFlag) : null + BuildVars.DEBUG_PRIVATE_VERSION ? LocaleController.getString(SharedConfig.forceRtmpStream ? R.string.DebugMenuDisableForceRtmpStreamFlag : R.string.DebugMenuEnableForceRtmpStreamFlag) : null, + BuildVars.DEBUG_PRIVATE_VERSION ? LocaleController.getString(R.string.DebugMenuClearWebViewCache) : null }; builder.setItems(items, (dialog, which) -> { if (which == 0) { @@ -2888,6 +2992,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. getNotificationCenter().postNotificationName(NotificationCenter.newSuggestionsAvailable); } else if (which == 17) { SharedConfig.toggleForceRTMPStream(); + } else if (which == 18) { + ApplicationLoader.applicationContext.deleteDatabase("webview.db"); + ApplicationLoader.applicationContext.deleteDatabase("webviewCache.db"); + WebStorage.getInstance().deleteAllData(); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -3021,7 +3129,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. frameLayout.addView(frameLayout1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.LEFT | Gravity.BOTTOM)); frameLayout1.setOnClickListener(v -> { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, banFromGroup, null, chat.default_banned_rights, currentChannelParticipant != null ? currentChannelParticipant.banned_rights : null, "", ChatRightsEditActivity.TYPE_BANNED, true, false); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, banFromGroup, null, chat.default_banned_rights, currentChannelParticipant != null ? currentChannelParticipant.banned_rights : null, "", ChatRightsEditActivity.TYPE_BANNED, true, false, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -3155,9 +3263,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. timeItem.setPadding(AndroidUtilities.dp(10), AndroidUtilities.dp(10), AndroidUtilities.dp(5), AndroidUtilities.dp(5)); timeItem.setScaleType(ImageView.ScaleType.CENTER); timeItem.setAlpha(0.0f); - timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context)); + timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context, null)); frameLayout.addView(timeItem, LayoutHelper.createFrame(34, 34, Gravity.TOP | Gravity.LEFT)); - updateTimeItem(); showAvatarProgress(false, false); @@ -3498,9 +3605,25 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. scrimPaint.setAlpha(0); actionBarBackgroundPaint.setColor(Theme.getColor(Theme.key_listSelector)); contentView.blurBehindViews.add(sharedMediaLayout); + updateTtlIcon(); return fragmentView; } + private void updateTtlIcon() { + if (ttlIconView == null) { + return; + } + boolean visible = false; + if (currentEncryptedChat == null) { + if (userInfo != null && userInfo.ttl_period > 0) { + visible = true; + } else if (chatInfo != null && ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_DELETE_MESSAGES) && chatInfo.ttl_period > 0) { + visible = true; + } + } + AndroidUtilities.updateViewVisibilityAnimated(ttlIconView, visible, 0.8f, fragmentOpened); + } + public long getDialogId() { if (dialogId != 0) { return dialogId; @@ -3760,7 +3883,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private void openRightsEdit(int action, TLRPC.User user, TLRPC.ChatParticipant participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean editingAdmin) { boolean[] needShowBulletin = new boolean[1]; - ChatRightsEditActivity fragment = new ChatRightsEditActivity(user.id, chatId, adminRights, currentChat.default_banned_rights, bannedRights, rank, action, true, false) { + ChatRightsEditActivity fragment = new ChatRightsEditActivity(user.id, chatId, adminRights, currentChat.default_banned_rights, bannedRights, rank, action, true, false, null) { @Override protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { if (!isOpen && backward && needShowBulletin[0] && BulletinFactory.canShowBulletin(ProfileActivity.this)) { @@ -4663,7 +4786,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } - if (isPulledDown || overlaysView.animator != null && overlaysView.animator.isRunning()) { + if (isPulledDown || (overlaysView != null && overlaysView.animator != null && overlaysView.animator.isRunning())) { final ViewGroup.LayoutParams overlaysLp = overlaysView.getLayoutParams(); overlaysLp.width = listView.getMeasuredWidth(); overlaysLp.height = (int) (extraHeight + newTop); @@ -4864,7 +4987,6 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (currentEncryptedChat != null && chat.id == currentEncryptedChat.id) { currentEncryptedChat = chat; updateListAnimated(false); - updateTimeItem(); } } else if (id == NotificationCenter.blockedUsersDidLoad) { boolean oldValue = userBlocked; @@ -4915,7 +5037,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (currentChat.megagroup && (loadChannelParticipants || !byChannelUsers)) { getChannelParticipants(true); } - updateTimeItem(); + updateAutoDeleteItem(); + updateTtlIcon(); } } else if (id == NotificationCenter.closeChats) { removeSelfFromStack(); @@ -4947,7 +5070,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. needLayout(true); } } - updateTimeItem(); + updateAutoDeleteItem(); + updateTtlIcon(); } } else if (id == NotificationCenter.didReceiveNewMessages) { boolean scheduled = (Boolean) args[2]; @@ -4985,6 +5109,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } + private void updateAutoDeleteItem() { + if (autoDeleteItem == null || autoDeletePopupWrapper == null) { + return; + } + int ttl = 0; + if (userInfo != null || chatInfo != null) { + ttl = userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period; + } + autoDeleteItemDrawable.setTime(ttl); + autoDeletePopupWrapper.updateItems(ttl); + } + private void updateTimeItem() { if (timerDrawable == null) { return; @@ -5207,10 +5343,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } int actionBarColor = actionBarAnimationColorFrom != 0 ? actionBarAnimationColorFrom : Theme.getColor(Theme.key_actionBarDefault); + int actionBarColor2 = actionBarColor; if (SharedConfig.chatBlurEnabled()) { actionBarColor = ColorUtils.setAlphaComponent(actionBarColor, 0); } topView.setBackgroundColor(ColorUtils.blendARGB(actionBarColor, color, progress)); + timerDrawable.setBackgroundColor(ColorUtils.blendARGB(actionBarColor2, color, progress)); color = AvatarDrawable.getIconColorForId(userId != 0 || ChatObject.isChannel(chatId, currentAccount) && !currentChat.megagroup ? 5 : chatId); int iconColor = Theme.getColor(Theme.key_actionBarDefaultIcon); @@ -5261,7 +5399,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override protected AnimatorSet onCustomTransitionAnimation(final boolean isOpen, final Runnable callback) { - if (playProfileAnimation != 0 && allowProfileAnimation && !isPulledDown) { + if (playProfileAnimation != 0 && allowProfileAnimation && !isPulledDown && !disableProfileAnimation) { if (timeItem != null) { timeItem.setAlpha(1.0f); } @@ -5271,6 +5409,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. previousTransitionFragment = (ChatActivity) fragment; } } + if (previousTransitionFragment != null) { + updateTimeItem(); + } final AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(playProfileAnimation == 2 ? 250 : 180); listView.setLayerType(View.LAYER_TYPE_HARDWARE, null); @@ -5346,6 +5487,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. editItem.setAlpha(0.0f); animators.add(ObjectAnimator.ofFloat(editItem, View.ALPHA, 1.0f)); } + if (ttlIconView.getTag() != null) { + ttlIconView.setAlpha(0f); + animators.add(ObjectAnimator.ofFloat(ttlIconView, View.ALPHA, 1.0f)); + } boolean onlineTextCrosafade = false; BaseFragment previousFragment = parentLayout.fragmentsStack.size() > 1 ? parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2) : null; @@ -5380,6 +5525,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. animators.add(ObjectAnimator.ofFloat(nameTextView[a], View.ALPHA, a == 0 ? 1.0f : 0.0f)); } if (timeItem.getTag() != null) { + timeItem.setAlpha(0f); animators.add(ObjectAnimator.ofFloat(timeItem, View.ALPHA, 0.0f, 1.0f)); animators.add(ObjectAnimator.ofFloat(timeItem, View.SCALE_X, 0.0f, 1.0f)); animators.add(ObjectAnimator.ofFloat(timeItem, View.SCALE_Y, 0.0f, 1.0f)); @@ -5400,6 +5546,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. editItem.setAlpha(1.0f); animators.add(ObjectAnimator.ofFloat(editItem, View.ALPHA, 0.0f)); } + if (ttlIconView != null) { + animators.add(ObjectAnimator.ofFloat(ttlIconView, View.ALPHA, ttlIconView.getAlpha(), 0.0f)); + } boolean crossfadeOnlineText = false; BaseFragment previousFragment = parentLayout.fragmentsStack.size() > 1 ? parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2) : null; @@ -5645,6 +5794,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. infoSectionRow = -1; secretSettingsSectionRow = -1; bottomPaddingRow = -1; + addToGroupButtonRow = -1; + addToGroupInfoRow = -1; membersHeaderRow = -1; membersStartRow = -1; @@ -5765,6 +5916,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } + if (user != null && isBot && !user.bot_nochats) { // TODO(dkaraush): and had invite button sent + addToGroupButtonRow = rowCount++; + addToGroupInfoRow = rowCount++; + } + if (hasMedia || userInfo != null && userInfo.common_chats_count != 0) { sharedMediaRow = rowCount++; } else if (lastSectionRow == -1 && needSendMessage) { @@ -6194,7 +6350,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (actionBar == null || otherItem == null) { return; } - ActionBarMenu menu = actionBar.createMenu(); + Context context = actionBar.getContext(); otherItem.removeAllSubItems(); animatingItem = null; @@ -6222,6 +6378,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. otherItem.addSubItem(block_contact, R.drawable.msg_block, LocaleController.getString("Unblock", R.string.Unblock)); } } else { + if (currentEncryptedChat == null) { + createAutoDeleteItem(context); + } if (isBot) { if (!user.bot_nochats) { otherItem.addSubItem(invite_to_group, R.drawable.msg_addbot, LocaleController.getString("BotInvite", R.string.BotInvite)); @@ -6240,6 +6399,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } } else { + if (currentEncryptedChat == null) { + createAutoDeleteItem(context); + } + if (!TextUtils.isEmpty(user.phone)) { otherItem.addSubItem(share_contact, R.drawable.msg_share, LocaleController.getString("ShareContact", R.string.ShareContact)); } @@ -6255,6 +6418,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } else if (chatId != 0) { TLRPC.Chat chat = getMessagesController().getChat(chatId); hasVoiceChatItem = false; + if (ChatObject.canUserDoAdminAction(chat, ChatObject.ACTION_DELETE_MESSAGES)) { + createAutoDeleteItem(context); + } if (ChatObject.isChannel(chat)) { if (ChatObject.hasAdminRights(chat) || chat.megagroup && ChatObject.canChangeChatInfo(chat)) { editItemVisible = true; @@ -6396,6 +6562,37 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } + private void createAutoDeleteItem(Context context) { + autoDeletePopupWrapper = new AutoDeletePopupWrapper(context, otherItem.getPopupLayout().getSwipeBack(), new AutoDeletePopupWrapper.Callback() { + + @Override + public void dismiss() { + otherItem.toggleSubMenu(); + } + + @Override + public void setAutoDeleteHistory(int time, int action) { + ProfileActivity.this.setAutoDeleteHistory(time, action); + } + }, false, getResourceProvider()); + int ttl = 0; + if (userInfo != null || chatInfo != null) { + ttl = userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period; + } + autoDeleteItemDrawable = TimerDrawable.getTtlIcon(ttl); + autoDeleteItem = otherItem.addSwipeBackItem(0, autoDeleteItemDrawable, LocaleController.getString("AutoDeletePopupTitle", R.string.AutoDeletePopupTitle), autoDeletePopupWrapper.windowLayout); + otherItem.addColoredGap(); + updateAutoDeleteItem(); + } + + private void setAutoDeleteHistory(int time, int action) { + long did = getDialogId(); + getMessagesController().setDialogHistoryTTL(did, time); + if (userInfo != null || chatInfo != null) { + undoView.showWithAction(did, action, getMessagesController().getUser(did), userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period, null, null); + } + } + @Override protected void onDialogDismiss(Dialog dialog) { if (listView != null) { @@ -6942,7 +7139,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. VIEW_TYPE_BOTTOM_PADDING = 12, VIEW_TYPE_SHARED_MEDIA = 13, VIEW_TYPE_VERSION = 14, - VIEW_TYPE_SUGGESTION = 15; + VIEW_TYPE_SUGGESTION = 15, + VIEW_TYPE_ADDTOGROUP_INFO = 17; private Context mContext; @@ -7073,6 +7271,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. view = sharedMediaLayout; break; } + case VIEW_TYPE_ADDTOGROUP_INFO: { + view = new TextInfoPrivacyCell(mContext); + break; + } case VIEW_TYPE_VERSION: default: { TextInfoPrivacyCell cell = new TextInfoPrivacyCell(mContext, 10); @@ -7188,7 +7390,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. TextDetailCell detailCell = (TextDetailCell) holder.itemView; if (position == usernameRow) { Drawable drawable = ContextCompat.getDrawable(detailCell.getContext(), R.drawable.msg_qr_mini); - drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_switch2TrackChecked), PorterDuff.Mode.SRC_IN)); + drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_switch2TrackChecked), PorterDuff.Mode.MULTIPLY)); detailCell.setImage(drawable); } else { detailCell.setImage(null); @@ -7371,6 +7573,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. textCell.getImageView().setPadding(0, 0, 0, AndroidUtilities.dp(8)); textCell.setImageLeft(12); setAvatarCell = textCell; + } else if (position == addToGroupButtonRow) { + textCell.setTextAndIcon(LocaleController.getString("AddToGroupOrChannel", R.string.AddToGroupOrChannel), R.drawable.groups_create, false); // TODO(dkaraush): text! icon! + textCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); } break; case VIEW_TYPE_NOTIFICATIONS_CHECK: @@ -7429,6 +7634,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (val == null) { val = LocaleController.getString("NotificationsOff", R.string.NotificationsOff); } + checkCell.setAnimationsEnabled(fragmentOpened); checkCell.setTextAndValueAndCheck(LocaleController.getString("Notifications", R.string.Notifications), val, enabled, false); } break; @@ -7490,6 +7696,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. SettingsSuggestionCell suggestionCell = (SettingsSuggestionCell) holder.itemView; suggestionCell.setType(position == passwordSuggestionRow ? SettingsSuggestionCell.TYPE_PASSWORD : SettingsSuggestionCell.TYPE_PHONE); break; + case VIEW_TYPE_ADDTOGROUP_INFO: + TextInfoPrivacyCell addToGroupInfo = (TextInfoPrivacyCell) holder.itemView; + addToGroupInfo.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + addToGroupInfo.setText("This bot is able to manage a group or channel."); // TODO(dkaraush): text! + break; } } @@ -7509,7 +7720,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. position == versionRow || position == dataRow || position == chatRow || position == questionRow || position == devicesRow || position == filtersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == sendLastLogsRow || - position == clearLogsRow || position == switchBackendRow || position == setAvatarRow; + position == clearLogsRow || position == switchBackendRow || position == setAvatarRow || position == addToGroupButtonRow; } if (holder.itemView instanceof UserCell) { UserCell userCell = (UserCell) holder.itemView; @@ -7549,7 +7760,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. position == languageRow || position == dataRow || position == chatRow || position == questionRow || position == devicesRow || position == filtersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == sendLastLogsRow || - position == clearLogsRow || position == switchBackendRow || position == setAvatarRow) { + position == clearLogsRow || position == switchBackendRow || position == setAvatarRow || position == addToGroupButtonRow) { return VIEW_TYPE_TEXT; } else if (position == notificationsDividerRow) { return VIEW_TYPE_DIVIDER; @@ -7572,6 +7783,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return VIEW_TYPE_VERSION; } else if (position == passwordSuggestionRow || position == phoneSuggestionRow) { return VIEW_TYPE_SUGGESTION; + } else if (position == addToGroupInfoRow) { + return VIEW_TYPE_ADDTOGROUP_INFO; } return 0; } @@ -8554,6 +8767,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. put(++pointer, membersSectionRow, sparseIntArray); put(++pointer, sharedMediaRow, sparseIntArray); put(++pointer, unblockRow, sparseIntArray); + put(++pointer, addToGroupButtonRow, sparseIntArray); + put(++pointer, addToGroupInfoRow, sparseIntArray); put(++pointer, joinRow, sparseIntArray); put(++pointer, lastSectionRow, sparseIntArray); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java index 18a65e899..887bd0671 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java @@ -21,28 +21,30 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; -import android.text.TextUtils; -import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; -import android.widget.TextView; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ChatObject; -import org.telegram.messenger.DialogObject; -import org.telegram.messenger.MessagesController; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.HeaderCell; @@ -51,20 +53,16 @@ import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCheckBoxCell; import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextColorCell; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Cells.UserCell2; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - public class ProfileNotificationsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private RecyclerListView listView; @@ -80,6 +78,8 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi private ProfileNotificationsActivityDelegate delegate; + ChatAvatarContainer avatarContainer; + private int customRow; private int customInfoRow; private int generalRow; @@ -222,7 +222,6 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi @Override public View createView(final Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); - actionBar.setAllowOverlayTitle(true); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -270,11 +269,29 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi finishFragment(); } }); + + avatarContainer = new ChatAvatarContainer(context, null, false); + avatarContainer.setOccupyStatusBar(!AndroidUtilities.isTablet()); + + actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : 0, 0, 40, 0)); + actionBar.setAllowOverlayTitle(false); + if (dialogId < 0) { + TLRPC.Chat chatLocal = getMessagesController().getChat(-dialogId); + avatarContainer.setChatAvatar(chatLocal); + avatarContainer.setTitle(chatLocal.title); + } else { + TLRPC.User user = getMessagesController().getUser(dialogId); + if (user != null) { + avatarContainer.setUserAvatar(user); + avatarContainer.setTitle(ContactsController.formatName(user.first_name, user.last_name)); + } + } + if (addingException) { - actionBar.setTitle(LocaleController.getString("NotificationsNewException", R.string.NotificationsNewException)); + avatarContainer.setSubtitle(LocaleController.getString("NotificationsNewException", R.string.NotificationsNewException)); actionBar.createMenu().addItem(done_button, LocaleController.getString("Done", R.string.Done).toUpperCase()); } else { - actionBar.setTitle(LocaleController.getString("CustomNotifications", R.string.CustomNotifications)); + avatarContainer.setSubtitle(LocaleController.getString("CustomNotifications", R.string.CustomNotifications)); } fragmentView = new FrameLayout(context); @@ -295,48 +312,28 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { @Override public void onItemClick(View view, int position) { - if (position == customRow && view instanceof TextCheckBoxCell) { + if (position == customRow && view instanceof TextCheckCell) { SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); customEnabled = !customEnabled; notificationsEnabled = customEnabled; - preferences.edit().putBoolean("custom_" + dialogId, customEnabled).commit(); - TextCheckBoxCell cell = (TextCheckBoxCell) view; + preferences.edit().putBoolean("custom_" + dialogId, customEnabled).apply(); + TextCheckCell cell = (TextCheckCell) view; cell.setChecked(customEnabled); + int clr = Theme.getColor(customEnabled ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked); + if (customEnabled) { + cell.setBackgroundColorAnimated(customEnabled, clr); + } else { + cell.setBackgroundColorAnimatedReverse(clr); + } checkRowsEnabled(); } else if (customEnabled) { if (!view.isEnabled()) { return; } if (position == soundRow) { - try { - Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - Uri currentSound = null; - - String defaultPath = null; - Uri defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI; - if (defaultUri != null) { - defaultPath = defaultUri.getPath(); - } - - String path = preferences.getString("sound_path_" + dialogId, defaultPath); - if (path != null && !path.equals("NoSound")) { - if (path.equals(defaultPath)) { - currentSound = defaultUri; - } else { - currentSound = Uri.parse(path); - } - } - - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound); - startActivityForResult(tmpIntent, 12); - } catch (Exception e) { - FileLog.e(e); - } + Bundle bundle = new Bundle(); + bundle.putLong("dialog_id", dialogId); + presentFragment(new NotificationsSoundActivity(bundle)); } else if (position == ringtoneRow) { try { Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); @@ -406,77 +403,15 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi if (notifyMaxCount == 0) { notifyMaxCount = 2; } - final int selected = (notifyDelay / 60 - 1) * 10 + notifyMaxCount - 1; - - RecyclerListView list = new RecyclerListView(getParentActivity()); - list.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); - list.setClipToPadding(true); - list.setAdapter(new RecyclerListView.SelectionAdapter() { - @Override - public int getItemCount() { - return 100; - } - - @Override - public boolean isEnabled(RecyclerView.ViewHolder holder) { - return true; - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - TextView textView = new TextView(context1) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY)); - } - }; - textView.setGravity(Gravity.CENTER); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - textView.setSingleLine(true); - textView.setEllipsize(TextUtils.TruncateAt.END); - textView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - return new RecyclerListView.Holder(textView); - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - TextView textView = (TextView) holder.itemView; - textView.setTextColor(Theme.getColor(position == selected ? Theme.key_dialogTextGray : Theme.key_dialogTextBlack)); - int notifyMaxCount = position % 10; - int notifyDelay = position / 10; - String times = LocaleController.formatPluralString("Times", notifyMaxCount + 1); - String minutes = LocaleController.formatPluralString("Minutes", notifyDelay + 1); - textView.setText(LocaleController.formatString("SmartNotificationsDetail", R.string.SmartNotificationsDetail, times, minutes)); - } - }); - list.setPadding(0, AndroidUtilities.dp(12), 0, AndroidUtilities.dp(8)); - list.setOnItemClickListener((view1, position1) -> { - if (position1 < 0 || position1 >= 100) { - return; - } - int notifyMaxCount1 = position1 % 10 + 1; - int notifyDelay1 = position1 / 10 + 1; - SharedPreferences preferences1 = MessagesController.getNotificationsSettings(currentAccount); - preferences1.edit().putInt("smart_max_count_" + dialogId, notifyMaxCount1).commit(); - preferences1.edit().putInt("smart_delay_" + dialogId, notifyDelay1 * 60).commit(); + AlertsCreator.createSoundFrequencyPickerDialog(getParentActivity(), notifyMaxCount, notifyDelay, (time, minute) -> { + MessagesController.getNotificationsSettings(currentAccount).edit() + .putInt("smart_max_count_" + dialogId, time) + .putInt("smart_delay_" + dialogId, minute) + .apply(); if (adapter != null) { adapter.notifyItemChanged(smartRow); } - dismissCurrentDialog(); }); - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("SmartNotificationsAlert", R.string.SmartNotificationsAlert)); - builder.setView(list); - builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setNegativeButton(LocaleController.getString("SmartNotificationsDisabled", R.string.SmartNotificationsDisabled), (dialog, which) -> { - SharedPreferences preferences12 = MessagesController.getNotificationsSettings(currentAccount); - preferences12.edit().putInt("smart_max_count_" + dialogId, 0).commit(); - if (adapter != null) { - adapter.notifyItemChanged(smartRow); - } - dismissCurrentDialog(); - }); - showDialog(builder.create()); } else if (position == colorRow) { if (getParentActivity() == null) { return; @@ -699,8 +634,11 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 5: - view = new TextCheckBoxCell(context); - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + TextCheckCell checkBoxCell = new TextCheckCell(context); + checkBoxCell.setHeight(56); + checkBoxCell.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + checkBoxCell.setColors(Theme.key_windowBackgroundCheckText, Theme.key_switchTrackBlue, Theme.key_switchTrackBlueChecked, Theme.key_switchTrackBlueThumb, Theme.key_switchTrackBlueThumbChecked); + view = checkBoxCell; break; case 6: view = new UserCell2(context, 4, 0); @@ -740,8 +678,14 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); if (position == soundRow) { String value = preferences.getString("sound_" + dialogId, LocaleController.getString("SoundDefault", R.string.SoundDefault)); - if (value.equals("NoSound")) { + long documentId = preferences.getLong("sound_document_id_" + dialogId, 0); + if (documentId != 0) { + TLRPC.Document document = getMediaDataController().ringtoneDataStore.getDocument(documentId); + value = NotificationsSoundActivity.trimTitle(document, document.file_name_fixed); + } else if (value.equals("NoSound")) { value = LocaleController.getString("NoSound", R.string.NoSound); + } else if (value.equals("Default")) { + value = LocaleController.getString("SoundDefault", R.string.SoundDefault); } textCell.setTextAndValue(LocaleController.getString("Sound", R.string.Sound), value, true); } else if (position == ringtoneRow) { @@ -865,8 +809,8 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi break; } case 5: { - TextCheckBoxCell cell = (TextCheckBoxCell) holder.itemView; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + TextCheckCell cell = (TextCheckCell) holder.itemView; + cell.setBackgroundColor(Theme.getColor(customEnabled && notificationsEnabled ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked)); cell.setTextAndCheck(LocaleController.getString("NotificationsEnableCustom", R.string.NotificationsEnableCustom), customEnabled && notificationsEnabled, false); break; } @@ -1017,12 +961,6 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundBlue)); themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundPink)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, null, null, null, Theme.key_checkboxSquareUnchecked)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, null, null, null, Theme.key_checkboxSquareDisabled)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, null, null, null, Theme.key_checkboxSquareBackground)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, null, null, null, Theme.key_checkboxSquareCheck)); - return themeDescriptions; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java index 357b85b30..03b6032d9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java @@ -19,6 +19,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.RectF; import android.graphics.SurfaceTexture; @@ -54,6 +55,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; @@ -269,6 +271,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD private float dragY; private float clipTop; private float clipBottom; + private float clipTopOrigin; + private float clipBottomOrigin; private float clipHorizontal; private float translationX; private float translationY; @@ -279,7 +283,11 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD private float animateToScale; private float animateToClipTop; private float animateToClipBottom; + private float animateToClipTopOrigin; + private float animateToClipBottomOrigin; private float animateToClipHorizontal; + private int[] animateFromRadius; + private boolean animateToRadius; private float animationValue; private int currentRotation; private long animationStartTime; @@ -723,6 +731,14 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD int viewHeight = AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); scale = Math.max(width / viewWidth, height / viewHeight); + if (object.radius != null) { + animateFromRadius = new int[object.radius.length]; + for (int i = 0; i < object.radius.length; ++i) { + animateFromRadius[i] = object.radius[i]; + } + } else { + animateFromRadius = null; + } translationX = object.viewX + drawRegion.left + width / 2 - viewWidth / 2; translationY = object.viewY + drawRegion.top + height / 2 - viewHeight / 2; clipHorizontal = Math.abs(drawRegion.left - object.imageReceiver.getImageX()); @@ -730,24 +746,25 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD int[] coords2 = new int[2]; object.parentView.getLocationInWindow(coords2); clipTop = coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; - if (clipTop < 0) { - clipTop = 0; - } + clipTop = Math.max(0, Math.max(clipTop, clipVertical)); clipBottom = (object.viewY + drawRegion.top + (int) height) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; - if (clipBottom < 0) { - clipBottom = 0; - } - clipTop = Math.max(clipTop, clipVertical); - clipBottom = Math.max(clipBottom, clipVertical); + clipBottom = Math.max(0, Math.max(clipBottom, clipVertical)); + clipTopOrigin = 0;//coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; + clipTopOrigin = Math.max(0, Math.max(clipTopOrigin, clipVertical)); + clipBottomOrigin = 0;//(object.viewY + drawRegion.top + (int) height) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; + clipBottomOrigin = Math.max(0, Math.max(clipBottomOrigin, clipVertical)); animationStartTime = System.currentTimeMillis(); animateToX = 0; animateToY = 0; animateToClipBottom = 0; + animateToClipBottomOrigin = 0; animateToClipHorizontal = 0; animateToClipTop = 0; + animateToClipTopOrigin = 0; animateToScale = 1.0f; + animateToRadius = true; zoomAnimation = true; NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagesDeleted); @@ -939,6 +956,9 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD } + private float[] currentRadii; + private Path roundRectPath = new Path(); + private void onDraw(Canvas canvas) { if (!isPhotoVisible) { return; @@ -949,6 +969,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD float currentScale; float currentClipTop; float currentClipBottom; + float currentClipTopOrigin; + float currentClipBottomOrigin; float currentClipHorizontal; float aty = -1; @@ -972,6 +994,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD currentTranslationX = translationX + (animateToX - translationX) * av; currentClipTop = clipTop + (animateToClipTop - clipTop) * av; currentClipBottom = clipBottom + (animateToClipBottom - clipBottom) * av; + currentClipTopOrigin = clipTopOrigin + (animateToClipTopOrigin - clipTopOrigin) * av; + currentClipBottomOrigin = clipBottomOrigin + (animateToClipBottomOrigin - clipBottomOrigin) * av; currentClipHorizontal = clipHorizontal + (animateToClipHorizontal - clipHorizontal) * av; } else { currentScale = scale + (animateToScale - scale) * animationValue; @@ -979,8 +1003,11 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD currentTranslationX = translationX + (animateToX - translationX) * animationValue; currentClipTop = clipTop + (animateToClipTop - clipTop) * animationValue; currentClipBottom = clipBottom + (animateToClipBottom - clipBottom) * animationValue; + currentClipTopOrigin = clipTopOrigin + (animateToClipTopOrigin - clipTopOrigin) * animationValue; + currentClipBottomOrigin = clipBottomOrigin + (animateToClipBottomOrigin - clipBottomOrigin) * animationValue; currentClipHorizontal = clipHorizontal + (animateToClipHorizontal - clipHorizontal) * animationValue; } + if (animateToScale == 1 && scale == 1 && translationX == 0) { aty = currentTranslationY; } @@ -992,6 +1019,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD translationY = animateToY; clipBottom = animateToClipBottom; clipTop = animateToClipTop; + clipTopOrigin = animateToClipTopOrigin; + clipBottomOrigin = animateToClipBottomOrigin; clipHorizontal = animateToClipHorizontal; scale = animateToScale; animationStartTime = 0; @@ -1015,12 +1044,29 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD currentTranslationX = translationX; currentClipTop = clipTop; currentClipBottom = clipBottom; + currentClipTopOrigin = clipTopOrigin; + currentClipBottomOrigin = clipBottomOrigin; currentClipHorizontal = clipHorizontal; if (!moving) { aty = translationY; } } + boolean zeroRadius = true; + if (animateFromRadius != null) { + if (currentRadii == null) { + currentRadii = new float[8]; + } + float t = animateToRadius ? animationValue : 1f - animationValue; + zeroRadius = true; + for (int i = 0; i < 8; i += 2) { + currentRadii[i] = currentRadii[i + 1] = AndroidUtilities.lerp((float) animateFromRadius[i / 2] * 2, 0, t); + if (currentRadii[i] > 0) { + zeroRadius = false; + } + } + } + float translateX = currentTranslationX; float scaleDiff = 0; float alpha = 1; @@ -1061,6 +1107,12 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD int height = (int) (bitmapHeight * scale); canvas.clipRect(-width / 2 + currentClipHorizontal / sc, -height / 2 + currentClipTop / sc, width / 2 - currentClipHorizontal / sc, height / 2 - currentClipBottom / sc); + if (!zeroRadius) { + roundRectPath.reset(); + AndroidUtilities.rectTmp.set(-width / 2 + currentClipHorizontal / sc, -height / 2 + currentClipTopOrigin / sc, width / 2 - currentClipHorizontal / sc, height / 2 - currentClipBottomOrigin / sc); + roundRectPath.addRoundRect(AndroidUtilities.rectTmp, currentRadii, Path.Direction.CW); + canvas.clipPath(roundRectPath); + } if (!drawTextureView || !textureUploaded || !videoCrossfadeStarted || videoCrossfadeAlpha != 1.0f) { centerImage.setAlpha(alpha); @@ -1181,21 +1233,22 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD int[] coords2 = new int[2]; object.parentView.getLocationInWindow(coords2); animateToClipTop = coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; - if (animateToClipTop < 0) { - animateToClipTop = 0; - } + animateToClipTop = Math.max(0, Math.max(animateToClipTop, clipVertical)); animateToClipBottom = (object.viewY + drawRegion.top + (int) height) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; - if (animateToClipBottom < 0) { - animateToClipBottom = 0; - } + animateToClipBottom = Math.max(0, Math.max(animateToClipBottom, clipVertical)); + + animateToClipTopOrigin = 0; // coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; + animateToClipTopOrigin = Math.max(0, Math.max(animateToClipTopOrigin, clipVertical)); + animateToClipBottomOrigin = 0; // (object.viewY + drawRegion.top + (int) height) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; + animateToClipBottomOrigin = Math.max(0, Math.max(animateToClipBottomOrigin, clipVertical)); + animationStartTime = System.currentTimeMillis(); - animateToClipBottom = Math.max(animateToClipBottom, clipVertical); - animateToClipTop = Math.max(animateToClipTop, clipVertical); zoomAnimation = true; } else { int h = (AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)); animateToY = translationY >= 0 ? h : -h; } + animateToRadius = false; if (isVideo) { videoCrossfadeStarted = false; textureUploaded = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java index cbbd2c235..4dfd602a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java @@ -2654,7 +2654,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente builder.setItems(items.toArray(new CharSequence[actions.size()]), AndroidUtilities.toIntArray(icons), (dialogInterface, i) -> { if (actions.get(i) == 0) { boolean[] needShowBulletin = new boolean[1]; - ChatRightsEditActivity newFragment = new ChatRightsEditActivity(user.id, chat.id, finalCurrentParticipant.channelParticipant.admin_rights, null, finalCurrentParticipant.channelParticipant.banned_rights, finalCurrentParticipant.channelParticipant.rank, ChatRightsEditActivity.TYPE_ADMIN, true, finalIsAdmin) { + ChatRightsEditActivity newFragment = new ChatRightsEditActivity(user.id, chat.id, finalCurrentParticipant.channelParticipant.admin_rights, null, finalCurrentParticipant.channelParticipant.banned_rights, finalCurrentParticipant.channelParticipant.rank, ChatRightsEditActivity.TYPE_ADMIN, true, finalIsAdmin, null) { @Override protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { if (!isOpen && backward && needShowBulletin[0] && BulletinFactory.canShowBulletin(fragment)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java index bbe074968..2e23d8cc4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java @@ -75,6 +75,7 @@ import org.telegram.ui.Cells.ChatListCell; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.NotificationsCheckCell; +import org.telegram.ui.Cells.RadioButtonCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextCheckCell; @@ -134,6 +135,9 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No private int raiseToSpeakRow; private int sendByEnterRow; private int saveToGalleryRow; + private int saveToGalleryOption1Row; + private int saveToGalleryOption2Row; + private int saveToGallerySectionRow; private int distanceRow; private int enableAnimationsRow; private int settings2Row; @@ -508,6 +512,9 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No raiseToSpeakRow = -1; sendByEnterRow = -1; saveToGalleryRow = -1; + saveToGalleryOption1Row = -1; + saveToGalleryOption2Row = -1; + saveToGallerySectionRow = -1; distanceRow = -1; settings2Row = -1; stickersRow = -1; @@ -1991,6 +1998,9 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No case 18: view = new TextSettingsCell(mContext); break; + case 19: + view = new RadioButtonCell(mContext); + break; } return new RecyclerListView.Holder(view); } @@ -2055,7 +2065,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No break; } case 3: { - if (position == stickersSection2Row || position == nightTypeInfoRow && themeInfoRow == -1 || position == themeInfoRow && nightTypeInfoRow != -1) { + if (position == stickersSection2Row || position == nightTypeInfoRow && themeInfoRow == -1 || position == themeInfoRow && nightTypeInfoRow != -1 || position == saveToGallerySectionRow) { holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } else { holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); @@ -2204,6 +2214,16 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No } break; } + case 19:{ + RadioButtonCell radioCell = (RadioButtonCell) holder.itemView; + if (position == saveToGalleryOption1Row) { + radioCell.setTextAndValue("save media only from peer chats", "",true, false); + } else { + radioCell.setTextAndValue("save media from all chats", "",true, false); + } + + break; + } } } @@ -2228,7 +2248,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No return 2; } else if (position == themeInfoRow || position == nightTypeInfoRow || position == scheduleFromToInfoRow || position == stickersSection2Row || position == settings2Row || position == newThemeInfoRow || - position == chatListInfoRow || position == bubbleRadiusInfoRow || position == swipeGestureInfoRow) { + position == chatListInfoRow || position == bubbleRadiusInfoRow || position == swipeGestureInfoRow || position == saveToGallerySectionRow) { return 3; } else if (position == nightDisabledRow || position == nightScheduledRow || position == nightAutomaticRow || position == nightSystemDefaultRow) { return 4; @@ -2264,6 +2284,8 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No return 17; } else if (position == reactionsDoubleTapRow) { return 18; + } else if (position == saveToGalleryOption1Row || position == saveToGalleryOption2Row) { + return 19; } return 1; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java index a292ba0bf..5cdd2fe4a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java @@ -1547,39 +1547,39 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro messagesPlayAnimationImageView.setScaleType(ImageView.ScaleType.CENTER); messagesPlayAnimationImageView.setImageResource(R.drawable.bg_rotate_large); messagesPlayAnimationView.addView(messagesPlayAnimationImageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + + for (int a = 0; a < 2; a++) { + final int num = a; + messagesCheckBoxView[a] = new WallpaperCheckBoxView(context, a == 0, backgroundImage); + messagesCheckBoxView[a].setText(texts[a], textSizes[a], maxTextSize); + + if (a == 0) { + messagesCheckBoxView[a].setChecked(accent.myMessagesAnimated, false); + } + int width = maxTextSize + AndroidUtilities.dp(14 * 2 + 28); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.gravity = Gravity.CENTER; + if (a == 1) { + layoutParams.leftMargin = width / 2 + AndroidUtilities.dp(10); + } else { + layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); + } + messagesButtonsContainer.addView(messagesCheckBoxView[a], layoutParams); + WallpaperCheckBoxView view = messagesCheckBoxView[a]; + messagesCheckBoxView[a].setOnClickListener(v -> { + if (messagesButtonsContainer.getAlpha() != 1.0f) { + return; + } + if (num == 0) { + view.setChecked(!view.isChecked(), true); + accent.myMessagesAnimated = view.isChecked(); + Theme.refreshThemeColors(true, true); + listView2.invalidateViews(); + } + }); + } } - - for (int a = 0; a < 2; a++) { - final int num = a; - messagesCheckBoxView[a] = new WallpaperCheckBoxView(context, a == 0, backgroundImage); - messagesCheckBoxView[a].setText(texts[a], textSizes[a], maxTextSize); - - if (a == 0) { - messagesCheckBoxView[a].setChecked(accent.myMessagesAnimated, false); - } - int width = maxTextSize + AndroidUtilities.dp(14 * 2 + 28); - FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.gravity = Gravity.CENTER; - if (a == 1) { - layoutParams.leftMargin = width / 2 + AndroidUtilities.dp(10); - } else { - layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); - } - messagesButtonsContainer.addView(messagesCheckBoxView[a], layoutParams); - WallpaperCheckBoxView view = messagesCheckBoxView[a]; - messagesCheckBoxView[a].setOnClickListener(v -> { - if (messagesButtonsContainer.getAlpha() != 1.0f) { - return; - } - if (num == 0) { - view.setChecked(!view.isChecked(), true); - accent.myMessagesAnimated = view.isChecked(); - Theme.refreshThemeColors(true, true); - listView2.invalidateViews(); - } - }); - } } if (screenType == SCREEN_TYPE_ACCENT_COLOR || currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java index 93eea235a..a1d36292c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java @@ -39,6 +39,7 @@ import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; +import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -199,9 +200,6 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), false); actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarWhiteSelector), false); actionBar.setCastShadows(false); - if (!AndroidUtilities.isTablet()) { - actionBar.showActionModeTop(); - } } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override @@ -1297,4 +1295,10 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific super.finishFragment(); } } + + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + return ColorUtils.calculateLuminance(color) > 0.7f; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java index ece4f9d3b..e1084b358 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java @@ -51,6 +51,8 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; +import androidx.core.graphics.ColorUtils; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -252,9 +254,6 @@ public class TwoStepVerificationSetupActivity extends BaseFragment { actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarWhiteSelector), false); actionBar.setCastShadows(false); actionBar.setAddToContainer(false); - if (!AndroidUtilities.isTablet()) { - actionBar.showActionModeTop(); - } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -2186,4 +2185,10 @@ public class TwoStepVerificationSetupActivity extends BaseFragment { super.finishFragment(); } } + + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + return ColorUtils.calculateLuminance(color) > 0.7f; + } } diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_invite.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_invite.png new file mode 100644 index 0000000000000000000000000000000000000000..73e5707c132aa8d743802a8098a092ef8be0ce23 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^{2``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBeyyjAV@L(#(Mbn+8x(k4qaVk*7qFNYh?yrc zhXWZ2tU&IZ1=DUYE3WKn`7nuJ@rz>+g9f7@ugv3gk5*N0^VwmS4_L?c@wldZX*NlH z_~qa|jqKw$mGj+>FuRydY5N$bt-f}Srd90jo1T09K7@p=UU~hk`p=gADSzMU$JBOa VPII|D;R4Vh44$rjF6*2UngFOaOx*wg literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_webview.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_webview.png new file mode 100644 index 0000000000000000000000000000000000000000..475d08f2e00e043672ba1704778b11fe497b63c9 GIT binary patch literal 336 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#?ecVS46zV= zJK2`+kO5Dt^gljk_J+pJX5)*ETzv3Zt>6|MVxrt|cO&bv~Q zCjVsWiN585o9@kjIXyme2dnsT2Zi#CRI|Sqte)nx%K1v3l`~Z~0)-cYr>mdKI;Vst E0IXDQ+W-In literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete.png new file mode 100644 index 0000000000000000000000000000000000000000..33cb8df2c835d8706fd69a05e6f9455824b83cdb GIT binary patch literal 928 zcmV;R17G}!P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz03Q0skR9Fe^m_29|K@`WcQT&V{ zK}1l{A|Hq-#zKo=V-pn-MePL(3wx1B;1Em%n?Q~Z2manbS}g?UmC3nnxht*1sAGgIx*^0iz<&tRd(|jMk(Uz7u_Y64 z+>y?lguL(|gmg1%a568^#23xzZOC33d!=GDXCZxXi1N>Hb*j!>$elC6_ZbqGzhdrZ zp+!y30JsUX2KzI@feHB9YP1<=7eA9NKlXvz#Y3jsmN&-O%GB!y+k$)urTuh-3Yjne zno-N+fXhukWj9Q4BjZJvSh7Ec-VUJp>w?;J-0tH?KQ***%4UMiCdR_eEF zD7PWgR6CEbeKhm{oQrD4l1M1+kdM}CklxX4skjjV{ertqE%3SMYfuk46F|9Nz}C3x z0Tv>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0eMv+?R9Fe^m`!XT|oOjOuoO|Zo`|i6lWo7@R@Eu4M4u_-Zbh?JfIP*K-L1bHKRLIvSu_6 z^{xZS5LoVy9ke0Y)1)<1l4qUJK7W+V^&Se^|*`;19z9-%}I2551E45Oz;mL;f7 zPohUV_R|zuFd{(h6xaneMNl$xTLZy%;Pw!a_$qJ#ya4-*gS{JQvGzGUMeED$1(S@I zNRzk?m^6(|CUDAvP7fG|>o?A)wejBBrtV-&G45DREZi`G79i2)yDDG&QP8 zSm~0UMI`UUe-T`>xIbmKSmj$|goL`9M&^UnBIGoFe0Hj7oxc z8c4oa5$x9)Px#{&?!3JQUoDtxHG&$#xUUX4Iw@-JIB!L;o52TQBKs~l1pH-@Nx`Qt z{|IQ$vuU+*qnco>mn*!=(X8Ya`6qx$Q^5+bCi?iXkTJfwZn_FKqaehIKA;_N&1kwB z#%;(oHIYZydK$S3cEoDNNF;OslcEm!6sZKZ1=tYDGzF@F-_#)2Nq+|Et$z$CcL3-G zU7S!v(`Sc%%*<)B;15NO2yY{Js{|)n$R+#rs)cS(pA8_bg_-wL+BIb7Ch@vJV{x}8 zkWEqTQ`$W3sEe5+nLis`L;4bDz=lAnNLTz{k6sA|`8)oO@p}4q%%92%SR|VNV|D-l N002ovPDHLkV1f!<#v1?t literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1h.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1h.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed05a6da92b694d35e57060d0e2ad2fe8706cb2 GIT binary patch literal 1002 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0R7pfZR9Fe^m|tklQ5eVHcQjLL zO%zdF3|B-VSrRuxl0PfuZb_6&<${!yA(t+eqTIMxikcEDf7U1^T&<7`+^iIK!LY^V z^Zo5SZ_nPH-|M%%@4FOFec$If&%g8h&N;tx&hO3T{!{4@$d@+9t)ru(^;ouo6<}dN zUp}8djy!!tA-lkB@B_qXnX17sAG`*4z?OC!HCQL5xE1jfZAAc^fllD_yUYB#(XpD$WjM7EgO6gw1bAMN${NmPJk}3I%{0i zj|9FLt%v1N$4M&5vjl7d*(u}B{=H! znPh@mfl-SOLfHUrnKAII@ky?R@{#4MGFYFsNd-lkpjOW+*E_7NpvYcZP+(BTVb6!ofkD5qS`T*%lU##R}NoKu#lB(CZYw| z$k<3_P3rxw(|F_*2a!wd#;>ri0q-rwkB}9l%T;Y;9a&5%{*bs!=0F}@&Po+@7`q=)MPDNJiVsGF#ht2uWTJ?QM$- zikN`IACC@v4uBV+#d08D0o`Dp>BMPo0#Cr9BE3!p?cllsZ}hftGREmTT+h>&QQ^VH z6=My&s(t;?Q8N^(>9u}SIgZu7pdAavXu7i9vvI8E6}E}|cfq)Il{!LZAfRHGd~(eK zG-3bs!%7lnw9c=5x@bE2JN}MwHT^r{ YZ}M5c+EvSTng9R*07*qoM6N<$g4D~p8~^|S literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1m.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1m.png new file mode 100644 index 0000000000000000000000000000000000000000..c087d2a9fa4c74f00b05d835adbc79041725e8b2 GIT binary patch literal 1069 zcmV+|1k(G7P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0mq|oHR9Fe^m`zAjQ545#GSooS zAczWbVMRnAE{Z@3YGXx&eQa9wu_n-+aQ1X&Rg(ZWruHd(E5A$>q4A`wy0!YFA~ zkQG=GWvThm??1jH*O_~tGx&5<2Yz$Tz31F>&%AfvyLTp)`Y-WUARX`adq+n{%kXT0 zm9Q|PGo4PKz@9mwka}o^e(=dsRfA(bbiqB?oOp#Kt%VNAmSH-&;RRf@4W!Y#{&?t?}s&o>FNbKxYkKux~m zym2IOi_v;m<_#>clRQ2aNb}zx!y&I&jy2B2f;{~}_$gYgtI&u{xEku8Zz0eSiRFQG=HgdkVAYVZ` zT#Z+3fqCfP#M}lgbQSd#S|Lsjy&}!5JFTIh;Qt9N&}Ttz zK@aF0h#acgC&N+aP^7J`<_L+OqT8S!u7bp3OlLZ|3+1pl(+GVK5W98Y*C|miz?;f} zu7FSQ&~joIL8a3^LR%Ykz0;>%;SJ~rtOvm_8U!ZZ%@t>fJDT={H?8Y4J3EH0;lr`s}sO|I20_v=U_l$hkSCC z!1zM<%{OTu2}-ky(vwo?&!9@ioCl5V1#Qw(6Ot7CLs2s_ZaaJf6D{P#e!Xg;+tX(g zNNZu{{FIIgdh7(YW7kgY(s)LbRPU))u%j;K1j+o_5EY~^aUHgKQU$xxK~Ic>Npxb= nX;7z3oespz{~g1m|DOB>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0(n&-?R9Fe^n9FZXQ542q;uVcl zkP5<}7zojcM?4Y+iimjq0VION$bbPMB~e7epaYLc3=xSz2STG>O-E7_saHsZK|P}b zEn3z3eaBiSyQk;goa(JeSjpG5_P5qvd!4iQ*?Zp(8S-BWzkys~ce=Nyr>6wZDli93 zHZ6Iw4dYV4JX%gOMEzQQ0O373)t6;-b~So z(KzJ01tgtdUO0BDO^|<0S~EqNrf?u~&IKw)@*wo}u?f&V<5JxxphyG*RM{Y1=+Sx8 z;?$-m(WjmHYs#B2kAvJfunVlq6B5mB2?4$XpAG}zmw`**HP|g5dNz0oE+k?P!D+Kx z<2?3w@EFvCY+o0Fn}JJZknEI`rd#F1-WKqFWayzfjBgBb>N^3pZLH=&Q!RhzG=gI|9CdP0kN>1FchA@{Uux zQwI7YY6_SQnn5i19@A(sVv*^krd9NCu)x}`Z&};bMhq1#9Z6b2K1dY6z;8jf#V3^y zkSyqo1uo&~Ct**uw#R!O&l}B%$gm&}>W{u@!E+c`8|Xst2AnfqZ_M9L5B447T}3lN zBefuZGd^|RsgU+3*23Hl#(;Y^o$s+10~ING2>;=i8UKB1)~lFtgD0#4l6XskiE8t|RpGynLeHy$_`INW8gQR&YW5KkL>thp;_vpZ< z8>04%i(yCFItJ=M8`zTYorU`f4kma_)f1rQp@p9=I13)G_(!JqjGj1k$E8mn9_~1B zsmzx%;)xpU>&Fbn@Z+V|G^Q3t@L*ri_S&n_bXBAlkt7Km%qwg;`EP(7$#Dy|=}@#w zKDkB$?c~2NBp8(_s-1R!e+HG(=O|F$R-l7=U_ug2pI`bhquXS`ABq~0xV7MuI+$o7 zmk+EO>rEmpbpQG+f26c9bvtYV@lRPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~{z*hZR9Fe^mb+_IVGzZ4Rbo&B zQ4oxRX%q?3&PEV}g=G+YG?GG)fK3`nx^y9bfEIQ^2r6j>!BPYd#+JANi%FXPzTCMJ&?=(0L4uicwwgEnY z3V2yAm$&fSXKZ8u+ySc~%fu0PU|V*C@Fds(MQxpi$+m3@u^#Xswu>jMuY+S?j}22C za;k~rO&UGMZQ3I;=Ts}iXY-1Q3)Evam$x^OhswAq;a`CLiNus7JqJQBF0%0ydgBtU zec($?qxu1VurWKmqFx{knKb*-I})liO{qKBr36Z$6grnp3_n$$2%uD4;W&%*myO-tqMlVMz=d96d1 z^gh}Ur*9A}fUBYCUtpWQf%q}dO@5AV)pD#>3b~QM5!aj7+O2|ShS`I4B8gcbiw59F zqgCy2vrcR=K+fNPqmm=H5@yY6ZI^7H7MS_ks&>3Z!%m-QCPqWErW1PYPa&GUD}fMC z=@&!arTcjOTCB$j8EXyHJ$VhB$l#XpY)Bdx0h*!OcNAf&RjGahdfY#QQ$Uxlq2<|-9_3#sd<_&%X& z1maU5&L(&S-U0iyAk1aD3i@PR1p313*+0*vdWJ7%Y-$4h1nn|uO%&TjjE%rBm|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM315=Bqi(^Ox z=iBM$y+Z;;j@SNk+OnvY<*`?;2G^vPvUjEL=TG3iE5VVsc<$+_FYYcZ>$qApI7HZ^ zW~}2n+xy6^^~3WoKdk}ob({K}hTMC-t7mc?H-7JIl+H2zg16Gbx9sN+ za!y#`)~Y?H(oX3e%lyWvu~z#;PW+RevN^rqr6q@950kjU6jPq>%E7_2v)9#1@IG?C zQF8mw<~Q8Gs@J{Bd=dTS_Ex6wyvSQBH;Sh6=Kc&`@M|mYmZze(zIE~0U0~&K6?YX+ zTaYX17{;c>8y8{}Vzp+)mXc@lL{#n`*ndNI@#-1hx@T--nbt6UXPJu0!q_HcMZ+M4WZ9j$xc|#-j?~KBNl|U{%vyZ#i~6x`sbAiNPLg1( z+B>y|Vehoof3^#*C!g$+J?-0`@lpToe)(DnALd$(7tIIN7YBW?*shY3(DCblQAg*b znOlpCt}FVuaD6GvbT!Q~ndWeJYro~TtoE4FG>#W$xy2{m@@AXn7_N_Ke8KgHkvHVl U`fW=*qe1D?)78&qol`;+018o3$ba4!c;Cvfy>&@&aaQ3HQXTs7}`3|w9 zg@G*GYqy3RtdC!y^n-iN7j_QKzx>~R@U!svfCJ>18mNJ&|jpnD{x~?Y)53v-9s^trG=-~ zgi4g@gfx{3Ep~nPT#svY?kds#hvHus?U>(qclI1_+v(l?t$kr|8(PZu zu*N!;as4)0QW-1fXmek0%W~U*BfH=ff^1@%ZHy zAJ4txxS`$=t+sPbz#pCFinEfBKXP8Wy5W$7=OKoVvy9n%l{-X_dDJj|b_%Eu_{KN0 zeSMnP86A#_O2r?w5?2&29_or%c;pgauj>4%hqtFPCAlifUb>OssB$4RYV~V@D-mKD zzW$dKxwtIXmbN#sPF&D2scmiQ&*nD)YcFf+nq*q3{M;3^)8DEidHdWQDoyJ|t9*ZU z#>{bS_J}b(IqP)S_P?t$JYBliJ65$n2-I1_6#s9c%~qA2`A^>5Y$!av>fIF)V}XrK zzZ+V6v<@t^Pn@;N(TrXAQh3CrkDW)fZz!JGEq(UtzrFTX8s%*hetz?1_zq5+p00i_ I>zopr0A$ZH7XSbN delta 614 zcmV-s0-62q1^xt(BYy%#Nkl1 zD@#EQ{vXCdYr#ev!6vA|!p4*~Vk0OK#egsH6*VTG44#F#5#uAN4$T9=DPSB}?aAK*_ki2L*PM}}h*J2MP=BT!l=Mt#EJ(U0X((r_ z7BWUUlAe21K1%xFwRvyu{Qn?y%$zMrx-4l}(t59rNqS;BGffGtso=FaAs@H?J8&mr z<25i1><7kx?ZD@VonNs%mfF-efD;KqYk_r64ftk#8=X(UWKk4X5`MY}y{Xu+y~N$n zcWTK_0!OpVmwyKrp{dZqa`I455ayv(8KZ}QOTb8v{5yLSjqTZybjSIX?UxHRl4Y)K zkTh%dCQ`?~Dnjn0jM{i>!$`EYS4GItU$pU}C+`3kfy16GT-s9SNDX^ks7j0}oCRF& zcnj766%5ZN2hU{%ef`7TP@7Pk+M(&iw;D=q_IMp}G zA#Dit6$3&!3<%{gAe2KJLPgNWWHFt-5h|Z4Gq5aU`*WdAUkN<`UI4d%dEkeQUjp|7 z9ak)VX=1$1x9l;n&#I0R=YU~PHWSgQg{la-^)Kgt2Xiq;p)CBp;C|X>nn(n*QGgV9G_QxZ;^PIM~n{7$PMfGX)>tADOZGwom$_~Z{8x2oHP zvQwx5gf-(f*;)0bsCLw;congyYRGvj%0y+`0|?=mMD+C5Kgn;r+T=d&5Pk8f(fws6+X!2BKNkEKbx zuY@1tBoJE<>{tD-=8Ecd^I6-w`H<_6v`M@vY{(plJgtd2F2Tqo=mOHzPtfERV=ezq zM1Fwyuge5qkSrDV_;>m9HgR_}wojbcGD9u-0Dm>`$@|d^5RoCzN}Pd8dN|shcp(*d zQeT0wT)D+hd>K~X)sw%_I1Rm9q)8oiY@aEGL{{fi@F#agYH!fpuND@{pTndM*W0lgELg+kmJJi;aC+RBp(Da)M0W@CeW%@V|Dv*u0S=6D8y-8$e6%oyO9xpSurA{#2mG-1oRUj zkyc-JlVFV53(`povL&}$VA||TYHjlsREPy7Ey%`|On;ZFpdNPxy>VAk)Uw7+8sfi+ zO^^KZ5MQ3DECun){+q0gd6^?R<+^1Vj)O_C8}w90N+}Am(>-`9-=T_op!e=eP!(2H zDGItyqW92j2}!OW>K(4H4}df92Kzc^%c;~0V!xb*rGYoXIb^giktW*OQ`PW@qBf#) zl6pb8nSW`JYy)hjxzJ~?qrC~fz)WZ*W#T=#64*K%A>>S!x zpIN;Q^j7!|v*0R33l-OcC;li5t3dDF`WVm(OmzL4K%DG-5EQ*4=LF{|7w`w2Tcuop zHE@O&Wd1nK_+u{75W2&)rH=c@(yxL6IS_sCWq+a$#$g*sU?odzkFuHL^gb8Rirxb| zVE`UNPMG&6^S{QRH`JAKMD3wYIi1w1DC@*&7rWiX-6iQDJb*UHhK&E{Y;&cf3Tngm z)de=72T2qsPYKZ8nhlfP*q2U^rL?IfUcS(RxDq)JS&*U&5S=I5m^uVayv=W&pymRm zVSiig>|N4PdnltNW`ORiPT1uTT0C}>cE)^AhjD!QWs%*aFV~YLlW#sQYw4j00000NkvXXu0mjf(&@*D diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_disable.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_disable.png new file mode 100644 index 0000000000000000000000000000000000000000..772be087424ef22af1021acfd141028a3adf2613 GIT binary patch literal 803 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM315>Z3i(^Ox z=i3<@^R74uwAFSrd2sTw3Zuq1x-yuazs?2qq`Tdwi%w&`x>$){iFo-XR#qgx<< z$M`{)@nQBqCsT}mE_^Um(#h!{O8=3-6ALcB(KT;K<<9`s=x_bS?j8|{S@94c718jozM>#vsP{k%iQi5!?b+b zim9Kj9V>EnT^oEjd_`5se+Lit18)tPIj0D0U$`jb^4kSp#STU>#`pY{v%hQcadBsm z?}A%KU!!Jfcb$ygct)HF@7%zN(L%B#vg zZ(7}L-}K>_2mgol8u#}0q=z1s3wC?p7Q=h!R_#wr<}9yw!adZ6~1%P zgVx^{y3gTe~DWM4fyhvlS literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete.png new file mode 100644 index 0000000000000000000000000000000000000000..4628a69ed5c77e081c58cece44fdec7211db64a7 GIT binary patch literal 755 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&i1|)m0d)^pvk0C)|NX|z>h16DRlc$Mu+u#M-k%+JYpwJ5?$Qd<5P4N7 z*}9cK?H9)R}(^CN?OZXw**k2~*^rykNC9 z*DtmiHRjb|U78vvTz2~{N}qCSt@8Qo9gHV$CmBwu z+VFO-+@EGCkw^0n$n@+=JY#>z&Sra3RhXJ+`P|tjN|;3dbFW)?{>?;XK5m7Ru2x4R zKGt)cUJ$MSQ{-`!(c>+_B~M#*Bek=Cyk5HR!()>-jpCxMv9tZxhior9E9kK)@Z36H zdDgtsHw8uC7W|EwyOs0)_W<8-Gxz^EU)puieZ%hA3l7*gJMZiGIQ{0Q@|8E@?_ccs zXHv9-D{{KV7U@l`%ct*q7_)ujvh=q9;sNddxp*I*d1z_Z`$4WMoshVlO&v{1hayHaCPtP+vbmo2$%GkZEJU2UZs8gNH781-p1CnniUtO%-eM zedDu1@bZeStrGj~&)r-jkmQtR`{C`JopbFsTU#1C-j)y3n|@o;h?(1ftN8-&Y)65Z zz-@UQC5PDdIOyIs6}7rNp*{D-#&2z2YG)i77lkdE)F|uG6c%pyN7%r6(>HtXv^9s? zXa97a+5E9e_~rXnW{rbxdp9P^Glw5|!gR{z9~@MCXBBf` zLg&lqnOE;2oDF3Y{W zqnM{WDsp~yZSm6ghaRb`e0#MhdU5{7a`6pIu16G2O}wwAcTX~vEANZ{edb6*wT)R3 zF8|)vFPnOFren|%`}W3y%8*AVdV`N_y|Y6^v|IW0d?mHZnL%fN1uZ@Jy>gq|nd%w5 z;i9E4e$1bI%SAAT)p}#;KGP!hm+3KLatXJROhb$u*I)6=yVE6Fk(R(dNnmfRY>>IP zxr&hNkuz!UdO!Ey(XIOpXF=`L5jBiWihEu<1;ivac&N?%<(Q<{p!eY5icZb4iMF^jJON^!NG3 z3tqd~UTBb|J!!oJiUqA^~ZVj^PkzO`5&A!ng66;;86e7Xm*mRWR!;LjD&xq1#>e8`YpzX!CUT literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mute.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mute.png index 9a6e3b2b3e3c862f4f76d8f9eec05d5cc974084d..b1d0862838c3c5a51ed4ed58e99c2ba3498bad9f 100644 GIT binary patch delta 1137 zcmV-%1djWH289WbBYyw^b5ch_0Itp)=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS z`~Uz0?@2^KR9Fe^mraOGVHn5noiPXtgBV4aA{I!giH(i#&wn8c7BXmtjfJt$NJ&XP z78Y2OQW6pyC8ew^Y(&07GCndHHDP=V*YAJs`yB5*_r3SrJ6I@B{m=8f|L5cV&%Nio z=T0W`-~Q!KAeYPS0}sLSYX1&;8o_4J0wz@3AFOB4T_F1cRt1X!B(*zT4=%D^t}TJm z>L`XR1fQdkxqsYO{K~Wm)a-HfNvAoJ)sL@L4C>P673FDK3`~?hsgk0|?Eq#k2paYJ3h2IP6i#9Gt(2y#Mnl@nehG2@#B!1@-$DE*pR_J^eev8#t3c_O+a6- z*=2%St4Z|~`=a6-9lj0>3=Mz}3bI=AJ-?JP+=JQ!2m*MHMwWg8H(8 z+{`i5*)j8txZrD#MnP@`zUe+0?gmsWik>1taErh)r`h&vf-^hk=kzIz1opUpAie@t z`$eoP5`RTqfgsj8#m&wT46wPx*IYtJ%qZg}Xo*Y66$puo2*{<1q9!S5D4cEqvm-VW zVu6wPwZ?0s4PK%#P6Pt#%8DXiAV?$N#(_sbrdwgG<3~hH{&Kh`uwN>b&1SDs)C|4= zy$9_sL|;tVM8_z+mtVtfl8NzQCxP1#ufl$7yOdCJS~`lx95?Xv4Cm z8W8;Y)JRURs>eX4duU>CAc^(hCeRNrZGY~AWn`bY&I=CkNNP%oB6l&Gl)rR%ZIy@g zHUs@skV$A$S~oR8QSkP}olKiiHqW4S;5(3YgPEZQ_>smFCq=D-)4NUo5X5hOtFPKK zWDEEKWN*P#e+X;+#E|GU#uFEbvfLl>Y_J`ebrLk%U}D{4vR?-sN!EW|R7bRJ{%Z0J zHw(-IW^E?YJc*>J6_)!Wo(=Zf?g_82baH4Dcwf|$P|a^~Y_JE|(?=M+HrmS#rAGg@ zKL7{)y7;8_$^OI)o<`q%pq~=gIdvcPXU_kgv`^qC-~Jyv=&RVv00000NkvXXu0mjf D=jH&x delta 747 zcmVVa#(kR`SL2axlF z!1oH_i+e7hg?}-&Et2*~YI2;CCM3O+)Gn!6(y*jMlAg?Ifd}fWmi(r&6=UJ6sX}%3 z*(>Rsq()QbZ-S56Z=F*2Bz4S%I1x~feZIBuw59k_NmCZm;WAK#TvQeYXBPt`u2d3S z9h%M?vM9MH1Nd)B>i3koE2-04AC+_^_WodtHjwcJK7Ukn`XZ=lNhc-UmQKJ+cYKLh&%fL3_DjDX&k2(${;aot@cK~lZs2jlI z6d=Fb_j#vpmQs0voNura5!nM^RRy4=-q%qpAY|ujfTteRGhmacRqmo#qExMboHv;| zk$tidMpx;clzl$bms$eJ?r4Jvb<6$x^=0Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz1J4r-AR9Fe^mr;mRWfaF}+)OkT zB3&?9a36#~bZL zqJl(AGl->hMcUl)_y73Loij7{-nrB6OVEM;ob#RYKj(b&-Fv_9-csqmB-Ltl3s}9J zbEe+RN_Nx(Ex5I~y@D295#>uR} zdCrl>jeu_yJan-;*e8G{nRYolVoV%yO;lsl)g8A0`hxj`#<9l*FJY^w{>fSAzl;4Y zSX-BzGY~iCDAzowLiz;DexWm1cc>7>q#*A0pppR-nk*=0@X07D1pH$ za0m>wDllT1Xx-R)s+J_G5o@7>j1(#ebt|x^NKc%$fn^cZ0`?TE$JUmGAx#2_Zo=NQ z1pM29?LC3QSofXwnOuR>3+y4$ewQr}cLI|$X-tC0B0)E5atvTkfJLx7EzkSloB<{~ zeXP!gF&0@`&dol^xD4KpaZ`Q9!J&Ii@|yXwG@Q-AZi_L`Tj2-TFUIjSTl%jSBU!wU zz(MmZMaSCHv4-^w!(>7<)nnZqN#~L6{W!PasKn*mlW6!2MjrPCLZ=9B0sGldKR9|J3NzPJ|_%0ndWd ziL=>w!nw|3Pk;q54BiHf;(H{${e(JQ#_!H9YFhp*6MqG~PNHpo2U3do9+q436Pj~L z|7K^l6Z?v*V>fQvvEzFrz5Rqzm(Ue2YU(nXJd8%|;Iv4_E#fEiOO0FF=Io;8gGjtn zFv0godix2@Qs|FZEbnp6>i1&|+{hv{_^pR}s&|lNLfnK}-l^yx;E~LG@0pLh`%z1! z`7Ca+K##QtV(wJz9fwXq9CCZZ5f`d6;S7Vr-pN?|%2D7Sf9+v!g8dELBlt{)e5}ca zrT1USJ&^ta-jr3`p_;Kas`_=yOh|fHHqjSCc+qc}Sb(5fKs8Omi+{^h*cHn_e+-g) ztz~isK{aA6RFFyrwb>0_|3sfQCQ}&6yH9gQzDK!0HB3~yy_F|n1Gr`t(BFgP5X_%K zEvlTDiwdHe8)}R;EE4q@=s+G5$gzxO!DN>*eL5Ji!z@I;V zGrkON0y}neYIlJ?;4g{Js`tQ2_M9qu>B7YH8FL)WfubU=a{M33os9l{TS9TYY&{2F v06TzI#olMMQo=QG5lpip|DgYuWm|zqOE~g<Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz1x=BPqR9Fe^mtBZeRTRhXs3~eG znhEMC8VI6TAu=fH^e{x|kcA3C5I*Rm!GJGeM3Rsgi6R3kqv%uhU}0rGgoL9d8c~f; zX@Ot)QBo6R5~(x&{%6)Yt+VIcxp#101Q+~gef`(k`|f@AK4&VG2T6K+duM{tLpf*q zjT>}7iXH*Gf#j<}H>grTubrR=bbyg%v=M0#;$&inz%t7XFX2oewgNm2rhutHat&Mu zUEpX#Lqj(@%5}K~!w7yH zNbOD_wh7z|xnHrj15L7QJBM3N9C2OLV^iqc?g{iK9?vv^Wg&SKTTS&#J_zx@u-^iY z7K#UO#I+jLx~QjmYY`4x@Ne}0KMv<{@B{c9WXp%vNpLxjF=v3W2TZ9JsE1333UEe& zji9wwgEp^3>%rEkx-U@=>xIgst*(YpX9GV)I&r!NhD6j0_$k&HvuienbO=cF5H3gy zh>ZpFK_k$eQV?P@z_3CvIOG-pKP0;Estd%0z-51A64bBz(37SwqvJjEoW*y=+SG=# z-*{3B(|qoe++jp5=d?V5fq%?$QrE#<^Q9Mwi+;^wU&PwfhBFQLW3eOV)1`gUlAT=X zSDi@l4D1&3_o6k~d7uaAxV{SN7VF(<1wLlx<`ZI29qU;}I&9k2L^sgKXxIbJVPCL# z%qujSes6;gumOxWUQ|BDEb{%Y6oSivOH-^Qs7vgoC3T~Z11;uDtrH*ZTjty8lq(qX zlb%hUL@$rI%qF-l5E@egxuxI_FuxD9=Pv;b^g4JKNPI$nGMQ{Zw7!vk%CdcRW){ZC$Bq+Hp^JZTxxWTu ztT}J!fd+a*AFRq*7iw!Yx}(Nzj2Iw z>^Pw=>VCJ{!reej+vTEf?N>lMfffsTUOgnfMSWiRUmrtbdR>vpAP0a%-!Fyl9{jCJ zl!%V>bag`eN%cD>8-V!NR`-JO^qu72NCz@f*&j%)Rw%VOLjQaP*0cUx=LZ|9prKlBR>3f^+-wT0o2Q-Bjr@}sn9Pu;g#smfFJRyb=4B8wH~NU z)O&C%Pr)Rh_m9hu82w*@)n;LF)d1DHsOO{_W#wrKbv*TUk8&L6Wl(j+lrxUFQPit& zouniC4V%Vup9bQzfj7Z~JW;9qi~S9_0{rUN>p*u>6Np=)chwfKlUGhJ`u>H9>ED=b zpc~XH;;JV8kO3!CbA{4snvWp%ELaJi0$LS+QEH`xv*1(E$%@=XKa?R`f&T!sQ{YK= SRv3@~0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0JV``BR9Fe^n9oa8Q546UEHyPj z3X+Jhg(-=DKu}A;ek_Cp39*g%7bLDC$W;Vw+_bG0wMZ91R?x26@-i)p~@b%n#&i8xnnfuUAE25&3!C+ELe7>P$(=1v7Mi) z8Snvwwn1Q09qg^84T>~@S+L@KQ_gw~=mv9YOEQ`m2fmG$vhfjQ?NXP+BPafYABZb5 zMk&w_p1OkOH1E$+0^W#;@Yl0wq8!A-V96^M8!A5>EkKZ5FVJO{JqOj_I*8iAJP7R< zfn^{cn)vO0W6WE@q9cC7AM*2=#)vw=dsjs6JGcst`vo+2apldV>o6YU+m^t;0e8V2 z&}W=f53vEf0A~7D9ZVA`55zN*Uf(2LuGlV%cQ38xRu1BX*v=l{3tP#Qfp|cCvkB3e zbb}e7oiSwFAq0)!3y^&T%_%*UrQjcMI$W_%V;QNM07V8>$=O&nTH~S}vjX_q9)1+i z*2>mEt1TkWybW|k5c2e`l3q6B*Qk0-0lNVgd@=Dp@EgQT@zVi+!4c>Ecx+thfz;_l z-(uo~SPSuO4KX*p)k~08e!1><%5}d2M}pIpQsvc~()BLa3=Bn$gMcKG4JRHMj<9 zvfK^Pj4rqCmBT>y&1H6H17DNnZirQHfHQ7&ooDRewe=!(x%xPEpc#AyvbnG-u^+`u z`JZ({7kxhSIY(2yW({@Nt)uT@EE)+6<9El}`Os{&?Kdt!`qwW*Qy#&RhL%168 zP7uC6$}XAoKy}PU!&-@R6gpn6I;Ad)?NXv9OG0&kU1rtqt*C?40_{ear4ZwXz+`x&}LW7OuVJeVN|)ul&HSjA^I` z=-(*5Y2LFd4a62<@gbn!=5L)Jit+x(>bV2|0Mza~A#=3iR{#J207*qoM6N<$g3zS6 ARR910 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_silent.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_silent.png new file mode 100644 index 0000000000000000000000000000000000000000..7f5a2f869f41ee703b2573172aae697859efcaff GIT binary patch literal 801 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM315>xBi(^Ox z=i3?ky=4Lgj=w*mv226K;-;=8AN2)V6l649HcaN&cuhH1i(8s=M)u@eSIj&O6gZSP zmiJD$q!x8ov?*huz@&ynadyRfD$lH){if>OIxfDNnezE%&#K?wJNqt9@4E(n4*Mt1 zk87`HExuC4=yxE>ZvJ|e(BE#Q3YQr7F=*EpEXxnk=uDZlt+Dj*lS?=DZ}>g=h45;& zvrz}lofDXMOYbq-cr)T?-fWk{VjFU#@{{ea?z-_j@9o}WL03(pi+EjY+2?Lk+$W@U zvqH=4tR2JD*q-!*ZbvpLx-520ZMw%E>uB^yIDb~aYF&?oWq&LU_^RGYeG|U$I4Sgt z#^z@yes*g5a~LH}KUm=MRqM6WGX&t!Je2!v`tYG>L;cXj!I6P81UB|mThJRu0 z2G3?IM<>>#TURD4rJeNH^C0@s5;u=oEhg~_WxXkBElwV>jvhze&v>$>!c9`*kHobM z<;%O-o?LV{(g>F{n1H>*30j@!e@Fm z>Hn!Wl2+@CPd{bTELd&%KvwwM7(D|Orlh>T=J6Uzn@0Bi7@B--*u{Ik$eQoC+ zFnW6WM_h}@-Z&wFOS8iNpL)Vs!0zJN+VXr~Qpdrn!wEc|KhsaV7x2;72vIP8m1pm8 zPHm@h%;ZzN(|&zq5n5@_e>6F1lR|0zJc+5|OQtoPx@#BAtvTb)`t5w~T5tBQ;ocOy ztMrBB-K#z(yo>L}{5Dcdn(g3q@9lmj?fr#uxA*MWb|+U@kfSHiPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0FG)l}R9Fe^mrY1jK@`V*YTsEd zY9mNcT2WC%fkm`Zs9h9oLMmFc4H4S(fr|oB+GfxuB8Vc17AhgFBf_<~}}=6kwko9Ulz8n;nu32NnzVD7UkgKEt&hfY(~(!-nsl{sYtD)@Ayq+|%$&9G6s%2{ zhV|+yzGhakBpoKDF31$6c{d=;G@kawnkiQkofTt`tnf!Nw*`KgHRM|gHL3b6FsFi) zj5W5w1$kfc;@^N57QzPJ^x_krrAI z3+s}#12(}h48jW^mSCPW05_Az}vvsZ3T^8D_oHAE))BWZ+7GKGtgn; za%bImppBrx5g!W(7$Dy0Xl@m1h}FP1N7F-Fw?RFVdhM;fprHrdZwTtG8s8SCWc-|? zIpxtDMDyLz6*k{9ptmvJ5WX?9C-J8te{8gm!zjo;f%iEfRt?&fSD=g756}&<6_&(T zVibsX!8lkOp`q<{k0DF{K+;9gRzUuTC7qYoF}VpoLYRGK@JL=Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0(@8`@R9Fe^ms^NUQ5eV1VdOd* zj7ub9G);1uNXW=#LMbGXORnWong=O~67n(+D7n07T$((oc_33}?1PltWu!DOBS|I? zGc+#49KZi*tvzeb+2@>n8Ywkj{pMS1eV6s^wf0_TO(fDI|Je#egX)dPn zLH1n7$k&UQ5-5fi@W|bP&MpKGf-fLBkUgTS2Qj^%1UA8GxDQ{!l}B_6x<;ny;n)Y> zInhVcxJK}aLNRQBlW-60!_dqq$I|6Z87GaN@Pm`C(sg2dCES5l$0w-yjlqX-7Pdht zyaq|Vn=@;hfFfv8q>(ddt%$bdsu^?DcRJdN^RNS^LtgSkjCml5CEL_b39wGQbd3bf zr>`fO2z#MF?1U}Q3cQ?A=U67cP&N|T zf|T>1g3vm-tH8=z8e`KX#O4{tSddSyTju6S#F}fwb_^GcaS~cTvJ+hAu5oC*rKl;^9!CGwf;1sT9YzVsNbo3XMxqzu zPuhY=qMPGv(9Lf#3@2ZxUuufdDrvPO!=Rq{If-5*auFTw`l(ZZDaJp;)rIdULOoT^s|IVQi!co}?h{M7WfiMAff{-36m+~o%+ zH!!{eiI#Q?_}fN%4cJ7D$+2!9zXH&g`V3TzR^vJ7T+&L-g%+?<;l}%Itkb|QshpcZ zpRv0QIu3LP3MKgVhLrP;v6=80B+40lb-_>$jSwX78C(^rk`PYhnhM$#4-!TDTjIuJ v>`Q+=l!E>zYl0V0%_-c5?vb7quq*Hfmb&39w${b&00000NkvXXu0mjf+WYZR literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_on.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_on.png new file mode 100644 index 0000000000000000000000000000000000000000..0deae5a629d0ef72ac9bb404bebaff75c7f17b49 GIT binary patch literal 831 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31Jg=R7srqY z&bQP3JwyXV+S9jOGC1h!xFs`DF;FBhL}cxhEb-RaT^(Y%(Hv`)TCyg4a4U+xz2l+a z(Ji)Cq$}!6d~J6V(_-Hzi%d*?KYx|A{a#sFoc`{NcXI|`%{}Aif8NN3b88_gH4}%6zpAO3Fu_ zGnzIRNXs28_ej1T>$|3qwbpReT=!zZ6!urbUyPr$Jz(9_a{U7H?uQ00I>pW=#jT-M zO4_Ukbv7nWIJB&h>9|pT_RRmG>*sEr>sZa$et+3U!((*@ydEDd+wFoif}LxuF6Lk3 ziZv-P4&Ew~R4JpqHEF5vd>|euv`pf>DkIEJQ0=BSv%9})7D*f^4l;R0(&oxKQ zjvSJnv6WjYQH0BYb>p!)YgOJiWp22mCkW&f~UZOAeoY zE%u-HqjhTahV!D%=~N!MWvbsSlfFrDRddsd;2EnICeAf~u*zi}S6ayDgG)8TP1g+g%Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS z`~Uz0Gf6~2R9Fe^m_2AyQ546MXpIVfM9>yd(Nd_34i2@bpnuRVg5sbB9h@wP1s5j= zzd)^<&Q`agU=;+#5A0&1Qmvbdc1i@TrGsBsX_YqqPI8Z∓sU$xA@!fq%}&z2|>U zZ*K0pud&#i{AVi=kE-8%KHmY?cJLWIh{xmEsJKJ%(8wZi8(8^?b0`#16q6~s06aFG zOdIpG=T1Q4fVU&NAzj1%$Ky%AcP5U1E^#$ z7Aqh2FE?<}HFRAkIz5Iytn;hZkoB1Y!`MqLDZVz;>l%{PJOC<+tgdmfU}GLmJy*^^x2Fg~jxVx6GP zPQ~8^RQhGio(o6u+g-vt^pLYv&0xF**Eog0YcPnWqBJrHq%rc4v| z2c=siQSXMfnTB%4-r(%7b!&)CEKm4zuJ9!Kk$>34Q>f))BOmOt6+<=nq^NA-mtdo# zzszQqo2AI+qAGm8wkssNU8EI)s?MPzjpuUVNFa}!+jg@nK)E;9wSkDDoJ3RdZhr?@nZP+%NiChq-iLfD(Lg6*`R~UUaF0_rhn|zjSKtrH WL0U*iKN02t0000-94 delta 861 zcmV-j1ET!N2lEDyBYy)rNkl*s||y3NguiuqG0cOerZcge1!+ zTa?TP#V3>$NsSW9Qizg#Q6xp#vP3b~lqE8@Om_3v&3SY@y)*CoywA+|;$NqGo_kN{ z{=4Tq=bp=d8pLuPfDn1iV$@M_5oAu`v$N8xDQkT&4KPoofZ{HrU!7skvRiQ z25tduo!=T8#{!3eb-<9E-V=tYSkg5YrX!Ntxb<$5KH1u8o7?W}KTFynsdIhg&=^Ti zo%5ZR)Z`#ETz}FjmsB@IkNXsRV`gblUWWg~z?e%!%hvk=2rqsvFgk=H)oax=zT8FBj9}AzSPgYs_I> zK1iCGM`*JV3gJE}X>`o)nb}>46FP4Tm6AqD>Yhcq=6{)M*$C~j@Ar}>I@|R&AFBLN zT)ilazb>E&Fu?RmPv~ciSbbx>{q6xzfP<#@0S23X)f2jB z;|yRB&?bwtNpMx)3cOs4Vs;hI?|82eLgP3ndh!ucVu9ljHW+)JCXG(rHQCB#o=h zZ&n&YL3&9#=SYRFufLsEwau+b;xjFwARS|`i02l<=()3?u?Yof9;+!4!jq}bzaSJz nsl8$!Njf8GQc@rPkrTi#UHTt9SsJ;b00000NkvXXu0mjfqPw00 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_videocall.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_videocall.png index c6d203879d301d0dc1838d8f979bfdbbb448f06d..0faa29a9c205e0b3abdc8f777a46d94911de4663 100644 GIT binary patch delta 664 zcmcb}vVnDiNGZx^prw85kH`QX@Rme0>?TfNTy1#`a7G79fieh^2s-fq{7e zBLg##W(0{XV1mo4EMP{kK?=3_9{*urV3P85aSVyzd^^ow!=+H*c==!3ACsF!+|}8G zE^V`Xd(?5~jr!RIQ>V->np9L;_~3z8wRqvNKp{)dK)y21DN3&sYSaEcyMF%NKAYET zyUo9vex5z^``pUU_o{?DTZH@+<{Yq}?XcxTUGdHs(|vIl_^r4e+ntLnI(Hz^L~8Hn ziSOq+8QVUPU{TDUaHe@ykm$$qCW#gLqWuCB(&8L1Oe*4by2tvhevXp<4dc8%lVIKw zqsTXw7yhZ9eBSu_)d2@$_|b+cdKzM}9!fxYzZur2jwPmVB~KIXeE`c2^M9P52bn=kP`eSa&Y_xI2JA)!~2 zT4m~HO}tcpZNmNEJkr1Nf*!UU;;i&-IDdFe_?fTazhrlnbe%NM7CpiALi1KYnDLGU zes3AJ)SWJB%a+>f*~_M%m+KMcCmI>sEc8_9pRlu4&%NcEcePB^le>j-m^T%5)t^YZ zn$(;sRnWsZQ}AZ3)WLOD7tTL8WSQ@wx%-LmjOTkYUY+LJ#Cs~z^~uE3vHVPel{t57 zPQP2J`2IZC45oE4#T^qD_gn0byH?ZJvTF|+5PwK`_|95?Wl9bn4PJF_vp$x}gl w`MUWt?1dtO`x|VQg?Y}NZ1E<$FrBk@5>yN#Mth=~P*6RO zS5SA*5k>WpJ>{EtFo>wA1WC&pqMkGo6{VmYVtyj3w|}0fCB>+SpM=PnFX_L7FI}`nl{d-U=r*GnpY9x_h5Fx z;xp*3WcIq!jLe2*L-rCiWQ|x)!*z`wx=B`z4QU8llrClC)h^`~xmWNV&fx%bz3tM| z(w*9WfH4PIV%>S4`}0k%buZt8U;L<^HhDJQ9#7z5P2eBj=fOnemm>!N0000jeZBC+vC1X3Q#x?D5l&_=)VSu(x;b1%(Ywvub!*I$>OWLlI(`OivXW%~BgBiLc_O7B;G z!CBuMf2;b2FP(pTmr%X}@3bB3p3c(lxnCChJ#(hN)IHBzf9=h@yY6`{^>l7JlOO!e zB$HWa4eu)s`=ab%y>Btf6C(C7yf6?udS|()N7WtnOS^C8oY~pN|8mB@=IuJjZqTSKpqusctS~dh7QU-~Df}Hoo%hl|1O=P`Z4X!i2snB21Si&pPAqD`>Ky zM|zeK!%IJ3r3wG8xG-&G7 zoGQ-`Sh}9HpOhc)eZ}X8Qu~&nMg}xqX2d?=FPL*dX49%8pFj!0)78&qol`;+076a$ A{{R30 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pip_replay_large.png b/TMessagesProj/src/main/res/drawable-hdpi/pip_replay_large.png new file mode 100644 index 0000000000000000000000000000000000000000..a09d4d71d75a76dd701279f61d76f0818bba722d GIT binary patch literal 984 zcmeAS@N?(olHy`uVBq!ia0vp^W+2SL1|)l2v+e>Z#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~yTfmH9gA{&t)>{Hp?&Rs>7?Q#I zcBXAch@-&qVo#OMV{Sb^I;FTBxw&0GaJM9=26F4V9C2I2A}y`W-8;2aL8;>wM^duN zqOh(<>|%>tIh=wtE_xVvak+AT6slLwPt1G2clYh@-{zHXVy;gsEC2R?{>D)dBzPN_ORgp?#YI}Pwzz> z{Jz;?R?}xEruQ7bg&zo4@Un5Y9!jrCmiCpM*naF_*AqLozx%ASzxwPrHqrk}dDCu_ za{ez?_s*-&Jrs42cS6c>O9_VZ1K(#Xng8bPx#dyrqFmlNe!&y3Gx9ZTcet%D_PaFi zogwR&#_10xiKWZlo^#I7aA)oVl^?u4o_mfzdGbmyj%D90uMgHGjB8HMy8OJ%=bzq! z`Sao<^tXL}wa@K~nt_^dTw3?0@Jn-Q^VXld&z;t=@phSC?DZ9S2B#+4&sRCI)1;jD zM0G@{@_QKrHQ#mXt4@Y9B~9-&s$)9y^~7D?`%@n6f7iWRiNC4%fVpbTu1BpR?FI9L z{#-t??|%O2)lMmkg{BsyR)%epwYVN7H9JP~vQN@xp_xxM-`f#Y&G}HK)#LNCOEh@%Q1UZZolH9(~bXbY(B62H(u+<@5XI% z_oX)0XzUAE<-E~T((IvJ(4TyxfSs|fA^Qxnw11|&KNdEN_obPyPt6vS#eLdGtPbwb zN@%I53-f%)a46Ns&bTb?Y3Z*12a1d3ezN~CQx}@5Q-1Jo$LSr-TB`d6zD6%=I$?jv zdjHH*vL6f{8RQx4_tR0;dcm~bM|I-=278`Wc2$#vpPrJ<^^ZKW`N^l)AP4@6MXS3W z8UB$}&}ZXbqE+LVv_W!jq{#%8-dzg2SVb-H!Xb+=Qt?tVMYNo!6t7W}#GuC>m+ z>lO3)#?`#ViPf4aTa()7Bet#3xhBt!>l*8o|0J>k`Tm|Rjv*C{bNerHGAMAkoX==*%bcpVmN#l) zU>1|MM#qQ6HWqv?^SLsPo+-4rTdMuViZkJZ#;w=Sm{r(=7=+TCCOMl+dU7RdZ(>VfwYa(EIs^C8`3~k4&VO6a qTHbST47lLT5TJNbko~f=2`__gbdLOtm~2mwi#%QZT-G@yGywqNFF~yU literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete.png new file mode 100644 index 0000000000000000000000000000000000000000..d77fe24914962666c2f48a81bc8af22c621de821 GIT binary patch literal 643 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgf?5(GZV~7Xu z(W%znhXW+qq&G%+A9M|Pqqak&`+-tNb9Zxdv#TIGySn2Pt-F83V~+$19C2;u`^O|` zwR(j{(1)gOixnDrA1jliCOu2KtW@_wMg9KMvzGBilOo>qpUrT&Z*rEW^6&-z)WZgS z(kr>oI&Kl>D&Y0A4pQus+|gp{(bjd9T~nf!>%_Z-9F`O86YnRqd=x(M?UgChde3>S z{uRxoFF3r^rZu=q@SiID>3M}mwT}H&vq{Gm>vjrmS_ zW!BDY@A+Jui$3zaYWbh0dg06QbNdboNkyK2GnY?jQO&xouWV$TPOTKSQj64H*`V{H zeX>$na_Wp{y3gMQT>PcLIxF^uzOm;XmZ-+xkDm$r-amg|vXCzCe#Ua;&nlC&8cIP4 Nz|+;wWt~$(6992z{t(k5=XL1ipK_*6p@DyQ9-mME8L050-6vuQ;@<{vi0yAv0;?M+N4r3+y+|wmg*b z&}S2lIUwKg=3_%G){u%m%VY(2z z;DveF(O;g->{_jmthIqV_QQ5VBf&*+E7nMIro1rtwl4nQ=XJ;11TS1)BrbKc_?Npv zjnbb;3r_cBSAh%S3k5nAGybRK3LiLs&{@JM-0H3FhPCeL2YU>4qki0c#&q$`&+N%A z(amf%?Uih2FU(`Ssb#~k_L1hs$6NM2oPX@6=WdmQJ`04kep_Y9v|s+kwx8*JZ`xL? zv)Nzd4;t=BI-2(JbAi{anGSVlG#(v2vLZpvKJnz?1J}D`|F?gOR(RF9`NmNN%NWbQ zx;uE!ix_KHEaywpFI}SYUvKkqS*I#@=8DuyTe4m>e6c^)u;qNo+z9`fTeLT@8`Z{2 z7u*Xuc>b{Pj>Ih+Tus>5igqZY=>rth`^PDYL#w~K&6n2R{@|L{c%o*#rZl-(enJuI~;Y7pV ze@5O<_AsnfsM;AB8hhHmRP)38|6hXBPfPsZU4KV?L)PXJP?BTtboFyt=akR{07cO+ AzW@LL literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1h.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1h.png new file mode 100644 index 0000000000000000000000000000000000000000..48e44a2f8c1ab4d4dbe0ee5cf36044624d92e90c GIT binary patch literal 707 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfl1fX#WBQ# z_vlpbY~etOHshpO0zx4ITx=|?=8Xz0OBOg?kKGZV?R2m;Z>vgD_+Qq$X&2`Q6so>B zBqrigu<)JBny!Uxds3ApRy}z4V^8`y&Ek_hp3OfF8b9AXe`bDO>mmDT33L7(o55DO z{Gr4io~8#sElPJIL(J zJHFpeZ1Ie1vH!qrWiWZF&l;ZV4{E~v&iF4n7jV|TIn8d{g!>KU1!XCMjAvt#FV6J8 z62rT4<>CAv3}rnVdkbE*dEMH0fQ4=A_FVSlbxTfhyvV%B+j~}KH>auShI5BF<9p&- zrfrWs$Fwi#%5tZ({+GToetG=C$?r*{_C2TnA}4nyEUVQ{!0Q=TX`HUMxrB znR$gS^GyEff8}r9IAFzd6)r_Y#I-t_-q&w4WX#+Imxild*{Le~FYdi?l*D8c{$ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1m.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1m.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f49e51f4d705fe8282a70c1ed01d872688c2d8 GIT binary patch literal 740 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfyvL)#WBQ# zck9%%*}{$z?UQfJGGTLhb5dc-r8qCw4@wA|2C^w zuY7NDPNGu$q0Am%waM9YzhuvLzG!l%nd`=>u+MaPH-sG_{~NV)hg10v`7bEb5OZb*3iptvmLV<&R2Mo7O(=sLy?^e++N5X-}NX zk#Tmb&aBGtqoEV*Dl-nS7fd%a5b&!FIGLnyq1Ewz>h`9`cXD33IqY_ozY<^kMP!cI z$rtIpdABz3S4&+|d$-MEOWmYRoD0Mqng2B?UN}Bw${HEb-<{j1Y&-L!W z<&HV!Ki(ZGK6-{>w$X%>X_vq4bPSo(aJ69BJsG*?eeuN%J>Or1?l`yU$8C|_O!psh z*EFr-x^S;avgGKK{~Wh$|9)WV+Qi&+S!Ro>bwj*yDeK;+RoiP{s7}}-7dFQ>R&*Al zDW4(_Y69MVqs>zTwh-wp!%Jcl+A?RsE;*OFe|evVR|w P1EnxeS3j3^P6^&_O7`P)Iqt0xVz^8IQL1LHVzpCg5 zDsSg2NS=JAv4!(pW9bjx=74AspLp9lP3IQPm@?ntY`{rzhw8YE0{8jkALN{LEXg>( zRd?3UZIiSWlcN$u?HX?$3sIc&Yr&+(kmF`N$L<+RE_&gXCn0O4`)fhn`Am6+;wcw> z^90^zeN}x^d&6|o#qb5^zDo8w|5lgW=6H6?@dRPH!>JSIZ2sGyp?^4TMN?$Oqe+*( z9p84!>h3)M=-+(5IQ}rkZc3dH(;HeKTPsjf)psz_z)&TB@n7y*UfCT?yB1D*zmcnL z$J*r?`4PWms|3#(e9(yc$X&o_! zu!}}Cn=3?ihHh}bCHfMB%!( zODk_&`1PUQu}C;8!IjPE#W9hrCNJ5`l7CKK{wPx|_f1>ym!eK%q-B(=`$F?@j^(>E z>db!J5&Kn9v(WsJ(!FKx89hEt7kzGTE2`zicbE5V%lbY5#=fay)e~qMH)H6mo z{wnlV`K+$+@U*Gtg6|&hr_Ss6|M~Ly(3=aBxtSxgRAz@fya7svp00i_>zopr0OWZ< AQUCw| literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_bot.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_bot.png new file mode 100644 index 0000000000000000000000000000000000000000..a76e39048da8eac179d68b8ff828c267ee68926c GIT binary patch literal 657 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?6;?jV~7Xu z-Kl%^odYF~!~Wl-FA*`a*GEqk63sA zkt+umt=Lg_zSOVy*1gxOdetj`?R#!{{`b7g)#q|;->+8|{LWf)U;glB9`%O}AHzGY zZ+J8ka`xModWzJBdHk(39fB7P5rWVZNDk$&5waboty&-dMW=3WrX z%a938*z<{FRp*y$)d{Cg^LCXQs!a@MRgh2qYU7g{(Ri>}mGAJ3Ci`8fT)FJd zn{0{X7ww1E%~jB6>3W|otDC*0Y4KaBwfD2SWZyN^9O=oI`P+M^-PAo;@9ou#IlXTM zeOS3Sd}54od}+q2@AuHEvhVl51k=gSCGsPBGqQJG<$lLrtfHwQ@~}s!fIm6jY5C4` z58YZFY`eT1v|i4dQ#0j{#9_{llCKI|9B031EiO82^+uUX^-{MZd&2~-BkKtX7;_8J3C!-Sh&9&kg~~|(<#65*p+WP@^)t}*jOZbnXfr? zQQQ=vlKWw8x-XnA%3o5t6Vxx(u6@CR_j|(b0N-10m)d;FJ!*4q&$(m&YEH$n~w;%v?Ry}FPpk#vw>Y}B}Z^XG-uMn{DiG7S6=GoY!i;oJ>tbG?Z|SF zBkS7x>2p(W#H3B?jpeI3b7tqC&2#3?)fJg$md*aiBF~Y3okGj8HB!Q#1z#T!*!R$I zX1(Dyb+Mmp0xJ)y-*E~p?J2Ej2w(9d>t?0)wWR5ll6=hy6_e(FY~{UTw>5CtwpDwVw%S-a zr7K)^o={4C$oZ1Vx1N3*S<2t7GVv&r)*|m>OI4t4ab*gml>#Xad w>woTBe8s*eg4yZ9c~AS5)9Sw(8NWQBpWf4aE_8RNDJUvDUHx3vIVCg!0B9=7N&o-= literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_delete.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_delete.png index 0a846fb25d6425c5f8e06dce2f821dbc0f63317b..3b557e12828598448deb4fdb1946fb702e9833cd 100644 GIT binary patch delta 498 zcmZ3@+|4pUxt@WsILO_JVcj{ImkbOHE~ycoX}-P;T0k}j17mw80}GJF2*grA%)r3B zfRTY2NHc=O7BInOB^EFv*dT?EOiR}Sm6dwBIEHxeUY%m=&Fm=9R$RAWYuBRIsndj5 zxU-|H>%9)t$0yI<@~{% ztiP8X}Be@oZT$#UcX{`-Yez(vF-a#e|@G{@UShn_3(+#69#8gYo)9bc+xh$ z4#?2t`LI;u__?M(cK@mbqQ9R~dFS)zv|@QN!#u~`ohE;zFKn#03_8)7pza2Z2Pxl;Lz4YihkF3`B{keQe zmItNJ=Zie4yJN+;*V}g2+w9F7KWteZ;LYjtTc#y^SAF0r;eet~EbnyV62le?+jLr~ zt*<{dWw9-5-H%8;ksEKO9Z`JI{N1TgNayjqhR_So6zzSyIQbi63pni@=k{vcX})}9 cM}5pcwu*m$HyW$`o&t&sPgg&ebxsLQ0H!?5EC2ui delta 402 zcmV;D0d4+^1gis(BYy#MNkl z42WQ*f5b*B?d(kox57pc1ZxW=(ZuA)gBvr9FL`4WLGZw3&MfzyS?}R zYN9OZP|`@8kBhE=1*`+xzy)w>Z3Dn6kOo%TIr{>U!(fa+gnv!o#&{Mu0hWLX;K>>P z43uNlB<-p->TUX5T(?`n8E^p9fDDi_E~nmr-(Iuw)(z-7d^(^`kxDhgrepf&fjeN~ z3o&y*5!m-T;si#4F)JHmatXW#m;+`)1m3)I2PoKf<~?4t;L+HMS)zcCS+nRcr;SIK zW6EaS3)EXVhkpoE?6$;loW70)zJ-5*9}(zwUcArovw@G0bbSsCTduhT#_ir;Stcz7 z#`*YgHY_u)Sv@5wo51@dy-GUv^I6;$y;wQa&;_aqyx$&TDP)VH=l=-o0n6=Pse?%q wI11UK$QC6PBvk|LUecER-vRUaGXUNJq98ak&qixr01E&B07*qoM6N<$g4o=+t^fc4 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_delete_auto.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_delete_auto.png index aa789fd4e0a0e6fda0538f69fd07ca078f8d9ee2..d95af7c86c8cdd603cad921e3c994e5243af0f46 100644 GIT binary patch delta 534 zcmV+x0_pwp1dIicfq(W%L_t(Y4b7I%D@0Kg$LINxSjhMpVddvSHWo@YN*0vNLir2) z2NVB%8O{P`XOP*_rT@{P{#sn*>S(Dj}n14)?Fk=OM3ZjsLpV)yp zQJFcwm!xdlG2)&0b;j6s_pHE)HU8rvXVV9_&|l2d=no-k*Ob@+#`0mdz@SIYGeqNB z5(Cg-3%n+{S0b6@yVk6PcXol-1X`qv>>97JUW{H`Mw2&z<2X-b-$55;!~xC&xkuO! z&}37bseEgH<$t>6?LbWGdx1xg+mx}O z9Y`+c{gbJ}p;05u;PyZYy5StQi2K%&cZ=r`iRG-uO{zcS5{$zn#6cD{oX?x&VDB!M<6;J$%pg-vL0JZBRJ-I#co%ET98qft(W%Q?w-5TwIMg5ZTl3GN1t7_CaH zlhe<3Bs3T_Z9u$MrPWFN?Aol)Z%_lDG>_ZDBRpbWQ_o}whyK8xZ$SBNX%LM@cl{RA z>Jd4PgbT0;dVjB0q04O6YJ)?HnD>5#@eE`@-^2*IDlIkONN#j26dD43H)BwM6imZ4 z{(f{MsDa*=I|U-9t?yzO-y=N3EWFS(i%x@fvkp!nDG8FKbH+O&W~&-$S?_hN!c}2h zfF}*yJFwsQfm&$OUmb^b6@vt;KStYfi!niyZud34XLaHSbiPaI3b^GAM-HYSL*Xy9 z@=UQ8>fS*0%~{s=z)y~t=mY)R+&8P*HvS8EwZ|=K3S5Dn_Ly0KaS9}xra!bzfqD3Z yZ#ac*I0s1ydP5g=Cs1S#a-b%X57>hqJN6IChp8eW_1T&L0000LXZ=2M|7qEn;D2)h>;Hx+N~((# zlO26KCluaIzju8`@jc5qn?7DKeSf^z{(JGcIqO{>?Qj2nnKNYdRY4Qu35|A(_ov#l z=$`-FcQ$Sh<71vTjlJP&*V)eIdMtjnpP%c~2e$VcxFR#Q^39rU`*g`fv;5B!l@Fx` zOi8c^@(Gf%U_F|&MDCzS%>nKgC!Q&D`v}FF%QR%E&ox!K^?*q(L1dkR-{dJPr@BY4 z;GAt4ATlN8P5TaCE+d7ab!^ruU#^$jQu!R=8F)60X#Z_HF8Hi&OOx$fhq z`5VQOZydhC_dM;d=?8__O(zcVt_l2expjK`o+mRm@b228ptW`3NAon{*AJ_2v85*8 zyqysne>5Y>c1`-(mf-!(i+3%pZd3a->x6UM!Ys4y1ri*p%+eWid_%OE7fEP*d_Qet z)Vf`AURGuo+GcIoo@aARMzwBoE=$#&<#U@3sO@_18|L%2%pojZ$-`Mv%OLK&$^3=E z!m;+UH*A;8UVT#GLiG#5FI;g=eQB(xBzw2`8%SNT+MmI}E|_;n;6>T(hFXnAC01br z_FcOE3Dcr~_IxaNoUEeLP$#$8Ds%5f7EZn$$hYS%JIA7sCv)~hnNH6c;lLpdTcGSZVP@Qdad=?HHD zc}MP}Uwlr`%^( zYOdkcd&nJ^XgB47{-IrUp65OFeP;Q__{KSSFTb~S&f6pF5)4us4S#EWbes3u;`uyb ztK~D=%>P7plnE)#{n1e&ns?#P5vfnR{)uvW^IGQ_Ji5H%%h%&auWWm8?Req8&klM4 z%iDh#=9qlcc50S<;c(Y{lH-Ci-mA}_kbEQBmF#}^;rjC)llNS!jG6sK@D)?Z?2qla evu;GKdLgbjbM9u-+4~DXLGS76=d#Wzp$PyPX~OIP literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_empty.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..4df725ebee2e53a5c692ba08184c3b44bc0528b3 GIT binary patch literal 444 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~STEL88gA~qMxhWK=OwH59F~mY} z?G$@2W=D~BW47i@-;~If7=_k^RWS$D%r|V}+_+gl=Tgf7vz?9X0;^ec_a2mU7Wl|< zi{th8=sAhyb5H!M{_u96`TM={n~gVLep#X8IjQ)D15f^^&||y#ll{HxIu;3(Dg0*R zv_14D`~_Ql+5GosTvX0Kklm-yl&Cg$SC8yL-80>m(F-2(0K`g&y z&MxWl=>O$kv2F9kL#LFM$6Q+YTxwgG$L__ge>bbCe!XPW?4WaA!g%eajO>^457^ml z{2pFa%i0tEWsk>-m6DuWK4#wf=Wu-A)T7e^Ccllp@c+TJwgu-JZI=1B|IpM9`6=%B zK;W8ym7*ojl%JWUy>||}uG=Z$A^UH)+qx5{ryY&U_j$Old#!iglk8uN=_~xppD*yM P2ZfxctDnm{r-UW|2rsFv literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_timer.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_timer.png new file mode 100644 index 0000000000000000000000000000000000000000..7e177ecf1f5b0d7c166fd96c4fb3233d6278f5d6 GIT binary patch literal 319 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${E7uqD?MEtLo`H} zPITmJG7xdO$oo-2X0iAOyPSmcvJn-W=N`}6QKG8o_)0qG9H%>5k5KZ!WO){rXU>~CH}kZ>m{?0%X7Ir mZ`)=2BwGBq-QT@%?^o6}a%@qD=V;9YIo{LN&t;ucLK6VQw`!CC literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mute.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute.png index 4dc2917ba504a1596babdf6ae0854f253a4a67f7..250a9a7ee801cf7f3dd5d188fb9007899db5a8bf 100644 GIT binary patch delta 739 zcmV<90v!GD1NsG!BYyw^b5ch_0Itp)=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR917@z|H1ONa40RR917ytkO0OB=u ztpET5WJyFpR7efolubyKQ51&fQ?ZfKlvy~Nen>%EwreH25`RTnL_tCcxoD+=V1ZB| z?Ltsol_-TQH8zWYV41P?rO&Ux=W_ssp7 z$z+a<6^q5!P=KnmO)-{*5txRqw0S|Df*FuKheQ*!6R-llUD9F*4G;wvb|Moh;VH;U znvmDP8x3F&pnny1VG(k$4Ikkuq&H$P*aZDC$R@on^pkuEBDf1bK=u~u-MoZnFwq2U z5XSt;mnM4&jcy_0)FzDi4S#gmvMJT#J50vixCU)j7;uX_ zj~;A-u1j6gJiMOpD(t~o$lAD2;TB5sQ55}Q>^dyM70})2ck&SCA;X+sxJL@%BKbCc z1DX;)D8z)R35%+U?Al+K=|$hQvD}W0x2!*gul}zFDhM^9scC}OHy?uE@Sa@vsAsz3 z8Wc%n|9?EPKoh+_?Wh4RzB<};wzxWsA`VAe| z6dP+7y72RH8Of*>aV7SJ>~uWQ255;U8bZHktLMsVG^i)m4Lz3Ic3#) z!aAHRpC8Pbcnf5oApUJ+-OeMfvpD`69^fY@*H#OVj}EHVaq9kNY0=Py96CbO{Y>j#P{*178;=SfHFre=CV#6`a0v1dNL~w&g)~*l4FN_Y0C^{g0!&8&q9A2f1Fj{tN;)%p%Ekjp zD*@vbB>gfQmjV`6l6Wo#2CZ>9>pfVcnhWgERsALKly{Qs6{XSQMIUfs3luW|SIIZP zDe%Q>_081)+34^(>4vp+zf~OPy-6$}U2NMH*!MbYwoqM{L23cGs0UVUfgiwtcSRw0 z9oGs-<8!9p&IfYbxB50~(|{9m)h}sW(v_rTNq+*F?Mae2>%XxiJp(JvEY4xaX)FK$ N002ovPDHLkV1no^&({C| diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_1h.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_1h.png new file mode 100644 index 0000000000000000000000000000000000000000..0fa0e550f0f7ccf9380f680afc4bc1d9673c001a GIT binary patch literal 809 zcmV+^1J?YBP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR917@z|H1ONa40RR917ytkO0OB=utpET5lSxEDR7efQmECL3VHn4s-wczH zX%seOl0tUkwUo1=g*9>JSZhc716WaWib#}GIg%(A2XaD7Ydg@|OHIK*L7dl_qy)qcmH0VT<%|5KA*3Hez^6w`_gmPsEd2+eL-z>(U?l3{G01MhA~*;`;P#DR(opOs zjkF8lx+R}z?eq0ZFI(XXK7sSL{*J!{yFphIOtIxulSZZ<<$czG>$SmMxC0Bof5mg+ z4XG$2kOp3WOuf2~7vWSz3&|dkJ%q&-f{cW;)`QFURFzR^hA%J$y5Yfyb$`}H>!qwq zo)p#81M1a`X4j{l?CUS_R6W1iH*$Faw8ciYZECTJ@A1 zZ)PvTZkPkvGdKfVq0vyRoN6*@yE6w?E6||Jz5)J+LRev{Nt1b;>AzI9O_Za#5qAjM n!M{6tR7cPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR917@z|H1ONa40RR917ytkO0OB=utpET5y-7qtR7efQm0xI2VHn5HnPF-c zH8CzMi`>XBnX+2s!f>ORxRDzrt?gzvZY1SmE?oF?Bg&;eNfO24NBMbDaIo@0WJNQ=dK0`+c70eb0H%?|m0V|I(5qsexl~ai;6ibJVEG_SX7< zWCQVK*Z~95(PCUH?1Ta=1=%J#9#=ua1Ue`U=D1CL2&y{ z@WN2+rW)1GhI1y~*VyORlb*4}S$qt~ZCu2kh7F*%38vUIQ!YOM#CbXP1R(FhYT3i{x|i08u+ zAInS2j!kPoSFh%1EYGW{A7q`@pbvi~D5XEoajPu%ia7VAXq~0funTm}_y_Lu+SHS*gV*p0wC6K2^;oaw zsH@maq64Pj8Tj2_u{JBJ)_T<2kJ7!xl#{8pYx*pI8PTBEJ`Xyz)l50nRNc<>zf`sLXx9C+4Rq+5tnM9t818bK dCr$f5?l&&zA4>uegJ}Q&002ovPDHLkV1m!*h7AA! literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_period.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_period.png new file mode 100644 index 0000000000000000000000000000000000000000..ae1b570ca2d44043c9e959abc42e5c3de61b99b0 GIT binary patch literal 736 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfyv9$#WBQ# z_vln#kB~r-V6R z=~w3x@vj>fTZU!x{IrqY5j0E z$O>@($$L;KMd4}qlf@a!9Lvn)&sK+4ntu{7dtB-~%Z|^w?MCRc=}N8@cc1<0`XhgA zdI2+A0xOr!Hpa-`d#1}gRsJKFt{471k#Eg9=YvU~a|5znB;D6oXS9UPXxEKkn0fW8 z%jH9>^P8PmjpbT*x%NM0UGcZA^R3aetuE3tw7yHSKQuc!{dAaFldxyYpI>n$k0-QU zKlAtRTg_*;7o2{=0wd+7ykUS50F@&j^< z1pip6+aHZFOH1B3F~zoqVQ+x#q$6$rL~5Gi3vTY7aKw4S-LG7ySR%^>%Mw|?SU8`q zUC-$!e6jOROU{hH-@UoLzbU5PzL6Web)lKgUs?BnLw1vAZ#la3^j*hJ*I!<*O14|h z;&CmT^YdbinFaf=#~aJ^GmpBIFGvcxCK*tkd!YE;1NO%sZ^wW4Kf8LR-LYMu)aB{w K=d#Wzp$P!GC@@<9 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_silent.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_silent.png new file mode 100644 index 0000000000000000000000000000000000000000..6b37956a9e71a5593e9a245c3722b17210835345 GIT binary patch literal 609 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?6jwgV~7Xu z(<%NM&4m)jzvpoamQCom#Kq43d}{aPNzJ$QGA441voAezF!14nCoc}15}6pp7vwj& z=+MbTmG-Bv63)iWe_s22O?-CF=I_s<=iAoTy?_6E&-?eav(JBDpK`m*I_IEWPt~sv z65kGRcNFDqaJP|cid45bDDLBIe`3PjS?mdy*!U|CN184+FU&x&~R1J?LUonCt9h4{P%n~)mby=(_xPCnC^ zA(%2FD11*~_PRng0p|&g%msce5^W-LUN@L>U2Kq=(jAj+*EpkF=mPh7h1VAkS!<+6 zq}5I;HJh_@<>%k$-fOx~Fsxd7$$gf0(X&k*$5|BT z9?$%dc}hIM%X8M*O&3M>9tuzSR)6;9752ky(oYs;XPB4=hua@8xgfLHS0L75@5S$F z4H8Lvl!Y&FTDpPeCmcKh=5cKEu_0L7~KHEG$v$x#H=wElz#)y4Cwtl`;6U@S%!Y&-& znHl03%WZO?>#;@p4XuvgQ;a6s3E}Ennr5B4*0efl4yQTCttHGE_s+Dbt}v6nzj3(% z`|mc}oT{V)Iv&aw7+df89mx$?BJ<5fV!ucBy;}kE7qM1wN2|oMT{66K;5ox%ZS|?G zZ?{@<3GoF8zCQec&%7XU!umTKa;KbFsPU4)cuD^*^~)i>Prs|adU-l{Mp1+0C7-ub z9rfEnFKs^&wzS{}AD_lbPVLh?-peLG{t~OS<;+~g5o_6buZc^mXDO*{f4~~1$Y149t*021BhwIFP}*P2u#dmD zg1O|C)pp@JYme`F=h7ozv}(j0vgkQz>GA9TMkTvu<=F=m%N~fX+gtg1^9G*t0WZ}) zo_3u5g<)++x`R}!lSZrOgk!l2uO}vQzjHYMAoxe*2Zr-`e$#d^`8i%%8=L$1Mdgw1 zR>k10ZExE+bec@W?l|i4vn7fxTPQEIf1=JS^N@w#U0OC)p5Ws9;rFJZJM)^y9Y(9O hdh!<*mjCttC4aD-L$>bZ$x={~@O1TaS?83{1OPc_2=M>_ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_off.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_off.png new file mode 100644 index 0000000000000000000000000000000000000000..1c346dc7fd2aa160ed448c49782b918d42774f1e GIT binary patch literal 738 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|y#WBQ# z_v+R74F5uj;~)P%i&xt^&B;qePfhXE+)H^p51k4Z7AP(b$h#vE?zMBnk`@v1w52AV z!Cc*o+KQgKotpp0^XAoz!*y}z%g&v*EUwEwebw&kyPtOFzgO-%Z+ZXo-`aXpQ{mX9 zZ@8zNep>qH=F*^*%F^r2rrDppQ?%xgl1)H$yY956Y>v4SGZoE5S8wE>{(*^EVr9jN zq?0)g{y~LWn|j0_2>zN}k!2@QvPksojfM*!-@KZ3Q^!=gAF1slvbEemwarTVup5wUZpp(gxoub+i-En)4-C1Jb zcOkN66Yr~^8x!U%S$LmixAcBN{;f+k6<7((X%C2&@}9Luf^Yiy-j4Zxk2X$y+o68H zZ~l*#8{77<*gsCTI(bd;Z+*tOwC>}#We;foIh5>kJnYEUf1-s9|GW~6l`P}F>OP8Y z$y@MBG)J$T^V9Xm){pp3dlyLRJ=V-q{AN~u>67Tud9#krh_|u6xTv1N{*P%T6>!!A~?k21h)trIaVTeYuS}!P8-DkFgLX}ZB0;?@Lc$yv9%@P zp(D$|L&w~j7qv#*tXO;h_8FetvrA(|yBqlT?J<8p=jL4>ov@clf1fdI%e@{nzr`-2 zc}{BN?F{9K>=)Lwt&*FN_SdU?;p&6Bhj~tBx=%H;yKFK|R_}nq2?1Sm3F`tb){ets zJdR%&Rq~yL-!$fhB~1Umrgy_czO54+-JJX#CaP?AYHQ03{>ppUSa*Tner0O~v6Ek~ zHhB0Rn)Hvo#a34R+w*>nFUGvL<>qgQ;hlVe&()&M=;uX-S^XC^nTy12oBteMzR<^} zzvGa|n?t5^CfGh+e?Y(dJeSP@hI$7{rRA2)6OT>$^f$7s ze!D#O*8acf_WK(wk3Mirzp#c&=!UmK(Sq&`(hp=mDeNw1iGIFp%lV8ZU4=(8&sn{! z$hFR%WccB%_I{gFI&)TkwX=G7&eW{YdPl2Y;iA_GqAqSeNt$ZQXE$+IG-}Uit}35* zT+M=O{Rg%nh4)S=cPGDy7Pv0HNMC4!%1-HN4>`;dWEPooyomg{j{nRx`&6~WuS}rW N^mO%eS?83{1OWVbPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR917@z|H1ONa40RR917ytkO0OB=u ztpET597#k$R7efwlsiZqQ51%E+@K&v4fu`_L9|GbO2yJjuzwP)EfiBI78YrYX|xlJ zDI!F$5!^+v5yeWd5FwC8At4DVvtvnJE4A^7zW{PRFIH^L#@z%aCfhAcx1DE|=#ptwP7 zsDUq_hR^Mk_rMunb3J{o{O1cSDWug7!=k6jLD45SyJ zVMeKK%D2?`19pg|Db-lxQgHrefaOF8a)A~7FkC$YMlRTtB=1lHhB(p&l4 zt4}Wa7k`CKt=CA{B<1IAv5mzZkGZgT4_oeUAkG;;Tn73Q=$rKo8vXi$K83GA+6Mi2 zPWaIP{82at=@Zmj-JL8O7PS*?fcxFBZUD9wBn=pc=n!{mt|B%CumaL1=ut>-!u4nP z#W(g(Km&dEQ()4GoBf(te42JcKUBuj@V-rc0Tkk?fy&;#3=RMQ002ovPDHLkV1mI> B7-#?h delta 528 zcmV+r0`L8@1*im&BYy$!Nkldb^=iYn1 zpYC(-IhX&#)T(||o${w`u9r7$6~t@mNXXt%_s93CzX51hFMoyLHMLV+8u7`9)BLcy zq)|XhxE^8`0+z;C$JlXof%+oi33Y2#K%aU)5>J=rR>k<4h`ZE%>bp3jfihsNdR2X% z`DBO;&j2q23h!6nt54MK954|HW0~Jm56!Z>0&qfIsE&qsnj4I{gE=7C;Rdd20XP=t zl`2DD=7 z%6tJjLgQ??)0BivI;@2cw8Ngovi<%HlBAvh}@EI5h&5gi=v|vswoCMAS16lGn z;0kcF4j`?W4}1WIfQP^?U6cedO=kv9np_11}ks57-GGHcOqdtzLBePU;hk7I1`%t6pdbxTxYtLz{H|wU|>Ugy5bi~;BB6=<#YL;fEc@EwsJ6(UMu SvTFbU00{s|MNUMnLSTYj$o`xF diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_videocall.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_videocall.png index 45dd2cfc1f559dc554582d477ad5396d70f96d1f..8e005ed8fbd026f333935b4c941ada20669bc996 100644 GIT binary patch delta 479 zcmZ3>{F8ZtNGZx^prw85kH`QX@Rme0>?TfNTy1#`a7G79fieh^2s-fq{7e zBLg##W(0{XV1mm^EMP{kK?)z4maYXVOZIee4DsN7JH^(U*-@aaxKm*fOG^XS#*G5e zg54rvVM)sM)513La5N=6j^7~o=IXO7?t^{;x@+Euh_ZMqclZi@(4KdG_nWpmqB}2d z{v20fw0ZMp<8tS3MLT`|r!zSUggg+LC9vF#GkgPI-1jLF(-*!-sx9IOF?jxgEB!)C zoYn?QX6t}9->ja5+8OQs*P`b=&wV_b?cK@cJ_-l6=NH&-0XQRt6NP*E@Yo0#h;of)#J{rm2& z_E$@DA9U@tRL}aq%5h6x`drh3#WM>0t}K(iI9GSak@`CElEcnLymFm=?PZg6+j4HH zmhtjsF0wYwdaRqw`K~cy3!~Qy&7w~W&O6J_Tfo7tu(x5K>v@A5u7^_|u+^;+V;8%7 z`N8!EOnnJaAI~kHc7Wk^=#17K+cPE?bK9B!kemJTyYLUTN7atOT0KvKKq2qx>gTe~ HDWM4f#LF=8dr zbiROHv=?jyv9S=K~Stxq>otH36fF?2tl;45G*XLEUhF_2;%z9x&xO>%$>58 zWZ~P{ot^prWRts0W<37=4H*4~*4ic3+fdS6LhNwff)itm)qh%a7Fo|ioBX@WliYw0 z_{(UB2#t9-jtD%mo>PN+HXSItM2d;pB3yusWw>-JYtM;Qzdld{`SfQgbo)x^+3`ZJ zKGuj?Fn)iU^&L54udh4ZMtcgBSGeBA}Mh()*{ajT?^l;d5D1+uOamj@;(5o8o z31u)Ktcg$tGk+==kD(0q_*+iK#bqDLUOM_?oy1SD2Jw z%IA9%e$gVXad1Su@wucR;uUyI_i*% xzOM7s$jfeC8xo>i>n%_4OG4fFc=Qc?0V$?2ThQ2_Pz(S7002ovPDHLkV1j@uzq9}V diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pip_pause_large.png b/TMessagesProj/src/main/res/drawable-mdpi/pip_pause_large.png new file mode 100644 index 0000000000000000000000000000000000000000..b8691206d7e0722e83f4847b7baa75e86179637a GIT binary patch literal 365 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*1@5*F9YvLo!(3 z&WPq}G2n4cHGBAH2fz8tWp_^H9E^Xdq99}v@Fun3K(NM^%9zW-`!AL1a5yk92{bUU zC@?ghX7SRT{Pt*B%<9;*+kXQuMOa@na0K`*XEt&QY~bra z5v3{V+_f$dZnorwg6gB0F2&*1?o)A4k149Q@9 zJI$Btkbyv}biYCc%SWdw`SQ4fz2X;)OH?0u-g$A$SMb&AMFLKf{4PzJc|fFX*~u+? zzVH2K+MDO)z^TEgx`1VhLo3U#efJl>TOt0c=T=B6bJKi{>gvY{@x7cKe{a58`%yIc zXJ$lGt@F>!A0gGxo-BJPC_QV^OgE3*l(;Y{!G#-_D)u&an1}kPCidF%Hl0{0cF$zl z71cGLmrPWca4E`;w`*0;yyRERc|raXzu5~PR~)Qu&tBVW82`#N{EFMk+Dklhf?k|& znpIeT+;8PC#eD}Of8KvD;rA%2^3^w6cM-{~$3H7{6B?%f@?rjS#hCZR!g+}fVqaO9 zjaFK-?K+_CrdN90;kCpB|GS18S{vD4HSbz*s@^x((JG7y=0gdNKa3SGgfGpz-M NpQo#z%Q~loCIGmYq;dcN literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pip_replay_large.png b/TMessagesProj/src/main/res/drawable-mdpi/pip_replay_large.png new file mode 100644 index 0000000000000000000000000000000000000000..e66c7b44ec92d8bf5f5b9edb0dd695c34d8f1d89 GIT binary patch literal 681 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31Cy|)i(^Ox z=i6zv`YeGWZM=fq8jxB!fnj1U!E3ENy?v;0N(KO+z;+*QTaPb0hA+C)g(ydIL z6FSasn74W7bnCT`dW zzCh=F^Tj2cHO`*FHHH$6%onzuTlD9CyHg3@wgq0M-+5EbRE{?nRC=|wi#l}KTR)r(xa_!ppZYeIB=rZG_2+m?gb;ZQ{SA{#i-hAbq%X#FnR{HJFd$ikY;<-$xTa-=Rd|&*}!(*un^g_4) zciy`?+h4Wp7FP`0sz9afW*aB`=p6$!p1N zH8G+0fre{ECuMOK8dVuTSNpLE?3*{>9mK*%<;BjcVGtV z&wiCH2PI@0xABVo|G#zmLqWaP$O^X0_jU;SOrE28;=IALyh}@1#S~c`cONk1mrd(^ zZT0&7fzXCyXP=lkurB#g7Q6eJTjfPQ7i)pH4AvhQTm19BF+Gs51SJzsS3j3^P6gX)ynR0?x_XSjmpI@|dgUPY_BF5_%&po-9c=i?3L$*i$at}2AC+v@x kILfmpHa4x5(_@|}LxR_X^&O9Efo@{(boFyt=akR{0Q)vl?*IS* literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_webview.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_webview.png new file mode 100644 index 0000000000000000000000000000000000000000..f2ce5124087cc3ea0fa018944e0ced6d94dd9ef4 GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUz4CN%4DsN7 z8+w}ekO5Dw0CR!s9Ek?y=r1R9cn&80X?xIOafqemyOwIz62;u6sudyL(`5h8d%Mar zw0EwLMZ?xI#@k{(GoAHW;(HCJ6gqvB`ol6^s5pD=JN1TU+4~1}&ds)cH7DV%+RV=F zDY}#1g_@m+;?+E`f9~#CQ}$hpS-a@|Liq#y8<$>Dom2fmi{}^XhQoaRi3P8E@+%tu zOB{RAb*228v;SNM-7cmD)wjFe7$`iKG<`qyg562m*qk0&r3TD|Q_?t`dH{>zvpr~YB6-mr63YVgOaAm4ks`njxgN@xNA D)$WQJ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete.png new file mode 100644 index 0000000000000000000000000000000000000000..5eba29d6caa4e80c7702ff585ade7657181cca52 GIT binary patch literal 1273 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGV@X6oRA>e5nMr6BK@f(GN(7gK zf`S?sR3ZxIq~KY>g8>CW6qg`^XAuvIiUwRjZ~?)KD{gqwlb%FFR0P3;iikNxBDjFd z#Wm4r{QmHo)O5Pvn|W_u448udO?P$GUo|s5(>48u4I7f7D^SrDsHw=?IQR7QETFp* z%mY&lKG0rOQ&aPpJs8>Ep#2vSRg{a`B?6^Ql~T`PD6-hsE^Dbwc>$6kSB9F31aTvj^iEXMYU zRp!plO& zkZ8_Vb=sKlI)PE(xrwhg-E3=9w2iSADJOc{#4z zt*bji9!G(bTdAU9t=h(kZe7{$`C{IsQoe2++mT?b>j#e*TmepQ1dTE(AzK349H}{8N=t>$Oz;}0_}dcoW3UA{IT$XGFT>JzZj#@>x$ zadfw5Am@5Uf;(Gwkv>WZ_c79CMs)?7NdAq{WohbpdS7t3 zY90ND*q%VTrQ5O<+9axNlZABG0$uSd=-LXynGZT~__W~F(S8vnz^Ez= zQ7gHY5_#tvsm*W|GBREY5w)7p)k9ws;{QD+(mG;>dRviB2w#sOe zyqY_`Yh1dE(?8qTD%=4#|FyYRTRP)_1&*reJAf5!a3xCGfNL%);*77D2oilKS9^1J zE-?;*WfdnJA}E}MeJUilL|K3GDJOiF z0k=qL`sfbURV&{pFF{pyWcr)ck>R%n=x(Mf51gZSv|sz)P_{0KG~lrUXh%Y;ro#u? jgY%DW5*w2L{tEmBT^j}X;q-m600000NkvXXu0mjft=>N> literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1d.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1d.png new file mode 100644 index 0000000000000000000000000000000000000000..04f068450ff9b7b3580a18f5dc44fc1a683f36a2 GIT binary patch literal 1426 zcmV;D1#S9?P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG{7FPXRA>e5nO}%jMHt3ivsKD2 zM2xcaPbP&zLga;af`LIoLLkyjY(d>dloT2fRzgrpi8s2Hg%UwV7n@y#h!tIRq5TKh zWrb9f6kmaGjq;2Y0`vDjKG*ipleLl zW;`-7axc}@U=f&Y_znG$uCA_wl-HIhX|M$hf+Fb)nM0Zk`oU4~2Dl^ijay03x!`?p z5ws({AvwrBk-qw{UFG;j2EjwP!c-Fe*m5XE~yJx6I?*nXujh{=*j6y-?PTe9Jk{w zTCajZbe7MR=7T+h@-YZH+m{mTE?}?@44dJDrpKx;HkoIp=mL(%Uc62cXT4rl$Nmp& zd^C%8TCH3`GA}~$1q9M~l}9bm0@Gu)?F;Z}UB@iTGqEo2<)BvfROl!uKc#PGDh_>%z{CaMR1yZFK8tjS>TE$^=d+`|` zH}1|Q#*G+W3$K(*$-@tdyW%{Pbqwc%b0EmLzSJu*0)HKXQ|f46ZezvZYJOI^$) zLUOcI9T;7;4_nPU5az!=u63vKENsVc78n999sjf#k|OAgpjR$&qW5IYL6^Ee?%sp* z*TBlki53~+SQioBi8?;7&%tjWkgp&sigKykhj&e<_+zhv4g%rFQlowdhHP!mTHn0Ia0hY#oXtdVRL71|f3t>cuv-gsH`_ZN1jDHGxBaNAT$MzYVDT`xe*Wk# gcZn11|K|w&2ONz%8IEm+9RL6T07*qoM6N<$f^IH^pa1{> literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1h.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1h.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ba3e583828e53a4f00ff16b321bb69bd9d1ced GIT binary patch literal 1358 zcmV-U1+n^xP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGxJg7oRA>e5nN5gRRT#(T)oFyR zz=hvaMoOZPZYB}3CMsMsVPQs_781A7YJ_D2%1G$i|I>{7FuSt z(P^QA3WE7HrcS^AG-v$3=ic|ud#~@Ed7*jW&w0*sp09K7x##P)v`o;%6S%J@P`NK_ zGaeiqe2VI;U=f&OxCpZ2#Bx*^m`=u+n^iF zE*b;dd0;QN0#1S_iu$T)hf^j0H*h*ZrO=p73xu!9AlGnC^OKO_RKq5I@`sU4O(-`| zfd2*HJJ1J;y%h}GKs@GmBWwJViaJjWeN%ycf|(Slj9$g)gWzGf)RQkgd1XeNO;PN3 zM$gzZFxEVO!<=Z$mpW`LygD!ioU-_u>E^pmCXccfsX&@-8ur0v2DV0GE(g9)9 zB!{kMs<*)V;C0ua{s7nrltAi+4Y|IxonSqf?DmCtoM_Q<>Z;`krIjFFBi00c+E$yR z&w|`b+7Fmc%~);|^YQ$;$`rIQ`^M@+ECDNEH0@U&5F1c`8iaZI2K*J%@g1fQ3Fl3{#pBn~(X{$FM*ZM2{5r}Jat9LX zBo#JCdQ-Ah9iWH5 zlI0o8^flvav42{F^S_x~i(eY~)av>px{QKF;8XDOh%k#mG1qn){bk@7I09w`-|*AG z7vM+mOptqt{CRK`90ZSen|Ne1zy%=E4c>xSCs9YKnGQ4`D|4eT#V7Kv5@65_N6HTJ zxNFJpuSznjf{_jyH_doV5B188*gsf&U99C>STPvSYn2Brd9jH(K)&7%iV>BoM@Kea3}gHof>hy{wNN6 zfP4jdAuE@{ZFtvkioXd3)!k999~?>on=Qa+I;unTV&No5GsL|=1kQR%1ss3~8SM3!K&3h3;sRWslsd~^QjCb0?n-#>wW0hpYpGYb63 Q4*&oF07*qoM6N<$g0C@My8r+H literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1m.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1m.png new file mode 100644 index 0000000000000000000000000000000000000000..f5c36154cd8baf6fbd908e265095a56fea69a735 GIT binary patch literal 1505 zcmV<71s?i|P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHOG!jQRA>e5nOlffRTRf(yv#s$ zrx7YIU4~+WeDYz6sOVypWKmf3Qla%!5%p434}o0>x+7&D420=ZQ4^!cbky_D( z$i~17Cz~)$Epz()zd7r3ee2uj%=vCQ&@A|W>$2BgYv0b^`<$<p%OF%Q%Fg3Jfy!9T#$!*$N>Fpyy(81|Wv4}ewR z;hkdGn$Q+TaTb>{GY(nW|XGZY$_44rh|r-b1F`qji6dKapd2_HmlCL zjRxZPgHON^Xl_=h*aPC4e+pasM=Erl9D1gV)+0;{E)%O%dfXypTqED{#;axIxi{p# zd*T*54=QV)-|K>C&3AO!xb*5kFZjmg*G_k)_bHTd)*)r2-KK31Y++(oNX|jv56X94 zalS|;T@QT4Rr%hXEukGx0;7*gWy4!{8zW6!)BAj>gauCI*7o`+_z=u5a6MFnqraG~ zK2%aK;j3rm0x%<%V$)W*Aljpj&xzoC(D+W12&O~J(~{^T9S2>=-UbIV=U?F`nJ@BV zuIzcUM~=^Bz^)S-xOhK`Rf=^2JP3?*`qtfTu-yp$Fek@vS9J6lV8q$g$@5}nY%{?R z&QIbM(a&_s6!&P;jmK&8yUh?c!~NzcPJlt!>)<%)(AYSu{LanfW8u}=K-SrDPgdsH zRVe-5fP8w;D=K+ULl_35$hX0(6g!|dDWk0>I6jKJ2mA<@fuBJcT1w)+;J6~_Me21F z>cvOT+8y4pr~|so*AO%EJ%-uve(+9BVX-ok;+xEc&Zse$n_hzZ8$iv0TGWB-cx-+^|Wzn3q${pQ4TE1*2y7qBxpQ6`zp8V1nwm6sN4 zIzZ5`sQHtteT|b-qSmpI$$H@I1Ro`)wo1_}K%>4M+zE_+HvzuW$rX`Rpxx_baAhn@ z>Nu9ZPUE`*=*m3|s@DKyeQwbgx0T5x&WO)NU??&lmfPz|&dj2*FB?$?!_Kh<4a@U7c7PnwhWSJP+(st&9%q zOTAh~-p?#KTvz+X4pu50$hY8rG)ot%Gk)37P}-;cn58b1x-jeTX)00000NkvXX Hu0mjftxCg5 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1w.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1w.png new file mode 100644 index 0000000000000000000000000000000000000000..58edfe6bf38d2423d23ddbab962b1b599a04853e GIT binary patch literal 1591 zcmV-72FUq|P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHp-DtRRA>e5nOlfeRT#(5sLhmR zH*!LAX0(Q6y7&-+Qtkh=IZ2J8V>)Z3~bAlQek+#&iW* z#uV*>hlhtRXLt+f0ka+UBj482(()~QVv(8#FM(Yki`H4^I86Z`f<54QaDmxQ7^i3_ zcmo^oNq?HO!f`>p`ooa{B^@H7DFZdN~WBGgouM#GV1uQ%OA-X~MWS(}uR-Zta*z-AV9Mr!r~ zzfr#H%#B5YbUg5ZYZ`ku*FqmJ0HaTHRl{3n8zbGi((n0P1v8wet=H=_;3LqL;W}c% z(I3p#j#$zXetJ$8gK6Hv_);*>>r6&J11M&y={!fj2+Z`lLNdYHv^*_~6JXR~>}~LG zaQqE^p8VkV2A!7R5+BQWI@lNN8@(;WJ{N39;hnKP*Odg##K?`#q;v!;+w1%FBz=uWd4M?VdmVPoU*2I1c}{hSPsm?Ocx$ZvwPf^OJs z@Qxt==ycZ-r*9`Oe`QCrk9>Mb4%=$?-erm&5hLN6*`XL04s26VO>cA?}8*N;|w8yptHx z!WM=Ho$4ydTs2LkJ?M`Ies$ntegb{uHy?BHcQUo1W=&wPMH?sapvm<(_G9S#obAdW zFLt`sLDoUhmaLz^Cg*G7Q4`>)A42g2oL_12V;5Py1B`6~dyrptcD+*1XFS*GK5?>% zxhLS4&1{P<$o&L*Xz*;}Z30>zyBPl*a_TwoSAQq=de7G1!Cx$O(NhDAegd;xP;QY1 z^ziQp0b08&L1!4-@-iMzpx)J2sQmYZ9B&0)Wmyx*w{`n$BeK5>t47qx^YK~GX<~Oc z`z9wRA{RwVPp8oyWPMObD4xLf#8Rm&;r6$=aS_o^U``0!5gO6(b71>ON3d(1e-Y#w zM(iPAcQ&!d6ZjypR4Ur_ZgArwVn5D z&B&%EjJ&J{hcLWv#=zsfBej=aLjd_#_t}Wc?F=T0!Bs6Z$5N4@%^?$=fvuA_aijg^3t z`B_Cv)6=7)UGy3|(I@T0R=5MU{`GOKwWh&53IcUv)LX_=(?2a*ZxlVp9r2qXD_zyq}Lhv|HXF~u0002ovPDHLkV1l|7?R)?L literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_bot.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_bot.png new file mode 100644 index 0000000000000000000000000000000000000000..43c4a5a0e2dede90820a88cc9fa8978e5a9cdc30 GIT binary patch literal 1199 zcmV;g1W@~lP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG8A(JzRA>e5n8|BYK@i3hH(cTp z47h`stEecFQy?IM3xeoT@a6&mK>}U`a}p2w4+O93Rgh?M5CpxeD0mZbU%-GyqZl>* zzL~C}=H>0l7?&yd(%scn-&g%!r>AFHTAJ2;0{{0DXr0dGPfSeAgKu@f3feh=|2yql z@JeWHZT%MfGv82j2RI6DfUh9S6r)(>bj;Wa5N`whU=)-!<@STN-?|V4yTNNPT_&#X z-?9jVj(~5G%6~Gx1Ny*ruo}#^g47Q_%_&B)%JC-7BbL*U7J=hlG4yZJZY?UP9H88& z9WTn2D;|{|;Gg_=#wT(mrv!-uh|5eGJt-;0ryyJk-kAdJIM`F1DLw!=*|{oj?Qd@hn$#4Sdu!~~&bictypwS0A9Bo*59ZA+8i&T9(~+h=6sKm8=+rR# zL1*LC7?ZQb4Wwb#mmHmQ2BzD_MmrRjhW|8p05V^@VnXcc1g;_G&2GoVX7oPc+8H%3Y21R-P7Eb`EZ7 z90s**lf`9kAS=%1x6rwU&~C6C*mqu=FWjnV&<=Kzd=+dfLQ?ntb6JrER0t7}=<9%7B8?0xvV|I1 zM``YVW&ygSX=|AI%ar+My8Y}5P_3%D`bo^bR>5b%D7XUdfj`aeQjls>jb}s6={0g1 z{4tlgq)M~?2lOdxwulAgzN1)D(Kcu-a(TW6=dO0M7Vy$#=(qn(ZrrG@G^AzbYcOBF zmZz~0_}_$v^JSKgLT?zDNqb>=HZma?Ft*TMqD}p!pp2k6fw;X5WN~F)0btX$;XYX5 z$i4>ObLX2%cOA*Ps?T>Mx>{`Ew0Yxv<+?1Q3%vJ_ronw_b(O0&Aq&Dz;P+>v)*y|} zgfb?%Gq+GQ19F`bdx1ojMCVJ6Ka%$tTxZKXD9O=GYd(SI6ZjjSz%O#<-i-!q+k*fA N002ovPDHLkV1j((8$AF3 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_customize.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_customize.png new file mode 100644 index 0000000000000000000000000000000000000000..d9522439c8a7ca59ee15bd8bb1ae1d63f75a90cc GIT binary patch literal 989 zcmV<310wv1P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFM@d9MRA>e5na@jAK@`W|(^AM> zDP)mS|3DZn><2BvjkyY2=P@*w&QpScDaB%lvkWykKzlR+dqkb5qLSD)R4eyKDa^U zY>319nvMi)H}&^M52-z^@8WX%L+9 zZ~=N|5_}k+8%FG5KEs=)_#O1yYIx-_#ZD5GCf>YogSOZ?P z-eyklv8Yt&eE z?NtrO?~X(iJQ^Djr(Oc+Kwf)7N=`#QdE zprgE(8Sk@Y=t5JXl`itrVAC<$c2J|f&BQN|E+3it1{I&KwO28oc8Hn5pSNVEVwKYG!#q@E|&FGJ{x(KDu= zGref9=xQd{;8+kD1aS|;dN9_*arB;zsWKkyFbfBSMuDE>lSIGJR2Cc)$Anlv&_72) zvWR0OsiVyA1CZPgNxf+A1gseBYyw^b5ch_0Itp)=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg z3;+NFN=ZaPRA>e5SxsvcK@i=I5-p@yubw<8 z=ta+>;>DvNIcgx_K@lY?ir|t2{L17MH8Zg-Jss7!ZP^{c8^J>8q#UaxEa z5d*{F@GRs3WC5bvZ%oWVZb9~pUD^ohCdAqXFuX7}Ng$ZZ*2u|Dl8CNEKb8dqF#(LP zkSzt)Cp@o1-hUP2^05J(laMPAStIRszu&*~w>zT0NZ=r`D&14QP@um-_H#a4i>_qC zV(YTmuN2SJSPxl$Kr54t!O|q;F+@&}QMN@mpK>drGH`md4tU&^iNTN9}RY$dVCqc zRyqQC19=TOnln=1&p_msegv6J;tN3X0jz9ylYrKMz`+D$sdR+rnHsaolkbw1tW#oIs8WY=fVT6dwDd>3?cBBmrh5M*Qtf(glz zz-I)*w=p{mh|_7xglMvyi_8@$Ze#i0vuy0JoQrufAz3OQ!7*^^1Q;)U1qy080cI?Q zd4Ku-Np=F?!tBS3ZQeo!3Nyoud7T)Pt!`n#4NZWVNmc>Gp~+yPy!nSFz`(mudf!)$ zUdKwgTaB40rHU9L;6o5@7bDJy6<&Mxm-WHq$tV)DJ3b&QkHim zD_hAz*$96Cb&ImFx{I464djrT&~%UTJz|woCna;6vg$KS;V?Ft$TuD$C)h zn-Ucs{^1ctQGcqh4Tq&C1LA)x>xQcb;@M(jDK7aVj)GTF6#Yzl!X=uO5JG_6Jl*0~4!$x0m7*3qZUv#Y5`TF7Em=p2(b464eL6& zH*oQV5Pw3z??kzs!p~*!e|t^rh7b^M_OF=y<{99d;hzDQflr42V)z$kBNOxI%()zR zZfH73GZ0_OhQ=pOv$Dr|`CN93Z0h?7r(ItGZ>@5iD_vWXh@B=$fZ3^ibUomk8{G>$ zwr)KH;+*}TUc5~pP9+`(wi^C3u&W~?D>vE|)=R)@NV?bOpBfiK|E1g{X{Jxk-;}h} zM?l{6`k48%c+hlj$fVSFU6(~M)RcrGFbMHh z0~IHM1EGnJK@GxzQwN3$l7oc8vQbc?7Cj6x5Cy@TI#AK8qNdyguWv1{zjg0k`ak>Z zz0ZD~&P81CKi~S+`+MwfKTf6cgdU?A=;`Ts5Bvx&fH3`s;C~4C5=`uO!=|V$AT4!c z_(8uJ1jQ^*Te;ZTAPTQUOVL@Nhyld70!9Y0F43+7=YqaB17YTZkAe9ZZEb03S=Prk z>6Zaaky$nN&7@M$ZxZ_>Nw#TpJ`-td<7{3HDgF%g!(G+4g_WiCnWa{+3)tz=OuA0; zm2m@$y#{cakAKroagP79yqjyqud%AsNn7YIEU#8sH?O1HuBwXI6)-DS;RTx6z)p}j zdKSgxIAsd?{yH|-(f`H@+^u8xMBRU9fUPtgoCc@Bj7C;U{FT7&(mO$GDY*z_4`5DT zml8B02nhy&8=i>v-3YTPQPL@-hIgd%lJI4-qX;-uf`4jW5kF$n4&dS=mx`TCjiPXD z%^R6B?Eo%__gLY}X2Y>HZ)C1K0~pHQjJzvGX2>Sg6}ZXS-(Al=?Eu0{sfp_4$fDO3 zs5|=>IPCz!!8B2p0_)l8#Dpg;(l_k@y72y2B4{EJ7iOQ92%W;mvZ)5ZUc66)za>he zR$wzZ?0=2Ua&3})vFuZ^np%Y|>5GB5AuGT{9pHc%OWRYMK3bA$1p-&S4jQ!rl`O?u zU3mvk`U)`fGr?A{7L16V?*dYSt^rOb3xuk1CFpD5mItRj4;IxJMhNn*K-pVp0ksX0 z`fP>2V-Vj1m5WIqn`HocE|+~bwzoQ`qt4L24}a{jdbr4{*enCki`ascxeDW@swMFD z+0kAljot=37(~)*ZLeYC4*{MBN)|X55o9s=1AGHs0Y`z+J}A6eI4yNumKNtWpx>G`i40_d+GKeaGCw^^^K7AolKfkWJ4r#d zE$x4TZK4aa9SGhEgp+8`xiR=n}FyS$i$_Ppqx6aL|Hsw|1u6&T0t zr9PXn9Yo-fL2xZ7DWB`~U8MJzb%pOo@7HVhi-Em-v`fDpYeo3S;;eryO_Shfgs&ui z+*L#8naNIgFW?6J24H*CUV6f0diyYY#}xSfLi3LCP&@J;`q=nid`6=^1%`p!;C~tX ztj$LRYzJ9rw`am>fjHU)Y{kVA`a$4V@v+G&P6YfE=v`TI)UekyBicP;aSZ+q)jN-T z4ESAaFPY5sgaSiI5OQ+K`BkrXfT{ zA|XC@Yy`0o3yGB#OKFfa;v*Inl?qKOu@I!JSP1bE@sSA8R*95)erGzjPG{cSnenFc z-oi=#@1A?^`J6j*=gxg4B?(YAo81GtzyQca?-90xh6KVT=YN8P%D`0+m4;9}l3WIP zdLo%aQ8QP1Qbb}ik;$h968VDtRM*D~+7qDH?dztN&QVb53a@7}nGISYb)MvBsjDh% zy)6mG4=ermHr+U5rE!!!x-&ifH=e$?`$`GCwrVI(ma8-#+yHW~7LsH|+aFer?-{^o zEk-xP3{x8K=YLt5VvCjQ7J7_9pUo)6vAbchd@~>h%tAHIQcx!S0?`0*yP1K(0>v+q zu*^oOph(j3rD08s#Ft_5QQ-1E2T2L=zaR7gSpml<;ulA)z)))kObhQCVnSi4$Whl&8sxx3XacSdEKe@Sh7{%FP>F?tj~nH)dSc8igRwf{T=IM(-R(ES@l9+snZJf8xrj?)_aUqFIa`nU2mq6_pMp0!EuT&G`o=mR)Qz&KqG&07EJ-}wz)IzRV=1kC~oeKeo+;`n`|}c z25n$vlz)oSyoL12qE{RzPZFL1a}AhH<0fPs^!IXmy>XOs{G>Spva*qEU- zWp@_75xiBh;}o$^^&K|V0(5YanFMx$9bf`udVdC_P&u1g1Rf~6ljzP@{gQkh;*l*h z4!~DsXg4T#xZxk?MMe?wExr!XJunxD&KXb#!U<#B_du)<8XXP4 z&A>(rJo<}J{-q37=BZ^b@2T?H9Mu+^3>Z|lRbm@91CLaI#Td)g=>)l^SgDR;UvZ@# ziUj)#nmKAzd_^LBNbbETPj?Nb(#ok}Fn?hnYxQ%n%#(IX6nxB9em)0B_K#p!4t^;6 znWANVh^hKJI@`e~QO<+vU0Z$T88-XgaNTFIej)H+viY1xy~54?V3=du~Hy`C7xuC*?eN5 zTMOPPo6x_VZ2l4%BN_dMm)vfH^*c?_R|06 zkx5tfLQSbAY70g(vP7Q;Q5J>Q=&iE(E7%x`$+kdNxX0ipF!USdE;s=6LGq|v{{U&j VKqa$lPQd^G002ovPDHLkV1iQb9Ebn_ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_disable.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_disable.png new file mode 100644 index 0000000000000000000000000000000000000000..eac4873c4b6efc452db53fdf83838a7b4c2269ea GIT binary patch literal 1204 zcmV;l1WWsgP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG9!W$&RA>e5nNLVmQ542!7XG1> z5_4goU}2D(Kqx^BS1E2Ja??^F+6o1dwhHNwZ3PXNE(}`fs#=J(lUfNu5JV`Xiz1DR zEGqk*@m)D{dH20{XXa_p9Qe5J-ur#uIp@urnKy4TnR1lR!2f*)vZZW)XJ@Aczcb)C zXbeV%%sSWz#+7U~`%V`BiJ<6qa0{$}q#<0#X#BtHk9fnq~E&h1+xBx?bWBC7tw z-UlFO`EdX_mNnUPg?P#(m|l>e2W*B^@R_xT;4(PkszCMvj&Ma|hj{n6^hK>>JPdwW z8KsDu;E=DmXacR>h~yad^^4?VI05XKVc}S$Fu|sH0P(V8B7r=fg6p8=EZ1>q%vE|k zuYjLcu0cidKg6sP{IE=A`URZ#cZ^nuC)ffeBzI@D%CU>E7Hk+NM*9;attR@&^;_kY z8fqP7x|b1+D-$`q25wtxX*F@($}{e+G-L;HBlxCFo){Wy`_;r#m0xO+Ta#n~d0L6( z<&^uIy_-!`!^M88 zP2ev#iaL7piVd5GdnFpge>n|2dxs-7vGJMgsD}h&)Ra3t+ImB*@+~6d~Y~WLpCh%#nYU*~ThS+M6 z^S*(dLdOPPMK^(md?V{wTYO0A$4O!ohk4BOcZWhx7 z+ELZOR%}Yh3resYD@aJdv!GW3-Lk4@J~kcXAtjJ6j^wwoG46PIH6giy{$d@9Ns)UW z$h%(O#*V~_JP1Bbz#Rc5q^4w_iVzo#it!UT>QQ4X6~EY5LUIPV8FH~0YitP6y8@9J z(s&9H*#wF0M>$=lzCH;!L{6VWRFT|D(K zL6dUM-^o(oR1M_J>-fmzf<-NODqcW5b-ZL!U9hPZVpI>7fF1KJoYq{QW6=Wfuw#jZ zdLOS?E`}B00kA{fWOA8Z0*B*_gcEQ@qdz2==0cuHxqmiV39{Bac8d8`NcTWp2zi^e z=in_cf9eU%{ONa+W4WIXyEHagzri1XGmPm5P1J$=;5#Tb#6!HoPDtvFG?Dl&cny3* zG@^C?NKa6{_a)@=q>xkWT?FzgPA(Y(4s-t#uLt7_<2;wj8`&sF`3xNJ8Tbo$FcxG& Sj3_(+0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0LPY14zWeSQuPLPzi^XPAj)M_!2y~UP$vEzL z-Ueg-LLq0 zei%|!zoN{62`~nRz&=}qc{5l8R;F!?vkrrNyW5tjtS>W;f?Y0T#1+5-*a0HfT=IM| zBuO)mB-_Y4^fSJ|6cciL!9a?XYAA`pE3=5Ly&CZkH44j`u_AX>OCBx2I}JX7bD{h= ze@W%!GQw zK;^A36sxQim1UnZ!vw_=5U?@`m-!JbC5I$ zRAdKs+Vr9dkiQ??S3<^h;Qq)UcnYY@MHNc2Lm*fBD%esoMp>69lX8825@rm+gwN?X zA-@m2G(4)_a-ksj0=NTun)rAORK{EgYz&Fl!7n8+;|uhfg=}+0C#J{bEQw*o7>0rg zadYxcn_R1YVN!_8RUdKvCUI3xe_15zfq8|K<60fWrQ_&Flh|c+7j-2hXohCe+#Fkm zV_kl-x)(LM9+1<4?(*~KZKi;eN{&3#XF;ztGzC=Be6vb1lG{ON#gIjTXh6GR%)BvX z>7|rQ6S+J(GBrk1xjbBxnxgJ`@DTL*Vln)WqT*IWYHu?xvAil!dy)IDlM-&&m|Gr1l>usWBm}wnzHX|OiLm=dhDMK zLQKq?zu}e7@R!2aE&@)dtG@AnS3b+8t!FdCFa9 z-%yzPWU`u3xo*YqC-<8G0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~r%6OXR9Fekm_0}wK@`Vbm4JmH zXaW&W#SfAcA*G%{u+hTCLJP4lAc&q4x% z${pzC_hcsbcD=oijXURqKl5hhef)QJW_D)1sxl>;%~s>m1BO5=Xf`;Zob)^|MH#<9 z~PQXov;X(kvw0Uto0ZvQWxU+}hYH$d&%xasGbt1^qebSMPzCk$*9+VOcyLPY)u7SwgQv7^2I0>0m z@m8{rKH@Vhqk`{KkSxO`XNqHRWWLkZkh5^8kyz%87Fks_aZn)cEcgY+^2Vn_R+FB< zGBRqz9 zx8EXUM#;$`9|8}-Dae4=dCAyD44hnp$kPZ~Y~Iikqqr`LO`%DPbr@2?k)k5373orogknbB0#E(4LSE^OU`G%jMwCf9d@N$$=6Og+`Vv00000NkvXX Hu0mjf8v9#! literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_timer.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_timer.png new file mode 100644 index 0000000000000000000000000000000000000000..084570304462873ac43f75a780ef0a63d62cde41 GIT binary patch literal 489 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEZEbeP*X%!WK|@4Ku@(pO#C&M-~ShRO9+b;)B{Ex88Kh3}@$h_L?5B)Xw2Eu5tD`~9TjVgVwq;{RP+g-iB7T7RKGLGQ%pKZ|FrU+-bZ zbY4OAkmS{KJUf|}tz6R=pJa8?Nq2Jg-pnlwIya{+`{Z|EHs`19+)mY+F8iX zmat-S#!1Dq8+Cp9cr{b?6gMO5*d;T#ov|Ii>7-zH#6wIEk KelF{r5}E*J!@qF= literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute.png index 7fb830bc7451802c463905cd3e28130f53054f18..d959f1e2480540b5ba4a91a0eed086685aaef67c 100644 GIT binary patch delta 1490 zcmV;@1ugo62;&QoBYyw^b5ch_0Itp)=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg z3;+NHO-V#SRA>e5nM;UPWf;e2x?5nTCP*YoO%_y8(U8?9n}12jYSYDrqM`(eXe6St zMbU*8hRsF_S`L>o&@N>iub|KmLJKks)rm-&WT%maVl z=YBcwnfH9>*wZsbQ&(W>3goW9`1tr8U4H53^8%P2@s(EvgMU)D6Mnji+kw-|X;F;2b%Gv} z9bp>yB$Uaj3o@AIDJ>IRY6$$+CWYTXJ}xbUu4#bq!L|q}PFLUQFv804tGp6iI0Qbc ztfEe`<69L%-*$lT$LBoo0Z8ew@Tt6#spAmXb${OnmWyv!09)Yz5sU8%;JcyYcUjm= ztpwwl9oYsVqVBqT@a0kWEUg8v1A^lX{iu@(+G@?HYJgP>=!gcBNqWR(WUYTiPe zu71$lZ3nR5 z8iKf%1E3!Q{{Yd8;H0G99CQa{%xI0Ivfm=CB*S=^Rgk@ToKe{_O@>fGzzA@|@ShJ_wx7O&j!|&SSm3y+=Jk zD;}SH=$C*m%zg>HuAt{Lb2CexpU~?5|IVxrlVg_2s^LBLrvsR8dA8yZNFeOHgKwp&_VE3wn}z7g77VPhi(4S4V`$Z>np>0aE1A8fgd2x9@FJm;?|+iQ(C0H z`tbj`A^ATz4#$WkS6!9IJx39bf8kDe4*XXpy^Od$$K%)w9tD3VK}F)KT%rPjWE$eL zBkJBz*Pk#&lCR*j} zijHRP2L9Sc78qIlb}FV%0ZKr-nW)j>CUG#8ciSy#BB^0sk+jgUB<|=0nETYKZk= zpY)Xm)__j*N>LL8r$dYt#Y=S6P6PTZ(&~x6PR*4mmJRVf>rSvdjcNNNP95vY6g{6< s9jSUv+zvMKB;CL|MN?Pc|8NEV1z2`nq9(C1HUIzs07*qoM6N<$f>%Yo$N&HU delta 1006 zcmVH`rK3r)mEgNOwc@n~7lMnC!2Oibp^x#w}u zxp&hq`6un1b7tmuzM22bnTttHDh83%(M0kw$!jEQjq+S#9e>GglAribKS|ypSs%5| z45%0S04b8^t>*ek)p>DsDyGK`kZXlu zoHz#HkbnByPRpU?wU9-HXtN-^oDdgIDo1h`$(P2&YL7CpB5VLlNzO=WE0L=cTLAR> zI3X!|B-h500DuRCUv`S5qyW4iVqdXcX*5o0h;F0KSe?)S<3?F*Ia)~|wg${jp``%^ zjR$2_PA33ir&w{KQ*9(8Yhvh-+y&r_QArnoi+?_wxgh`#LpEFu;5C3sqpV+T0EdEB zl1f=4o@9;VFv?G3B-e+`;U(55rPk9hCx97J7nZ7>Xc$RnHs|n7Z0}-gashxk$JtBr z9?8$@EYpq=t6@29-Wd^KIEoY50CdPfZ-qMBu|t;sqsAev*8T_p^0Kanbs`9WUkKm< z$A2(59ulBMy%75ZFsl=B0O*jRGio({j^wm}0Q!r}>&wpRM4SK;%_Kiqjdyr_mS#KH zN(Xf!ZUBjuB;Qz#_c|K)JDGEB#WS2p0zhJ!`YpiJfJ)Cn0RlOZ6oAAc^~OvMl3dIG zlRwB099~Y;CJi7_P4ceQxODm;$t4y*YiE{vTo8}sR6J<_iRmOSGgH5e^+Oi16+ZR2 zAU5U$K%$)F3AJZ(Nfxm30QIERuRQ|amoEp*XjCVE?-YdmN_my!!VqPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NH@kvBMRA>e5nO%rgRTRhXO=nU| zg`u#58lB9iEEjVV!->x%ZqibEUuqfA-qzMCOV?AFkcBi_dykPajcAqQJBvH z`vN{KVxEsn=>&9vFN4IL%ulyq^o2kR%9CR_z5;4scLeFO$(JYMT6x* zF^LgJC)gV#Z1q9-Hh{l^7)^D`w*p-f9X`kF@HCFeoR=6-Owl)hPfD6MoY;~aPJNx+^CPZ`M z?*(2GFT0$y__6hc%hY3TN?roKYrx?s{ujoxeJu0)BcHY=XL?^Vo!BWrwN2DhV%w3K zPtan^h{iRUff(^$4~_=$OMN`P0q567udtA}#^p*~942SIfNpX@+Ce_&=CKNy;s!wY zRt%5Qc=q(FtsYE#Zw*_k1q`r_Jz?24()_LHFM`I4hH=b%6FEk;b&yQ@OtCSs02;dl zhkwrRu|OM%=|O)6*tf(x=+BzJ#W>VTo(9MB zVw^oZNZat;4qkCF57OjpHxE_ci|;YD09&O9{M{cCmYI9bw^{UhuoLLT^i)KoC)u(l zq`nu=ms-FvM-o0BovW03j*H&ybgBLk-5dD))c4|hOf4YyRC%_Ny1#^mg4|!-e5TVw z)n7Kg$CI*vu$e0JN(-3Djg`3Gs#GS&-{`-U<%oLlXQ$~II6wja=Do3O!HoFNob7j~ z7gc=^>P-px=lF!KE4gE!a)eQ%@L^IVW(JWijeiJ~uP4jYidsYBMxsSK)Gm>n!+hQvJv^ zo_&4c+6q)HpqeJ?rP$H8N+fKy>}cF%zIKn)+Z5E^T)HL%U0^sMT3wo`WCHb82Q}40 zS4oZ4xC*TGbR!J2{#KjPcYV}tl%u9lB5zxORq3HRqABH>gazndfqa5Xi zq8f|BoVZOD2FnANZ1%`n>LTuxu-J~{#%GZa>axepg@)3rc*)Ax* zJ;EaNhr>GXJ(wsFmpH@Ul-jchu~JNbI@|}o0aZo0;_zQw?Q1%ZnFe~n1K>lTtw)~7 zrx?XH`-IFZm9m$*2U6J?1{xEmez4LtZ(mZn7j#b?;`%Q98w~NM&M2zw0 RK#c$Z002ovPDHLkV1iPx2i^bx literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_8h.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_8h.png new file mode 100644 index 0000000000000000000000000000000000000000..34131e40820b237b45954e5a1412968d73d2b014 GIT binary patch literal 1856 zcmV-G2fz4Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NIs!2paRA>e5m|Lh8RTRfPc}WeG zER&)-CS^Tjk`I-Zq;$auyVy&R3grXD!ico`UNJFbK!f+_TZ6@$MDPAdxQk!K|Ed~C0S%bm|2Cuc-r zMxwkFoCD4d9M-K3> z!871{P?qGY7{zvvat=Wk=h}_#D({yo<9HGH6?poPfv#vmj3LV2_oLkmy?s{p;EL-rAuVP|S?%7ey(#UBe<38S}CZl{R za(tU{ZGFNuIo*kvzC$quoRUd+425Dsta8MpTD_D4-W|LVIZVl<$H8CyEsXnx1ZsXw zlwd#Ohd{ElG6_p6lq2L)PEV?7ljw_V%l0txwVCuN$Ace$Zqa$>fV>iT`kBEsX74Pn zoItrft+f0o`+@1;I@2AKOenjAY~)Eiq*tRh-tumtpYFd3_JmqajYY(PYl-eJ6Z8 zV$2G@hemwWV?wEohSncf4>Mkqc&3FGh8G9bC1xVIHra(XhJWj16ICHJrhzF~_<>vn&RgZ4u0H0$jC3_p+M@;J~#LQksCg5Oa1h#-6Bd+|Lc>&l$> zngI6&ox1j9cofCcK$AEGUIO#M$3Ube-sh_MJ!MDlc5Ex;Bw`W=V5@6`BR?aZY@+YQ z_n4W0U-$ZFAwx7Z2<2R7(B_*A9z%B}SQl)k!=DJUSaP@V-R1NW|8V00PBzi^;(I)r zGMeP3 zDmYn}8icjEUUHz@OfZhm4&=9N44(VfAH;ZDaQ@BfC8NJP*u-X-9eEJ&A2!Wq%jE=!G=R=aGy~`%T{q`YY#5vm-ACM(Sy( z*$O$1t1Jrs5Ae&PFt)Rdsu^m-YP70!ZrpVj{H@cKIllkuOINSmkp}9irjdFnclE6f z0ShfU@cCxzYEHfRQSF75Ymz{pjjd6lNtF{-44~emsHS=tSTW5JcLMcq!yaIC0O9@) zB`Xo6+(0#qRC{=d(0msXOaMBods@yQbL`E}QfyH!pq!pmb3$=sNh^t(fWI;-^f|b> zWQtrjxSivI;=6{Jg#Njk27UycMard|{`A^4 z6R@ll(|^*Bw~N&4?zfqwxt9_@O{`~TGd0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGu}MThRA>e5m|KVyM-YZR#%sKR zM)o1HYNDs4L9#kXp08aq&P)qLa+CNAqxB}b(T4XZwLFykP<9)y{;D4ZH zhc1GFul1lq{|8%t9pj}FBoC|oCvy;6FE4_~3IA&FH_)=&aA2&_0}1*>~L*Vys~9x`zK|Jg!qI?bj;XGZQ+znLEnWROXZBklR)--*|&`> zjyaWJfb^&#ru{R7s*|U46@L0*l~ZPcka#kNq%*wu%Gv!qSjIX2sTh<9-;}67LfNxX zDQ=FsLUJc!I{-F&dsQI?>RP)hM&~JySLpg;+3p2>U&jg+^@uCzI$ipl;f1EF;xg)e zqtMF5>8JXss_z8!Qj=G@m@ui87zcvSEF7Y5q!DF{>8RGeAUdCNi>uy_@zA)1N!-y^ zmO>5vnaWm+Prd4wtoq)8;6xPvDM8y*;694qr23htZ)E}$FYA0S=p9wrK>J;!XWG1# z2~goWVBWlB-PdsSpJiHkM3(skqIJJS6)WpL_@!ROr>dDwpj_)-&nUB9h~kAyulvXJ z*JB^45+*AFMRo@AihcPYTGzQJO7r(yXlqgD=PySmbv0d3*s^s&UXsb(zghL^F z^R|Tk!j%!5eZFzI$t&kn$ACQOS~in6c3ja8UOFV*z$Kui<(s670H+^-oQdqWDASiC z`4_N@};F_J=HGvD3 z(-^DY7F{_A%8526u0OH^cZSa9+kbW~6*)h~vSh^m6&MQ&z8tqimG4LX z-49Uw0HJ6f8$^`SR@As(mQl`@9oZ;5A00$X1|2cC`Qi002ov JPDHLkV1l(lXW#$; literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_silent.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_silent.png new file mode 100644 index 0000000000000000000000000000000000000000..fa98016523c984178a0fcd83cc7efc3c89e53ab5 GIT binary patch literal 1121 zcmV-n1fKheP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NF%Sl8*RA>e5nN3JkQ544=6*CF5 zHjxyB5Y)~fszo98fl@@cNDzx^Q4vHi3pagiLd)7#E2Bjaw22@hgqAL%6e<^j6u5{K z`XZ(%Lu~q;;k}vj?z=P2)O#}*ngf6C`MUT1&zs-P`XWG_~!it z+M{N?A~r;NfL>YAdu(LzyHx;$x`C{=FY+t&+sKQLm^%ePrURI#%gKD?<0znhiOE`s zugjCO5&vDVT*Z?-Wk-}<8I@H%4&H#@pjf$B3|j_^cMCDWNU@An-f%JGB`4Mb7+g-1 zQsh0!B^`z2TYmxkt)L4uEVUTqY!yhJ`8RM{b)G{%1E!Tvt10&TtakjZ4w+W^%1w18 zc!Ax;*k5hq5gWvRL1O490y#K70$8;+?cppP-yEPiK z(|jM0y(Zh?0EF6U<;Yr}hl9Km_j$1uw4?Otr2nft`R=(Pd=+T-khX13+)Ow73g5|FwBw9H^wKgZyAs{mPPNY#S-K+8178uORH=UxF`5%rLJ zq$@z51aeAc1zUfHJdzE#pg?XJklUgb`N|+)8|0U2*8%h$F7OU;fK(G0Gl&XTn nU-=&Jw0=fgmFfz(umXPogwYyr@p07R00000NkvXXu0mjf_jl?9 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_add.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_add.png new file mode 100644 index 0000000000000000000000000000000000000000..9b480b16732658aa33d3e29b84d6dbf0eae92eab GIT binary patch literal 1275 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGWl2OqRA>e5nOlgBQ547Lxa59m z+>*6DhfsHfk*gzIRFB6%0U?2jOWX(o#r z^xR}0vUy{{~ClV&03gRTN6Td`1V0^T5Eddwt*+-kd5NrW( z@-w*<}m4QLenSAw6w$^jmZ7=v`#tjK3&@=QaR1SzP1pon?I`DC+0e`TJnF0;7v zLQ+a+CQ!iz1VxM|)(a3P;*3j|WdxgGMJXUCqJnsLK$xhnA|jpiT?8yz0YMR6h;i%!S`&9Q(ApQI#~!I;QuTKexTtTyKT5o{u)Q=sev>mw1r&RVS(>9k zbpU-7MM_J21Ix&GKmh5HQpjmEGH_fcGpwwe-;F)0fD?vy6Ww>YRi7t)y@CD6xfNGH zqnW^YAr9L?`y9t7JU;?%t5bK+W)! zVSPj22+9dO5a{bOIE~7Qc$w$Exm;}J;B*dmMlR3yj8A`{ODwwu zyHFoc)`Jc{-!NOFJsIaC5a$}QE^PHz^fu5s9}X6P?!d`Kl*v)sqa(VOak`<82bv)5 zcGci2F{I}&1nvR!<4GzycP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG{YgYYRA>e5m|ut$RUF5?ve~L> zW$K#9`kqMFZSEGpkD?2HMDj4MhpeyLhB^vg@o1nWnKFi?P z-P;7hNj^j1f56ITR2stm26Wwtw_qVm$THbtHu&EA1j0#bY4ul+y|fK0Hj#4Ms+K^Q zL<c>WG&~k2F%tb4SkXRbN}eRJuW16B?03)< zCZUa;w#!z2qcS~f64=%}0Zq0Sg6#vP?u<5URxVSSktGT2?n?riZ1e?%uD#LcYBZuR zyqTqvz$SA7!EUltz;gNvg+f1mE8tV(KL%ZI?AfNRBDHD>XjUXKK(PvTs2+;m)JI5S zu4|~ItZD+97)cDm8q}?3qS`a{ki-JhR+d`z1l+7hVjcP>SEn2f`$=MnY0ItFECJ1o zBswWJnpx^Q;!BcPZrW<6GO(6QE72;HHVYg&tP}bjSm}JwXTfa<#I@%x@zz%1W!MGU zW&QwqcDI6#T{0(tZ2_W}8G1VmfD`HMZj$J2a7&%8Emw)(^Ke!HQbhZID@E@B2D%V> zvFV(t%}oS-CFtr~=`j5-(Q(t&GnY86vk`OXNeSqX%gOh4A~Y_8=y3^+^j`^tdaKhj zl{mZ*2C;><#vg%B+IEAs1;r#Of%V4tqCXM(bmZut0(SX!nd$^OV+PZec?Dvt74?VU z1Mnp&ffb(NQ~qS=*CE$+&+dKSF13#HR4>5mX%5)xDA7t%0%I`>{*a-uHhz=**tE?B z{}gaLZP6*9?-Q$I*a}uA#tgg)hFYPl6iq;G7-{9QqO1KO=#TuI3ynS-u7Z_MsKlNE zXCEsu@}K`{F$1rH{c3QcWia?U^UQ)OeIvkMwVbcY=$S{K3EH_@`GQJt3Ro<@8)O1T zc3HEVu$Uiq`f$(AS(5&F?{Hb5}`c3;3(S4chcl(_8o) z*tddyk|}*tK;P9?UQ4nM+Od2Q{6CTnV0E3&O->D1VJGpMq0bDO zx;nZfnsC?&?iL&WK>e5BPAKcj=go<6G#|Zty6u=H*H?_S66tlWaui&Fv(Ur#_%F)3 h)UQDO3f#vl@E=xdS9<&kZ<7E3002ovPDHLkV1h-Ejz9na literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_on.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_on.png new file mode 100644 index 0000000000000000000000000000000000000000..97be3b6d59e38604075af94dcdddd96e7fe4ecb6 GIT binary patch literal 1064 zcmV+@1lRkCP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFl1W5CRA>e5nN3JkQ544=ze+0# ztdxjqAr(YKU%NgOgK(8D3c?ma5VVa9rENh3(W0UVYSX?pR!D(`8WEYah(1<{R8|H> zQkdBEJLA0JygT0e-Z1mViQa*q_uPB`_ug|q-h1<&Wo5C&EAW4>K%&&9pG+p}iKzlU zCK8Ecsm14uhhSGhJDh=D7zfYZ;_UM^m?cxR9Uz#MjK3|-R#IUZxNMrrR(9gPO%%xl z2zCVnO0W{77xZ#l5CP>6nLx8mQ;-P|a18@=fNZ%0+yJ@Q2;yfjlumb(o&vEcCQv=& zX8*0sF3PQh;Ol773$of_Y!s0fY${*^9M=u$bBW4VDL>22djj-$8f?M8r_KvDl@jdd ztSIs*D8vNX)%Y*)Z-W=?n5rv1m#wY>ZEb~!k`DLlPF;PLyDCG}nKyx=KX~$;K!`a; zD~Tr%?fM4y9`8W#8bzy!cOcsJ4emYOf#5ZYRuS(&wCfw(`#-+}h4?ugyiBtw__bL} z@eWu6@<#Uwp76f#jx@9teFEvgyNU1w%r_&Y{t;z8W_cue2CD{b&d(qSn_yHou=vxu z+!cJ$c7T93rB`-=5zr+036OVd&q80DP9cMq!$G(SPvJET!bRBSjTSP!hE4}Bub!Kw zjB~$~RK5{)!Z*m@2yiD1gUfCim9ripG+PYaWm|;kw!@^>+qBkl8Xwmk%cVI4s;m8jjo8$_AC8>OY5tnQKM=o?n$4($WY&7=xr0I zL-$*0~Mt8x`{v>}14nrGs!AsCK zMn->Tv~@pIj<`j)#$V@ZLH$vs|AVj3y00m9wJ@OcLGCXE&Av{8GBjua{S>@vYlE%^ zhQKqq(4B@*uAOt>yG?o>sPr+u?R%?p47r8fQyqzW1>`}KG4dOr5443ot29~**I@)? z=fo!90m!j5zxZXw4s>X|9^`y#lkJp;+8uZUdY8zip3qr8%mN2PK-)^tPv|hs+!{LE z3*RA($^WueyL+62T7s&F8{lm*uFqu4yJ6lOgqImI@T?J_+=*I2Quzt+6^7w%q5oMy ipRvU&5U)UvEASV+G)?GAfqI(&0000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg z3;+NGvq?ljRA>e5nOlfeWfaHfIEt6Nn*`>F2&rk1VW^~Gntu;Q#o&uzCaI{TM5H|h z`JfLf>O+zCP}G}Xkw`%>SoqLIL0@bhq(M5RPvvjaS0^Xod2XeH3z zHc|mgV^Vbgngipiq=B*U$DH1?7Z4W2I5m|?unhQ>6@R}hEeZOv2FwrJd~g8Rc7iRD z7Gs_H)pR8AQlJDzx(X|^l3>ehz~5tAl_ZpR|<}Qj}6#-e7699 zHN?MS_8v!^M}wy_plx#lczUO&pg8xs0mZ^!w^qMB|3V&DF%J%_!5MHD^p@VQ7&I{w ztf~eyjej|7LJ^;2=ECvQ;M^N=S7yLqAXsJt*rtKU!<3SU{wrXl-`V6cKa|=Q)zI%a zmu`h+!7>#1r#66I&jJ;u8^WeI9bHReV<^$~=%Y*3mKZf$1g&6t1}2mR=!Jq@l9L6u5!*9{92J{#=daKN#1`2{_HLw_)|9`Qnjuk#7@~cuhY8l`i;2(AJ701_| z_9U<=#k=7nC|m_h4*k* zy6I|r7T!M>PQ)v4%Q-jtbl}5K{1N0Gt{$=e$*c!nM{L0Fw>Maop&>v$#a~_U&){2G z{kx{4mJ#s2frHqKaSOHKG$)z#BI6|{#(%p&Vs6s@JPCFa=%Ok6Iub+2F~^zT39r?U zv<<~5r&N>Oi2y^uX;2OQjdR!0N%x55627S~bLF1*G|X85{EMCzI-PKw0KNs)kUlNv zrbq0q#jmOc@Yn0S7RgBSpRlNL3+Y`%+dstWNw5=m`UBy~N)fU5cm?no0d@m_B7s=kUnzE>K&}D z-VPFUOIk1Ks!%*2=>bV!OKO$W65h2Z?d=_B^jZc*60k{ckaTG%+b-#DNk98@I$oTt zk-S6FS1wzs9)Gz2o9_jFP3-+c-wUx`2XHXdxyQ@flk$_mX5hxNv59RG2a?IZQR0Lt zMW7YpQA z7T36UN)c!QR(a5u*XP>M<{zLZBak^3bNfBPHGClHbx9}6xDN{tzO35Wl!tlbMnM|K7W3O7bM*$X@;aJl5Ufpj*s!aU>7}tf-$Ym_e_Wv@(p>>!y-nP|_aP zCrer!3Dgt;HV|g(--hmQ4*EVxyTkL9YS4Y49)FlA^@aA=OX_g_s2>~|Mww7E;m0tS z%X~j%I1=>f%}Ss(=%*@~cQX>`4*H;*PKJ0Y9aIw%Fnhl%Je#u`cHK;Ac6j&ShR!=i z#}jspE)3&u4f>pH<2w2yfz#o|cpa(BC9Mk2pGn#ro)<`(>-urOZ;uez87i7rKELtv z9e;(k#EA|0bF}{@K_AFWC=2F{=~CCtLA)txU4>xI9Lu(X2-wLp%k=}ELyCc-na;BC z{QfAP09*)sUSl|YqQ<*GxnOP*u*QSRt8?1D9NLUz^dbS11s;jk0-MZ|0xvXqa(fb~ z_LaL*&h&eyo?~ij3Lr2GcnbJ4>3e;eZ>ontCT2RvlYw3ZrjCJt-GyKC zL_vymZV@V)fXPx|Z!+LJC9b8V2(*>Rh*%2e2|uOI7`rF}Cf6kS8^c!5c2q;4J%2eI zY~t@$`Tt{Zyetfm_WUd^e>}KfFrdZGFt!u002ovPDHLkV1n)@ BIgkJV diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_videocall.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_videocall.png index c79c49e3a40d03a149770cc9cb233501fa6d462b..53877643c59ae7cc67287351adb93d873f4a8be1 100644 GIT binary patch delta 886 zcmV-+1Bv{v28{=hB!2;OQb$4nuFf3k0000)WmrjOO-%qQ0000800D<-00aO400961 z02%-Q00003paB2_0000100961paK8{000010000mpaTE|000010000m00000+c#_s z0008_NklTK zp^%*gVIgHKj5K!gN+Qfg9*yKtGt69{-|hbOJ?EZ#oIB1rchvt^-~PYX|M&Xeb35l> zD0uP{@DuP8@DuP8@Dmtk6DXBR&0sg^1s}jDNP~t6@&;T28#8H}z$?H@kOy5R$<(+; zuy=qhU=5fM=YLzk!HWM1@}&DDYY7*It`qcy3K>M+slG)gU}%Pa1{OFS>tk>QJO?A- zU#XP?L(YyUQm zjs%Pu2_$>!60!~mZ|o1ST~j09F++tenypD3W(se=`8-JTv`fN|@SFIZ+w-UNNrcJ9 zPZY(U2O3=(53Gc)$xe%~yg=7Y@vkCmRVqD!Dq{|cj!=$!$m^08Z+rCwLa}le2g%q) z@k8}wZh!O%XszGtE#5Ydrv|i{#Jq1H@u)I#^e2$fU=xS+Cy;nl89DkBNO7=Z8s?Zb zrC79vYU4FI_>QmE8hoQ0u-9fs_BMQiCeDEPk9W6&wb2bky)y5iuIn@rdt2dp&<4Ia zC2O1TS+bf(-$J`ddY2~Vg_7&ZjG9dwcrDHwgn!S3r8v8lSS7*F!fOp?>&I`o`BYA1 zwec0wueq|rah#O4I?pUt5?#<_@OBS08$1Z4F(20L zItAv$SMqmj?376`ix5kJ-5I6v91IiZ9eBtjjrZgy;3wcG@SjiMHxfK(w0VHh1ONa4 M07*qoM6N<$f-t;=0{{R3 delta 792 zcmV+z1LypW2d@T@B!2{FK}|sb0I`n?{9y$E00QPoL_t(&1?`wgXca*ahG$;H4WmXB zF(`Ntam7FsaXBj9JctT{2Nw{@&7dyfeRB58O3%a9v@(A1Ft4n&{$XG;0DmLLAJ-R9K6&H^ta$T7*qCP^vRYIljq8L$vWz!kV~%k z2bEJAwkc*4_f0TIXfW;)gOW9t9>x*n*k>JeRLFN#<$QwvP0d9e08$x@ruO}l`b9aHp-)ruv*x&;`h0labX%sn-ZOIg`?P z`k42teACh8m$J*)(A$k3jqmInrvw}MjIz!;3s%@W1jkLXXxt-d&`-wfGQ9})f?G0) zL{2DL?a3UIwX7ck<}XeDj_!chph%J1W))bfHh+~9w@yB%N5lq~{S3Xpa1nD{`iVbS zVPs)9Xtc;lTW19kCfK%tk2T2L$38Q@W_*t0FpyiQ5%P#6RpbpZeDgsccmbr)d*B4H zCn)w7GK*v+U?Ib9An)ZFph%Io-Fq+y2Fz`flmJeIX8&VL+SmJi2Yd&72mbR8`~qKW W3K88vUAmJ10000V46Z=aKp zddv4#@2%hQ;Lm?{{-`?ndsgwW-1n!iJ=|U_bY*7A7srlUg7WKL0&C%#H zdfV#KdS`ExvENzuWpaDzoYI?upJPu%>c-S;|M9f4J9A_4@k!Qx=XRDco>RYHQ15*H z-@F-rgTMdRy}Q5u)`|UFxebcu{@=ca;o&Up2BsF)LoZ7Qh&o`eec<$=?{9D37d9^G zUHZHIoLxlpZe}^YybJ#ytaX}ibtu}Wd#?4gJB4}YzJ9xUUAksXvhBOWKA{bhX9e4b v7uQx?`Y`#_!(!9JE@7NR!~=)G57kEh>j{4G%VbzGK?%Xr)z4*}Q$iB}Q%3tE literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pip_play_large.png b/TMessagesProj/src/main/res/drawable-xhdpi/pip_play_large.png new file mode 100644 index 0000000000000000000000000000000000000000..37b561d451f0154f52a71fdd2520067a454edfab GIT binary patch literal 900 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(;}uz(rC1}R)=9Ph`#!1T`3#WAFU z@$H&1-1Z9QH%tf${OHkWvhot6tPrcMDyQ$QJqLuMc8RsGH?Ey+Q{<`4gvBpM`S;jIJ3Pw?QEgYzU*b2>cJyZ1ztML$@6#;&&qJTjHZUb^21YDdNxTfQ(JJ4 z_nC3hh19TLZ=Tg{`eMoae0RW~0<+n7**{fr`fp{D#P@TQzPo@wqll$tKy878j)W)BzC+KG$^?0 zA9*0*dX@C9y>?5_H#n~UYF1KR%f;jt{xw+0;MA(^tRnH|`@1wY%#eT1_er(7a6ztr z1jD|cf$M%oOxbM!f;MMK} zy?5Q2>?~CRzHSr<{;cv~?XmFQ`BKmFwf#+g+&&eu;SE2bga%28ixoeJ`@K27X71kH QW1t-1>FVdQ&MBb@04l>~4*&oF literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pip_replay_large.png b/TMessagesProj/src/main/res/drawable-xhdpi/pip_replay_large.png new file mode 100644 index 0000000000000000000000000000000000000000..65207aa6a92e11e6ef71923d6de1825f1f0ec594 GIT binary patch literal 1330 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^v49!D1}U6i==Pq0fn|=Ti(^Oy z)MY~Z%w$dVZ-K$St_$S6jt_kwUoN5C{0wjW+o(-6zJmQ zGT{a%H+Od)i=cd9h_~ohL8nmL{g+E7oqRd>`?I|}-=F=mQ~hW8vpGAz&-?%P{M?=8 z@3JFj8ZU1MKA`zPq=3tUbqlJd9de__<1Zr9h-UN^eylCG0k@=6ev7U ztzb4uqo{DQqriR(KZXCih8>StKCy5K9OqPFN)=F_$Rt{tC0cml1>X$SBuO3LHw-VB z_a+~o7orvVOaHx&vb&rAgxV*EBrou239S9n(|5J8PT;D`8s!DMmV_*F?mob=A@#1w zm8dMGt(R9CDD7Q#M}Q;QTq7jh$m!zDvI)LRE_OB-@g~?>uvR%tC@oC<^d`sD4jOF>~TtK!WQ?~pBGF!wk{cB6Hc75EzT;~8Daq5O9hSr&v_dvsXRS>RDv_xkS5iAftxC>M zNLZ*iE%-#6!!PHL+Rk>*Us|bOYdiErM&(a*?5xFq=EO=fy*#@*-g5JX@I(hw(VxuM z+8nC(E_}b}QA|Mi`&jp9NzM!AuR6U^=X0gvY4xsoI!`usrlR5wsw;I${Q<84^V(W&m|e{J!fy(x3Oe74ie zZ55#>Cdd{U&3q;vJ4B z^4v{14cyNir8AgJep2Is(t48m~}z&im~$_c0tEomw?^V$(O!#Rx3z^^pTsYAHkxJCu%_slALC;7$BI58bu h0HBoz2yUg;2mYO=d+oPRREr0dSDvnZF6*2UngAluK}-Mu literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_invite.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_invite.png new file mode 100644 index 0000000000000000000000000000000000000000..536943329c64efd68dfcccf984d29e9242046660 GIT binary patch literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{t-_X$B+ufx6>Z-HW>)G?KkFoz+utZbAZii zmhuKhtHxc8(kIxSn<|-!W_#ay)nDy7`O>pb@0@lp2QVc*^SZ{RDwud&-_KP@!1M6? zHv%V_KB}zD>$Bk03M(|5_U-Tmj#>JKUys~$OR6=r72GPHulnQ6&lfr3mRIjhn7%cn z&Q$uh?DUKue~XQ~+I{#=9CwvjJmXHZG0TJX`=)IzJ@;)>--pY$9%Ysj!y85}Sb4q9e06BVcdH?_b literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_webview.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_webview.png new file mode 100644 index 0000000000000000000000000000000000000000..e771235b6d6ed7dc4b1dc1d73b99d22e0e4fc9e5 GIT binary patch literal 437 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`nY^cqV@L$& z+i*j^Lk2uK0@814S|;wFvT*(DJK_hJE0~p&a-SEtY5LwW$@5m~O7RYpRkw@Rmz<;{ zEX*pTxnQf_gYXL8{?r!N8Ao+)X=o%Hay*za*+cL*gU6edjX~1| z1#WrQ&#OzBd#&8t`&N0$Th^7y0!0=-w&|F*SN@n6TtpBS`ltAM35(4!u)n7NWZRlUVwV;Blh{^sH5RtaTllE8*wLr&!l8MmPqzpx zpR1w5RmfHFxv0%W(T_3jpZ>XkPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>)=5M`RCodHoLh)hRT#%-yk^lf zgcaqBQVo$2DOPB27G&v65HaLKWDF{0NjJI>1ic6ekuRk^MMxLPA|nF}y3qJwMokgH zK*Av2Z7377(Q^9zXU?`W>wNoi_Fj9RJu~Nnzk9E>*ZP0|^__iLx3Q(AY0U^UBhZXM z<08=7DA&Wo!&C7+4|IUbz{M2|a@^M1+IoWHk01{!01@Fssx-kvK$7 z0c*h#kj2bL48jc&qzAaR3V6Mvrum9G!WP1{8Qf9_=TXY`g8}d-I9WLldr2SUdYH}O z!kge>w5;GIe>|*U;rR&a0Z}hqE|1t@{@nt)!R7S|rOr(7If%12>gCR*JSwLGeU;*D z2L+Y^ecCe{Ja>XmfcrioYs9|J>?A7zGTOneQ9Ysm_Ht!OR$pQD;qCzXLb~>RSe-)h zQFArucU4uTf8qR|Ld4(%UyH$qK>e$ifY%pwUG2cR?wqLLZ05SRmw#R28eN!%>zxz! zSe@nCBaPN*`A3)Tc=eU^aq#jUwEXB+4tpUFa&4(usll1(x)oIS;y)toe+&v~53o$Z z(SWm*hPHPN(NB97i-Uz=$Z({`s+4z55CHU90a9CT3d&?ULZsot9$;B1-#OI{M)VSJ z&Jh1SdD*{qkgPSxm8D_DxG=PC3~9qdnHm78M&;JPQ~jKA^C?H`44^y4wL@fFlsZUM z)|7>1g>?c`i+3v0h{aYz$h+Sunk-30O?FxHIlajk%2$f^ya!x+FqKkRI$fqpI=8V^ zJwnma2A%|6N$XK|4mbt^8{niZY5g(fsAvrWcZ@02pak0P0|$XjU5zV~N>N$x9C!-M zPFinFIV$ScsqTG}9I<6%3KpC|!CbI&RLc2(k8?J?P$@XW-@8`x^e+fu?7zUa;i- z3@-5PHX}rq~ zs5PFl9;E@dqOUYU+u_;?l5{{1QLe|6@3RI^O~1$*?rWEYYg*LH%RYcONpQ|l?g17A zfAb{dcZ26rH!o>`wBqUAxO;AfG}+6srDY?*`NE?JYkN)2u)_+FM-8!53t~%*7TC+- z#e`*(7PDS2XWYtGfULX4dhA@TG-=Df%OgE2xqGa4hFi9tw6z=Lv`b(Kv;tIf>$yZJ z)1OjrIHvA8g0nBCjIYb5Tp}w#)~<-TZbcty8onQ%cOtmnqRiHa>sc;+>r~c9Abzfk z7iXazMf|A`^a`jRQk)^JUhWL15#Ew;Ycb+wZ~|x`zRDu6SwN$pM(lq9SKJl+n#U{> zA9?t_3Lbs#hrkc`I^csh7Y@WWe6X5J!%~o1?;z29WpFJu@+M~%cTlM&%u4qw5TH^{ zx%vte?bEEm9cpK4PAZpn(mr*gs7SjsSs!fO)0|Vfc_k{Adf6vUkZ99&;2%(J+tY9< z(i3svP&@Qp`!ZF4R0$?`)-50}ekCDwD@H3KTpOt@dptEYY!hYk!c5wtNq*O~w4QC^ zAA*Un{bhq2nMykQ>?B0veFN2O+F-2`?8b}iTjc7ye~1V^NhYc+BguuR)f zO24Tyx8MZC1VL-&{Z@o3d9QP{Cd31Z+>ZFY5nP{}gQUcW&|ohrNZRCCSZ5Mnw}J0K zU>ZmI`9dWPidzl=x|6~lw?JqwCrK6sUHU|6xHYzVJ8 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1d.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1d.png new file mode 100644 index 0000000000000000000000000000000000000000..3ce1023fcf76b094cf4d8a1660957578349d614a GIT binary patch literal 2147 zcmV-p2%PtcP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?%}GQ-RCodHoNI_xRTRe^pJ}C1 zR;Cr2WszbfVyRSOk(Q5vK1B4P2ZK(DNiVR1hzf)x$`7LUsVqV*k+dKxG9xX_h>66Q zNVA8jg=ty%N~hm{oHLxe@7m{{*L|pW!GG@AYp>T{=bZgK+NDdK>KUkKpq_#1WuT#2 zuG`w$y5V~$7!J+@XLn#PzbhLW8vf$<^dS<`7t8<)K?^txe6)>d37u-fU<%ucczAdLRtgA?(1|8AgWd{$pReQXa08X;YJ(x+1qKG6&V zt!`AI@>Z@JD-sM&@HGys2AW?z3v%tK6SV{9dUB$YvxNHGI{!q$Ra=;btIzShR!6Cu zUF{ex|HP#yUUMZ44!QJ$mLEOJz7BaWb(2h`Dl>`eIuM@4ze73yH7G`#fJI7<7MwLn z#J1cB`te+Y#ldKB*l?uRswSVDAOXZ@B}i?#CXmVWiyfjwk8Zpjl2)w%-(Rf7^wb^Cu=WK{)q4uO`&kEquy{RI_%5>LKN4ackt5ks| zP$K@p;P+6wc5vM{%0yH@a*v_7mVK7b4SpnxATB{*95@GjfsGcQ0b zivFKQT}c*tJF$N?f_iF>f@Scu50#9RRS=$iQf#LwNi3l;1iTLZYu7&UM?>yB%MSc! zz&=olb|LUFNcVbJ&Xe$PJi~}kLB(3fAlCpM00)3YM_?9gm{HbEIcN!&;Jr)zg-P0% zSr&)Znrmqs!|3({z6C8+om4ObhkJKtP4WvZcSgmDFR6@gCOOeCw9epJtW_{?wJIE5 zAE&JT$t4{gYSa|AfFr;n>AqxD00GdWKDnP=mlguAc`QPIDz} z?#JMZhS8BU@?3*&u_idovnUtM@vH<{uhI_3SY(j~>;eBq3T3Z+4HH)KFO6y1(jDOH zS_#ru7A_^9Ot}_vE^`A8VRDyYc9_AlSo;iS(LfP5K|1lQMY2v><0i=ZyryW`VI`;* z6XA==YGm9#$XaF?ea~v8=B_4!VMI6IAr*xrVA#9&GsC zX7J*&iUt-dLDp9hL*ja;+^c==%bR6NM`bUbR_| z5`cTY)dnwaf>t2A0BD5PM7W8OvGjb8JL6kw6s*267@M$}_e^>+Hr*u+thVK`gNi9w z^aPQ`W9WWo=ub3wpO?TXGYa0^I3eL>m!a%)YvQE{)abusu5 zXd6UZw{t9A_&0!MKn=G@hnVZYBA|~ot$C1Tx|4^_V?c3;WN&0=Ws(aNb3gXM<^>?_ zYnmi{Qx@M>g75(X#kN(Za49B=r{ck(zR-8+lTx|x)?>-tbqkC)dX;Llg2445l|>Jy z4jF5w%Et?uPi-->qoegRQYT1?7-%*Oi?t+^;R-4f>wHfenlguhVGX~VJPu}Oc2H&m z#6195r^K7#=QChn=w$u`?^@z_NeLT~>%GBXlk26UtW!{HwZan;s0$1f`Fs&hi&|)ttN&3jMVv|XHO#okkfV7UxXN1a-Bt1#K*DVNi0~h1d z`Y5G`ZLO`|44gT?(@N==y`F&7CoOaWvx<5DgSs&|SqrQW!~_2`%btL^4v0uofWtv# z5x?5%SPHatnre?5y*og#UBRVE+AbLsH~uI&_f#NCHnNU@MkAo*$Jj{0!pfxos8>s$ zjhKjfZ8uXtlkL}U3SHGeiQu&?(b`QLQCVmk%KfY+!T-!-cn^F%$+_Kh%YQCBg48a6 zwo0^GPD`__U@$fnXwDUolBuuL`dIQc%_C@Sx=jZfcC7^?Y%iG!QiIVL0p^0+L3M}o zyzT%E(Lulrpi!>{M0M)kS1hl1;@YX&`$~dz=Z69HXj1kbpYXGf>Y!Jp*nA Z{s&F4%BOs-D=Gj0002ovPDHLkV1lIS*YE%U literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1h.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1h.png new file mode 100644 index 0000000000000000000000000000000000000000..7b8facd343ee681a46dce21d9215659d3af47558 GIT binary patch literal 1980 zcmV;t2SfOYP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?CP_p=RCodHoLh_(MHGfvKvooY z)d0F;B51@5MrDI25F^1G5q3B6ff!%VY=CGKC2CgR;DrYslm`R&gqIK@5+hz72%xAC zqZot6sB0u{j0z}tC%PiLe*f$Y^j4pq>D$co40Dp7={j}JsdG+OS65ZnGGau78X0J0 zppk*h(b%P1YzJ-uob)n7J!kKT&8(AJr+C+z5{W|mmmzy04E%S-%wrw#%4Mx zatVs$!6&t|=__B~e{^uaUit}-(8x$LKsm{?s{@nl;fr(KaMW-3;0Hx@;sJ6=@kC&r> z-b$rt8v^rzUhRnqJ9mONfjb_-%F(-t8%b&aH_ipyhx`frcMmnQleQJ4kL{^IZ%CJ( z3eu?vA8#%Ly{=cD@)ulpRm2$@p{-fqRiOFRDv;_x9VrePSI;Syob}YFHuy(!uG+!` zt}!R*u{uuOgVpxYY9GJU<26^(%ORC<&}v6rIcPvWO5HqDsme_Jx)FG1@vl)%e+`P! zZeWp;qXlOs3Ey5eoPIo2XKA1v^cxN7vC3r6DI@^@tOO~R>kBf8eleuw!-v44OpZC; zfN^>@7%-gw1YYvD9Y&TJ#>LXIq9zDm*963Hf1&^|s#UqQ@YFn~W?tp^ItHl6xb!28 zvtuU-Wo=nlRIy25Z08+Cf|z9m0`DG2G+YryZFX7vIeWrc$etAOYz8hZj^!y6LM>u6I$r%y*FkfcxrX-J25%UPR{7T?` zWgf@IO0d(hm6f8_kxzg&a2?RTxvvLW39_~>^l2sxY0|YFya=X~)K&Z{QCXxpj#J|( z`{sDo7&O6ARI$(C`B)_61DKJf0zM;^V^}xNH!rdhq*E3y>7!nyXBS&n2@*amb!g|EMc7-TkVeo35wV43c0KK6Pfo^VyZ@y z*vTxBi~-OCT0t9l-g4HLAOy8y|I!eiYw+rxDz1|_pq>=;xD|XY_n$*)ZMCV;nDe_Z zZfvRP;gH6pwT@#}QH#|1AeFm{of+VDU>y*LouehG1)9_l?q~|oKjc@@e|1W216TxN z?Qx@bHz;gZaB0$Sa4$+4m-JIRr-MW7*wg9znKB%bqW)2@_H*`Pdv+1~`>0#O-ukCS zWU5nz^IDc@?WT>WBy<4fRx1kl?*|w@3|~DtwVQ6Wp9&8rwF{uF60Mfw(o)MAj4c3~ za}`L*dqz4y0<&D+$t_p8|B`Pp8^+f<(~QilF~_fvN^IGSJ9CBLk;T2L1=c1BdM1 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1m.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1m.png new file mode 100644 index 0000000000000000000000000000000000000000..04d53f0af83a0b8a13703c808912fcf960de7582 GIT binary patch literal 2303 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS@X-PyuRCodHoN1_4RTRg4X=#&6 zY9kF2+Mrp96q9{VedtSlDT|7%hz3Pc3>v_SvdAJ0!Z5NV zDu)s^i!z7T?|!xbY28n zI;-lowzl5XJroQFL%^|BY~%T6OH0d6o`((*kp5sYcnYiqyFrLHP%z-2j}DDI983a> z!M`92&9VZ7fh)lh@G6)H4zuLCG!Lhb1oObpATPxNgrPBDpJ(s~^7nuvyL3?G98Mkv zW`oV32$@3+gO4W|{e`kyL8(2ePgzmNvC-IC2rkZGa|^QT!A9^W*i}u3Ch1=(578+U zyaevRm+P41e-8;ZosUDUAZgO2xI&xw_gOF<9G}%ubozo1Ks|actL=u!<7IE4RjD2= zLtp~X(q5Rba}8Jl{P_r0g+4A^Nl^p1F%Z1h?oaUFPbnE!w62gowub|)kUl*W(rF4G zZ_WhkeXpGSI?_{`;tZ8g*I2L=Xn*x6D0QOF)D9|F&q)f-Ldr{<{4+V%*}^njb53Yj z?V;?>&i2u&AHUS&wO7*OP|7@L)uXN)nvl0qHr`a~WF~%H0^D8v+vLkXgJQH5Sft?S zz}Y1U-(EMIzQ0swsbDnNZB(RT)g^mQ6af6Q0;INF5XlsJVo1k_FMvf|a?WuZjML-5 ze#7~%;T2!)Ff!XPE|!iJ-GcD-i9j1}E7Smt>QrtWJhjj1HcL6a9s$&2eEJQ>(Yb?! zvaT#FYT70+xAUGNjTmb+1l|l!G+h=&U3OXbIiIGp(DkHf&l|v}TXK1dl}Wy(YQAA- zt6Yv|P{RLHz*eVS8%g(1GLbZo+-xW==bq&=gKx5^{4@&2g5$vF=&rQ{k-HTBC13|w zikzOQ2;G4QP6MjrYjjtJ6e;@^`SU4Puh|1$hNpX|Y=n{iz}K9J6@kDMIaC-#Vwx|6%O3zctWYy%+Ci02r7|L6~9Iy*m^dHRH zMH%VSfpw>|I!&X{T?Ks74>2r_ej1t3M#FYeGS+;kbJlq^!Ga0PIhnk|up1oPRoNvxuQv32)=>^4X@Z>X$XUr* z7PHDrvYVh5FNy_-Uq-{|oVaMO4-H<0g^uiKGInVVnWRg0SJp~T#qJ=h0KR(b^;TJ0 zp4tht!`5bTEf{a<#sY-UP;i7NyoKQvd`m#te&jVd>iHLV1ZY+I1LP(7a8p3}2KYta zgXtXk05}O~sO#Qbf$u<8fQEOFXwR%ScpX>-Nh{RJ;6&1o0WG6NsWo6A#1Dv@Y;7%E z(!3d))2smLLjs>R`V1>iP}I}@w#qW_)B__L$*-!OSR?YI$c(8m+TW!)+0;qv2OR8c zTLIEn7CvR)O!*el=NEaResA&fFM9H6v)c_pZ8kel+5qW|XS3)XD%#{!HiKSMIdSvs z3;#x^Y%A&IPCiT0`n)E#`dI{_$FO#>1N>x1ZVI8yn z^EIphS-r&?cD}7L^BOj7j=^YH-R|&|%safKYpsI+sKBMP0g81!*GSoECi)+-xze$F zDZ}d;@>e;$Pmrs-x;pY{lCcHG3XrwmIU|krl4YLv?7cT)6v%+R{?k8cSY)_QMSI^T2^24fCM&91@8j|L07hO50tj2 z;OS0!C(ymj9KSqG9=-WMchd^g!$~@n-v^=}MK481CdmiOP%Q1W54N-l28SnQM}t_; z2|8yKpx+ntGm2^~%FhPwiv+T5OKJjH5-1*wFAnvEzE8oM(z@}&(mdZFQglm@-%~7g z_YbHB(+2A;@t5#}3rD7iVW>NQf_EYQ`=o%4$P|Qn!WitXA941*J%~ehf zPr9`@X>HJ&epXA{2z=8=4sQaz%b%ZCFS8uRwXN@VAChNoXb}YhG!U!@A$o>_Lc8L; z{!#BJaBg1x()4gbhrOgAHT#cQbZ7k)h)Czia#pCkQNscCq|k7S9BuTUL+NbwT2z_$ zye@CsO4Gw3%}Gyrj#*iK7%%~p@~dJ;f84tqSRaVPuF%ZV8d}s4?r00JyWOwEe|6>Y zEYM%w2s=n-faE_KBY>`1uLY${{LPGuSr-k_ zi-5^MtKM3WG^q!Nm}$I$%uXAx1W3R9P@qr#h5&s*BItE<=zm_IsE2wY&=Y~42pl>Q Z_#Y_?0rbV?MeqOs002ovPDHLkV1j6mM5_P* literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1w.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1w.png new file mode 100644 index 0000000000000000000000000000000000000000..3249b9e95a70040e5e0d141d8561aba7044bd2b0 GIT binary patch literal 2470 zcmV;X30d}uP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS^5J^NqRCodHn|-X-V;ILf6iPZt zF}0{gL*}Is)r6QrFB_Ye`9l_^q!C-#{NW$NKl)4g%f^goCd?`%6q1*Wv6kk{YbU)( zNa@Ar`<(N8&fWD~_j8`#@A;i`o}+VZ-}Afg>$>jizV7R}-+#Z;ty>p$MW8DJT@mQG z2-I~{)dvqAJd(PHg5h8QIIbDncrLE1tJ}%*@F4=y2TTDAz7B>!7XvEBJNG#!+ibP*TmSN<*nH-Hn z)@UgT6M>fYstG$2z#G8MN3aU?Ue%RUYXCR;g5^#AME|ZvGN#(PV&$<$|*id2W+`D(5;{nTBi5 zi4CiNkdLVRc^k6vZlMll;@3qW+{M32KL0Z)MyCUh z6dWBmYm)Ho1;^?8b9I&qMuI&~MH*H$*>jQr;GY*DwdK4-r>ZB0bbMF~JgUh#Cu}fI zj{yf9=Rb#6{c4AinT~O>bgbwUgs)FT+HhM{4Zx^Q<=(+l`0HSAL#Gtw92Dk9}w<7$rfm0xx#1+0ndVc1?{FkT4Lvi z<;Xu2$hDWcJd}rNWVeHGnVuKQ!!&w!*Zf#0&n-3TGzH$CT3kli0cMbeGHy?=)PlF{8x{us}8RXmJ(XRbw_QFQCUa?lzTcHAg+ z2MSn7>LG)zeR#U0_vjW!w;zgO&rQmmV0F{vV>`*q93v|oo>)u3RS{Xp?xhTO#rt?{ z3nVCugMA%h{HyOTbYe84#M;rbZu4*pdGe0i|aw5hbQvr6UEbjrOmMdC_WB!H>~;RVW9n! zDzr2yv4OzbLaa;VdZMHGXR9?5 zm1?$d&^rkfx9p@_3s7%#bfOMPt66dKC4F`%bkf%)9w1XNH6e$jdF_xOCi;3J^EQoF zhdN4^3^90~(FQ5Uh;iNs{))*hAKgFU*&Vsgb{7V^c6fal$dnA_r;|V4$Umo^a_`3e zHTuey?2Ehr=_?CMda0K;EprTpyL3Cx=#onld_tkzn}1d$ijn6Ihu_cgDh-g{c;-!B zfWnD7>>-=!4Ikma+Q5l(879dw!3)sxK-WuppVuVziuzuFio&)`(BQAIZ&$lQfN1zI zWZ@BHWwS4D2R>=FO?sRSkcO}wl0nfz(z~wNYn8kJdA-FOcGgywy#1925S-I66!sq3 zO#<_dsbn1b+9}&}*Sq`x-W(GaFD?iHb9ay~Br6S2N!PQ6GUmNure0wKlmzBuWa=FW zX&xF0dL)eI=L(arG+VOJcmeWe{vnmtkWx=QW4|e51GJIe@Pl-kd&T>KzE(YNS8aP{ zP^6grq?l?-9N=MBR--~zT^v}7ZWK!`6l|2;2Zd#*XpO0Cx5+Ow`tywZZPaaTX4IHgH`$GD(I#OkapkY==#t>6wfKAjLbb$hc?orONJQT zSY7^G$H-+4FAtVC4<&Zh?d=&*tKXJH!Fgt#e;iZ(PFjkq9PRNAFAvsd7}**z^aVfI z_E1LtAo-OcFG%aheJ99Qoh<1=%@#cerqX@wbwbPmZ>!+(H1VpJxEE&dUyoD}(_e)> zZvz-HlaWmz`he6|u1R&2)tzrhJIL6jI8oQaptqlvHp6hY7x0e-TWkUH7Z;6|NuW0j zTnSwJWs0_lC|u2@{b0(k0J;Xz3Nfd}vY$d{7SIbxox(o^6MW4kF7nYpR~)*XYyc0G z(@$jR>9SsaiS#3!oybx>Dd^qV$f))y6%o3+2B~yd7Hp#5yCUPwO6V7_Sz0TH?is*d z%PwiHoGZuB|MA74zRE)z@k)-5qU)h$rNOdQuMA&>6K>^9bV0*zBko$cd= zqiMj`wh`p@YF&rj?1X`tj$yG5IRa#_q3uiJ>!Xo2Os~3j4C~CYHc~-n_<%~UqP;E4 zI{2v;kZ3S5)R{lQJKyMt48G}2uJ%bG&2N*sso}}6 zmLRPlwbfaz>bBt9>0mL?)ymwe4aN*$Tvs8n_wahJRr7OFtZljR2|{160mSGj1m1;s zZa%~eQLpZb&Wg#~jgJ#L?3D|W_DSuwnWV0<;8T#0&XM`7P+6mj1L{e!;g&eMnncBC zx3s=sTW721lgi9*J8-qy@$?FPry2)akpS*MLs`F}fr724^*hhuQ+{iFq3E zb@j0b+yDw+oTaUka@T?6x`L!jzr!7v*0!gw50`Qw9MbzK9Y02;FxZIh2G9WX{$IC_ zO2_`GSC?yRke3^_>yY2U&El6lYm0DR#}b|0yaO)mifI#?^J~s(B|0r| z3-qy9$1dl2{Q@*ZF9N0jt$OQ0xk)`b#Paf|Qac?sUI~zX`Jq4u-2p&fkOPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>21!IgRCodHn_Z|>RTRhXwGXbA zWRR6oB>0li2bqMC1r-uPgc&IWiIIYD(TiE61c6x4OKNUaBX#6%~Y_ z-Ael+D>W5y`u(SKrak+v^S$THIGqK5_t|T&z1DxNIcJ}}?~EfOjWiW#D$rD*sX$YK zrUFA+fzdkiYPDKp#9IpP0#|{#5$4cp%$1XL4uc;fd{4U%jE|0vYHT=!qD%*?!ESI2 zR2BJeN`EMt8~Kng`AiaVQE~e(5E%oXCNV|77u*t>seDGhX-p9( zf9nvMMz%jl>@exIT4&Hdk?oC(s3dq_VgxCQxi&#BqMs{NUpR-RU!l`m2Hm%juB#s}eZv%;_SG z86*|~>n*Y+OoZ}Y;I+jllDIA^@3r7ef{hy_zC+jdw}vcpch8z~ z9>dRq-x|L<5oc{Wdn*K5Zv_7eUFsH}@fqMwa9vr3nj86;k>&#%9eKV6zN}B17i5fx zd;F;MH>Wvgd;vJ*%+uZ}_l{b&z};`j*Mf|go3Zg_PuiTyV?>(?PWe&k--{e|&`)27ak zI30BCbt&%3A-5DQkhRE7FL8GtAm5%huBQ^J_2AY@Y%BUkshEdfQW+q5qzzOY6#3b6oL#x?}OR#m&kgwx80T z?`l}#_3C{HXd%Xo$LwE`E!=d*dk$O%-U9NO zB^I|SIpF&?94!UkfL+9EnT|2s24c}}x$EFb-yM(b)|t)*KncNhF-fQ0=2Ani1Fm~A zc-bBAR1>3%8F+o&*G9Ey=i4a|y~}~ym%$bKCqtga;T;(^wGYGT zCW5Zb5!laBHBc?u;uj>=7ism{yuHYTnryYE+*&nOhysa&jsl^4Rn2JxE_!5gA7#=4 zhDu7G)Ef}HIxScoV{p*-X4^rKySnQ&Uon9PnZF!@`)PGH(srBthk>oR#|u(2=fv5S5!?WN~Noe{ez0M@e&KQmXzPlw=p{tv_4zYL^_xtkPQC ztQ-fd9L2ma5yE*9 zCm?RVED0CI^F$>5a_eV5BK>{9dfq(`^>oE0;zZLW;$HNrDMp$A&v%9Vud|)YONx05 zZ!Hc$TrAldKBDK5sI$OtR&;ceKwtM>1G=^lo|~Xu#foAowm4WK&a;XJF7;RtNI!6R z9h911lw<&Vz1ml@=Xo=LuY4{j(kAO;8c^Lc`LYUZMKN?s>;FOws)$?VKf6{c8wB)g z()S0jLgJMA>)Sku2U|lRb29;T(7OldD`Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=AxT6*RCodHo6nCFMHI((jjTW- zXv`uY;2JfEAu+&)0|$P^AYSmmm4i1AaFWDCLc)bW;*AIw_!GPX!HrQMfdtv8gur1< zRDK0k5j5&5!ua`;?PYv<)l=QGFw;Htl5e`}RlV2s{mx8vb#+Z&U$Ue?QXnai6i5mr z1(E_ufuw+=K)>TF7J|9p7Ptz|^!NAw&aw9lQ3k*ca2|wgf{LTyot{!i zgu(Zqh>g&AsP;lZawoW7M46_x)2pnU4{>IIG2q#EI9GV2@NWaRy&!yty_ib+AhSJ068}IR zDe4!3Q78Uid`t6UD^mxNa}L1^_;SU`2-0pD(AZ;bZ`P)pkGW$Ij26-PD~5o^oMFb0 zQR5F5$@4Ll`%Ht&l;1YKCsCZB@4rmTg&_8x{n#mMKrUp&41%)L1E&jZyS^dAt1%?J zyHazU9v`d~7Kl%5oFqTmL>(-@#kCK{T)&k-&pAo%IKCKH*|?b8W!fx{32G&f9z3nR zXdRK|vT>2=3pe{bCgSN9jWnsVw$3_QmHEBDMjQKc)nI?URqSJ^pCIQ5_^9pN5St7B z0oJw_Nlx$)n}G7kB00LYEksT@NrPr(D=+3x1{l|P5!8{m$|bkg@HN3AY? z0WN`%FjO_pf@dl(iX{N4&EOtr$9^Jsfz4f;GUPUZpGzvFhhBTDuZ=cSL?Af?J}V&7 zAGF;IW=$pOg%b#`28X~^;F;Ee_JB%%YjT%6Vm@dDP!2stNC>?b(^Bd+9#FOXnk*@h z6i5mr1=>)c?LoSYYfoz^Hw)b$UIMyd=mw#sl$+cvw5-ybrYQv21H4yDxF1eIG!4drXH`pvrigAy8~<`j27qqw~Ru0Hqc_87WF(ko#n3l5q5(> z%e2`;0$5)}H6x-L=nI(@Exg6O% zm~K4pH2T%?O}SzP+Cjv(Q&F8id71H~%$r$n3-XOTI(Fd8YuiVsUZ6oI25H@n-!z@u z#W=Lz_<}|HuK$yK4J_wH##Mg18E8nH0mYJVH-GE-X09BT15`Y+th9I_~2gwwAtOWF`P5JxMrXIJvP^M z)j4Fel&ZfwgytO!psTx_24unG_yE5qi1m2XfXqWfq+#G~O2=Kuc4j$icSMG@ zV7!nVj~Z*Qc74UkK5a<80!AM3jylty0HdD%v+Gp;D8fL0`}`Y(Osk9f`{+O!!rlN@ zCQnCWApa~KSOc>6V%oH>_hO?A#8)^bO9~_fk^)JAq(D+2DUcLM3QVs8{{f-~uA?oC R2VMXG002ovPDHLkV1hm}nP~t3 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete.png index 800cd12af18f127e3bb4683b62d81610ca69606b..4b87ebc01cdb325b60964da7d40bd7e5e920eebe 100644 GIT binary patch delta 1269 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8 z?*IS z@e2G6d<(t@pJcqxIL5CGO^cEFV1f(q4ftPp6XQ6JUl>U|ga#)C{{Syx%rh*JFdTii zLe|z&W`@CQHUZjODLHx@i;1XL`BDmDs5?%#Pu%vVEa;sXQSZ z|Gs@L`1eMxL2eoT9{!s|Q*0!WYov@ni!GFg{5g+hm4DCnMOTqYG5E1fFvIOlEaE32 z{wV@+zh4U_oT2;s5a@b{Z}b*JqR*jZGj=~}J}CmdgaDgxdmfoFT~7FO9-L3Lsz6ns zDlkk1a4x#*4qW^ivB`FyX6pEn7y0pE*eyQ*65KZ)Bzt2ZMp1m@o2xqm^1hFb>m&H( z?ih?mB7YCZ2Os}!fBcB?cT&zlHj4$kh=8PT=r&=&HhGYbZ+Nlc#c47$@b+Lqy$oYTYnWuRYVaBl4v176-x09LP!7PYBS+{ zdI^1pa6bqC_u>kE%KT&FyJ~|MPxHUwme&G!9i{SUyu}>YjsYa8Tc)q;Ch>i7h`-ZB z91d(O5C_B5zMl3rQ}~MK=?nt@<_e_twc7sy8bxm_e8n>gG*=*18CAh3GKGQ^{?r6g zz<;WOh2|cWM&YYMMkUK#K}sN1!6-6?f)u{u83mUskgAL#7)7Q~kiu6yqu_D{Qk79l zJc>-AAce1ZM#1F@q$;B-7)7Q~kiu6yqu}g;Dr(SKP~T3|rBBhEXVwaGr_r&E-_f)DPBowO9}K%pgs_NZFVU<#j8yYIyc@R&*0V$(9!ze zl#&r~;KZ}`R5R|l7pxZHKP@}7x8cv>H`<`Yye>a+tdY-R8@P>fg3P*QIOXE0_9CwOKBmb=^cLG<77Iilq3;F!A^Z;fD!jD)Lc;IxPw=-`H6Kd@)O=Nesz6ns fDo_=eT?PIDp-oE;EsQ+>xa_R9)ykvXiyJ zmf`kCr?uAGlI|!?eC*5o){Kk&Nb`{md#2BP9IJHvps(bTdR4EVWj6V#S10>fZ%qGK zqkqiIBVWam&6lx;rC{T$fcly4SxObNW-h*6E%5nS*3OQ%GoqyC7I(`sRiyRaXV}*w zFt19ggzv#UUZV^_ryZx8it;v2HnLs(c(!XmpW}LlnkZxWn=1c~mF?M*A@?e?PGrRy zYlUVGqmF>23s;YPv`K$-b;7n^Lj2Y3bJ>rd@7r%xB@;5gb&}S$S)1@IKHM3XqaL<#wQTIW=^U>;ulX6S+r6Jdu|?o9(*gTi WA0%4O^#n>W0D-5gpUXO@geCw`$2XDy diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete_auto.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete_auto.png index 9112817b109b9a1f9778f5550c2feef147d6a78c..cee6d944ec2d64589558b2ea17b066e69582ed42 100644 GIT binary patch delta 1725 zcmV;u215Cy4yq22fq#@qL_t(|0qvVxs8v-IhR-q6NYn16nLZ>Z$Q~-tE>OKBK^M9r z1wlo=SP#CG)x4e zmA~58q$v%J!g6pd)(ClzqjLv4h{}_CsvnB{$#3@yBdw>9mDPEAM&s4i0rs{$J|=Bl zI^sRb=j0)bkAFE%fcEF{QKar*kw$sjsAIN`?kbxXv#atG!wJjnx)7GNq#-vS{RABr z(LB=PC^7Q1PwQ6XNBq@~`JO+Umw6QBl*Tt$2VHD$U=lBl@y`<=-S0DF4!fxQ00BBJ z#y9gVhNG`y&bq8TQ-AUV=ph2I0k!*)E{n?;fAvHC>3>T<0{sZ|BhZ@>U|)1$vfAbZ+|j~$HU_r^m+FF@YNMM>09!QH%)6W4R+@8k7x?_hj&%AO^O3Og)Lp zh<_KL37tXQR!iv6jp(oF8_Xg-(I!S9bDLd&us@s#HsDS{Uom`s!+t#5(^vW1?aq#L2%vEI1vEBe=p$RB@dE$f1}(0oQi6%5sK`_&!)lr zJS5Q}{TyY5-ym`a7_dJaGR=Ns`ELgOV1IbLj=j_5rRIydJ6f~>h~92mPm)Fj9)G93 zPp-FeorSJ7`Kh_85rUvKx|;@X5Y_J$htdv`_SV7^i!$Ypp!zHo$`OqE2NIB1L)0X_ zA|+qt72ju}TLQe_N#B9q667g)2yJ<^W9xBm*UO*Dn^7glalQa}8nyDwxQZ2I0Ds~Q zhC2PVA@HRKN1bO)J(*8>bt}sQV1)zvT4ex3jb*c0%`x_$V_T0#+*8{QTy1xD%P%WIbhyydR}3NK|_3> zi|VgWq1>ESA@eTuP4s1SL7E@CQg;U$%000*h08&yZ8weYWnnK!YsVbkZhwV%ys-Z=tU0WbqtBe5bLCnp)^Xac5;! z0rE&+9io>=+mW?)QP*~jbZ2E%0rK`ecXE$c@t@M~O$078c5V}1(`mHWG~8_L>P!G< zp#Pv&c9U@*dUjDX+Fop(Vt?OV)SueX-X72DeeTRMKBH{`cpfb)yKt~F1jE+x#&+ZQ zC+w`R9ick~XD({DCH4PA7*Ne3ZPcoe>%v~)P)8b8){>EHiJ-nXhQ}qT&uc=w+R~sc zL^TV_%43!!4)tZi$~rPKo##+*0s1X!<$a4)s|~tN`#!cTa@s93NPmQBuTMC{s65L!mI)A*8}2#D7SI(I4hPQeJhMZ2~qh#p?o=F!nBP`%09 z$2M6lqSFA~cDaAtH8$9_(J{p7`~_rPj_PyIY*e#kFS=FA3+^7Sed$M_;RyT-rowY% T*n^an00000NkvXXu0mjfbxloC delta 1719 zcmV;o21xm;4x|o{fq#xkL_t(|0qvY!s8vN2$IsQYLa$&&A6ABa8B!tiP*fO_NFmX02Ik&6>4m&z?PJ-`i+ZM3a+~E5I9I4}Ta3X(a9Y!Mk83m{w7k z)px_-=7RS@H?$q&1=UAia*qsZ4%pRAW<1-2)cY$*3`lONB1vXaf81^iWO0$1@qDc; zdE!rTU*^?VHKnJ2ncpcyK5Hn2Xg?J!2j2rtcWFT_d9L^;-c@(i`(p-!(K2V~mHT6S z^sFue`qCSetA8$z2^gc9&d@8zV|;Y0Tjnh`VFWj6$Pz`|g(r;0>4vN{(NLOauG)Os zN5B#=GflV0+a%FrU^Pj%*0sd&vl29l<+4QU`Za7OL9+MOrMlj;dm=DNj!&}D?TS)2irODCjkGI=mhb}(MfKKO;E?nCILkG$Q@~bp-dgE)@^)Q8%5pU|BfFd zDC3fsmVY2-d*&0RD4mQkR@W@|xTd7u(aU_I6s6;0(6I^c+VYlB3#`>)(jtg%<`bnT z9XI%x_?%5vS=uc|$NuA1;?TS$%c~>4N})0nR7${AI~^n_BjbYv4HA@*fsE#Un?d?$ zSo0a_=xpw{1dXX7YF;%L%*sAPQ&JaNPk60clz)!%i@(g>yVDIV%iJh-Bt&m2t)%7A z2_0-6y?(pJ^5h`ZW{{xN^fVfS1Z5=1KR(S+txq#++a*N%0Js2b10$?$zfzVKs>ka*UEl=)R})efB$;sLx;O zuzv=PscdLoH8-x&0*{y9$vz@UFM{G{lYc2(-Rpcx)wTQO6a^T+&D9N^sLdaK^o(<^ zb-4|}xw^luc-@2WNe)AFLv)h-TXOtaAAQOf`bi|W+(nizC#%CP=3)&g=Nd{cA-fsu zG1}yo`;a7^VYD?x{g$9hje+jt5&tprtAD_oM*9^B@}_ES6U0@&1H1-a1uI$um%(cK zS_CBND3GuGpVSKQ%ki@aP z{y=`d){Wwg&eIm@LVg$10TRPP@V60*B`-|emgQg@0=znEC zoC4YTZCiw4E=60crn^)}`FC-_g5 zEDw9YFgn}GViWYaGxW+4u7LdMWN9-A-|`nn3%x$2`T;xR2_?(JT6?8A&VNyCf?juq zUMVkpqafz-Ys~7lNES^wF7@dwpJ~;p8{oTJzTy@lZpXIxTw9)6!CN&fm` zCFqBO`j_)-O^2KyDnYF&eJ930I|n6}*LuE(y}GLw^?mkD&S9&R*DYQB*>rd3|4_*D1rTj4|;YQ|TtNIF}bb`Ohr!A6jJHu(kk* zqsdx>g)*o zR-owsf(v7#z-Bhsp`F1$7wfBM^a*|l$g6~=y$ED22_kfd!6xklUVn}{tfys=-=0un z0M`RK7}N9%g0z5=q-mIE-E zVYh>%+wpmxT=&u5A4HN~v8F&y+1uDfZ+Ch=lMLz+a5867#7xe$xdp zatxQwe*h>uOdDv5^6UTr N002ovPDHLkV1h6?T#Nt! diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_disable.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_disable.png new file mode 100644 index 0000000000000000000000000000000000000000..6e86c08895425b645d0a08579107f39e1905f0af GIT binary patch literal 1659 zcmV->288*EP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS== z(l9WK5yVCqcfNqiC?dV>r3lV5biag4S8m!(({JEBfHTZakdX^+M#PJt3sKa|fTJMY z{yry>r214+Nve`G=DRi#%}CYczR7?>EC7?>D1stnAA3jE;U;26G7 zgI~Z;;6w%vEB|JA#ql5Td^VfybL?GuBM3rP$?g)k0xpB|;5Z18Pbkg7AK*Ut3&K8f zJo*AL7r_pA4`PXI$>zl)$q<3hz$SPIQj2`ZS8sPiryqqtFMv7dTjcXXr{Imo(O4(A zHSFI8zZrgfRc|<<2EFJ&&N=V|)X5Ts zJ#Z783Jp%WSsS&LjXF^*=R)l#)gzD%P}c!JLgza8p=&U*k=c^XDp5=uUHx@xPXOEC zb48R3&fNgfZsj~++01M&IQm4fZRc%zJ>vL|FDmNaf-Mj_&S@RHd}O}l(;94l(#hQVtrk#TAV10!wsTSu!X|1f(m; zcf0LIWd}!k;oJwVs8c)-M200plcYY$>bR9loYxWzX}mE9uIRD)^=ZZNEEp?E>%?Xa z0hCks@fk)ofhAkT%M^t%leA?eK;33BhgN@M#G0~LP=9C;NZlw&QmkMBTzS}vl)Mqv z)c06&BiC_{D36sSz4BPne$owVcMXewQ&)NKa(;9qDP~~3;NEqA1i@1l=#Gjc#h&HBp(NKz$rlP*dhv-?A6&V|Ox=HO zrLT?KI+Qm!oBiniqu zkYwdz<=lv%d{M70FQs+^lVs)6h@et3sR{#=6qJ^)4+>^D$V-LNKqOgLi-zWCD5&spVE_zks+s(>hp5=Tf7n7h&OB*I#x$0J= zDkmh#%E8LDIyElE&J$+U9>UJXyxp+Xc*4vZCB`~Uxq1z^I1!5^?8KXLRUR1J0j|_e z+PC1Kwh2LWdb-ixH)+39>)fY+(Z=J}>1p`Uc=S@-T7xbkiDLd@htZ4pdRpM+l8%?k<`Cso^DtT*G(JUi(H zkfg0SX}7=R8Q^FaSfWizRRhl4M3N)EtF9#9=C0l7!4SwA@NL1n72RP2gEb^^x+H0~ z;3;0*RBhtap1`qQNjXF5HgV=ZD4sTeZyT^~w;}r^^*O%VD*ZO#0!iBh;uCd><|16) zKE+W!fz=`BarU#3JWmd<)29eI8NMSV=}Pk5Zu;dG;QRcTB_|C6)F)XRt*HJcdclqT zIh1TxiDF9o=|N6H-H|}_bn^`Xib*Uf>;Y{-3En9p-K>q;%0`_imMEVbRPHsbBc^zs zfYvDA2HHauYWMs2B-0^EuO-&ITivhT^}Kwx-?3UuBK6+{su$c%U`>@!9aWCjXW=gS zP@yYI+llKs@+PdwmTV@!VnX{0H}A$}lF?S%OF+vmmw`UKJG5J$I!iuLsbwgwKHLYr z{cDQe2qLMHK$za!P6O@i8tp$fDFrPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91HlPCl1ONa40RR91HUIzs0P{mGqyPW~2uVaiRA>d=n%|36RTRg&+88EA zKTxUA21~~Wi-aJ3n};Ap=)vq^{80}f8VE*0^fJ}M1d%3TJ@f}?R#rY(Bx>}e4x?fZ zDbYhC2s@?+A+Y}3h;B5SM=&$BVa{4{7DU&_0^S3aXbFi3LM8PN@Z=E6{-_SS zK}OK(e%_N(qOW%&hUh*BTmyyoPHA*o7u{h_LSmQ=hN_s|Qge(oqEk}Ce25{Qx* zW`a?Wi0)?vnoYe|`c7F<_nY=7rQnHUl?{&aaMQ#v(2TE@lDG`*EpgQ zXPOAS3G6GNZn(N*SCDugyuBS0HzC01Q$Pz(Pj)wH+IkhtTO9Vz|6@)F_|Y76zvC}a zo#7@tJ#x4kR1ob>SW{PRn?)0NXMmT$<&+P5dkw{scAU~q-?d{v>$fk!T+O{c16H&L z7)2mn2-1^Q>nkZg->yRlK2Aug*Ii2Ns8No$>%g{ycRtV_NJ#eEwt32sUoZ~7odJP; zI=|#04cKm{eo?^YC+fEaY(mvHjlrEtY|B1+75y$3=p zIqD|@w!nrZwEpp})4Y7iijf#e<%*syoj0ohJ2ps?HnZa~eDf z8}8xOGX5a2avsHe6HMDhxE=y0fRr*NdPccOj>jPb%1Q(NyVI{F?Teg@`q7^kNO1ur5XaB3};lDhwQfv+6{TCAV zI`9G5l-ZWb(ro5r2AQfLUOSqEnUj{&wQS5CR=u)e`eiz!>is^G zPOXSRFKlr??Id*_UG^5YQpBL_hZ1i)iM>{PJQ;U1D*G|gGbXX`DBqruPQ4n#vLF0u z|Kt=n0Pe4kK2V~;|L>?a$(iKV18rb>(wm3tCOPkrUCHX0DfZ7H?uAnW*jexuSeC>R z{R+9drFYnldP;OMGXgr=@2C9^U_ZP+L{BJ9h(ir1-l03{I!S(Vv>NRIu)APs+FSS7 zt*m3IFT~oaxaF_z24DIVsGHc+#QHEAOIq(~ul_K|`jOa+jm@Ssqjfk literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_empty.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..062f5666a7fc4e39dfc93ba5eeb5dc0b90ea7209 GIT binary patch literal 1190 zcmV;X1X=ruP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91HlPCl1ONa40RR91HUIzs0P{mGqyPW}5J^NqRA>d=n$2%aQ5eRJYK5la zBaI+vkhBY$NV;fub~F-;ss$kyB4s5Z5u389M1n@}Cp1ceMtnrV77Y;=h}Z}cD+}~P zeZ=@Z?c6bW=e;wg?#$fVH+g#Jy!V{dF?G*3;3jDISmHkmJX3Gj;FXEQNARWKp;xo< zy(4`dbb@A}fupFAZz~A16Ga0|Cj+%@1nSwj0p~y}GC>MNK#BSdJR8E<6lsN(2nK0&Kd+@E^mrvW zL|zBPHBflZlt#C%$SW){AROj_of*vgr{ZMRknW9s5>@^=r3gzn)PP|Sn10t4DK`0B zX`ZsC?pO7e5_x!ZSaPI$3koBHRutak8=Geeel5V-HyrCi#c@;1Bx^&V1*&udg4Zlb z(t|D?ZfHSk*M6F(n%n|abi!!`us!RQONoqHrCaNFGsnOQ(F2C;={#Cw(EF5q^>A0= zd4;R!fb(8(2^EV?HOwbxZ(O?!ZeG00yw z0#2*N?4HCJ8=51DQ8h)h)$nbTFxxsGO{OFye;ShWB`j^6NlfPLiAdO}QL@~mlaSPT zL9UHU*w_c#4h>LFnXp@@r)T!l=P+mQ#L+H_^t*IfL^<_JX|PY`+>F2 z_|X1$CWy#BYwC(GoT7;o#x(VJAVlSiTm(-x7UE{yYm2&~%-gWpK6NX>e`&F#ZVhz7 z{UX>M`tRpv(l&GKXnxcchp;4VzpaGt2*|Z3t}r>tm6Q$BTe*rdzXu8lOTrfSW=GUG zzVI#XOsmEHP~wy$>{w`P1ve-Z_hY1OM%Z)Ga{~SauVjq-!QVkRJ_3VaSwS)OCIx2R zQEea+aou2M9j+U3-XS}h)8+UaVli;j72P}t(W+&d) zkqgQVNQI?-a(HavM`HVe%;s9T zk2a}TD-peUQ-mTo2HjxVl{-b6YHG!r5J&r~;!X79TtR0hY*xUjK_%!TWdHyG literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_timer.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_timer.png new file mode 100644 index 0000000000000000000000000000000000000000..b80d87b5c6d8be5baa8f551baee81194d7ef6a7f GIT binary patch literal 733 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31CzU_i(^Ox z=i3?k^<5kVj=$&Z)DUfPQ7zG$>!Bgyr0k;o$bQGM`hvThz5g9s{WA0dS7emD@c5&p z;i9B6?|gxO+V`^S)#dLWsi@6-^X5#=e(U^u`_A4I<@*2WxRpTaTJyfgW(LVGWURWr zg-=~r5PMblSnL;#u0`d?{DL4{pU6>_hr&bismG$lR#O}j>FRqcY*^Cr=k-fFIzuzux4-W>ZAihPv^ zVzm{r|NQwnQDuInToL2Rnon69(q)&d_Pk@sl;OO2j&YyqBlbD2Tb%U|{W&mEC;O!1 zYq6%sd;w9{wL7IVwx8|GS9LJTdtQH@aVqnHfQ1?$HUJNg| z_CAa;i##LwF;_g`rlT^DEmUPYpjF$+t~U>?XUW#hffjlKMYM``L%P7B%sD9a{6Y z{kn6WWtoZMXF-$Gk!d-v%6!{&&G&kq7N1oncxQQo?XlnzfvJ~oK0Eq!YH~iyBR4*` z2c?~b22$UJUZnV+w0`?BY;OJoxm|X(@6F6gO*c$?Kg)5OX>3o5l&lbY>?G}jmR1U% z)lP}tIV|#J(RBkWmBuWmKy}lTdbf_UTwfTxwzzewm*$GCdOugKu(1yPe_r9Q-OI4- zKLK01CY`RoT<>+g=G!ig>Ar!VQvdy%&%5r?zuNs58~N>6)?fR-BiPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8 z?*IS@W=TXrRCodHn|X*;RUF5iG|MHIG#4hl6RDYDAuWFe27hIXWSg1LhV@sAsTibX zAr+!o5g}w{ibjD*DJ?EwXl0QVR1}nHay7Lwmo&{LC!IdO>7F-d&iwBB?tAl;_k*wZ zoZtCv_dDm^d+xc{cI~QCWuVGHm4PY)RR&Hv1{xb1yMrZQCs+*zopdKz%n3orLSW0U zbj~j(W)fd=^nV9Wf-k@xup4{^W`Hx3#3+jm#cTntl$0crJpc~7Nv-}Lv~MX30dYwv zWSLc%-7E=7B$#6-iD(~Z?6$c2OFm8!wP0IFp}(OYnpY9Tni-NOOf9plHn04d<4{B$ z2qQ^mQqd$4<6)3RUUW~4AaY~57fb-X-SLw2NmMeDh<|+_2$Ka2oC5}fRf^G0`-BPB>Wx)Q=^JvJeDBik8MYAJJ<-K)I&`PU6^Bh?g6vrMjR)I7n8;Xv+b6d+fqzqxgnfJP4luHYM%N?-VV8*@iH&b3 zFdKy3HNRpkQ5{KYZDB*;R3rrjUx?pDAn}C~+sp)+f{Aex_!DR%Kl9LQpox*`NZ=@v zW#Nit7gBvO6%k8wg2}HYOBoR9|f&!ARCFU{U%3^aqu}3^*K^1mk zGl8$N1EDMlNyN>SAgP&{^UX*g4-BXP2u$;o0@)tPQCMZapJ4xh8L=bke){<@F zpTQKjHoMQbEG%W$(v{h^U8^?MT|wMxw0{AcsjZv?1!K9AM7&snuo($lk>{^&5p_;> z9q9i8I)wSi)C-$EA2KE@)XPBZx&fQqNFr7eg5;8*$&V=2{cQ9yi|Q4p>!S#IRdJ97 zUgC9&364)LBoQYGL02ku8RE zB;{Z?4QO{K)Q!`$lF^TqK}R-dwoN(=*E+`1ZE?2>bq*Q8zbKOMPehQU$5z&Cdx0wl zP;_!jL^r@Sr2iM_aEfbOs(wvP%{F3R0k#8I`l47*K}D~)B`~?xa*!E+O!}6{nr)ob zZ)#${gT`)0-+Y zwb^K!y=HfUcH!~J8QbghrQ5UY1WDG6B+bNipZFs(n;s?3k)~eAKa9()IP46|)@-Zm z5H<%KJL&dl6M`gjT9UB;8n+=}G#E-h{5Fh%CA+M)X$~+A>v+&=n`Yb0Ab*oR14;Yw zSq(Ou7zvKrwM$zMX)EW3Hk(1_#L|*v{E{5`DG3qUcB*^Fl5l4!G554NK~hu+Ng6@; z!gfqRz#;N!*Bk9s_3sryPzgzz6p&&c*4Z7aUAZ&J6q)Bt;^#GnxObV@)^VlPwwnX( zPSDAtRwN|}`Ae#cx3pCe#{)jlqy^;X%;;0{jqxXOhG^u!!##6PnNRyM9r_Bn{ zF(%6kS6Y3%W&APpfDbgOc#`D*bRE|!M>ofuqoRd&_qZY z9Od7pV-)waR&}5Y`x(mcj5LK~?*SiZ@t+7K)DteBjFdw6V%= zPsK00Rcc4{CuJ>=m>%$fEi1CdE2|$B&j3g5%AK~1O)j=5Vw??DfL&l2=u>RWviVc& z5HJt?1Y|KNq-+B6Gps9HAtyp22#LLop9tqst+C2Lm4PY)SsC~b3CX(^ek^#}00000 LNkvXXu0mjf>u3>O delta 1179 zcmV;M1Z4aC5v~c4BYy;SNkl#kXei*76^xD>%fqBPxh-ELip&~{TTB-li-2>z)cnkJ|TCB{`+nrJ>5oL8=w znYs7AIdf-TcpuE>{+V;~duQg(IrmP`QAZth6j6<)X_9#_4u1kT0N^Ho?FcR&0Wc0= z0>JYC<^aqCxB%d82!oAA!+uf$%CwJ2?(jd|A~}>hAF@3~@*3^>ndB=W>^qgY@K6R$ zQ_D3$`q%*`D+TG%IsiRnIM$mTdRl6@eFa=1N9@_WZnS|oXlWUt}edaOC9E=Xe}mn{AN zL-GTXU771miV7$sq+>b)Oxh%Q(r{0bfI>ieo#eKqzduR7WVtU{K$4J7S^7{~A^Ei9 z-lPFZKpJtt`GMr)1@|WpNCMKd;l8g(c9*c-7J#H7eScnIMH~f?D_M1E7{C`gnayiO zCz`)HI+zB~2jFc0f0wjra?p`oR+lMRZ50p%AT=z1v`tX}nNp3i`U${M0IP=U%cLch ze~}pS0fdr}2HOFIO|BuPhR*3s(Q1E-Hq>yN1hC}kYf^L2EP!_fZA(B(2G9b45lO>Z zzL1ibqE-)wM>q)`qpa-f6kTj%S2}lysu73q21t~b7x}IV-Ni6|H6!R%&lf=_4 zsA2;`>X1?Zgp?tr0tl%>N(m5Bgp?W}qy{NPKu8Hv7SLaY^WAkgVNnv0vVi6c=S@|{ zIu#vK7SO!m{3ih3@pvaDp(Z4gf

fv>yeqDA=DXn-ob)ic*a=0Ox%S`0lcP%iLc6h?BEqiWs}uW!ANR;Bp&KzWM1NtRP^z}ROaJ_$2{z80(cX^ z6^}kl5wt2(SYT80!GkZNx@ApJ)286iL|K}rFTY9~nEw>Z9`*HRLI zDnm*IkZP}zykl|vp58Vk0jLtBlmJ0*ocqP%_>SJYFSRAJ6r|JuLC-ngSsYioNq_RV zs#O`ztyQ$;f}|c2T`2-mt)JxA4oEhA+JY??q{AjIDZJJA9l*<$lCMiuuZN??&BAJG z#0bhZ*Mc%XB=&gNQIYhc?n}*gA2QK7$kfz?d9?t}q<|fj2fj%1iRLkrd^XgD)>x)k t_d@R9<7|bn?JSse)KNzr)hz)30u;Kah_L`anu`Dc002ovPDHLkV1h!`8B72G diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_1h.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_1h.png new file mode 100644 index 0000000000000000000000000000000000000000..8c41b8955ac55e8d2b225fd6489b5f06b5d77473 GIT binary patch literal 2540 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS^R!KxbRCodHn|p{CRTRhFw9Lvf z%5*b|EEFZul1#LRK~@w-nFK;*^tOjogb_j5`;Q1B3JR^P43nZL!lM4LG{SsfFDoBq zWo6k*)Ya^@eZK3=dguPmo!`vt%x^c^17GLfbIi^Lv^lXH$sXdjv0vX@$j!fea-3LOllYuKjM2z(T7lSuJC|QPbi@3xo?mj8;r!c+)gk)yO zH~dXOLKfpppq2g28xj;%JBdC`*IHKacPSUc+2eIo}JsBO(*Mu>QZ;8t(ZWuL!z7$_hR(5-mZxpS~y;mngj;AJ|6_yTYLz{`wr;* z8&y4ch0GClK}rp})wK@* zfNYKx1>N1n7#ruM90R$}DJ2WY#|8qtgubbiAQh4*NAPl>2J>b+S2_?|8!_z{2Ie8c z{v7ZGxEG|J-i!|hSA!Gs#0c5KGY}|eU)~J)WYWW?h0c;YGZ92a5Zv#Pd_iAN5Nibe zFrYn&M7I(b))*B~z;mYv4JrNu1KE6oP&;e0I6rUfbb3E*a7d*`xHW=)rf0vP#;AY- z&i#OL_ho(oy0*LCelY3Lq%YI55aOf_SlZ6^28#zDZB$)ZY}pmjK|0MPj@qg*xJgXh z>3TtRYA3el^nV1iJiD4M0ehjG3ofr2>|BL%R}HSH#^7a~HbIkImZ<$450(Bh^zAAp zNB3bbfG)Q`igJIhJ=xt2tJbzrbAl*RPv5LJrWSd782tLsc@>=3uH4=DXLqwxTUHGx zM>W?ZW=;@RdbqWZXZ;iXm7dP;&OvdeucUty_|DL0QjxqCd)-i;33Q(|B$K0Uq#9I< zE2`Cepck4TYyYv3Q?%7(b=xGZOUwUd(phsAeh;~}Iok(ezX7ZQZ-BSJYT|tj^w!1y zLoytesD_1xg;jHp&;$)N2$mYUb`^o+hw!oPZyJ}Nue+$n4uRt^^n;8sJ^8x_e8eOT zH^$Rc%Zx#*=3En`w-5E?d<I>F3yz!wltG zLzhr7A)lfs_fbM3La?LDa2}I1h8%*+fa7h|V$~cxgZesTaWn771F>IO$GaiYbLD0* z6>I{ojHYA#db&1o+p5K?IoAZmFZJReRUNIf`gzWbJHRIJ19*nuele7-qEKjeqD2rINSTzUFplwE!OgE^8UtZM_oP}~I6>Aan0RrRC5wVK{?=nh3QvnSW}XF}jk;DXR?Wc)`o$m(zi~8- zySU1##i}_tL2Hcy&3%Gl_g_$1wOBO=C&=1J9n+x7wIg>$JMyx{s>P}~I68Jp{WZt$$96jU9Dd)m)#rE0eOyAht7Fw_n0YD)^$CnGg+hvF(j=Z zY6f~4nY!a;ybl-y>i#HTqe;@Y(Ecq-A~@q`086GN4D)ng>kYm)SoNW2+U1!iOy#!9 z6<8mqsGiXH>`7tM^upK)L#& znmTs&#OXsc!Do;9-*P-Ow(Dv~?A zLhKEe)P&ll&<9GT{71Vo5?3xD^wE@Rs3up42Z9a25`DQosEh(T!l4{M=qq~VKCmPF zb$tnN9Ed+~qM4A5^v2XBsmMUFfpV}!IUiS1=p-$HE&!qbNb);l+FW!fALN4EkLtOPlIrYz7kmuk(IP!+GbxA}w zpAUm;vU#-qH_V0DegyQ0bv@VuwgQRXa_ZI0kw6dFj|HbiZ4PziF)XI@5bV#omW?!E zqD}>$fX))dKDCiG=Z-~!y@0+Z{R%Wn6iYFC9F#1W3f>1*iMXeN$|k0iHK^Vn zfdceR;YHwVpv_v*XG!{`Pv00W0CQPm)^My;8Ztp{1x!{y`lkTBdeOvb5!SDb7G^=B z#ahtwXf5KJ2t68I#H4KI*e%^N&^-g)Gw{EdfqwzjKSNQnR1Z)90000Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS_nMp)JRCodHnhUHQRTYMNY3Tz> zsbJe%XfT!9szE6>N&~gM5FUb}0h$;R@TwrRA`KYC5Mv@SAtt73R17LwKnxO}m#RL9=iGBnYrHG@&#blfdhI=D_Uzd+BSs9< z@CXc#z`-~Id-v|02d)M0KN#y%P1H6T%m*{ORwKy{2e$!BpXpiwH4{Tnm3pGg(K~H74*vY<~pC*7Yf~Bi@^6*I$1Y zm<+~)BY@}?@G5v7`~__4>FIfyV>2`H&s0{#P1RC$TvI2C*x z+zz&YW=THsRg9@sJ;CM!AXW2D+CEtoqgFeCZUiaXMZ;yOK(vhmmw=TZRV+K9Ux(LV!Di2|XY0ImnmfliZhDA$BUEpupls-%cdMShh! z0$y1X^nTio^+C{$1XqEVLAOacm3w4R*A(NZ$p0t zliV)nGY9z=Fx%=&_}#Q^2AYJQ1lxcnXOSjr{UfFWP2w}aXi$gNV{{qyJ!p;T)1k=U z2A5lX#=pj~51$8uwxWta$Ai>A;HIMWJ_&ox1!dPd%>(o}znas|0Li(-=a6mYBVWa+ zBGqzx`$cKQhChT+d8!&f*x#`T!wJ25=Q?biP zwH;!kBWoI1o^V=cZ5w!;KA&*>Gy1|LhOtCdc27h%9uOc6A z?Fu}N*Eomm$nUd8$Ya1CoShYKL8v>S+R#Jdl@lm;id1vqSqxe8?WWA(HI5gT7J-4T z&!s?Xiw&U9JD~Fqs;CA?x638ozT2{D0IDS--GK{)k>=5Nf{BHORs@1v2O@e2W!EmL zs@hcx*cugz?z$@fmf8t?9*7Wo~}zD(_n zM9q2@i%5Nmp7vWSfMB;qSALr%GcYPu6m43Gr?w-0Pn%ZZ z+H8yHAs-i`b`Q`fVn+X>XphL3QflZ*CF43M@+JgKkYUA3^8WICeF zt;38g_66{;(|PeIuPE_pxTLU+{0kxJ$XIYP&~jlOC~RXCjAKE4P+u&mui=JXYJlEr zy)%9ld$xN6y;VJHg^W+_ulN%n^T^+Z)aLqDpqGBj!5W~qD{H~|@RgMHVO3xl^?5{U zfV5HW>3**W6#TUz~OFk6i!GGFw<`)iKkitaGC+M>h-i6g|;}OmGu_%Q++Y${3MO47JbpjvN9271ySms9GtbI z=xMS|QpV$W0!Y0b@o}|2njXbN9}Un}^ydSujMdSv0KbFy3cBRtk2XC9d3r9YA=Kfy z-FqYZYd`dr65FG}kAoPI>L!%oqYL_f1`ZATPuN@$*j=0|5ZiHq{q~f7gC6JTGN`() z2jbwXjqs;~0?JfcefRo8&~0;0&wHC(#_kDc`>njqAFwq_wxYiSHVn8ij`|Yy*|->%LN#f6 zO21Icd~vweJ0ULzg%g218vGG>`h+P%m#Uvz?zHWe$99wHiTa$p#2ybSDZR~e1~k~m zJHOYFA9cE1T%R-M_%_3Ll8yQj^*K2}(L(Bkii*e5KE~N-Vo%-uj&QaT{jJ$Q+UTFx z4vP8`^*K2}j|5fp1-d~MmyK?d`S(48dYH4VVEEGwpR;}~;^RG$8xHZ<7x+hgP7ct$ zL4XsvjE)ZUR<+s+8UJ}^x{TMur==II0Kdb@O^f7yGfpQ4j!~cE0pj1F zGwE-|J?QkTQ%2tl8mFPtF5xr>L(3He~~JhmV4+E!D#1 z64+>o|C2yprdmehqQJmkVlM?GCo1Y6Ge1HDtAL zXduEmrMUPXN=wEbwk{TE=szq?@r= z!v4~pO3Q8PL~l@0w}lkD zA9QSB+A;@KoiaM0kEpa2doIvot<}9Gy`j}NhWCIwm}53^>?n0*fNT#Ktcl3lz}Kr6 z4V)%n-EA~6=PwgASqs{O)+DZh*Z@{DDF5O(Ov58EJOaZb@P9D^{{=&a2PPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>>q$gGRCodHoLz`jRTRf((n?E9 zD1y`^C&w(pO8Wv|g0Mg;q#o=;!6M15peHft$-v5|UM5JT9wfCyC@R8-AgCyUtfaD3 zbnIg)OEN1hQm5ZP&z;WQckOe|p7V9*G7A=W@3q(Zum4_i&c6GcyP2-8QAw;ocj9P= z3=R$s_A-?zDbpEb{6KeicYlgsXAM)FJ~TwO;ykvqs^FOo6YUMDOw9L@2IOgtMqQtf znu=~h2O?E_YF&Jyyw}&9|5SPv0zHJfB3mIv0w?qq6PHzu0@b=mLu3;~?rxBAJ~y*q z-s9MY)g_O$NRI*R1$3GNx|jYOa{unwtM5Wwx0O!@%49^+r;Wr%vCS?sZxFUYu*nnz z7T`>h+tHIv$xd~a2Edf#3Xi$yYV~-`3^a39NjYU54O~YG~fHQ&kJ*X=OFx-UR z7}Kk0m-lo5_OF!=uFi5`V_f+ z=rz^^LTti_u=r>Z<(}!{VcXc^nQmC@;^gX+ZzB4YC+|Dh&(D=07A!1On3jmc#F%>* z{YNdw6kFj1TH{IhCic_ggo|hk6BV{4YvMU@7>nv1PgZHV#d1Hal2vc&_Mq+tZWp#2 zc<4J4CtOsUyyt-RA$pmEd5nH9dB2a_@t;9oT$AQ}nDL#&o{Y!lYLj>a>dGG&F3AO) zA($L9P~~!ELx%A3U0^jCwZ64hm!JJq2J)|Vs}pgWTongz9*8VA$Q{Jiv`~5h3K&o> zR5@K)UI2Vo-c8X$gG67IFPoxVeFhJUo8eZHi9gplsI|kb{Dl)d^eEwqxM?BJC3$|{ zxR%UkINA5}7v1UDn!1oa8-t2?X48Pb^9w_}z&+t}QBH98Galcii<>yU?TgD|&r=|4 z5qvKxDU-M&BJ6zz^TdBi>_Q5m?SxO1J6<69SsZ=wrajLZWF;Rkv;1#-oMvco6n#0G z_SJ3Wwm1qevs7K6%)|^wy+TRamA74i&NC))$gsstdjE1TZU|`q%q{j$g1?p9;+O!@ zI+SM(vbO9x0N@oS_&HZW4-QF-^mU9sV}Lwq*y1KDx5Y6YliJQxpj2?nfg=5h{R3-^ z;!VQ-qA~U=anBj{(oK2Rpfbp*I2Sv>{q*m1Y?XD}ra)Xhk1=a^_p3E$5m(RQ$|~X{ zYKsC<9Bt^Vb!R2T`N-j1X}9(QMeEKh%vw9&xM6Q0Rg>run?1ciH;B0b+QWc(a1$07J(twE6O z0b#)qO2!6pI@5DuM)$az;?@!$I^hKo*Em*CJGek3)T`31=($Fw-wfN3i7P;_P2U|d z6x*XPyzcDssN-EHSA+P4f&CT5r-8-7b-n*0LD$#RVKYCFb$Os+pXJ?&yi+LYb z3D!x^5wjQv{*jL3zdTEfw?GP}NZa|i1^rh24v~K5ac4BQ)G2vyv3Ml6oBU>?+B@jo z%t#d75&h^F6esDF$Vi;qDCf4VK&D%)X!hK)w}P4Vc-#QD#2ZC(XlpzQ+Pg_`N(HVXUsZq7EJsOH1S_k$R`lCaQ9jk>BcN5 zz*)5Q^6F}|aUxZxRX;&rVsTD=R>E&oMk_E{fzb+dYz6)W_K-Aip6wG`00000NkvXX Hu0mjf)8T{W literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_silent.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_silent.png new file mode 100644 index 0000000000000000000000000000000000000000..a48c93c7ae9933ef41d0b8435540cb886e482fc6 GIT binary patch literal 1356 zcmV-S1+)5zP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS095hwpXA9~_McJu( z6K4R;^)1GL_M*>4k)faS^}>;Mv~M0j3`W*xtc?Npk#Z`e$k#`l z#3oDwG%FERsf;Rh%~sXRfV7W)DkKLS>8n=*)NG088V^^vOvoK*L}`$KWSX>*Q%{R>C>^A3n(c?$ojU@<{ZOJe5p5+-U71VXx~-_ zj@c&elZ?YlKn^%E=V)`13duV_4mk2{wLOxQGw-T(rQESAZ7 zjyC5c?sIZLx*>gPfV9U-7RIl|Cfx60OlGmm9$o^DaXKJLUtJoYVbg)N-3QG{T`;r8 zQcE!vj_Je!DY2|7OP68E^$$IL$yIznx`v9d0Xo@c&Q>E^`pH~!jmABXI9YlX$(&S^ zNt;~l2?{^^xX=PA{BW29Qqey>pLQKH&CdyQe#Fw+Hd0@8HD+KE(}{|Fc%j>M+_+x= zQJ4C=SUkSz_esc$$6x*{Xds0Ls9c1B6du9Lf&?IWi1RYiEIh<1@E{W&1J1gNB1qvu z@*I%Ds|YzDg_l`!Kw8MWRLkp7>y;V)lj}I8_LFel7wY7#MD2yTd!+`DXYeH6hFq^? z%0r-H(#MebYBZz~$f$db&;OTt&DkZ{T3!qPO8gGfcFJr?TK=)XBa~%taZbH| zEMTqzl5asr(OqQEJx|y_ix!*MDZd4V`R68O{556DpT7Vg5C{Z{A@B>@QIm(9V<+4I O0000$ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_add.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_add.png new file mode 100644 index 0000000000000000000000000000000000000000..56d9d307fa1f47938bb55cc0ddfb5ac9098de694 GIT binary patch literal 1909 zcmV-*2a5QKP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>-$_J4RCodHn`@{QRTRg)>cz|? zH7m2MG%Hi-W!Xcchhz^3gy?}5)rSlUEK;yC>Iy|deGsz3!X89Q&kvPF7}|?MP>70d z5bD)ROieQFdi7?v-@j&#)4pq-XXc!9FSFp!%&fiE+H3vK%$_|n`}FBkO36UUK*>PK zK*KW7)UcW5kXTn&*O7#|$qV&*Q&ZFK9K!aF5F!U`0KRBngq0!&AY-=AOkg`ZEjxYF zI`km>kw&hT&M-Tq>dgcls%zC4WGEs(U_SLC^E7=kGBFbX>h_(X_|@gPVBhuuU|m3u+&AqX-CP|%qm zNX7(?v;JTQ@GV5LCX^}}2pNRK^sBa1kn;=~+#Q=mw83VYMaFu63n9CrUGi%!j3CIlj5O1d^AkQU z89VbUH+`hS2qKmFG3oq5yGzFQ7@wLq7fFyNbFMs#;sdar%Ve9|*oeo4JZf-xX-;#j zQ}BLBxd*JQmK@^G0b4!Hb^1wtNSwKWcym$*Nb5jn1A!~;Y2#S-1fA*z=6D6rk5Uni zTMWCFiUB+F0rGWaif>oQ8RQ2qXnTPX_hxjfsq$!}%~W}|t7(+4D;N5To=DJIKY3?+ z5yxvOT#qM_;@K#Ud@QN-(c=hW{Q8257FboG8x6jMfGb1Vby-c9jc03_E%5rV+Vatn zL}6o)pCNtB0v*7TPL%H%4brL262+S3$1ikCM}-rl0_bN7*a4~)#i$I-g_7eXUK4`6 zzQ#~oYZVO1cTC}=1UsO^ni1rYG=x4s&OnlUh6Ho3$$qT~@<{4Wzb~X9Nw!5kNrZD< z4}$z`=zAVG2*N~d^L+cdY)PP|mzY~5{m%e@09T}&;o8^ym?Y{-kP0S;5#Twn(S!C! z)SL{fLlUVwK~`Q_bUkh+ou$ZXd`g01*eeN&A*ep{fS9E6YGy1PMy#1$yyZNE*6d|} zWDSilNRz`*uo?KG{h^VG8;!mB61$OlPYl$oed$t3ZzkwCg9%G#m>p8}$T5gZMGF>= z0>^+3u$}Q`FWcOu#}MR=AGgE6)!-7Kr7;zu{bvqVfp@^lN<$;=kZf)p=xPZf*|KKs#^ox50F(CohCp--o+qC z>xn*!A?G0N8^8`wm?S=fNLs7Hv;b-v7z=a<(egMgIM5OmeT4fYr@P5QVx0_J5h*W& zr@;^OwV$nCZ475~F_53uG}cb&d>Ci}zkxXU6NANItYO%mBy0S%Lf-nEqi^w%V-f95 z;C>J$ElF}nY(p>CfNf#DMd={>USdm(7+MUPSn${EdzTUC+{8gFLjvj%!J5+R3uL#mEhNT^ zMq*O!v+P|Rb~6qC1L!VyZNrYSwQ~3!y{0PJg#cFpS9E(%{CO5z4UnyF5RU(yv&3bG z-5{{n@Yfk}X_PwXvW*vd&hh(9=kz6Y?Ah zsyoyy@G4M0IzxQXv)X!~JJ{rE`wIGZJN@XO8H2Au*m7EZeESx(0)Hm0!8B~;gx=ST zV;so!qaAr_{M3iR4q{ugW||5TI-dY`f@(##*DDH2v%X;|Y!XOw-MeJ&MsaO@t0=g4 z3LFmJb}LVCtUJ%>g41i9@D!`FX$8<(5hl7*y$|$Cw%16vK{~23ir1vPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS@k4Z#9RCodHn+c2*MHGg2IpjVC zK@Jr`ML-R6yYfo+UPS5Q0Y_FM@{Hc1c-g{N`&vbQlO;1KfTG9-p8AvmbW+2T# znt}f*1DSs3Ra8{e0^fyPF?n-`7{xj0Q#?%vx19QRm;5hJ-Jv8+3-$NXpB<}0c>wR&gN!XRXYk|waSTGx` z2gg9Xa)^Mega_gkNYXB4jAXJ`Tq1V*sR=FtW56u179>IjVOCk4$hcz0(A7+9cPEWc z#Y|vvAhZVP4(Q#OD1^P?9HXWA|Eq3wkqHepfw_Dirth)O+PQa znpcC(&TX;?yDo=Al;bTvqp)c~9f9w0S9>k${XtEaE#B&H1bhp=aZ38w9dD9|f2j}A zD^FYmIY}7UJ&3Q21zv>)0g-H;~e`H*y}VGo6x5`r{SNcw@|O0Y$` zAq~;BnY_ZVSGXD|K}@(hXy?oll768sl2n>f55sc&wPuAz0wsu9>a;)$@%he-AxY;t zBI!rR<|=Db&%<9^giuJ(1Zk3|18ojFJ2QqPtwmas);Ts;S%dl#{BLmCDy*6cf;73N zAfHKhb7l%jI`h%pO=m!+RLAfZ{yAnts`XS6qT>?u(zf*|X}AW2XEgTUKXhm4G;A!&+7TVUqU5TqGGlFpHafCbVm@)#r~ z^ee6t1L0J`)7m(UTU8AH+uirc_+=@z*gn|{R&eEflT zV40jR6C@RZF*rZ#5pX;9xsasoKwuJDf}9yc(!JE5babQCj|6&AK^x0JB=iJn){yit zgrL&&XfYty#S8W7efIKEs{L%vTqzZZUev&qoGlBU5 z>lj4`Z`t_mRmYTifl9mdJWyA*K!i>j1O3ju3&fH?ad-%{usHhuG>O$4Y4ak8`Y^HG z1PXyo^!A#La!Ulg7uXkZo?6n7j0#ByfWIQi<0Gnmr#`8lMN19d}Z1QTDb$zyMu9VTf%h` z4F_JYwa}E1_$5f+7*ni=`Z#5Qe@y3y{wrl0HwozG+U0JJsz+Vd?iP~huLskB?V0B| z_Ju&Ffg3;}(7E%4U??bcq=7A7iMpI3!8&v+B`n1Gj8|t$OF;v}LFDLMyf=P7sf|*P zGUXEzdc7B|TWNc*?6kE6Itla=zu%x~mIN<(^(#C6-GJ9kL^qC(WySk$BT+5jtoT$* zWCbfhqcA^aGzS z!B@YDZ7`Fd`z5FjzP5E`H+KCZ;wiMZ2U~$n^rw~{p22<^NN|TG^K3t{ZXa??w&d|e zkn#{a#S-tBa;fwKS}RKl_O@U%u!*jYQg_5sNxTdM>&)Ubnk#mZ(G)I9tq{mfThocblU$WP<{$!+%Eo zT5{!{pN7| zNYEN+@_wY$-HM>5V2wwx7XHCbU%pBLGC=__WgCX5ovAG$KJ|dU@}}r(txr2{A+9PI z4>X2YvIB=M?oQAffv-FQk6|C?_K#U7K!@Wt(cNqUD0M)EtqQmWYymcz5wqhM4kWDs za=;rv{b+KIXf0X=o&cTARM_eR+ux%w7yq4egc*}*8XTPf?PS-04vx(zccZTdy1t#A zbSLUj4~XcFY^TzJbzzrdNJhyxwT^0seURKS?~wS{!8aFN4NTFR*PcAF*1VH(BG!>;Y7X8s?smG-ByPSU^NmtXg>|Q6NO3`leQ3xjX~>1)GqFU z64V4NGLrdGb>}%d?haEFz}R%=^bFA2^#{l)SJx!aw`o35LNC$flm~PqTj|AfkuGay zOkNMH-9cN>4Cu!@EyA0@mn?FJDbtc>Ak9FUfiweY2GR^vCTaq((9-|;YyCos-A6k}rvt8f4+lUw@c?usqL-Ck000qz0EnKT zm756s&o@v6`PZ)mg*b`^09Hw9BqHNDNL|j#Wil=AO~wgE+!#(4=NVjFW173;%>l&y z>`VS|R8tPz&>;ht(NLBX*kE9fSu=eWO7_jRDCDkh$iZLn7r^WBICtqmE2_Be#mNd^ zWY~+51U0XpkXq1eye$2&d_=|iB<+t-RY>cuVrVgTIH6_W8Z^udLUn;$uW3BM;c$F) zlMa$NaD6HgY~8gOA>MlXx-e}cQTX*nU%3ezOv-KHMOjI>w)bBN+XnHAX-J|8_t$EO z1Il`X!?=$da$Vt<6{W;SbxM&81;-!Uy|mzm=GJgPAIN=ny~UeMuCzxN2fGl3IDspf zGWXfwQTuH$hD&L{qc3m>Mx?^j!!Orqu)N#CuO@(-COCNi82afNf&r^LU<|(tTRJOtgDSVp~56;Glj=Z?fnUm18(@taW9v)TNeyUMN?K0c)s(j%h}FDKfX!vd|_Ua zpErZyPH!r0!ekt7tgusbTnt&~I7t=c`8xK+IX9>98;-<^ZdXYTp*TzG+X^KzH@>XH z0vaClW=N+^G=*%q6*2tO48h!Kl7v;qhkWzK3vl`1byLRECH_**lz41d9%_CmR_yU0 zil+i<6VZII&WUeE1i`=)TmCn}Q08JSPozHmV98me=?sN_0jeBTJ}?INu*;p0RFf+e zei{uB)P3HM%5hrtajngBNK#h26GDAFpjDcMLB$?+>V5e7i|@M!k9TTVr9ZcO+UO4#O#4Uv}5P6bsh3`k{Y; zFK#|XH6g1Q7uNbk8ccx1c3w915CgC3S;D-CcC`=a=!drC7O(I6Va$5OtLysrBNNGk z;dXak2Xj=}cMl0NwHSC`)wX8XyEXS3XcupccQu&)Y##ZRoh^sixW%|LPwpv0sq&-3 zO5|Nf7215qsSwoOUe(n8;<1l63Im#`HDEt$l}Ab;rN5qs$k3&jcB8z!H1uH`!*og1UZz|iB zR;Zk{0*cYh2v6fN%l^EwHwAr};INOim_H@2X(6o7d+tuu7s4eMOKKAb8 z@r1_`W4X-r)hVba5Z2adYg=w{fG&JGiuO6D3HMLesz5!IPD(E`eMWgGi%Dr_sAgko zzCw3A4P5?~kz8rM9hT=~pkk*ao#82SA2O0sQhf*5jr8jM!iBNTZt#sy&dpYgQjj$o zb@jD%?1d*xk`K%LWkK$ZUt=vifBEh@u5-2AE~U*iK3e;pdZY-nSC(Y_;_hGX#fIMb zT71=6ao>_7s=cw=-6}Dt`+&7{L43nQmD%(F0xO=JxE zAzN$ej5=wmgG*!>a?tkaYuqUBWO9{2msHTf55>+uLQJHSWTR2%3U9m~%M@9~#F`f@ zKD;zxbS5mLY2a|3G5-_Gb&w8e7uaSwCRmG$uS8rvvI?s&AJd{UgsX|Li0+atBPD;z zdkSDTTa!TVUd81u4^3bs2(EWLy{;Yz((&lF@BE&88fZ;9%pdmgvd$|yp-gMqNgFrn zvKeTIOP9-Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031 z000^Q000001E2u_0{{R30RRC20H6W@1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8 z?*IS?07*naRCodHoPB6kbri?<=u}p-wo=M1&B8TS|A=94R)35nBYPpjUeK~vup%NT zC@D2`DN@)!(HlgN2Kt9kMz0bY_M#-^l2ja{$rjo)w$ikzbA8Ukeh+tN=f3RO-LvOD zdk%cL_xC;LcYf!b-TS-0=iZ-|loX{{fno)U6)0AqSb<^%Vy-|>PtO=o1rL6S#K96z?7aU2oe*tmHlJHS&3j&Dc3Uc1@H{U0zXn#C9-wyolS0CSj^lBGe zHh)Jv$66qX0iPR;h~;%k@M;?ac|RkIw>U&5|*gUR+K1utTpdryOQ+=e_1k&?!zeyTJ6%N~g z)-}St4i11YIfX$Rlb!g9MTjeOlE!8OgMZy?4EQ0jJY?{4n^nV0PNS8+o<83yE`47v zpp%vZ5as=hb4W0Llq+bN4&2jz-Y;BiKKIzU(-mSr%II{F!F^0MGmJY7F7GJ*h_WV{3*@igqXI0Y?e`?zu56_#OPrKdAj38}6n{lJ z1C|o;D@N3_NV?A8o8bOdy!?QzDYyc8l5F7oCr{g*KITr`k%G$Aw#&6W$H@g-Ai0uA z^c_#K?(`~mqK@sVEzOF8El_W=UmHnJF*u<*4ZgC_3nV{2^__sA;{w^=up zkwvRlWI-rTG%cq!LA%tdq+yp#ihnC*0+EkX(YI5$lZun3^%|$MpbJFOR~m(AH8`Q< zv96_~&a7mS4C9;`X|Qr0+3`vDV;(y29WO7vvR0apXJvM?mM-0=F6T z5$xsL*yKKBNr}u;zi9``CV5SgeU_-Vfb)&$U+Y~pYgKwDi6R@Z?Xn(s%6~37O^UOC zXy5ROcq0kF<)gd9;CBdTT|s@emGpM3G#un3b*E2I`{5t8bQD!~h}>`Jz7x(WP@7?V z7mkMYg_#kPMKv4bmvGl{_55S#gqjD=Q9Ai$ze%{1QphXFDmW>U)+OPUt1R|D1vh{$ zuo5&-9Q|_xI{o%k7LmI_jeoQ~@-}_^x5!YWM833l2@?Mlpsxz2&K$9M8CWtSV`QDs zBe9=-tb8nv9A(3mwQH^4GQjFDw_3q|I3zdOX!SeLBHM9l&4O4Y#&LgoUTTdKg(H^G zuNo2k$X1x0z>-zkhn|SFUalmuDTvJrvs9pq9Lt@bsgF zPv%pBJY5DNe_~wt|ESlMkYwfk)1inJk_F&RuJ4FBlC=EC0zW^u-$X zxt`gx_P*!ddtP(7A1pX`owN5@=ev8az0cZfAJkDt9d%@gLVs{;l6m_d?gTIcKr?__ z0JHCCW!3=s(Xr){`8YSAv#%4Bt+&A%8+0Q3(3mb05LKB%jC|LG2!c zH<3IiVm(m^T1N7(5+n&$=Yb$;&O1FuuCa#kI0!0`Y$Dl8a(@Yuq~(svilD1We&;c6 zxp|m!>Wo5ASk5H*Fv%{D9qm~VB>&(~4uiyrK2u@6@VVkjM*;y57(T(gJ2X0ZbiAVMW+$-p0FPs7s6J6%<`5NSVz5?p3Zk55Q4) z0%j{?BxJk=j%eg-?tfC`B{6m@!IYRBe>q*OE98iGn-SGj z-z!Rey*?kbL@6L6&*F%$0!d30f^7771_ybjBTAWhVS>V4ObcO3jCi#PLkve;2w)9> zafHf0bsvU-^+?lTICmtzUXdhjUYh}fX5Vl z6M*X#{cc5fYj9AD1i`H1f2QcQfv7{#6^X1>f&}jYJQn9h zwMdY3nYD`kYsaK;ilW;U9Ml>?GJp9bJkbkbnWB?v!c0Y9Y-wSF4l5TnRAX%hcz+wf zwaRTbnK-nK+W=f<>AH;!AxLvz3x*j%vjCiB>3;Dfd}@w-(A#~OAkBfb0$A*b73C3Q zESvrWu+TC8X)u{=Ha4oyl|aybY6e03qoIYt*n{?QFBo=`9G5ad5^#TyWLt^4##@c?UVG19DU-%}|mTmXiF4-GLhsr9;4cFl7hF*RX%BgM9wF~KIEvV1DdQ`lbC5uhHb4{AuDCL~Qq#kgDUZT8e$kK9)d5hmx z&335ZRU@li&v%*RC2d9FxPOU5ZLsvIE^KDK>-kgDQuZq6WC!$m0Iz1aBXTHG@^T5e0@&iYrqira*r_dvAkUx2nI8H)PA8M~d7Q+_8S;6Y gI_jvSj(^b diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_videocall.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_videocall.png index 838720c4f6e670aab75f8b1b5a3e34aa9c9158f7..97da5f1a6aacbdd8221cd8c4897cb836fdbb8382 100644 GIT binary patch delta 1105 zcmbQn@r+}FNGZx^prw85kH`QX@Rme0>?TfNTy1#`a7G79fieh^2s-fq{7e zBLg##W(0{XV1mnfEMP{kK?)}ry1fS~zu@WO7*fIbcJ}^k5l4~Z@Bc7rUYX#;Dk^Qw z${N_*!69Z=FSapwcSC(cYp-UG4y$#p(m&oTMK;Ay1&%I`e+=A;i`;Zwj^6m8{QSAB z`RtoJw_8`M?UcU${XuHlz5bi;Ys$;s=Y3y#(ZGMjQuH%%x4$tU$9qtHGzvE8un`Pyp&k}sIJFJ`JT-pO~w)S6?e3o%BOjwb0EU`VWp0?H6R&7@LkbOinE;P4~V?uWHWY?a_FEr|J zotG|g?z?WePA0w}!|0*krfg0rx8++O2;Hune*fwulcp^5CzWrG?-pW95Rh5%fYY_$ z^zz*37w=u>w>pX*GdeG3?!WG+;W{6MbREtjnTUhUS=N~`Ngv+2-(T!nB!4_LB+7T) zuH>gtO8J@>C+}R~!uDXwXHOrM!l=)St{a-UG(u@sX^21cp4^J?ZF zOG6VXEhFp0&z{~B=g#YM{A;b$jE;-PUw%FRjqCjB zv%B*8?!4#wXw{y*v#!|i+&rhaIo5JEM(Xk_!9YuO~nRSP|xNW^Xe^TwiC)Gd0BW2CQUmV-+bM2G8k*45TZN5LW^Sqgt z$AplH^=*?@w{gs6mdW0ccF?#j>nQu|4fk7@7`$)V)ONjVZESe(@?Q#TPjJ=UGCF#H z|0@1XT${sQvp;zoR6aqX@ZWpWuIXGSUkZdA*SaqKmRtMZb1TJ<<|kRMZuI*l@w%!j z%cwo@FK_q>G0xI8TjEcL7D?E)c)7k&4_Wm!UDGjQ$y;A91y4Qmo$8*MIbKQ?EYqWG z?%mcpy_mav!hAM?-}&zxV!Wu} z2Z#{@f{1z$Pw|7`K>|SpL2`&EJqZ2;4;}>nfe-}`f`@=7B?u9+r~%J{5D^igF+_tG zgNmADeJboMlb)LC*=3W=_Ey2mc2`&TRz2yN-JO|qbeI_dBY$87jDQg^0!F|H7y%<- z1dM&>xu>8vj33HeivZai zSMp8WNsJvvpMRoY&+9znwY54GTKDnoQ2a%9NxqVI!YEdD*Cg7X7}OoRaNkvjSgb#V z?q~c%XsoEK0xI)y$U*T$l?YOh30xl#0oY5@gmNM1^=Q-6{o{@cn}gG=3eFFn#-zwBX7P|bL70CtldM((~3XS zrL0w9olfn?YUV-(ADnIkPF78!0s5L%Y$Ic#0ZM+kYlKQ{PH2E)r8TE%fIJ)xkOA@# z@C@4yGC&>zo?+WTZ3akg*)-Kc+d&8UP1RILp??9A%c@tKx`pD4K|h2`t_#$0BwkmZ zw)~oRY~^Q5Xgf$)bfa;KJ(>rMFD67lQnTF4dj+I(J^*!%vtS5^So}!&OXo@+2=PhP zcJj)A5~N+R%kzHg5~Jmt;=AcfNSUVs3T+3)>(0D+7!RzrRY0wNZ(csZCX`|$*BFg$ z?tgB=*A)fCUY8`!JxPCYC(}Qx_=@1t@|q#B^XO4Zf&=(p0AaT?e!}TXcRt}`Vi3;< zQHMONc?YH0M+VNIPIL^tMXrr&fI@r1Odg_=ThM9tFKqz7{*9c0a>k@050w*taU3K( zhx<)MOh~2rsL|) zah(LpPAa1!Tbbl~-Q2VK#LFQkztv=?h{@qMiEf}R?p*JEcP8~SDailT5Fp&D{^LTi uz7a42M!*Od0V7}pjDQg^0!Cns3H%4XEX#${cF%}28J29*~C-V}>aY>EvO!M_+ z&;qhK7#Q0#8CXC{fLIEM85o!sFfuR$X-1IP0w%cZgayn9Hb|kpJy!=%`3z4N$B+uf zw^tqWZW{=&UfA{e8-r#1#N@9UH=i@vdTuH|sidvkk>h!6di{I`J)xO0=Vr@4zirOX z$i%`Spy1HJKyAhWU#91uf0|tT9I-xmZ*S>qqqKpK-qXx?B5y z{rY1K^Nv+XX0K15_jOBX(LBRz58rLwx_;H)WQWiCHRlz3AOExceCFzXm*V#k?YqOT ze)yh|#*_K)^v>&__k8Pn?9{&J`mMTaZ+`Df3r;w{-ul{|qHojodh6c({ATH`@cr?B zzt)zv%Gz1{yLA7Up?#UftIf*y{Fh%oe?Cs<@4FS>qjr6t_g-Gr;koVXeKy%F8B-7c znO{|TZJz!5z1QcJM_9cM{MV}c^h;JSt31 zn8>L*yf6Q96D6wZr!f58xoh!l`yEf;=vGh9t2)1VdRF}3e}PP2e!uF=`~P6t=Iw7{ zcfGVdAGhl6*MBv3^Fhhxefqr0sMV(5`$~6IuYJ3`>b}I4%jXWyYOcT4Rd%I1_wDMU z{}R{!bl1zhE?u*IV_xmEc{|JJZTvO+xlsAMuZ7PRzALTtw-=^G`UhpGDAs>W^Ifhq U229cF%}28J29*~C-V}>aY>EvO!M_+ z&;qhK7#Q0#8CXC{fLIEM85o!sFfuR$X-1IP0w%cZgayn9Hb|kpJy!<<1FMLqi(^Oy z;+<$Kk-hB+$UXqQJmNW#)o; z2X^eUes}L>NtK)Sp4COMPZyoqcS?O~?9}OxKmJ%>SLBc|t>MYeHJ|*Bme*W8(0kMP zrRKbbBRf`YdT)IEW&P4`J0C4%d|=ObvLNi~Vr9?ZVt-)|WfiGjl|zr!qM!Bno483$ z)tSUnVeLM_%sEu*uFlNFi{ICs{eSn^B(dU({E$VSx<@!>9;#k^Nrh{pa)MrFNS6m= zP>Y{xuh#^PD_yM5Cc9a7Z)p(dp5r9N>Q$muQ1|Zg_0nc*qkfaDotHU6_+M??W$&S4 zcXZwJ;w#+_?iy)Y?U^PMJwoR$Zew7&>QJ~VZ{^=Op^uu|n3rWK1@KOpwN9&Xo2p>u zlLL+l>>kdOO^O&4ConH@oor$>LEyvzjy03qnA#i~uUTB~_E%;p>WSD8nIolmq3PI_ zIbkVMiUGZx-esaw-8i-^(Vcg>+f$k4lf;F<@^6_f4ze?io~Lf|Q)Zd9`Lis4>P$C| zD;rgL^{2-Ibsg^eZZgLg$nbC5QgKt~5=Udyo09Xve3w`Jnt5m9na_=1V&`NQl^hn| zvo_f5Yt3T$hs*hj**Hyj%I}9x_Er`;v3=^{@9GoXR4#m2^doG7ihUxt-I@B!G}miU^;hS^Uq7i;S$yk``PuEaYeD?y z#XmioS)x*;+pVAP(W}kear%6mWMkUQBlk87US<;1Sa#Q=K$m06y=Aq1nJ4#j_GOyS zx_)T(i!`@0Gn^lI`s{BEef?zq2Fu-|H!m2U{A{zyR52h&`cdThX-{r`>EXRqTXkV| z@kcc#d((x#>MktFd=&7Q!$jogv)B8sP5C`Z{gwW7#emOl>#E$otW0iHn6T8a##zZsMj?r#NQ{aT+s(Mn91DN^e1wauQg z-JFd&y>+i{F6}$o;xNta`&XUd<4H~m-ivovU0a!Ks5oKiMPJ+B5Gx|q#r?gw`Pb>n zul2XOEd^H0UVHE2X`7C}`p@s)d37?}alvF8r)bw@eXSsqBKF>Z=*kG!w}V(c>-Cbp z!yJt=3iH%fK4xrokTX~|`--8#9WADvE`7I`oHOLk=WTp-ae~#?m`iW3Ufvm2_~xaO zr`-qZyK`eNo(fMmzinNh?UhN&?o75^F0Yn0w!He)UAh6%XO zeLuwn{=6ClpLT9qv$EFx>8w-74n}my0sy9v0n)pc9jWgK z0FcTD0;F~b-0kIq{xdzFFZJJi*SPjpqyYecLvYTHC$9kK?)s%7Pr;JS|G;o>4oFYt zh;y!Elt9`C4^Ac)PBJ-cQ$*wd*im{p=z2qb{$wI^GV=?XSz4NEC#}qG(=9UjL!5y> zdGnKX7hf;r&WmSXuuk7iZ^lp$`F>w1pP`98W9FmhCn&iSVXRm@6TV<=54Tp^1LpV?MDQac99p!gMZ8z6yLMpO+UL}&d<44C61 z8y{%16sNa3nJ*zZyPUXIQuD4xjCE^v)efCY1EpFi#6h?!vwjUu1!287C~CybYp6Eh zNri=PS!^pBR0|O$w7d_Y%ZW8||hvU-|3Mi98i6w>SFrpQ|?*@akDxbEDyx z8AZZrOPO$cfJd({@`L4HU7?%{sQSCj2Y~(pP6|cR<@3#~d?|M0-m$chdBR^SsxLAv zQpW1B*4+i$YPe-R=lz{WJ{W8(uR~jnI7YlDpcRH?DD-$suS0stOQI2%coHim49&aG z8t)qn7iOSA^&X2+N*6_n%+a&FlmE2BVsd>dE$mgVCS8adZ;Oxoyh&Rw8Y$0UVrlyF zw!r!5Ydn(N8p`xQYqxhP@z8ML@WS7c(2|7j*;>D_=LP(q;ptuzp8~`v!Mg#~Gs9<~ z1?1Ymvai`9WMXhGzFZhp?Vj<~vBjKH7rZs5Ju(2+Ih zY^3Yeo?cC(sVO~;h4yToW@9};NH~47#MstsR_rf>obJ)Uk2wI*tr}S`D5jzk( zV&@WQNJ7hFCxglk+_c_Zl9$+~@$cqapzmB50?zh1HlibXzX6yg$8Yc^$4%2%nl_^a zuxe-Wtwuld^HGq&cM1gDI zO+YU+;ZhCJzj_}Mva3Rh3>R_5SIFDo@Cgs_Bbc!&h@R@1KFrL7K0#%7hmC5u14WV> zw|NtfjFAbpf|AaF!yZ4B2l~D#>bK-Vzpa>zHnnsuzRZ0b#xVJtSlinhfP0pOlo7RI zxk}$I)8njGw^sO#(s91i`H@y#_rvxY8=#wy|JbP#EfknR(D2~${S5w0+W4i2)1RHZ zBl`}+S|GwOM}OP41m(CYo%+w9(BErWiG`@|n(JjTWAuIEXw;sr;v{4#U#gf?lSvfY zi4Q{xuUb!4XU$G7G(0YK16}_F5_P^0etdkZCVhBM0xcab9FvG0QO)%j^jK3`#p#cN zc2CR7IED~c61{N3oogzN%n4dhLAeA`(+mUv!w8fHafj9shSOO&gSrMDzz z{+Un0^-=5KMJf(rl^`s_Q}{Z?ezrf4+r$0ms%!lw{m&t4P z`f7%c&h_@|5n^S7Rhd^E_E^g=B@=&RH&PrWE$TNuR@yzfXr|F7AypxTPngk3fyQe0 zKqAJoA5kgmzd3jS?PLO9M^PokNrpjC4v3fVe;}*$X*}Iz^j_Z1z3zTp+%XU5ilafy Fe*uzdpR@n~ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable/avd_flip.xml b/TMessagesProj/src/main/res/drawable/avd_flip.xml new file mode 100644 index 000000000..f39b83996 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/avd_flip.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/drawable/tg_splash_320.xml b/TMessagesProj/src/main/res/drawable/tg_splash_320.xml new file mode 100644 index 000000000..e46e5f6f9 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/tg_splash_320.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/drawable/vd_flip.xml b/TMessagesProj/src/main/res/drawable/vd_flip.xml new file mode 100644 index 000000000..3eae5f050 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/vd_flip.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/raw/bot_webview_cross_to_sheet.json b/TMessagesProj/src/main/res/raw/bot_webview_cross_to_sheet.json new file mode 100644 index 000000000..194f3f756 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/bot_webview_cross_to_sheet.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE 1.1.0","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":22,"w":400,"h":400,"nm":"Icon Cross - Sheet","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16,"s":[0]},{"t":17,"s":[100]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[-90]},{"t":19,"s":[0]}],"ix":10},"p":{"a":0,"k":[199.889,94.444,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":1,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":8,"s":[85,85,100]},{"t":19,"s":[87.8,87.8,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":17,"s":[{"i":[[0,0],[0,0],[0,0],[5.563,0.602],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-4.027,-4.787],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-137.063,-35.692],[101.551,-27.99],[108.363,7.164],[98.561,-2.186],[-115.918,-9.099],[-136.756,-0.822],[-143.844,25.663]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[0,0],[0,0],[0,0],[2.977,-0.397],[0,0],[7.855,-5.16],[0,0]],"o":[[0,0],[0,0],[-1.653,-9.205],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-131.237,-31.981],[120.492,-29.916],[120.483,30.641],[114.172,20.784],[-124.47,25.867],[-132.442,28.233],[-134.389,37.125]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[0,0],[0,0],[6.73,0],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-0.32,-6.72],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-128.5,-39],[128.5,-39],[128.5,39],[115.91,27],[-116.52,27],[-128.5,38.68],[-128.5,39]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.592156862745,0.592156862745,0.592156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[111.111,111.111],"ix":3},"r":{"a":0,"k":-0.075,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":23,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Path 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[0]},{"t":19,"s":[180]}],"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":1,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":8,"s":[85,85,100]},{"t":19,"s":[90,90,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":1,"s":[{"i":[[94.07,-96.65],[-14.5,14.885],[0,0],[-13.93,14.3],[0,0],[-13.85,13.69]],"o":[[17.57,-17.9],[0,0],[15.65,-16.01],[0,0],[9.88,-8.65],[0,0]],"v":[[-95.87,97.1],[-58.85,59.365],[-16.1,16.01],[21.13,-21.95],[67.97,-67.85],[98.45,-97.84]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[94.254,-96.761],[-14.134,15.233],[0,0],[-14.292,13.939],[0,0],[-13.501,12.621]],"o":[[16.414,-17.448],[0,0],[15.255,-16.329],[0,0],[10.344,-8.432],[0,0]],"v":[[-95.768,98.258],[-60.973,60.165],[-19.301,13.308],[18.281,-25.004],[68.572,-69.746],[99.574,-97.67]],"c":false}]},{"t":19,"s":[{"i":[[101.36,-101.05],[0,28.67],[0,0],[-28.27,0],[0,0],[0,-28.67]],"o":[[-28.27,0],[0,0],[0,-28.67],[0,0],[28.27,0],[0,0]],"v":[[-91.82,143],[-143,91.09],[-143,-91.09],[-91.82,-143],[91.82,-143],[143,-91.09]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[22]},{"t":19,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[78]},{"t":19,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":23,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Path","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[-90]},{"t":19,"s":[0]}],"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":1,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":8,"s":[85,85,100]},{"t":19,"s":[90,90,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":1,"s":[{"i":[[94.07,-96.65],[-14.5,14.885],[0,0],[-13.93,14.3],[0,0],[-13.85,13.69]],"o":[[17.57,-17.9],[0,0],[15.65,-16.01],[0,0],[9.88,-8.65],[0,0]],"v":[[-95.87,97.1],[-58.85,59.365],[-16.1,16.01],[21.13,-21.95],[67.97,-67.85],[98.45,-97.84]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[94.254,-96.761],[-14.134,15.233],[0,0],[-14.292,13.939],[0,0],[-13.501,12.621]],"o":[[16.414,-17.448],[0,0],[15.255,-16.329],[0,0],[10.344,-8.432],[0,0]],"v":[[-95.768,98.258],[-60.973,60.165],[-19.301,13.308],[18.281,-25.004],[68.572,-69.746],[99.574,-97.67]],"c":false}]},{"t":19,"s":[{"i":[[101.36,-101.05],[0,28.67],[0,0],[-28.27,0],[0,0],[0,-28.67]],"o":[[-28.27,0],[0,0],[0,-28.67],[0,0],[28.27,0],[0,0]],"v":[[-91.82,143],[-143,91.09],[-143,-91.09],[-91.82,-143],[91.82,-143],[143,-91.09]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[22]},{"t":19,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[78]},{"t":19,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":23,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/bot_webview_sheet_to_cross.json b/TMessagesProj/src/main/res/raw/bot_webview_sheet_to_cross.json new file mode 100644 index 000000000..f7b3df250 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/bot_webview_sheet_to_cross.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE 1.1.0","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":22,"w":400,"h":400,"nm":"Icon Sheet - Cross","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[100]},{"t":4,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[-0.737]},{"t":20,"s":[-90]}],"ix":10},"p":{"a":0,"k":[199.889,94.444,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":1,"s":[90,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":12,"s":[85,85,100]},{"t":19,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":1,"s":[{"i":[[0,0],[0,0],[0,0],[6.73,0],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-0.32,-6.72],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-128.5,-39],[128.5,-39],[128.5,39],[115.91,27],[-116.52,27],[-128.5,38.68],[-128.5,39]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":2,"s":[{"i":[[0,0],[0,0],[0,0],[6.73,0],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-3.868,-6.262],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-117.276,-35.38],[109.015,-34.936],[128.983,11.495],[120.865,12.05],[-116.52,27],[-126.06,31.653],[-128.5,39]],"c":true}]},{"t":3,"s":[{"i":[[0,0],[0,0],[0,0],[6.73,0],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-3.868,-6.262],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-102.392,-18.806],[87.683,-27.969],[106.014,-6.856],[93.212,-8.892],[-75.63,-10.574],[-97.414,3.029],[-107.412,16.44]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.592156862745,0.592156862745,0.592156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":22,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Path 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.262],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[180]},{"t":20,"s":[0]}],"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":1,"s":[90,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":12,"s":[85,85,100]},{"t":19,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":1,"s":[{"i":[[101.36,-101.05],[0,28.67],[0,0],[-28.27,0],[0,0],[0,-28.67]],"o":[[-28.27,0],[0,0],[0,-28.67],[0,0],[28.27,0],[0,0]],"v":[[-91.82,143],[-143,91.09],[-143,-91.09],[-91.82,-143],[91.82,-143],[143,-91.09]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[94.254,-96.761],[-14.134,15.233],[0,0],[-14.292,13.939],[0,0],[-13.501,12.621]],"o":[[16.414,-17.448],[0,0],[15.255,-16.329],[0,0],[10.344,-8.432],[0,0]],"v":[[-95.768,98.258],[-60.973,60.165],[-19.301,13.308],[18.281,-25.004],[68.572,-69.746],[99.574,-97.67]],"c":false}]},{"t":13,"s":[{"i":[[94.07,-96.65],[-14.5,14.885],[0,0],[-13.93,14.3],[0,0],[-13.85,13.69]],"o":[[17.57,-17.9],[0,0],[15.65,-16.01],[0,0],[9.88,-8.65],[0,0]],"v":[[-95.87,97.1],[-58.85,59.365],[-16.1,16.01],[21.13,-21.95],[67.97,-67.85],[98.45,-97.84]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[0.915]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0.509]},"t":2,"s":[12]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[22]},{"t":19,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[78]},{"t":19,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":22,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Path","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.262],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[0]},{"t":20,"s":[-90]}],"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":1,"s":[90,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":12,"s":[85,85,100]},{"t":19,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":1,"s":[{"i":[[101.36,-101.05],[0,28.67],[0,0],[-28.27,0],[0,0],[0,-28.67]],"o":[[-28.27,0],[0,0],[0,-28.67],[0,0],[28.27,0],[0,0]],"v":[[-91.82,143],[-143,91.09],[-143,-91.09],[-91.82,-143],[91.82,-143],[143,-91.09]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[94.254,-96.761],[-14.134,15.233],[0,0],[-14.292,13.939],[0,0],[-13.501,12.621]],"o":[[16.414,-17.448],[0,0],[15.255,-16.329],[0,0],[10.344,-8.432],[0,0]],"v":[[-95.768,98.258],[-60.973,60.165],[-19.301,13.308],[18.281,-25.004],[68.572,-69.746],[99.574,-97.67]],"c":false}]},{"t":13,"s":[{"i":[[94.07,-96.65],[-14.5,14.885],[0,0],[-13.93,14.3],[0,0],[-13.85,13.69]],"o":[[17.57,-17.9],[0,0],[15.65,-16.01],[0,0],[9.88,-8.65],[0,0]],"v":[[-95.87,97.1],[-58.85,59.365],[-16.1,16.01],[21.13,-21.95],[67.97,-67.85],[98.45,-97.84]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[22]},{"t":19,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[78]},{"t":19,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":22,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/durgerking_placeholder.svg b/TMessagesProj/src/main/res/raw/durgerking_placeholder.svg new file mode 100644 index 000000000..3ab775b1c --- /dev/null +++ b/TMessagesProj/src/main/res/raw/durgerking_placeholder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/mute_for.json b/TMessagesProj/src/main/res/raw/mute_for.json new file mode 100644 index 000000000..1ec4f52fd --- /dev/null +++ b/TMessagesProj/src/main/res/raw/mute_for.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":61,"w":512,"h":512,"nm":"Mute for","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.05,"y":0},"t":0,"s":[256,404,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[256,218,0],"to":[0,0,0],"ti":[0,0,0]},{"t":24,"s":[256,256,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.05,0.05,0.05],"y":[0,0,0]},"t":0,"s":[0,0,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":16,"s":[103,103,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":29,"s":[96,96,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":40,"s":[102,102,100]},{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":51,"s":[99,99,100]},{"t":60,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Z","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28,"s":[100]},{"t":35,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[-18.201,18.449,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":26,"s":[128.01,-129.801,0],"to":[0,0,0],"ti":[0,0,0]},{"t":35,"s":[166.212,-157.57,0]}],"ix":2},"a":{"a":0,"k":[135.35,-152.7,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[137,137,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":17,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":26,"s":[85,85,100]},{"t":35,"s":[40,40,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-9.2],[1.8,-2.7],[0,0],[0,0],[0,-9.3],[7.5,0],[0,0],[2.9,2.3],[-4.9,7.2],[0,0],[0,0],[0,7.6],[-7,0.5]],"o":[[9.2,0],[0,3.3],[0,0],[0,0],[7.1,0],[0,9],[0,0],[-3.7,0],[-7,-5.4],[0,0],[0,0],[-7.1,0],[0,-7.6],[0,0]],"v":[[158.6,-205],[175.3,-188.3],[172.5,-179.1],[132.7,-127.3],[165.2,-127.3],[178.6,-114.1],[166.1,-100.4],[112.1,-100.4],[101.9,-103.9],[98.2,-126.4],[137.9,-178.1],[105.5,-178.1],[92.1,-191.5],[104.6,-204.9]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":26,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Body","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.514],"y":[0]},"t":0,"s":[15]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":13,"s":[-10]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":26,"s":[7]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":37,"s":[-3]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":48,"s":[1]},{"t":60,"s":[0]}],"ix":10},"p":{"a":0,"k":[-21.031,-93.65,0],"ix":2},"a":{"a":0,"k":[-21.031,-93.65,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.2,"y":0},"t":34,"s":[{"i":[[0,0],[0.012,-0.589],[0.466,-0.029],[0,0],[0.183,0.136],[-0.348,0.53],[0,0],[0,0],[0,0.613],[-0.466,0.029],[0,0],[0,-0.666],[0.124,-0.189],[0,0]],"o":[[0.466,0.029],[-0.012,0.583],[0,0],[-0.23,-0.018],[-0.519,-0.383],[0,0],[0,0],[-0.466,-0.029],[0,-0.607],[0,0],[0.666,0],[0,0.23],[0,0],[0,0]],"v":[[-60.566,62.774],[-59.7,63.699],[-60.566,64.625],[-64.797,64.625],[-65.428,64.395],[-65.723,62.768],[-62.169,57.941],[-65.328,57.941],[-66.194,57.016],[-65.328,56.091],[-60.896,56.091],[-59.688,57.299],[-59.876,57.941],[-63.442,62.78]],"c":true}]},{"t":60,"s":[{"i":[[0,0],[0.2,-10],[7.9,-0.5],[0,0],[3.1,2.3],[-5.9,9],[0,0],[0,0],[0,10.4],[-7.9,0.5],[0,0],[0,-11.3],[2.1,-3.2],[0,0]],"o":[[7.9,0.5],[-0.2,9.9],[0,0],[-3.9,-0.3],[-8.8,-6.5],[0,0],[0,0],[-7.9,-0.5],[0,-10.3],[0,0],[11.3,0],[0,3.9],[0,0],[0,0]],"v":[[20.9,58.7],[35.6,74.4],[20.9,90.1],[-50.9,90.1],[-61.6,86.2],[-66.6,58.6],[-6.3,-23.3],[-59.9,-23.3],[-74.6,-39],[-59.9,-54.7],[15.3,-54.7],[35.8,-34.2],[32.6,-23.3],[-27.9,58.8]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-19.4,17.7],"ix":2},"a":{"a":0,"k":[-19.4,17.7],"ix":1},"s":{"a":1,"k":[{"t":20,"s":[0,0],"h":1},{"t":34,"s":[100,100],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.6,"y":1},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[0.034,-1.69],[1.335,-0.084],[0,0],[0.525,0.388],[-0.997,1.521],[0,0],[0,0],[0,1.757],[-1.335,0.084],[0,0],[0,-1.909],[0.355,-0.541],[0,0]],"o":[[1.335,0.084],[-0.034,1.673],[0,0],[-0.659,-0.051],[-1.487,-1.098],[0,0],[0,0],[-1.335,-0.084],[0,-1.74],[0,0],[1.909,0],[0,0.659],[0,0],[0,0]],"v":[[-12.59,24.628],[-10.107,27.281],[-12.59,29.934],[-24.723,29.934],[-26.531,29.275],[-27.376,24.611],[-17.187,10.772],[-26.244,10.772],[-28.728,8.119],[-26.244,5.466],[-13.537,5.466],[-10.073,8.93],[-10.613,10.772],[-20.836,24.645]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[0,0],[0.2,-10],[7.9,-0.5],[0,0],[3.1,2.3],[-5.9,9],[0,0],[0,0],[0,10.4],[-7.9,0.5],[0,0],[0,-11.3],[2.1,-3.2],[0,0]],"o":[[7.9,0.5],[-0.2,9.9],[0,0],[-3.9,-0.3],[-8.8,-6.5],[0,0],[0,0],[-7.9,-0.5],[0,-10.3],[0,0],[11.3,0],[0,3.9],[0,0],[0,0]],"v":[[20.9,58.7],[35.6,74.4],[20.9,90.1],[-50.9,90.1],[-61.6,86.2],[-66.6,58.6],[-6.3,-23.3],[-59.9,-23.3],[-74.6,-39],[-59.9,-54.7],[15.3,-54.7],[35.8,-34.2],[32.6,-23.3],[-27.9,58.8]],"c":true}]},{"t":60,"s":[{"i":[[0,0],[0.15,-6.923],[8.798,0.25],[0,0],[2.302,1.588],[-4.375,6.231],[0,0],[0,0],[0.107,8.63],[-5.857,0.346],[0,0],[0,-7.823],[1.557,-2.215],[0,0]],"o":[[5.857,0.346],[-0.148,6.854],[0,0],[-2.892,-0.208],[-6.525,-4.5],[0,0],[0,0],[-5.857,-0.346],[-0.116,-9.391],[0,0],[8.378,0],[0,2.7],[0,0],[0,0]],"v":[[16.202,42.011],[26.602,54.13],[14.702,67.5],[-40.784,67],[-48.718,64.3],[-52.675,43.191],[-12.215,-9.511],[-45.207,-10.011],[-57.607,-22.88],[-45.957,-36],[9.8,-35.75],[25.25,-19.557],[22.877,-12.011],[-17.231,41.58]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[-66.124,69.677],"to":[0,0],"ti":[0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.167,"y":0.167},"t":26,"s":[-1.656,3.622],"to":[0,0],"ti":[0,0]},{"t":60,"s":[131.6,-150.3]}],"ix":2},"a":{"a":0,"k":[-19.4,17.7],"ix":1},"s":{"a":1,"k":[{"t":1,"s":[0,0],"h":1},{"t":14,"s":[100,100],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0.2,-10],[7.9,-0.5],[0,0],[3.1,2.3],[-5.9,9],[0,0],[0,0],[0,10.4],[-7.9,0.5],[0,0],[0,-11.3],[2.1,-3.2],[0,0]],"o":[[7.9,0.5],[-0.2,9.9],[0,0],[-3.9,-0.3],[-8.8,-6.5],[0,0],[0,0],[-7.9,-0.5],[0,-10.3],[0,0],[11.3,0],[0,3.9],[0,0],[0,0]],"v":[[20.9,58.7],[35.6,74.4],[20.9,90.1],[-50.9,90.1],[-61.6,86.2],[-66.6,58.6],[-6.3,-23.3],[-59.9,-23.3],[-74.6,-39],[-59.9,-54.7],[15.3,-54.7],[35.8,-34.2],[32.6,-23.3],[-27.9,58.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[0.148,-7.096],[5.801,-0.355],[0,0],[2.28,1.627],[-4.333,6.386],[0,0],[0,0],[0,7.38],[-5.801,0.355],[0,0],[0,-8.018],[1.542,-2.271],[0,0]],"o":[[5.801,0.355],[-0.147,7.025],[0,0],[-2.864,-0.213],[-6.462,-4.612],[0,0],[0,0],[-5.801,-0.355],[0,-7.309],[0,0],[8.298,0],[0,2.767],[0,0],[0,0]],"v":[[9.195,44.886],[19.437,57.181],[9,69.117],[-45.657,69.952],[-53.515,67.185],[-57.116,45.08],[-15.421,-10.242],[-52.369,-9.827],[-63.183,-22.112],[-52.176,-34.172],[3.034,-34.859],[18.1,-19.626],[15.75,-11.891],[-26.291,45.294]],"c":true}]},{"t":25,"s":[{"i":[[0,0],[0.125,-5.911],[6.158,0.167],[0,0],[1.924,1.355],[-3.657,5.32],[0,0],[0,0],[0,6.147],[-4.897,0.296],[0,0],[0,-6.679],[1.302,-1.892],[0,0]],"o":[[4.897,0.296],[-0.124,5.852],[0,0],[-2.418,-0.177],[-5.455,-3.842],[0,0],[0,0],[-4.897,-0.296],[0,-6.088],[0,0],[7.005,0],[0,2.305],[0,0],[0,0]],"v":[[4.126,39.89],[13.642,51.059],[4.008,62.091],[-44.717,61.966],[-51.35,59.661],[-54.367,40.413],[-20.426,-3.835],[-49.379,-3.843],[-58.889,-14.427],[-49.961,-25.495],[-0.549,-25.64],[12.327,-12.359],[10.344,-5.916],[-24.855,40.148]],"c":true}]}],"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[-19.4,17.7],"to":[0,0],"ti":[0,0]},{"t":26,"s":[131.763,-130.207]}],"ix":2},"a":{"a":0,"k":[-19.4,17.7],"ix":1},"s":{"a":1,"k":[{"t":17,"s":[100,100],"h":1},{"t":26,"s":[0,0],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[12.7,12.4],[0,0],[0,2.5],[0,0],[57.3,13.9],[0,0],[15.9,0],[0,-14.1],[0,0],[0,-60],[0,0],[1.7,-1.9],[0,0],[-18,0],[0,0]],"o":[[0,0],[-1.5,-2],[0,0],[-1,-60],[0,0],[0,-14.5],[-14.8,0],[0,0],[-56.3,15.2],[0,0],[-0.2,2.5],[0,0],[-11.8,12.7],[0,0],[17.8,-0.7]],"v":[[130.1,110.1],[105.8,82.8],[103.5,75.9],[103.5,-8.2],[4.7,-128.3],[4.7,-141.5],[-22.1,-167.7],[-48.3,-141.5],[-48.3,-128.4],[-143.6,-5.9],[-143.6,76.9],[-146.5,83.6],[-170.8,110.8],[-151.8,144.4],[112.6,144.4]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Bottom","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.514,"y":0},"t":2,"s":[-58.416,164.067,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":16,"s":[9.925,165.08,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":29,"s":[-38.506,164.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":40,"s":[-6.869,164.433,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":51,"s":[-26.011,164.7,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[-20.011,164.7,0]}],"ix":2},"a":{"a":0,"k":[-20.011,164.7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.7,-0.3],[-0.8,19.1]],"o":[[0,20.2],[-21.7,0.2],[0,0]],"v":[[21.2,164.7],[-20,202.8],[-61.2,164.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/sound_download.json b/TMessagesProj/src/main/res/raw/sound_download.json new file mode 100644 index 000000000..d323a10f4 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/sound_download.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":66,"w":512,"h":512,"nm":"Sound Download 2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.764],"y":[1]},"o":{"x":[0.683],"y":[0]},"t":4,"s":[-5]},{"i":{"x":[0.44],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":15,"s":[2]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.576],"y":[0]},"t":23,"s":[-1]},{"i":{"x":[0.517],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":32,"s":[2]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.545],"y":[0]},"t":39,"s":[-1]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":47,"s":[2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":56,"s":[-1]},{"t":65,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.59,"y":1},"o":{"x":0.236,"y":0},"t":0,"s":[256,416,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.4,"y":0},"t":11,"s":[262,232,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":19,"s":[256,284,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.4,"y":0},"t":28,"s":[256,256,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":34,"s":[256,284,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":43,"s":[256,236,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":52,"s":[256,300,0],"to":[0,0,0],"ti":[0,0,0]},{"t":63,"s":[256,256,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":0,"s":[60,10,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":11,"s":[90,110,100]},{"i":{"x":[0.6,0.6,0.6],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":19,"s":[105,95,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":28,"s":[95,105,100]},{"i":{"x":[0.6,0.6,0.6],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":34,"s":[105,95,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":43,"s":[95,105,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":52,"s":[105,95,100]},{"t":63,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":1,"op":179,"st":-1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Arrow 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.8,"y":1},"o":{"x":0.7,"y":0},"t":36,"s":[395,27.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.2,"y":0},"t":51,"s":[395,219.333,0],"to":[0,0,0],"ti":[0,0,0]},{"t":62,"s":[395,141.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[117,-105.5],[139.054,-69],[161,-105.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[62,-80],[139.188,-36.333],[216,-80]],"c":false}]},{"t":62,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.038,-110],[139.02,-69.849]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.125,-172],[139.071,-37.349]],"c":false}]},{"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.063,-193],[139.063,-37.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":36,"op":213,"st":33,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arrow 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.744,"y":0.482},"o":{"x":0.477,"y":0},"t":16,"s":[395,41.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.615,"y":0.728},"o":{"x":0.312,"y":0.353},"t":28,"s":[391,145.474,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.581,"y":1},"o":{"x":0.265,"y":0.596},"t":34,"s":[401.815,238.274,0],"to":[0,0,0],"ti":[0,0,0]},{"t":42,"s":[399,277.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[103,-112.817],[139.088,-93],[175,-112.817]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]},{"t":38,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[139,-86.5],[139,-51.833],[139,-86.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.066,-130],[139.033,-93.461]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.125,-167],[139.063,-37.5]],"c":false}]},{"t":38,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.5,-102],[139,-53]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":16,"op":38,"st":-1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arrow 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.746,"y":0.458},"o":{"x":0.463,"y":0},"t":4,"s":[395,105.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.489,"y":1},"o":{"x":0.267,"y":0.449},"t":12,"s":[395,167.999,0],"to":[0,0,0],"ti":[0,0,0]},{"t":23,"s":[401,277.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[93.085,-94.664],[139.112,-63],[184.915,-94.664]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]},{"t":20,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[139.25,-103],[139,-51.833],[139.25,-103]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.084,-137],[139.042,-63.736]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.125,-167],[139.063,-37.5]],"c":false}]},{"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.5,-103.5],[139,-53]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":20,"st":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"R","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[88.174,82.369,0],"ix":2},"a":{"a":0,"k":[88.174,82.369,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.566,"y":1},"o":{"x":0.61,"y":0},"t":0,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.904,-49.445],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[119.406,-46.501],[136.514,-43.354]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[162.959,25.276],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[122.462,28.22],[139.57,31.366]],"c":true}]},{"i":{"x":0.287,"y":1},"o":{"x":0.451,"y":0},"t":22,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.226],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.305,-51.745],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.808,-48.801],[135.916,-45.654]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":34,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.027,13.718],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.529,16.663],[135.637,19.809]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.599,"y":0},"t":42,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.226],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.611,-74.745],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[119.114,-71.801],[136.222,-68.654]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.2,"y":0},"t":51,"s":[{"i":[[-4.316,1.274],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-3.48,-4.272],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.226],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[160.128,43.818],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[111.637,55.698],[111.65,43.878],[135.309,47.714]],"c":true}]},{"t":62,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.452,6.555],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.955,9.499],[136.063,12.646]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":181,"st":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"L","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-58.912,2.378,0],"ix":2},"a":{"a":0,"k":[-58.912,2.378,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.82,"y":1},"o":{"x":0.279,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[48.175,-182.632],[48.165,-140.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.458,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[94.175,-189.632],[94.165,-147.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.837,"y":1},"o":{"x":0.66,"y":0},"t":22,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[62.175,-183.632],[62.165,-141.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.82,"y":1},"o":{"x":0.3,"y":0},"t":34,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[90.175,-190.632],[90.165,-148.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.66,"y":0},"t":42,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[63.175,-182.632],[63.165,-140.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.2,"y":0},"t":51,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[88.175,-187.632],[88.165,-145.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"t":62,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[88.175,-187.632],[88.165,-145.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":179,"st":-1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/sound_off.json b/TMessagesProj/src/main/res/raw/sound_off.json new file mode 100644 index 000000000..cca176358 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/sound_off.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":61,"w":512,"h":512,"nm":"Sound Off","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.507],"y":[1.085]},"o":{"x":[0.595],"y":[0]},"t":0,"s":[28]},{"i":{"x":[0.95],"y":[1]},"o":{"x":[0.7],"y":[0.283]},"t":14,"s":[-7]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[10]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":36,"s":[-5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":41,"s":[5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":46,"s":[-3]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":52,"s":[1]},{"t":60,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":0,"s":[326,365.957,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.8,"y":1},"o":{"x":0.6,"y":0},"t":20,"s":[247.971,230.719,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":32,"s":[283.5,285.957,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":44,"s":[276,239.957,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[276,255.957,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.1,0.1,0.1],"y":[0,0,0]},"t":0,"s":[20,0,100]},{"i":{"x":[0.95,0.95,0.95],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.8],"y":[0,0,0]},"t":18,"s":[90,104,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":30,"s":[90,75,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":37,"s":[105,105,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":42,"s":[97,97,100]},{"t":48,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Line","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6.25,1.35,0],"ix":2},"a":{"a":0,"k":[6.25,1.35,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.6,"y":1},"o":{"x":0.8,"y":0},"t":19,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-194.619,-190.263],[168.481,158.037]],"c":false}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":32,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-145.787,-140.476],[207.235,196.36]],"c":false}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":37,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-185.469,-181.453],[165.552,155.752]],"c":false}]},{"t":43,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-175.3,-172.8],[187.8,175.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":34,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":19,"s":[0]},{"t":30,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":19,"s":[0]},{"t":30,"s":[3]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":21,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Top Top","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[38.282,-48.297,0],"ix":2},"a":{"a":0,"k":[38.282,-48.297,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.1,"y":0},"t":3,"s":[{"i":[[0,0.1],[0.8,0],[0,0],[0,0],[-6.4,1.5],[0,0]],"o":[[-0.2,-0.9],[0,0],[0,0],[-1.266,-33.912],[0,0],[23.1,-4.8]],"v":[[184.317,-78.65],[182.517,-80.15],[-106.368,-35.177],[-147.331,-33.019],[-115.272,-76.324],[174.017,-120.15]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[0,0.1],[0.8,0],[0,0],[0,0],[-6.4,1.5],[0,0]],"o":[[-0.2,-0.9],[0,0],[0,0],[-1.266,-33.912],[0,0],[23.1,-4.8]],"v":[[120.8,-149.7],[119,-151.2],[-59.396,-113.953],[-100.359,-111.795],[-68.3,-155.1],[110.5,-191.2]],"c":true}]},{"t":19,"s":[{"i":[[0,0.1],[0.8,0],[0,0],[0,0],[-6.4,1.5],[0,0]],"o":[[-0.2,-0.9],[0,0],[0,0],[-1.266,-33.912],[0,0],[23.1,-4.8]],"v":[[120.8,-149.7],[119,-151.2],[-59.396,-113.953],[-100.359,-111.795],[-68.3,-155.1],[110.5,-191.2]],"c":true}],"h":1},{"t":25,"s":[{"i":[[0,0.1],[0.8,0],[0,0],[0,0],[-6.4,1.5],[0,0]],"o":[[-0.2,-0.9],[0,0],[0,0],[4.8,-4],[0,0],[23.1,-4.8]],"v":[[120.8,-149.7],[119,-151.2],[-54.3,-116.3],[-85.3,-146.7],[-68.3,-155.1],[110.5,-191.2]],"c":true}],"h":1}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Top Bottom","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[38.282,-48.297,0],"ix":2},"a":{"a":0,"k":[38.282,-48.297,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.1,"y":0},"t":3,"s":[{"i":[[-4.3,-19.24],[1.331,-8.002],[12.42,-8.541],[5.324,5.994],[0,0],[0,0.083],[0.8,0],[0,0]],"o":[[1.5,6.552],[-0.957,5.754],[-6.18,-7.561],[26.409,-1.342],[0,0],[-0.2,-0.746],[0,0],[28.171,-4.938]],"v":[[219.954,-90.552],[219.845,104.803],[203.836,131.006],[138.861,57.639],[178.453,62.603],[180.6,-78.452],[178.8,-79.696],[169.299,-118.145]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[-4.3,-23.2],[1.331,-9.649],[12.42,-10.298],[5.324,7.227],[0,0],[0,0.1],[0.8,0],[0,0]],"o":[[1.5,7.9],[-0.957,6.939],[-6.18,-9.117],[26.409,-1.618],[0,0],[-0.2,-0.9],[0,0],[23.1,-4.8]],"v":[[160.9,-157.8],[162.191,105.885],[146.183,137.481],[81.208,49.015],[120.8,55],[120.8,-149.7],[119,-151.2],[110.5,-191.2]],"c":true}]},{"t":19,"s":[{"i":[[-4.3,-23.2],[1.331,-9.649],[12.42,-10.298],[5.324,7.227],[0,0],[0,0.1],[0.8,0],[0,0]],"o":[[1.5,7.9],[-0.957,6.939],[-6.18,-9.117],[26.409,-1.618],[0,0],[-0.2,-0.9],[0,0],[23.1,-4.8]],"v":[[160.9,-157.8],[162.191,105.885],[146.183,137.481],[81.208,49.015],[120.8,55],[120.8,-149.7],[119,-151.2],[110.5,-191.2]],"c":true}],"h":1},{"t":28,"s":[{"i":[[-4.3,-23.2],[0,0],[0,0],[0,0],[0,0],[0,0.1],[0.8,0],[0,0]],"o":[[1.5,7.9],[0,0],[0,0],[0,0],[0,0],[-0.2,-0.9],[0,0],[23.1,-4.8]],"v":[[160.9,-157.8],[161.7,95.5],[160.755,94.564],[121.112,55.309],[120.8,55],[120.8,-149.7],[119,-151.2],[110.5,-191.2]],"c":true}],"h":1}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Bottom R","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[63.15,116.65,0],"ix":2},"a":{"a":0,"k":[63.15,116.65,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.1,"y":0},"t":3,"s":[{"i":[[-58.795,2.85],[0,0],[7.433,0],[0,26.189]],"o":[[0,0],[-20.002,19.246],[-41.46,0],[0,-8.499]],"v":[[140.985,58.827],[207.76,129.436],[143.556,152.205],[72.886,104.596]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[-56.158,3.287],[0,0],[7.1,0],[0,30.2]],"o":[[0,0],[-17.583,17.964],[-39.6,0],[0,-9.8]],"v":[[82.619,48.668],[146.381,136.663],[86.7,157.5],[19.2,102.6]],"c":true}]},{"t":19,"s":[{"i":[[-56.158,3.287],[0,0],[7.1,0],[0,30.2]],"o":[[0,0],[-17.583,17.964],[-39.6,0],[0,-9.8]],"v":[[82.619,48.668],[146.381,136.663],[86.7,157.5],[19.2,102.6]],"c":true}],"h":1},{"t":28,"s":[{"i":[[-6,8],[0,0],[7.1,0],[0,30.2]],"o":[[0,0],[-6.5,1.5],[-39.6,0],[0,-9.8]],"v":[[27.7,75.8],[107.1,155.3],[86.7,157.5],[19.2,102.6]],"c":true}],"h":1}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Bottom L","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-131.6,73.1,0],"ix":2},"a":{"a":0,"k":[-131.6,73.1,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.1,"y":0},"t":3,"s":[{"i":[[0,0],[0,0],[0,-1.484],[39.5,0],[0,24.9],[-39.5,0],[-9.2,-2.721]],"o":[[0,0],[0,0],[0,24.818],[-39.5,0],[0,-24.818],[10.9,0],[0,0]],"v":[[-149.241,-39.902],[-107.881,-40.686],[-110.291,145.989],[-181.891,191.007],[-253.491,145.989],[-181.891,100.97],[-151.491,105.258]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[0,0],[0,0],[0,-1.8],[39.5,0],[0,30.2],[-39.5,0],[-9.2,-3.3]],"o":[[0,0],[0,0],[0,30.1],[-39.5,0],[0,-30.1],[10.9,0],[0,0]],"v":[[-100.461,-113.925],[-59.1,-114.876],[-60,137],[-131.6,191.599],[-203.2,137],[-131.6,82.4],[-101.2,87.6]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[0,0],[0,-1.8],[39.5,0],[0,30.2],[-39.5,0],[-9.2,-3.3]],"o":[[0,0],[0,0],[0,30.1],[-39.5,0],[0,-30.1],[10.9,0],[0,0]],"v":[[-100.461,-113.925],[-59.1,-114.876],[-60,137],[-131.6,191.599],[-203.2,137],[-131.6,82.4],[-101.2,87.6]],"c":true}],"h":1},{"t":25,"s":[{"i":[[0,0],[0,0],[0,-1.8],[39.5,0],[0,30.2],[-39.5,0],[-9.2,-3.3]],"o":[[0,0],[0,0],[0,30.1],[-39.5,0],[0,-30.1],[10.9,0],[0,0]],"v":[[-101.1,-45.4],[-60.1,-5.9],[-60,137],[-131.6,191.6],[-203.2,137],[-131.6,82.4],[-101.2,87.6]],"c":true}],"h":1}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/sound_on.json b/TMessagesProj/src/main/res/raw/sound_on.json new file mode 100644 index 000000000..f5a9ccb5a --- /dev/null +++ b/TMessagesProj/src/main/res/raw/sound_on.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":61,"w":512,"h":512,"nm":"Sound On","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.3],"y":[0.919]},"o":{"x":[0.433],"y":[0]},"t":0,"s":[-20]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.425],"y":[-0.114]},"t":12,"s":[12]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":26,"s":[-4]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":39,"s":[4]},{"t":57,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[196,376,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.71,"y":1},"o":{"x":0.4,"y":0},"t":18,"s":[256,220,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.71,"y":1},"o":{"x":0.29,"y":0},"t":31,"s":[256,276,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.29,"y":0},"t":44,"s":[256,232,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[256,256,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[20,0,100]},{"i":{"x":[0.71,0.71,0.71],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":16,"s":[90,107,100]},{"i":{"x":[0.71,0.71,0.71],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":29,"s":[105,95,100]},{"i":{"x":[0.6,0.6,0.6],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":42,"s":[95,105,100]},{"t":58,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Note ON L","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.053,-0.397,0],"ix":2},"a":{"a":0,"k":[-0.053,-0.397,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":2,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[203.232,-154.081],[163.782,-144.356],[161.232,-147.481],[-73.733,-106.013],[-75.233,-104.613],[-74.98,161.798],[-146.78,216.298],[-218.68,161.798],[-146.88,107.298],[-116.38,112.498],[-116.433,-104.113],[-83.633,-145.713],[152.532,-187.481]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":12,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[183.101,-147.811],[143.651,-138.086],[141.101,-141.211],[-35.959,-125.135],[-37.459,-123.735],[-39.2,55.8],[-111,110.3],[-182.9,55.8],[-111.1,1.3],[-80.6,6.5],[-78.659,-123.235],[-45.859,-164.835],[132.401,-181.211]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":25,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[181.854,-163.321],[142.404,-153.596],[139.854,-156.721],[-38.353,-110.011],[-39.853,-108.611],[-39.6,157.8],[-111.4,212.3],[-183.3,157.8],[-111.5,103.3],[-81,108.5],[-81.053,-108.111],[-48.253,-149.711],[131.154,-196.721]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":38,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[183.101,-147.811],[143.651,-138.086],[141.101,-141.211],[-36.108,-128.131],[-37.608,-126.731],[-39.2,55.8],[-111,110.3],[-182.9,55.8],[-111.1,1.3],[-80.6,6.5],[-78.808,-126.231],[-46.008,-167.831],[132.401,-181.211]],"c":true}]},{"t":60,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[182,-157.8],[142.55,-148.075],[140,-151.2],[-38,-115.5],[-39.5,-114.1],[-39.3,136.8],[-111.1,191.3],[-183,136.8],[-111.2,82.3],[-80.7,87.5],[-80.7,-113.6],[-47.9,-155.2],[131.3,-191.2]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Note ON R","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.053,-0.397,0],"ix":2},"a":{"a":0,"k":[-0.053,-0.397,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":2,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[205.461,-155.207],[206.207,78.814],[131.007,133.314],[62.607,78.814],[131.007,24.314],[165.207,30.614],[165.261,-147.107]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":12,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[182.963,-149.059],[185.985,150.495],[110.785,204.995],[42.385,150.495],[110.785,95.995],[144.985,102.295],[142.763,-140.959]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":25,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[181.854,-163.321],[182.6,70.7],[107.4,125.2],[39,70.7],[107.4,16.2],[141.6,22.5],[141.654,-155.221]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":38,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[182.963,-149.059],[185.985,150.495],[110.785,204.995],[42.385,150.495],[110.785,95.995],[144.985,102.295],[142.763,-140.959]],"c":true}]},{"t":60,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[182,-157.8],[182.8,102.7],[107.6,157.2],[39.2,102.7],[107.6,48.2],[141.8,54.5],[141.8,-149.7]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/utyan_change_number.tgs b/TMessagesProj/src/main/res/raw/utyan_change_number.tgs new file mode 100644 index 000000000..4085c3f95 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/utyan_change_number.tgs @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2.2","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"_032_SIM_OUT","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0},"p":{"a":0,"k":[44.5,44.5,0]},"a":{"a":0,"k":[60,60,0]},"s":{"a":0,"k":[280,280,100]}},"ao":0,"ip":96,"op":276,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 6","parent":1,"sr":1,"ks":{"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 7","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-45},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 9","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-135},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 8","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-90},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 10","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-180},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 11","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-225},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 12","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-270},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 13","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-315},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":10,"ty":3,"nm":"NULL CONTROL","parent":20,"sr":1,"ks":{"o":{"a":0,"k":0},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[5]},{"t":238,"s":[3]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[-7.461,49.744,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.967},"o":{"x":0.333,"y":0},"t":78,"s":[-5.807,49.589,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[-18.277,49.366,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.028},"t":210,"s":[-18.277,49.366,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[-5.807,49.589,0],"to":[0,0,0],"ti":[0,0,0]},{"t":238,"s":[-7.461,49.744,0]}]},"a":{"a":0,"k":[60,60,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.65,0.65,0.65],"y":[0,0,0]},"t":60,"s":[86.58,86.58,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.967,1.033,1.033]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":78,"s":[90,86.58,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.333,1.333,1.333]},"o":{"x":[0.167,0.167,0.167],"y":[-0.333,-0.333,-0.333]},"t":90,"s":[64.58,86.58,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.028,-0.028,-0.028]},"t":210,"s":[64.58,86.58,100]},{"i":{"x":[0.35,0.35,0.35],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":220,"s":[90,86.58,100]},{"t":238,"s":[86.58,86.58,100]}]}},"ao":0,"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Layer 18","parent":14,"sr":1,"ks":{"r":{"a":0,"k":-0.192},"p":{"a":0,"k":[-18.16,-3.564,0]},"a":{"a":0,"k":[760.164,23.42,0]},"s":{"a":0,"k":[62.374,62.485,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0.342],[-13.908,-0.342]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[786.371,34.76]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0.342],[-13.908,-0.342]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[787.706,14.042]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0.342],[-13.908,-0.342]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[732.524,33.436]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 3","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0.342],[-13.908,-0.342]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[733.859,12.717]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 4","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[5.269,7.676],[-5.342,7.018],[3.511,5.143],[-5.666,6.487]],"o":[[-5.269,-7.676],[5.342,-7.018],[-3.511,-5.143],[5.666,-6.487]],"v":[[-0.71,30.845],[0.661,9.556],[0.778,-9.575],[2.906,-30.845]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[773.021,23.275]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 5","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-5.269,-7.676],[5.342,-7.018],[-3.511,-5.143],[5.666,-6.487]],"o":[[5.269,7.676],[-5.342,7.018],[3.511,5.143],[-5.666,6.487]],"v":[[1.008,-30.845],[-0.363,-9.556],[-1.709,11.336],[-2.608,30.845]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[748.129,22.616]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 6","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.482,7.48],[0,0],[-7.491,-0.184],[0,0],[0.482,-7.48],[0,0],[7.491,0.184],[0,0]],"o":[[0,0],[0.482,-7.48],[0,0],[7.491,0.184],[0,0],[-0.482,7.48],[0,0],[-7.491,-0.184]],"v":[[-42.006,16.78],[-39.714,-18.79],[-25.277,-31.999],[29.314,-30.657],[42.006,-16.78],[39.714,18.79],[25.277,31.999],[-29.314,30.657]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.827450990677,0.301960796118,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[760.164,23.42]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 7","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Layer 13","parent":10,"sr":1,"ks":{"r":{"a":0,"k":-4.925},"p":{"a":0,"k":[57.076,-23.931,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[103.95,103.95,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":99,"s":[103.95,145.531,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":108,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":198,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":212,"s":[103.95,145.531,100]},{"t":220,"s":[103.95,103.95,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.145,1.726],[0,0],[3.605,0.131],[0,0],[0.302,-3.594],[0,0],[-3.605,-0.131],[0,0],[-1.327,1.176],[0,0]],"o":[[0,0],[0.302,-3.594],[0,0],[-3.605,-0.131],[0,0],[-0.302,3.594],[0,0],[1.731,0.063],[0,0],[1.327,-1.176]],"v":[[53.897,11.199],[56.88,-24.257],[50.9,-31.002],[-45.333,-34.509],[-52.408,-28.239],[-56.88,24.903],[-50.9,31.649],[27.592,34.509],[32.368,32.771],[51.597,15.731]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Layer 17","parent":10,"sr":1,"ks":{"o":{"a":0,"k":30},"r":{"a":0,"k":-4.925},"p":{"a":0,"k":[71.154,-7.093,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[103.95,103.95,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":99,"s":[103.95,145.531,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":108,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":198,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":212,"s":[103.95,145.531,100]},{"t":220,"s":[103.95,103.95,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.145,1.726],[0,0],[3.605,0.131],[0,0],[0.302,-3.594],[0,0],[-3.605,-0.131],[0,0],[-1.327,1.176],[0,0]],"o":[[0,0],[0.302,-3.594],[0,0],[-3.605,-0.131],[0,0],[-0.302,3.594],[0,0],[1.731,0.063],[0,0],[1.327,-1.176]],"v":[[53.897,11.199],[56.88,-24.257],[50.9,-31.002],[-45.333,-34.509],[-52.408,-28.239],[-56.88,24.903],[-50.9,31.649],[27.592,34.509],[32.368,32.771],[51.597,15.731]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":3,"nm":"ALL","sr":1,"ks":{"o":{"a":0,"k":0},"p":{"a":0,"k":[184.732,461.677,0]},"a":{"a":0,"k":[60,60,0]},"s":{"a":0,"k":[102.688,97.312,100]}},"ao":0,"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"wing_bl","parent":18,"sr":1,"ks":{"p":{"a":0,"k":[-8.855,-11.869,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[{"i":[[-17.276,5.324],[-17.581,17.49]],"o":[[35.586,-10.373],[9.488,-9.438]],"v":[[-35.127,5.783],[45.001,-36.879]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[-17.276,5.324],[-8.234,24.443]],"o":[[35.586,-10.373],[4.273,-12.683]],"v":[[-35.127,5.783],[31.82,-43.067]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[{"i":[[-17.276,5.324],[-16.274,23.744]],"o":[[35.586,-10.373],[7.566,-11.039]],"v":[[-35.127,5.783],[31.82,-43.067]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[-17.276,5.324],[-24.88,5.04]],"o":[[27.71,-32.456],[13.117,-2.657]],"v":[[-35.127,5.783],[37.564,-28.441]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[-17.276,5.324],[-22.504,0.69]],"o":[[23.282,-27.828],[13.377,-0.41]],"v":[[-35.127,5.783],[37.564,-28.441]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[-17.276,5.324],[-22.504,0.69]],"o":[[23.282,-27.828],[13.377,-0.41]],"v":[[-35.127,5.783],[37.564,-28.441]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[-17.276,5.324],[-22.504,0.69]],"o":[[23.282,-27.828],[13.377,-0.41]],"v":[[-35.127,5.783],[37.564,-28.441]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[-17.276,5.324],[-5.585,25.207]],"o":[[24.367,-10.734],[2.895,-13.066]],"v":[[-15.415,10.058],[36.215,-49.966]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[-17.276,5.324],[5.972,33.072]],"o":[[24.367,-10.734],[-2.378,-13.17]],"v":[[-0.918,31.478],[29.91,-25.042]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[-17.276,5.324],[5.972,33.072]],"o":[[19.202,-5.366],[-2.378,-13.17]],"v":[[-32.362,4.039],[3.355,-46.163]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":206,"s":[{"i":[[-17.276,5.324],[-16.274,23.744]],"o":[[35.586,-10.373],[7.566,-11.039]],"v":[[-12.052,22.789],[54.895,-26.061]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":216,"s":[{"i":[[-17.276,5.324],[-16.274,23.744]],"o":[[24.939,-3.096],[7.566,-11.039]],"v":[[-24.432,4.873],[45.308,-38.48]],"c":false}]},{"t":224,"s":[{"i":[[-17.276,5.324],[-17.581,17.49]],"o":[[35.586,-10.373],[9.488,-9.438]],"v":[[-35.127,5.783],[45.001,-36.879]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[5]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"wing_l","parent":37,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[29.776]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":80,"s":[4.46]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[37.851]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[59.739]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":112,"s":[4.46]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":128,"s":[21.37]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":140,"s":[21.37]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":146,"s":[55.489]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":152,"s":[-44.575]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":174,"s":[196.558]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":190,"s":[4.46]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":203.334,"s":[22.973]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":208,"s":[22.973]},{"t":224,"s":[29.776]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[-30.879,8.023,0],"to":[8.62,5.016,0],"ti":[-4.359,4.747,0]},{"t":80,"s":[-0.69,2.885,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[-0.69,2.885,0],"to":[-15.117,14.007,0],"ti":[3.965,5.433,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[-60.094,3.912,0],"to":[10.448,10.012,0],"ti":[-2.412,5.004,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[-0.69,2.885,0],"to":[-18.039,1.676,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":128,"s":[-40.617,2.885,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[-40.617,2.885,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":152,"s":[-75.675,-12.016,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":174,"s":[-76.445,-11.57,0],"to":[0,0,0],"ti":[-2.412,5.004,0]},{"t":190,"s":[-29.905,2.885,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":208,"s":[-0.69,2.885,0],"to":[-4.283,6.172,0],"ti":[6.595,3.708,0]},{"t":224,"s":[-30.879,8.023,0]}]},"a":{"a":0,"k":[-31.735,12.164,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[{"i":[[0,0],[-4.979,-16.514],[39.864,-41.939]],"o":[[90.592,-20.031],[32.187,51.424],[0,0]],"v":[[-54.963,-24.543],[53.934,-82.266],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[0,0],[-4.979,-16.514],[63.721,-32.03]],"o":[[96.719,-10.119],[37.874,31.846],[0,0]],"v":[[-54.963,-24.543],[18.075,-103.691],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[{"i":[[0,0],[-4.979,-16.514],[53.781,-41.332]],"o":[[80.14,-24.918],[37.874,31.846],[0,0]],"v":[[-54.963,-24.543],[42.597,-103.877],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[0,0],[-4.979,-16.514],[10.322,-50.653]],"o":[[68.489,-50.418],[-13.793,31.74],[0,0]],"v":[[-54.963,-24.543],[56.936,-39.654],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[-4.979,-16.514],[10.322,-50.653]],"o":[[68.489,-50.418],[-13.793,31.74],[0,0]],"v":[[-54.963,-24.543],[56.936,-39.654],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[0,0],[-4.979,-16.514],[10.322,-50.653]],"o":[[68.489,-50.418],[-13.793,31.74],[0,0]],"v":[[-54.963,-24.543],[56.936,-39.654],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[0,0],[-4.979,-16.514],[10.322,-50.653]],"o":[[68.489,-50.418],[-13.793,31.74],[0,0]],"v":[[-54.963,-24.543],[56.936,-39.654],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[0,0],[-32.75,-11.91],[59.265,-50.183]],"o":[[78.567,-33.366],[24.656,17.24],[0,0]],"v":[[-43.586,-9.728],[36.855,-97.669],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[-32.75,-11.91],[70.329,-22.436]],"o":[[66.395,-10.011],[24.656,17.24],[0,0]],"v":[[-54.047,-22.699],[13.364,-72.459],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[{"i":[[0,0],[-32.75,-11.91],[55.046,-37.171]],"o":[[66.395,-10.011],[24.656,17.24],[0,0]],"v":[[-54.047,-22.699],[-11.282,-96.108],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":206,"s":[{"i":[[0,0],[-4.979,-16.514],[63.721,-32.03]],"o":[[96.719,-10.119],[37.874,31.846],[0,0]],"v":[[-39.368,-7.715],[52.499,-94.845],[8.031,54.817]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":216,"s":[{"i":[[0,0],[-4.979,-16.514],[63.721,-32.03]],"o":[[96.719,-10.119],[37.874,31.846],[0,0]],"v":[[-54.963,-24.543],[52.499,-94.845],[-7.564,37.989]],"c":false}]},{"t":224,"s":[{"i":[[0,0],[-4.979,-16.514],[39.864,-41.939]],"o":[[90.592,-20.031],[32.187,51.424],[0,0]],"v":[[-54.963,-24.543],[53.934,-82.266],[-7.564,37.989]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Layer 9","parent":20,"sr":1,"ks":{"r":{"a":0,"k":1},"p":{"a":0,"k":[-12.158,109.645,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[-15.991,2],[0,0]],"o":[[0,0],[15.991,2]],"v":[[-28.751,0],[28.751,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[-15.991,2],[0,0]],"o":[[0,0],[15.991,2]],"v":[[-25.504,-0.023],[31.997,-0.023]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[-12.744,2],[0,0]],"o":[[0,0],[12.744,2]],"v":[[-33.734,-0.189],[12.092,-0.189]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[-12.744,2],[0,0]],"o":[[0,0],[12.744,2]],"v":[[-33.734,-0.189],[12.092,-0.189]],"c":false}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[-15.991,2],[0,0]],"o":[[0,0],[15.991,2]],"v":[[-25.504,-0.023],[31.997,-0.023]],"c":false}]},{"t":234,"s":[{"i":[[-15.991,2],[0,0]],"o":[[0,0],[15.991,2]],"v":[[-28.751,0],[28.751,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"phone","sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[2]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[-2]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[-2]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":222,"s":[2]},{"t":238,"s":[2]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.85,"y":0},"t":60,"s":[376.205,446.188,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[423.908,446.188,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.15,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[423.908,446.188,0],"to":[0,0,0],"ti":[0,0,0]},{"t":234,"s":[376.205,446.188,0]}]},"a":{"a":0,"k":[-2.564,120.731,0]},"s":{"a":0,"k":[115.5,115.5,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[15.283,0.013],[0,0],[0.248,-3.693],[0,0],[4.492,0.004],[0,0],[-0.311,4.619],[0,0],[3.592,0.003],[0,0],[1.057,-15.715],[0,0],[-15.283,-0.013],[0,0],[-1.057,15.715],[0,0]],"o":[[0,0],[-3.592,-0.003],[0,0],[-0.311,4.619],[0,0],[-4.492,-0.004],[0,0],[0.248,-3.693],[0,0],[-15.283,-0.013],[0,0],[-1.057,15.715],[0,0],[15.283,0.013],[0,0],[1.057,-15.715]],"v":[[45.404,-120.462],[42.113,-120.465],[35.159,-113.783],[35.159,-113.783],[26.463,-105.426],[-17.142,-105.464],[-24.713,-113.835],[-24.713,-113.835],[-30.767,-120.528],[-34.058,-120.53],[-58.052,-97.473],[-71.291,97.564],[-55.109,120.656],[32.344,120.731],[53.054,97.671],[66.293,-97.366]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[15.991,0],[0,0],[0.226,-3.694],[0,0],[4.7,0],[0,0],[-0.283,4.62],[0,0],[3.758,0],[0,0],[0.963,-15.718],[0,0],[-15.991,0],[0,0],[-0.963,15.718],[0,0]],"o":[[0,0],[-3.758,0],[0,0],[-0.283,4.62],[0,0],[-4.7,0],[0,0],[0.226,-3.694],[0,0],[-15.991,0],[0,0],[-0.963,15.718],[0,0],[15.991,0],[0,0],[0.963,-15.718]],"v":[[49.017,-120.612],[45.574,-120.612],[38.359,-113.923],[38.359,-113.923],[29.336,-105.558],[-16.287,-105.558],[-24.284,-113.923],[-24.284,-113.923],[-30.679,-120.612],[-34.122,-120.612],[-59.018,-97.531],[-70.974,97.531],[-53.834,120.612],[37.668,120.612],[59.127,97.531],[71.083,-97.531]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[12.455,0.066],[0,0],[0.336,-3.691],[0,0],[3.661,0.019],[0,0],[-0.421,4.616],[0,0],[2.927,0.015],[0,0],[1.432,-15.705],[0,0],[-12.455,-0.066],[0,0],[-1.432,15.705],[0,0]],"o":[[0,0],[-2.927,-0.015],[0,0],[-0.421,4.616],[0,0],[-3.661,-0.019],[0,0],[0.336,-3.691],[0,0],[-12.455,-0.066],[0,0],[-1.432,15.705],[0,0],[12.455,0.066],[0,0],[1.432,-15.705]],"v":[[30.957,-119.864],[28.275,-119.878],[22.366,-113.223],[22.366,-113.223],[14.975,-104.9],[-20.56,-105.087],[-26.426,-113.48],[-26.426,-113.48],[-31.117,-120.191],[-33.799,-120.205],[-54.19,-97.24],[-72.56,97.694],[-60.21,120.832],[11.059,121.206],[28.774,98.227],[47.144,-96.707]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[12.455,0.066],[0,0],[0.336,-3.691],[0,0],[3.661,0.019],[0,0],[-0.421,4.616],[0,0],[2.927,0.015],[0,0],[1.432,-15.705],[0,0],[-12.455,-0.066],[0,0],[-1.432,15.705],[0,0]],"o":[[0,0],[-2.927,-0.015],[0,0],[-0.421,4.616],[0,0],[-3.661,-0.019],[0,0],[0.336,-3.691],[0,0],[-12.455,-0.066],[0,0],[-1.432,15.705],[0,0],[12.455,0.066],[0,0],[1.432,-15.705]],"v":[[30.957,-119.864],[28.275,-119.878],[22.366,-113.223],[22.366,-113.223],[14.975,-104.9],[-20.56,-105.087],[-26.426,-113.48],[-26.426,-113.48],[-31.117,-120.191],[-33.799,-120.205],[-54.19,-97.24],[-72.56,97.694],[-60.21,120.832],[11.059,121.206],[28.774,98.227],[47.144,-96.707]],"c":true}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[15.991,0],[0,0],[0.226,-3.694],[0,0],[4.7,0],[0,0],[-0.283,4.62],[0,0],[3.758,0],[0,0],[0.963,-15.718],[0,0],[-15.991,0],[0,0],[-0.963,15.718],[0,0]],"o":[[0,0],[-3.758,0],[0,0],[-0.283,4.62],[0,0],[-4.7,0],[0,0],[0.226,-3.694],[0,0],[-15.991,0],[0,0],[-0.963,15.718],[0,0],[15.991,0],[0,0],[0.963,-15.718]],"v":[[49.017,-120.612],[45.574,-120.612],[38.359,-113.923],[38.359,-113.923],[29.336,-105.558],[-16.287,-105.558],[-24.284,-113.923],[-24.284,-113.923],[-30.679,-120.612],[-34.122,-120.612],[-59.018,-97.531],[-70.974,97.531],[-53.834,120.612],[37.668,120.612],[59.127,97.531],[71.083,-97.531]],"c":true}]},{"t":234,"s":[{"i":[[15.283,0.013],[0,0],[0.248,-3.693],[0,0],[4.492,0.004],[0,0],[-0.311,4.619],[0,0],[3.592,0.003],[0,0],[1.057,-15.715],[0,0],[-15.283,-0.013],[0,0],[-1.057,15.715],[0,0]],"o":[[0,0],[-3.592,-0.003],[0,0],[-0.311,4.619],[0,0],[-4.492,-0.004],[0,0],[0.248,-3.693],[0,0],[-15.283,-0.013],[0,0],[-1.057,15.715],[0,0],[15.283,0.013],[0,0],[1.057,-15.715]],"v":[[45.404,-120.462],[42.113,-120.465],[35.159,-113.783],[35.159,-113.783],[26.463,-105.426],[-17.142,-105.464],[-24.713,-113.835],[-24.713,-113.835],[-30.767,-120.528],[-34.058,-120.53],[-58.052,-97.473],[-71.291,97.564],[-55.109,120.656],[32.344,120.731],[53.054,97.671],[66.293,-97.366]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":56,"s":[0.273039604636,0.643120799345,0.868321078431,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.283864578546,0.876776960784,0.444299675437,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[0.283864578546,0.876776960784,0.444299675437,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":214,"s":[0.273039604636,0.643120799345,0.868321078431,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":236,"s":[0.273039604636,0.643120799345,0.868321078431,1]},{"t":270,"s":[0.283864578546,0.876776960784,0.444299675437,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Layer 7","parent":20,"sr":1,"ks":{"p":{"a":0,"k":[0.017,0,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[0,0],[-1.953,28.612],[0,0],[-26.105,0],[0,0],[1.865,-27.295],[0,0],[25.412,0]],"o":[[-26.617,0],[0,0],[1.784,-26.143],[0,0],[27.368,0],[0,0],[-1.905,27.916],[0,0]],"v":[[-54.757,136.924],[-87.506,96.47],[-74.191,-98.593],[-33.172,-137.043],[44.78,-137.043],[82.394,-96.59],[69.078,98.472],[31.452,136.924]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[0,0],[-1.754,28.612],[0,0],[-26.435,0],[0,0],[1.674,-27.295],[0,0],[25.733,0]],"o":[[-26.954,0],[0,0],[1.602,-26.143],[0,0],[27.714,0],[0,0],[-1.71,27.916],[0,0]],"v":[[-53.851,136.984],[-87.331,96.53],[-75.375,-98.533],[-34.139,-136.984],[49,-136.984],[87.406,-96.531],[75.45,98.532],[37.65,136.984]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[-2.751,28.612],[0,0],[-24.785,0],[0,0],[2.625,-27.295],[0,0],[24.127,0]],"o":[[-25.271,0],[0,0],[2.513,-26.143],[0,0],[25.984,0],[0,0],[-2.683,27.916],[0,0]],"v":[[-58.38,136.685],[-88.206,96.231],[-69.453,-98.831],[-29.304,-137.282],[27.909,-137.282],[62.353,-96.829],[43.6,98.234],[6.673,136.685]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[0,0],[-2.751,28.612],[0,0],[-24.785,0],[0,0],[2.625,-27.295],[0,0],[24.127,0]],"o":[[-25.271,0],[0,0],[2.513,-26.143],[0,0],[25.984,0],[0,0],[-2.683,27.916],[0,0]],"v":[[-58.38,136.685],[-88.206,96.231],[-69.453,-98.831],[-29.304,-137.282],[27.909,-137.282],[62.353,-96.829],[43.6,98.234],[6.673,136.685]],"c":true}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[0,0],[-1.754,28.612],[0,0],[-26.435,0],[0,0],[1.674,-27.295],[0,0],[25.733,0]],"o":[[-26.954,0],[0,0],[1.602,-26.143],[0,0],[27.714,0],[0,0],[-1.71,27.916],[0,0]],"v":[[-53.851,136.984],[-87.331,96.53],[-75.375,-98.533],[-34.139,-136.984],[49,-136.984],[87.406,-96.531],[75.45,98.532],[37.65,136.984]],"c":true}]},{"t":234,"s":[{"i":[[0,0],[-1.953,28.612],[0,0],[-26.105,0],[0,0],[1.865,-27.295],[0,0],[25.412,0]],"o":[[-26.617,0],[0,0],[1.784,-26.143],[0,0],[27.368,0],[0,0],[-1.905,27.916],[0,0]],"v":[[-54.757,136.924],[-87.506,96.47],[-74.191,-98.593],[-33.172,-137.043],[44.78,-137.043],[82.394,-96.59],[69.078,98.472],[31.452,136.924]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.84],"y":[0]},"t":60,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"i":{"x":[0.16],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"t":234,"s":[0.552941176471,0.003921568627,0.996078491211,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Layer 19","parent":20,"sr":1,"ks":{"p":{"a":0,"k":[-8.635,-0.302,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-77.384,96.343],[-64.476,-98.839]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-77.384,96.343],[-65.774,-98.793]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-88.206,96.231],[-69.453,-98.831]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-88.206,96.231],[-69.453,-98.831]],"c":false}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-77.384,96.343],[-65.774,-98.793]],"c":false}]},{"t":234,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-77.384,96.343],[-64.476,-98.839]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.84],"y":[0]},"t":60,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"i":{"x":[0.16],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"t":234,"s":[0.38431372549,0.062745098039,0.647058823529,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"sim 2","parent":20,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":174,"s":[165.948]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":198,"s":[11.974]},{"t":204,"s":[2.981]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[-314.937,77.506,0],"to":[252.931,98.89,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[-187.083,-41.038,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":196,"s":[-205.254,-41.673,0],"to":[0,0,0],"ti":[-111.831,-17.041,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[-43.298,-2.247,0],"to":[111.831,17.041,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":214,"s":[6.153,1.95,0],"to":[0,0,0],"ti":[0,0,0]},{"t":228,"s":[6.153,1.95,0]}]},"a":{"a":0,"k":[293.859,350.706,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":190,"s":[100.016,100,100]},{"i":{"x":[0,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":204,"s":[100.016,100,100]},{"i":{"x":[0,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":214,"s":[80.016,99.507,100]},{"t":228,"s":[80.016,99.507,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[3.149,0],[-3.071,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":210,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[296.227,358.747]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[3.149,0],[-3.071,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":210,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[296.227,337.996]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[44.956,0],[38.737,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":210,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.438,0.007],[-14.848,0.013]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[242.38,358.747]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 3","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[44.956,0],[38.737,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":210,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[242.38,337.996]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 4","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[1.287,7.546],[-1.092,7.15],[0.858,5.057],[-1.172,6.626]],"o":[[-1.287,-7.546],[1.092,-7.15],[-0.858,-5.057],[1.172,-6.626]],"v":[[10.63,30.889],[10.63,9.567],[10.381,-9.567],[10.55,-30.889]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]},{"t":210,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[282.776,347.563]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 5","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[-1.287,-7.546],[1.092,-7.15],[-0.858,-5.057],[1.172,-6.626]],"o":[[1.287,7.546],[-1.092,7.15],[0.858,5.057],[-1.172,6.626]],"v":[[30.691,-30.889],[30.691,-9.567],[30.691,11.359],[30.771,30.889]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.357,11.359],[0,30.889]],"c":false}]},{"t":210,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.827,11.365],[-1.41,30.909]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[256.644,347.563]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 6","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,7.491],[0,0],[-1.675,0],[0,0],[0,-7.491],[0,0],[1.675,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[1.675,0],[0,0],[0,7.491],[0,0],[-1.675,0]],"v":[[11.785,17.813],[11.785,-17.813],[14.818,-31.378],[27.024,-31.378],[30.057,-17.813],[30.057,17.813],[27.024,31.378],[14.818,31.378]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-40.86,17.813],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-27.296,31.378]],"c":true}]},{"t":210,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-42.27,17.833],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-28.706,31.398]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":7,"k":{"a":0,"k":[0,0.969,0.882,0.451,0.007,0.984,0.941,0.725,0.015,1,1,1,0.233,1,1,1,0.45,1,1,1,0.46,0.984,0.941,0.725,0.47,0.969,0.882,0.451]}},"s":{"a":1,"k":[{"i":{"x":0.667,"y":0.779},"o":{"x":0.333,"y":0},"t":174,"s":[40.307,-3.438],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.233,"y":1},"t":180,"s":[-58.119,-1.804],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[-83.342,-4.221],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[-83.342,-4.221],"to":[0,0],"ti":[0,0]},{"t":226,"s":[40.307,-3.438]}]},"e":{"a":1,"k":[{"i":{"x":0.667,"y":0.265},"o":{"x":0.333,"y":0},"t":174,"s":[100,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0.237},"t":180,"s":[135.751,4.033],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[-50.395,-2.943],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[-50.395,-2.943],"to":[0,0],"ti":[0,0]},{"t":226,"s":[100,0]}]},"t":1,"nm":"gggggd","hd":false},{"ty":"tr","p":{"a":0,"k":[269.332,348.051]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 7","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[269.332,348.051]},"a":{"a":0,"k":[269.332,348.051]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,2.578],[0,0],[1.2,0],[0,0],[0,-5.369],[0,0],[-1.2,0],[0,0],[-0.408,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-1.2,0],[0,0],[0,5.369],[0,0],[0.576,0],[0,0],[0.408,-1.823]],"v":[[20.073,13.272],[20.073,-39.693],[17.899,-49.415],[-14.145,-49.415],[-16.319,-39.693],[-16.319,39.693],[-14.145,49.415],[11.992,49.415],[13.529,46.567],[19.436,20.146]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,2.578],[0,0],[5.369,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-1.823,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[2.578,0],[0,0],[1.823,-1.823]],"v":[[81.38,13.272],[81.38,-39.693],[71.659,-49.415],[-71.659,-49.415],[-81.38,-39.693],[-81.38,39.693],[-71.659,49.415],[45.237,49.415],[52.111,46.567],[78.533,20.146]],"c":true}]},{"t":210,"s":[{"i":[[0,2.578],[0,0],[2.461,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-0.836,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[1.182,0],[0,0],[0.836,-1.823]],"v":[[46.763,13.486],[46.763,-39.48],[42.306,-49.201],[-71.659,-49.415],[-81.38,-39.693],[-86.081,39.76],[-76.359,49.482],[30.195,49.629],[33.346,46.781],[45.457,20.36]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.360784313725,0.478431372549,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.298314921061,0.626238116096,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[293.859,350.706]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false}],"ip":174,"op":212,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"sim","parent":20,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.676],"y":[0]},"t":120,"s":[2.981]},{"i":{"x":[0.843],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":130,"s":[-87]},{"i":{"x":[0.28],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":136,"s":[-84.422]},{"i":{"x":[0.28],"y":[1]},"o":{"x":[0.72],"y":[0]},"t":140,"s":[-84.422]},{"i":{"x":[0.525],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":146,"s":[-75.422]},{"t":166,"s":[-444.422]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[6.153,1.95,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":98,"s":[-56.802,-1.745,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":102,"s":[-43.298,-2.247,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[-43.298,-2.247,0],"to":[0,0,0],"ti":[0,0,0]},{"t":128,"s":[-146.635,-5.011,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[-146.635,-5.011,0],"to":[0,0,0],"ti":[8.699,-11.94,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.182,"y":0},"t":146,"s":[-162.284,28.159,0],"to":[-3.342,-34.908,0],"ti":[151.73,-82.575,0]},{"t":166,"s":[-335.962,-231.985,0]}]},"a":{"a":0,"k":[293.859,350.706,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[80.016,99.507,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":100,"s":[105,99.507,100]},{"i":{"x":[0.28,0.28,0.28],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":104,"s":[100.016,100,100]},{"i":{"x":[0.28,0.28,0.28],"y":[1,1,1]},"o":{"x":[1,1,0.72],"y":[0,0,0]},"t":140,"s":[100.016,99.507,100]},{"i":{"x":[0.88,0.88,0.88],"y":[1,1,1]},"o":{"x":[1,1,0.72],"y":[0,0,0]},"t":148,"s":[100.016,99.507,100]},{"t":166,"s":[0,0,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":128,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.404,-4.488],[-7.911,-4.488]],"c":false}]},{"t":172,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[296.227,358.747]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":128,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.404,3.839],[-7.911,3.839]],"c":false}]},{"t":172,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[296.227,337.996]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.438,0.007],[-14.848,0.013]],"c":false}]},{"t":128,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[40.783,-4.488],[35.277,-4.488]],"c":false}]},{"t":172,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[242.38,358.747]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 3","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":128,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[40.783,3.839],[35.277,3.839]],"c":false}]},{"t":172,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[242.38,337.996]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 4","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]},{"t":128,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[1.139,4.518],[-0.967,4.28],[0.759,3.028],[-1.037,3.967]],"o":[[-1.139,-4.518],[0.967,-4.28],[-0.759,-3.028],[1.037,-3.967]],"v":[[5.761,18.493],[5.761,5.728],[5.54,-5.728],[5.69,-18.493]],"c":false}]},{"t":172,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[282.776,347.563]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 5","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.827,11.365],[-1.41,30.909]],"c":false}]},{"t":128,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.357,11.359],[0,30.889]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.357,11.359],[0,30.889]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[-1.139,-4.518],[0.967,-4.28],[-0.759,-3.028],[1.037,-3.967]],"o":[[1.139,4.518],[-0.967,4.28],[0.759,3.028],[-1.037,3.967]],"v":[[26.519,-18.493],[26.519,-5.728],[26.519,6.8],[26.589,18.493]],"c":false}]},{"t":172,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.357,11.359],[0,30.889]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[256.644,347.563]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 6","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-42.27,17.833],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-28.706,31.398]],"c":true}]},{"t":128,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-40.86,17.813],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-27.296,31.378]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-40.86,17.813],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-27.296,31.378]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,4.911],[0,0],[-1.624,0],[0,0],[0,-4.911],[0,0],[1.624,0],[0,0]],"o":[[0,0],[0,-4.911],[0,0],[1.624,0],[0,0],[0,4.911],[0,0],[-1.624,0]],"v":[[7.559,11.678],[7.559,-11.678],[10.5,-20.571],[22.334,-20.571],[25.275,-11.678],[25.275,11.678],[22.334,20.571],[10.5,20.571]],"c":true}]},{"t":172,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-40.86,17.813],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-27.296,31.378]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[8]},{"t":166,"s":[20]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":7,"k":{"a":0,"k":[0,0.969,0.882,0.451,0.007,0.984,0.941,0.725,0.015,1,1,1,0.233,1,1,1,0.45,1,1,1,0.46,0.984,0.941,0.725,0.47,0.969,0.882,0.451]}},"s":{"a":1,"k":[{"i":{"x":0.667,"y":0.779},"o":{"x":0.333,"y":0},"t":118,"s":[40.307,-3.438],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.233,"y":1},"t":124,"s":[-58.119,-1.804],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":134,"s":[-83.342,-4.221],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[-83.342,-4.221],"to":[0,0],"ti":[0,0]},{"t":170,"s":[40.307,-3.438]}]},"e":{"a":1,"k":[{"i":{"x":0.667,"y":0.265},"o":{"x":0.333,"y":0},"t":118,"s":[100,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0.237},"t":124,"s":[135.751,4.033],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":134,"s":[-50.395,-2.943],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[-50.395,-2.943],"to":[0,0],"ti":[0,0]},{"t":170,"s":[100,0]}]},"t":1,"nm":"gggggd","hd":false},{"ty":"tr","p":{"a":0,"k":[269.332,348.051]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 7","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[269.332,348.051]},"a":{"a":0,"k":[269.332,348.051]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,2.578],[0,0],[2.461,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-0.836,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[1.182,0],[0,0],[0.836,-1.823]],"v":[[46.763,13.486],[46.763,-39.48],[42.306,-49.201],[-71.659,-49.415],[-81.38,-39.693],[-86.081,39.76],[-76.359,49.482],[30.195,49.629],[33.346,46.781],[45.457,20.36]],"c":true}]},{"t":128,"s":[{"i":[[0,2.578],[0,0],[5.369,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-1.823,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[2.578,0],[0,0],[1.823,-1.823]],"v":[[81.38,13.272],[81.38,-39.693],[71.659,-49.415],[-71.659,-49.415],[-81.38,-39.693],[-81.38,39.693],[-71.659,49.415],[45.237,49.415],[52.111,46.567],[78.533,20.146]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,2.578],[0,0],[5.369,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-1.823,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[2.578,0],[0,0],[1.823,-1.823]],"v":[[81.38,13.272],[81.38,-39.693],[71.659,-49.415],[-71.659,-49.415],[-81.38,-39.693],[-81.38,39.693],[-71.659,49.415],[45.237,49.415],[52.111,46.567],[78.533,20.146]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,2.578],[0,0],[1.775,0],[0,0],[0,-5.369],[0,0],[-1.775,0],[0,0],[-0.603,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-1.775,0],[0,0],[0,5.369],[0,0],[0.853,0],[0,0],[0.603,-1.823]],"v":[[26.909,13.272],[26.909,-39.693],[23.695,-49.415],[-23.695,-49.415],[-26.909,-39.693],[-26.909,39.693],[-23.695,49.415],[14.958,49.415],[17.231,46.567],[25.968,20.146]],"c":true}]},{"t":172,"s":[{"i":[[0,2.578],[0,0],[5.369,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-1.823,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[2.578,0],[0,0],[1.823,-1.823]],"v":[[81.38,13.272],[81.38,-39.693],[71.659,-49.415],[-71.659,-49.415],[-81.38,-39.693],[-81.38,39.693],[-71.659,49.415],[45.237,49.415],[52.111,46.567],[78.533,20.146]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.066666666667,0.482352941176,0.121568627451,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[10]},{"t":166,"s":[20]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.462745098039,0.752941176471,0.035294117647,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[293.859,350.706]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false}],"ip":92,"op":300,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Shape Layer 15","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-84.812,-40.085],[71,-165.689]],"o":[[44,20.796],[-29.976,69.954]],"v":[[-159,-199.915],[-58,38.689]],"c":false}},"nm":"Path 2","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":150,"s":[100]},{"t":168,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":150,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":158,"s":[100]},{"t":166,"s":[0]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.654],"y":[0.944]},"o":{"x":[0.298],"y":[0]},"t":150,"s":[5]},{"i":{"x":[0.819],"y":[1.017]},"o":{"x":[0.42],"y":[-0.043]},"t":158,"s":[20]},{"t":163,"s":[5]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"Shape Layer 14","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-92.352,2.527],[58,-220.43]],"o":[[80,-2.189],[-19.367,73.606]],"v":[[-196,-221.806],[-20,70.43]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":148,"s":[100]},{"t":166,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":153,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":159,"s":[54]},{"t":166,"s":[0]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.654],"y":[0.942]},"o":{"x":[0.298],"y":[0]},"t":153,"s":[5]},{"i":{"x":[0.819],"y":[1.032]},"o":{"x":[0.42],"y":[-0.083]},"t":159,"s":[20]},{"t":166,"s":[5]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"Layer 6","parent":20,"sr":1,"ks":{"p":{"a":0,"k":[4.03,-0.011,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[0,0],[-1.953,28.612],[0,0],[-26.105,0],[0,0],[1.865,-27.295],[0,0],[25.412,0]],"o":[[-26.617,0],[0,0],[1.784,-26.143],[0,0],[27.368,0],[0,0],[-1.905,27.916],[0,0]],"v":[[-58.633,136.882],[-91.382,96.428],[-78.08,-98.529],[-37.144,-136.985],[49.227,-137.44],[86.841,-96.987],[73.539,97.97],[35.914,136.422]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[0,0],[-1.754,28.612],[0,0],[-26.435,0],[0,0],[1.674,-27.295],[0,0],[25.733,0]],"o":[[-26.954,0],[0,0],[1.602,-26.143],[0,0],[27.714,0],[0,0],[-1.71,27.916],[0,0]],"v":[[-56.066,136.789],[-89.546,96.335],[-77.605,-98.611],[-36.461,-137.067],[46.658,-137.065],[85.064,-96.612],[73.124,98.334],[35.324,136.786]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[-2.751,28.612],[0,0],[-24.785,0],[0,0],[2.625,-27.295],[0,0],[24.127,0]],"o":[[-25.271,0],[0,0],[2.513,-26.143],[0,0],[25.984,0],[0,0],[-2.683,27.916],[0,0]],"v":[[-81.03,136.831],[-110.856,96.377],[-92.111,-98.628],[-52.007,-137.081],[23.599,-136.972],[58.044,-96.519],[39.298,98.485],[2.371,136.937]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[0,0],[-2.751,28.612],[0,0],[-24.785,0],[0,0],[2.625,-27.295],[0,0],[24.127,0]],"o":[[-25.271,0],[0,0],[2.513,-26.143],[0,0],[25.984,0],[0,0],[-2.683,27.916],[0,0]],"v":[[-81.03,136.831],[-110.856,96.377],[-92.111,-98.628],[-52.007,-137.081],[23.599,-136.972],[58.044,-96.519],[39.298,98.485],[2.371,136.937]],"c":true}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[0,0],[-1.754,28.612],[0,0],[-26.435,0],[0,0],[1.674,-27.295],[0,0],[25.733,0]],"o":[[-26.954,0],[0,0],[1.602,-26.143],[0,0],[27.714,0],[0,0],[-1.71,27.916],[0,0]],"v":[[-56.066,136.789],[-89.546,96.335],[-77.605,-98.611],[-36.461,-137.067],[46.658,-137.065],[85.064,-96.612],[73.124,98.334],[35.324,136.786]],"c":true}]},{"t":234,"s":[{"i":[[0,0],[-1.953,28.612],[0,0],[-26.105,0],[0,0],[1.865,-27.295],[0,0],[25.412,0]],"o":[[-26.617,0],[0,0],[1.784,-26.143],[0,0],[27.368,0],[0,0],[-1.905,27.916],[0,0]],"v":[[-58.633,136.882],[-91.382,96.428],[-78.08,-98.529],[-37.144,-136.985],[49.227,-137.44],[86.841,-96.987],[73.539,97.97],[35.914,136.422]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.84],"y":[0]},"t":60,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"i":{"x":[0.16],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"t":234,"s":[0.38431372549,0.062745098039,0.647058823529,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.84],"y":[0]},"t":60,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"i":{"x":[0.16],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"t":234,"s":[0.38431372549,0.062745098039,0.647058823529,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"eye 2","parent":32,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":60,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":72,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[143.686,193.046,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[143.686,193.046,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":152,"s":[152.299,193.077,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[152.299,193.077,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":216,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"t":228,"s":[138.817,193.029,0]}]},"a":{"a":0,"k":[147.88,185.335,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":60,"s":[99.787,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":72,"s":[99.787,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":112,"s":[99.787,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":128,"s":[95,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":140,"s":[95,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[80,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":174,"s":[80,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":192,"s":[99.787,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":216,"s":[99.787,100,100]},{"t":228,"s":[99.787,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[-0.452,-1.863],[3.093,-0.314],[0.452,1.863],[-3.093,0.314]],"o":[[0.452,1.863],[-3.093,0.314],[-0.452,-1.863],[3.093,-0.314]],"v":[[2.407,14.924],[-2.375,18.866],[-8.794,16.062],[-4.012,12.12]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[-0.452,-1.863],[3.093,-0.314],[0.452,1.863],[-3.093,0.314]],"o":[[0.452,1.863],[-3.093,0.314],[-0.452,-1.863],[3.093,-0.314]],"v":[[2.407,14.924],[-2.375,18.866],[-8.794,16.062],[-4.012,12.12]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":182,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":188,"s":[{"i":[[-0.452,-1.863],[3.093,-0.314],[0.452,1.863],[-3.093,0.314]],"o":[[0.452,1.863],[-3.093,0.314],[-0.452,-1.863],[3.093,-0.314]],"v":[[2.407,14.924],[-2.375,18.866],[-8.794,16.062],[-4.012,12.12]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":194,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"t":234,"s":[{"i":[[-0.452,-1.863],[3.093,-0.314],[0.452,1.863],[-3.093,0.314]],"o":[[0.452,1.863],[-3.093,0.314],[-0.452,-1.863],[3.093,-0.314]],"v":[[2.407,14.924],[-2.375,18.866],[-8.794,16.062],[-4.012,12.12]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":80,"s":[0,0,0,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":86,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":170,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":176,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":182,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":188,"s":[0,0,0,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":194,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":228,"s":[1,1,1,1]},{"t":234,"s":[0,0,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[149.824,171.565]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[5.062,-6.391],[20.249,0.534],[6.627,5.855],[-18.219,-0.566]],"o":[[-5.425,6.85],[-17.702,-0.466],[-6.809,-6.015],[20.458,0.636]],"v":[[27.893,12.284],[-0.054,7.019],[-28.57,12.484],[1.562,-4.579]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[5.062,-6.391],[20.249,0.534],[6.627,5.855],[-18.219,-0.566]],"o":[[-5.425,6.85],[-17.702,-0.466],[-6.809,-6.015],[20.458,0.636]],"v":[[27.893,12.284],[-0.054,7.019],[-28.57,12.484],[1.562,-4.579]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":182,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":188,"s":[{"i":[[5.062,-6.391],[20.249,0.534],[6.627,5.855],[-18.219,-0.566]],"o":[[-5.425,6.85],[-17.702,-0.466],[-6.809,-6.015],[20.458,0.636]],"v":[[27.893,12.284],[-0.054,7.019],[-28.57,12.484],[1.562,-4.579]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":194,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"t":234,"s":[{"i":[[5.062,-6.391],[20.249,0.534],[6.627,5.855],[-18.219,-0.566]],"o":[[-5.425,6.85],[-17.702,-0.466],[-6.809,-6.015],[20.458,0.636]],"v":[[27.893,12.284],[-0.054,7.019],[-28.57,12.484],[1.562,-4.579]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":80,"s":[6]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":86,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":176,"s":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":182,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":188,"s":[6]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":194,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[0]},{"t":234,"s":[6]}]},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[147.88,185.335]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[147.88,185.335]},"a":{"a":0,"k":[147.88,185.335]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"eye","parent":32,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[307.76,193.862,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":72,"s":[301.917,193.842,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[301.917,193.842,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[306.786,193.859,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":140,"s":[306.786,193.859,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":152,"s":[306.786,193.859,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[306.786,193.859,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[301.917,193.842,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":216,"s":[301.917,193.842,0],"to":[0,0,0],"ti":[0,0,0]},{"t":228,"s":[307.76,193.862,0]}]},"a":{"a":0,"k":[293.018,185.074,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":60,"s":[115,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":72,"s":[105,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":112,"s":[105,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":128,"s":[115,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":140,"s":[115,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[120,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":174,"s":[120,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":192,"s":[105,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":216,"s":[105,100,100]},{"t":228,"s":[115,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[0.393,-2.046],[1.834,0.352],[-0.393,2.046],[-1.834,-0.352]],"o":[[-0.393,2.046],[-1.834,-0.352],[0.393,-2.046],[1.834,0.352]],"v":[[7.462,7.436],[3.43,10.502],[0.819,6.161],[4.851,3.094]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[0.393,-2.046],[1.834,0.352],[-0.393,2.046],[-1.834,-0.352]],"o":[[-0.393,2.046],[-1.834,-0.352],[0.393,-2.046],[1.834,0.352]],"v":[[7.462,7.436],[3.43,10.502],[0.819,6.161],[4.851,3.094]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":182,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":188,"s":[{"i":[[0.393,-2.046],[1.834,0.352],[-0.393,2.046],[-1.834,-0.352]],"o":[[-0.393,2.046],[-1.834,-0.352],[0.393,-2.046],[1.834,0.352]],"v":[[7.462,7.436],[3.43,10.502],[0.819,6.161],[4.851,3.094]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":194,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"t":234,"s":[{"i":[[0.393,-2.046],[1.834,0.352],[-0.393,2.046],[-1.834,-0.352]],"o":[[-0.393,2.046],[-1.834,-0.352],[0.393,-2.046],[1.834,0.352]],"v":[[7.462,7.436],[3.43,10.502],[0.819,6.161],[4.851,3.094]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":80,"s":[0,0,0,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":86,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":170,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":176,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":182,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":188,"s":[0,0,0,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":194,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":228,"s":[1,1,1,1]},{"t":234,"s":[0,0,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[289.869,171.446]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[-4.028,-4.701],[-16.852,0.144],[-3.874,5.201],[11.871,-2.293]],"o":[[4.332,5.056],[16.513,-0.141],[3.569,-4.791],[-11.871,2.293]],"v":[[-18.384,5.894],[0.65,-1.771],[20.406,5.307],[-1.229,-11.575]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[-4.427,-16.68],[-11.76,4.217],[4.427,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[-4.428,-16.68],[-11.76,4.217],[4.428,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[-4.028,-4.701],[-16.852,0.144],[-3.874,5.201],[11.871,-2.293]],"o":[[4.332,5.056],[16.513,-0.141],[3.569,-4.791],[-11.871,2.293]],"v":[[-18.384,5.894],[0.65,-1.771],[20.406,5.307],[-1.229,-11.575]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":182,"s":[{"i":[[-4.427,-16.68],[-11.76,4.217],[4.427,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":188,"s":[{"i":[[-4.028,-4.701],[-16.852,0.144],[-3.874,5.201],[11.871,-2.293]],"o":[[4.332,5.056],[16.513,-0.141],[3.569,-4.791],[-11.871,2.293]],"v":[[-18.384,5.894],[0.65,-1.771],[20.406,5.307],[-1.229,-11.575]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":194,"s":[{"i":[[-4.427,-16.68],[-11.76,4.217],[4.427,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-4.428,-16.68],[-11.76,4.217],[4.428,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"t":234,"s":[{"i":[[-4.028,-4.701],[-16.852,0.144],[-3.874,5.201],[11.871,-2.293]],"o":[[4.332,5.056],[16.513,-0.141],[3.569,-4.791],[-11.871,2.293]],"v":[[-18.384,5.894],[0.65,-1.771],[20.406,5.307],[-1.229,-11.575]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":80,"s":[6]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":86,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":176,"s":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":182,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":188,"s":[6]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":194,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[0]},{"t":234,"s":[6]}]},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[293.018,185.074]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[293.018,185.074]},"a":{"a":0,"k":[293.018,185.074]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[149.824,171.565]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[147.88,185.335]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[147.88,185.335]},"a":{"a":0,"k":[147.88,185.335]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"beak_bl","parent":31,"sr":1,"ks":{"r":{"a":0,"k":-26.335},"p":{"a":0,"k":[211.876,216.495,0]},"a":{"a":0,"k":[35.051,-0.937,0]},"s":{"a":0,"k":[-100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[31.846,-15.21],[-9.151,-31.298]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[31.846,-15.21],[-9.151,-31.298]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[31.846,-15.21],[-9.151,-31.298]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[43.175,-19.787],[2.178,-35.875]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[42.855,-15.249],[1.859,-31.337]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[37.628,-18.009],[-3.368,-34.097]],"c":false}]},{"t":216,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[31.846,-15.21],[-9.151,-31.298]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.517647058824,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[24.706,22.107]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[95]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":-14,"op":354,"st":10,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"mouth","parent":32,"sr":1,"ks":{"p":{"a":0,"k":[237.401,247.552,0]},"a":{"a":0,"k":[237.401,247.552,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[33.146,5.228],[-7.617,-0.476],[0,0]],"o":[[0,0],[7.617,0.476],[-36.437,2.698]],"v":[[-67.852,0.563],[-17.759,4.038],[49.944,0.695]],"c":true}]},{"t":128,"s":[{"i":[[33.146,5.228],[-7.617,-0.476],[0,0]],"o":[[0,0],[7.617,0.476],[-36.437,2.698]],"v":[[-67.852,0.563],[-17.759,4.038],[49.944,0.695]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.490196079016,0.035294119269,0.035294119269,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[237.401,247.552]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"fl","c":{"a":0,"k":[0.490196078431,0.035294117647,0.035294117647,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"beak","parent":35,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":60,"s":[-0.134]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":72,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":116,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":178,"s":[7.771]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":196,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":206,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":216,"s":[-0.134]},{"t":228,"s":[-0.134]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[6.825,60.141,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":72,"s":[26.289,70.441,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[26.289,70.441,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":128,"s":[9.223,89.945,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[9.223,89.945,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[-42.294,11.783,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[-33.624,88.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":192,"s":[26.289,70.441,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":216,"s":[26.289,70.441,0],"to":[0,0,0],"ti":[0,0,0]},{"t":228,"s":[6.825,60.141,0]}]},"a":{"a":0,"k":[227.021,227.06,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[12.67,4.843],[26.569,-0.895],[38.329,-5.184],[-1.527,-10.216],[-6.604,-0.924],[-33.038,1.174],[7.149,7.125]],"o":[[-22.616,-8.645],[-20.157,0.679],[-15.975,2.16],[0.912,7.325],[45.699,6.397],[11.541,-0.41],[12.67,-12.213]],"v":[[42.778,2.247],[0.134,-43.954],[-56.562,-0.787],[-76.4,20.973],[-64.732,37.374],[51.997,39.136],[61.526,18.975]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[10.355,4.062],[17.947,0.289],[29.75,-3.088],[-1.467,-9.194],[-6.347,-0.832],[-26.436,1.174],[0.444,17.051]],"o":[[-20.875,-8.189],[-18.096,-0.291],[-15.409,1.6],[0.876,6.592],[43.921,5.757],[9.235,-0.41],[-0.444,-17.051]],"v":[[43.983,2.761],[-2.103,-38.666],[-57.394,3.669],[-76.46,23.253],[-65.246,38.014],[51.361,39.136],[68.329,21.585]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[10.355,4.062],[17.947,0.289],[29.75,-3.088],[-1.467,-9.194],[-6.347,-0.832],[-26.436,1.174],[0.444,17.051]],"o":[[-20.875,-8.189],[-18.096,-0.291],[-15.409,1.6],[0.876,6.592],[43.921,5.757],[9.235,-0.41],[-0.444,-17.051]],"v":[[43.983,2.761],[-2.103,-38.666],[-57.394,3.669],[-76.46,23.253],[-65.246,38.014],[51.361,39.136],[68.329,21.585]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[10.355,4.062],[23.28,2.939],[29.75,-3.088],[-9.177,-8.492],[-6.347,-0.832],[-31.934,6.314],[0.444,17.051]],"o":[[-20.875,-8.189],[-21.351,-2.695],[-15.409,1.6],[-9.719,6.921],[43.921,5.757],[9.068,-1.793],[-0.444,-17.051]],"v":[[36.202,0.164],[2.318,-49.44],[-57.394,3.669],[-65.738,20.722],[-65.246,38.014],[51.361,39.136],[68.329,21.585]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[11.029,1.444],[23.28,2.939],[29.75,-3.088],[-9.177,-8.492],[-6.156,-1.753],[-30.244,12.038],[2.189,10.683]],"o":[[-17.364,-2.273],[-21.351,-2.695],[-15.409,1.6],[-9.719,6.921],[41.809,11.908],[12.417,-4.942],[-3.424,-16.71]],"v":[[42.32,-0.556],[-5.089,-38.611],[-57.394,3.669],[-65.738,20.722],[-65.235,34.931],[64.034,35.18],[77.687,14.942]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[{"i":[[12.67,4.843],[26.569,-0.895],[38.329,-5.184],[-1.527,-10.216],[-6.604,-0.924],[-33.038,1.174],[7.149,7.125]],"o":[[-22.616,-8.645],[-20.157,0.679],[-15.975,2.16],[0.912,7.325],[45.699,6.397],[11.541,-0.41],[12.67,-12.213]],"v":[[42.778,2.247],[0.134,-43.954],[-56.562,-0.787],[-76.4,20.973],[-64.732,37.374],[51.997,39.136],[61.526,18.975]],"c":true}]},{"t":216,"s":[{"i":[[12.67,4.843],[26.569,-0.895],[38.329,-5.184],[-1.527,-10.216],[-6.604,-0.924],[-33.038,1.174],[7.149,7.125]],"o":[[-22.616,-8.645],[-20.157,0.679],[-15.975,2.16],[0.912,7.325],[45.699,6.397],[11.541,-0.41],[12.67,-12.213]],"v":[[42.778,2.247],[0.134,-43.954],[-56.562,-0.787],[-76.4,20.973],[-64.732,37.374],[51.997,39.136],[61.526,18.975]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.811764717102,0.207843139768,0.007843137719,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.364705890417,0.121568627656,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[227.021,227.06]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"head_bl2","parent":35,"sr":1,"ks":{"p":{"a":0,"k":[121.325,22.259,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,-35.646],[19.005,-18.433]],"o":[[28.147,25.502],[0,28.584],[0,0]],"v":[[-22.887,-83.863],[22.887,12.639],[-7.452,83.863]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.988235294819,0.933333337307,0.129411771894,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[5]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"head_bl1","parent":35,"sr":1,"ks":{"r":{"a":0,"k":-21.149},"p":{"a":0,"k":[-15.163,40.193,0]},"a":{"a":0,"k":[71.641,94.652,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[-26.697,16.101],[-13.876,3.539]],"o":[[11.529,-27.092],[11.933,-7.196],[0,0]],"v":[[-49.05,41.823],[10.169,-25.495],[49.05,-41.823]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[0,0],[-26.698,17.712],[-13.876,3.893]],"o":[[11.529,-29.805],[11.933,-7.917],[0,0]],"v":[[-49.05,41.823],[10.169,-32.236],[49.05,-50.199]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[0,0],[-26.698,17.712],[-13.876,3.893]],"o":[[11.529,-29.805],[11.933,-7.917],[0,0]],"v":[[-49.05,41.823],[10.169,-32.236],[49.05,-50.199]],"c":false}]},{"t":152,"s":[{"i":[[0,0],[-26.697,16.101],[-13.876,3.539]],"o":[[11.529,-27.092],[11.933,-7.196],[0,0]],"v":[[-49.05,41.823],[10.169,-25.495],[49.05,-41.823]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[5]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":"head","parent":37,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":152,"s":[-0.07]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[-11.109]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":190,"s":[7.381]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":208,"s":[-11.109]},{"t":216,"s":[-0.07]}]},"p":{"a":0,"k":[13.86,-52.631,0]},"a":{"a":0,"k":[0,131.046,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":142,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[102,98,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":162,"s":[98,102,100]},{"t":172,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[0,39.247],[93.266,0],[0,-83.375],[-28.671,-23.75]],"o":[[29.034,-23.938],[0,-83.375],[-93.265,0],[0,39.353],[0,0]],"v":[[122.976,131.046],[168.871,34.404],[0,-131.046],[-168.871,34.404],[-123.254,130.814]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[0,0],[0,41.488],[93.266,0],[0,-88.135],[-28.671,-25.106]],"o":[[29.034,-25.304],[0,-88.135],[-93.265,0],[0,41.6],[0,0]],"v":[[122.976,131.046],[168.871,28.886],[0,-146.008],[-168.871,28.886],[-123.254,130.801]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[0,0],[0,41.488],[93.266,0],[0,-88.135],[-28.671,-25.106]],"o":[[29.034,-25.304],[0,-88.135],[-93.265,0],[0,41.6],[0,0]],"v":[[122.976,131.046],[168.871,28.886],[0,-146.008],[-168.871,28.886],[-123.254,130.801]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[0,0],[0,39.247],[93.266,0],[0,-83.375],[-28.671,-23.75]],"o":[[29.034,-23.938],[0,-83.375],[-93.265,0],[0,39.353],[0,0]],"v":[[122.976,131.046],[168.871,34.404],[0,-131.046],[-168.871,34.404],[-123.254,130.814]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[0,0],[0,39.247],[93.266,0],[0,-83.375],[-28.671,-23.75]],"o":[[29.034,-23.938],[0,-83.375],[-93.265,0],[0,39.353],[0,0]],"v":[[122.976,131.046],[168.871,34.404],[0,-131.046],[-168.871,34.404],[-123.254,130.814]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0,0],[-3.003,39.132],[92.992,7.135],[6.379,-83.131],[-26.77,-25.874]],"o":[[30.78,-21.646],[6.379,-83.131],[-92.991,-7.135],[-3.011,39.238],[0,0]],"v":[[112.472,139.977],[165.625,47.129],[9.907,-130.755],[-171.126,21.29],[-133.019,120.908]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[0,0],[1.65,39.212],[93.183,-3.921],[-3.506,-83.301],[-29.644,-22.524]],"o":[[28.002,-25.137],[-3.506,-83.301],[-93.182,3.921],[1.655,39.319],[0,0]],"v":[[128.377,125.759],[170.168,27.273],[-5.51,-130.93],[-167.275,41.473],[-117.645,135.881]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":208,"s":[{"i":[[0,0],[-3.351,39.104],[92.925,7.964],[7.119,-83.071],[-26.538,-26.112]],"o":[[30.972,-21.371],[7.119,-83.071],[-92.924,-7.964],[-3.36,39.21],[0,0]],"v":[[111.237,140.989],[165.216,48.619],[11.09,-130.646],[-171.292,19.779],[-134.074,119.732]],"c":false}]},{"t":216,"s":[{"i":[[0,0],[0,39.247],[93.266,0],[0,-83.375],[-28.671,-23.75]],"o":[[29.034,-23.938],[0,-83.375],[-93.265,0],[0,39.353],[0,0]],"v":[[122.976,131.046],[168.871,34.404],[0,-131.046],[-168.871,34.404],[-123.254,130.814]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":36,"ty":4,"nm":"body_bl","parent":37,"sr":1,"ks":{"p":{"a":0,"k":[-119.736,-0.714,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[0.532,30.674],[-7.534,10.558]],"o":[[-0.532,-30.634],[7.534,-10.558]],"v":[[-4.68,39.243],[16.13,-34.978]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0.532,30.674],[-7.534,10.558]],"o":[[-0.532,-30.634],[7.534,-10.558]],"v":[[-18.107,55.658],[2.703,-18.562]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[0.532,30.674],[-7.534,10.558]],"o":[[-0.532,-30.634],[7.534,-10.558]],"v":[[-1.438,35.627],[19.371,-38.593]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":208,"s":[{"i":[[4.283,30.378],[-6.185,11.401]],"o":[[-4.278,-30.338],[6.185,-11.401]],"v":[[-6.173,61.533],[5.395,-14.676]],"c":false}]},{"t":216,"s":[{"i":[[0.532,30.674],[-7.534,10.558]],"o":[[-0.532,-30.634],[7.534,-10.558]],"v":[[-4.68,39.243],[16.13,-34.978]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[5]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":37,"ty":4,"nm":"body","parent":16,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":152,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[8.001]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":190,"s":[-5.672]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":208,"s":[8.001]},{"t":216,"s":[0]}]},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[0,96.715,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":60,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":70,"s":[98,102,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":80,"s":[102,98,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":140,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":150,"s":[102,98,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":160,"s":[98,102,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":170,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":200,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":210,"s":[102,98,100]},{"t":220,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[71.236,0],[5.903,43.474],[-2.258,8.046],[-3.176,8.703],[-80.635,0],[-6.187,-98.296]],"o":[[-70.876,0],[-1.544,-11.374],[3.64,-12.969],[26.363,-72.246],[88.008,0],[4.493,71.386]],"v":[[9.675,96.704],[-140.688,40.912],[-139.291,9.007],[-130.851,-17.988],[9.675,-96.715],[170.594,27.852]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[67.887,-11.068],[12.142,42.029],[-0.946,8.299],[-1.722,9.091],[-77.788,0],[-20.63,-96.141]],"o":[[-67.543,11.012],[-3.177,-10.996],[1.525,-13.378],[14.294,-75.464],[84.9,0],[14.982,69.821]],"v":[[0.936,100.7],[-150.719,68.948],[-154.17,37.213],[-150.173,9.235],[14.946,-96.715],[143.968,7.681]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[72.128,5.61],[2.5,43.804],[-2.93,7.843],[-3.176,8.703],[-80.635,0],[1.597,-98.478]],"o":[[-71.763,-5.581],[-0.654,-11.461],[4.723,-12.642],[26.363,-72.246],[88.008,0],[-1.16,71.518]],"v":[[5.171,103.309],[-142.612,35.849],[-138.646,4.154],[-130.851,-17.988],[9.675,-96.715],[173.612,47.342]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":208,"s":[{"i":[[67.774,-11.068],[12.121,42.029],[-0.945,8.299],[-1.719,9.091],[-77.659,0],[-20.595,-96.141]],"o":[[-67.431,11.012],[-3.171,-10.996],[1.523,-13.378],[14.271,-75.464],[84.76,0],[14.957,69.821]],"v":[[10.671,99.32],[-140.733,67.567],[-144.178,35.833],[-140.188,7.855],[24.658,-98.095],[153.466,6.301]],"c":true}]},{"t":216,"s":[{"i":[[71.236,0],[5.903,43.474],[-2.258,8.046],[-3.176,8.703],[-80.635,0],[-6.187,-98.296]],"o":[[-70.876,0],[-1.544,-11.374],[3.64,-12.969],[26.363,-72.246],[88.008,0],[4.493,71.386]],"v":[[9.675,96.704],[-140.688,40.912],[-139.291,9.007],[-130.851,-17.988],[9.675,-96.715],[170.594,27.852]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":38,"ty":4,"nm":"wing_r","parent":20,"sr":1,"ks":{"r":{"a":0,"k":-10.217},"p":{"a":0,"k":[-47.701,27.595,0]},"a":{"a":0,"k":[-55.027,0,0]},"s":{"a":0,"k":[97.223,102.418,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-1.344,-14.601],[18.156,3.909]],"o":[[29.698,34.178],[7.257,81.386],[0,0]],"v":[[-63.22,-73.982],[42.009,-45.869],[-105.875,19.506]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"_032_SIM","refId":"comp_0","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]},"a":{"a":0,"k":[256,256,0]}},"ao":0,"w":512,"h":512,"ip":0,"op":180,"st":-60,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/utyan_newborn.json b/TMessagesProj/src/main/res/raw/utyan_newborn.json deleted file mode 100644 index 7d6a61feb..000000000 --- a/TMessagesProj/src/main/res/raw/utyan_newborn.json +++ /dev/null @@ -1 +0,0 @@ -{"v":"5.8.1","fr":60,"ip":0,"op":150,"w":512,"h":512,"nm":"_2_chik_noline_referce","ddd":0,"assets":[{"id":"comp_0","nm":"_2_chik_noline_easestop","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"egg_b_tr 6","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-18.479,-43.267,0],"ix":2,"l":2},"a":{"a":0,"k":[-18.479,-43.267,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-36.71,-90.037],[-12.471,-111.182],[-17.842,-139.982],[-7.757,-147.278]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[18.23,46.77],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":47,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":79,"s":[0]},{"t":81,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":79,"s":[100]},{"t":81,"s":[28]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":81,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"egg_b_tr 5","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-0.355,"ix":10},"p":{"a":0,"k":[146.387,290.13,0],"ix":2,"l":2},"a":{"a":0,"k":[-18.479,-43.267,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[8.08,-7.048],[0,0],[0,0],[0,0]],"v":[[-42.089,-89.053],[-15.239,-111.549],[-17.842,-139.982],[-7.757,-147.278]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[18.23,46.77],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":47,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":79,"s":[0]},{"t":81,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":79,"s":[100]},{"t":81,"s":[28]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":81,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"grandnull","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.153,386.731,0],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":212,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":3,"nm":"NULL CONTROL","parent":3,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.535],"y":[1]},"o":{"x":[0.536],"y":[0]},"t":11.211,"s":[-9.809]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.473],"y":[0]},"t":19.061,"s":[12.154]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":26.666,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":33.334,"s":[0]},{"i":{"x":[0.535],"y":[1]},"o":{"x":[0.536],"y":[0]},"t":44.547,"s":[-9.809]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.473],"y":[0]},"t":52.395,"s":[12.154]},{"t":60,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[57.77,176.006,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[57.77,176.006,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":212,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"egg_t_6","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,160.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[-181.485,100.295],[-160.692,120.39],[-148.352,105.01],[-136.002,131.24],[-121.102,149.24],[-102.062,124.76],[-94.702,131.24],[-69.362,110.16],[-52.692,106.56],[-43.142,124.76],[-43.142,144.61],[-25.432,133.81],[-13.092,145.13],[-8.972,159.53],[24.967,117.82],[45.487,129.91],[61.478,92.14],[95.938,103.98],[105.198,128.67],[126.277,145.64],[138.038,114.78],[148.908,122.59],[154.568,141.53],[181.509,97.928]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[50]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[29]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[29]},{"t":52,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[50]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[66]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[66]},{"t":52,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":70,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"egg_t_81","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]},{"t":170,"s":[{"i":[[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":170,"op":186,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"egg_t_23","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":166,"op":170,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"egg_t_18","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[24.95,-19.767],[0,-89.581],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[58.602,45.959]],"o":[[-58.226,46.131],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-89.939],[-24.778,-19.432]],"v":[[-82.669,-123.861],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[82.468,-124.412]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[24.95,-19.767],[0,-89.581],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[58.602,45.959]],"o":[[-58.226,46.131],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-89.939],[-24.778,-19.432]],"v":[[-82.669,-123.861],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[82.468,-124.412]],"c":true}]},{"t":165,"s":[{"i":[[46.665,-3.093],[0,-84.4],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53.231,48.02]],"o":[[-52.841,48.138],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-84.778],[-51.798,-3.447]],"v":[[-92.589,-115.421],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[92.375,-116.068]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"egg_t_17","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[32.825,-46.917],[0,-65.144],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[33.991,48.638]],"o":[[-34.038,48.65],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-65.092],[-32.833,-46.981]],"v":[[-125.876,-77.152],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[126.456,-77.038]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[32.825,-46.917],[0,-65.144],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[33.991,48.638]],"o":[[-34.038,48.65],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-65.092],[-32.833,-46.981]],"v":[[-125.876,-77.152],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[126.456,-77.038]],"c":true}]},{"t":164,"s":[{"i":[[57.71,-3.99],[0,-59.703],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[29.153,47.044]],"o":[[-29.197,47.062],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-59.652],[-47.63,-8.609]],"v":[[-134.133,-64.62],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[134.707,-64.501]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"egg_t_16","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[32.591,-71.193],[0,-46.475],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[17.771,39.902]],"o":[[-18.586,40.601],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-45.35],[-32.373,-72.69]],"v":[[-151.809,-31.571],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[153.643,-28.617]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[32.591,-71.193],[0,-46.475],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[17.771,39.902]],"o":[[-18.586,40.601],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-45.35],[-32.373,-72.69]],"v":[[-151.809,-31.571],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[153.643,-28.617]],"c":true}]},{"t":163,"s":[{"i":[[64.472,-5.011],[0,-42.058],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[14.765,37.016]],"o":[[-15.466,37.737],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-41.017],[-70.454,-16.819]],"v":[[-156.896,-19.837],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[158.53,-17.03]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"egg_t_15","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[27.378,-91.558],[0,-31.11],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.219,28.496]],"o":[[-8.794,29.408],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-30.02],[-26.817,-92.976]],"v":[[-167.598,10.464],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[169.006,13.559]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[27.378,-91.558],[0,-31.11],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.219,28.496]],"o":[[-8.794,29.408],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-30.02],[-26.817,-92.976]],"v":[[-167.598,10.464],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[169.006,13.559]],"c":true}]},{"t":162,"s":[{"i":[[107.699,-11.215],[0,-27.992],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[6.72,25.908]],"o":[[-7.196,26.767],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-27.004],[-65.795,-15.553]],"v":[[-170.122,19.357],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[171.371,22.195]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"egg_t_14","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[85.449,0],[19.735,-106.678],[0,-19.177],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-84.283,0],[-3.479,18.804],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-17.671]],"v":[[0.25,-155.28],[-175.931,44.989],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[85.449,0],[19.735,-106.678],[0,-19.177],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-84.283,0],[-3.479,18.804],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-17.671]],"v":[[0.25,-155.28],[-175.931,44.989],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":161,"s":[{"i":[[128.521,-14.996],[0,-17.22],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[2.407,15.663]],"o":[[-2.823,16.956],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-15.865],[-70.009,-15.999]],"v":[[-176.945,50.759],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[178.086,54.761]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"egg_t_13","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[10.689,-118.329],[0,-9.212],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.538,7.383]],"o":[[-0.829,9.178],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.398],[-8.768,-120.321]],"v":[[-180.004,74.572],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.946,79.994]],"c":true}]},{"t":160,"s":[{"i":[[124.822,-19.096],[0,-8.268],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.435,6.63]],"o":[[-0.67,8.246],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-6.641],[-43.027,-12.465]],"v":[[-180.246,77.393],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[181.103,82.262]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"egg_t_12","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":159,"s":[{"i":[[82.336,-11.719],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-0.785,0.112],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-51.683,-20.716]],"v":[[-181.259,99.681],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.738,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.528,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[179.76,104.678]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":159,"op":160,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"egg_t_22","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[172.972,116.399],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[97.688,109.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[171.47,118.83]],"c":false}]},{"t":160,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[172.972,116.399],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"egg_t_21","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-6.645,13.26]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[2.073,-4.137]],"v":[[-53.943,108.31],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.218,122.07],[45.737,134.16],[53.904,108.81]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"egg_t_11","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-170.29,115.123],[-160.442,124.64],[-150.966,112.828],[-148.102,109.26],[-147.165,111.251],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-170.473,114.946],[-160.442,124.64],[-151.96,114.067],[-148.852,113.51],[-146.017,113.689],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-53.943,108.81]],"c":false}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-170.29,115.123],[-160.442,124.64],[-150.966,112.828],[-148.102,109.26],[-147.165,111.251],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"egg_t_20","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.611,6.042]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,-8.372],[-8.722,-86.321]],"v":[[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[161.03,135.726],[181.759,102.178],[180.822,80.619]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[102.138,124.095],[105.448,132.92],[126.527,149.89],[135.288,127.53],[149.658,129.09],[154.818,145.78],[163.209,132.2]],"c":false}]},{"t":160,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.611,6.042]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,-8.372],[-8.722,-86.321]],"v":[[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[161.03,135.726],[181.759,102.178],[180.822,80.619]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"egg_t_19","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[-0.685,3.059],[-9.375,11.891],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.607,-7.177],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[46.657,129.242],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.287,119.03],[149.157,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-2.204,7.069]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-20.991,0.003]],"v":[[-46.442,122.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[48.568,122.615]],"c":false}]},{"t":160,"s":[{"i":[[-0.685,3.059],[-9.375,11.891],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.607,-7.177],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[46.657,129.242],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.287,119.03],[149.157,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"egg_t_10","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-138.058,130.593],[-135.752,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.137,2.415],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-139.163,128.246],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-80.718,124.065]],"c":false}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-138.058,130.593],[-135.752,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"egg_t_80","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":83,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-43.892,132.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[17.278,131.827]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":83,"op":84,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"egg_t_90","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[100.452,120.267],[105.448,132.92],[126.527,149.89],[135.788,123.53],[149.157,126.84],[154.818,145.78],[166.399,127.038]],"c":false}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"egg_t_89","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-3.577,9.555]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-44.168,-3.001]],"v":[[-48.947,117.471],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.218,122.07],[45.737,134.16],[50.244,117.222]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"egg_t_79","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-142.462,121.239],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-72.782,117.29]],"c":false}]},{"t":160,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"egg_t_78","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-98.274,132.126],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.723,163.78],[25.217,122.07],[45.737,134.16],[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":81,"s":[{"i":[[-0.004,-0.401],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-180.235,105.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.113,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.729,101.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[177.243,109.487]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-98.274,132.126],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.723,163.78],[25.217,122.07],[45.737,134.16],[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":81,"op":82,"st":0,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"egg_t_77","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[10.622,-118.401],[0,-9.147],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.582,7.682]],"o":[[-0.818,9.115],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.699],[-9.094,-119.994]],"v":[[-180.021,74.765],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.879,79.092]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":80,"s":[{"i":[[123.336,-12.013],[0,-8.21],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.47,6.899]],"o":[[-0.661,8.188],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-6.911],[-154.472,-18.4]],"v":[[-180.26,77.567],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[181.049,81.453]],"c":false}]},{"t":160,"s":[{"i":[[10.622,-118.401],[0,-9.147],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.582,7.682]],"o":[[-0.818,9.115],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.699],[-9.094,-119.994]],"v":[[-180.021,74.765],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.879,79.092]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":81,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"egg_t_76","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[23.972,-99.244],[0,-25.141],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.146,22.785]],"o":[[-5.861,24.266],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-23.492],[-22.887,-101.326]],"v":[[-172.219,27.574],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[173.836,32.357]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":79,"s":[{"i":[[99.994,-12.501],[0,-22.593],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[4.187,20.601]],"o":[[-4.774,21.967],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-21.105],[-102.755,-13.847]],"v":[[-173.918,34.979],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[175.331,39.325]],"c":false}]},{"t":160,"s":[{"i":[[23.972,-99.244],[0,-25.141],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.146,22.785]],"o":[[-5.861,24.266],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-23.492],[-22.887,-101.326]],"v":[[-172.219,27.574],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[173.836,32.357]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":79,"op":80,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"egg_t_75","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[33.354,-63.059],[0,-52.607],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[22.474,43.499]],"o":[[-23.284,44.02],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-51.586],[-33.276,-64.407]],"v":[[-144.055,-47.311],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[145.899,-44.74]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":78,"s":[{"i":[[87.812,-6.089],[0,-47.771],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[18.835,40.807]],"o":[[-19.545,41.38],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-46.813],[-98.323,-11.581]],"v":[[-150.236,-34.953],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[151.9,-32.461]],"c":false}]},{"t":160,"s":[{"i":[[33.354,-63.059],[0,-52.607],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[22.474,43.499]],"o":[[-23.284,44.02],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-51.586],[-33.276,-64.407]],"v":[[-144.055,-47.311],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[145.899,-44.74]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"egg_t_74","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[17.832,-9.166],[0,-102.587],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[71.209,37.788]],"o":[[-72.075,37.047],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-101.78],[-18.32,-9.722]],"v":[[-56.248,-141.021],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[58.442,-140.136]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":77,"s":[{"i":[[29.168,0.107],[0,-98.586],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[66.814,41.184]],"o":[[-67.78,40.49],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-97.682],[-34.371,-1.52]],"v":[[-64.591,-136.387],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[66.948,-135.26]],"c":false}]},{"t":160,"s":[{"i":[[17.832,-9.166],[0,-102.587],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[71.209,37.788]],"o":[[-72.075,37.047],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-101.78],[-18.32,-9.722]],"v":[[-56.248,-141.021],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[58.442,-140.136]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"egg_t_4","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":77,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"egg_bl17","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[107.034,99.923,0],"ix":2,"l":2},"a":{"a":0,"k":[18.048,23.191,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.749,-2.071],[2.071,-1.749],[1.749,2.072],[-2.072,1.75]],"o":[[1.749,2.071],[-2.071,1.75],[-1.75,-2.071],[2.071,-1.749]],"v":[[3.751,-3.168],[3.168,3.75],[-3.75,3.167],[-3.167,-3.751]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30.347,40.632],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.948,-5.859],[5.859,-4.948],[4.948,5.859],[-5.859,4.948]],"o":[[4.948,5.859],[-5.859,4.948],[-4.948,-5.859],[5.859,-4.948]],"v":[[10.609,-8.96],[8.96,10.609],[-10.609,8.959],[-8.96,-10.609]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.806,15.807],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":165,"op":180,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"egg_bl16","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[107.034,99.923,0],"ix":2,"l":2},"a":{"a":0,"k":[18.048,23.191,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.749,-2.071],[2.071,-1.749],[1.749,2.072],[-2.072,1.75]],"o":[[1.749,2.071],[-2.071,1.75],[-1.75,-2.071],[2.071,-1.749]],"v":[[3.751,-3.168],[3.168,3.75],[-3.75,3.167],[-3.167,-3.751]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30.347,40.632],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.948,-5.859],[-0.262,-2.711],[3.62,-3.057],[4.948,5.859],[-0.207,3.436],[-3.947,0.25]],"o":[[1.891,2.239],[0.423,4.385],[-5.859,4.948],[-2.396,-2.838],[0.22,-3.659],[12.003,-0.76]],"v":[[7.109,0.04],[13.821,-1.347],[8.96,10.609],[-10.609,8.959],[-13.861,-0.833],[-2.96,-1.609]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.806,15.807],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"egg_bl3","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[107.034,99.923,0],"ix":2,"l":2},"a":{"a":0,"k":[18.048,23.191,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.749,-2.071],[2.071,-1.749],[1.749,2.072],[-2.072,1.75]],"o":[[1.749,2.071],[-2.071,1.75],[-1.75,-2.071],[2.071,-1.749]],"v":[[3.751,-3.168],[3.168,3.75],[-3.75,3.167],[-3.167,-3.751]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30.347,40.632],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.948,-5.859],[5.859,-4.948],[4.948,5.859],[-5.859,4.948]],"o":[[4.948,5.859],[-5.859,4.948],[-4.948,-5.859],[5.859,-4.948]],"v":[[10.609,-8.96],[8.96,10.609],[-10.609,8.959],[-8.96,-10.609]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.806,15.807],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":77,"st":0,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"egg_bl15","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[17.63,-60.68],[47.011,13.658],[-17.629,60.679],[-47.01,-13.659]],"o":[[-17.63,60.68],[-47.01,-13.659],[17.63,-60.68],[47.011,13.658]],"v":[[86.068,37.456],[-28.236,109.633],[-86.069,-12.556],[35.469,-109.633]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":166,"op":180,"st":0,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":"egg_bl14","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[16.009,-55.1],[47.011,13.658],[-17.629,60.679],[-30.814,16.075],[-35.246,0.552]],"o":[[-17.63,60.68],[-47.01,-13.659],[11.359,-39.097],[18.263,-0.455],[38.28,21.725]],"v":[[86.068,37.456],[-28.236,109.633],[-86.069,-12.556],[-16.234,-102.414],[47.774,-104.421]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":36,"ty":4,"nm":"egg_bl13","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.999,-30.973],[47.011,13.658],[-17.629,60.679],[-7.123,11.723],[-60.408,-0.531]],"o":[[-17.63,60.68],[-47.01,-13.659],[3.865,-13.304],[54.856,-6.088],[9.508,27.799]],"v":[[86.068,37.456],[-28.236,109.633],[-86.069,-12.556],[-69.327,-50.377],[84.437,-55.433]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":37,"ty":4,"nm":"egg_bl12","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.69,-16.141],[47.011,13.658],[-14.155,57.852],[-69.608,-1.013]],"o":[[-17.63,60.68],[-45.468,-13.211],[0.48,-1.962],[0.562,16.51]],"v":[[86.068,37.456],[-28.236,109.633],[-87.656,-6.626],[92.136,-12.19]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":38,"ty":4,"nm":"egg_bl11","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.33,-4.578],[47.011,13.658],[2.981,39.387],[-56.872,0.238]],"o":[[-17.63,60.68],[-35.075,-10.191],[35.564,-2.543],[-0.893,4.684]],"v":[[86.068,37.456],[-28.236,109.633],[-91.036,30.829],[89.4,23.548]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":39,"ty":4,"nm":"egg_bl10","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-44.024,-1.23],[42.443,12.331],[10.193,24.095]],"o":[[-21.242,48.522],[-25.483,-7.404],[48.469,-5.275]],"v":[[80.053,54.137],[-28.236,109.633],[-83.941,60.683]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":40,"ty":4,"nm":"egg_bl9","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-41.549,1.556],[33.892,9.846],[10.588,11.612]],"o":[[-23.652,29.267],[-15.896,-4.619],[48.522,-1.932]],"v":[[64.578,79.887],[-28.236,109.633],[-68.494,84.875]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":41,"ty":4,"nm":"Shape Layer 4","parent":10,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":51,"s":[0]},{"t":55,"s":[100]}],"ix":11},"r":{"a":0,"k":-10.372,"ix":10},"p":{"a":0,"k":[161.097,239.971,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-4.302,36.792],[-21.186,47.659],[-17.164,58.925],[16.01,39.441]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":42,"ty":4,"nm":"Shape Layer 3","parent":10,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":51,"s":[0]},{"t":55,"s":[100]}],"ix":11},"r":{"a":0,"k":-10.372,"ix":10},"p":{"a":0,"k":[150.866,301.747,0],"ix":2,"l":2},"a":{"a":0,"k":[-21.186,58.925,0],"ix":1,"l":2},"s":{"a":0,"k":[81.255,81.255,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[16.152,-6.03],[4.498,-1.206],[4.281,31.268],[-21.186,47.659],[-17.164,58.925],[16.01,39.441],[14.28,10.927],[24.404,2.971]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":78,"st":0,"bm":0},{"ddd":0,"ind":43,"ty":4,"nm":"egg_bl18","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-17.63,60.68],[45.422,-2.369],[-30.653,-8.906]],"o":[[-61.54,-2.602],[7.242,32.059],[47.011,13.658]],"v":[[85.068,39.956],[-88.894,45.224],[-28.236,109.633]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":44,"ty":4,"nm":"egg_bl2","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[17.63,-60.68],[47.011,13.658],[-17.629,60.679],[-47.01,-13.659]],"o":[[-17.63,60.68],[-47.01,-13.659],[17.63,-60.68],[47.011,13.658]],"v":[[86.068,37.456],[-28.236,109.633],[-86.069,-12.556],[35.469,-109.633]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":77,"st":0,"bm":0},{"ddd":0,"ind":45,"ty":4,"nm":"egg_bl4","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[241.403,207.828,0],"ix":2,"l":2},"a":{"a":0,"k":[21.324,22.678,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.288,-10.035],[6.939,5.73],[-8.287,10.036],[-6.939,-5.73]],"o":[[-8.288,10.035],[-6.939,-5.73],[8.288,-10.035],[6.939,5.73]],"v":[[12.621,11.117],[-13.356,16.698],[-12.787,-9.866],[14.135,-16.698]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[21.324,22.678],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":162,"op":180,"st":0,"bm":0},{"ddd":0,"ind":46,"ty":4,"nm":"egg_bl6","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[241.403,207.828,0],"ix":2,"l":2},"a":{"a":0,"k":[21.324,22.678,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.96,-4.795],[6.939,5.73],[-4.755,8.597],[0.396,-5.252]],"o":[[-8.288,10.035],[-5.887,-4.861],[0.85,-1.536],[-0.362,4.806]],"v":[[12.621,11.117],[-13.356,16.698],[-15.941,-5.269],[19.049,-3.739]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[21.324,22.678],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":47,"ty":4,"nm":"egg_bl1","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[241.403,207.828,0],"ix":2,"l":2},"a":{"a":0,"k":[21.324,22.678,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.288,-10.035],[6.939,5.73],[-8.287,10.036],[-6.939,-5.73]],"o":[[-8.288,10.035],[-6.939,-5.73],[8.288,-10.035],[6.939,5.73]],"v":[[12.621,11.117],[-13.356,16.698],[-12.787,-9.866],[14.135,-16.698]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[21.324,22.678],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":78,"st":0,"bm":0},{"ddd":0,"ind":48,"ty":4,"nm":"egg_t_33","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.56,33.82],[0,-74.74],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[46.73,43.02],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-105.81]],"v":[[-65.94,-147.105],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":166,"op":170,"st":0,"bm":0},{"ddd":0,"ind":49,"ty":4,"nm":"egg_t_32","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.64,0.757],[0,-58.717],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[50.465,48.763]],"o":[[31.026,43.493],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-82.072],[-6.582,-1.398]],"v":[[-38.131,-115.306],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[-18.41,-114.151]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":50,"ty":4,"nm":"egg_t_31","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.108,2.239],[0,-39.023],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[27.778,46.449]],"o":[[14.89,34.662],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-58.047],[-13.204,-1.677]],"v":[[-11.099,-66.884],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[21.212,-63.467]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":51,"ty":4,"nm":"egg_t_30","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[11.899,0.525],[0,-22.718],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[13.729,35.896]],"o":[[5.379,21.903],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-39.439],[-8.878,-3.856]],"v":[[4.11,-21.408],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[44.386,-15.528]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":52,"ty":4,"nm":"egg_t_29","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[20.698,4.033],[0,-9.818],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.957,24.456]],"o":[[1.054,9.764],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-25.354],[-17.741,-5.563]],"v":[[10.811,16.574],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[56.749,24.17]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":53,"ty":4,"nm":"egg_t_28","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[20.099,2.243],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[1.955,14.118]],"o":[[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-14.261],[-16.453,-4.507]],"v":[[12.41,48.485],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[62.962,56.735]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":54,"ty":4,"nm":"egg_t_27","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.448,-1.632],[10.243,1.97],[7.919,-17.656],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.305,5.548]],"o":[[-11.052,-4.132],[-2.57,21.931],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-5.553],[-17.471,-2.474]],"v":[[35.56,78.895],[10.766,74.793],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[65.48,82.737]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":55,"ty":4,"nm":"egg_t_26","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[14.818,0.179],[5.252,-11.71],[0,0],[0,0],[0,0],[0,0],[-9.452,15.297],[-1.136,1.838],[0,0]],"o":[[-2.977,13.62],[0,0],[0,0],[0,0],[0,0],[0,0],[1.369,-2.215],[0,0],[-9.932,-2.967]],"v":[[7.19,96.249],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[62.157,105.519],[54.94,102.396],[49.44,101.895]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":159,"op":160,"st":0,"bm":0},{"ddd":0,"ind":56,"ty":4,"nm":"egg_t_25","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[12.853,0.454],[2.979,-6.642],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-2.268,7.265],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-9.432,-3.033]],"v":[[2.656,113.407],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[52.492,121.16],[46.94,118.896],[36.94,118.395]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":57,"ty":4,"nm":"egg_t_24","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[30.085,1.784],[1.098,-2.448],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-1.004,2.534],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-2.076,126.8],[-5.23,134.274],[10.71,147.106],[17.288,129.845],[23.22,128.496],[35.09,131.056],[39,142.996],[45.928,131.784]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":58,"ty":4,"nm":"egg_t_72","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[35.745,5.225],[1.79,-3.99],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-1.537,4.217],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-0.236,121.962],[-5.23,134.274],[10.71,147.106],[19.97,125.746],[34.34,127.056],[39,142.996],[47.526,129.197]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":59,"ty":4,"nm":"egg_t_71","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[27.501,1],[4.329,-9.65],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-2.801,10.955],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[5.508,103.349],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[58.989,110.646]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":81,"op":82,"st":0,"bm":0},{"ddd":0,"ind":60,"ty":4,"nm":"egg_t_70","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[16.773,0.973],[7.889,-17.588],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.297,5.472]],"o":[[-2.582,21.831],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-5.477],[-16.484,-2.447]],"v":[[10.736,75.046],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[65.493,82.966]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":81,"st":0,"bm":0},{"ddd":0,"ind":61,"ty":4,"nm":"egg_t_69","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[19.893,3.005],[0,-4.182],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[3.558,19.016]],"o":[[0.195,4.18],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-19.401],[-16.48,-5.097]],"v":[[12.116,33.439],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[60.488,41.541]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":79,"op":80,"st":0,"bm":0},{"ddd":0,"ind":62,"ty":4,"nm":"egg_t_68","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-27.386],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-44.843],[0,0]],"v":[[0.487,-34.792],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[38.415,-30.065]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":63,"ty":4,"nm":"egg_t_67","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.261,-4.788],[0,-67.44],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[63.059,43.619]],"o":[[39.36,44.23],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-94.149],[-7.81,-5.402]],"v":[[-52.695,-133.605],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[-41.709,-133.361]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":64,"ty":4,"nm":"egg_t_3","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.56,33.82],[0,-74.74],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[46.73,43.02],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-105.81]],"v":[[-65.94,-147.105],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":77,"st":0,"bm":0},{"ddd":0,"ind":65,"ty":4,"nm":"egg_t_43","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[91.47,0],[0,-118.066],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295]],"o":[[-91.469,0],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-118.066]],"v":[[-0.001,-150.585],[-167.465,86.956],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":166,"op":170,"st":0,"bm":0},{"ddd":0,"ind":66,"ty":4,"nm":"egg_t_42","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[37.711,-1.388],[0,-84.62],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[56.985,40.926]],"o":[[-55.793,41.562],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-85.747],[-30.319,-3.251]],"v":[[-72.634,-124.57],[-167.465,86.955],[-166.807,105.538],[-160.693,111.446],[-148.353,96.066],[-136.003,122.296],[-121.103,140.295],[-102.062,115.816],[-94.703,122.296],[-69.363,101.216],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[70.396,-126.208]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":67,"ty":4,"nm":"egg_t_41","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[71.525,-1.815],[0,-57.785],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[30.644,44.686]],"o":[[-29.313,44.288],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-59.267],[-56.095,-1.935]],"v":[[-119.948,-73.24],[-167.465,86.955],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.296],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[117.671,-76.62]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":68,"ty":4,"nm":"egg_t_40","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[67.845,-5.566],[0,-40.336],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[15.074,35.606]],"o":[[-15.327,35.845],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-39.974],[-66.103,-9.033]],"v":[[-143.268,-29.727],[-167.465,86.956],[-166.807,105.538],[-160.693,111.446],[-148.353,96.066],[-136.003,122.296],[-121.103,140.296],[-102.062,115.816],[-94.703,122.296],[-69.363,101.216],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.866],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956],[143.679,-28.76]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":69,"ty":4,"nm":"egg_t_39","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[83.23,-8.207],[0,-25.874],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[6.735,24.865]],"o":[[-6.662,24.737],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-26.022],[-80.462,-12.281]],"v":[[-157.153,10.404],[-167.465,86.956],[-166.807,105.538],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.035],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956],[157.038,9.978]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":70,"ty":4,"nm":"egg_t_38","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[36.609,1.018],[0,-15.79],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[2.384,14.971]],"o":[[-2.574,15.551],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-15.182],[-147.248,-20.279]],"v":[[-163.533,39.8],[-167.465,86.955],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.296],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[163.824,41.597]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":71,"ty":4,"nm":"egg_t_37","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.324,-8.084],[0,-6.676],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[0.309,5.371]],"o":[[-0.475,6.663],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-5.376],[-0.422,-13.976]],"v":[[-166.748,66.936],[-167.465,86.956],[-166.807,105.538],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.035],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956],[166.998,70.829]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":72,"ty":4,"nm":"egg_t_36","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.161,7.154],[80.398,0.72],[-0.017,-0.869],[-0.313,-4.439],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.713,-6.79],[0.022,-0.968],[-86.784,-0.778],[0.089,4.583],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.038,105.835],[148.908,113.645],[154.567,132.585],[166.079,113.954],[167.397,93.036],[10.584,80.223],[-167.417,90.008],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":159,"op":160,"st":0,"bm":0},{"ddd":0,"ind":73,"ty":4,"nm":"egg_t_46","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.129,1.483]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.154,-1.466],[0.635,-7.32]],"v":[[98.434,101.692],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[166.503,109.532]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":74,"ty":4,"nm":"egg_t_35","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-5.399,11.983],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[2.29,-5.083],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[52.178,98.722],[-166.807,105.537],[-160.693,111.446],[-145.853,106.566],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":75,"ty":4,"nm":"egg_t_45","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[104.076,115.424],[105.197,119.725],[126.277,136.696],[134.787,118.835],[149.907,120.895],[154.567,132.585],[160.644,122.752]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":76,"ty":4,"nm":"egg_t_44","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-1.363,3.943],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[1.273,-3.683],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.967,113.376],[45.487,120.965],[46.803,114.357],[-43.143,113.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":77,"ty":4,"nm":"egg_t_34","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-102.062,115.816],[-94.703,122.295],[-87.022,115.906],[-137.367,119.397],[-136.003,122.295],[-121.103,140.295]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":78,"ty":4,"nm":"egg_t_88","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,4.149],[0,0],[0,0],[0,0],[0,0]],"v":[[13.989,122.368],[-42.143,123.219],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":83,"op":84,"st":0,"bm":0},{"ddd":0,"ind":79,"ty":4,"nm":"egg_t_87","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.902,3.081],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[55.427,1.098]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-45.958,-0.91]],"v":[[-140.757,112.198],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-76.863,107.715],[-48.192,107.116],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[49.478,109.196],[105.438,113.035],[105.197,119.725],[126.277,136.695],[136.037,114.835],[148.907,116.145],[154.567,132.585],[162.976,118.214],[-2.957,106.947]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":80,"ty":4,"nm":"egg_t_86","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.042,-1.365],[-0.246,-3.49],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.227,5.271],[80.529,0.763]],"o":[[0.109,3.578],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.532,-5.068],[0.078,-1.821],[-86.592,-0.821]],"v":[[-167.343,94.936],[-166.807,105.537],[-160.693,111.445],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-69.363,101.215],[-52.692,97.616],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[60.978,87.696],[95.938,95.035],[105.198,119.725],[126.277,136.695],[138.037,105.835],[148.907,113.645],[154.568,132.585],[166.079,113.954],[167.221,98.445],[10.072,86.869]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":81,"op":82,"st":0,"bm":0},{"ddd":0,"ind":81,"ty":4,"nm":"egg_t_85","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-6.934],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[0,0],[81.51,1.64]],"o":[[0,0],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-5.458],[0,0],[-62.483,-1.257]],"v":[[-166.691,66.163],[-167.465,86.955],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.695],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[166.984,70.585],[-2.441,58.366]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":81,"st":0,"bm":0},{"ddd":0,"ind":82,"ty":4,"nm":"egg_t_84","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-21.293],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[0,0],[80.019,0.044]],"o":[[0,0],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-19.645],[0,0],[-67.007,-0.037]],"v":[[-160.405,23.649],[-167.465,86.955],[-166.807,105.537],[-160.693,111.445],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-69.363,101.215],[-52.693,97.615],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.695],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[161.432,28.46],[2.583,16.571]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":79,"op":80,"st":0,"bm":0},{"ddd":0,"ind":83,"ty":4,"nm":"egg_t_83","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[47.93,-2.289],[0,-46.846],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[18.576,38.6]],"o":[[-20.148,39.739],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-44.798],[-68.372,-15.543]],"v":[[-135.353,-46.697],[-167.465,86.955],[-166.807,105.537],[-160.693,111.445],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[61.478,83.196],[95.937,95.035],[105.197,119.725],[126.277,136.695],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[137.948,-41.444]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":84,"ty":4,"nm":"egg_t_82","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[14.517,-0.497],[0,-103.316],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[74.533,26.022]],"o":[[-75.832,24.472],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-102.108],[-15.515,-1.388]],"v":[[-33.44,-145.227],[-167.465,86.955],[-166.807,105.537],[-160.693,111.446],[-148.353,96.065],[-136.003,122.296],[-121.103,140.296],[-102.062,115.816],[-94.703,122.296],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.866],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.035],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[36.092,-144.336]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":85,"ty":4,"nm":"egg_t_2","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[91.47,0],[0,-118.066],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295]],"o":[[-91.469,0],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-118.066]],"v":[[-0.001,-150.585],[-167.465,86.956],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":77,"st":0,"bm":0},{"ddd":0,"ind":86,"ty":4,"nm":"egg_b_tr4","parent":89,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.999,39.154,0],"ix":2,"l":2},"a":{"a":0,"k":[42.686,10,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.724,"y":1},"o":{"x":0.167,"y":0},"t":170,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[15.64,-16.328],[-2.068,-9.128],[-16.343,12.486]],"c":false}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[21.03,-13.267],[-1.365,-5.285],[-16.343,12.486]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[26.343,22.486],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50.666,"s":[0]},{"t":54,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":185,"st":0,"bm":0},{"ddd":0,"ind":87,"ty":4,"nm":"egg_b_tr3","parent":89,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.999,39.154,0],"ix":2,"l":2},"a":{"a":0,"k":[42.686,10,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.724,"y":1},"o":{"x":0.167,"y":0},"t":170,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[16.343,-12.486],[-1.365,-5.285],[-16.343,12.486]],"c":false}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[21.03,-13.267],[-1.365,-5.285],[-16.343,12.486]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[26.343,22.486],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50.666,"s":[0]},{"t":54,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":185,"st":0,"bm":0},{"ddd":0,"ind":88,"ty":4,"nm":"egg_b_tr 4","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[172.538,318.809,0],"ix":2,"l":2},"a":{"a":0,"k":[26.211,6.5,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.724,"y":1},"o":{"x":0.167,"y":0},"t":170,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13.698,-49.098],[-4.388,-8.319],[-0.757,16.556],[4.372,24.411]],"c":false}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9.948,-35.348],[-4.388,-8.319],[-0.757,16.556],[4.372,24.411]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[6]},{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[18.23,46.77],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"t":54,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":187,"st":0,"bm":0},{"ddd":0,"ind":89,"ty":4,"nm":"egg_b_tr 3","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[172.538,318.809,0],"ix":2,"l":2},"a":{"a":0,"k":[26.211,6.5,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.724,"y":1},"o":{"x":0.167,"y":0},"t":170,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[6.418,-47.145],[-8.231,-7.616],[-0.758,16.556],[5.141,24.27]],"c":false}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9.948,-35.348],[-4.388,-8.319],[-0.757,16.556],[4.372,24.411]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[6]},{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[18.23,46.77],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"t":54,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":187,"st":0,"bm":0},{"ddd":0,"ind":90,"ty":4,"nm":"egg_full_8","parent":93,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,231.454,0],"ix":2,"l":2},"a":{"a":0,"k":[201.51,251.204,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-127.967],[99.141,0],[0,127.967],[-99.14,0]],"o":[[0,127.967],[-99.14,0],[0,-127.967],[99.141,0]],"v":[[181.51,26.257],[0,231.204],[-181.51,26.257],[0,-231.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.51,251.204],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":170,"op":210,"st":150,"bm":0},{"ddd":0,"ind":91,"ty":4,"nm":"egg_full_7","parent":93,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[182.672,236.934,0],"ix":2,"l":2},"a":{"a":0,"k":[180.595,225.725,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-105.81],[99.14,0],[12.65,108.53],[-63.35,0],[0,114],[46.73,43.02]],"o":[[0,127.97],[-90.5,0],[26.54,61.77],[88.53,0],[0,-74.74],[75.56,33.82]],"v":[[180.595,20.775],[-0.915,225.725],[-180.595,53.045],[-35.015,149.945],[127.065,-32.635],[48.715,-225.725]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[180.595,225.725],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":170,"op":210,"st":150,"bm":0},{"ddd":0,"ind":92,"ty":4,"nm":"egg_full_6","parent":93,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,231.454,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,213.566,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-118.066],[91.47,0],[0,118.066],[-91.469,0]],"o":[[0,118.066],[-91.469,0],[0,-118.066],[91.47,0]],"v":[[167.465,24.225],[-0.001,213.316],[-167.465,24.225],[-0.001,-213.316]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,213.566],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":170,"op":210,"st":150,"bm":0},{"ddd":0,"ind":93,"ty":4,"nm":"egg_full__02","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.77,174.006,0],"ix":2,"l":2},"a":{"a":0,"k":[181.76,462.659,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-127.967],[99.141,0],[0,127.967],[-99.14,0]],"o":[[0,127.967],[-99.14,0],[0,-127.967],[99.141,0]],"v":[[181.51,26.257],[0,231.204],[-181.51,26.257],[0,-231.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[181.76,231.454],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":170,"op":210,"st":150,"bm":0},{"ddd":0,"ind":94,"ty":4,"nm":"Shape Layer 2","parent":126,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":51,"s":[0]},{"t":55,"s":[100]}],"ix":11},"r":{"a":0,"k":-6.732,"ix":10},"p":{"a":0,"k":[184.257,315.806,0],"ix":2,"l":2},"a":{"a":0,"k":[22,104.25,0],"ix":1,"l":2},"s":{"a":0,"k":[70.899,70.899,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[13.25,104.25],[-11.75,144.5],[-31.5,149],[-52,163.25],[-51.843,172.029],[-44.5,174.25],[-26.5,158.75],[-17.75,155.75],[-15.75,174.25],[-9,184.75],[-1.5,188.75],[0,176.75],[-3.952,165.128],[-3.953,148.378],[22,107.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":95,"ty":4,"nm":"egg_t_60","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":166,"op":170,"st":0,"bm":0},{"ddd":0,"ind":96,"ty":4,"nm":"egg_t_59","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[24.95,-19.767],[0,-89.581],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[58.602,45.959]],"o":[[-58.226,46.131],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-89.939],[-24.778,-19.432]],"v":[[-82.669,-123.861],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[82.468,-124.412]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[24.95,-19.767],[0,-89.581],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[58.602,45.959]],"o":[[-58.226,46.131],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-89.939],[-24.778,-19.432]],"v":[[-82.669,-123.861],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[82.468,-124.412]],"c":true}]},{"t":165,"s":[{"i":[[53.231,48.02],[46.665,-3.093],[0,-84.4],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.798,-3.447],[-52.841,48.138],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-84.778]],"v":[[92.375,-116.068],[-92.589,-115.421],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":97,"ty":4,"nm":"egg_t_58","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[32.825,-46.917],[0,-65.144],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[33.991,48.638]],"o":[[-34.038,48.65],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-65.092],[-32.833,-46.981]],"v":[[-125.876,-77.152],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[126.456,-77.038]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[32.825,-46.917],[0,-65.144],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[33.991,48.638]],"o":[[-34.038,48.65],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-65.092],[-32.833,-46.981]],"v":[[-125.876,-77.152],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[126.456,-77.038]],"c":true}]},{"t":164,"s":[{"i":[[57.71,-3.99],[0,-59.703],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[29.153,47.044]],"o":[[-29.197,47.062],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-59.652],[-47.63,-8.609]],"v":[[-134.133,-64.62],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[134.707,-64.501]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":98,"ty":4,"nm":"egg_t_57","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[32.591,-71.193],[0,-46.475],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[17.771,39.902]],"o":[[-18.586,40.601],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-45.35],[-32.373,-72.69]],"v":[[-151.809,-31.571],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[153.643,-28.617]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[32.591,-71.193],[0,-46.475],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[17.771,39.902]],"o":[[-18.586,40.601],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-45.35],[-32.373,-72.69]],"v":[[-151.809,-31.571],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[153.643,-28.617]],"c":true}]},{"t":163,"s":[{"i":[[64.472,-5.011],[0,-42.058],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[14.765,37.016]],"o":[[-15.466,37.737],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-41.017],[-70.454,-16.819]],"v":[[-156.896,-19.837],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[158.53,-17.03]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":99,"ty":4,"nm":"egg_t_56","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[27.378,-91.558],[0,-31.11],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.219,28.496]],"o":[[-8.794,29.408],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-30.02],[-26.817,-92.976]],"v":[[-167.598,10.464],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[169.006,13.559]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[27.378,-91.558],[0,-31.11],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.219,28.496]],"o":[[-8.794,29.408],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-30.02],[-26.817,-92.976]],"v":[[-167.598,10.464],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[169.006,13.559]],"c":true}]},{"t":162,"s":[{"i":[[107.699,-11.215],[0,-27.992],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[6.72,25.908]],"o":[[-7.196,26.767],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-27.004],[-65.795,-15.553]],"v":[[-170.122,19.357],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[171.371,22.195]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":100,"ty":4,"nm":"egg_t_55","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[85.449,0],[19.735,-106.678],[0,-19.177],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-84.283,0],[-3.479,18.804],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-17.671]],"v":[[0.25,-155.28],[-175.931,44.989],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[85.449,0],[19.735,-106.678],[0,-19.177],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-84.283,0],[-3.479,18.804],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-17.671]],"v":[[0.25,-155.28],[-175.931,44.989],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":161,"s":[{"i":[[128.521,-14.996],[0,-17.22],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[2.407,15.663]],"o":[[-2.823,16.956],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-15.865],[-70.009,-15.999]],"v":[[-176.945,50.759],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[178.086,54.761]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":101,"ty":4,"nm":"egg_t_54","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[10.689,-118.329],[0,-9.212],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.538,7.383]],"o":[[-0.829,9.178],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.398],[-8.768,-120.321]],"v":[[-180.004,74.572],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.946,79.994]],"c":true}]},{"t":160,"s":[{"i":[[124.822,-19.096],[0,-8.268],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.435,6.63]],"o":[[-0.67,8.246],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-6.641],[-43.027,-12.465]],"v":[[-180.246,77.393],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[181.103,82.262]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":102,"ty":4,"nm":"egg_t_53","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":159,"s":[{"i":[[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[82.336,-11.719],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-51.683,-20.716],[-0.785,0.112],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.528,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[179.76,104.678],[-181.259,99.681],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.738,134.16]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":159,"op":160,"st":0,"bm":0},{"ddd":0,"ind":103,"ty":4,"nm":"egg_t_52","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[172.972,116.399],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[97.688,109.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[171.47,118.83]],"c":true}]},{"t":160,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[172.972,116.399],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":104,"ty":4,"nm":"egg_t_51","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-6.645,13.26]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[2.073,-4.137]],"v":[[-53.943,108.31],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.218,122.07],[45.737,134.16],[53.904,108.81]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":105,"ty":4,"nm":"egg_t_50","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-170.29,115.123],[-160.442,124.64],[-150.966,112.828],[-148.102,109.26],[-147.165,111.251],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-53.943,108.81],[-170.473,114.946],[-160.442,124.64],[-151.96,114.067],[-148.852,113.51],[-146.017,113.689],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41]],"c":true}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-170.29,115.123],[-160.442,124.64],[-150.966,112.828],[-148.102,109.26],[-147.165,111.251],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":106,"ty":4,"nm":"egg_t_49","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.611,6.042]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-8.372],[-8.722,-86.321]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[161.03,135.726],[181.759,102.178],[180.822,80.619]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[6.25,2],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-6.25,-2],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[163.576,131.868],[102.138,124.095],[105.448,132.92],[126.527,149.89],[135.288,127.53],[149.658,129.09],[154.818,145.78],[163.209,132.2]],"c":false}]},{"t":160,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.611,6.042]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-8.372],[-8.722,-86.321]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[161.03,135.726],[181.759,102.178],[180.822,80.619]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":107,"ty":4,"nm":"egg_t_48","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[-0.685,3.059],[-9.375,11.891],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.607,-7.177],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[46.657,129.242],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.287,119.03],[149.157,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[0,0],[-2.204,7.069],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[-20.991,0.003],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.217,122.07],[45.737,134.16],[48.568,122.615],[-46.442,122.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78]],"c":true}]},{"t":160,"s":[{"i":[[-0.685,3.059],[-9.375,11.891],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.607,-7.177],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[46.657,129.242],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.287,119.03],[149.157,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":108,"ty":4,"nm":"egg_t_47","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-138.058,130.593],[-135.752,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[1.137,2.415],[0,0],[0,0],[0,0],[0,0]],"v":[[-80.718,124.065],[-139.163,128.246],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-138.058,130.593],[-135.752,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":109,"ty":4,"nm":"egg_t_100","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":83,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[17.278,131.827],[-43.892,132.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":83,"op":84,"st":0,"bm":0},{"ddd":0,"ind":110,"ty":4,"nm":"egg_t_99","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[100.452,120.267],[105.448,132.92],[126.527,149.89],[135.788,123.53],[149.157,126.84],[154.818,145.78],[166.399,127.038]],"c":true}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":111,"ty":4,"nm":"egg_t_98","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[-3.577,9.555],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-44.168,-3.001],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[50.244,117.222],[-48.947,117.471],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.218,122.07],[45.737,134.16]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":112,"ty":4,"nm":"egg_t_97","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-72.782,117.29],[-142.462,121.239],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"t":160,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":113,"ty":4,"nm":"egg_t_96","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-98.274,132.126],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.723,163.78],[25.217,122.07],[45.737,134.16],[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":81,"s":[{"i":[[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[87.822,1.068],[-0.004,-0.401],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-90.868,-1.106],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[177.243,109.487],[5.072,95.275],[-180.235,105.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.113,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-98.274,132.126],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.723,163.78],[25.217,122.07],[45.737,134.16],[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":81,"op":82,"st":0,"bm":0},{"ddd":0,"ind":114,"ty":4,"nm":"egg_t_95","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[10.622,-118.401],[0,-9.147],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.582,7.682]],"o":[[-0.818,9.115],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.699],[-9.094,-119.994]],"v":[[-180.021,74.765],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.879,79.092]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":80,"s":[{"i":[[123.336,-12.013],[0,-8.21],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.47,6.899]],"o":[[-0.661,8.188],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-6.911],[-154.472,-18.4]],"v":[[-180.26,77.567],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[181.049,81.453]],"c":true}]},{"t":160,"s":[{"i":[[10.622,-118.401],[0,-9.147],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.582,7.682]],"o":[[-0.818,9.115],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.699],[-9.094,-119.994]],"v":[[-180.021,74.765],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.879,79.092]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":81,"st":0,"bm":0},{"ddd":0,"ind":115,"ty":4,"nm":"egg_t_94","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[23.972,-99.244],[0,-25.141],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.146,22.785]],"o":[[-5.861,24.266],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-23.492],[-22.887,-101.326]],"v":[[-172.219,27.574],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[173.836,32.357]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":79,"s":[{"i":[[99.994,-12.501],[0,-22.593],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[4.187,20.601]],"o":[[-4.774,21.967],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-21.105],[-102.755,-13.847]],"v":[[-173.918,34.979],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[175.331,39.325]],"c":true}]},{"t":160,"s":[{"i":[[23.972,-99.244],[0,-25.141],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.146,22.785]],"o":[[-5.861,24.266],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-23.492],[-22.887,-101.326]],"v":[[-172.219,27.574],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[173.836,32.357]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":79,"op":80,"st":0,"bm":0},{"ddd":0,"ind":116,"ty":4,"nm":"egg_t_93","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[33.354,-63.059],[0,-52.607],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[22.474,43.499]],"o":[[-23.284,44.02],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-51.586],[-33.276,-64.407]],"v":[[-144.055,-47.311],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[145.899,-44.74]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":78,"s":[{"i":[[87.812,-6.089],[0,-47.771],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[18.835,40.807]],"o":[[-19.545,41.38],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-46.813],[-98.323,-11.581]],"v":[[-150.236,-34.953],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[151.9,-32.461]],"c":true}]},{"t":160,"s":[{"i":[[33.354,-63.059],[0,-52.607],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[22.474,43.499]],"o":[[-23.284,44.02],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-51.586],[-33.276,-64.407]],"v":[[-144.055,-47.311],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[145.899,-44.74]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":117,"ty":4,"nm":"egg_t_92","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[17.832,-9.166],[0,-102.587],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[71.209,37.788]],"o":[[-72.075,37.047],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-101.78],[-18.32,-9.722]],"v":[[-56.248,-141.021],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[58.442,-140.136]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":77,"s":[{"i":[[29.168,0.107],[0,-98.586],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[66.814,41.184]],"o":[[-67.78,40.49],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-97.682],[-34.371,-1.52]],"v":[[-64.591,-136.387],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[66.948,-135.26]],"c":true}]},{"t":160,"s":[{"i":[[17.832,-9.166],[0,-102.587],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[71.209,37.788]],"o":[[-72.075,37.047],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-101.78],[-18.32,-9.722]],"v":[[-56.248,-141.021],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[58.442,-140.136]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":118,"ty":4,"nm":"egg_t_1","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.301,"y":0},"t":75,"s":[60,-405.409,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":89,"s":[60,-759.409,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.817,"y":1},"o":{"x":0.768,"y":0},"t":150,"s":[60,-759.409,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.32,"y":0},"t":168,"s":[60,-380.681,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[60,-403.409,0]}],"ix":2,"l":2},"a":{"a":0,"k":[181.759,0.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[1,1,0.333],"y":[0,0,0]},"t":75,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":82,"s":[100,100,100]},{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":150,"s":[100,100,100]},{"t":170,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":75,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0,-159.53],[-181.509,97.931],[-181.485,100.295],[-160.692,120.39],[-148.352,105.01],[-136.002,131.24],[-121.102,149.24],[-102.062,124.76],[-94.702,131.24],[-69.362,110.16],[-52.692,106.56],[-43.142,124.76],[-43.142,144.61],[-25.432,133.81],[-13.092,145.13],[-8.972,159.53],[24.967,117.82],[45.487,129.91],[61.478,92.14],[95.938,103.98],[105.198,128.67],[126.277,145.64],[138.038,114.78],[148.908,122.59],[154.568,141.53],[181.509,97.928]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0,-159.53],[-181.509,97.931],[-181.485,100.295],[-160.692,120.39],[-148.352,105.01],[-136.002,131.24],[-121.102,149.24],[-102.062,124.76],[-94.702,131.24],[-69.362,110.16],[-52.692,106.56],[-43.142,124.76],[-43.142,144.61],[-25.432,133.81],[-13.092,145.13],[-8.972,159.53],[24.967,117.82],[45.487,129.91],[61.478,92.14],[95.938,103.98],[105.198,128.67],[126.277,145.64],[138.038,114.78],[148.908,122.59],[154.568,141.53],[181.509,97.928]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[181.759,159.78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":77,"st":0,"bm":0},{"ddd":0,"ind":119,"ty":4,"nm":"egg_t_7","parent":120,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[201.51,181.53,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,-127.967],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[-181.259,94.681],[-160.442,117.14],[-148.102,101.76],[-135.752,127.99],[-120.852,145.99],[-101.812,121.51],[-94.452,127.99],[-69.112,106.91],[-52.442,103.31],[-42.892,121.51],[-42.892,141.36],[-25.182,130.56],[-12.842,141.88],[-8.722,156.28],[25.217,114.57],[45.737,126.66],[61.728,88.89],[96.188,100.73],[105.448,125.42],[126.527,142.39],[138.288,111.53],[149.158,119.34],[154.818,138.28],[181.759,94.678]],"c":false}]},{"t":85,"s":[{"i":[[0,-127.967],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[-181.259,94.681],[-160.442,117.14],[-148.102,101.76],[-135.752,127.99],[-120.852,145.99],[-101.812,121.51],[-94.452,127.99],[-69.112,106.91],[-52.442,103.31],[-42.892,121.51],[-42.892,141.36],[-25.182,130.56],[-12.842,141.88],[-8.722,156.28],[25.217,114.57],[45.737,126.66],[61.728,88.89],[96.188,100.73],[105.448,125.42],[126.527,142.39],[138.288,111.53],[149.158,119.34],[154.818,138.28],[181.759,94.678]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":75,"op":170,"st":0,"bm":0},{"ddd":0,"ind":120,"ty":4,"nm":"egg_full_9","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,229.454,0],"ix":2,"l":2},"a":{"a":0,"k":[201.51,251.204,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-127.967],[99.141,0],[0,127.967]],"o":[[0,127.967],[-99.14,0],[0,-127.967]],"v":[[181.51,26.257],[0,233.204],[-181.51,26.257]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.51,251.204],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-20,"op":170,"st":0,"bm":0},{"ddd":0,"ind":121,"ty":4,"nm":"egg_b_6","parent":126,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[0]},{"t":20,"s":[100],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"t":55,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.768,298.559,0],"ix":2,"l":2},"a":{"a":0,"k":[181.75,43.89,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.58,-7.25],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.04,5.16],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.37,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,7.62],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.73,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.3,-4.99],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[181.5,-37.85],[180.63,-15.54],[158.77,18.91],[148.39,15.35],[141.79,-4.84],[129.71,26.02],[99.52,4.72],[90.01,-19.97],[67.13,-29.91],[50.93,9.95],[27.64,-3.8],[-12.96,43.64],[-19.95,19.84],[-28.57,12.01],[-52.18,24.2],[-52.18,-6.45],[-59.14,-17.06],[-70.26,-12.46],[-94.29,7.62],[-100.85,2.14],[-120.41,26.62],[-141.72,3.62],[-150.4,-14.61],[-159.87,-2.11],[-180.98,-20.26],[-181.5,-35.49],[-160.7,-15.39],[-148.36,-30.77],[-136.01,-4.54],[-121.11,13.46],[-102.07,-11.02],[-94.71,-4.54],[-69.37,-25.62],[-52.7,-29.22],[-43.15,-11.02],[-43.15,8.83],[-25.44,-1.97],[-13.1,9.35],[-8.98,23.75],[24.96,-17.96],[45.48,-5.87],[61.47,-43.64],[95.93,-31.8],[105.19,-7.11],[126.27,9.86],[138.03,-21],[148.9,-13.19],[154.56,5.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[181.75,43.89],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":47,"op":170,"st":0,"bm":0},{"ddd":0,"ind":122,"ty":4,"nm":"egg_b_4","parent":126,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[0]},{"t":20,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.768,298.559,0],"ix":2,"l":2},"a":{"a":0,"k":[181.75,43.89,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.37,16.96]],"o":[[-13.73,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[67.13,-29.91],[50.93,9.95],[27.64,-3.8],[-12.96,43.64],[-19.95,19.84],[-28.57,12.01],[-52.18,24.2],[-52.18,-6.45],[-59.14,-17.06],[-70.26,-12.46],[-69.37,-25.62],[-52.7,-29.22],[-43.15,-11.02],[-43.15,8.83],[-25.44,-1.97],[-13.1,9.35],[-8.98,23.75],[24.96,-17.96],[45.48,-5.87],[61.47,-43.64]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[181.75,43.89],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-16,"op":170,"st":0,"bm":0},{"ddd":0,"ind":123,"ty":4,"nm":"egg_full_4","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,231.454,0],"ix":2,"l":2},"a":{"a":0,"k":[201.51,251.204,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-127.967],[99.141,0],[0,127.967],[-99.14,0]],"o":[[0,127.967],[-99.14,0],[0,-127.967],[99.141,0]],"v":[[181.51,26.257],[0,231.204],[-181.51,26.257],[0,-229.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.51,251.204],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":70,"st":0,"bm":0},{"ddd":0,"ind":124,"ty":4,"nm":"egg_full_3","parent":126,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[182.672,236.934,0],"ix":2,"l":2},"a":{"a":0,"k":[180.595,225.725,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-105.81],[99.14,0],[12.65,108.53],[-63.35,0],[0,114],[46.73,43.02]],"o":[[0,127.97],[-90.5,0],[26.54,61.77],[88.53,0],[0,-74.74],[75.56,33.82]],"v":[[180.595,20.775],[-0.915,225.725],[-180.595,53.045],[-35.015,147.945],[127.065,-32.635],[48.715,-225.725]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[180.595,225.725],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":70,"st":0,"bm":0},{"ddd":0,"ind":125,"ty":4,"nm":"egg_full_2","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,230.454,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,213.566,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-118.066],[91.47,0],[0,118.066],[-91.469,0]],"o":[[0,118.066],[-91.469,0],[0,-118.066],[91.47,0]],"v":[[167.465,24.225],[-0.001,213.316],[-170.465,24.225],[-0.001,-213.316]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[167.715,213.566],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":70,"st":0,"bm":0},{"ddd":0,"ind":126,"ty":4,"nm":"egg_full__0","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,60,0],"ix":2,"l":2},"a":{"a":0,"k":[181.76,462.659,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-127.967],[99.141,0],[0,127.967],[-99.14,0]],"o":[[0,127.967],[-99.14,0],[0,-127.967],[99.141,0]],"v":[[181.51,26.257],[0,231.204],[-181.51,26.257],[0,-229.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[181.76,231.454],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":70,"st":0,"bm":0},{"ddd":0,"ind":127,"ty":4,"nm":"egg_b_3","parent":129,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[182.85,108.515,0],"ix":2,"l":2},"a":{"a":0,"k":[180.4,102.475,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[99.14,0],[11.489,98.62],[-63.35,0],[-26.98,60.1],[0,0],[0,0],[0,0],[0,0]],"o":[[0,127.97],[-98.843,0],[26.54,61.77],[62.44,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[180.4,-102.475],[-1.11,102.475],[-180.4,-69.985],[-34.82,26.915],[109.59,-67.305],[125.17,-54.765],[136.93,-85.625],[147.8,-77.815],[153.46,-58.875]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[180.4,102.475],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":128,"ty":4,"nm":"egg_b_2","parent":129,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.75,108.515,0],"ix":2,"l":2},"a":{"a":0,"k":[181.75,102.725,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[99.14,0],[1,126.56],[0,0],[-86.32,0],[-12.45,107.48]],"o":[[0,127.97],[-98.53,0],[0,0],[10.18,111.57],[84.56,0],[0,0]],"v":[[181.5,-102.475],[-0.01,102.475],[-181.5,-100.115],[-171.29,-88.315],[-0.01,85.385],[170.58,-81.565]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[181.75,102.725],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":129,"ty":4,"nm":"egg_b_1","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.778,68.636,0],"ix":2,"l":2},"a":{"a":0,"k":[181.75,105.62,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[99.14,0],[1,126.56],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.37,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,127.97],[-98.53,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[181.5,-99.58],[-0.01,105.37],[-181.5,-97.22],[-160.7,-77.12],[-148.36,-92.5],[-136.01,-66.27],[-121.11,-48.27],[-102.07,-72.75],[-94.71,-66.27],[-69.37,-87.35],[-52.7,-90.95],[-43.15,-72.75],[-43.15,-52.9],[-25.44,-63.7],[-13.1,-52.38],[-8.98,-37.98],[24.96,-79.69],[45.48,-67.6],[61.47,-105.37],[95.93,-93.53],[105.19,-68.84],[126.27,-51.87],[138.03,-82.73],[148.9,-74.92],[154.56,-55.98]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[181.75,105.62],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":130,"ty":4,"nm":"beak2","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.624,20.618,0],"ix":2,"l":2},"a":{"a":0,"k":[18.347,20.86,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":70,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[0.913,1.794],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-1.692,1.09],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-4.586,18.72],[-4.599,18.734],[-9.64,17.372],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[-1.828,-2.368],[0,0],[1.883,-5.692],[0,0],[0.913,1.794],[0.975,3.473],[-2.73,-0.727]],"o":[[0,0],[-4.156,4.062],[0,0],[-1.692,1.09],[0.934,-7.922],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-0.336,2.97],[-0.349,2.984],[-5.39,1.622],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[0.913,1.794],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-1.692,1.09],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-4.586,18.72],[-4.599,18.734],[-9.64,17.372],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[-1.828,-2.368],[0,0],[-0.771,-5.51],[0,0],[0.913,1.794],[2.644,3.293],[-2.73,-0.727]],"o":[[0,0],[2.741,4.972],[0,0],[-1.692,1.09],[-7.117,-10.102],[2.757,-1.154],[2.729,0.728]],"v":[[14.606,-16.108],[15.317,-15.54],[23.63,9.077],[23.617,9.091],[19.306,8.575],[0,-18.956],[8.346,-19.749]],"c":true}]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0},"t":103.227,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[1.594,0.716],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-2.314,-0.062],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-2.426,8.701],[-2.439,8.715],[-7.48,7.353],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[{"i":[[-1.828,-2.368],[0,0],[0.108,-0.668],[0,0],[0.913,1.794],[0.13,1.056],[-2.73,-0.727]],"o":[[0,0],[-3.643,9.427],[0,0],[-1.692,1.09],[-0.374,-5.681],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-22.071,11.277],[-22.084,11.291],[-27.125,9.929],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[1.594,0.716],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-2.314,-0.062],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-2.426,8.701],[-2.439,8.715],[-7.48,7.353],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[1.762,0.853],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-1.158,-0.109],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-2.426,8.701],[-2.439,8.715],[-7.48,7.353],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"t":160,"s":[{"i":[[-1.828,-2.368],[0,0],[0.108,-0.668],[0,0],[2.426,0.344],[0.13,1.056],[-2.73,-0.727]],"o":[[0,0],[-2.938,3.046],[0,0],[-1.386,-1.089],[0.708,-2.043],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[0.833,3.412],[0.82,3.426],[-4.221,2.064],[-5.552,-18.305],[2.794,-19.098]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949000000954,0.713999986649,0.141000002623,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[20.616,21.639],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[{"i":[[1.553,-1.014],[0,0],[0.919,1.803],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.696,1.107],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-2.31,19.503],[-7.37,18.155],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[1.553,-1.014],[0,0],[0.919,1.803],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.696,1.107],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[1.94,3.753],[-3.12,2.405],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[1.553,-1.014],[0,0],[0.919,1.803],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.696,1.107],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-2.31,19.503],[-7.37,18.155],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[-0.354,-2.379],[0,0],[4.672,1.076],[0,0],[-0.725,1.779],[-8.599,-2.292],[-2.304,-4.433]],"o":[[0.664,4.458],[-1.696,1.107],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[1.912,3.678]],"v":[[25.787,3.217],[25.906,9.86],[19.672,9.377],[-11.707,2.486],[-11.82,-3.065],[10.614,-18.97],[22.743,-6.638]],"c":true}]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0},"t":103.227,"s":[{"i":[[1.553,-1.014],[0,0],[1.843,0.552],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-2.324,-0.28],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-0.15,9.484],[-5.21,8.136],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[{"i":[[1.221,-1.209],[0,0],[0.919,1.803],[-2.124,4.06],[-2.045,2.04],[-8.599,-2.292],[1.555,-10.337]],"o":[[-0.236,0.994],[-1.696,1.107],[0,0],[2.109,-4.032],[5.644,-5.63],[8.706,2.32],[-0.355,1.746]],"v":[[14.093,11.775],[-19.795,12.06],[-24.855,10.712],[-22.958,2.829],[-15.758,-8.886],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[{"i":[[1.553,-1.014],[0,0],[1.843,0.552],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-2.324,-0.28],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-0.15,9.484],[-5.21,8.136],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[{"i":[[1.553,-1.014],[0,0],[2.088,0.873],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.759,-0.151],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-0.15,9.484],[-5.21,8.136],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"t":160,"s":[{"i":[[1.553,-1.014],[0,0],[2.722,0.086],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.314,-1.143],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[3.109,4.195],[-1.951,2.847],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.96899998188,0.552999973297,0.086000002921,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.371,20.969],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":131,"ty":3,"nm":"NULL CONTROL","parent":145,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":89,"s":[6.002]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.666],"y":[0]},"t":96.451,"s":[-2.783]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[8.998]},{"t":140,"s":[6.002]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[97.22,142.747,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[138.01,152.756,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[48.177,136.503,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[97.22,142.747,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":132,"ty":4,"nm":"Shape Layer 6","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":22.631,"ix":10},"p":{"a":0,"k":[-58.833,24.044,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-2.987,-3.616],[-1.252,3.611]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[2.736,3.312],[0.696,-2.008]],"v":[[79.86,-33.288],[66.25,-32],[67.536,-26.283],[72.995,-17.937],[78.248,-18.765]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-6.509,-3.107],[1,1.875]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[5.5,2.625],[-1,-1.875]],"v":[[91.125,-36.875],[66.25,-32],[69,-27.5],[89.75,-10.125],[96.25,-11.625]],"c":true}]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0},"t":103.227,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-2.987,-3.616],[-1.252,3.611]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[2.736,3.312],[0.696,-2.008]],"v":[[90.64,-32.738],[66.25,-32],[58.686,-24.647],[75.985,-4.507],[81.237,-5.335]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[{"i":[[2,3.375],[3.125,0.875],[-2.418,-7.564],[-2.555,-3.875],[-3.003,2.982]],"o":[[-11.875,4.375],[0.375,2.5],[1.051,3.288],[3.648,5.534],[4.954,-4.919]],"v":[[88.173,-28.956],[66.25,-32],[60.605,-22.558],[64.925,-9.393],[72.835,-6.897]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-2.987,-3.616],[-1.252,3.611]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[2.736,3.312],[0.696,-2.008]],"v":[[90.64,-32.738],[66.25,-32],[58.686,-24.647],[75.985,-4.507],[81.237,-5.335]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-2.987,-3.616],[-1.252,3.611]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[2.736,3.312],[0.696,-2.008]],"v":[[90.64,-32.738],[66.25,-32],[58.686,-24.647],[75.985,-4.507],[81.237,-5.335]],"c":true}]},{"t":160,"s":[{"i":[[2,0.074],[3.125,0.019],[-3.75,-0.154],[-2.987,-0.079],[-1.252,0.079]],"o":[[-11.875,0.096],[0.375,0.055],[3.75,0.154],[2.736,0.073],[0.696,-0.044]],"v":[[79.86,-33.288],[66.25,-33.26],[67.536,-33.135],[70.622,-32.87],[75.874,-32.888]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843208313,0.458823561668,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.611642181873,0.043521407992,0.043521407992,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":89,"op":162,"st":0,"bm":0},{"ddd":0,"ind":133,"ty":4,"nm":"beak1","parent":131,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-6.002,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":84.801,"s":[55.817,20.219,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":89,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":140,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"t":160,"s":[65.491,22.752,0]}],"ix":2,"l":2},"a":{"a":0,"k":[19.915,25.962,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[0.235,-0.882],[4.834,-3.642],[3.479,0.927],[2.18,4.669],[-1.57,5.888],[-9.487,-2.529],[1.556,-10.336]],"o":[[-1.486,5.573],[-4.445,3.349],[-3.263,-0.87],[-2.669,-5.717],[2.849,-10.689],[8.705,2.321],[-0.136,0.927]],"v":[[17.557,4.873],[6.907,19.51],[-5.889,23.777],[-14.445,14.64],[-16.813,-4.288],[6.63,-23.183],[18.109,2.158]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[0.235,-0.882],[1.19,-3.323],[3.68,3.492],[2.18,4.669],[-1.57,5.888],[-9.487,-2.529],[1.556,-10.336]],"o":[[-1.358,5.092],[-3.374,2.565],[-2.88,-2.733],[-2.669,-5.717],[2.849,-10.689],[8.705,2.321],[-0.136,0.927]],"v":[[16.389,0.201],[13.447,27.399],[-3.875,20.566],[-9.373,10.267],[-11.261,-4.94],[12.182,-23.835],[23.661,1.507]],"c":true}]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0},"t":103.227,"s":[{"i":[[0.222,-0.882],[4.573,-3.642],[3.291,0.927],[3.12,9.735],[-1.485,5.888],[-8.974,-2.529],[1.472,-10.336]],"o":[[-1.406,5.573],[-4.205,3.349],[-3.087,-0.87],[-1.915,-5.976],[2.695,-10.689],[8.235,2.321],[-0.129,0.927]],"v":[[17.912,5.604],[6.791,25.373],[-6.375,32.466],[-15.833,18.159],[-15.758,-3.822],[7.575,-22.453],[18.434,2.889]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[{"i":[[-0.075,-0.91],[2.837,-3.44],[3.262,-0.922],[5.204,4.51],[-1.435,5.381],[-9.487,-2.529],[1.556,-10.336]],"o":[[0.317,3.838],[-3.541,4.294],[-6.744,1.906],[-0.166,-3.014],[2.849,-10.689],[8.705,2.321],[-0.136,0.927]],"v":[[17.557,4.873],[12.2,17.103],[0.373,23.136],[-15.378,20.963],[-16.813,-4.288],[6.63,-23.183],[18.109,2.159]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[{"i":[[0.222,-0.882],[4.573,-3.642],[3.291,0.927],[3.12,9.735],[-1.485,5.888],[-8.974,-2.529],[1.472,-10.336]],"o":[[-1.406,5.573],[-4.205,3.349],[-3.087,-0.87],[-1.915,-5.976],[2.695,-10.689],[8.235,2.321],[-0.129,0.927]],"v":[[17.912,5.604],[6.791,25.373],[-6.375,32.466],[-15.833,18.159],[-15.758,-3.822],[7.575,-22.453],[18.434,2.889]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[{"i":[[0.222,-0.882],[4.573,-3.642],[3.291,0.927],[3.12,9.735],[-1.485,5.888],[-8.974,-2.529],[1.472,-10.336]],"o":[[-1.406,5.573],[-4.205,3.349],[-3.087,-0.87],[-1.915,-5.976],[2.695,-10.689],[8.235,2.321],[-0.129,0.927]],"v":[[17.912,5.604],[6.791,25.373],[-6.375,32.466],[-15.833,18.159],[-15.758,-3.822],[7.575,-22.453],[18.434,2.889]],"c":true}]},{"t":160,"s":[{"i":[[0.235,-0.882],[4.834,-3.642],[3.479,0.927],[2.18,4.669],[-1.57,5.888],[-9.487,-2.529],[1.556,-10.336]],"o":[[-1.486,5.573],[-4.445,3.349],[-3.263,-0.87],[-2.669,-5.717],[2.849,-10.689],[8.705,2.321],[-0.136,0.927]],"v":[[17.557,4.873],[6.907,19.51],[-5.889,23.777],[-14.445,14.64],[-16.813,-4.288],[6.63,-23.183],[18.109,2.158]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.583999991417,0.226999998093,0.012000000104,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[19.915,25.963],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":134,"ty":4,"nm":"beak_shad","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.104,40.172,0],"ix":2,"l":2},"a":{"a":0,"k":[22.318,28.428,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[0,0],[0.325,-12.821],[-13.76,-2.314],[8.575,29.159]],"o":[[0,0],[-0.282,11.143],[18.343,3.086],[0,0]],"v":[[-15.174,-28.178],[-21.786,-7.822],[-5.876,25.092],[13.492,-26.524]],"c":true}]},{"i":{"x":0.382,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[0,0],[4.393,-13.371],[-13.76,-2.314],[8.575,29.159]],"o":[[0,0],[-3.479,10.59],[18.343,3.086],[0,0]],"v":[[-5.756,-32.905],[-22.483,-9.725],[-9.497,13.625],[12.795,-28.427]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.949,"y":0},"t":110,"s":[{"i":[[0,0],[0.325,-12.821],[-13.76,-2.314],[8.575,29.159]],"o":[[0,0],[-0.282,11.143],[18.343,3.086],[0,0]],"v":[[-15.174,-28.178],[-21.786,-7.822],[0.835,21.455],[13.492,-26.524]],"c":true}]},{"t":140,"s":[{"i":[[0,0],[0.325,-12.821],[-13.76,-2.314],[8.575,29.159]],"o":[[0,0],[-0.282,11.143],[18.343,3.086],[0,0]],"v":[[-15.174,-28.178],[-21.786,-7.822],[-5.876,25.092],[13.492,-26.524]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[22.317,28.428],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":135,"ty":4,"nm":"eye_l_bl2","parent":137,"sr":1,"ks":{"o":{"a":1,"k":[{"t":85,"s":[0],"h":1},{"t":88,"s":[100],"h":1},{"t":112,"s":[0],"h":1},{"t":116,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.782,11.647,0],"ix":2,"l":2},"a":{"a":0,"k":[9.274,6.623,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[1.39,-1.603],[4.591,1.224],[0.081,0.849],[-4.591,-1.224]],"o":[[0.205,-0.083],[-4.591,-1.224],[-0.156,-2.117],[4.591,1.224]],"v":[[7.479,9.653],[-0.257,5.082],[-9.148,5.221],[0.038,4.351]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.148,-1.279],[1.789,-5.149]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.148,-1.279],[1.789,-5.149]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[1.39,-1.603],[4.591,1.224],[0.081,0.849],[-4.591,-1.224]],"o":[[0.205,-0.083],[-4.591,-1.224],[-0.156,-2.117],[4.591,1.224]],"v":[[7.479,9.653],[-0.257,5.082],[-9.148,5.221],[0.038,4.351]],"c":true}]},{"t":120,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.148,-1.279],[1.789,-5.149]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.961000025272,0.961000025272,0.961000025272,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[9.274,6.623],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":136,"ty":4,"nm":"eye_l_bl1","parent":137,"sr":1,"ks":{"o":{"a":1,"k":[{"t":85,"s":[0],"h":1},{"t":88,"s":[100],"h":1},{"t":112,"s":[0],"h":1},{"t":116,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[17.514,28.882,0],"ix":2,"l":2},"a":{"a":0,"k":[12.335,11.569,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[0.154,-0.694],[6.231,1.661],[-0.839,1.802],[-6.231,-1.661]],"o":[[-0.846,0.306],[-6.231,-1.661],[0.221,-0.762],[6.231,1.661]],"v":[[12.298,-5.972],[1.515,-11.092],[-9.02,-11.403],[1.737,-10.929]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.264,-2.429]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.264,-2.429]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[0.154,-0.694],[6.231,1.661],[-0.839,1.802],[-6.231,-1.661]],"o":[[-0.846,0.306],[-6.231,-1.661],[0.221,-0.762],[6.231,1.661]],"v":[[12.298,-5.972],[1.515,-11.092],[-9.02,-11.403],[1.737,-10.929]],"c":true}]},{"t":120,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.264,-2.429]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.282000005245,0.286000013351,0.286000013351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.335,11.57],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":137,"ty":4,"nm":"eye_l","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[-10.692,-13.618,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[-9.449,-12.553,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0.167},"t":103.227,"s":[-10.692,-13.618,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[-0.953,-12.908,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[-10.692,-13.618,0]}],"ix":2,"l":2},"a":{"a":0,"k":[18.32,22.44,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":89,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.621,0.621,0.621],"y":[0,0,0]},"t":96.451,"s":[100,100,100]},{"i":{"x":[0.355,0.355,0.355],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":103.227,"s":[100,100,100]},{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.578,0.578,0.578],"y":[0,0,0]},"t":110,"s":[80,100,100]},{"t":140,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[3.909,-2.445],[8.357,2.228],[1.027,4.56],[-8.357,-2.228]],"o":[[-3.986,2.493],[-8.356,-2.227],[-1.151,-5.112],[8.357,2.227]],"v":[[15.132,4.033],[0.929,-1.788],[-15.132,-4.033],[3.072,-7.212]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.322,19.962],[-15.132,-4.033],[5.322,-19.962]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.322,19.962],[-15.132,-4.033],[5.322,-19.962]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[3.909,-2.445],[8.357,2.228],[1.027,4.56],[-8.357,-2.228]],"o":[[-3.986,2.493],[-8.356,-2.227],[-1.151,-5.112],[8.357,2.227]],"v":[[15.132,4.033],[0.929,-1.788],[-15.132,-4.033],[3.072,-7.212]],"c":true}]},{"t":120,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.322,19.962],[-15.132,-4.033],[5.322,-19.962]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.067000001669,0.067000001669,0.067000001669,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.32,22.44],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":138,"ty":4,"nm":"eye_r_bl2","parent":140,"sr":1,"ks":{"o":{"a":1,"k":[{"t":85,"s":[0],"h":1},{"t":88,"s":[100],"h":1},{"t":112,"s":[0],"h":1},{"t":116,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.782,11.647,0],"ix":2,"l":2},"a":{"a":0,"k":[9.274,6.623,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[0.261,-0.794],[4.591,1.224],[0.137,0.138],[-4.591,-1.224]],"o":[[-0.315,1.263],[-4.591,-1.224],[-0.163,-1.359],[4.591,1.224]],"v":[[7.729,9.403],[-0.007,4.582],[-11.148,4.471],[-0.462,4.601]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.147,-1.279],[1.789,-5.149]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.147,-1.279],[1.789,-5.149]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[0.261,-0.794],[4.591,1.224],[0.137,0.138],[-4.591,-1.224]],"o":[[-0.315,1.263],[-4.591,-1.224],[-0.163,-1.359],[4.591,1.224]],"v":[[7.729,9.403],[-0.007,4.582],[-11.148,4.471],[-0.462,4.601]],"c":true}]},{"t":120,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.147,-1.279],[1.789,-5.149]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.961000025272,0.961000025272,0.961000025272,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[9.274,6.623],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":139,"ty":4,"nm":"eye_r_bl1","parent":140,"sr":1,"ks":{"o":{"a":1,"k":[{"t":85,"s":[0],"h":1},{"t":88,"s":[100],"h":1},{"t":112,"s":[0],"h":1},{"t":116,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[17.514,28.882,0],"ix":2,"l":2},"a":{"a":0,"k":[12.336,11.57,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[1.867,-0.418],[6.231,1.661],[-0.355,1.246],[-6.231,-1.661]],"o":[[-1.54,0.345],[-6.231,-1.661],[0.277,-0.223],[6.231,1.661]],"v":[[11.048,-4.972],[1.015,-10.592],[-10.019,-10.653],[0.987,-11.179]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.263,-2.429]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.263,-2.429]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[1.867,-0.418],[6.231,1.661],[-0.355,1.246],[-6.231,-1.661]],"o":[[-1.54,0.345],[-6.231,-1.661],[0.277,-0.223],[6.231,1.661]],"v":[[11.048,-4.972],[1.015,-10.592],[-10.019,-10.653],[0.987,-11.179]],"c":true}]},{"t":120,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.263,-2.429]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.282000005245,0.286000013351,0.286000013351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.335,11.57],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":140,"ty":4,"nm":"eye_r","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[67.002,7.093,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.877},"o":{"x":0.666,"y":0},"t":96.451,"s":[58.626,-0.605,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0.134},"t":103.227,"s":[67.002,7.093,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[67.261,7.284,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[67.002,7.093,0]}],"ix":2,"l":2},"a":{"a":0,"k":[18.32,22.439,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":89,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.621,0.621,0.621],"y":[0,0,0]},"t":96.451,"s":[80,100,100]},{"i":{"x":[0.355,0.355,0.355],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":103.227,"s":[100,100,100]},{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.578,0.578,0.578],"y":[0,0,0]},"t":110,"s":[100,100,100]},{"t":140,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[2.634,-3.48],[8.357,2.228],[1.332,4.35],[-8.357,-2.228]],"o":[[-3.431,4.533],[-8.356,-2.227],[-1.216,-3.968],[8.357,2.227]],"v":[[15.132,4.033],[0.179,-2.788],[-15.131,-4.033],[2.321,-6.712]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.321,19.962],[-15.131,-4.033],[5.321,-19.962]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.321,19.962],[-15.131,-4.033],[5.321,-19.962]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[2.634,-3.48],[8.357,2.228],[1.332,4.35],[-8.357,-2.228]],"o":[[-3.431,4.533],[-8.356,-2.227],[-1.216,-3.968],[8.357,2.227]],"v":[[15.132,4.033],[0.179,-2.788],[-15.131,-4.033],[2.321,-6.712]],"c":true}]},{"t":120,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.321,19.962],[-15.131,-4.033],[5.321,-19.962]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.067000001669,0.067000001669,0.067000001669,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.32,22.44],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":141,"ty":4,"nm":"head_bl","parent":145,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[6.555]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[0]},{"t":140,"s":[6.555]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.453,"y":1},"o":{"x":0.773,"y":0},"t":80,"s":[139.506,32.601,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.62,"y":0},"t":95,"s":[149.436,41.692,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[139.506,32.601,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[149.436,41.692,0]}],"ix":2,"l":2},"a":{"a":0,"k":[25.789,20.981,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-6.378,-3.534]],"o":[[0,0],[0,0]],"v":[[-5.29,-2.599],[5.29,2.599]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[20.29,17.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.313,-0.891]],"o":[[1.243,0.787],[0,0]],"v":[[-1.919,-1.258],[1.919,1.258]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[34.659,25.704],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":142,"ty":4,"nm":"head4","parent":145,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[103.985,91.496,0],"ix":2,"l":2},"a":{"a":0,"k":[117.329,111.246,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-3.696,13.867],[58.314,15.545],[13.471,-50.535],[-5.642,-12.859],[-11.388,-10.339]],"o":[[14.991,-7.265],[13.272,-49.788],[-59.056,-15.742],[-3.456,12.963],[0,0],[0,0]],"v":[[52.787,91.246],[84.057,54.218],[23.35,-75.504],[-93.873,6.787],[-90.094,46.283],[-72.377,71.821]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.808000028133,0.458999991417,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[117.329,111.246],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[0]},{"t":140,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[100]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[94]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[100]},{"t":140,"s":[94]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":143,"ty":4,"nm":"head3","parent":145,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.858,59.375,0],"ix":2,"l":2},"a":{"a":0,"k":[60.724,41.946,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.216,-15.817],[31.07,8.282],[-4.217,15.817],[-31.023,-8.457]],"o":[[-4.216,15.817],[-31.07,-8.283],[4.216,-15.817],[31.962,8.712]],"v":[[56.258,19.771],[-7.634,33.414],[-56.257,-10.222],[10.601,-33.239]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.991999983788,0.991999983788,0.615999996662,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[60.724,41.946],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":144,"ty":4,"nm":"head2","parent":145,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[103.527,87.848,0],"ix":2,"l":2},"a":{"a":0,"k":[82.548,74.918,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[9.177,-34.428],[39.206,9.704],[-6.819,25.581],[-46.907,-12.504]],"o":[[-6.819,25.581],[-49.703,-12.303],[9.315,-34.944],[46.318,12.347]],"v":[[73.121,40.486],[-14.262,64.964],[-75.479,-0.4],[21.027,-62.164]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.995999991894,0.902000010014,0.234999999404,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[82.548,74.918],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":145,"ty":4,"nm":"head1","parent":149,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[-20.676]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[0]},{"t":140,"s":[-20.676]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.453,"y":1},"o":{"x":0.773,"y":0},"t":80,"s":[124.041,75.846,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.62,"y":0},"t":95,"s":[144.041,75.846,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[124.041,75.846,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[144.041,75.846,0]}],"ix":2,"l":2},"a":{"a":0,"k":[100.375,195.015,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[13.272,-49.788],[49.134,13.098],[-9.861,36.993],[-59.057,-15.742]],"o":[[-9.861,36.993],[-49.134,-13.097],[13.471,-50.535],[58.314,15.545]],"v":[[87.26,43.46],[-20.142,88.907],[-90.671,-3.972],[26.553,-86.262]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[100.782,102.255],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":146,"ty":4,"nm":"body4","parent":149,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[122.654,122.223,0],"ix":2,"l":2},"a":{"a":0,"k":[142.404,141.973,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-66.537],[67.602,0],[0,49.438],[-81.253,0]],"o":[[0,49.438],[-67.602,0],[0,-67.536],[80.233,0]],"v":[[122.404,24.542],[0,121.973],[-122.404,24.542],[0,-121.972]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.808000028133,0.458999991417,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.404,141.973],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":147,"ty":4,"nm":"body3","parent":149,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120.726,53.422,0],"ix":2,"l":2},"a":{"a":0,"k":[92.328,39.364,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-24.938,-25.244],[44.659,0],[11.674,24.528],[-41.222,0]],"o":[[-11.941,24.289],[-44.957,0],[25.61,-37.204],[40.817,0]],"v":[[92.079,-6.395],[1.971,39.114],[-92.079,-1.91],[1.971,-39.114]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.662999987602,0.071000002325,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[92.328,39.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":148,"ty":4,"nm":"body2","parent":149,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[122.654,82.349,0],"ix":2,"l":2},"a":{"a":0,"k":[87.4,49.029,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-29.679],[50.826,0],[0,25.413],[-47.996,0]],"o":[[0,25.413],[-50.825,0],[0,-28.565],[47.927,0]],"v":[[87.15,5.752],[-0.001,48.779],[-87.15,5.752],[-0.001,-48.779]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.875,0.224000006914,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[87.4,49.029],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":149,"ty":4,"nm":"body1","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[-4]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[6.83]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[-4]},{"t":140,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[67.584,171.386,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.167,"y":0.167},"t":85,"s":[67.584,115.386,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":140,"s":[67.584,115.386,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[67.584,115.386,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[67.584,95.386,0],"to":[0,0,0],"ti":[0,0,0]},{"t":166,"s":[67.584,171.386,0]}],"ix":2,"l":2},"a":{"a":0,"k":[122.654,244.195,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-66.537],[67.602,0],[0,49.438],[-81.253,0]],"o":[[0,49.438],[-67.602,0],[0,-67.536],[80.233,0]],"v":[[122.404,24.542],[0,121.973],[-122.404,24.542],[0,-121.973]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[122.654,122.223],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":150,"ty":4,"nm":"wing_r4","parent":155,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[88.898,65.006,0],"ix":2,"l":2},"a":{"a":0,"k":[90.221,63.386,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-67.412,-44.501],[-18.895,-53.049],[61.467,-52.565],[-33.624,14.61]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-67.412,-44.501],[-18.895,-53.049],[47.313,11.257],[-33.624,14.61]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-67.412,-44.501],[-18.895,-53.049],[61.467,-52.565],[-33.624,14.61]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-67.412,-44.501],[-18.895,-53.049],[47.313,11.257],[-33.624,14.61]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-67.412,-44.501],[-18.895,-53.049],[61.467,-52.565],[-33.624,14.61]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-67.412,-44.501],[-18.895,-53.049],[47.313,11.257],[-33.624,14.61]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-67.412,-44.501],[-18.895,-53.049],[47.313,11.257],[-33.624,14.61]],"c":true}]},{"t":161,"s":[{"i":[[-22.559,17.979],[-28.894,-11.81],[1.9,-11.642],[36.756,0.551]],"o":[[0,0],[44.231,18.078],[-2.898,17.761],[-34.454,-0.517]],"v":[[-67.412,-44.501],[-18.895,-53.049],[60.021,-17.548],[-33.624,14.61]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.808000028133,0.458999991417,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[90.221,63.386],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":151,"ty":4,"nm":"wing_r3","parent":155,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.717,30.786,0],"ix":2,"l":2},"a":{"a":0,"k":[50.514,39.922,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[0,0],[-26.186,3.797]],"o":[[0,0],[0,0]],"v":[[-21.999,-10.559],[33.374,-12.153]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[0,0],[-21.858,-21.337]],"o":[[0,0],[0,0]],"v":[[-23.014,-12.422],[23.014,12.422]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[0,0],[-26.186,3.797]],"o":[[0,0],[0,0]],"v":[[-21.999,-10.559],[33.374,-12.153]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[0,0],[-21.858,-21.337]],"o":[[0,0],[0,0]],"v":[[-23.014,-12.422],[23.014,12.422]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[-26.186,3.797]],"o":[[0,0],[0,0]],"v":[[-21.999,-10.559],[33.374,-12.153]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[0,0],[-21.858,-21.337]],"o":[[0,0],[0,0]],"v":[[-23.014,-12.422],[23.014,12.422]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[0,0],[-21.858,-21.337]],"o":[[0,0],[0,0]],"v":[[-23.014,-12.422],[23.014,12.422]],"c":false}]},{"t":161,"s":[{"i":[[0,0],[-18.503,-7.991]],"o":[[0,0],[0,0]],"v":[[-11.898,-4.625],[32.063,6.381]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.995999991894,0.902000010014,0.234999999404,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":11,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[50.514,39.922],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":152,"ty":4,"nm":"wing_r2","parent":155,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[75.174,39.177,0],"ix":2,"l":2},"a":{"a":0,"k":[65.77,39.179,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-27.243,-2.537],[-10.226,-3.612],[-0.687,2.477],[47.214,4.823],[0,0]],"o":[[-4.376,-11.157],[0,0],[39.19,3.65],[5.054,-0.088],[3.161,-11.364],[-28.886,-2.951],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[69.508,-17.811],[73.092,-27.568],[-6.611,-26.531],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-25.893,-8.84],[-3.366,-13.37],[-0.687,2.477],[42.065,14.368],[0,0]],"o":[[-4.376,-11.157],[0,0],[32.123,10.971],[5.054,-0.088],[3.161,-11.364],[-29.542,-10.085],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[53.33,38.93],[62.359,35.467],[-3.845,-28.844],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-27.243,-2.537],[-10.226,-3.612],[-0.687,2.477],[47.214,4.823],[0,0]],"o":[[-4.376,-11.157],[0,0],[39.19,3.65],[5.054,-0.088],[3.161,-11.364],[-28.886,-2.951],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[69.508,-17.811],[73.092,-27.568],[-6.611,-26.531],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-25.893,-8.84],[-3.366,-13.37],[-0.687,2.477],[42.065,14.368],[0,0]],"o":[[-4.376,-11.157],[0,0],[32.123,10.971],[5.054,-0.088],[3.161,-11.364],[-29.542,-10.085],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[53.33,38.93],[62.359,35.467],[-3.845,-28.844],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-27.243,-2.537],[-10.226,-3.612],[-0.687,2.477],[47.214,4.823],[0,0]],"o":[[-4.376,-11.157],[0,0],[39.19,3.65],[5.054,-0.088],[3.161,-11.364],[-28.886,-2.951],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[69.508,-17.811],[73.092,-27.568],[-6.611,-26.531],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-25.893,-8.84],[-3.366,-13.37],[-0.687,2.477],[42.065,14.368],[0,0]],"o":[[-4.376,-11.157],[0,0],[32.123,10.971],[5.054,-0.088],[3.161,-11.364],[-29.542,-10.085],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[53.33,38.93],[62.359,35.467],[-3.845,-28.844],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-25.893,-8.84],[-3.366,-13.37],[-0.687,2.477],[42.065,14.368],[0,0]],"o":[[-4.376,-11.157],[0,0],[32.123,10.971],[5.054,-0.088],[3.161,-11.364],[-29.542,-10.085],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[53.33,38.93],[62.359,35.467],[-3.845,-28.844],[-52.37,-20.296]],"c":true}]},{"t":161,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-27.243,-2.537],[-10.226,-3.612],[-0.568,2.507],[48.234,10.409],[0,0]],"o":[[-4.376,-11.157],[0,0],[39.19,3.65],[5.054,-0.088],[2.06,-9.099],[-28.383,-6.125],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-2.091,-5.905],[69.335,15.722],[72.919,5.966],[-7.949,-22.863],[-52.37,-20.296]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[65.77,39.18],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":153,"ty":3,"nm":"NULL CONTROL","parent":3,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.453,"y":1},"o":{"x":0.773,"y":0},"t":80,"s":[52.416,-56.006,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.62,"y":0},"t":95,"s":[80.416,-56.006,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[56.416,-56.006,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[67.416,-56.006,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":154,"ty":3,"nm":"NULL CONTROL","parent":153,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[35.411]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":85,"s":[-3.748]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":151,"s":[-3.748]},{"t":158,"s":[-66.476]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[98.066,119.369,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":85,"s":[98.066,49.369,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[98.066,49.369,0],"to":[0,0,0],"ti":[0,0,0]},{"t":166,"s":[98.066,119.369,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":155,"ty":4,"nm":"wing_r1","parent":154,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":85,"s":[-25.358]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[10.739]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":95,"s":[-25.358]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[10.739]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":105,"s":[-25.358]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":110,"s":[7.704]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":150,"s":[7.704]},{"t":168,"s":[-8.239]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":85,"s":[100,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":92,"s":[100,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[100,60,0],"to":[0,0,0],"ti":[0,0,0]},{"t":158,"s":[78.192,104.994,0]}],"ix":2,"l":2},"a":{"a":0,"k":[13.816,43.208,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-47.662,-24.751],[0.855,-33.299],[81.217,-32.815],[-13.874,34.36]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-47.662,-24.751],[0.855,-33.299],[67.063,31.007],[-13.874,34.36]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-47.662,-24.751],[0.855,-33.299],[81.217,-32.815],[-13.874,34.36]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-47.662,-24.751],[0.855,-33.299],[67.063,31.007],[-13.874,34.36]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-47.662,-24.751],[0.855,-33.299],[81.217,-32.815],[-13.874,34.36]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-47.662,-24.751],[0.855,-33.299],[67.063,31.007],[-13.874,34.36]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-47.662,-24.751],[0.855,-33.299],[67.063,31.007],[-13.874,34.36]],"c":true}]},{"t":161,"s":[{"i":[[-22.559,17.979],[-28.894,-11.81],[1.9,-11.642],[36.756,0.551]],"o":[[0,0],[44.231,18.078],[-2.898,17.761],[-34.454,-0.517]],"v":[[-47.662,-24.751],[0.855,-33.299],[79.771,2.202],[-13.874,34.36]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.666999995708,0.071000002325,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[70.471,43.636],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":156,"ty":4,"nm":"wing_l4","parent":160,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[68.46,47.555,0],"ix":2,"l":2},"a":{"a":0,"k":[88.21,67.305,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[24.496,15.235],[28.69,-12.299],[-2.268,-13.172],[-55.682,3.877]],"o":[[0,0],[-44.491,19.072],[1.757,10.209],[34.375,-2.394]],"v":[[43.714,-31.002],[-5.467,-33.851],[-83.747,-13.32],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[24.496,15.235],[28.69,-12.299],[-2.268,-13.172],[-55.682,3.877]],"o":[[0,0],[-44.491,19.072],[1.757,10.209],[34.375,-2.394]],"v":[[43.714,-31.002],[-5.467,-33.851],[-83.747,-13.32],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[24.496,15.235],[28.69,-12.299],[-2.268,-13.172],[-55.682,3.877]],"o":[[0,0],[-44.491,19.072],[1.757,10.209],[34.375,-2.394]],"v":[[43.714,-31.002],[-5.467,-33.851],[-83.747,-13.32],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"t":161,"s":[{"i":[[24.496,15.235],[26.957,-15.738],[-4.457,-10.921],[-45.137,3.088]],"o":[[0,0],[-38.597,22.534],[3.914,9.591],[34.378,-2.352]],"v":[[43.714,-31.002],[-5.467,-33.851],[-77.315,-1.635],[17.025,31.635]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.808000028133,0.458999991417,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[88.21,67.305],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":157,"ty":4,"nm":"wing_l3","parent":160,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[67.223,25.602,0],"ix":2,"l":2},"a":{"a":0,"k":[49.357,37.615,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[0,0],[-14.525,-1.794]],"o":[[13.36,-4.762],[0,0]],"v":[[-23.298,5.736],[16.026,-6.364]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[0,0],[-20.743,-3.772]],"o":[[0,0],[0,0]],"v":[[-21.857,10.114],[21.857,-6.343]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[0,0],[-14.525,-1.794]],"o":[[13.36,-4.762],[0,0]],"v":[[-23.298,5.736],[16.026,-6.364]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[0,0],[-20.743,-3.772]],"o":[[0,0],[0,0]],"v":[[-21.857,10.114],[21.857,-6.343]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[-14.525,-1.794]],"o":[[13.36,-4.762],[0,0]],"v":[[-23.298,5.736],[16.026,-6.364]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[0,0],[-20.743,-3.772]],"o":[[0,0],[0,0]],"v":[[-21.857,10.114],[21.857,-6.343]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[0,0],[-20.743,-3.772]],"o":[[0,0],[0,0]],"v":[[-21.857,10.114],[21.857,-6.343]],"c":false}]},{"t":161,"s":[{"i":[[0,0],[-25.065,5.635]],"o":[[0,0],[0,0]],"v":[[-29.896,8.838],[21.857,-6.343]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.995999991894,0.902000010014,0.234999999404,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":11,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[49.357,37.615],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":158,"ty":4,"nm":"wing_l2","parent":160,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[63.424,44.203,0],"ix":2,"l":2},"a":{"a":0,"k":[63.425,44.205,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[25.341,-10.455],[17.759,1.762],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-31.379,12.946],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[1.052,-16.054],[-73.26,-4.569],[-76.092,-12.594],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[24.689,-11.79],[1.79,-13.67],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-30.63,14.63],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-49.345,43.455],[-58.715,41.065],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[25.341,-10.455],[17.759,1.762],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-31.379,12.946],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[1.052,-16.054],[-73.26,-4.569],[-76.092,-12.594],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[24.689,-11.79],[1.79,-13.67],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-30.63,14.63],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-49.345,43.455],[-58.715,41.065],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[25.341,-10.455],[17.759,1.762],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-31.379,12.946],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[1.052,-16.054],[-73.26,-4.569],[-76.092,-12.594],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[24.689,-11.79],[1.79,-13.67],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-30.63,14.63],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-49.345,43.455],[-58.715,41.065],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[24.689,-11.79],[1.79,-13.67],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-30.63,14.63],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-49.345,43.455],[-58.715,41.065],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"t":161,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[25.124,-10.832],[22.705,-1.343],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-32.087,13.833],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-65.631,5.789],[-70.63,-1.412],[-0.435,-30.505],[48.755,-27.655]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[63.425,44.205],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":159,"ty":3,"nm":"NULL CONTROL","parent":153,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[-52.273]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":85,"s":[-3.748]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":151,"s":[-3.748]},{"t":158,"s":[60.261]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[21.934,140.631,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":85,"s":[21.934,70.631,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[21.934,70.631,0],"to":[0,0,0],"ti":[0,0,0]},{"t":166,"s":[21.934,140.631,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":160,"ty":4,"nm":"wing_l1","parent":159,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":85,"s":[44.874]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[16.506]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":95,"s":[44.874]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[16.506]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":105,"s":[44.874]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":110,"s":[15.391]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":150,"s":[15.391]},{"t":168,"s":[7.417]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":85,"s":[20,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":92,"s":[20,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[20,60,0],"to":[0,0,0],"ti":[0,0,0]},{"t":158,"s":[29.436,109.101,0]}],"ix":2,"l":2},"a":{"a":0,"k":[123.721,48.108,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-2.055,-11.615],[-34.193,-0.139]],"o":[[0,0],[-40.115,19.158],[5.28,29.839],[34.458,0.141]],"v":[[43.714,-31.002],[-5.467,-33.851],[-81.666,-15.139],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-2.055,-11.615],[-34.193,-0.139]],"o":[[0,0],[-40.115,19.158],[5.28,29.839],[34.458,0.141]],"v":[[43.714,-31.002],[-5.467,-33.851],[-81.666,-15.139],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-2.055,-11.615],[-34.193,-0.139]],"o":[[0,0],[-40.115,19.158],[5.28,29.839],[34.458,0.141]],"v":[[43.714,-31.002],[-5.467,-33.851],[-81.666,-15.139],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"t":161,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-46.212,9.075]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[41.222,-8.095]],"v":[[43.714,-31.002],[-5.467,-33.851],[-78.963,1.493],[17.025,31.635]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.666999995708,0.071000002325,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[68.46,47.555],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":161,"ty":4,"nm":"egg_back1","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.065,23.756,0],"ix":2,"l":2},"a":{"a":0,"k":[204.214,88.403,0],"ix":1,"l":2},"s":{"a":0,"k":[99,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.887,123.603],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-53.828,-27.429]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53.829,27.428]],"v":[[184.403,-53.325],[176.443,-42.625],[166.1,-57.987],[153.26,-40.297],[130.529,-68.403],[97.475,-34.649],[34.529,-47.146],[-17.352,-34.649],[-48.443,-51.526],[-107.592,-41.414],[-143.414,-60.99],[-162.613,-47.146],[-178.786,-52.84],[-130.385,40.283]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.407999992371,0.31400001049,0.175999999046,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[204.214,88.403],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.887,123.603],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-53.828,-27.429]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53.829,27.428]],"v":[[184.403,-53.325],[176.443,-42.625],[166.1,-57.987],[153.26,-40.297],[130.529,-68.403],[97.475,-34.649],[34.529,-47.146],[-17.352,-34.649],[-48.443,-51.526],[-107.592,-41.414],[-143.414,-60.99],[-162.613,-47.146],[-178.786,-52.84],[-130.385,40.283]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.592000007629,0.455000013113,0.224000006914,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[204.214,88.403],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"_2_chik_noline_easestop","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":0,"k":[-100,100,100],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":0,"op":151,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/utyan_newborn.tgs b/TMessagesProj/src/main/res/raw/utyan_newborn.tgs new file mode 100644 index 000000000..2f94c5a6f --- /dev/null +++ b/TMessagesProj/src/main/res/raw/utyan_newborn.tgs @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"_053_EGG_OUT","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0},"p":{"a":0,"k":[256,500.908,0]},"a":{"a":0,"k":[60,60,0]},"s":{"a":0,"k":[95,95,100]}},"ao":0,"ip":0,"op":306,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"egg_bl","parent":7,"sr":1,"ks":{"p":{"a":0,"k":[1.654,-64.199,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-3.507,17.894],[0,0],[0,0],[-6.251,2.166],[0,0],[-1.281,2.528],[0,0],[0,0],[0,0],[-5.421,3.864],[0,0],[0,0],[-4.03,3.473],[0,0],[0,0],[-2.076,9.679],[0,0],[0,0],[-3.197,3.921],[0,0]],"o":[[0,0],[0,0],[1.312,6.485],[0,0],[2.678,-0.928],[0,0],[0,0],[0,0],[3.051,5.917],[0,0],[0,0],[4.107,3.382],[0,0],[0,0],[5.12,8.472],[0,0],[0,0],[4.556,2.2],[0,0],[1.352,10.622]],"v":[[-164.175,-40.735],[-145.036,-31.339],[-135.736,14.617],[-121.445,22.776],[-104.028,16.741],[-97.856,11.354],[-81.739,-20.458],[-52.901,-35.705],[-26.524,15.453],[-10.466,19.344],[13.833,2.025],[21.231,8.116],[35.313,7.959],[58.552,-12.067],[87.272,35.453],[107.313,32.091],[119.522,-24.843],[146.379,-11.875],[159.603,-14.811],[164.175,-20.42]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[50]},{"t":80,"s":[16],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[16]},{"t":120,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[50]},{"t":80,"s":[86],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[86]},{"t":120,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":50,"op":300,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"egg 2","parent":11,"sr":1,"ks":{"p":{"a":0,"k":[-0.594,98.167,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.782,18.863],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-5.396,22.871]],"v":[[172.088,-108.121],[153.042,-84.761],[114.065,-103.58],[98.698,-31.912],[62.644,-91.567],[29.846,-63.305],[15.926,-74.767],[-15.49,-52.375],[-46.99,-113.467],[-87.569,-92.011],[-105.293,-57.03],[-124.069,-50.524],[-134.557,-102.346],[-169.594,-119.546]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[50]},{"t":80,"s":[15.82],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[15.82]},{"t":120,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[50]},{"t":80,"s":[84.18],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[84.18]},{"t":120,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":8,"op":300,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"egg 3","parent":11,"sr":1,"ks":{"p":{"a":0,"k":[-0.594,98.167,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-20.217],[-103.123,0],[0,103.123],[3.782,18.863]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-5.396,22.871],[0,103.123],[103.123,0],[0,-16.835],[0,0]],"v":[[153.042,-84.761],[114.065,-103.58],[98.698,-31.912],[62.644,-91.567],[29.846,-63.305],[15.926,-74.767],[-15.49,-52.375],[-46.99,-113.467],[-87.569,-92.011],[-105.293,-57.03],[-124.069,-50.524],[-134.557,-102.346],[-169.594,-119.546],[-177.863,-54.108],[0,119.546],[177.863,-54.108],[172.088,-108.121]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":126,"op":300,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"egg_bl6","parent":11,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-23.168,-72.905,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[7.414,-22.016],[-30.787,0],[-21.435,25.701],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[20.572,16.425],[39.248,0],[-2.431,-5.464],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.583,58.273],[-63.986,78.271],[-78.395,110.505],[0,136.252],[93.834,95.402],[84.283,80.451],[51.159,108.396],[38.957,95.834],[6.844,119.212]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":126,"op":294,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"egg_bl5","parent":11,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-13.915,-37.733,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.456,-6.35],[1.056,-6.227],[-88.193,0],[-10.366,79.967],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-1.456,6.35],[6.364,85.29],[84.846,0],[-11.741,-5.796],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-156.184,18.535],[-159.956,37.417],[-0.26,179.98],[158.468,47.009],[129.234,32.812],[110.853,101.029],[76.152,44.867],[41.318,73.686],[28.099,60.509],[-2.625,80.909],[-34.816,21.358],[-74.896,43.459],[-91.491,78.677],[-110.842,83.056],[-122.333,32.211]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":126,"op":294,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"egg","parent":11,"sr":1,"ks":{"p":{"a":0,"k":[-0.594,98.167,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-20.217],[-103.123,0],[0,103.123],[3.782,18.863]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-5.396,22.871],[0,103.123],[103.123,0],[0,-16.835],[0,0]],"v":[[153.042,-84.761],[114.065,-103.58],[98.698,-31.912],[62.644,-91.567],[29.846,-63.305],[15.926,-74.767],[-15.49,-52.375],[-46.99,-113.467],[-87.569,-92.011],[-105.293,-57.03],[-124.069,-50.524],[-134.557,-102.346],[-169.594,-119.546],[-177.863,-54.108],[0,119.546],[177.863,-54.108],[172.088,-108.121]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431379795,0.847058832645,0.796078443527,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":126,"op":300,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"egg_str","parent":11,"sr":1,"ks":{},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-103.123],[103.123,0],[0,103.123],[-103.123,0]],"o":[[0,103.123],[-103.123,0],[0,-103.123],[103.123,0]],"v":[[177.863,44.06],[0,217.713],[-177.863,44.06],[0,-217.713]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":126,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"egg_bl2","parent":11,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-23.168,-72.905,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-69.541],[69.541,0],[0,69.541],[-69.541,0]],"o":[[0,69.541],[-69.541,0],[0,-69.541],[69.541,0]],"v":[[119.943,19.148],[0,136.252],[-119.943,19.148],[0,-136.252]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":126,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"egg_bl1","parent":11,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-13.915,-37.733,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[16.754,-98.773],[-88.193,0],[0,92.891],[71.198,27.043],[9.085,0]],"o":[[6.364,85.291],[92.891,0],[0,-78.661],[-8.613,-2.316],[-89.171,0]],"v":[[-159.956,37.417],[-0.26,179.98],[159.956,23.557],[40.477,-176.428],[13.915,-179.98]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":126,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"egg1","parent":1,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":66.666,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":73.334,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":81.334,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":93.334,"s":[-5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":100,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":118.484,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":126.971,"s":[-10]},{"t":138,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[60,60,0],"to":[0,-0.667,0],"ti":[0,0.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":66.666,"s":[60,56,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":93.334,"s":[60,56,0],"to":[0,0.667,0],"ti":[0,-0.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":100,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":110,"s":[60,60,0],"to":[0,-0.667,0],"ti":[0,0.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":118.484,"s":[60,56,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":127.818,"s":[60,56,0],"to":[0,0.667,0],"ti":[0,-0.667,0]},{"t":138,"s":[60,60,0]}]},"a":{"a":0,"k":[0,217.713,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":62,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":68,"s":[103,97,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":76,"s":[98,102,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":88,"s":[103,97,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":98,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":112,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":122,"s":[105,95,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":136,"s":[95,105,100]},{"t":150,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-103.123],[103.123,0],[0,103.123],[-103.123,0]],"o":[[0,103.123],[-103.123,0],[0,-103.123],[103.123,0]],"v":[[177.863,44.06],[0,217.713],[-177.863,44.06],[0,-217.713]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431379795,0.847058832645,0.796078443527,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":126,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"hat 2","parent":16,"sr":1,"ks":{"p":{"a":0,"k":[123.535,31.198,0]},"a":{"a":0,"k":[123.535,31.198,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":126,"s":[{"i":[[51.485,0],[33.612,-96.651],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-27.112,-106.94]],"v":[[-0.221,-57.456],[-159.478,94.998],[-117.172,145.81],[-51.356,106.349],[-14.171,157.805],[35.63,123.868],[86.825,158.355],[114.915,100.139],[153.449,99.729]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"t":190,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-93.79,37.179],[-43.469,-4.001],[0.912,29.506],[37.749,-16.727],[89.886,21.263],[101.34,9.386],[127.241,34.528]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-93.79,37.179],[-43.469,-4.001],[0.912,29.506],[37.749,-16.727],[89.886,21.263],[101.34,9.386],[127.241,34.528]],"c":true}]},{"t":226,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":126,"op":300,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"egg_bl4","parent":16,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-23.725,84.558,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":126,"s":[{"i":[[51.411,0],[34.704,-91.659],[0,0],[0,0],[0,0],[0,0],[0,0],[34.301,37.077]],"o":[[-47.702,12.346],[11.558,10.226],[0,0],[0,0],[0,0],[0,0],[0,0],[-17.858,-52.568]],"v":[[0,-136.252],[-134.489,8.781],[-93.067,57.884],[-28.648,24.451],[8.022,72.302],[58.117,39.375],[108.866,72.806],[119.542,-17.214]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-9.722,-5.787],[-9.305,-6.754]],"o":[[-47.702,12.346],[11.558,10.226],[0,0],[0,0],[0,0],[0,0],[8.451,5.03],[-17.858,-52.567]],"v":[[0,-136.252],[-104.498,-51.594],[-78.861,-28.511],[-12.879,-51.194],[28.573,-27.881],[65.195,-64.669],[82.076,-55.051],[110.22,-36.758]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-9.722,-5.787],[-9.305,-6.754]],"o":[[-47.702,12.346],[11.558,10.226],[0,0],[0,0],[0,0],[0,0],[8.451,5.03],[-17.858,-52.567]],"v":[[0,-136.252],[-104.498,-51.594],[-78.861,-28.511],[-12.879,-51.194],[28.573,-27.881],[65.195,-64.669],[82.076,-55.051],[110.22,-36.758]],"c":true}]},{"t":190,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-6.579,-5.164],[-6.97,-6.819]],"o":[[-47.702,12.346],[15.523,1.968],[0,0],[0,0],[0,0],[0,0],[5.719,4.488],[-8.788,-27.002]],"v":[[0,-136.252],[-104.498,-51.594],[-70.476,-45.736],[-20.561,-87.741],[24.706,-55.219],[61.053,-102.542],[72.239,-94.241],[92.137,-76.914]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-6.579,-5.164],[-6.97,-6.819]],"o":[[-47.702,12.346],[15.523,1.968],[0,0],[0,0],[0,0],[0,0],[5.719,4.488],[-8.788,-27.002]],"v":[[0,-136.252],[-104.498,-51.594],[-70.476,-45.736],[-20.561,-87.741],[24.706,-55.219],[61.053,-102.542],[72.239,-94.241],[92.137,-76.914]],"c":true}]},{"t":226,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-9.722,-5.787],[-9.305,-6.754]],"o":[[-47.702,12.346],[11.558,10.226],[0,0],[0,0],[0,0],[0,0],[8.451,5.03],[-17.858,-52.567]],"v":[[0,-136.252],[-104.498,-51.594],[-78.861,-28.511],[-12.879,-51.194],[28.573,-27.881],[65.195,-64.669],[82.076,-55.051],[110.22,-36.758]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":126,"op":290,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"egg_bl3","parent":16,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-14.472,119.73,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":126,"s":[{"i":[[9.085,0],[39.887,-100.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[7.723,7.735],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-12.437,-83.837],[-8.613,-2.316]],"v":[[13.915,-179.98],[-144.763,-26.189],[-101.906,24.267],[-38.001,-13.529],[-0.769,37.726],[48.518,5.975],[99.231,37.249],[128.496,-17.943],[146.193,-37.555],[40.477,-176.428]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[7.723,7.735],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-87.567,-63.657],[-21.528,-87.352],[18.255,-63.613],[54.762,-98.376],[108.13,-72.457],[119.662,-92.193],[130.478,-89.32],[40.477,-176.428]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[7.723,7.735],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-87.567,-63.657],[-21.528,-87.352],[18.255,-63.613],[54.762,-98.376],[108.13,-72.457],[119.662,-92.193],[130.478,-89.32],[40.477,-176.428]],"c":true}]},{"t":190,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[17.888,5.056],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-80.288,-82.971],[-29.819,-123.044],[15.245,-90.333],[51.727,-134.161],[104.871,-100.649],[116.07,-108.995],[129.844,-97.531],[40.477,-176.428]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[17.888,5.056],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-80.288,-82.971],[-29.819,-123.044],[15.245,-90.333],[51.727,-134.161],[104.871,-100.649],[116.07,-108.995],[129.844,-97.531],[40.477,-176.428]],"c":true}]},{"t":226,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[7.723,7.735],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-87.567,-63.657],[-21.528,-87.352],[18.255,-63.613],[54.762,-98.376],[108.13,-72.457],[119.662,-92.193],[130.478,-89.32],[40.477,-176.428]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":126,"op":290,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Layer 38","parent":16,"sr":1,"ks":{"p":{"a":0,"k":[-3.3,26.816,0]},"s":{"a":0,"k":[105.263,105.263,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":126,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[102.228,63.773],[80.907,113.294],[39.124,82.405],[30.023,83.915],[-9.206,110.988],[-41.849,66.01],[-48.51,65.442],[-106.89,99.08],[-131.204,72.623]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.194,-6.017],[88.205,7.945],[43.992,-15.218],[34.891,-13.709],[6.13,16.584],[-27.394,-3.382],[-34.055,-3.951],[-90.377,17.697],[-98.18,10.795]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.194,-6.017],[88.205,7.945],[43.992,-15.218],[34.891,-13.709],[6.13,16.584],[-27.394,-3.382],[-34.055,-3.951],[-90.377,17.697],[-98.18,10.795]],"c":false}]},{"t":190,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.092,-21.436],[86.916,-16.616],[41.713,-50.927],[32.612,-49.418],[2.864,-9.094],[-36.348,-38.372],[-43.009,-38.941],[-88.278,0.486],[-101.87,-0.455]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.092,-21.436],[86.916,-16.616],[41.713,-50.927],[32.612,-49.418],[2.864,-9.094],[-36.348,-38.372],[-43.009,-38.941],[-88.278,0.486],[-101.87,-0.455]],"c":false}]},{"t":226,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.194,-6.017],[88.205,7.945],[43.992,-15.218],[34.891,-13.709],[6.13,16.584],[-27.394,-3.382],[-34.055,-3.951],[-90.377,17.697],[-98.18,10.795]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"hat","parent":26,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[0]},{"t":190,"s":[37.905],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":212,"s":[37.905]},{"t":226,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[0.939,-82.485,0],"to":[9.814,-32.669,0],"ti":[-38.822,-18.461,0]},{"t":190,"s":[105.196,-115.024,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[105.196,-115.024,0],"to":[9.187,-4.882,0],"ti":[14.326,-36.582,0]},{"t":226,"s":[0.939,-82.485,0]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":126,"s":[{"i":[[51.485,0],[33.612,-96.651],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-27.112,-106.94]],"v":[[-0.221,-57.456],[-159.478,94.998],[-117.172,145.81],[-51.356,106.349],[-14.171,157.805],[35.63,123.868],[86.825,158.355],[114.915,100.139],[153.449,99.729]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"t":190,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-93.79,37.179],[-43.469,-4.001],[0.912,29.506],[37.749,-16.727],[89.886,21.263],[101.34,9.386],[127.241,34.528]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-93.79,37.179],[-43.469,-4.001],[0.912,29.506],[37.749,-16.727],[89.886,21.263],[101.34,9.386],[127.241,34.528]],"c":true}]},{"t":226,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431379795,0.847058832645,0.796078443527,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":126,"op":300,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"eye_bl 2","parent":18,"sr":1,"ks":{"p":{"a":0,"k":[-5.931,-13.756,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":142,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":148,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":198,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":234,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"t":240,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":100,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":106,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1.925],"y":[0]},"t":112,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":136,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":142,"s":[0,0,0,1]},{"i":{"x":[0.585],"y":[1]},"o":{"x":[1],"y":[0]},"t":148,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":170,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":176,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":198,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":204,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":228,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":234,"s":[0,0,0,1]},{"t":240,"s":[1,1,1,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"eye 2","parent":22,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":152,"s":[71.553,-58.199,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[71.553,-58.199,0],"to":[-1.247,0.1,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[64.073,-57.597,0],"to":[0,0,0],"ti":[-1.247,0.1,0]},{"t":212,"s":[71.553,-58.199,0]}]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":166,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":190,"s":[90,100,100]},{"t":212,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":142,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":148,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[-1.122,-0.585],[24.793,-0.029],[-2.473,1.548],[-19.728,0.15]],"o":[[2.467,1.287],[-18.217,0.021],[1.796,-1.124],[24.811,-0.188]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[1.335,5.48]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":198,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":234,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"t":240,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":106,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.185],"y":[0]},"t":112,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":136,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":142,"s":[8]},{"i":{"x":[0.738],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":148,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":176,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":198,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":234,"s":[8]},{"t":240,"s":[3]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"eye_bl","parent":20,"sr":1,"ks":{"p":{"a":0,"k":[-5.931,-13.756,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":142,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":148,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":198,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":234,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"t":240,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":100,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":106,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1.925],"y":[0]},"t":112,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":136,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":142,"s":[0,0,0,1]},{"i":{"x":[0.585],"y":[1]},"o":{"x":[1],"y":[0]},"t":148,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":170,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":176,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":198,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":204,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":228,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":234,"s":[0,0,0,1]},{"t":240,"s":[1,1,1,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"eye","parent":22,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[-76.447,-58.199,0],"to":[1.318,0.183,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[-68.541,-57.099,0],"to":[0,0,0],"ti":[1.318,0.183,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":190,"s":[-76.447,-58.199,0],"to":[0,0,0],"ti":[0,0,0]},{"t":212,"s":[-76.447,-58.199,0]}]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":166,"s":[90,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":190,"s":[100,100,100]},{"t":212,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":142,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":148,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[-1.122,-0.585],[24.793,-0.029],[-2.473,1.548],[-19.728,0.15]],"o":[[2.467,1.287],[-18.217,0.021],[1.796,-1.124],[24.811,-0.188]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[1.335,5.48]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":198,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":234,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"t":240,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":106,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.185],"y":[0]},"t":112,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":136,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":142,"s":[8]},{"i":{"x":[0.738],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":148,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":176,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":198,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":234,"s":[8]},{"t":240,"s":[3]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"beak_bl","parent":24,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-21.085,-12.859,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[-8.717,1.178],[-5.525,11.05]],"o":[[8.215,-1.111],[3.916,-7.833]],"v":[[-13.902,8.257],[13.902,-8.257]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[-8.717,1.178],[-5.525,11.05]],"o":[[8.215,-1.111],[3.916,-7.833]],"v":[[-13.902,8.257],[13.902,-8.257]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-8.717,1.178],[-5.525,11.05]],"o":[[8.215,-1.111],[3.916,-7.833]],"v":[[-13.902,8.257],[13.902,-8.257]],"c":false}]},{"t":242,"s":[{"i":[[-8.717,1.178],[-5.525,11.05]],"o":[[8.215,-1.111],[3.916,-7.833]],"v":[[-13.902,8.257],[13.902,-8.257]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"mouth","parent":24,"sr":1,"ks":{"o":{"a":1,"k":[{"t":104,"s":[0],"h":1},{"t":152,"s":[100],"h":1},{"t":240,"s":[0],"h":1}]},"p":{"a":0,"k":[1.036,14.348,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[18.855,4.147],[-16.363,1.196],[-7.193,3.594]],"o":[[4.333,0.853],[18.111,-1.324],[-15.424,7.974]],"v":[[-32.488,-9.198],[1.276,-6.041],[32.39,-12.417]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[16.286,0.667],[-16.402,0.395],[-8.343,13.613]],"o":[[5.359,6.089],[11.173,-0.269],[-14.142,3.08]],"v":[[-31.783,-6.869],[0.583,9.942],[31.783,-9.952]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[16.286,0.667],[-16.402,0.395],[-8.343,13.613]],"o":[[5.359,6.089],[11.173,-0.269],[-14.142,3.08]],"v":[[-31.783,-6.869],[0.583,9.942],[31.783,-9.952]],"c":true}]},{"t":240,"s":[{"i":[[18.855,4.147],[-16.363,1.196],[-7.193,3.594]],"o":[[4.333,0.853],[18.111,-1.324],[-15.424,7.974]],"v":[[-32.488,-9.198],[1.276,-6.041],[32.39,-12.417]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.490196079016,0.035294119269,0.035294119269,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.490196079016,0.035294119269,0.035294119269,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"lips","parent":24,"sr":1,"ks":{"p":{"a":0,"k":[1.701,4.903,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[0,0],[-27.403,11.373]],"o":[[25.831,5.896],[0,0]],"v":[[-42.55,-2.052],[42.957,-7.148]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[0,0],[-34.325,6.961]],"o":[[23.321,0.63],[0,0]],"v":[[-42.027,2.058],[42.027,-2.673]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[0,0],[-34.325,6.961]],"o":[[23.321,0.63],[0,0]],"v":[[-42.027,2.058],[42.027,-2.673]],"c":false}]},{"t":242,"s":[{"i":[[0,0],[-27.403,11.373]],"o":[[25.831,5.896],[0,0]],"v":[[-42.55,-2.052],[42.957,-7.148]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.490196079016,0.035294119269,0.035294119269,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"beak","parent":26,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":152,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[-12.998]},{"t":190,"s":[0.178],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":212,"s":[0.178]},{"t":234,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[1.026,53.198,0],"to":[1.697,-7.68,0],"ti":[7.422,-6.804,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[-10.732,42.411,0],"to":[19.253,-22.069,0],"ti":[6.204,-22.149,0]},{"t":190,"s":[6.973,73.474,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[6.973,73.474,0],"to":[-0.182,-14.626,0],"ti":[2.164,-3.681,0]},{"t":234,"s":[1.026,53.198,0]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[15.624,0.527],[12.064,-0.021],[37.03,-3.608],[-17.096,-6.557],[-17.932,1.474],[-12.049,7.878]],"o":[[-37.988,-2.814],[-14.971,0.026],[-18.714,1.483],[19.171,7.353],[21.022,-1.728],[10.622,-6.945]],"v":[[41.776,-15.026],[0.351,-38.361],[-41.611,-12.1],[-43.815,12.487],[6.294,20.861],[50.368,5.864]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[15.624,0.527],[12.064,-0.021],[37.03,-3.608],[-13.94,-2.768],[-17.989,0.354],[-7.667,20.847]],"o":[[-37.988,-2.814],[-14.971,0.026],[-18.714,1.483],[9.28,23.039],[17.989,-0.354],[14.609,-0.252]],"v":[[41.776,-15.026],[0.351,-38.361],[-41.611,-12.1],[-42.381,7.693],[3.441,38.35],[44.016,2.253]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[15.624,0.527],[12.064,-0.021],[37.03,-3.608],[-13.94,-2.768],[-17.989,0.354],[-7.667,20.847]],"o":[[-37.988,-2.814],[-14.971,0.026],[-18.714,1.483],[9.28,23.039],[17.989,-0.354],[14.609,-0.252]],"v":[[41.776,-15.026],[0.351,-38.361],[-41.611,-12.1],[-42.381,7.693],[3.441,38.35],[44.016,2.253]],"c":true}]},{"t":242,"s":[{"i":[[15.624,0.527],[12.064,-0.021],[37.03,-3.608],[-17.096,-6.557],[-17.932,1.474],[-12.049,7.878]],"o":[[-37.988,-2.814],[-14.971,0.026],[-18.714,1.483],[19.171,7.353],[21.022,-1.728],[10.622,-6.945]],"v":[[41.776,-15.026],[0.351,-38.361],[-41.611,-12.1],[-43.815,12.487],[6.294,20.861],[50.368,5.864]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.811764717102,0.207843139768,0.007843137719,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.364705890417,0.121568627656,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Group 1","parent":26,"sr":1,"ks":{"p":{"a":0,"k":[-117.062,11.459,0]},"s":{"a":0,"k":[105.263,105.263,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[0,0],[-31.516,26.673]],"o":[[-0.034,-0.717],[13.121,-11.105]],"v":[[-1.209,24.606],[23.614,-41.458]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":172,"s":[{"i":[[0,0],[-79.176,26.109]],"o":[[-0.034,-0.717],[16.324,-5.383]],"v":[[-1.209,24.606],[76.412,-77.172]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[0,0],[-79.176,26.109]],"o":[[-0.034,-0.717],[16.324,-5.383]],"v":[[-1.209,24.606],[76.412,-77.172]],"c":false}]},{"t":226,"s":[{"i":[[0,0],[-31.516,26.673]],"o":[[-0.034,-0.717],[13.121,-11.105]],"v":[[-1.209,24.606],[23.614,-41.458]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":192,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[5]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[0]},{"t":240,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":192,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[95]},{"t":240,"s":[95]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 2","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"head","parent":32,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":154,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[-10.658]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":186,"s":[16.261]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[16.261]},{"t":226,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":126,"s":[-2.137,13.016,0],"to":[0.5,-9,0],"ti":[-0.5,9,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.7,"y":0.7},"t":142,"s":[0.863,-40.984,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[0.863,-40.984,0],"to":[-4.5,-1.667,0],"ti":[-1.833,-2,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[-26.137,-50.984,0],"to":[1.833,2,0],"ti":[-6.333,-3.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":186,"s":[11.863,-28.984,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[11.863,-28.984,0],"to":[-1.833,-2,0],"ti":[1.833,2,0]},{"t":226,"s":[0.863,-40.984,0]}]},"a":{"a":0,"k":[0,105.595,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":154,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":162,"s":[98,102,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":176,"s":[102,98,100]},{"t":196,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[-4.466,5.42],[0,25.261],[78.003,0],[0,-69.731],[-18.777,-19.089]],"o":[[14.917,-18.104],[0,-69.731],[-78.003,0],[0,28.799],[2.682,2.727]],"v":[[117.967,98.538],[141.236,32.779],[0,-105.595],[-141.236,32.779],[-111.608,105.595]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[-4.774,5.151],[-1.47,25.219],[77.871,4.54],[4.058,-69.613],[-17.634,-20.149]],"o":[[15.945,-17.205],[4.058,-69.613],[-77.87,-4.54],[-1.676,28.75],[2.519,2.878]],"v":[[117.397,105.896],[144.453,41.603],[11.509,-104.757],[-137.541,25.163],[-112.201,99.58]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":186,"s":[{"i":[[-3.517,6.079],[4.141,24.92],[76.948,-12.787],[-11.431,-68.788],[-21.652,-15.753]],"o":[[11.747,-20.304],[-11.431,-68.788],[-76.947,12.787],[4.721,28.41],[3.093,2.25]],"v":[[126.305,79.696],[138.479,11.012],[-23.53,-102.339],[-140.172,57.316],[-99.009,124.29]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[{"i":[[-3.517,6.079],[4.141,24.92],[76.948,-12.787],[-11.431,-68.788],[-21.652,-15.753]],"o":[[11.747,-20.304],[-11.431,-68.788],[-76.947,12.787],[4.721,28.41],[3.093,2.25]],"v":[[126.305,79.696],[138.479,11.012],[-23.53,-102.339],[-140.172,57.316],[-99.009,124.29]],"c":false}]},{"t":226,"s":[{"i":[[-4.466,5.42],[0,25.261],[78.003,0],[0,-69.731],[-18.777,-19.089]],"o":[[14.917,-18.104],[0,-69.731],[-78.003,0],[0,28.799],[2.682,2.727]],"v":[[117.967,98.538],[141.236,32.779],[0,-105.595],[-141.236,32.779],[-111.608,105.595]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"Layer 39","parent":28,"sr":1,"ks":{"o":{"a":0,"k":50},"p":{"a":0,"k":[-7.202,50.028,0]},"s":{"a":0,"k":[105.263,105.263,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0]],"v":[[98.401,-27.012],[91.412,-13.05],[47.199,-36.213],[38.098,-34.703],[9.337,-4.411],[-24.187,-24.377],[-30.848,-24.946],[-87.17,-3.298]],"c":false}]},{"t":190,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0]],"v":[[99.678,-21.818],[91.302,-5.479],[47.346,-30.299],[38.245,-28.789],[9.457,2.405],[-24.04,-18.463],[-30.701,-19.031],[-86.873,4.566]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0]],"v":[[99.678,-21.818],[91.302,-5.479],[47.346,-30.299],[38.245,-28.789],[9.457,2.405],[-24.04,-18.463],[-30.701,-19.031],[-86.873,4.566]],"c":false}]},{"t":226,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0]],"v":[[98.401,-27.012],[91.412,-13.05],[47.199,-36.213],[38.098,-34.703],[9.337,-4.411],[-24.187,-24.377],[-30.848,-24.946],[-87.17,-3.298]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.917647118662,0.898039275525,0.862745157878,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"hat 3","parent":16,"sr":1,"ks":{},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"t":190,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.719,65.049],[-36.734,40.456],[4.556,65.049],[39.274,28.481],[93.466,56.871],[104.747,34.333],[127.241,34.528]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.719,65.049],[-36.734,40.456],[4.556,65.049],[39.274,28.481],[93.466,56.871],[104.747,34.333],[127.241,34.528]],"c":true}]},{"t":226,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.809911151961,0.774132463044,0.71599222819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"wing","parent":32,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":154,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[-41.998]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":190,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":212,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":226,"s":[-41.998]},{"t":236,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":118,"s":[67.833,-2.967,0],"to":[7.148,-3.993,0],"ti":[-7.148,3.993,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.7,"y":0.7},"t":134,"s":[110.723,-26.923,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[110.723,-26.923,0],"to":[-2.833,-8.5,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[93.723,-77.923,0],"to":[0,0,0],"ti":[-2.833,-8.5,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":1,"y":1},"t":190,"s":[110.723,-26.923,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[110.723,-26.923,0],"to":[1.06,-3.907,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":226,"s":[117.083,-50.367,0],"to":[0,0,0],"ti":[1.06,-3.907,0]},{"t":236,"s":[110.723,-26.923,0]}]},"a":{"a":0,"k":[-38,10,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[-26.375,10.894],[-10.894,-9.299],[15.481,-6.88]],"o":[[26.375,-10.894],[10.894,9.299],[-15.481,6.88]],"v":[[-51.094,-17.505],[50.007,-36.63],[-28.733,39.258]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[-28.013,5.439],[-14.323,-0.025],[110.256,-18.389]],"o":[[82.606,-16.04],[25.955,0.046],[-16.71,2.787]],"v":[[-51.094,-17.505],[40.159,-122.382],[-51.991,56.361]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":190,"s":[{"i":[[-26.489,10.614],[-10.894,-9.299],[41.775,-72.863]],"o":[[61.398,-24.603],[10.894,9.299],[-8.426,14.697]],"v":[[-52.915,-37.647],[75.033,-53.431],[-22.097,62.688]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[-26.489,10.614],[-10.894,-9.299],[36.773,-81.774]],"o":[[61.398,-24.603],[10.894,9.299],[-6.948,15.451]],"v":[[-52.915,-37.647],[73.837,-56.271],[-5.191,70.407]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":226,"s":[{"i":[[-28.013,5.439],[-14.323,-0.025],[154.158,-2.538]],"o":[[82.606,-16.04],[25.955,0.046],[-16.939,0.279]],"v":[[-51.094,-17.505],[60.479,-100.012],[-68.541,50.439]],"c":false}]},{"t":236,"s":[{"i":[[-24.807,14.104],[-10.894,-9.299],[25.623,-24.231]],"o":[[35.353,-20.099],[10.894,9.299],[-12.309,11.64]],"v":[[-51.094,-17.505],[53.164,-23.999],[-26.628,42.416]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"Group 2","parent":31,"sr":1,"ks":{"r":{"a":0,"k":87.025},"p":{"a":0,"k":[-22.432,-25.336,0]},"a":{"a":0,"k":[-3.703,14.028,0]},"s":{"a":0,"k":[105.263,105.263,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":156,"s":[{"i":[[0,0],[-1.88,12.796]],"o":[[-0.021,-0.44],[1.184,-8.054]],"v":[[-4.221,24.977],[-3.046,3.079]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":168,"s":[{"i":[[0,0],[-1.88,12.796]],"o":[[-0.021,-0.44],[1.184,-8.054]],"v":[[2.911,12.803],[-0.313,-10.663]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":190,"s":[{"i":[[0,0],[-0.892,16.675]],"o":[[0.049,-0.438],[0.435,-8.129]],"v":[[9.974,6.265],[13.383,-24.109]],"c":false}]},{"i":{"x":0.833,"y":0.771},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[0,0],[-4.153,14.442]],"o":[[-0.021,-0.44],[2.25,-7.824]],"v":[[2.498,0.447],[15.576,-23.398]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.229},"t":224,"s":[{"i":[[0,0],[-4.331,10.606]],"o":[[-0.021,-0.44],[3.078,-7.536]],"v":[[-16.415,23.679],[-3.338,-0.166]],"c":false}]},{"t":238,"s":[{"i":[[0,0],[-1.88,12.796]],"o":[[-0.021,-0.44],[1.184,-8.054]],"v":[[1.914,22.542],[-0.118,-0.273]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":192,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[5]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[0]},{"t":240,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":192,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[95]},{"t":240,"s":[95]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"wing","parent":32,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":220,"s":[23.836]},{"t":234,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":118,"s":[-72.05,-11.733,0],"to":[-6.108,-2.813,0],"ti":[6.108,2.813,0]},{"t":134,"s":[-108.7,-28.609,0]}]},"a":{"a":0,"k":[28,7,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":156,"s":[{"i":[[44.723,19.495],[6.88,-6.88],[-21.215,-12.041]],"o":[[-44.723,-19.495],[-6.88,6.88],[21.215,12.041]],"v":[[55.051,-21.113],[-54.463,-33.792],[15.3,37.944]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":168,"s":[{"i":[[40.019,27.905],[6.88,-6.88],[-12.005,-38.832]],"o":[[-50.639,-35.31],[-6.88,6.88],[7.205,23.305]],"v":[[55.051,-21.113],[-33.354,-19.801],[15.3,37.944]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":190,"s":[{"i":[[43.781,-21.527],[6.88,-6.88],[-36.462,3.735]],"o":[[-35.333,17.373],[-6.88,6.88],[24.267,-2.486]],"v":[[55.002,-33.744],[-28.249,-25.127],[24.734,27.382]],"c":false}]},{"i":{"x":0.833,"y":0.771},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[31.423,-37.32],[6.88,-6.88],[-21.215,-12.041]],"o":[[-30.66,36.415],[-6.88,6.88],[21.215,12.041]],"v":[[54.449,-31.891],[-14.199,-34.428],[15.3,37.944]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.229},"t":224,"s":[{"i":[[38.977,-5.05],[6.88,-6.88],[-21.215,-12.041]],"o":[[-38.648,4.659],[-6.88,6.88],[21.215,12.041]],"v":[[46.091,-30.836],[-50.254,-51.54],[15.3,37.944]],"c":false}]},{"t":238,"s":[{"i":[[41.97,24.874],[6.88,-6.88],[-27.724,-35.81]],"o":[[-49.58,-29.385],[-6.88,6.88],[14.933,19.289]],"v":[[55.051,-21.113],[-54.463,-21.16],[15.3,37.944]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"body","parent":11,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":154,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[-8.077]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":190,"s":[-4]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":212,"s":[-8.077]},{"t":238,"s":[0]}]},"p":{"a":0,"k":[0.389,106.033,0]},"a":{"a":0,"k":[-1.366,88.432,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":154,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":166,"s":[102,97,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":176,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":198,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":210,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":222,"s":[104,96,100]},{"t":234,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":156,"s":[{"i":[[64.383,0],[6.394,38.501],[-25.026,0],[-12.695,-155.506]],"o":[[-55.365,0],[-22.826,-137.447],[73.802,0],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[-17.431,-112.855],[146.58,44.662]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":168,"s":[{"i":[[64.383,0],[2.301,38.485],[-24.793,-1.896],[-31.206,-151.304]],"o":[[-55.365,0],[-22.007,-135.548],[75.527,6.194],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[-35.39,-122.327],[146.58,44.662]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[64.383,0],[-6.704,38.449],[-24.28,-6.067],[20.527,-81.097]],"o":[[-55.365,0],[26.413,-151.494],[79.321,19.822],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[30.572,-112.038],[146.58,44.662]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[64.383,0],[-6.704,38.449],[-24.28,-6.067],[20.527,-81.097]],"o":[[-55.365,0],[26.413,-151.494],[79.321,19.822],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[30.572,-112.038],[146.58,44.662]],"c":true}]},{"t":228,"s":[{"i":[[64.383,0],[6.394,38.501],[-25.026,0],[-12.695,-155.506]],"o":[[-55.365,0],[-22.826,-137.447],[73.802,0],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[-17.431,-112.855],[146.58,44.662]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"egg 4","parent":11,"sr":1,"ks":{"p":{"a":0,"k":[-0.594,98.167,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,-20.217],[-103.123,0],[0,103.123],[3.782,18.863]],"o":[[0,0],[0,0],[0,0],[-5.396,22.871],[0,103.123],[103.123,0],[0,-16.835],[0,0]],"v":[[144.621,-98.445],[114.065,-103.58],[-126.136,-117.083],[-169.594,-119.546],[-177.863,-54.108],[0,119.546],[177.863,-54.108],[172.088,-108.121]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.811764765721,0.772549079446,0.717647058824,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false}],"ip":132,"op":300,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"_053_EGG","refId":"comp_0","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]},"a":{"a":0,"k":[256,256,0]}},"ao":0,"w":512,"h":512,"ip":0,"op":180,"st":-60,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-night/styles.xml b/TMessagesProj/src/main/res/values-night/styles.xml index 6758ec954..85bbd39fd 100644 --- a/TMessagesProj/src/main/res/values-night/styles.xml +++ b/TMessagesProj/src/main/res/values-night/styles.xml @@ -20,6 +20,9 @@ #232d3a #000000 false + @drawable/tg_splash_320 + @integer/splash_screen_duration + ?android:windowBackground +