From 750eedfc968c2183d0b3f995d52427d5fc8280ad Mon Sep 17 00:00:00 2001 From: xaxtix Date: Fri, 22 Sep 2023 18:40:36 +0400 Subject: [PATCH] update to 10.1.0 (3919) --- TMessagesProj/build.gradle | 17 +- .../widget/DefaultItemAnimator.java | 20 +- .../telegram/messenger/AndroidUtilities.java | 10 + .../telegram/messenger/ApplicationLoader.java | 9 +- .../org/telegram/messenger/BuildVars.java | 5 +- .../messenger/ChannelBoostsController.java | 108 + .../ChatMessagesMetadataController.java | 2 +- .../messenger/ContactsController.java | 3 + .../messenger/DatabaseMigrationHelper.java | 6 + .../org/telegram/messenger/FileLoader.java | 26 +- .../telegram/messenger/FileRefController.java | 34 +- .../org/telegram/messenger/ImageReceiver.java | 46 + .../telegram/messenger/LocaleController.java | 10 +- .../telegram/messenger/MediaController.java | 4 +- .../messenger/MediaDataController.java | 20 +- .../org/telegram/messenger/MessageObject.java | 45 +- .../messenger/MessagesController.java | 24 +- .../telegram/messenger/MessagesStorage.java | 24 +- .../messenger/SendMessagesHelper.java | 3 +- .../org/telegram/messenger/SharedConfig.java | 32 +- .../telegram/messenger/VideoEditedInfo.java | 29 +- .../messenger/video/AudioBufferConverter.java | 4 +- .../video/VideoPlayerHolderBase.java | 18 +- .../video/remix/DefaultAudioRemixer.java | 8 +- .../video/remix/DownMixAudioRemixer.java | 45 +- .../video/resample/DefaultAudioResampler.java | 4 +- .../main/java/org/telegram/tgnet/TLRPC.java | 1755 +++++++++++++++-- .../ui/ActionBar/ActionBarLayout.java | 13 +- .../telegram/ui/ActionBar/BaseFragment.java | 8 + .../ui/ActionBar/INavigationLayout.java | 4 + .../telegram/ui/Adapters/ContactsAdapter.java | 10 +- .../telegram/ui/Adapters/DialogsAdapter.java | 15 +- .../ui/Adapters/DrawerLayoutAdapter.java | 1 - .../org/telegram/ui/Cells/ChatActionCell.java | 1 + .../telegram/ui/Cells/ChatMessageCell.java | 38 +- .../telegram/ui/Cells/DrawerActionCell.java | 2 +- .../ui/Cells/SharedPhotoVideoCell2.java | 5 + .../ui/Cells/UnconfirmedAuthHintCell.java | 2 + .../org/telegram/ui/ChannelBoostLayout.java | 383 ++++ .../java/org/telegram/ui/ChatActivity.java | 110 +- .../telegram/ui/ChatRightsEditActivity.java | 209 +- .../telegram/ui/Components/AlertsCreator.java | 4 +- .../ui/Components/AnimatedEmojiDrawable.java | 22 - .../ui/Components/AnimatedEmojiSpan.java | 34 - .../ui/Components/BlockingUpdateView.java | 68 +- .../ui/Components/BlurringShader.java | 63 +- .../ui/Components/BottomPagerTabs.java | 20 +- .../ui/Components/BulletinFactory.java | 13 + .../telegram/ui/Components/ButtonBounce.java | 18 +- .../ui/Components/ChatActivityEnterView.java | 1 + .../ui/Components/ChatAttachAlert.java | 85 + .../ChatAttachAlertPhotoLayout.java | 10 +- .../ui/Components/ChatAvatarContainer.java | 16 + .../telegram/ui/Components/Crop/CropView.java | 56 +- .../org/telegram/ui/Components/HintView.java | 3 +- .../telegram/ui/Components/ItemOptions.java | 18 +- .../ui/Components/LinkActionView.java | 7 + .../telegram/ui/Components/MediaActivity.java | 7 +- .../ui/Components/MentionsContainerView.java | 9 + .../Paint/Views/EntitiesContainerView.java | 11 + .../ui/Components/Paint/Views/EntityView.java | 7 +- .../Paint/Views/LPhotoPaintView.java | 59 +- .../Paint/Views/ReactionWidgetEntityView.java | 377 ++++ .../Components/Paint/Views/StickerView.java | 1 + .../Components/Premium/LimitPreviewView.java | 245 ++- .../Premium/LimitReachedBottomSheet.java | 442 ++++- .../ui/Components/RLottieDrawable.java | 22 +- .../ChatSelectionReactionMenuOverlay.java | 26 +- .../Reactions/CustomEmojiReactionsWindow.java | 10 +- .../Reactions/ReactionImageHolder.java | 48 +- .../Components/Reactions/ReactionsUtils.java | 32 + .../Components/ReactionsContainerLayout.java | 24 +- .../ui/Components/SharedMediaLayout.java | 51 +- .../ui/Components/ViewPagerFixed.java | 10 +- .../ui/Components/spoilers/SpoilerEffect.java | 57 +- .../Components/spoilers/SpoilerEffect2.java | 32 +- .../spoilers/SpoilerEffectBitmapFactory.java | 1 + .../java/org/telegram/ui/DialogsActivity.java | 168 +- .../telegram/ui/EmojiAnimationsOverlay.java | 77 + .../java/org/telegram/ui/LaunchActivity.java | 120 +- .../java/org/telegram/ui/LoginActivity.java | 2 + .../org/telegram/ui/PaymentFormActivity.java | 4 +- .../java/org/telegram/ui/PhotoViewer.java | 114 +- .../telegram/ui/PrivacySettingsActivity.java | 47 +- .../java/org/telegram/ui/ProfileActivity.java | 286 ++- .../main/java/org/telegram/ui/QrActivity.java | 11 +- .../org/telegram/ui/SecretMediaViewer.java | 12 +- .../org/telegram/ui/SessionsActivity.java | 9 +- .../org/telegram/ui/StatisticActivity.java | 158 +- .../ui/Stories/ChannelBoostUtilities.java | 19 + .../ui/Stories/DialogStoriesCell.java | 328 +-- .../ui/Stories/MessageMediaStoryFull.java | 1 + .../telegram/ui/Stories/PeerStoriesView.java | 771 +++++--- .../ui/Stories/ProfileStoriesView.java | 269 ++- .../ui/Stories/SelfStoriesPreviewView.java | 1 - .../ui/Stories/SelfStoryViewsPage.java | 18 +- .../ui/Stories/SelfStoryViewsView.java | 16 +- .../ui/Stories/StoriesController.java | 869 +++++--- .../ui/Stories/StoriesListPlaceProvider.java | 5 +- .../telegram/ui/Stories/StoriesStorage.java | 109 +- .../telegram/ui/Stories/StoriesUtilities.java | 147 +- .../ui/Stories/StoriesVolumeContorl.java | 21 + .../telegram/ui/Stories/StoryCaptionView.java | 13 +- .../ui/Stories/StoryMediaAreasView.java | 75 +- .../ui/Stories/StoryReactionWidgetView.java | 154 ++ .../org/telegram/ui/Stories/StoryViewer.java | 89 +- .../Stories/StoryWidgetsImageDecorator.java | 146 ++ .../telegram/ui/Stories/UserListPoller.java | 38 +- ...java => ViewsForPeerStoriesRequester.java} | 28 +- .../recorder/CaptionContainerView.java | 37 +- .../ui/Stories/recorder/DraftsController.java | 13 + .../ui/Stories/recorder/EmojiBottomSheet.java | 144 +- .../ui/Stories/recorder/KeyboardNotifier.java | 5 +- .../ui/Stories/recorder/PaintView.java | 603 +++++- .../ui/Stories/recorder/PreviewView.java | 22 +- .../ui/Stories/recorder/StoryEntry.java | 102 +- .../recorder/StoryPrivacyBottomSheet.java | 642 ++++-- .../recorder/StoryPrivacySelector.java | 2 +- .../ui/Stories/recorder/StoryRecorder.java | 179 +- .../ui/Stories/recorder/TimelineView.java | 426 ++-- .../ui/Stories/recorder/VolumeSliderView.java | 45 +- TMessagesProj/src/main/res/raw/boosts.json | 1 + .../src/main/res/raw/spoiler_compute.glsl | 39 + TMessagesProj/src/main/res/raw/stats.json | 1 + TMessagesProj/src/main/res/values/strings.xml | 62 +- TMessagesProj_App/build.gradle | 3 - TMessagesProj_AppHockeyApp/build.gradle | 14 + .../messenger/ApplicationLoaderImpl.java | 43 + TMessagesProj_AppStandalone/.gitignore | 1 + TMessagesProj_AppStandalone/build.gradle | 142 ++ .../google-services.json | 98 + .../src/main/AndroidManifest.xml | 19 + .../messenger/ApplicationLoaderImpl.java | 77 + .../messenger/GoogleVoiceClientActivity.java | 19 + .../messenger/GoogleVoiceClientService.java | 22 + gradle.properties | 4 +- settings.gradle | 1 + 137 files changed, 9590 insertions(+), 2322 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ChannelBoostLayout.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ReactionWidgetEntityView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Stories/ChannelBoostUtilities.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryReactionWidgetView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryWidgetsImageDecorator.java rename TMessagesProj/src/main/java/org/telegram/ui/Stories/{ViewsForSelfStoriesRequester.java => ViewsForPeerStoriesRequester.java} (80%) create mode 100644 TMessagesProj/src/main/res/raw/boosts.json create mode 100644 TMessagesProj/src/main/res/raw/spoiler_compute.glsl create mode 100644 TMessagesProj/src/main/res/raw/stats.json create mode 100644 TMessagesProj_AppStandalone/.gitignore create mode 100644 TMessagesProj_AppStandalone/build.gradle create mode 100644 TMessagesProj_AppStandalone/google-services.json create mode 100644 TMessagesProj_AppStandalone/src/main/AndroidManifest.xml create mode 100644 TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java create mode 100644 TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/GoogleVoiceClientActivity.java create mode 100644 TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/GoogleVoiceClientService.java diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index e03a85d6605..04241d3b6e9 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -17,12 +17,14 @@ configurations.all { } dependencies { + implementation 'androidx.fragment:fragment:1.2.0' implementation 'androidx.core:core:1.10.1' implementation 'androidx.palette:palette:1.0.0' - implementation 'androidx.exifinterface:exifinterface:1.3.3' + implementation 'androidx.exifinterface:exifinterface:1.3.6' implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0' implementation 'androidx.multidex:multidex:2.0.1' implementation "androidx.sharetarget:sharetarget:1.2.0" + implementation 'androidx.interpolator:interpolator:1.0.0' compileOnly 'org.checkerframework:checker-qual:2.5.2' compileOnly 'org.checkerframework:checker-compat-qual:2.5.0' @@ -138,6 +140,19 @@ android { buildConfigField "boolean", "BUILD_HOST_IS_WINDOWS", isWindows } + HA_hardcore { + debuggable false + jniDebuggable false + minifyEnabled true + multiDexEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' + ndk.debugSymbolLevel = 'FULL' + buildConfigField "String", "APP_CENTER_HASH", "\"" + getProps("APP_CENTER_HASH_HARDCORE") + "\"" + buildConfigField "boolean", "DEBUG_VERSION", "true" + buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "true" + buildConfigField "boolean", "BUILD_HOST_IS_WINDOWS", isWindows + } + standalone { debuggable false jniDebuggable false diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/DefaultItemAnimator.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/DefaultItemAnimator.java index cc458d8d8f5..5d923a3a6f4 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/DefaultItemAnimator.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/DefaultItemAnimator.java @@ -236,7 +236,11 @@ protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { .setInterpolator(getRemoveInterpolator()) .alpha(0) .scaleX(1f - animateByScale(view)) - .scaleY(1f - animateByScale(view)) + .scaleY(1f - animateByScale(view)); + if (Build.VERSION.SDK_INT >= 19) { + animation.setUpdateListener(animation1 -> onRemoveAnimationUpdate(holder)); + } + animation .setListener( new AnimatorListenerAdapter() { @Override @@ -284,7 +288,11 @@ public void animateAddImpl(final RecyclerView.ViewHolder holder) { .scaleY(1f) .setDuration(getAddDuration()) .setStartDelay(getAddDelay()) - .setInterpolator(getAddInterpolator()) + .setInterpolator(getAddInterpolator()); + if (Build.VERSION.SDK_INT >= 19) { + animation.setUpdateListener(animation1 -> onAddAnimationUpdate(holder)); + } + animation .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animator) { @@ -342,6 +350,14 @@ protected void onChangeAnimationUpdate(RecyclerView.ViewHolder holder) { } + protected void onAddAnimationUpdate(RecyclerView.ViewHolder holder) { + + } + + protected void onRemoveAnimationUpdate(RecyclerView.ViewHolder holder) { + + } + protected void beforeAnimateMoveImpl(final RecyclerView.ViewHolder holder) { } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index c470a17927a..5d45028492f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -785,6 +785,16 @@ public static float[] getCoordinateInParent(ViewGroup parentView, View view) { return new float[] {xOffset, yOffset}; } + public static void doOnLayout(View view, Runnable runnable) { + view.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) { + view.removeOnLayoutChangeListener(this); + runnable.run(); + } + }); + } + private static class LinkSpec { String url; int start; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index a5297e449c2..35f9306dbfb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -44,7 +44,7 @@ public class ApplicationLoader extends Application { - private static ApplicationLoader applicationLoaderInstance; + public static ApplicationLoader applicationLoaderInstance; @SuppressLint("StaticFieldLeak") public static volatile Context applicationContext; @@ -555,4 +555,11 @@ protected void logDualCameraInternal(boolean success, boolean vendor) { } + public boolean checkApkInstallPermissions(final Context context) { + return false; + } + + public boolean openApkInstall(Activity activity, TLRPC.Document document) { + return false; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 243cf2c9b09..0580dd0e92f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -24,8 +24,8 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 3872; - public static String BUILD_VERSION_STRING = "10.0.9"; + public static int BUILD_VERSION = 3919; + public static String BUILD_VERSION_STRING = "10.1.0"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; @@ -33,6 +33,7 @@ public class BuildVars { public static String SAFETYNET_KEY = "AIzaSyDqt8P-7F7CPCseMkOiVRgb1LY8RN1bvH8"; public static String SMS_HASH = isStandaloneApp() ? "w0lkcmTZkKh" : (DEBUG_VERSION ? "O2P2z+/jBpJ" : "oLeq9AcOZkT"); public static String PLAYSTORE_APP_URL = "https://play.google.com/store/apps/details?id=org.telegram.messenger"; + public static String HUAWEI_STORE_URL = "https://appgallery.huawei.com/app/C101184875"; public static String GOOGLE_AUTH_CLIENT_ID = "760348033671-81kmi3pi84p11ub8hp9a1funsv0rn2p9.apps.googleusercontent.com"; public static String HUAWEI_APP_ID = "101184875"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java new file mode 100644 index 00000000000..4fdc97a6783 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java @@ -0,0 +1,108 @@ +package org.telegram.messenger; + +import com.google.android.exoplayer2.util.Consumer; + +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.BulletinFactory; + +public class ChannelBoostsController { + + private final int currentAccount; + private final MessagesController messagesController; + private final ConnectionsManager connectionsManager; + + public final static int BOOSTS_FOR_LEVEL_1 = 1; + public final static int BOOSTS_FOR_LEVEL_2 = 1; + + public ChannelBoostsController(int currentAccount) { + this.currentAccount = currentAccount; + messagesController = MessagesController.getInstance(currentAccount); + connectionsManager = ConnectionsManager.getInstance(currentAccount); + } + + + public void getBoostsStats(long dialogId, Consumer consumer) { + TLRPC.TL_stories_getBoostsStatus req = new TLRPC.TL_stories_getBoostsStatus(); + req.peer = messagesController.getInputPeer(dialogId); + connectionsManager.sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + consumer.accept((TLRPC.TL_stories_boostsStatus) response); + } else { + BulletinFactory.showForError(error); + consumer.accept(null); + } + })); + + } + + public void userCanBoostChannel(long dialogId, Consumer consumer) { + TLRPC.TL_stories_canApplyBoost req = new TLRPC.TL_stories_canApplyBoost(); + req.peer = messagesController.getInputPeer(dialogId); + connectionsManager.sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + CanApplyBoost canApplyBoost = new CanApplyBoost(); + if (response != null) { + canApplyBoost.canApply = true; + if (response instanceof TLRPC.TL_stories_canApplyBoostReplace) { + TLRPC.TL_stories_canApplyBoostReplace canApplyBoostReplace = (TLRPC.TL_stories_canApplyBoostReplace) response; + messagesController.putChats(canApplyBoostReplace.chats, false); + canApplyBoost.replaceDialogId = DialogObject.getPeerDialogId(canApplyBoostReplace.current_boost); + if (canApplyBoost.replaceDialogId == 0 && canApplyBoostReplace.chats.size() > 0) { + canApplyBoost.replaceDialogId = -canApplyBoostReplace.chats.get(0).id; + } + } + } else { + if (error != null) { + if (error.text.equals("SAME_BOOST_ALREADY_ACTIVE") || error.text.equals("BOOST_NOT_MODIFIED")) { + canApplyBoost.alreadyActive = true; + } else if (error.text.equals("PREMIUM_GIFTED_NOT_ALLOWED")) { + canApplyBoost.giftedPremium = true; + } else if (error.text.startsWith("FLOOD_WAIT")) { + canApplyBoost.floodWait = Utilities.parseInt(error.text); + canApplyBoost.lastCheckTime = System.currentTimeMillis(); + } + } + } + consumer.accept(canApplyBoost); + }), ConnectionsManager.RequestFlagDoNotWaitFloodWait); + } + + public void applyBoost(long dialogId) { + TLRPC.TL_stories_applyBoost req = new TLRPC.TL_stories_applyBoost(); + req.peer = messagesController.getInputPeer(dialogId); + connectionsManager.sendRequest(req, (response, error) -> { + + }); + } + + public int getTotalBooststToLevel(int level) { + int count = 0; + if (level >= 1) { + count += BOOSTS_FOR_LEVEL_1; + } + if (level >= 2) { + count += BOOSTS_FOR_LEVEL_2; + } + return count; + } + + public static class CanApplyBoost { + public boolean canApply; + public long replaceDialogId; + + public boolean alreadyActive; + public int floodWait; + public boolean giftedPremium; + private long lastCheckTime; + + public void checkTime() { + floodWait -= (System.currentTimeMillis() - lastCheckTime) / 1000; + lastCheckTime = System.currentTimeMillis(); + if (floodWait < 0) { + floodWait = 0; + canApply = true; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java index fc73ae225d6..a13d2151575 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java @@ -87,7 +87,7 @@ private void loadStoriesForMessages(long dialogId, ArrayList visi continue; } long storyDialogId = storyItem.dialogId; - req.user_id = chatActivity.getMessagesController().getInputUser(storyDialogId); + req.peer = chatActivity.getMessagesController().getInputPeer(storyDialogId); req.id.add(storyItem.id); int storyId = storyItem.id; int reqId = chatActivity.getConnectionsManager().sendRequest(req, (response, error) -> { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java index f3588267241..717f609128d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -2864,6 +2864,9 @@ public static String formatName(TLObject object) { } public static String formatName(TLRPC.User user) { + if (user == null) { + return ""; + } return formatName(user.first_name, user.last_name, 0); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java index b63f4a9bddc..b52a05a4722 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java @@ -1370,6 +1370,12 @@ public static int migrate(MessagesStorage messagesStorage, int version) throws E version = 133; } + if (version == 133) { + database.executeFast("ALTER TABLE unread_push_messages ADD COLUMN topicId INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 134").stepThis().dispose(); + version = 134; + } + return version; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 2c1855d0b9c..5de954d13fa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -1169,6 +1169,10 @@ public File getPathToMessage(TLRPC.Message message) { } public File getPathToMessage(TLRPC.Message message, boolean useFileDatabaseQueue) { + return getPathToMessage(message, useFileDatabaseQueue, false); + } + + public File getPathToMessage(TLRPC.Message message, boolean useFileDatabaseQueue, boolean saveAsFile) { if (message == null) { return new File(""); } @@ -1184,7 +1188,7 @@ public File getPathToMessage(TLRPC.Message message, boolean useFileDatabaseQueue } } else { if (MessageObject.getMedia(message) instanceof TLRPC.TL_messageMediaDocument) { - return getPathToAttach(MessageObject.getMedia(message).document, null, MessageObject.getMedia(message).ttl_seconds != 0, useFileDatabaseQueue); + return getPathToAttach(MessageObject.getMedia(message).document, null,null, MessageObject.getMedia(message).ttl_seconds != 0, useFileDatabaseQueue, saveAsFile); } else if (MessageObject.getMedia(message) instanceof TLRPC.TL_messageMediaPhoto) { ArrayList sizes = MessageObject.getMedia(message).photo.sizes; if (sizes.size() > 0) { @@ -1221,21 +1225,22 @@ public File getPathToAttach(TLObject attach, boolean forceCache) { } public File getPathToAttach(TLObject attach, String ext, boolean forceCache) { - return getPathToAttach(attach, null, ext, forceCache, true); + return getPathToAttach(attach, null, ext, forceCache, true, false); } public File getPathToAttach(TLObject attach, String ext, boolean forceCache, boolean useFileDatabaseQueue) { - return getPathToAttach(attach, null, ext, forceCache, useFileDatabaseQueue); + return getPathToAttach(attach, null, ext, forceCache, useFileDatabaseQueue, false); } /** * Return real file name. Used before file.exist() */ - public File getPathToAttach(TLObject attach, String size, String ext, boolean forceCache, boolean useFileDatabaseQueue) { + public File getPathToAttach(TLObject attach, String size, String ext, boolean forceCache, boolean useFileDatabaseQueue, boolean saveAsFile) { File dir = null; long documentId = 0; int dcId = 0; int type = 0; + String fileName = null; if (forceCache) { dir = getDirectory(MEDIA_DIR_CACHE); } else { @@ -1252,7 +1257,13 @@ public File getPathToAttach(TLObject attach, String size, String ext, boolean fo } else if (MessageObject.isVideoDocument(document)) { type = MEDIA_DIR_VIDEO; } else { - type = MEDIA_DIR_DOCUMENT; + String documentFileName = getDocumentFileName(document); + if (saveAsFile && !TextUtils.isEmpty(documentFileName)) { + fileName = documentFileName; + type = MEDIA_DIR_FILES; + } else { + type = MEDIA_DIR_DOCUMENT; + } } } documentId = document.id; @@ -1323,7 +1334,10 @@ public File getPathToAttach(TLObject attach, String size, String ext, boolean fo return new File(path); } } - return new File(dir, getAttachFileName(attach, ext)); + if (fileName == null) { + fileName = getAttachFileName(attach, ext); + } + return new File(dir, fileName); } public FilePathDatabase getFileDatabase() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java index c4c8a7607b6..74c96b113eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java @@ -352,7 +352,7 @@ private void requestReferenceFromServer(Object parentObject, String locationKey, if (parentObject instanceof TLRPC.StoryItem) { TLRPC.StoryItem storyItem = (TLRPC.StoryItem) parentObject; TLRPC.TL_stories_getStoriesByID req = new TLRPC.TL_stories_getStoriesByID(); - req.user_id = getMessagesController().getInputUser(storyItem.dialogId); + req.peer = getMessagesController().getInputPeer(storyItem.dialogId); req.id.add(storyItem.id); getConnectionsManager().sendRequest(req, (response, error) -> { onRequestComplete(locationKey, parentKey, response, error, true, false); @@ -911,35 +911,7 @@ private boolean onRequestComplete(String locationKey, String parentKey, TLObject } } else if (response instanceof TLRPC.TL_help_appUpdate) { TLRPC.TL_help_appUpdate appUpdate = (TLRPC.TL_help_appUpdate) response; - try { - SharedConfig.pendingAppUpdate = appUpdate; - SharedConfig.saveConfig(); - } catch (Exception e) { - FileLog.e(e); - } - try { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.appUpdateAvailable); - } catch (Exception e) { - FileLog.e(e); - } - try { - if (appUpdate.document != null) { - result = appUpdate.document.file_reference; - TLRPC.TL_inputDocumentFileLocation location = new TLRPC.TL_inputDocumentFileLocation(); - location.id = appUpdate.document.id; - location.access_hash = appUpdate.document.access_hash; - location.file_reference = appUpdate.document.file_reference; - location.thumb_size = ""; - locationReplacement = new TLRPC.InputFileLocation[1]; - locationReplacement[0] = location; - } - } catch (Exception e) { - result = null; - FileLog.e(e); - } - if (result == null) { - result = getFileReference(appUpdate.document, requester.location, needReplacement, locationReplacement); - } + result = getFileReference(appUpdate.document, requester.location, needReplacement, locationReplacement); if (result == null) { result = getFileReference(appUpdate.sticker, requester.location, needReplacement, locationReplacement); } @@ -1091,7 +1063,7 @@ private boolean onRequestComplete(String locationKey, String parentKey, TLObject TLRPC.StoryItem storyItem = (TLRPC.StoryItem) operation.parentObject; if (newStoryItem == null) { TLRPC.TL_updateStory story = new TLRPC.TL_updateStory(); - story.user_id = storyItem.dialogId; + story.peer = getMessagesController().getPeer(storyItem.dialogId); story.story = new TLRPC.TL_storyItemDeleted(); story.story.id = storyItem.id; ArrayList updates = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index ab82c62380b..cd19c523f59 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -54,6 +54,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg List preloadReceivers; private boolean allowCrossfadeWithImage = true; private boolean allowDrawWhileCacheGenerating; + private ArrayList decorators; public boolean updateThumbShaderMatrix() { if (currentThumbDrawable != null && thumbShader != null) { @@ -1080,6 +1081,11 @@ public void onDetachedFromWindow() { if (lottieDrawable != null) { lottieDrawable.removeParentView(this); } + if (decorators != null) { + for (int i = 0; i < decorators.size(); i++) { + decorators.get(i).onDetachedFromWidnow(); + } + } } public boolean setBackupImage() { @@ -1163,6 +1169,11 @@ public boolean onAttachedToWindow() { if (staticThumbDrawable instanceof AttachableDrawable) { ((AttachableDrawable) staticThumbDrawable).onAttachedToWindow(this); } + if (decorators != null) { + for (int i = 0; i < decorators.size(); i++) { + decorators.get(i).onAttachedToWindow(this); + } + } return false; } @@ -2028,6 +2039,11 @@ public boolean draw(Canvas canvas, BackgroundThreadDrawHolder backgroundThreadDr if (gradientBitmap != null && currentImageKey != null) { canvas.restore(); } + if (result && isVisible && decorators != null) { + for (int i = 0; i < decorators.size(); i++) { + decorators.get(i).onDraw(canvas, this); + } + } return result; } @@ -3142,6 +3158,26 @@ public BackgroundThreadDrawHolder setDrawInBackgroundThread(BackgroundThreadDraw return holder; } + public void clearDecorators() { + if (decorators != null) { + if (attachedToWindow) { + for (int i = 0; i < decorators.size(); i++) { + decorators.get(i).onDetachedFromWidnow(); + } + } + decorators.clear(); + } + } + public void addDecorator(Decorator decorator) { + if (decorators == null) { + decorators = new ArrayList<>(); + } + decorators.add(decorator); + if (attachedToWindow) { + decorator.onAttachedToWindow(this); + } + } + public static class BackgroundThreadDrawHolder { public boolean animationNotReady; public float overrideAlpha; @@ -3224,4 +3260,14 @@ public ReactionLastFrame(Bitmap bitmap) { super(bitmap); } } + + public static abstract class Decorator { + protected abstract void onDraw(Canvas canvas, ImageReceiver imageReceiver); + public void onAttachedToWindow(ImageReceiver imageReceiver) { + + } + public void onDetachedFromWidnow() { + + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index 1b5e485778b..06d147fa6fa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -2040,14 +2040,14 @@ public static String formatDateForBan(long date) { public static String stringForMessageListDate(long date) { try { date *= 1000; - Calendar rightNow = Calendar.getInstance(); - int day = rightNow.get(Calendar.DAY_OF_YEAR); - rightNow.setTimeInMillis(date); - int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); - if (Math.abs(System.currentTimeMillis() - date) >= 31536000000L) { return getInstance().formatterYear.format(new Date(date)); } else { + Calendar rightNow = Calendar.getInstance(); + int day = rightNow.get(Calendar.DAY_OF_YEAR); + rightNow.setTimeInMillis(date); + int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); + int dayDiff = dateDay - day; if (dayDiff == 0 || dayDiff == -1 && System.currentTimeMillis() - date < 60 * 60 * 8 * 1000) { return getInstance().formatterDay.format(new Date(date)); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 7063e2e12c8..4fb4d54e568 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -4068,7 +4068,7 @@ public void start() { } } if (path == null || path.length() == 0) { - path = FileLoader.getInstance(currentAccount.getCurrentAccount()).getPathToMessage(message.messageOwner).toString(); + path = FileLoader.getInstance(currentAccount.getCurrentAccount()).getPathToMessage(message.messageOwner, true, !isMusic).toString(); } File sourceFile = new File(path); if (!sourceFile.exists()) { @@ -4122,7 +4122,7 @@ public void start() { } } if (path == null || path.length() == 0) { - path = FileLoader.getInstance(currentAccount.getCurrentAccount()).getPathToMessage(message.messageOwner).toString(); + path = FileLoader.getInstance(currentAccount.getCurrentAccount()).getPathToMessage(message.messageOwner, true, !isMusic).toString(); } File sourceFile = new File(path); if (!sourceFile.exists()) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index bf7b11c55f5..b76c7883762 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -94,6 +94,7 @@ 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_SIDE_MENU_ICON_KEY = "android_side_menu_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", @@ -1568,6 +1569,16 @@ public static TLRPC.TL_attachMenuBotIcon getStaticAttachMenuBotIcon(@NonNull TLR return null; } + @Nullable + public static TLRPC.TL_attachMenuBotIcon getSideAttachMenuBotIcon(@NonNull TLRPC.TL_attachMenuBot bot) { + for (TLRPC.TL_attachMenuBotIcon icon : bot.icons) { + if (icon.name.equals(ATTACH_MENU_BOT_SIDE_MENU_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) { @@ -5469,7 +5480,7 @@ public void loadReplyMessagesForMessages(ArrayList messages, long } if (messageObject.type == MessageObject.TYPE_STORY || messageObject.type == MessageObject.TYPE_STORY_MENTION) { if (messageObject.messageOwner.media.storyItem == null) { - long storyDialogId = messageObject.messageOwner.media.user_id; + long storyDialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.media.peer); if (messagesWithUnknownStories == null) { messagesWithUnknownStories = new LongSparseArray<>(); } @@ -5480,7 +5491,7 @@ public void loadReplyMessagesForMessages(ArrayList messages, long } array.add(messageObject); } else { - long storyDialogId = messageObject.messageOwner.media.user_id; + long storyDialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.media.peer); messageObject.messageOwner.media.storyItem = StoriesStorage.checkExpiredStateLocal(currentAccount, storyDialogId, messageObject.messageOwner.media.storyItem); } } else if (messageObject.getId() > 0 && messageObject.isReplyToStory()) { @@ -5554,7 +5565,7 @@ public void loadReplyMessagesForMessages(ArrayList messages, long if (attr instanceof TLRPC.TL_webPageAttributeStory) { TLRPC.TL_webPageAttributeStory attrStory = (TLRPC.TL_webPageAttributeStory) attr; if (attrStory.storyItem == null) { - long storyDialogId = attrStory.user_id; + long storyDialogId = DialogObject.getPeerDialogId(attrStory.peer); if (messagesWithUnknownStories == null) { messagesWithUnknownStories = new LongSparseArray<>(); } @@ -5565,7 +5576,7 @@ public void loadReplyMessagesForMessages(ArrayList messages, long } array.add(messageObject); } else { - long storyDialogId = attrStory.user_id; + long storyDialogId = DialogObject.getPeerDialogId(attrStory.peer); attrStory.storyItem = StoriesStorage.checkExpiredStateLocal(currentAccount, storyDialogId, attrStory.storyItem); } } @@ -7235,6 +7246,7 @@ public void moveStickerSetToTop(long setId, boolean emojis, boolean masks) { public void applyAttachMenuBot(TLRPC.TL_attachMenuBotsBot attachMenuBot) { attachMenuBots.bots.add(attachMenuBot.bot); + loadAttachMenuBots(false, true); } public boolean botInAttachMenu(long id) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index f1bdfc86df4..c10e8e1ff7b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -233,7 +233,6 @@ public class MessageObject { public int lastLineWidth; public int textWidth; public int textHeight; - public int captionHeight; public boolean hasRtl; public float textXOffset; @@ -1647,6 +1646,18 @@ public MessageObject(int accountNum, TLRPC.TL_channelAdminLogEvent event, ArrayL rights.append('\n').append(n.edit_messages ? '+' : '-').append(' '); rights.append(LocaleController.getString("EventLogPromotedEditMessages", R.string.EventLogPromotedEditMessages)); } + if (o.post_stories != n.post_stories) { + rights.append('\n').append(n.post_stories ? '+' : '-').append(' '); + rights.append(LocaleController.getString("EventLogPromotedPostStories", R.string.EventLogPromotedPostStories)); + } + if (o.edit_stories != n.edit_stories) { + rights.append('\n').append(n.edit_messages ? '+' : '-').append(' '); + rights.append(LocaleController.getString("EventLogPromotedEditStories", R.string.EventLogPromotedEditStories)); + } + if (o.delete_stories != n.delete_stories) { + rights.append('\n').append(n.delete_stories ? '+' : '-').append(' '); + rights.append(LocaleController.getString("EventLogPromotedDeleteStories", R.string.EventLogPromotedDeleteStories)); + } } if (o.delete_messages != n.delete_messages) { rights.append('\n').append(n.delete_messages ? '+' : '-').append(' '); @@ -4295,8 +4306,8 @@ public static boolean isDocumentHasThumb(TLRPC.Document document) { public static boolean canPreviewDocument(TLRPC.Document document) { if (document != null && document.mime_type != null) { - String mime = document.mime_type.toLowerCase(); - if (isDocumentHasThumb(document) && (mime.equals("image/png") || mime.equals("image/jpg") || mime.equals("image/jpeg")) || (Build.VERSION.SDK_INT >= 26 && (mime.equals("image/heic")))) { + String mime = document.mime_type; + if (isDocumentHasThumb(document) && (mime.equalsIgnoreCase("image/png") || mime.equalsIgnoreCase("image/jpg") || mime.equalsIgnoreCase("image/jpeg")) || (Build.VERSION.SDK_INT >= 26 && (mime.equalsIgnoreCase("image/heic")))) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { @@ -4872,28 +4883,6 @@ public void generateCaption() { caption = Emoji.replaceEmoji(text, Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); caption = replaceAnimatedEmoji(caption, entities, Theme.chat_msgTextPaint.getFontMetricsInt(), false); - int maxWidth = getMaxMessageTextWidth(); - final float lineSpacing = 1f; - final float lineAdd = 0; - Layout.Alignment align = Layout.Alignment.ALIGN_NORMAL; - StaticLayout captionLayout = null; - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - StaticLayout.Builder builder = - StaticLayout.Builder.obtain(caption, 0, caption.length(), Theme.chat_msgTextPaint, maxWidth) - .setLineSpacing(lineAdd, lineSpacing) - .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) - .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) - .setAlignment(align); - captionLayout = builder.build(); - } else { - captionLayout = new StaticLayout(caption, Theme.chat_msgTextPaint, maxWidth, align, lineSpacing, lineAdd, false); - } - } catch (Exception e) { - FileLog.e(e); - } - captionHeight = captionLayout == null ? 0 : captionLayout.getHeight(); - boolean hasEntities; if (messageOwner.send_state != MESSAGE_SEND_STATE_SENT) { hasEntities = false; @@ -6900,10 +6889,6 @@ public int getApproximateHeight() { photoHeight = h; } - if (caption != null && !TextUtils.isEmpty(caption)) { - photoHeight += captionHeight; - } - return photoHeight + AndroidUtilities.dp(14); } } @@ -8080,7 +8065,7 @@ public TLRPC.WebPage getStoryMentionWebpage() { webpage.type = "telegram_story"; TLRPC.TL_webPageAttributeStory attr = new TLRPC.TL_webPageAttributeStory(); attr.id = messageOwner.media.id; - attr.user_id = messageOwner.media.user_id; + attr.peer = MessagesController.getInstance(currentAccount).getPeer(messageOwner.media.user_id); if (messageOwner.media.storyItem != null) { attr.flags |= 1; attr.storyItem = messageOwner.media.storyItem; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 604202fff42..efe605149f3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -146,6 +146,7 @@ public class MessagesController extends BaseController implements NotificationCe private boolean hasArchivedChats; private boolean hasStories; public long storiesChangelogUserId = 777000; + private ChannelBoostsController channelBoostsControler; public static TLRPC.Peer getPeerFromInputPeer(TLRPC.InputPeer peer) { if (peer.chat_id != 0) { @@ -163,6 +164,19 @@ public static TLRPC.Peer getPeerFromInputPeer(TLRPC.InputPeer peer) { } } + public ChannelBoostsController getBoostsController() { + if (channelBoostsControler != null) { + return channelBoostsControler; + } + synchronized (lockObjects[currentAccount]) { + if (channelBoostsControler != null) { + return channelBoostsControler; + } + channelBoostsControler = new ChannelBoostsController(currentAccount); + } + return channelBoostsControler; + } + class ChatlistUpdatesStat { public ChatlistUpdatesStat() { this.loading = true; @@ -4708,6 +4722,9 @@ public void putChat(final TLRPC.Chat chat, boolean fromCache) { } else { oldChat.flags |= 16384; } + if (!chat.stories_hidden_min) { + chat.stories_hidden = oldChat.stories_hidden; + } if (oldFlags != newFlags || oldFlags2 != newFlags2) { AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.channelRightsUpdated, chat)); } @@ -14788,7 +14805,8 @@ public boolean processUpdateArray(ArrayList updates, ArrayList updates, ArrayList 0) { + usersToLoad.add(dialogId); + } + if (dialogId < 0) { + chatsToLoad.add(-dialogId); + } + } } if (message.replies != null) { for (int a = 0, N = message.replies.recent_repliers.size(); a < N; a++) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 45509795085..4e6abca5b12 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -3692,6 +3692,7 @@ public void sendMessage(SendMessageParams sendMessageParams) { TLRPC.TL_messageMediaStory mediaStory = new MessageMediaStoryFull(); mediaStory.id = sendingStory.id; mediaStory.user_id = sendingStory.dialogId; + mediaStory.peer = getMessagesController().getPeer(sendingStory.dialogId); mediaStory.storyItem = sendingStory; newMsg.media = mediaStory; type = MEDIA_TYPE_STORY; @@ -4278,7 +4279,7 @@ public void sendMessage(SendMessageParams sendMessageParams) { } else if (type == MEDIA_TYPE_STORY) { TLRPC.TL_inputMediaStory inputMediaStory = new TLRPC.TL_inputMediaStory(); inputMediaStory.id = sendingStory.id; - inputMediaStory.user_id = MessagesController.getInstance(currentAccount).getInputUser(sendingStory.dialogId); + inputMediaStory.peer = MessagesController.getInstance(currentAccount).getInputPeer(sendingStory.dialogId); inputMedia = inputMediaStory; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index 9698bbf1b2c..88a2d93156e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -234,6 +234,9 @@ private static boolean isWhitelisted(MediaCodecInfo codecInfo) { public static int searchMessagesAsListHintShows; public static int textSelectionHintShows; public static int scheduledOrNoSoundHintShows; + public static long scheduledOrNoSoundHintSeenAt; + public static int scheduledHintShows; + public static long scheduledHintSeenAt; public static int lockRecordAudioVideoHint; public static boolean forwardingOptionsHintShown; public static boolean searchMessagesAsListUsed; @@ -430,6 +433,9 @@ public static void saveConfig() { editor.putBoolean("sortFilesByName", sortFilesByName); editor.putInt("textSelectionHintShows", textSelectionHintShows); editor.putInt("scheduledOrNoSoundHintShows", scheduledOrNoSoundHintShows); + editor.putLong("scheduledOrNoSoundHintSeenAt", scheduledOrNoSoundHintSeenAt); + editor.putInt("scheduledHintShows", scheduledHintShows); + editor.putLong("scheduledHintSeenAt", scheduledHintSeenAt); editor.putBoolean("forwardingOptionsHintShown", forwardingOptionsHintShown); editor.putInt("lockRecordAudioVideoHint", lockRecordAudioVideoHint); editor.putString("storageCacheDir", !TextUtils.isEmpty(storageCacheDir) ? storageCacheDir : ""); @@ -605,6 +611,9 @@ public static void loadConfig() { storyReactionsLongPressHint = preferences.getBoolean("storyReactionsLongPressHint", false); textSelectionHintShows = preferences.getInt("textSelectionHintShows", 0); scheduledOrNoSoundHintShows = preferences.getInt("scheduledOrNoSoundHintShows", 0); + scheduledOrNoSoundHintSeenAt = preferences.getLong("scheduledOrNoSoundHintSeenAt", 0); + scheduledHintShows = preferences.getInt("scheduledHintShows", 0); + scheduledHintSeenAt = preferences.getLong("scheduledHintSeenAt", 0); forwardingOptionsHintShown = preferences.getBoolean("forwardingOptionsHintShown", false); lockRecordAudioVideoHint = preferences.getInt("lockRecordAudioVideoHint", 0); disableVoiceAudioEffects = preferences.getBoolean("disableVoiceAudioEffects", false); @@ -824,6 +833,9 @@ public static void clearConfig() { lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; textSelectionHintShows = 0; scheduledOrNoSoundHintShows = 0; + scheduledOrNoSoundHintSeenAt = 0; + scheduledHintShows = 0; + scheduledHintSeenAt = 0; lockRecordAudioVideoHint = 0; forwardingOptionsHintShown = false; messageSeenHintCount = 3; @@ -887,10 +899,21 @@ public static void removeTextSelectionHint() { editor.apply(); } - public static void increaseScheduledOrNoSuoundHintShowed() { + public static void increaseScheduledOrNoSoundHintShowed() { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); SharedPreferences.Editor editor = preferences.edit(); + scheduledOrNoSoundHintSeenAt = System.currentTimeMillis(); editor.putInt("scheduledOrNoSoundHintShows", ++scheduledOrNoSoundHintShows); + editor.putLong("scheduledOrNoSoundHintSeenAt", scheduledOrNoSoundHintSeenAt); + editor.apply(); + } + + public static void increaseScheduledHintShowed() { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + scheduledHintSeenAt = System.currentTimeMillis(); + editor.putInt("scheduledHintShows", ++scheduledHintShows); + editor.putLong("scheduledHintSeenAt", scheduledHintSeenAt); editor.apply(); } @@ -909,6 +932,13 @@ public static void removeScheduledOrNoSoundHint() { editor.apply(); } + public static void removeScheduledHint() { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("scheduledHintShows", 3); + editor.apply(); + } + public static void increaseLockRecordAudioVideoHintShowed() { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); SharedPreferences.Editor editor = preferences.edit(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index a329c51220b..8d41a95e65e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -284,19 +284,42 @@ public MediaEntity copy() { entity.rotation = rotation; entity.width = width; entity.height = height; + entity.additionalHeight = additionalHeight; entity.text = text; - entity.entities.addAll(entities); + if (entities != null) { + entity.entities = new ArrayList<>(); + entity.entities.addAll(entities); + } entity.color = color; entity.fontSize = fontSize; + entity.textTypeface = textTypeface; + entity.textTypefaceKey = textTypefaceKey; + entity.textAlign = textAlign; entity.viewWidth = viewWidth; entity.viewHeight = viewHeight; + entity.roundRadius = roundRadius; entity.scale = scale; entity.textViewWidth = textViewWidth; entity.textViewHeight = textViewHeight; entity.textViewX = textViewX; entity.textViewY = textViewY; - entity.textAlign = textAlign; - entity.textTypeface = textTypeface; + entity.document = document; + entity.parentObject = parentObject; + entity.metadata = metadata; + entity.ptr = ptr; + entity.currentFrame = currentFrame; + entity.framesPerDraw = framesPerDraw; + entity.bitmap = bitmap; + entity.view = view; + entity.canvas = canvas; + entity.animatedFileDrawable = animatedFileDrawable; + entity.roundRadiusCanvas = roundRadiusCanvas; + entity.mediaArea = mediaArea; + entity.mediaGeo = mediaGeo; + entity.density = density; + entity.W = W; + entity.H = H; + entity.visibleReaction = visibleReaction; return entity; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioBufferConverter.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioBufferConverter.java index 0af9045f567..8b21d037b69 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioBufferConverter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioBufferConverter.java @@ -68,7 +68,9 @@ public ShortBuffer convert(@NonNull ShortBuffer inputBuffer, int inputSampleRate } private void checkChannels(int inputChannelCount, int outputChannelCount){ - // Check channel count. + if (inputChannelCount == 6 && outputChannelCount == 2) { + return; + } if (inputChannelCount != 1 && inputChannelCount != 2) { throw new UnsupportedOperationException("Input channel count (" + inputChannelCount + ") not supported."); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/VideoPlayerHolderBase.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/VideoPlayerHolderBase.java index 9bf10baca4d..e381099e9ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/VideoPlayerHolderBase.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/VideoPlayerHolderBase.java @@ -1,6 +1,7 @@ package org.telegram.messenger.video; import android.graphics.Bitmap; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.SurfaceTexture; import android.net.Uri; @@ -251,6 +252,15 @@ public void pause() { return; } paused = true; + prepareStub(); + dispatchQueue.postRunnable(() -> { + if (videoPlayer != null) { + videoPlayer.pause(); + } + }); + } + + public void prepareStub() { if (surfaceView != null && firstFrameRendered && surfaceView.getHolder().getSurface().isValid()) { stubAvailable = true; if (playerStubBitmap == null) { @@ -259,13 +269,11 @@ public void pause() { } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { AndroidUtilities.getBitmapFromSurface(surfaceView, playerStubBitmap); + if (playerStubBitmap.getPixel(0, 0) == Color.TRANSPARENT) { + stubAvailable = false; + } } } - dispatchQueue.postRunnable(() -> { - if (videoPlayer != null) { - videoPlayer.pause(); - } - }); } public void play() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/remix/DefaultAudioRemixer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/remix/DefaultAudioRemixer.java index 9f20f3329da..036d36f17a0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/remix/DefaultAudioRemixer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/remix/DefaultAudioRemixer.java @@ -9,7 +9,9 @@ public class DefaultAudioRemixer implements AudioRemixer { @Override public void remix(@NonNull ShortBuffer inputBuffer, int inputChannelCount, @NonNull ShortBuffer outputBuffer, int outputChannelCount) { AudioRemixer remixer; - if (inputChannelCount > outputChannelCount) { + if (inputChannelCount == 6 && outputChannelCount == 2) { + remixer = AudioRemixer.PASSTHROUGH; + } else if (inputChannelCount > outputChannelCount) { remixer = DOWNMIX; } else if (inputChannelCount < outputChannelCount) { remixer = AudioRemixer.UPMIX; @@ -22,7 +24,9 @@ public void remix(@NonNull ShortBuffer inputBuffer, int inputChannelCount, @NonN @Override public int getRemixedSize(int inputSize, int inputChannelCount, int outputChannelCount) { AudioRemixer remixer; - if (inputChannelCount > outputChannelCount) { + if (inputChannelCount == 6 && outputChannelCount == 2) { + remixer = AudioRemixer.PASSTHROUGH; + } else if (inputChannelCount > outputChannelCount) { remixer = DOWNMIX; } else if (inputChannelCount < outputChannelCount) { remixer = AudioRemixer.UPMIX; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/remix/DownMixAudioRemixer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/remix/DownMixAudioRemixer.java index 26062c547ed..30f07771daa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/remix/DownMixAudioRemixer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/remix/DownMixAudioRemixer.java @@ -14,31 +14,12 @@ public class DownMixAudioRemixer implements AudioRemixer { @Override public void remix(@NonNull ShortBuffer inputBuffer, int inputChannelCount, @NonNull ShortBuffer outputBuffer, int outputChannelCount) { - // Down-mix stereo to mono - // Viktor Toth's algorithm - - // See: http://www.vttoth.com/CMS/index.php/technical-notes/68 - // http://stackoverflow.com/a/25102339 final int inRemaining = inputBuffer.remaining() / 2; final int outSpace = outputBuffer.remaining(); final int samplesToBeProcessed = Math.min(inRemaining, outSpace); for (int i = 0; i < samplesToBeProcessed; ++i) { - // Convert to unsigned - final int a = inputBuffer.get() + SIGNED_SHORT_LIMIT; - final int b = inputBuffer.get() + SIGNED_SHORT_LIMIT; - int m; - // Pick the equation - if ((a < SIGNED_SHORT_LIMIT) || (b < SIGNED_SHORT_LIMIT)) { - // Viktor's first equation when both sources are "quiet" - // (i.e. less than middle of the dynamic range) - m = a * b / SIGNED_SHORT_LIMIT; - } else { - // Viktor's second equation when one or both sources are loud - m = 2 * (a + b) - (a * b) / SIGNED_SHORT_LIMIT - UNSIGNED_SHORT_MAX; - } - // Convert output back to signed short - if (m == UNSIGNED_SHORT_MAX + 1) m = UNSIGNED_SHORT_MAX; - outputBuffer.put((short) (m - SIGNED_SHORT_LIMIT)); + outputBuffer.put(mix(inputBuffer.get(), inputBuffer.get())); } } @@ -46,4 +27,28 @@ public void remix(@NonNull ShortBuffer inputBuffer, int inputChannelCount, @NonN public int getRemixedSize(int inputSize, int inputChannelCount, int outputChannelCount) { return inputSize / 2; } + + private short mix(short input1, short input2) { + // Down-mix stereo to mono + // Viktor Toth's algorithm - + // See: http://www.vttoth.com/CMS/index.php/technical-notes/68 + // http://stackoverflow.com/a/25102339 + + // Convert to unsigned + final int a = input1 + SIGNED_SHORT_LIMIT; + final int b = input2 + SIGNED_SHORT_LIMIT; + int m; + // Pick the equation + if ((a < SIGNED_SHORT_LIMIT) || (b < SIGNED_SHORT_LIMIT)) { + // Viktor's first equation when both sources are "quiet" + // (i.e. less than middle of the dynamic range) + m = a * b / SIGNED_SHORT_LIMIT; + } else { + // Viktor's second equation when one or both sources are loud + m = 2 * (a + b) - (a * b) / SIGNED_SHORT_LIMIT - UNSIGNED_SHORT_MAX; + } + // Convert output back to signed short + if (m == UNSIGNED_SHORT_MAX + 1) m = UNSIGNED_SHORT_MAX; + return (short) (m - SIGNED_SHORT_LIMIT); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/resample/DefaultAudioResampler.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/resample/DefaultAudioResampler.java index fbb8f1cad70..2014e36aca0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/resample/DefaultAudioResampler.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/resample/DefaultAudioResampler.java @@ -12,7 +12,9 @@ public class DefaultAudioResampler implements AudioResampler { @Override public void resample(@NonNull ShortBuffer inputBuffer, int inputSampleRate, @NonNull ShortBuffer outputBuffer, int outputSampleRate, int channels) { - if (inputSampleRate < outputSampleRate) { + if (inputSampleRate == 6 && outputSampleRate == 2) { + PASSTHROUGH.resample(inputBuffer, inputSampleRate, outputBuffer, outputSampleRate, channels); + } else if (inputSampleRate < outputSampleRate) { UPSAMPLE.resample(inputBuffer, inputSampleRate, outputBuffer, outputSampleRate, channels); } else if (inputSampleRate > outputSampleRate) { DOWNSAMPLE.resample(inputBuffer, inputSampleRate, outputBuffer, outputSampleRate, channels); diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index 1d5c8f83e0d..066fcebcc43 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -74,7 +74,7 @@ public class TLRPC { public static final int MESSAGE_FLAG_HAS_BOT_ID = 0x00000800; public static final int MESSAGE_FLAG_EDITED = 0x00008000; - public static final int LAYER = 163; + public static final int LAYER = 164; public static class TL_stats_megagroupStats extends TLObject { public static int constructor = 0xef7ff916; @@ -4839,6 +4839,9 @@ public static class TL_chatAdminRights extends TLObject { public boolean manage_call; public boolean other; public boolean manage_topics; + public boolean post_stories; + public boolean edit_stories; + public boolean delete_stories; public static TL_chatAdminRights TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_chatAdminRights.constructor != constructor) { @@ -4867,6 +4870,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { manage_call = (flags & 2048) != 0; other = (flags & 4096) != 0; manage_topics = (flags & 8192) != 0; + post_stories = (flags & 16384) != 0; + edit_stories = (flags & 32768) != 0; + delete_stories = (flags & 65536) != 0; } public void serializeToStream(AbstractSerializedData stream) { @@ -4883,6 +4889,9 @@ public void serializeToStream(AbstractSerializedData stream) { flags = manage_call ? (flags | 2048) : (flags &~ 2048); flags = other ? (flags | 4096) : (flags &~ 4096); flags = manage_topics ? (flags | 8192) : (flags &~ 8192); + flags = post_stories ? (flags | 16384) : (flags &~ 16384); + flags = edit_stories ? (flags | 32768) : (flags &~ 32768); + flags = delete_stories ? (flags | 65536) : (flags &~ 65536); stream.writeInt32(flags); } } @@ -12507,7 +12516,7 @@ public void serializeToStream(AbstractSerializedData stream) { } } } - + public static class WebPageAttribute extends TLObject { public int flags; @@ -12517,6 +12526,9 @@ public static WebPageAttribute TLdeserialize(AbstractSerializedData stream, int case TL_webPageAttributeTheme.constructor: result = new TL_webPageAttributeTheme(); break; + case TL_webPageAttributeStory_layer162.constructor: + result = new TL_webPageAttributeStory_layer162(); + break; case TL_webPageAttributeStory.constructor: result = new TL_webPageAttributeStory(); break; @@ -12532,15 +12544,41 @@ public static WebPageAttribute TLdeserialize(AbstractSerializedData stream, int } public static class TL_webPageAttributeStory extends WebPageAttribute { - public static final int constructor = 0x939a4671; + public final static int constructor = 0x2e94c3e7; - public long user_id; + public int flags; + public Peer peer; public int id; - public TLRPC.StoryItem storyItem; + public StoryItem storyItem; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); - user_id = stream.readInt64(exception); + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + id = stream.readInt32(exception); + if ((flags & 1) != 0) { + storyItem = StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(id); + if ((flags & 1) != 0) { + storyItem.serializeToStream(stream); + } + } + } + + public static class TL_webPageAttributeStory_layer162 extends TL_webPageAttributeStory { + public static final int constructor = 0x939a4671; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + long user_id = stream.readInt64(exception); + peer = new TL_peerUser(); + peer.user_id = user_id; id = stream.readInt32(exception); if ((flags & 1) != 0) { storyItem = StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -12555,7 +12593,7 @@ public void serializeToStream(AbstractSerializedData stream) { } stream.writeInt32(constructor); stream.writeInt32(flags); - stream.writeInt64(user_id); + stream.writeInt64(peer.user_id); stream.writeInt32(id); if ((flags & 1) != 0) { storyItem.serializeToStream(stream); @@ -13260,7 +13298,9 @@ public static abstract class ChatFull extends TLObject { public boolean antispam; public boolean participants_hidden; public boolean translations_disabled; + public boolean stories_pinned_available; public ChatReactions available_reactions; + public PeerStories stories; public long inviterId; //custom public int invitesCount; //custom @@ -13271,9 +13311,12 @@ public static ChatFull TLdeserialize(AbstractSerializedData stream, int construc case 0xc9d31138: result = new TL_chatFull(); break; - case 0xf2355507: + case 0x723027bd: result = new TL_channelFull(); break; + case 0xf2355507: + result = new TL_channelFull_layer162(); + break; case 0xd18ee226: result = new TL_chatFull_layer144(); break; @@ -15719,7 +15762,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_channelFull extends ChatFull { - public static int constructor = 0xf2355507; + public static int constructor = 0x723027bd; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -15736,6 +15779,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { antispam = (flags2 & 2) != 0; participants_hidden = (flags2 & 4) != 0; translations_disabled = (flags2 & 8) != 0; + stories_pinned_available = (flags2 & 32) != 0; id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -15857,6 +15901,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 1073741824) != 0) { available_reactions = ChatReactions.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags2 & 16) != 0) { + stories = PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -15874,6 +15921,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags2 = antispam ? (flags2 | 2) : (flags2 &~ 2); flags2 = participants_hidden ? (flags2 | 4) : (flags2 &~ 4); flags2 = translations_disabled ? (flags2 | 8) : (flags2 &~ 8); + flags2 = stories_pinned_available ? (flags2 | 32) : (flags2 &~ 32); stream.writeInt32(flags2); stream.writeInt64(id); stream.writeString(about); @@ -15977,11 +16025,14 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 1073741824) != 0) { available_reactions.serializeToStream(stream); } + if ((flags2 & 16) != 0) { + stories.serializeToStream(stream); + } } } - public static class TL_channelFull_layer144 extends ChatFull { - public static int constructor = 0xea68a619; + public static class TL_channelFull_layer162 extends TL_channelFull { + public static int constructor = 0xf2355507; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -15995,6 +16046,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { blocked = (flags & 4194304) != 0; flags2 = stream.readInt32(exception); can_delete_channel = (flags2 & 1) != 0; + antispam = (flags2 & 2) != 0; + participants_hidden = (flags2 & 4) != 0; + translations_disabled = (flags2 & 8) != 0; id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -16114,17 +16168,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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_legacy.add(stream.readString(exception)); - } + available_reactions = ChatReactions.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -16140,6 +16184,9 @@ public void serializeToStream(AbstractSerializedData stream) { flags = blocked ? (flags | 4194304) : (flags &~ 4194304); stream.writeInt32(flags); flags2 = can_delete_channel ? (flags2 | 1) : (flags2 &~ 1); + flags2 = antispam ? (flags2 | 2) : (flags2 &~ 2); + flags2 = participants_hidden ? (flags2 | 4) : (flags2 &~ 4); + flags2 = translations_disabled ? (flags2 | 8) : (flags2 &~ 8); stream.writeInt32(flags2); stream.writeInt64(id); stream.writeString(about); @@ -16241,18 +16288,13 @@ public void serializeToStream(AbstractSerializedData stream) { default_send_as.serializeToStream(stream); } if ((flags & 1073741824) != 0) { - stream.writeInt32(0x1cb5c415); - count = available_reactions_legacy.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - stream.writeString(available_reactions_legacy.get(a)); - } + available_reactions.serializeToStream(stream); } } } - public static class TL_channelFull_layer139 extends ChatFull { - public static int constructor = 0xe13c3d20; + public static class TL_channelFull_layer144 extends ChatFull { + public static int constructor = 0xea68a619; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -16264,6 +16306,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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) { @@ -16408,6 +16452,8 @@ public void serializeToStream(AbstractSerializedData stream) { 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) { @@ -16518,9 +16564,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_channelFull_layer131 extends TL_channelFull { - public static int constructor = 0x548c3f93; - + public static class TL_channelFull_layer139 extends ChatFull { + public static int constructor = 0xe13c3d20; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -16555,7 +16600,7 @@ public void readParams(AbstractSerializedData stream, boolean 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 = (TL_chatInviteExported) ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); } int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -16628,6 +16673,41 @@ public void readParams(AbstractSerializedData stream, boolean 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_legacy.add(stream.readString(exception)); + } + } } public void serializeToStream(AbstractSerializedData stream) { @@ -16723,11 +16803,36 @@ public void serializeToStream(AbstractSerializedData stream) { 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_legacy.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(available_reactions_legacy.get(a)); + } + } } } - public static class TL_channelFull_layer122 extends TL_channelFull { - public static int constructor = 0xef3a6acd; + public static class TL_channelFull_layer131 extends TL_channelFull { + public static int constructor = 0x548c3f93; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -16740,7 +16845,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { has_scheduled = (flags & 524288) != 0; can_view_stats = (flags & 1048576) != 0; blocked = (flags & 4194304) != 0; - id = stream.readInt32(exception); + id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { participants_count = stream.readInt32(exception); @@ -16762,9 +16867,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { unread_count = stream.readInt32(exception); chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); - ExportedChatInvite invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); - if (invite instanceof TL_chatInviteExported) { - exported_invite = (TL_chatInviteExported) invite; + if ((flags & 8388608) != 0) { + exported_invite = (TL_chatInviteExported) ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); } int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -16782,7 +16886,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { bot_info.add(object); } if ((flags & 16) != 0) { - migrated_from_chat_id = stream.readInt32(exception); + migrated_from_chat_id = stream.readInt64(exception); } if ((flags & 16) != 0) { migrated_from_max_id = stream.readInt32(exception); @@ -16800,7 +16904,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { folder_id = stream.readInt32(exception); } if ((flags & 16384) != 0) { - linked_chat_id = stream.readInt32(exception); + linked_chat_id = stream.readInt64(exception); } if ((flags & 32768) != 0) { location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -16818,6 +16922,25 @@ public void readParams(AbstractSerializedData stream, boolean 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); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -16831,7 +16954,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = can_view_stats ? (flags | 1048576) : (flags &~ 1048576); flags = blocked ? (flags | 4194304) : (flags &~ 4194304); stream.writeInt32(flags); - stream.writeInt32((int) id); + stream.writeInt64(id); stream.writeString(about); if ((flags & 1) != 0) { stream.writeInt32(participants_count); @@ -16853,10 +16976,8 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(unread_count); chat_photo.serializeToStream(stream); notify_settings.serializeToStream(stream); - if (exported_invite != null) { + if ((flags & 8388608) != 0) { exported_invite.serializeToStream(stream); - } else { - new TLRPC.TL_chatInviteEmpty_layer122().serializeToStream(stream); } stream.writeInt32(0x1cb5c415); int count = bot_info.size(); @@ -16865,7 +16986,7 @@ public void serializeToStream(AbstractSerializedData stream) { bot_info.get(a).serializeToStream(stream); } if ((flags & 16) != 0) { - stream.writeInt32((int) migrated_from_chat_id); + stream.writeInt64(migrated_from_chat_id); } if ((flags & 16) != 0) { stream.writeInt32(migrated_from_max_id); @@ -16883,7 +17004,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(folder_id); } if ((flags & 16384) != 0) { - stream.writeInt32((int) linked_chat_id); + stream.writeInt64(linked_chat_id); } if ((flags & 32768) != 0) { location.serializeToStream(stream); @@ -16901,11 +17022,25 @@ public void serializeToStream(AbstractSerializedData stream) { 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); + } } } - public static class TL_channelFull_layer121 extends TL_channelFull { - public static int constructor = 0xf0e6672a; + public static class TL_channelFull_layer122 extends TL_channelFull { + public static int constructor = 0xef3a6acd; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -16993,6 +17128,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { stats_dc = stream.readInt32(exception); } pts = stream.readInt32(exception); + if ((flags & 2097152) != 0) { + call = TL_inputGroupCall.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -17028,7 +17166,11 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(unread_count); chat_photo.serializeToStream(stream); notify_settings.serializeToStream(stream); - exported_invite.serializeToStream(stream); + if (exported_invite != null) { + exported_invite.serializeToStream(stream); + } else { + new TLRPC.TL_chatInviteEmpty_layer122().serializeToStream(stream); + } stream.writeInt32(0x1cb5c415); int count = bot_info.size(); stream.writeInt32(count); @@ -17069,11 +17211,14 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(stats_dc); } stream.writeInt32(pts); + if ((flags & 2097152) != 0) { + call.serializeToStream(stream); + } } } - public static class TL_channelFull_layer103 extends TL_channelFull { - public static int constructor = 0x10916653; + public static class TL_channelFull_layer121 extends TL_channelFull { + public static int constructor = 0xf0e6672a; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -17082,8 +17227,10 @@ public void readParams(AbstractSerializedData stream, boolean exception) { can_set_username = (flags & 64) != 0; can_set_stickers = (flags & 128) != 0; hidden_prehistory = (flags & 1024) != 0; - can_view_stats = (flags & 4096) != 0; can_set_location = (flags & 65536) != 0; + has_scheduled = (flags & 524288) != 0; + can_view_stats = (flags & 1048576) != 0; + blocked = (flags & 4194304) != 0; id = stream.readInt32(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -17149,6 +17296,15 @@ public void readParams(AbstractSerializedData stream, boolean 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); } @@ -17158,8 +17314,10 @@ public void serializeToStream(AbstractSerializedData stream) { 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_view_stats ? (flags | 4096) : (flags &~ 4096); 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); stream.writeInt32((int) id); stream.writeString(about); @@ -17214,12 +17372,21 @@ public void serializeToStream(AbstractSerializedData stream) { 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); } } - public static class TL_channelFull_layer101 extends TL_channelFull { - public static int constructor = 0x9882e516; + public static class TL_channelFull_layer103 extends TL_channelFull { + public static int constructor = 0x10916653; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -17229,6 +17396,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { can_set_stickers = (flags & 128) != 0; hidden_prehistory = (flags & 1024) != 0; can_view_stats = (flags & 4096) != 0; + can_set_location = (flags & 65536) != 0; id = stream.readInt32(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -17288,7 +17456,152 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 2048) != 0) { folder_id = stream.readInt32(exception); } - if ((flags & 8192) != 0) { + if ((flags & 16384) != 0) { + linked_chat_id = stream.readInt32(exception); + } + if ((flags & 32768) != 0) { + location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + pts = stream.readInt32(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_view_stats ? (flags | 4096) : (flags &~ 4096); + flags = can_set_location ? (flags | 65536) : (flags &~ 65536); + stream.writeInt32(flags); + stream.writeInt32((int) 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); + 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.writeInt32((int) 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.writeInt32((int) linked_chat_id); + } + if ((flags & 32768) != 0) { + location.serializeToStream(stream); + } + stream.writeInt32(pts); + } + } + + public static class TL_channelFull_layer101 extends TL_channelFull { + public static int constructor = 0x9882e516; + + + 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_view_stats = (flags & 4096) != 0; + id = stream.readInt32(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); + ExportedChatInvite invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + if (invite instanceof TL_chatInviteExported) { + exported_invite = (TL_chatInviteExported) invite; + } + 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.readInt32(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 & 8192) != 0) { linked_chat_id = stream.readInt32(exception); } pts = stream.readInt32(exception); @@ -27358,7 +27671,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_invoice extends TLObject { - public static int constructor = 0x3e85a91b; + public static int constructor = 0x5db95a15; public int flags; public boolean test; @@ -27374,21 +27687,114 @@ public static class TL_invoice extends TLObject { public ArrayList prices = new ArrayList<>(); public long max_tip_amount; public ArrayList suggested_tip_amounts = new ArrayList<>(); - public String recurring_terms_url; + public String terms_url; public static TL_invoice TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_invoice.constructor != constructor) { + TL_invoice result = null; + switch (constructor) { + case 0x5db95a15: + result = new TL_invoice(); + break; + case 0x3e85a91b: + result = new TL_invoice_layer163(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_invoice", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + test = (flags & 1) != 0; + name_requested = (flags & 2) != 0; + phone_requested = (flags & 4) != 0; + email_requested = (flags & 8) != 0; + shipping_address_requested = (flags & 16) != 0; + flexible = (flags & 32) != 0; + phone_to_provider = (flags & 64) != 0; + email_to_provider = (flags & 128) != 0; + recurring = (flags & 512) != 0; + currency = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_invoice", constructor)); - } else { - return null; + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_labeledPrice object = TL_labeledPrice.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + prices.add(object); + } + if ((flags & 256) != 0) { + max_tip_amount = stream.readInt64(exception); + } + if ((flags & 256) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + suggested_tip_amounts.add(stream.readInt64(exception)); + } + } + if ((flags & 1024) != 0) { + terms_url = stream.readString(exception); } - TL_invoice result = new TL_invoice(); - result.readParams(stream, exception); - return result; } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = test ? (flags | 1) : (flags &~ 1); + flags = name_requested ? (flags | 2) : (flags &~ 2); + flags = phone_requested ? (flags | 4) : (flags &~ 4); + flags = email_requested ? (flags | 8) : (flags &~ 8); + flags = shipping_address_requested ? (flags | 16) : (flags &~ 16); + flags = flexible ? (flags | 32) : (flags &~ 32); + flags = phone_to_provider ? (flags | 64) : (flags &~ 64); + flags = email_to_provider ? (flags | 128) : (flags &~ 128); + flags = recurring ? (flags | 512) : (flags &~ 512); + stream.writeInt32(flags); + stream.writeString(currency); + stream.writeInt32(0x1cb5c415); + int count = prices.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + prices.get(a).serializeToStream(stream); + } + if ((flags & 256) != 0) { + stream.writeInt64(max_tip_amount); + } + if ((flags & 256) != 0) { + stream.writeInt32(0x1cb5c415); + count = suggested_tip_amounts.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(suggested_tip_amounts.get(a)); + } + } + if ((flags & 1024) != 0) { + stream.writeString(terms_url); + } + } + } + + public static class TL_invoice_layer163 extends TL_invoice { + public static int constructor = 0x3e85a91b; + public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); test = (flags & 1) != 0; @@ -27432,8 +27838,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { suggested_tip_amounts.add(stream.readInt64(exception)); } } - if ((flags & 512) != 0) { - recurring_terms_url = stream.readString(exception); + if ((flags & 1024) != 0) { + terms_url = stream.readString(exception); } } @@ -27468,7 +27874,7 @@ public void serializeToStream(AbstractSerializedData stream) { } } if ((flags & 512) != 0) { - stream.writeString(recurring_terms_url); + stream.writeString(terms_url); } } } @@ -32914,7 +33320,7 @@ public static Update TLdeserialize(AbstractSerializedData stream, int constructo case 0xc01e857f: result = new TL_updateUserTyping(); break; - case 0xfeb5345a: + case 0xf74e932b: result = new TL_updateReadStories(); break; case 0xebe46819: @@ -33016,7 +33422,7 @@ public static Update TLdeserialize(AbstractSerializedData stream, int constructo case 0xc32d5b12: result = new TL_updateDeleteChannelMessages(); break; - case 0xe3a73d20: + case 0x7d627683: result = new TL_updateSentStoryReaction(); break; case 0xf227868c: @@ -33037,7 +33443,7 @@ public static Update TLdeserialize(AbstractSerializedData stream, int constructo case 0x30f443db: result = new TL_updateRecentEmojiStatuses(); break; - case 0x205a4133: + case 0x75b3b798: result = new TL_updateStory(); break; case 0x7063c3db: @@ -34266,7 +34672,7 @@ public static class TL_updateUserEmojiStatus extends Update { public long user_id; public EmojiStatus emoji_status; - + public void readParams(AbstractSerializedData stream, boolean exception) { user_id = stream.readInt64(exception); emoji_status = EmojiStatus.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -34473,10 +34879,10 @@ public void serializeToStream(AbstractSerializedData stream) { draft.serializeToStream(stream); } } - + public static class TL_updateNewAuthorization extends Update { public static int constructor = 0x8951abef; - + public int flags; public boolean unconfirmed; public long hash; @@ -34971,21 +35377,21 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_updateSentStoryReaction extends Update { - public static int constructor = 0xe3a73d20; + public static int constructor = 0x7d627683; - public long user_id; + public Peer peer; public int story_id; public Reaction reaction; public void readParams(AbstractSerializedData stream, boolean exception) { - user_id = stream.readInt64(exception); + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); story_id = stream.readInt32(exception); reaction = Reaction.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeInt64(user_id); + peer.serializeToStream(stream); stream.writeInt32(story_id); reaction.serializeToStream(stream); } @@ -35098,7 +35504,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); } } - + public static class TL_updateRecentEmojiStatuses extends Update { public static int constructor = 0x30f443db; @@ -35378,7 +35784,6 @@ public void readParams(AbstractSerializedData stream, boolean exception) { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeInt32(flags); stream.writeInt32(0x1cb5c415); int count = messages.size(); stream.writeInt32(count); @@ -44690,6 +45095,10 @@ public static abstract class Chat extends TLObject { public InputChannel migrated_to; public boolean join_to_send; public boolean join_request; + public boolean stories_hidden; + public boolean stories_hidden_min; + public boolean stories_unavailable; + public int stories_max_id; public ArrayList usernames = new ArrayList<>(); @@ -44712,6 +45121,9 @@ public static Chat TLdeserialize(AbstractSerializedData stream, int constructor, case 0x4df30834: result = new TL_channel_layer104(); break; + case 0x94f592db: + result = new TL_channel(); + break; case 0x450b7115: result = new TL_channel_layer77(); break; @@ -44758,7 +45170,7 @@ public static Chat TLdeserialize(AbstractSerializedData stream, int constructor, result = new TL_channel_layer67(); break; case 0x83259464: - result = new TL_channel(); + result = new TL_channel_layer161(); break; case 0x8261ac61: result = new TL_channel_layer147(); @@ -45150,13 +45562,9 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_channel extends Chat { - public static int constructor = 0x83259464; + public static int constructor = 0x94f592db; public void readParams(AbstractSerializedData stream, boolean exception) { - readParams(stream, exception, true); - } - - public void readParams(AbstractSerializedData stream, boolean exception, boolean allowStrippedThumb) { flags = stream.readInt32(exception); creator = (flags & 1) != 0; left = (flags & 4) != 0; @@ -45179,6 +45587,173 @@ public void readParams(AbstractSerializedData stream, boolean exception, boolean join_request = (flags & 536870912) != 0; forum = (flags & 1073741824) != 0; flags2 = stream.readInt32(exception); + stories_hidden = (flags2 & 2) != 0; + stories_hidden_min = (flags2 & 4) != 0; + stories_unavailable = (flags2 & 8) != 0; + id = stream.readInt64(exception); + if ((flags & 8192) != 0) { + access_hash = stream.readInt64(exception); + } + title = stream.readString(exception); + if ((flags & 64) != 0) { + username = stream.readString(exception); + } + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + if ((flags & 512) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + if ((flags & 16384) != 0) { + admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 262144) != 0) { + default_banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags2 & 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_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + usernames.add(object); + } + } + if ((flags2 & 16) != 0) { + stories_max_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = left ? (flags | 4) : (flags &~ 4); + flags = broadcast ? (flags | 32) : (flags &~ 32); + flags = verified ? (flags | 128) : (flags &~ 128); + flags = megagroup ? (flags | 256) : (flags &~ 256); + flags = restricted ? (flags | 512) : (flags &~ 512); + flags = signatures ? (flags | 2048) : (flags &~ 2048); + flags = min ? (flags | 4096) : (flags &~ 4096); + flags = scam ? (flags | 524288) : (flags &~ 524288); + flags = has_link ? (flags | 1048576) : (flags &~ 1048576); + flags = has_geo ? (flags | 2097152) : (flags &~ 2097152); + flags = slowmode_enabled ? (flags | 4194304) : (flags &~ 4194304); + flags = call_active ? (flags | 8388608) : (flags &~ 8388608); + flags = call_not_empty ? (flags | 16777216) : (flags &~ 16777216); + flags = fake ? (flags | 33554432) : (flags &~ 33554432); + flags = gigagroup ? (flags | 67108864) : (flags &~ 67108864); + flags = noforwards ? (flags | 134217728) : (flags &~ 134217728); + flags = join_to_send ? (flags | 268435456) : (flags &~ 268435456); + flags = join_request ? (flags | 536870912) : (flags &~ 536870912); + flags = forum ? (flags | 1073741824) : (flags &~ 1073741824); + stream.writeInt32(flags); + flags2 = stories_hidden ? (flags2 | 2) : (flags2 &~ 2); + flags2 = stories_hidden_min ? (flags2 | 4) : (flags2 &~ 4); + flags2 = stories_unavailable ? (flags2 | 8) : (flags2 &~ 8); + stream.writeInt32(flags2); + stream.writeInt64(id); + if ((flags & 8192) != 0) { + stream.writeInt64(access_hash); + } + stream.writeString(title); + if ((flags & 64) != 0) { + stream.writeString(username); + } + photo.serializeToStream(stream); + stream.writeInt32(date); + if ((flags & 512) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + if ((flags & 16384) != 0) { + admin_rights.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + banned_rights.serializeToStream(stream); + } + if ((flags & 262144) != 0) { + default_banned_rights.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(participants_count); + } + if ((flags2 & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = usernames.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + usernames.get(a).serializeToStream(stream); + } + } + if ((flags2 & 16) != 0) { + stream.writeInt32(stories_max_id); + } + } + } + + public static class TL_channel_layer161 extends TL_channel { + public static int constructor = 0x83259464; + + public void readParams(AbstractSerializedData stream, boolean exception) { + readParams(stream, exception, true); + } + + public void readParams(AbstractSerializedData stream, boolean exception, boolean allowStrippedThumb) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + left = (flags & 4) != 0; + broadcast = (flags & 32) != 0; + verified = (flags & 128) != 0; + megagroup = (flags & 256) != 0; + restricted = (flags & 512) != 0; + signatures = (flags & 2048) != 0; + min = (flags & 4096) != 0; + scam = (flags & 524288) != 0; + has_link = (flags & 1048576) != 0; + has_geo = (flags & 2097152) != 0; + slowmode_enabled = (flags & 4194304) != 0; + call_active = (flags & 8388608) != 0; + call_not_empty = (flags & 16777216) != 0; + fake = (flags & 33554432) != 0; + gigagroup = (flags & 67108864) != 0; + noforwards = (flags & 134217728) != 0; + join_to_send = (flags & 268435456) != 0; + join_request = (flags & 536870912) != 0; + forum = (flags & 1073741824) != 0; + flags2 = stream.readInt32(exception); + stories_hidden = (flags2 & 2) != 0; + stories_hidden_min = (flags2 & 4) != 0; id = stream.readInt64(exception); if ((flags & 8192) != 0) { access_hash = stream.readInt64(exception); @@ -45260,6 +45835,8 @@ public void serializeToStream(AbstractSerializedData stream) { flags = join_request ? (flags | 536870912) : (flags &~ 536870912); flags = forum ? (flags | 1073741824) : (flags &~ 1073741824); stream.writeInt32(flags); + flags2 = stories_hidden ? (flags2 | 2) : (flags2 &~ 2); + flags2 = stories_hidden_min ? (flags2 | 4) : (flags2 &~ 4); stream.writeInt32(flags2); stream.writeInt64(id); if ((flags & 8192) != 0) { @@ -48638,7 +49215,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static abstract class ReactionCount extends TLObject { - + public int flags; public int chosen_order; public boolean chosen; //custom @@ -48787,14 +49364,17 @@ public static abstract class UserFull extends TLObject { public ArrayList premium_gifts = new ArrayList<>(); public Photo fallback_photo; public WallPaper wallpaper; - public TL_userStories stories; + public PeerStories stories; public static UserFull TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { UserFull result = null; switch (constructor) { - case 0x4fe1cc86: + case 0xb9b12c6c: result = new TL_userFull(); break; + case 0x4fe1cc86: + result = new TL_userFull_layer162(); + break; case 0x93eadb53: result = new TL_userFull_layer159(); break; @@ -48840,7 +49420,7 @@ public static UserFull TLdeserialize(AbstractSerializedData stream, int construc } public static class TL_userFull extends UserFull { - public static int constructor = 0x4fe1cc86; + public static int constructor = 0xb9b12c6c; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -48915,7 +49495,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); } if ((flags & 33554432) != 0) { - stories = TL_userStories.TLdeserialize(stream, stream.readInt32(exception), exception); + stories = PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -48989,8 +49569,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_userFull_layer159 extends UserFull { - public static int constructor = 0x93eadb53; + public static class TL_userFull_layer162 extends UserFull { + public static int constructor = 0x4fe1cc86; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -49002,6 +49582,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { video_calls_available = (flags & 8192) != 0; voice_messages_forbidden = (flags & 1048576) != 0; translations_disabled = (flags & 8388608) != 0; + stories_pinned_available = (flags & 67108864) != 0; + blocked_my_stories_from = (flags & 134217728) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -49062,6 +49644,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 16777216) != 0) { wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 33554432) != 0) { + stories = PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -49074,6 +49659,8 @@ public void serializeToStream(AbstractSerializedData stream) { flags = video_calls_available ? (flags | 8192) : (flags &~ 8192); flags = voice_messages_forbidden ? (flags | 1048576) : (flags &~ 1048576); flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); + flags = stories_pinned_available ? (flags | 67108864) : (flags &~ 67108864); + flags = blocked_my_stories_from ? (flags | 134217728) : (flags &~ 134217728); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -49126,11 +49713,14 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 16777216) != 0) { wallpaper.serializeToStream(stream); } + if ((flags & 33554432) != 0) { + stories.serializeToStream(stream); + } } } - public static class TL_userFull_layer156 extends UserFull { - public static int constructor = 0xf8d32aed; + public static class TL_userFull_layer159 extends UserFull { + public static int constructor = 0x93eadb53; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -49199,6 +49789,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { premium_gifts.add(object); } } + if ((flags & 16777216) != 0) { + wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -49260,11 +49853,14 @@ public void serializeToStream(AbstractSerializedData stream) { premium_gifts.get(a).serializeToStream(stream); } } + if ((flags & 16777216) != 0) { + wallpaper.serializeToStream(stream); + } } } - public static class TL_userFull_layer150_rev2 extends UserFull { - public static int constructor = 0xec6d41e3; + public static class TL_userFull_layer156 extends UserFull { + public static int constructor = 0xf8d32aed; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -49275,6 +49871,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { has_scheduled = (flags & 4096) != 0; video_calls_available = (flags & 8192) != 0; voice_messages_forbidden = (flags & 1048576) != 0; + translations_disabled = (flags & 8388608) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -49286,6 +49883,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 4) != 0) { profile_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 4194304) != 0) { + fallback_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); @@ -49340,6 +49940,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = has_scheduled ? (flags | 4096) : (flags &~ 4096); flags = video_calls_available ? (flags | 8192) : (flags &~ 8192); flags = voice_messages_forbidden ? (flags | 1048576) : (flags &~ 1048576); + flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -49352,6 +49953,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 4) != 0) { profile_photo.serializeToStream(stream); } + if ((flags & 4194304) != 0) { + fallback_photo.serializeToStream(stream); + } notify_settings.serializeToStream(stream); if ((flags & 8) != 0) { bot_info.serializeToStream(stream); @@ -49389,8 +49993,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_userFull_layer150 extends UserFull { - public static int constructor = 0xc4b1fc3f; + public static class TL_userFull_layer150_rev2 extends UserFull { + public static int constructor = 0xec6d41e3; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -49406,6 +50010,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { about = stream.readString(exception); } settings = TL_peerSettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 2097152) != 0) { + personal_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + } if ((flags & 4) != 0) { profile_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); } @@ -49469,6 +50076,9 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeString(about); } settings.serializeToStream(stream); + if ((flags & 2097152) != 0) { + personal_photo.serializeToStream(stream); + } if ((flags & 4) != 0) { profile_photo.serializeToStream(stream); } @@ -49509,8 +50119,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_userFull_layer143 extends TL_userFull { - public static int constructor = 0x8c72ea81; + public static class TL_userFull_layer150 extends UserFull { + public static int constructor = 0xc4b1fc3f; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -49520,6 +50130,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { can_pin_message = (flags & 128) != 0; has_scheduled = (flags & 4096) != 0; video_calls_available = (flags & 8192) != 0; + voice_messages_forbidden = (flags & 1048576) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -49554,6 +50165,23 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 262144) != 0) { bot_broadcast_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 524288) != 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_premiumGiftOption object = TL_premiumGiftOption.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + premium_gifts.add(object); + } + } } public void serializeToStream(AbstractSerializedData stream) { @@ -49564,6 +50192,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = can_pin_message ? (flags | 128) : (flags &~ 128); flags = has_scheduled ? (flags | 4096) : (flags &~ 4096); flags = video_calls_available ? (flags | 8192) : (flags &~ 8192); + flags = voice_messages_forbidden ? (flags | 1048576) : (flags &~ 1048576); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -49599,11 +50228,19 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 262144) != 0) { bot_broadcast_admin_rights.serializeToStream(stream); } + if ((flags & 524288) != 0) { + stream.writeInt32(0x1cb5c415); + int count = premium_gifts.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + premium_gifts.get(a).serializeToStream(stream); + } + } } } - public static class TL_userFull_layer139 extends UserFull { - public static int constructor = 0xcf366521; + public static class TL_userFull_layer143 extends TL_userFull { + public static int constructor = 0x8c72ea81; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -49641,6 +50278,12 @@ public void readParams(AbstractSerializedData stream, boolean 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) { @@ -49680,12 +50323,17 @@ public void serializeToStream(AbstractSerializedData stream) { 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_layer134 extends TL_userFull { - public static int constructor = 0xd697ff05; - + public static class TL_userFull_layer139 extends UserFull { + public static int constructor = 0xcf366521; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -49695,7 +50343,89 @@ public void readParams(AbstractSerializedData stream, boolean exception) { can_pin_message = (flags & 128) != 0; has_scheduled = (flags & 4096) != 0; video_calls_available = (flags & 8192) != 0; - user = User.TLdeserialize(stream, stream.readInt32(exception), exception); + 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); + } + } + + 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); + } + } + } + + public static class TL_userFull_layer134 extends TL_userFull { + public static int constructor = 0xd697ff05; + + + 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; + user = User.TLdeserialize(stream, stream.readInt32(exception), exception); if ((flags & 2) != 0) { about = stream.readString(exception); } @@ -61399,6 +62129,7 @@ public static abstract class MessageMedia extends TLObject { public int id; public StoryItem storyItem; public boolean via_mention; + public Peer peer; public static MessageMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { MessageMedia result = null; @@ -61424,9 +62155,12 @@ public static MessageMedia TLdeserialize(AbstractSerializedData stream, int cons case 0x3ded6320: result = new TL_messageMediaEmpty(); break; - case 0xcbb20d88: + case 0x68cb6283: result = new TL_messageMediaStory(); break; + case 0xcbb20d88: + result = new TL_messageMediaStory_layer162(); + break; case 0xc79aee1d: result = new MessageMediaStoryFull(); //custom break; @@ -68831,10 +69565,10 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeBool(enabled); } } - + public static class TL_channels_clickSponsoredMessage extends TLObject { public static int constructor = 0x18afbc93; - + public InputChannel channel; public byte[] random_id; @@ -69407,6 +70141,7 @@ public static abstract class StoryItem extends TLObject { public boolean selected_contacts; public boolean noforwards; public boolean min; + public boolean out; public int id; public int date; public int expire_date; @@ -69464,6 +70199,9 @@ public static abstract class StoryViews extends TLObject { public int views_count; public int reactions_count; public ArrayList recent_viewers = new ArrayList<>(); + public boolean has_viewers; + public int forwards_count; + public ArrayList reactions = new ArrayList<>(); public static StoryViews TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { StoryViews result = null; @@ -69472,8 +70210,12 @@ public static StoryViews TLdeserialize(AbstractSerializedData stream, int constr result = new TL_storyViews_layer160(); break; case 0xc64c0b97: + result = new TL_storyViews_layer161(); + break; + case 0x8d595cd6: result = new TL_storyViews(); break; + } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in StoryViews", constructor)); @@ -69521,7 +70263,7 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_storyViews extends StoryViews { + public static class TL_storyViews_layer161 extends StoryViews { public static int constructor = 0xc64c0b97; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -69559,6 +70301,81 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_storyViews extends StoryViews { + public static int constructor = 0x8d595cd6; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + has_viewers = (flags & 2) != 0; + views_count = stream.readInt32(exception); + if ((flags & 4) != 0) { + forwards_count = stream.readInt32(exception); + } + if ((flags & 8) != 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++) { + ReactionCount object = ReactionCount.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + reactions.add(object); + } + } + if ((flags & 16) != 0) { + reactions_count = stream.readInt32(exception); + } + if ((flags & 1) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + recent_viewers.add(stream.readInt64(exception)); + } + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = has_viewers ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeInt32(views_count); + if ((flags & 4) != 0) { + stream.writeInt32(forwards_count); + } + if ((flags & 8) != 0) { + stream.writeInt32(0x1cb5c415); + int count = reactions.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + reactions.get(a).serializeToStream(stream); + } + } + if ((flags & 16) != 0) { + stream.writeInt32(reactions_count); + } + if ((flags & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = recent_viewers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(recent_viewers.get(a)); + } + } + } + } + public static class TL_storyItem extends StoryItem { public static int constructor = 0x44c457ce; @@ -69572,6 +70389,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { edited = (flags & 2048) != 0; contacts = (flags & 4096) != 0; selected_contacts = (flags & 8192) != 0; + out = (flags & 65536) != 0; id = stream.readInt32(exception); date = stream.readInt32(exception); expire_date = stream.readInt32(exception); @@ -69648,6 +70466,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = edited ? (flags | 2048) : (flags &~ 2048); flags = contacts ? (flags | 4096) : (flags &~ 4096); flags = selected_contacts ? (flags | 8192) : (flags &~ 8192); + flags = out ? (flags | 65536) : (flags &~ 65536); stream.writeInt32(flags); stream.writeInt32(id); stream.writeInt32(date); @@ -69821,10 +70640,10 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(expire_date); } } - + public static class TL_mediaAreaCoordinates extends TLObject { public static final int constructor = 0x3d1ea4e; - + public double x; public double y; public double w; @@ -69863,9 +70682,13 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeDouble(rotation); } } - + public static class MediaArea extends TLObject { public TL_mediaAreaCoordinates coordinates; + public Reaction reaction; + public int flags; + public boolean dark; + public boolean flipped; public static MediaArea TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { MediaArea result = null; @@ -69879,6 +70702,9 @@ public static MediaArea TLdeserialize(AbstractSerializedData stream, int constru case TL_inputMediaAreaVenue.constructor: result = new TL_inputMediaAreaVenue(); break; + case TL_mediaAreaSuggestedReaction.constructor: + result = new TL_mediaAreaSuggestedReaction(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in MediaArea", constructor)); @@ -69890,9 +70716,30 @@ public static MediaArea TLdeserialize(AbstractSerializedData stream, int constru } } + public static class TL_mediaAreaSuggestedReaction extends MediaArea { + public static final int constructor = 0x14455871; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + dark = (flags & 1) != 0; + flipped = (flags & 2) != 0; + coordinates = TL_mediaAreaCoordinates.TLdeserialize(stream, stream.readInt32(exception), exception); + reaction = Reaction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = dark ? (flags | 1) : (flags &~ 1); + flags = flipped ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + coordinates.serializeToStream(stream); + reaction.serializeToStream(stream); + } + } + public static class TL_mediaAreaVenue extends MediaArea { public static final int constructor = 0xbe82db9c; - + public GeoPoint geo; public String title; public String address; @@ -70081,31 +70928,83 @@ public void serializeToStream(AbstractSerializedData stream) { } } - - public static class TL_userStories extends TLObject { - public static int constructor = 0x8611a200; + public static abstract class PeerStories extends TLObject { public int flags; - public long user_id; + public Peer peer; public int max_read_id; public ArrayList stories = new ArrayList<>(); - public static TL_userStories TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_userStories.constructor != constructor) { + public static PeerStories TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PeerStories result = null; + switch (constructor) { + case 0x9a35e999: + result = new TL_peerStories(); + break; + case 0x8611a200: + result = new TL_peerStories_layer162(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PeerStories", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_peerStories extends PeerStories { + public static int constructor = 0x9a35e999; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 1) != 0) { + max_read_id = stream.readInt32(exception); + } + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_userStories", constructor)); - } else { - return null; + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + StoryItem object = StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + stories.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + peer.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeInt32(max_read_id); + } + stream.writeInt32(0x1cb5c415); + int count = stories.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stories.get(a).serializeToStream(stream); } - TL_userStories result = new TL_userStories(); - result.readParams(stream, exception); - return result; } + } + + public static class TL_peerStories_layer162 extends TL_peerStories { + public static int constructor = 0x8611a200; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); - user_id = stream.readInt64(exception); + long user_id = stream.readInt64(exception); + peer = new TL_peerUser(); + peer.user_id = user_id; if ((flags & 1) != 0) { max_read_id = stream.readInt32(exception); } @@ -70129,7 +71028,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); stream.writeInt32(flags); - stream.writeInt64(user_id); + stream.writeInt64(peer.user_id); if ((flags & 1) != 0) { stream.writeInt32(max_read_id); } @@ -70142,27 +71041,28 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_stories_userStories extends TLObject { - public static int constructor = 0x37a6ff5f; + public static class TL_stories_peerStories extends TLObject { + public static int constructor = 0xcae68768; - public TL_userStories stories; + public PeerStories stories; + public ArrayList chats = new ArrayList<>(); public ArrayList users = new ArrayList<>(); - public static TL_stories_userStories TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_stories_userStories.constructor != constructor) { + public static TL_stories_peerStories TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_stories_peerStories.constructor != constructor) { if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_stories_userStories", constructor)); + throw new RuntimeException(String.format("can't parse magic %x in TL_stories_peerStories", constructor)); } else { return null; } } - TL_stories_userStories result = new TL_stories_userStories(); + TL_stories_peerStories result = new TL_stories_peerStories(); result.readParams(stream, exception); return result; } public void readParams(AbstractSerializedData stream, boolean exception) { - stories = TL_userStories.TLdeserialize(stream, stream.readInt32(exception), exception); + stories = PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -70171,6 +71071,21 @@ public void readParams(AbstractSerializedData stream, boolean exception) { return; } int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.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) { @@ -70184,7 +71099,13 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); stories.serializeToStream(stream); stream.writeInt32(0x1cb5c415); - int count = users.size(); + int count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.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); @@ -70200,7 +71121,7 @@ public static stories_AllStories TLdeserialize(AbstractSerializedData stream, in case 0x1158fe3e: result = new TL_stories_allStoriesNotModified(); break; - case 0x519d899e: + case 0x6efc5e81: result = new TL_stories_allStories(); break; } @@ -70236,13 +71157,14 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_allStories extends stories_AllStories { - public static int constructor = 0x519d899e; + public static int constructor = 0x6efc5e81; public int flags; public boolean has_more; public int count; public String state; - public ArrayList user_stories = new ArrayList<>(); + public ArrayList peer_stories = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); public ArrayList users = new ArrayList<>(); public TL_storiesStealthMode stealth_mode; @@ -70260,11 +71182,26 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } int count = stream.readInt32(exception); for (int a = 0; a < count; a++) { - TL_userStories object = TL_userStories.TLdeserialize(stream, stream.readInt32(exception), exception); + PeerStories object = PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + peer_stories.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++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); if (object == null) { return; } - user_stories.add(object); + chats.add(object); } magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -70291,10 +71228,16 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(count); stream.writeString(state); stream.writeInt32(0x1cb5c415); - int count = user_stories.size(); + int count = peer_stories.size(); stream.writeInt32(count); for (int a = 0; a < count; a++) { - user_stories.get(a).serializeToStream(stream); + peer_stories.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); } stream.writeInt32(0x1cb5c415); count = users.size(); @@ -70307,7 +71250,9 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_canSendStory extends TLObject { - public static int constructor = 0xb100d45d; + public static int constructor = 0xc7dfdfdd; + + public InputPeer peer; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Bool.TLdeserialize(stream, constructor, exception); @@ -70315,15 +71260,17 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + peer.serializeToStream(stream); } } public static class TL_stories_sendStory extends TLObject { - public static int constructor = 0xd455fcec; + public static int constructor = 0xbcb73644; public int flags; public boolean pinned; public boolean noforwards; + public InputPeer peer; public InputMedia media; public ArrayList media_areas = new ArrayList<>(); public String caption; @@ -70341,12 +71288,13 @@ public void serializeToStream(AbstractSerializedData stream) { flags = pinned ? (flags | 4) : (flags &~ 4); flags = noforwards ? (flags | 16) : (flags &~ 16); stream.writeInt32(flags); + peer.serializeToStream(stream); media.serializeToStream(stream); if ((flags & 32) != 0) { stream.writeInt32(0x1cb5c415); int count = media_areas.size(); stream.writeInt32(count); - for (int a = 0; a < count; ++a) { + for (int a = 0; a < count; a++) { media_areas.get(a).serializeToStream(stream); } } @@ -70375,8 +71323,9 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_deleteStories extends TLObject { - public static int constructor = 0xb5d501d7; + public static int constructor = 0xae59db5f; + public InputPeer peer; public ArrayList id = new ArrayList<>(); public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -70390,6 +71339,7 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + peer.serializeToStream(stream); stream.writeInt32(0x1cb5c415); int count = id.size(); stream.writeInt32(count); @@ -70400,8 +71350,9 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_togglePinned extends TLObject { - public static int constructor = 0x51602944; + public static int constructor = 0x9a75a1ef; + public InputPeer peer; public ArrayList id = new ArrayList<>(); public boolean pinned; @@ -70416,6 +71367,7 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + peer.serializeToStream(stream); stream.writeInt32(0x1cb5c415); int count = id.size(); stream.writeInt32(count); @@ -70427,9 +71379,10 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_editStory extends TLObject { - public static int constructor = 0xa9b91ae4; + public static int constructor = 0xb583ba46; public int flags; + public InputPeer peer; public int id; public InputMedia media; public ArrayList media_areas = new ArrayList<>(); @@ -70444,6 +71397,7 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); stream.writeInt32(flags); + peer.serializeToStream(stream); stream.writeInt32(id); if ((flags & 1) != 0) { media.serializeToStream(stream); @@ -70501,10 +71455,10 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_contacts_toggleStoriesHidden extends TLObject { - public static int constructor = 0x753fb865; + public static class TL_stories_togglePeerStoriesHidden extends TLObject { + public static int constructor = 0xbd0415c4; - public InputUser id; + public InputPeer peer; public boolean hidden; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -70513,19 +71467,19 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - id.serializeToStream(stream); + peer.serializeToStream(stream); stream.writeBool(hidden); } } - + public static class TL_contacts_setBlocked extends TLObject { public static int constructor = 0x94c65c76; - + public int flags; public boolean my_stories_from; public ArrayList id = new ArrayList<>(); public int limit; - + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Bool.TLdeserialize(stream, constructor, exception); } @@ -70544,10 +71498,11 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_stories extends TLObject { - public static int constructor = 0x4fe57df1; + public static int constructor = 0x5dd8c3c8; public int count; public ArrayList stories = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); public ArrayList users = new ArrayList<>(); public static TL_stories_stories TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -70588,6 +71543,21 @@ public void readParams(AbstractSerializedData stream, boolean exception) { return; } count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.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) { @@ -70607,6 +71577,12 @@ public void serializeToStream(AbstractSerializedData stream) { stories.get(a).serializeToStream(stream); } stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); count = users.size(); stream.writeInt32(count); for (int a = 0; a < count; a++) { @@ -70615,61 +71591,62 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_stories_getUserStories extends TLObject { - public static int constructor = 0x96d528e0; + public static class TL_stories_getPeerStories extends TLObject { + public static int constructor = 0x2c4ada50; - public InputUser user_id; + public InputPeer peer; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_stories_userStories.TLdeserialize(stream, constructor, exception); + return TL_stories_peerStories.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - user_id.serializeToStream(stream); + peer.serializeToStream(stream); } } - public static class TL_stories_getPinnedStories extends TLObject { - public static int constructor = 0xb471137; + public static class TL_updateStory extends Update { + public static int constructor = 0x75b3b798; - public InputUser user_id; - public int offset_id; - public int limit; + public Peer peer; + public StoryItem story; - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_stories_stories.TLdeserialize(stream, constructor, exception); + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + story = StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - user_id.serializeToStream(stream); - stream.writeInt32(offset_id); - stream.writeInt32(limit); + peer.serializeToStream(stream); + story.serializeToStream(stream); } } - public static class TL_updateStory extends Update { - public static int constructor = 0x205a4133; + public static class TL_stories_getPinnedStories extends TLObject { + public static int constructor = 0x5821a5dc; - public long user_id; - public StoryItem story; + public InputPeer peer; + public int offset_id; + public int limit; - public void readParams(AbstractSerializedData stream, boolean exception) { - user_id = stream.readInt64(exception); - story = StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_stories_stories.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeInt64(user_id); - story.serializeToStream(stream); + peer.serializeToStream(stream); + stream.writeInt32(offset_id); + stream.writeInt32(limit); } } public static class TL_stories_getStoriesArchive extends TLObject { - public static int constructor = 0x1f5bc5d2; + public static int constructor = 0xb4352016; + public InputPeer peer; public int offset_id; public int limit; @@ -70679,25 +71656,26 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + peer.serializeToStream(stream); stream.writeInt32(offset_id); stream.writeInt32(limit); } } public static class TL_updateReadStories extends Update { - public static int constructor = 0xfeb5345a; + public static int constructor = 0xf74e932b; - public long user_id; + public Peer peer; public int max_id; public void readParams(AbstractSerializedData stream, boolean exception) { - user_id = stream.readInt64(exception); + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); max_id = stream.readInt32(exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeInt64(user_id); + peer.serializeToStream(stream); stream.writeInt32(max_id); } } @@ -70788,9 +71766,9 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_readStories extends TLObject { - public static int constructor = 0xedc5105b; + public static int constructor = 0xa556dac8; - public InputUser user_id; + public InputPeer peer; public int max_id; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -70804,17 +71782,18 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - user_id.serializeToStream(stream); + peer.serializeToStream(stream); stream.writeInt32(max_id); } } public static class TL_stories_getStoryViewsList extends TLObject { - public static int constructor = 0xf95f61a4; + public static int constructor = 0x7ed23c57; public int flags; public boolean just_contacts; public boolean reactions_first; + public InputPeer peer; public String q; public int id; public String offset; @@ -70829,6 +71808,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = just_contacts ? (flags | 1) : (flags &~ 1); flags = reactions_first ? (flags | 4) : (flags &~ 4); stream.writeInt32(flags); + peer.serializeToStream(stream); if ((flags & 2) != 0) { stream.writeString(q); } @@ -70837,12 +71817,12 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(limit); } } - + public static class TL_editCloseFriends extends TLObject { public static int constructor = 0xba6705f0; public ArrayList id = new ArrayList<>(); - + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Bool.TLdeserialize(stream, constructor, exception); } @@ -70859,9 +71839,9 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_getStoriesByID extends TLObject { - public static int constructor = 0x6a15cf46; + public static int constructor = 0x5774ca74; - public InputUser user_id; + public InputPeer peer; public ArrayList id = new ArrayList<>(); public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -70870,7 +71850,7 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - user_id.serializeToStream(stream); + peer.serializeToStream(stream); stream.writeInt32(0x1cb5c415); int count = id.size(); stream.writeInt32(count); @@ -70881,8 +71861,9 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_getStoriesViews extends TLObject { - public static int constructor = 0x9a75d6a6; + public static int constructor = 0x28e16cc8; + public InputPeer peer; public ArrayList id = new ArrayList<>(); public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -70891,6 +71872,7 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + peer.serializeToStream(stream); stream.writeInt32(0x1cb5c415); int count = id.size(); stream.writeInt32(count); @@ -70994,9 +71976,9 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_exportStoryLink extends TLObject { - public static int constructor = 0x16e443ce; + public static int constructor = 0x7b8def20; - public InputUser user_id; + public InputPeer peer; public int id; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -71005,30 +71987,55 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - user_id.serializeToStream(stream); + peer.serializeToStream(stream); stream.writeInt32(id); } } public static class TL_inputMediaStory extends InputMedia { - public static int constructor = 0x9a86b58f; + public static int constructor = 0x89fdd778; - public InputUser user_id; + public InputPeer peer; public int id; public void readParams(AbstractSerializedData stream, boolean exception) { - user_id = InputUser.TLdeserialize(stream, stream.readInt32(exception), exception); + peer = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); id = stream.readInt32(exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - user_id.serializeToStream(stream); + peer.serializeToStream(stream); stream.writeInt32(id); } } public static class TL_messageMediaStory extends MessageMedia { + public static int constructor = 0x68cb6283; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + via_mention = (flags & 2) != 0; + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + id = stream.readInt32(exception); + if ((flags & 1) != 0) { + storyItem = TLRPC.StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = via_mention ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(id); + if ((flags & 1) != 0) { + storyItem.serializeToStream(stream); + } + } + } + + public static class TL_messageMediaStory_layer162 extends MessageMedia { public static int constructor = 0xcbb20d88; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -71039,6 +72046,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 1) != 0) { storyItem = TLRPC.StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); } + peer = new TL_peerUser(); + peer.user_id = user_id; } public void serializeToStream(AbstractSerializedData stream) { @@ -71050,7 +72059,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = via_mention ? (flags | 2) : (flags &~ 2); stream.writeInt32(flags); - stream.writeInt64(user_id); + stream.writeInt64(peer.user_id); stream.writeInt32(id); if ((flags & 1) != 0) { storyItem.serializeToStream(stream); @@ -71059,9 +72068,9 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_report extends TLObject { - public static int constructor = 0xc95be06a; + public static int constructor = 0x1923fa8c; - public InputUser user_id; + public InputPeer peer; public ArrayList id = new ArrayList<>(); public ReportReason reason; public String message; @@ -71072,7 +72081,7 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - user_id.serializeToStream(stream); + peer.serializeToStream(stream); stream.writeInt32(0x1cb5c415); int count = id.size(); stream.writeInt32(count); @@ -71084,8 +72093,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_stories_getAllReadUserStories extends TLObject { - public static int constructor = 0x729c562c; + public static class TL_stories_getAllReadPeerStories extends TLObject { + public static int constructor = 0x9b5ae7f9; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -71097,10 +72106,10 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_users_getStoriesMaxIDs extends TLObject { - public static int constructor = 0xca1cb9ab; + public static class TL_stories_getPeerMaxIDs extends TLObject { + public static int constructor = 0x535983c3; - public ArrayList id = new ArrayList<>(); + public ArrayList id = new ArrayList<>(); public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { Vector vector = new Vector(); @@ -71199,11 +72208,11 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_sendReaction extends TLObject { - public static int constructor = 0x49aaa9b3; + public static int constructor = 0x7fd736b2; public int flags; public boolean add_to_recent; - public InputUser user_id; + public InputPeer peer; public int story_id; public Reaction reaction; @@ -71215,7 +72224,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = add_to_recent ? (flags | 1) : (flags &~ 1); stream.writeInt32(flags); - user_id.serializeToStream(stream); + peer.serializeToStream(stream); stream.writeInt32(story_id); reaction.serializeToStream(stream); } @@ -71270,6 +72279,314 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_stories_getChatsToSend extends TLObject { + public static int constructor = 0xa56a8b60; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_chats.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_stories_boostsStatus extends TLObject { + public static int constructor = 0x66ea1fef; + + public int flags; + public int level; + public int current_level_boosts; + public int boosts; + public int next_level_boosts; + public TL_statsPercentValue premium_audience; + + public static TL_stories_boostsStatus TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_stories_boostsStatus.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_stories_boostsStatus", constructor)); + } else { + return null; + } + } + TL_stories_boostsStatus result = new TL_stories_boostsStatus(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + level = stream.readInt32(exception); + current_level_boosts = stream.readInt32(exception); + boosts = stream.readInt32(exception); + if ((flags & 1) != 0) { + next_level_boosts = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + premium_audience = TL_statsPercentValue.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(level); + stream.writeInt32(current_level_boosts); + stream.writeInt32(boosts); + if ((flags & 1) != 0) { + stream.writeInt32(next_level_boosts); + } + if ((flags & 2) != 0) { + premium_audience.serializeToStream(stream); + } + } + } + + public static abstract class stories_CanApplyBoostResult extends TLObject { + + public static stories_CanApplyBoostResult TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + stories_CanApplyBoostResult result = null; + switch (constructor) { + case 0x712c4655: + result = new TL_stories_canApplyBoostReplace(); + break; + case 0xc3173587: + result = new TL_stories_canApplyBoostOk(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in stories_CanApplyBoostResult", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_stories_canApplyBoostReplace extends stories_CanApplyBoostResult { + public static int constructor = 0x712c4655; + + public Peer current_boost; + public ArrayList chats = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + current_boost = Peer.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++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + current_boost.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + } + } + + public static class TL_stories_canApplyBoostOk extends stories_CanApplyBoostResult { + public static int constructor = 0xc3173587; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_stories_getBoostsStatus extends TLObject { + public static int constructor = 0x4c449472; + + public InputPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_stories_boostsStatus.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_stories_canApplyBoost extends TLObject { + public static int constructor = 0xdb05c1bd; + + public InputPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return stories_CanApplyBoostResult.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_stories_applyBoost extends TLObject { + public static int constructor = 0xf29d7c2b; + + public InputPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_booster extends TLObject { + public static int constructor = 0xe9e6380; + + public long user_id; + public int expires; + + public static TL_booster TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_booster.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_booster", constructor)); + } else { + return null; + } + } + TL_booster result = new TL_booster(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt64(exception); + expires = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(user_id); + stream.writeInt32(expires); + } + } + + public static class TL_stories_boostersList extends TLObject { + public static int constructor = 0xf3dd3d1d; + + public int flags; + public int count; + public ArrayList boosters = new ArrayList<>(); + public String next_offset; + public ArrayList users = new ArrayList<>(); + + public static TL_stories_boostersList TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_stories_boostersList.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_stories_boostersList", constructor)); + } else { + return null; + } + } + TL_stories_boostersList result = new TL_stories_boostersList(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_booster object = TL_booster.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + boosters.add(object); + } + if ((flags & 1) != 0) { + next_offset = stream.readString(exception); + } + 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.writeInt32(flags); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = boosters.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + boosters.get(a).serializeToStream(stream); + } + if ((flags & 1) != 0) { + stream.writeString(next_offset); + } + 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_stories_getBoostersList extends TLObject { + public static int constructor = 0x337ef980; + + public InputPeer peer; + public String offset; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_stories_boostersList.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeString(offset); + stream.writeInt32(limit); + } + } + //functions public static class Vector extends TLObject { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index ab2774aa663..f3455275cae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -69,6 +69,7 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F public boolean highlightActionButtons = false; private boolean attached; + private boolean isSheet; @Override public void setHighlightActionButtons(boolean highlightActionButtons) { @@ -440,6 +441,16 @@ public void setFragmentStack(List stack) { } } + @Override + public void setIsSheet(boolean isSheet) { + this.isSheet = isSheet; + } + + @Override + public boolean isSheet() { + return isSheet; + } + @Override public void onConfigurationChanged(android.content.res.Configuration newConfig) { super.onConfigurationChanged(newConfig); @@ -1213,7 +1224,7 @@ public boolean presentFragment(NavigationParams params) { return false; } if (BuildVars.LOGS_ENABLED) { - FileLog.d("present fragment " + fragment.getClass().getSimpleName()); + FileLog.d("present fragment " + fragment.getClass().getSimpleName() + " args=" + fragment.getArguments()); } StoryViewer.closeGlobalInstances(); if (inPreviewMode && transitionAnimationPreviewMode) { 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 cde9699d6f4..25c1b8d2715 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -393,6 +393,7 @@ public void onResume() { actionBar.onResume(); } if (storyViewer != null) { + storyViewer.onResume(); storyViewer.updatePlayingMode(); } if (overlayStoryViewer != null) { @@ -814,11 +815,13 @@ public INavigationLayout[] showAsSheet(BaseFragment fragment, BottomSheetParams } BottomSheet[] bottomSheet = new BottomSheet[1]; INavigationLayout[] actionBarLayout = new INavigationLayout[]{INavigationLayout.newLayout(getParentActivity(), () -> bottomSheet[0])}; + LaunchActivity.instance.sheetFragmentsStack.add(actionBarLayout[0]); bottomSheet[0] = new BottomSheet(getParentActivity(), true, fragment.getResourceProvider()) { { drawNavigationBar = true; actionBarLayout[0].setFragmentStack(new ArrayList<>()); actionBarLayout[0].addFragmentToStack(fragment); + actionBarLayout[0].setIsSheet(true); actionBarLayout[0].showLastFragment(); actionBarLayout[0].getView().setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, 0); containerView = actionBarLayout[0].getView(); @@ -836,6 +839,7 @@ public INavigationLayout[] showAsSheet(BaseFragment fragment, BottomSheetParams protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); fixNavigationBar(Theme.getColor(Theme.key_dialogBackgroundGray, fragment.getResourceProvider())); + AndroidUtilities.setLightStatusBar(getWindow(), fragment.isLightStatusBar()); } @Override @@ -860,6 +864,7 @@ public void dismiss() { } } super.dismiss(); + LaunchActivity.instance.sheetFragmentsStack.remove(actionBarLayout[0]); actionBarLayout[0] = null; } @@ -1052,6 +1057,9 @@ public interface PreviewDelegate { public StoryViewer getOrCreateStoryViewer() { if (storyViewer == null) { storyViewer = new StoryViewer(this); + if (parentLayout.isSheet()) { + storyViewer.fromBottomSheet = true; + } } return storyViewer; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java index efc254aba3e..52165dfd9a8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java @@ -277,6 +277,10 @@ default BottomSheet getBottomSheet() { return null; } + void setIsSheet(boolean isSheet); + + boolean isSheet(); + interface INavigationLayoutDelegate { default boolean needPresentFragment(INavigationLayout layout, NavigationParams params) { return needPresentFragment(params.fragment, params.removeLast, params.noAnimation, layout); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java index 8a40aa73af1..6b42be2247d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java @@ -68,7 +68,7 @@ public class ContactsAdapter extends RecyclerListView.SectionsAdapter { private boolean hasGps; private boolean isEmpty; public boolean hasStories; - public ArrayList userStories = new ArrayList<>(); + public ArrayList userStories = new ArrayList<>(); DialogStoriesCell dialogStoriesCell; BaseFragment fragment; @@ -84,7 +84,7 @@ public ContactsAdapter(Context context, BaseFragment fragment, int onlyUsersType this.fragment = fragment; } - public void setStories(ArrayList stories, boolean animated) { + public void setStories(ArrayList stories, boolean animated) { // boolean hasStories = !stories.isEmpty(); // userStories.clear(); // userStories.addAll(stories); @@ -194,7 +194,7 @@ public Object getItem(int section, int position) { if (position == userStories.size()) { return "Header"; } else { - return userStories.get(position).user_id; + return DialogObject.getPeerDialogId(userStories.get(position).peer); } } else if (hasStories && section > 1) { section--; @@ -517,7 +517,7 @@ public void onBindViewHolder(int section, int position, RecyclerView.ViewHolder userCell.setAvatarPadding(6); userCell.storyParams.drawSegments = true; StoriesController storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(userStories.get(position).user_id); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(DialogObject.getPeerDialogId(userStories.get(position).peer)); if (storiesController.hasUnreadStories(user.id)) { int newStories = storiesController.getUnreadStoriesCount(user.id); userCell.setData(user, ContactsController.formatName(user), LocaleController.formatPluralString("NewStories", newStories, newStories).toLowerCase(), 0); @@ -703,7 +703,7 @@ public void onStoryLongPressed(View view, long dialogId) { public void removeStory(long dialogId) { for (int i = 0; i < userStories.size(); i++) { - if (userStories.get(i).user_id == dialogId) { + if (DialogObject.getPeerDialogId(userStories.get(i).peer) == dialogId) { userStories.remove(i); if (userStories.isEmpty()) { 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 fe12b540f66..52d03e08914 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -1100,11 +1100,12 @@ public void openHiddenStories() { if (storiesController.getHiddenList().isEmpty()) { return; } - boolean unreadOnly = storiesController.getUnreadState(storiesController.getHiddenList().get(0).user_id) != StoriesController.STATE_READ; + boolean unreadOnly = storiesController.getUnreadState(DialogObject.getPeerDialogId(storiesController.getHiddenList().get(0).peer)) != StoriesController.STATE_READ; ArrayList peerIds = new ArrayList<>(); for (int i = 0; i < storiesController.getHiddenList().size(); i++) { - if (!unreadOnly || storiesController.getUnreadState(storiesController.getHiddenList().get(i).user_id) != StoriesController.STATE_READ) { - peerIds.add(storiesController.getHiddenList().get(i).user_id); + long dialogId = DialogObject.getPeerDialogId(storiesController.getHiddenList().get(i).peer); + if (!unreadOnly || storiesController.getUnreadState(dialogId) != StoriesController.STATE_READ) { + peerIds.add(dialogId); } } @@ -1323,6 +1324,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { height -= AndroidUtilities.statusBarHeight; if (parentFragment.hasStories && !collapsedView && !isTransitionSupport) { height -= ActionBar.getCurrentActionBarHeight(); + if (getParent() instanceof DialogsActivity.DialogsRecyclerView) { + DialogsActivity.DialogsRecyclerView dialogsRecyclerView = (DialogsActivity.DialogsRecyclerView) getParent(); + height -= dialogsRecyclerView.additionalPadding; + } } else if (collapsedView) { height -= paddingTop; } @@ -1333,6 +1338,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { height -= AndroidUtilities.statusBarHeight; if (parentFragment.hasStories && !collapsedView && !isTransitionSupport) { height -= ActionBar.getCurrentActionBarHeight(); + if (getParent() instanceof DialogsActivity.DialogsRecyclerView) { + DialogsActivity.DialogsRecyclerView dialogsRecyclerView = (DialogsActivity.DialogsRecyclerView) getParent(); + height -= dialogsRecyclerView.additionalPadding; + } } else if (collapsedView) { height -= paddingTop; } 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 06c3d0ab467..319f5576c04 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java @@ -319,7 +319,6 @@ private void resetItems() { } showDivider = true; } - boolean needDivider = false; if (MessagesController.getInstance(UserConfig.selectedAccount).storiesEnabled()) { items.add(new Item(16, LocaleController.getString("ProfileMyStories", R.string.ProfileMyStories), R.drawable.msg_menu_stories)); showDivider = true; 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 fd20b2d43c6..a332b75f6be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -420,6 +420,7 @@ public void setMessageObject(MessageObject messageObject, boolean force) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); previousWidth = 0; imageReceiver.setAutoRepeatCount(0); + imageReceiver.clearDecorators(); if (messageObject.isStoryMention()) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.media.user_id); avatarDrawable.setInfo(user); 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 e45c2566525..5d8d66473ed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -4317,6 +4317,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe photoImage.setCrossfadeDuration(ImageReceiver.DEFAULT_CROSSFADE_DURATION); photoImage.setCrossfadeByScale(0); photoImage.setGradientBitmap(null); + photoImage.clearDecorators(); lastTranslated = messageObject.translated; lastSendState = messageObject.messageOwner.send_state; lastDeleteDate = messageObject.messageOwner.destroyTime; @@ -4688,7 +4689,10 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe TLRPC.StoryItem storyItem = null; TLRPC.ThemeSettings androidThemeSettings = null; if (!drawInstantView) { - if ("telegram_livestream".equals(webpageType)) { + if ("telegram_channel_boost".equals(webpageType)) { + drawInstantView = true; + drawInstantViewType = 18; + } else if ("telegram_livestream".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 11; } else if ("telegram_voicechat".equals(webpageType)) { @@ -4751,7 +4755,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe storyItem = attribute.storyItem; if (storyItem != null) { storyItem.messageId = messageObject.getId(); - storyItem.dialogId = attribute.user_id; + storyItem.dialogId = DialogObject.getPeerDialogId(attribute.peer); if (storyItem instanceof TLRPC.TL_storyItemDeleted) { drawInstantView = false; hasLinkPreview = false; @@ -4977,8 +4981,8 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe "article".equals(type) || "telegram_bot".equals(type) || "telegram_user".equals(type) || "telegram_channel".equals(type) || "telegram_megagroup".equals(type) || "telegram_voicechat".equals(type) || - "telegram_livestream".equals(type); - smallImage = !slideshow && (!drawInstantView || drawInstantViewType == 1 || drawInstantViewType == 2 || drawInstantViewType == 9 || drawInstantViewType == 11 || drawInstantViewType == 13) && document == null && isSmallImageType; + "telegram_livestream".equals(type) || "telegram_channel_boost".equals(type); + smallImage = !slideshow && (!drawInstantView || drawInstantViewType == 1 || drawInstantViewType == 2 || drawInstantViewType == 9 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 18) && document == null && isSmallImageType; isSmallImage = smallImage && type != null && currentMessageObject.photoThumbs != null; } else if (hasInvoicePreview) { TLRPC.TL_messageMediaInvoice invoice = (TLRPC.TL_messageMediaInvoice) MessageObject.getMedia(messageObject.messageOwner); @@ -5011,7 +5015,9 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe isSmallImage = false; smallImage = false; } - if (drawInstantViewType == 11) { + if (drawInstantViewType == 18) { + site_name = LocaleController.getString("BoostChannel", R.string.BoostChannel); + } else if (drawInstantViewType == 11) { site_name = LocaleController.getString("VoipChannelVoiceChat", R.string.VoipChannelVoiceChat); } else if (drawInstantViewType == 9) { site_name = LocaleController.getString("VoipGroupVoiceChat", R.string.VoipGroupVoiceChat); @@ -9060,6 +9066,8 @@ private void createInstantViewButton() { str = LocaleController.getString("OpenLink").toUpperCase(); } else if (drawInstantViewType == 17) { str = LocaleController.getString("ViewStory").toUpperCase(); + } else if (drawInstantViewType == 18) { + str = LocaleController.getString("BoostLinkButton", R.string.BoostLinkButton); } else { str = LocaleController.getString("InstantView", R.string.InstantView); } @@ -10610,7 +10618,7 @@ public void drawLinkPreview(Canvas canvas, float alpha) { linkPreviewY += currentMessageObject.textHeight + AndroidUtilities.dp(4); } - if (drawPhotoImage && drawInstantView && drawInstantViewType != 9 && drawInstantViewType != 2 && drawInstantViewType != 13 && drawInstantViewType != 11 && drawInstantViewType != 1 || drawInstantViewType == 6 && imageBackgroundColor != 0) { + if (drawPhotoImage && drawInstantView && drawInstantViewType != 9 && drawInstantViewType != 2 && drawInstantViewType != 13 && drawInstantViewType != 11 && drawInstantViewType != 1 && drawInstantViewType != 18 || drawInstantViewType == 6 && imageBackgroundColor != 0) { if (linkPreviewY != startY) { linkPreviewY += AndroidUtilities.dp(2); } @@ -10791,7 +10799,7 @@ public void drawLinkPreview(Canvas canvas, float alpha) { linkPreviewY += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); } - if (drawPhotoImage && (!drawInstantView || drawInstantViewType == 9 || drawInstantViewType == 2 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 1)) { + if (drawPhotoImage && (!drawInstantView || drawInstantViewType == 9 || drawInstantViewType == 2 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 1 || drawInstantViewType == 18)) { if (linkPreviewY != startY) { linkPreviewY += AndroidUtilities.dp(2); } @@ -12897,7 +12905,17 @@ private void setMessageObjectInternal(MessageObject messageObject) { CharSequence lastLine; if (messageObject.type == MessageObject.TYPE_STORY) { currentForwardNameString = forwardedString = LocaleController.getString("ForwardedStory", R.string.ForwardedStory); - lastLine = AndroidUtilities.replaceTags(LocaleController.formatString("ForwardedStoryFrom", R.string.ForwardedStoryFrom, getNameFromDialogId(messageObject.messageOwner.media.user_id))); + long storyDialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.media.peer); + if (storyDialogId > 0) { + currentForwardUser = MessagesController.getInstance(currentAccount).getUser(storyDialogId); + } else { + currentForwardChannel = MessagesController.getInstance(currentAccount).getChat(-storyDialogId); + } + String name = getNameFromDialogId(storyDialogId); + if (storyDialogId < 0 && currentForwardChannel == null) { + name = LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate); + } + lastLine = AndroidUtilities.replaceTags(LocaleController.formatString("ForwardedStoryFrom", R.string.ForwardedStoryFrom, name)); forwardedNameWidth = getMaxNameWidth(); } else { if (currentForwardChannel != null) { @@ -15399,6 +15417,10 @@ public void setCheckBoxVisible(boolean visible, boolean animated) { invalidate(); } + public boolean isCheckBoxVisible() { + return checkBoxVisible || checkBoxAnimationInProgress; + } + public void setChecked(boolean checked, boolean allChecked, boolean animated) { if (checkBox != null) { checkBox.setChecked(allChecked, animated); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java index 1a746316bca..e6515b0a3ee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java @@ -143,7 +143,7 @@ public void setBot(TLRPC.TL_attachMenuBot bot) { } else { textView.setText(bot.short_name); } - TLRPC.TL_attachMenuBotIcon botIcon = MediaDataController.getSideMenuBotIcon(bot); + TLRPC.TL_attachMenuBotIcon botIcon = MediaDataController.getSideAttachMenuBotIcon(bot); if (botIcon != null) { imageView.setImage(ImageLocation.getForDocument(botIcon.icon), "24_24", (Drawable) null, bot); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java index 8ca76b8cf87..dc11ff06af9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java @@ -53,6 +53,7 @@ import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.Components.spoilers.SpoilerEffect2; import org.telegram.ui.PhotoViewer; +import org.telegram.ui.Stories.StoryWidgetsImageDecorator; import org.telegram.ui.Stories.recorder.DominantColors; public class SharedPhotoVideoCell2 extends FrameLayout { @@ -192,6 +193,7 @@ public void setMessageObject(MessageObject messageObject, int parentColumnsCount videoText = null; videoInfoLayot = null; showVideoLayout = false; + imageReceiver.clearDecorators(); if (!TextUtils.isEmpty(restrictionReason)) { showImageStub = true; } else if (messageObject.storyItem != null && messageObject.storyItem.media instanceof TLRPC.TL_messageMediaUnsupported) { @@ -270,6 +272,9 @@ public void setMessageObject(MessageObject messageObject, int parentColumnsCount if (imageReceiver.getBitmap() != null && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed) { blurImageReceiver.setImageBitmap(Utilities.stackBlurBitmapMax(imageReceiver.getBitmap())); } + if (messageObject != null && messageObject.storyItem != null) { + imageReceiver.addDecorator(new StoryWidgetsImageDecorator(messageObject.storyItem)); + } invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UnconfirmedAuthHintCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UnconfirmedAuthHintCell.java index 58325f4af35..26e3da62e8e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UnconfirmedAuthHintCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UnconfirmedAuthHintCell.java @@ -66,6 +66,8 @@ public class UnconfirmedAuthHintCell extends FrameLayout { public UnconfirmedAuthHintCell(Context context) { super(context); + setClickable(true); + linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.VERTICAL); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelBoostLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelBoostLayout.java new file mode 100644 index 00000000000..d5753612da6 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelBoostLayout.java @@ -0,0 +1,383 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.FixedHeightEmptyCell; +import org.telegram.ui.Cells.ManageChatTextCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Charts.view_data.ChartHeaderView; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkActionView; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.Premium.LimitPreviewView; +import org.telegram.ui.Components.RLottieImageView; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Stories.ChannelBoostUtilities; + +import java.util.ArrayList; +import java.util.Locale; +import java.util.Objects; + +public class ChannelBoostLayout extends FrameLayout { + + private final static int OVERVIEW_TYPE = 0; + private final static int HEADER_VIEW_TYPE = 1; + private final static int DIVIDER_VIEW_TYPE = 2; + private final static int LINK_VIEW_TYPE = 3; + private final static int BOOST_VIEW = 4; + private final static int USER_VIEW_TYPE = 5; + private final static int DIVIDER_TEXT_VIEW_TYPE = 6; + private final static int EMPTY_VIEW_8DP = 7; + private final static int NO_USERS_HINT = 8; + private final static int SHOW_MORE_VIEW_TYPE = 9; + + private final long dialogId; + int currentAccount = UserConfig.selectedAccount; + BaseFragment fragment; + + TLRPC.TL_stories_boostsStatus boostsStatus; + + private final Theme.ResourcesProvider resourcesProvider; + + ArrayList boosters = new ArrayList<>(); + boolean hasNext; + int nextRemaining; + ArrayList items = new ArrayList<>(); + + AdapterWithDiffUtils adapter = new AdapterWithDiffUtils() { + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return items.get(holder.getAdapterPosition()).selectable; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case BOOST_VIEW: + LimitPreviewView limitPreviewView = new LimitPreviewView(getContext(), R.drawable.filled_limit_boost, 10, 0, resourcesProvider); + limitPreviewView.isStatistic = true; + view = limitPreviewView; + Drawable shadowDrawable = Theme.getThemedDrawable(getContext(), R.drawable.greydivider, Theme.getColor(Theme.key_windowBackgroundGrayShadow, resourcesProvider)); + Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)); + CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); + combinedDrawable.setFullsize(true); + + view.setPadding(0, dp(20), 0, AndroidUtilities.dp(20)); + view.setBackground(combinedDrawable); + limitPreviewView.setBoosts(boostsStatus, false); + break; + case DIVIDER_TEXT_VIEW_TYPE: + view = new TextInfoPrivacyCell(parent.getContext(), 12, resourcesProvider); + shadowDrawable = Theme.getThemedDrawable(getContext(), R.drawable.greydivider, Theme.getColor(Theme.key_windowBackgroundGrayShadow, resourcesProvider)); + background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)); + combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); + combinedDrawable.setFullsize(true); + view.setBackground(combinedDrawable); + break; + case DIVIDER_VIEW_TYPE: + view = new ShadowSectionCell(parent.getContext(), 12, Theme.getColor(Theme.key_windowBackgroundGray)); + break; + case OVERVIEW_TYPE: + view = new StatisticActivity.OverviewCell(getContext()); + break; + case HEADER_VIEW_TYPE: + view = new ChartHeaderView(getContext()); + view.setPadding(view.getPaddingLeft(), AndroidUtilities.dp(16), view.getRight(), AndroidUtilities.dp(16)); + break; + case LINK_VIEW_TYPE: + LinkActionView linkActionView = new LinkActionView(getContext(), fragment, null, 0, false, false); + view = linkActionView; + linkActionView.hideOptions(); + linkActionView.setLink(ChannelBoostUtilities.createLink(currentAccount, dialogId)); + view.setPadding(AndroidUtilities.dp(11), 0, AndroidUtilities.dp(11), AndroidUtilities.dp(24)); + break; + case USER_VIEW_TYPE: + view = new UserCell(getContext(), 0, 0, false); + break; + case EMPTY_VIEW_8DP: + view = new FixedHeightEmptyCell(getContext(), 8); + break; + case NO_USERS_HINT: + FrameLayout frameLayout = new FrameLayout(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); + } + }; + TextView textView = new TextView(getContext()); + textView.setText(LocaleController.getString("NoBoostersHint", R.string.NoBoostersHint)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + textView.setGravity(Gravity.CENTER); + frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 7, 0, 0)); + view = frameLayout; + break; + case SHOW_MORE_VIEW_TYPE: + ManageChatTextCell actionCell = new ManageChatTextCell(getContext()); + actionCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); + // actionCell.setText(LocaleController.getString("ShowMore", R.string.ShowMore), null, R.drawable.arrow_more, false); + view = actionCell; + break; + default: + throw new UnsupportedOperationException(); + } + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (holder.getItemViewType() == BOOST_VIEW) { + + } else if (holder.getItemViewType() == HEADER_VIEW_TYPE) { + ChartHeaderView headerCell = (ChartHeaderView) holder.itemView; + headerCell.setTitle(items.get(position).title); + headerCell.showDate(false); + } else if (holder.getItemViewType() == OVERVIEW_TYPE) { + StatisticActivity.OverviewCell overviewCell = (StatisticActivity.OverviewCell) holder.itemView; + + overviewCell.setData(0, Integer.toString(boostsStatus.level), null, LocaleController.getString("BoostsLevel2", R.string.BoostsLevel2)); + if (boostsStatus.premium_audience != null || boostsStatus.premium_audience.total == 0) { + overviewCell.setData(1, "~" + (int) boostsStatus.premium_audience.part, String.format(Locale.US, "%.1f", (float) boostsStatus.premium_audience.part / (float) boostsStatus.premium_audience.total) + "%", LocaleController.getString("PremiumSubscribers", R.string.PremiumSubscribers)); + } else { + overviewCell.setData(1, "~0", "0%", LocaleController.getString("PremiumSubscribers", R.string.PremiumSubscribers)); + } + overviewCell.setData(2, String.valueOf(boostsStatus.boosts), null, LocaleController.getString("BoostsExisting", R.string.BoostsExisting)); + overviewCell.setData(3, String.valueOf(boostsStatus.next_level_boosts - boostsStatus.boosts), null, LocaleController.getString("BoostsToLevel", R.string.BoostsToLevel)); + } else if (holder.getItemViewType() == USER_VIEW_TYPE) { + TLRPC.TL_booster booster = items.get(position).booster; + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(booster.user_id); + UserCell userCell = (UserCell) holder.itemView; + String str = LocaleController.formatString("BoostExpireOn", R.string.BoostExpireOn, LocaleController.formatDate(booster.expires)); + userCell.setData(user, ContactsController.formatName(user), str, 0); + } else if (holder.getItemViewType() == DIVIDER_TEXT_VIEW_TYPE) { + TextInfoPrivacyCell privacyCell = (TextInfoPrivacyCell) holder.itemView; + privacyCell.setText(items.get(position).title); + } else if (holder.getItemViewType() == SHOW_MORE_VIEW_TYPE) { + ManageChatTextCell actionCell = (ManageChatTextCell) holder.itemView; + actionCell.setText(LocaleController.formatPluralString("ShowVotes", nextRemaining), null, R.drawable.arrow_more, false); + } + } + + @Override + public int getItemCount() { + return items.size(); + } + + @Override + public int getItemViewType(int position) { + return items.get(position).viewType; + } + }; + + RecyclerListView listView; + boolean usersLoading; + private LinearLayout progressLayout; + + public ChannelBoostLayout(BaseFragment fragment, long dialogId, Theme.ResourcesProvider resourcesProvider) { + super(fragment.getContext()); + this.fragment = fragment; + Context context = fragment.getContext(); + this.resourcesProvider = resourcesProvider; + this.dialogId = dialogId; + listView = new RecyclerListView(context); + listView.setLayoutManager(new LinearLayoutManager(context)); + DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator(); + defaultItemAnimator.setSupportsChangeAnimations(false); + defaultItemAnimator.setDelayAnimations(false); + listView.setItemAnimator(defaultItemAnimator); + listView.setOnItemClickListener((view, position) -> { + if (view instanceof UserCell) { + UserCell cell = (UserCell) view; + fragment.presentFragment(ProfileActivity.of(cell.getDialogId())); + } + if (items.get(position).viewType == SHOW_MORE_VIEW_TYPE) { + loadUsers(); + } + }); + addView(listView); + + loadStatistic(); + listView.setAdapter(adapter); + updateRows(false); + createEmptyView(getContext()); + progressLayout.setAlpha(0); + progressLayout.animate().alpha(1f).setDuration(200).setStartDelay(500).start(); + } + + private void updateRows(boolean animated) { + ArrayList oldItems = new ArrayList<>(items); + items.clear(); + if (boostsStatus != null) { + items.add(new ItemInternal(BOOST_VIEW, false)); + items.add(new ItemInternal(HEADER_VIEW_TYPE, LocaleController.getString("StatisticOverview", R.string.StatisticOverview))); + items.add(new ItemInternal(OVERVIEW_TYPE, true)); + items.add(new ItemInternal(DIVIDER_VIEW_TYPE, false)); + + + items.add(new ItemInternal(HEADER_VIEW_TYPE, LocaleController.getString("Boosters", R.string.Boosters))); + if (boosters.isEmpty()) { + items.add(new ItemInternal(NO_USERS_HINT, false)); + items.add(new ItemInternal(DIVIDER_VIEW_TYPE, false)); + } else { + for (int i = 0; i < boosters.size(); i++) { + items.add(new ItemInternal(USER_VIEW_TYPE, boosters.get(i))); + } + if (hasNext) { + items.add(new ItemInternal(SHOW_MORE_VIEW_TYPE, false)); + } else { + items.add(new ItemInternal(EMPTY_VIEW_8DP, false)); + } + items.add(new ItemInternal(DIVIDER_TEXT_VIEW_TYPE, LocaleController.getString("BoostersInfoDescription", R.string.BoostersInfoDescription))); + } + items.add(new ItemInternal(HEADER_VIEW_TYPE, LocaleController.getString("LinkForBoosting", R.string.LinkForBoosting))); + items.add(new ItemInternal(LINK_VIEW_TYPE, false)); + } + if (animated) { + adapter.setItems(oldItems, items); + } else { + adapter.notifyDataSetChanged(); + } + } + + private void loadStatistic() { + MessagesController.getInstance(currentAccount).getBoostsController().getBoostsStats(dialogId, tl_stories_boostsStatus -> AndroidUtilities.runOnUIThread(() -> { + boostsStatus = tl_stories_boostsStatus; + progressLayout.animate().cancel(); + progressLayout.animate().alpha(0).setDuration(100).setStartDelay(0).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressLayout.setVisibility(View.GONE); + } + }); + updateRows(true); + loadUsers(); + })); + } + + + private void loadUsers() { + if (usersLoading) { + return; + } + usersLoading = true; + TLRPC.TL_stories_getBoostersList listReq = new TLRPC.TL_stories_getBoostersList(); + listReq.limit = 25; + listReq.offset = ""; + listReq.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + ConnectionsManager.getInstance(currentAccount).sendRequest(listReq, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + usersLoading = false; + if (response != null) { + TLRPC.TL_stories_boostersList list = (TLRPC.TL_stories_boostersList) response; + boosters.addAll(list.boosters); + hasNext = !TextUtils.isEmpty(list.next_offset) && boosters.size() < list.count; + nextRemaining = list.count - boosters.size(); + updateRows(true); + } + }), ConnectionsManager.RequestFlagFailOnServerErrors); + } + + private class ItemInternal extends AdapterWithDiffUtils.Item { + + String title; + TLRPC.TL_booster booster; + + public ItemInternal(int viewType, String title) { + super(viewType, false); + this.title = title; + } + + public ItemInternal(int viewType, TLRPC.TL_booster booster) { + super(viewType, false); + this.booster = booster; + } + + public ItemInternal(int viewType, boolean selectable) { + super(viewType, selectable); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ItemInternal that = (ItemInternal) o; + if (booster != null && that.booster != null) { + return booster.user_id == that.booster.user_id; + } else { + return true; + } + } + + @Override + public int hashCode() { + return Objects.hash(title, booster); + } + + } + + public void createEmptyView(Context context) { + progressLayout = new LinearLayout(context); + progressLayout.setOrientation(LinearLayout.VERTICAL); + + RLottieImageView imageView = new RLottieImageView(context); + imageView.setAutoRepeat(true); + imageView.setAnimation(R.raw.statistic_preload, 120, 120); + imageView.playAnimation(); + + + TextView loadingTitle = new TextView(context); + loadingTitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + loadingTitle.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + loadingTitle.setTextColor(Theme.getColor(Theme.key_player_actionBarTitle)); + loadingTitle.setTag(Theme.key_player_actionBarTitle); + loadingTitle.setText(LocaleController.getString("LoadingStats", R.string.LoadingStats)); + loadingTitle.setGravity(Gravity.CENTER_HORIZONTAL); + + TextView loadingSubtitle = new TextView(context); + loadingSubtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + loadingSubtitle.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); + loadingSubtitle.setTag(Theme.key_player_actionBarSubtitle); + loadingSubtitle.setText(LocaleController.getString("LoadingStatsDescription", R.string.LoadingStatsDescription)); + loadingSubtitle.setGravity(Gravity.CENTER_HORIZONTAL); + + progressLayout.addView(imageView, LayoutHelper.createLinear(120, 120, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 20)); + progressLayout.addView(loadingTitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 10)); + progressLayout.addView(loadingSubtitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); + + addView(progressLayout, LayoutHelper.createFrame(240, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 30)); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index ba35bf6f0d4..ae50d77e12b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -316,6 +316,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -469,6 +470,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private HintView mediaBanTooltip; private HintView searchAsListHint; private HintView scheduledOrNoSoundHint; + private boolean scheduledOrNoSoundHintShown; + private HintView scheduledHint; + private boolean scheduledHintShown; private boolean searchAsListHintShown; private HintView fwdRestrictedTopHint; private HintView fwdRestrictedBottomHint; @@ -1811,6 +1815,12 @@ public void run() { emojiAnimationsOverlay.cancelAllAnimations(); } ReactionsEffectOverlay.dismissAll(); + if (TextUtils.isEmpty(text)) { + hideSendButtonHints(); + AndroidUtilities.cancelRunOnUIThread(showScheduledHintRunnable); + } else if (!bigChange){ + showScheduledHint(); + } } @Override @@ -2007,6 +2017,9 @@ public void onSendLongClick() { if (scheduledOrNoSoundHint != null) { scheduledOrNoSoundHint.hide(); } + if (scheduledHint != null) { + scheduledHint.hide(); + } } @Override @@ -2077,16 +2090,38 @@ public void onKeyboardRequested() { if (anchor == null || chatActivityEnterView.getEditField() == null || chatActivityEnterView.getEditField().getText().length() < 5) { return; } - SharedConfig.increaseScheduledOrNoSuoundHintShowed(); + SharedConfig.increaseScheduledOrNoSoundHintShowed(); if (scheduledOrNoSoundHint == null) { scheduledOrNoSoundHint = new HintView(getParentActivity(), 4, themeDelegate); - scheduledOrNoSoundHint.setShowingDuration(5000); + scheduledOrNoSoundHint.createCloseButton(); scheduledOrNoSoundHint.setAlpha(0); scheduledOrNoSoundHint.setVisibility(View.INVISIBLE); scheduledOrNoSoundHint.setText(LocaleController.getString("ScheduledOrNoSoundHint", R.string.ScheduledOrNoSoundHint)); contentView.addView(scheduledOrNoSoundHint, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 10, 0, 10, 0)); } scheduledOrNoSoundHint.showForView(anchor, true); + scheduledOrNoSoundHintShown = true; + }; + + private final Runnable showScheduledHintRunnable = () -> { + if (getParentActivity() == null || fragmentView == null || chatActivityEnterView == null) { + return; + } + View anchor = chatActivityEnterView.getSendButton(); + if (anchor == null || chatActivityEnterView.getEditField() == null || chatActivityEnterView.getEditField().getText().length() == 0) { + return; + } + SharedConfig.increaseScheduledHintShowed(); + if (scheduledHint == null) { + scheduledHint = new HintView(getParentActivity(), 4, themeDelegate); + scheduledHint.createCloseButton(); + scheduledHint.setAlpha(0); + scheduledHint.setVisibility(View.INVISIBLE); + scheduledHint.setText(LocaleController.getString("ScheduledHint", R.string.ScheduledHint)); + contentView.addView(scheduledHint, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 10, 0, 10, 0)); + } + scheduledHint.showForView(anchor, true); + scheduledHintShown = true; }; public ChatActivity(Bundle args) { @@ -2825,6 +2860,7 @@ public View createView(Context context) { selectedMessagesCanStarIds[a].clear(); } scheduledOrNoSoundHint = null; + scheduledHint = null; infoTopView = null; aspectRatioFrameLayout = null; videoTextureView = null; @@ -4931,9 +4967,9 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { } } float tx = cell.getSlidingOffsetX() + cell.getCheckBoxTranslation(); - int y = (int) ((replaceAnimation ? child.getTop() : child.getY()) + cell.getLayoutHeight() + cell.getTransitionParams().deltaBottom); int maxY = chatListView.getMeasuredHeight() - chatListView.getPaddingBottom(); + boolean canUpdateTx = cell.isCheckBoxVisible() && tx == 0; if (cell.isPlayingRound() || cell.getTransitionParams().animatePlayingRound) { if (cell.getTransitionParams().animatePlayingRound) { float progressLocal = cell.getTransitionParams().animateChangeProgress; @@ -5000,6 +5036,10 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { top = view.getTop(); if (view instanceof ChatMessageCell) { cell = (ChatMessageCell) view; + float newTx = cell.getSlidingOffsetX() + cell.getCheckBoxTranslation(); + if (canUpdateTx && newTx > 0) { + tx = newTx; + } if (!cell.drawPinnedTop()) { break; } else { @@ -5017,6 +5057,10 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { top = holder.itemView.getTop(); if (holder.itemView instanceof ChatMessageCell) { cell = (ChatMessageCell) holder.itemView; + float newTx = cell.getSlidingOffsetX() + cell.getCheckBoxTranslation(); + if (canUpdateTx && newTx > 0) { + tx = newTx; + } if (!cell.drawPinnedTop()) { break; } else { @@ -9398,11 +9442,22 @@ public void jumpToDate(int date) { } } + private boolean approved; public void processInlineBotWebView(TLRPC.TL_inlineBotWebView object) { - BotWebViewSheet webViewSheet = new BotWebViewSheet(getContext(), getResourceProvider()); - webViewSheet.setParentActivity(getParentActivity()); - webViewSheet.requestWebView(currentAccount, currentUser != null ? currentUser.id : currentChat.id, mentionContainer.getAdapter().getFoundContextBot().id, object.text, object.url, BotWebViewSheet.TYPE_SIMPLE_WEB_VIEW_BUTTON, 0, false, BotWebViewSheet.FLAG_FROM_INLINE_SWITCH); - webViewSheet.show(); + final Runnable open = () -> { + BotWebViewSheet webViewSheet = new BotWebViewSheet(getContext(), getResourceProvider()); + webViewSheet.setParentActivity(getParentActivity()); + webViewSheet.requestWebView(currentAccount, currentUser != null ? currentUser.id : currentChat.id, mentionContainer.getAdapter().getFoundContextBot().id, object.text, object.url, BotWebViewSheet.TYPE_SIMPLE_WEB_VIEW_BUTTON, 0, false, BotWebViewSheet.FLAG_FROM_INLINE_SWITCH); + webViewSheet.show(); + }; + if (approved) { + open.run(); + } else { + WebAppDisclaimerAlert.show(getContext(), ignored -> { + approved = true; + open.run(); + }, null); + } } public void processInlineBotContextPM(TLRPC.TL_inlineBotSwitchPM object) { @@ -9850,6 +9905,9 @@ private void hideHints(boolean scroll) { if (scheduledOrNoSoundHint != null) { scheduledOrNoSoundHint.hide(); } + if (scheduledHint != null) { + scheduledHint.hide(); + } } if (fwdRestrictedBottomHint != null) { fwdRestrictedBottomHint.hide(); @@ -9874,6 +9932,15 @@ private void hideHints(boolean scroll) { } } + private void hideSendButtonHints() { + if (scheduledOrNoSoundHint != null) { + scheduledOrNoSoundHint.hide(); + } + if (scheduledHint != null) { + scheduledHint.hide(); + } + } + private void showSlowModeHint(View view, boolean show, CharSequence time) { if (getParentActivity() == null || fragmentView == null || !show && (slowModeHint == null || slowModeHint.getVisibility() != View.VISIBLE)) { return; @@ -9923,9 +9990,20 @@ private void showSearchAsListHint() { searchAsListHint.showForView(searchCountText, true); } + private void showScheduledHint() { + boolean disableNoSound = (UserObject.isUserSelf(currentUser) || (chatInfo != null && chatInfo.slowmode_next_send_date > 0) && chatMode == 0); + if (scheduledHintShown || scheduledOrNoSoundHintShown || disableNoSound || SharedConfig.scheduledHintShows >= 3) { + return; + } + AndroidUtilities.cancelRunOnUIThread(showScheduledHintRunnable); + AndroidUtilities.runOnUIThread(showScheduledHintRunnable, 4000); + } + private void showScheduledOrNoSoundHint() { boolean disableNoSound = (UserObject.isUserSelf(currentUser) || (chatInfo != null && chatInfo.slowmode_next_send_date > 0) && chatMode == 0); - if (SharedConfig.scheduledOrNoSoundHintShows >= 3 || System.currentTimeMillis() % 4 != 0 || disableNoSound) { + long scheduledOrNoSoundHintTimeFromLastSeen = System.currentTimeMillis() - SharedConfig.scheduledOrNoSoundHintSeenAt; + long scheduledHintTimeFromLastSeen = System.currentTimeMillis() - SharedConfig.scheduledHintSeenAt; + if (disableNoSound || SharedConfig.scheduledOrNoSoundHintShows >= 3 || scheduledOrNoSoundHintTimeFromLastSeen < 86400000L || scheduledHintTimeFromLastSeen < 86400000L) { return; } AndroidUtilities.cancelRunOnUIThread(showScheduledOrNoSoundRunnable); @@ -13072,6 +13150,12 @@ protected void dispatchDraw(Canvas canvas) { } updateTextureViewPosition(false, false); updatePagedownButtonsPosition(); + if (scheduledOrNoSoundHint != null && scheduledOrNoSoundHint.isShowing()) { + scheduledOrNoSoundHint.updatePosition(); + } + if (scheduledHint != null && scheduledHint.isShowing()) { + scheduledHint.updatePosition(); + } int restoreToCount = -1; if (switchingFromTopics) { restoreToCount = canvas.saveLayerAlpha(0, actionBar.getBottom(), getMeasuredWidth(), getMeasuredHeight(), (int) (255 * switchingFromTopicsProgress), Canvas.ALL_SAVE_FLAG); @@ -14978,6 +15062,11 @@ public void onCaptionChanged(CharSequence caption) { } } + @Override + public void onApplyCaption(CharSequence caption) { + chatActivityEnterView.setFieldText(caption, true); + } + @Override public boolean closeKeyboard() { if (chatActivityEnterView != null && isKeyboardVisible()) { @@ -29049,6 +29138,7 @@ public void onSearchExpand() { AndroidUtilities.showKeyboard(searchItem.getSearchField()); removeKeyboardPositionBeforeTransition(); }, 500); + hideSendButtonHints(); } @Override @@ -29891,7 +29981,7 @@ public void didPressImage(ChatMessageCell cell, float x, float y) { if (message.type == MessageObject.TYPE_STORY) { if (message.messageOwner.media.storyItem != null && !(message.messageOwner.media.storyItem instanceof TLRPC.TL_storyItemDeleted)) { TLRPC.StoryItem storyItem = message.messageOwner.media.storyItem; - storyItem.dialogId = message.messageOwner.media.user_id; + storyItem.dialogId = DialogObject.getPeerDialogId(message.messageOwner.media.peer); storyItem.messageId = message.getId(); storyItem.messageType = 2; StoriesUtilities.applyViewedUser(storyItem, currentUser); @@ -30079,7 +30169,7 @@ public void didPressInstantButton(ChatMessageCell cell, int type) { if (webPage.attributes.get(i) instanceof TLRPC.TL_webPageAttributeStory) { TLRPC.TL_webPageAttributeStory story = (TLRPC.TL_webPageAttributeStory) webPage.attributes.get(i); if (story.storyItem != null) { - story.storyItem.dialogId = story.user_id; + story.storyItem.dialogId = DialogObject.getPeerDialogId(story.peer); story.storyItem.messageId = messageObject.getId(); story.storyItem.messageType = 1; getOrCreateStoryViewer().open(getContext(), story.storyItem, StoriesListPlaceProvider.of(chatListView)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index d34dae86f51..06d7ed86a42 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -140,6 +140,7 @@ public class ChatRightsEditActivity extends BaseFragment { private int sendMessagesRow; private int sendMediaRow; + private boolean sendMediaExpanded; private int sendPhotosRow; private int sendVideosRow; private int sendMusicRow; @@ -153,6 +154,17 @@ public class ChatRightsEditActivity extends BaseFragment { private int untilSectionRow; private int untilDateRow; + private int channelMessagesRow; + private boolean channelMessagesExpanded; + private int channelPostMessagesRow; + private int channelEditMessagesRow; + private int channelDeleteMessagesRow; + private int channelStoriesRow; + private boolean channelStoriesExpanded; + private int channelPostStoriesRow; + private int channelEditStoriesRow; + private int channelDeleteStoriesRow; + private ChatRightsEditActivityDelegate delegate; private String botHash; @@ -164,7 +176,6 @@ public class ChatRightsEditActivity extends BaseFragment { public static final int TYPE_ADD_BOT = 2; private boolean closingKeyboardAfterFinish = false; - private boolean sendMediaExpanded; public interface ChatRightsEditActivityDelegate { void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank); @@ -181,6 +192,7 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig currentUser = MessagesController.getInstance(currentAccount).getUser(userId); currentType = type; canEdit = edit; + channelMessagesExpanded = channelStoriesExpanded = !canEdit; botHash = addingNewBotHash; currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); if (rank == null) { @@ -214,6 +226,9 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig rightsAdmin.edit_messages = rightsAdmin.edit_messages || botDefaultRights.edit_messages; rightsAdmin.manage_call = rightsAdmin.manage_call || botDefaultRights.manage_call; rightsAdmin.manage_topics = rightsAdmin.manage_topics || botDefaultRights.manage_topics; + rightsAdmin.post_stories = rightsAdmin.post_stories || botDefaultRights.post_stories; + rightsAdmin.edit_stories = rightsAdmin.edit_stories || botDefaultRights.edit_stories; + rightsAdmin.delete_stories = rightsAdmin.delete_stories || botDefaultRights.delete_stories; rightsAdmin.other = rightsAdmin.other || botDefaultRights.other; } } @@ -237,6 +252,9 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig adminRights.invite_users = myAdminRights.invite_users; adminRights.pin_messages = myAdminRights.pin_messages; adminRights.manage_topics = myAdminRights.manage_topics; + adminRights.post_stories = myAdminRights.post_stories; + adminRights.edit_stories = myAdminRights.edit_stories; + adminRights.delete_stories = myAdminRights.delete_stories; adminRights.other = myAdminRights.other; initialIsSet = false; } @@ -252,6 +270,9 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig adminRights.invite_users = rightsAdmin.invite_users; adminRights.pin_messages = rightsAdmin.pin_messages; adminRights.manage_topics = rightsAdmin.manage_topics; + adminRights.post_stories = rightsAdmin.post_stories; + adminRights.edit_stories = rightsAdmin.edit_stories; + adminRights.delete_stories = rightsAdmin.delete_stories; adminRights.add_admins = rightsAdmin.add_admins; adminRights.anonymous = rightsAdmin.anonymous; adminRights.other = rightsAdmin.other; @@ -410,6 +431,9 @@ public static TLRPC.TL_chatAdminRights rightsOR(TLRPC.TL_chatAdminRights a, TLRP adminRights.add_admins = a.add_admins || b.add_admins; adminRights.manage_call = a.manage_call || b.manage_call; adminRights.manage_topics = a.manage_topics || b.manage_topics; + adminRights.post_stories = a.post_stories || b.post_stories; + adminRights.edit_stories = a.edit_stories || b.edit_stories; + adminRights.delete_stories = a.delete_stories || b.delete_stories; return adminRights; } @@ -418,7 +442,8 @@ public static TLRPC.TL_chatAdminRights emptyAdminRights(boolean value) { TLRPC.TL_chatAdminRights adminRights = new TLRPC.TL_chatAdminRights(); adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = - adminRights.pin_messages = adminRights.add_admins = adminRights.manage_call = adminRights.manage_topics = value; + adminRights.pin_messages = adminRights.add_admins = adminRights.manage_call = adminRights.manage_topics = + adminRights.post_stories = adminRights.edit_stories = adminRights.delete_stories = value; return adminRights; } @@ -527,15 +552,6 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { return; } if (position == sendMediaRow) { -// if (allDefaultMediaBanned()) { -// new AlertDialog.Builder(getParentActivity()) -// .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) -// .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) -// .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) -// .create() -// .show(); -// return; -// } sendMediaExpanded = !sendMediaExpanded; updateRows(false); if (sendMediaExpanded) { @@ -544,6 +560,26 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { listViewAdapter.notifyItemRangeRemoved(sendMediaRow + 1, 9); } return; + } else if (position == channelMessagesRow) { + channelMessagesExpanded = !channelMessagesExpanded; + updateRows(false); + listViewAdapter.notifyItemChanged(channelMessagesRow); + if (channelMessagesExpanded) { + listViewAdapter.notifyItemRangeInserted(channelMessagesRow + 1, 3); + } else { + listViewAdapter.notifyItemRangeRemoved(channelMessagesRow + 1, 3); + } + return; + } else if (position == channelStoriesRow) { + channelStoriesExpanded = !channelStoriesExpanded; + updateRows(false); + listViewAdapter.notifyItemChanged(channelStoriesRow); + if (channelStoriesExpanded) { + listViewAdapter.notifyItemRangeInserted(channelStoriesRow + 1, 3); + } else { + listViewAdapter.notifyItemRangeRemoved(channelStoriesRow + 1, 3); + } + return; } if (position == 0) { Bundle args = new Bundle(); @@ -714,7 +750,29 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { showDialog(builder.create()); } else if (view instanceof CheckBoxCell) { CheckBoxCell checkBoxCell = (CheckBoxCell) view; - if (currentType == TYPE_BANNED && bannedRights != null) { + if (position == channelPostMessagesRow || position == channelEditMessagesRow || position == channelDeleteMessagesRow) { + boolean value; + if (position == channelPostMessagesRow) { + value = adminRights.post_messages = !adminRights.post_messages; + } else if (position == channelEditMessagesRow) { + value = adminRights.edit_messages = !adminRights.edit_messages; + } else { + value = adminRights.delete_messages = !adminRights.delete_messages; + } + listViewAdapter.notifyItemChanged(channelMessagesRow); + checkBoxCell.setChecked(value, true); + } else if (position == channelPostStoriesRow || position == channelEditStoriesRow || position == channelDeleteStoriesRow) { + boolean value; + if (position == channelPostStoriesRow) { + value = adminRights.post_stories = !adminRights.post_stories; + } else if (position == channelEditStoriesRow) { + value = adminRights.edit_stories = !adminRights.edit_stories; + } else { + value = adminRights.delete_stories = !adminRights.delete_stories; + } + listViewAdapter.notifyItemChanged(channelStoriesRow); + checkBoxCell.setChecked(value, true); + } else if (currentType == TYPE_BANNED && bannedRights != null) { boolean disabled = !checkBoxCell.isChecked(); boolean value = false; @@ -875,7 +933,7 @@ private boolean isDefaultAdminRights() { private boolean hasAllAdminRights() { if (isChannel) { - return adminRights.change_info && adminRights.post_messages && adminRights.edit_messages && adminRights.delete_messages && adminRights.invite_users && adminRights.add_admins && adminRights.manage_call; + return adminRights.change_info && adminRights.post_messages && adminRights.edit_messages && adminRights.delete_messages && adminRights.invite_users && adminRights.add_admins && adminRights.manage_call && adminRights.post_stories && adminRights.edit_stories && adminRights.delete_stories; } else { return adminRights.change_info && adminRights.delete_messages && adminRights.ban_users && adminRights.invite_users && adminRights.pin_messages && adminRights.add_admins && adminRights.manage_call && (!isForum || adminRights.manage_topics); } @@ -1020,7 +1078,7 @@ private void initTransfer(TLRPC.InputCheckPasswordSRP srp, TwoStepVerificationAc }), ConnectionsManager.RequestFlagWithoutLogin); } else if (error.text.equals("CHANNELS_TOO_MUCH")) { if (getParentActivity() != null && !AccountInstance.getInstance(currentAccount).getUserConfig().isPremium()) { - showDialog(new LimitReachedBottomSheet(this, getParentActivity(), LimitReachedBottomSheet.TYPE_TO0_MANY_COMMUNITIES, currentAccount, getResourceProvider())); + showDialog(new LimitReachedBottomSheet(this, getParentActivity(), LimitReachedBottomSheet.TYPE_TO0_MANY_COMMUNITIES, currentAccount, null)); } else { presentFragment(new TooManyCommunitiesActivity(TooManyCommunitiesActivity.TYPE_EDIT)); } @@ -1068,6 +1126,15 @@ private void updateRows(boolean update) { sendMessagesRow = -1; sendMediaRow = -1; + channelMessagesRow = -1; + channelPostMessagesRow = -1; + channelEditMessagesRow = -1; + channelDeleteMessagesRow = -1; + channelStoriesRow = -1; + channelPostStoriesRow = -1; + channelEditStoriesRow = -1; + channelDeleteStoriesRow = -1; + sendPhotosRow = -1; sendVideosRow = -1; sendMusicRow = -1; @@ -1088,9 +1155,18 @@ private void updateRows(boolean update) { if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { if (isChannel) { changeInfoRow = rowCount++; - postMessagesRow = rowCount++; - editMesagesRow = rowCount++; - deleteMessagesRow = rowCount++; + channelMessagesRow = rowCount++; + if (channelMessagesExpanded) { + channelPostMessagesRow = rowCount++; + channelEditMessagesRow = rowCount++; + channelDeleteMessagesRow = rowCount++; + } + channelStoriesRow = rowCount++; + if (channelStoriesExpanded) { + channelPostStoriesRow = rowCount++; + channelEditStoriesRow = rowCount++; + channelDeleteStoriesRow = rowCount++; + } addUsersRow = rowCount++; startVoiceChatRow = rowCount++; addAdminsRow = rowCount++; @@ -1224,7 +1300,7 @@ private void onDonePressed() { } if (!adminRights.change_info && !adminRights.post_messages && !adminRights.edit_messages && !adminRights.delete_messages && !adminRights.ban_users && !adminRights.invite_users && (!isForum || !adminRights.manage_topics) && - !adminRights.pin_messages && !adminRights.add_admins && !adminRights.anonymous && !adminRights.manage_call) { + !adminRights.pin_messages && !adminRights.add_admins && !adminRights.anonymous && !adminRights.manage_call && (!isChannel || !adminRights.post_stories && !adminRights.edit_stories && !adminRights.delete_stories)) { adminRights.other = true; } else { adminRights.other = false; @@ -1240,6 +1316,7 @@ private void onDonePressed() { adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || (isForum && adminRights.manage_topics) || adminRights.pin_messages || adminRights.add_admins || adminRights.anonymous || adminRights.manage_call || + isChannel && (adminRights.post_stories || adminRights.edit_stories || adminRights.delete_stories) || adminRights.other ? 1 : 0, adminRights, bannedRights, currentRank); finishFragment(); } @@ -1453,6 +1530,14 @@ public long getItemId(int position) { if (position == sendVoiceRow) return 33; if (position == sendRoundRow) return 34; if (position == sendMediaRow) return 35; + if (position == channelMessagesRow) return 36; + if (position == channelPostMessagesRow) return 37; + if (position == channelEditMessagesRow) return 38; + if (position == channelDeleteMessagesRow) return 39; + if (position == channelStoriesRow) return 40; + if (position == channelPostStoriesRow) return 41; + if (position == channelEditStoriesRow) return 42; + if (position == channelDeleteStoriesRow) return 43; return 0; } else { return super.getItemId(position); @@ -1498,6 +1583,12 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { return myAdminRights.pin_messages && (defaultBannedRights == null || defaultBannedRights.pin_messages); } else if (position == manageTopicsRow) { return myAdminRights.manage_topics; + } else if (position == channelPostStoriesRow) { + return myAdminRights.post_stories; + } else if (position == channelEditStoriesRow) { + return myAdminRights.edit_stories; + } else if (position == channelDeleteStoriesRow) { + return myAdminRights.delete_stories; } } } @@ -1594,6 +1685,7 @@ public void afterTextChanged(Editable s) { break; case VIEW_TYPE_INNER_CHECK: CheckBoxCell checkBoxCell = new CheckBoxCell(mContext, 4, 21, getResourceProvider()); + checkBoxCell.setPad(1); checkBoxCell.getCheckBoxRound().setDrawBackgroundAsArc(14); checkBoxCell.getCheckBoxRound().setColor(Theme.key_switch2TrackChecked, Theme.key_radioBackground, Theme.key_checkboxCheck); checkBoxCell.setEnabled(true); @@ -1638,6 +1730,18 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == sendRoundRow) { checkBoxCell.setText(LocaleController.getString("SendMediaPermissionRound", R.string.SendMediaPermissionRound), "", !bannedRights.send_roundvideos && !defaultBannedRights.send_roundvideos, true, animated); checkBoxCell.setIcon(defaultBannedRights.send_roundvideos ? R.drawable.permission_locked : 0); + } else if (position == channelPostMessagesRow) { + checkBoxCell.setText(LocaleController.getString(R.string.EditAdminPostMessages), "", adminRights.post_messages, true, animated); + } else if (position == channelEditMessagesRow) { + checkBoxCell.setText(LocaleController.getString(R.string.EditAdminEditMessages), "", adminRights.edit_messages, true, animated); + } else if (position == channelDeleteMessagesRow) { + checkBoxCell.setText(LocaleController.getString(R.string.EditAdminDeleteMessages), "", adminRights.delete_messages, true, animated); + } else if (position == channelPostStoriesRow) { + checkBoxCell.setText(LocaleController.getString(R.string.EditAdminPostStories), "", adminRights.post_stories, true, animated); + } else if (position == channelEditStoriesRow) { + checkBoxCell.setText(LocaleController.getString(R.string.EditAdminEditStories), "", adminRights.edit_stories, true, animated); + } else if (position == channelDeleteStoriesRow) { + checkBoxCell.setText(LocaleController.getString(R.string.EditAdminDeleteStories), "", adminRights.delete_stories, true, animated); } break; case VIEW_TYPE_USER_CELL: @@ -1719,6 +1823,22 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { setSendMediaEnabled(checked); }); checkCell.setIcon(allDefaultMediaBanned() ? R.drawable.permission_locked : 0); + } else if (position == channelMessagesRow) { + int count = getChannelMessagesSelectedCount(); + checkCell.setTextAndCheck(LocaleController.getString(R.string.ChannelManageMessages), count > 0, true, true); + checkCell.setCollapseArrow(String.format(Locale.US, "%d/3", count), !channelMessagesExpanded, () -> { + boolean checked = checkCell.isChecked(); + checkCell.setChecked(checked); + setChannelMessagesEnabled(checked); + }); + } else if (position == channelStoriesRow) { + int count = getChannelStoriesSelectedCount(); + checkCell.setTextAndCheck(LocaleController.getString(R.string.ChannelManageStories), count > 0, true, true); + checkCell.setCollapseArrow(String.format(Locale.US, "%d/3", count), !channelStoriesExpanded, () -> { + boolean checked = checkCell.isChecked(); + checkCell.setChecked(checked); + setChannelStoriesEnabled(checked); + }); } else if (position == manageRow) { checkCell.setTextAndCheck(LocaleController.getString("ManageGroup", R.string.ManageGroup), asAdmin, true); checkCell.setIcon(myAdminRights.add_admins || isCreator ? 0 : R.drawable.permission_locked); @@ -1890,7 +2010,7 @@ public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) { public int getItemViewType(int position) { if (isExpandableSendMediaRow(position)) { return VIEW_TYPE_INNER_CHECK; - } else if (position == sendMediaRow) { + } else if (position == sendMediaRow || position == channelMessagesRow || position == channelStoriesRow) { return VIEW_TYPE_EXPANDABLE_SWITCH; } else if (position == 0) { return VIEW_TYPE_USER_CELL; @@ -1900,7 +2020,8 @@ public int getItemViewType(int position) { 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 == anonymousRow || position == startVoiceChatRow || position == manageRow || position == manageTopicsRow) { + position == sendMessagesRow || position == anonymousRow || position == startVoiceChatRow || position == manageRow || position == manageTopicsRow + ) { return VIEW_TYPE_SWITCH_CELL; } else if (position == cantEditInfoRow || position == rankInfoRow) { return VIEW_TYPE_INFO_CELL; @@ -1962,6 +2083,48 @@ private int getSendMediaSelectedCount() { return i; } + private int getChannelMessagesSelectedCount() { + int i = 0; + if (adminRights.post_messages) { + i++; + } + if (adminRights.edit_messages) { + i++; + } + if (adminRights.delete_messages) { + i++; + } + return i; + } + + private void setChannelMessagesEnabled(boolean enabled) { + adminRights.post_messages = !enabled; + adminRights.edit_messages = !enabled; + adminRights.delete_messages = !enabled; + AndroidUtilities.updateVisibleRows(listView); + } + + private int getChannelStoriesSelectedCount() { + int i = 0; + if (adminRights.post_stories) { + i++; + } + if (adminRights.edit_stories) { + i++; + } + if (adminRights.delete_stories) { + i++; + } + return i; + } + + private void setChannelStoriesEnabled(boolean enabled) { + adminRights.post_stories = !enabled; + adminRights.edit_stories = !enabled; + adminRights.delete_stories = !enabled; + AndroidUtilities.updateVisibleRows(listView); + } + private boolean allDefaultMediaBanned() { return defaultBannedRights.send_photos && defaultBannedRights.send_videos && defaultBannedRights.send_stickers && defaultBannedRights.send_audios && defaultBannedRights.send_docs && defaultBannedRights.send_voices && @@ -1970,8 +2133,10 @@ private boolean allDefaultMediaBanned() { private boolean isExpandableSendMediaRow(int position) { if (position == sendStickersRow || position == embedLinksRow || position == sendPollsRow || - position == sendPhotosRow || position == sendVideosRow || position == sendFilesRow || - position == sendMusicRow || position == sendRoundRow || position == sendVoiceRow) { + position == sendPhotosRow || position == sendVideosRow || position == sendFilesRow || + position == sendMusicRow || position == sendRoundRow || position == sendVoiceRow || + position == channelPostMessagesRow || position == channelEditMessagesRow || position == channelDeleteMessagesRow || + position == channelPostStoriesRow || position == channelEditStoriesRow || position == channelDeleteStoriesRow) { return true; } return false; 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 3e01f71edf8..b9077f4691a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -4183,7 +4183,7 @@ public static void sendReport(TLRPC.InputPeer peer, int type, String message, Ar } if (storyId != 0) { TLRPC.TL_stories_report request = new TLRPC.TL_stories_report(); - request.user_id = MessagesController.getInstance(UserConfig.selectedAccount).getInputUser(peer.user_id); + request.peer = MessagesController.getInstance(UserConfig.selectedAccount).getInputPeer(peer.user_id); request.id.add(storyId); request.message = message; request.reason = reason; @@ -4341,7 +4341,7 @@ protected void onSend(int type, String message) { if (storyId != 0) { TLRPC.TL_stories_report request = new TLRPC.TL_stories_report(); request.id.add(storyId); - request.user_id = MessagesController.getInstance(UserConfig.selectedAccount).getInputUser(dialog_id); + request.peer = MessagesController.getInstance(UserConfig.selectedAccount).getInputPeer(dialog_id); request.message = ""; if (type == REPORT_TYPE_SPAM) { request.reason = new TLRPC.TL_inputReportReasonSpam(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java index bb080cba866..7bdd189fc07 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java @@ -662,28 +662,6 @@ public void draw(@NonNull Canvas canvas) { imageReceiver.draw(canvas); } - public void drawRaw(Canvas canvas, boolean nextFrame, int fps) { - if (imageReceiver == null) { - return; - } - if (imageReceiver.getLottieAnimation() != null) { - RLottieDrawable rlottie = imageReceiver.getLottieAnimation(); - if (nextFrame) { - int inc = (int) Math.round((float) rlottie.getFramesCount() / (rlottie.getDuration() / 1000f) / 30f); - rlottie.currentFrame = (rlottie.currentFrame + inc) % rlottie.getFramesCount(); - } - rlottie.setBounds(getBounds()); - rlottie.drawFrame(canvas, rlottie.currentFrame); - } else if (imageReceiver.getAnimation() != null) { - AnimatedFileDrawable webp = imageReceiver.getAnimation(); - webp.drawFrame(canvas, nextFrame ? fps / 30 : 0); - } else { - imageReceiver.setImageCoords(getBounds()); - imageReceiver.setAlpha(alpha); - imageReceiver.draw(canvas); - } - } - public void draw(Canvas canvas, Rect drawableBounds, float alpha) { if (imageReceiver == null) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java index ab4b1012869..e7c20ab1314 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java @@ -220,40 +220,6 @@ public static void drawAnimatedEmojis(Canvas canvas, Layout layout, EmojiGrouped } } - public static void drawRawAnimatedEmojis(Canvas canvas, Layout layout, EmojiGroupedSpans stack, float offset, List spoilers, float boundTop, float boundBottom, float drawingYOffset, float alpha, int fps) { - if (canvas == null || layout == null || stack == null) { - return; - } - - boolean needRestore = false; - if (Emoji.emojiDrawingYOffset != 0 || offset != 0) { - needRestore = true; - canvas.save(); - canvas.translate(0, Emoji.emojiDrawingYOffset + AndroidUtilities.dp(20 * offset)); - } - - stack.rawIndex++; - for (int k = 0; k < stack.holders.size(); ++k) { - AnimatedEmojiHolder holder = stack.holders.get(k); - float halfSide = holder.span.measuredSize / 2f; - float cx, cy; - cx = holder.span.lastDrawnCx; - cy = holder.span.lastDrawnCy; - holder.drawableBounds.set((int) (cx - halfSide), (int) (cy - halfSide), (int) (cx + halfSide), (int) (cy + halfSide)); - holder.drawable.setBounds(holder.drawableBounds); - boolean nextFrame = false; - if (holder.drawable.rawDrawIndex < stack.rawIndex) { - holder.drawable.rawDrawIndex = stack.rawIndex; - nextFrame = true; - } - holder.drawable.drawRaw(canvas, nextFrame, fps); - } - - if (needRestore) { - canvas.restore(); - } - } - private static boolean isInsideSpoiler(Layout layout, int start, int end) { if (layout == null || !(layout.getText() instanceof Spanned)) { return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java index ab5e279da61..79a9b1f63e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java @@ -6,12 +6,10 @@ import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; -import android.content.Intent; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; -import android.net.Uri; import android.os.Build; import android.text.SpannableStringBuilder; import android.util.TypedValue; @@ -23,25 +21,21 @@ import android.widget.ScrollView; import android.widget.TextView; -import androidx.core.content.FileProvider; - 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.LocaleController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; -import org.telegram.messenger.UserConfig; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.voip.CellFlickerDrawable; -import java.io.File; import java.util.Locale; public class BlockingUpdateView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { @@ -145,16 +139,22 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { acceptButton.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); addView(acceptButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 46, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 45)); acceptButton.setOnClickListener(view1 -> { - if (!checkApkInstallPermissions(getContext())) { - return; - } - if (appUpdate.document instanceof TLRPC.TL_document) { - if (!openApkInstall((Activity) getContext(), appUpdate.document)) { - FileLoader.getInstance(accountNum).loadFile(appUpdate.document, "update", FileLoader.PRIORITY_HIGH, 1); - showProgress(true); + if (BuildVars.isStandaloneApp() || BuildVars.DEBUG_VERSION) { + if (!ApplicationLoader.applicationLoaderInstance.checkApkInstallPermissions(getContext())) { + return; + } + if (appUpdate.document instanceof TLRPC.TL_document) { + if (!ApplicationLoader.applicationLoaderInstance.openApkInstall((Activity) getContext(), appUpdate.document)) { + FileLoader.getInstance(accountNum).loadFile(appUpdate.document, "update", FileLoader.PRIORITY_HIGH, 1); + showProgress(true); + } + } else if (appUpdate.url != null) { + Browser.openUrl(getContext(), appUpdate.url); } - } else if (appUpdate.url != null) { - Browser.openUrl(getContext(), appUpdate.url); + } else if (BuildVars.isHuaweiStoreApp()){ + Browser.openUrl(context, BuildVars.HUAWEI_STORE_URL); + } else { + Browser.openUrl(context, BuildVars.PLAYSTORE_APP_URL); } }); @@ -209,7 +209,7 @@ public void didReceivedNotification(int id, int account, Object... args) { String location = (String) args[0]; if (fileName != null && fileName.equals(location)) { showProgress(false); - openApkInstall((Activity) getContext(), appUpdate.document); + ApplicationLoader.applicationLoaderInstance.openApkInstall((Activity) getContext(), appUpdate.document); } } else if (id == NotificationCenter.fileLoadFailed) { String location = (String) args[0]; @@ -227,39 +227,7 @@ public void didReceivedNotification(int id, int account, Object... args) { } } - public static boolean checkApkInstallPermissions(final Context context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !ApplicationLoader.applicationContext.getPackageManager().canRequestPackageInstalls()) { - AlertsCreator.createApkRestrictedDialog(context, null).show(); - return false; - } - return true; - } - public static boolean openApkInstall(Activity activity, TLRPC.Document document) { - boolean exists = false; - try { - String fileName = FileLoader.getAttachFileName(document); - File f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(document, true); - if (exists = f.exists()) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - if (Build.VERSION.SDK_INT >= 24) { - intent.setDataAndType(FileProvider.getUriForFile(activity, ApplicationLoader.getApplicationId() + ".provider", f), "application/vnd.android.package-archive"); - } else { - intent.setDataAndType(Uri.fromFile(f), "application/vnd.android.package-archive"); - } - try { - activity.startActivityForResult(intent, 500); - } catch (Exception e) { - FileLog.e(e); - } - } - } catch (Exception e) { - FileLog.e(e); - } - return exists; - } private void showProgress(final boolean show) { if (progressAnimation != null) { @@ -332,7 +300,7 @@ public void show(int account, TLRPC.TL_help_appUpdate update, boolean check) { NotificationCenter.getInstance(accountNum).addObserver(this, NotificationCenter.fileLoaded); NotificationCenter.getInstance(accountNum).addObserver(this, NotificationCenter.fileLoadFailed); NotificationCenter.getInstance(accountNum).addObserver(this, NotificationCenter.fileLoadProgressChanged); - if (check) { + if (check && BuildVars.isStandaloneApp()) { TLRPC.TL_help_getAppUpdate req = new TLRPC.TL_help_getAppUpdate(); try { req.source = ApplicationLoader.applicationContext.getPackageManager().getInstallerPackageName(ApplicationLoader.applicationContext.getPackageName()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java index cc48da38aec..26b57060f71 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java @@ -931,14 +931,11 @@ private boolean setupMatrix(int bitmapWidth, int bitmapHeight) { return true; } - public Drawable makeDrawable(float offsetX, float offsetY, Drawable base) { + public Drawable makeDrawable(float offsetX, float offsetY, Drawable base, float r) { return new Drawable() { float alpha = 1f; private final Paint dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - { - dimPaint.setColor(0x52000000); - } @Nullable private Paint getPaint() { @@ -971,22 +968,47 @@ public void draw(@NonNull Canvas canvas) { Rect bounds = getBounds(); if (paint != null) { - canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, 0xFF, Canvas.ALL_SAVE_FLAG); + if (base != null) { + canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, 0xFF, Canvas.ALL_SAVE_FLAG); + base.setBounds(bounds); + base.draw(canvas); + canvas.drawRect(bounds, paint); + canvas.restore(); + getPadding(AndroidUtilities.rectTmp2); + AndroidUtilities.rectTmp.set( + bounds.left + AndroidUtilities.rectTmp2.left, + bounds.top + AndroidUtilities.rectTmp2.top, + bounds.right - AndroidUtilities.rectTmp2.right, + bounds.bottom - AndroidUtilities.rectTmp2.bottom + ); + dimPaint.setColor(0x66000000); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint); + } else { + if (r > 0) { + AndroidUtilities.rectTmp.set(bounds); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, paint); + } else { + canvas.drawRect(bounds, paint); + } + dimPaint.setColor(0x66000000); + if (r > 0) { + AndroidUtilities.rectTmp.set(bounds); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint); + } else { + canvas.drawRect(bounds, dimPaint); + } + } + } else if (base != null) { base.setBounds(bounds); base.draw(canvas); - canvas.drawRect(bounds, paint); - canvas.restore(); - getPadding(AndroidUtilities.rectTmp2); - AndroidUtilities.rectTmp.set( - bounds.left + AndroidUtilities.rectTmp2.left, - bounds.top + AndroidUtilities.rectTmp2.top, - bounds.right - AndroidUtilities.rectTmp2.right, - bounds.bottom - AndroidUtilities.rectTmp2.bottom - ); - canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(6), dp(6), dimPaint); } else { - base.setBounds(bounds); - base.draw(canvas); + dimPaint.setColor(-14145495); + if (r > 0) { + AndroidUtilities.rectTmp.set(bounds); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint); + } else { + canvas.drawRect(bounds, dimPaint); + } } } @@ -1005,7 +1027,12 @@ public int getOpacity() { @Override public boolean getPadding(@NonNull Rect padding) { - return base.getPadding(padding); + if (base != null) { + return base.getPadding(padding); + } else { + padding.set(0, 0, 0, 0); + return true; + } } }; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java index 7b61e26b366..4b55e6164e5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java @@ -44,6 +44,8 @@ protected class Tab { final RectF clickRect = new RectF(); final AnimatedFloat nonscrollingT = new AnimatedFloat(BottomPagerTabs.this, 0, 200, CubicBezierInterpolator.EASE_OUT_QUINT); + public int customEndFrameMid; + public int customEndFrameEnd; public Tab(int i, int resId, CharSequence text) { this.i = i; @@ -70,29 +72,27 @@ public void setActive(boolean active, boolean animated) { return; } - if (i == 0) { - // 0 - 20 - // 20 - 40 + if (tabs[i].customEndFrameMid != 0) { if (active) { - drawable.setCustomEndFrame(20); - if (drawable.getCurrentFrame() >= 38) { + drawable.setCustomEndFrame(customEndFrameMid); + if (drawable.getCurrentFrame() >= customEndFrameEnd - 2) { drawable.setCurrentFrame(0, false); } - if (drawable.getCurrentFrame() <= 20) { + if (drawable.getCurrentFrame() <= customEndFrameMid) { drawable.start(); } else { - drawable.setCurrentFrame(20); + drawable.setCurrentFrame(customEndFrameMid); } } else { - if (drawable.getCurrentFrame() >= 19) { - drawable.setCustomEndFrame(39); + if (drawable.getCurrentFrame() >= customEndFrameMid - 1) { + drawable.setCustomEndFrame(customEndFrameEnd - 1); drawable.start(); } else { drawable.setCustomEndFrame(0); drawable.setCurrentFrame(0); } } - } else if (i == 1 && active) { + } else if (active) { drawable.setCurrentFrame(0); if (animated) { drawable.start(); 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 b18155cc23d..b0da22c3aa3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -22,6 +22,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.LocaleController; @@ -68,6 +69,18 @@ public static BulletinFactory global() { return BulletinFactory.of(baseFragment); } + public static void showForError(TLRPC.TL_error error) { + BulletinFactory bulletinFactory = BulletinFactory.global(); + if (bulletinFactory == null) { + return; + } + if (BuildVars.DEBUG_VERSION) { + bulletinFactory.createErrorBulletin(error.code + " " + error.text).show(); + } else { + bulletinFactory.createErrorBulletin(LocaleController.getString("UnknownError", R.string.UnknownError)).show(); + } + } + public enum FileType { PHOTO("PhotoSavedHint", R.string.PhotoSavedHint, Icon.SAVED_TO_GALLERY), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java index 64d51ace75e..a2c44ec1ac4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java @@ -11,19 +11,27 @@ public class ButtonBounce { private View view; - private final float durationMultiplier; + private final float durationPressMultiplier; + private final float durationReleaseMultiplier; private final float overshoot; private long releaseDelay = 0; public ButtonBounce(View viewToInvalidate) { view = viewToInvalidate; - durationMultiplier = 1f; + durationPressMultiplier = durationReleaseMultiplier = 1f; overshoot = 5.0f; } public ButtonBounce(View viewToInvalidate, float durationMultiplier, float overshoot) { view = viewToInvalidate; - this.durationMultiplier = durationMultiplier; + this.durationPressMultiplier = this.durationReleaseMultiplier = durationMultiplier; + this.overshoot = overshoot; + } + + public ButtonBounce(View viewToInvalidate, float durationPressMultiplier, float durationReleaseMultiplier, float overshoot) { + view = viewToInvalidate; + this.durationPressMultiplier = durationPressMultiplier; + this.durationReleaseMultiplier = durationReleaseMultiplier; this.overshoot = overshoot; } @@ -65,11 +73,11 @@ public void onAnimationEnd(Animator animation) { }); if (isPressed) { animator.setInterpolator(CubicBezierInterpolator.DEFAULT); - animator.setDuration((long) (60 * durationMultiplier)); + animator.setDuration((long) (60 * durationPressMultiplier)); animator.setStartDelay(0); } else { animator.setInterpolator(new OvershootInterpolator(overshoot)); - animator.setDuration((long) (350 * durationMultiplier)); + animator.setDuration((long) (350 * durationReleaseMultiplier)); animator.setStartDelay(releaseDelay); } animator.start(); 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 1272bd6416e..dc6b81ff0c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -3654,6 +3654,7 @@ public void didSelectDate(boolean notify, int scheduleDate) { }, resourcesProvider); }); sendPopupLayout.addView(scheduleButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + SharedConfig.removeScheduledHint(); if (!self && dialog_id > 0) { sendWhenOnlineButton = new ActionBarMenuSubItem(getContext(), true, !sendWithoutSoundButtonValue, resourcesProvider); sendWhenOnlineButton.setTextAndIcon(LocaleController.getString("SendWhenOnline", R.string.SendWhenOnline), R.drawable.msg_online); 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 b3d904dca62..c31e7cbc55f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -34,6 +34,7 @@ import android.os.Build; import android.os.Bundle; import android.text.Editable; +import android.text.SpannableStringBuilder; import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; @@ -76,6 +77,7 @@ import org.telegram.messenger.DialogObject; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; @@ -110,6 +112,8 @@ import org.telegram.ui.PhotoPickerActivity; import org.telegram.ui.PhotoPickerSearchActivity; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.Stories.DarkThemeResourceProvider; +import org.telegram.ui.Stories.recorder.CaptionContainerView; import java.io.File; import java.util.ArrayList; @@ -2463,6 +2467,12 @@ public void onTextChanged(CharSequence charSequence, int start, int before, int if ((count - before) >= 1) { processChange = true; } + if (mentionContainer == null) { + createMentionsContainer(); + } + if (mentionContainer.getAdapter() != null) { + mentionContainer.getAdapter().searchUsernameOrHashtag(charSequence, commentTextView.getEditText().getSelectionStart(), null, false, false); + } } @Override @@ -2796,6 +2806,13 @@ protected void onStop() { public void updateCommentTextViewPosition() { commentTextView.getLocationOnScreen(commentTextViewLocation); + if (mentionContainer != null) { + float y = -commentTextView.getHeight(); + if (mentionContainer.getY() != y) { + mentionContainer.setTranslationY(y); + mentionContainer.invalidate(); + } + } } public int getCommentTextViewTop() { @@ -4661,4 +4678,72 @@ public void setAllowEnterCaption(boolean allowEnterCaption) { public void setDocumentsDelegate(ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate documentsDelegate) { this.documentsDelegate = documentsDelegate; } + + private void replaceWithText(int start, int len, CharSequence text, boolean parseEmoji) { + if (commentTextView == null) { + return; + } + try { + SpannableStringBuilder builder = new SpannableStringBuilder(commentTextView.getText()); + builder.replace(start, start + len, text); + if (parseEmoji) { + Emoji.replaceEmoji(builder, commentTextView.getEditText().getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); + } + commentTextView.setText(builder); + commentTextView.setSelection(start + text.length()); + } catch (Exception e) { + FileLog.e(e); + } + } + + public MentionsContainerView mentionContainer; + private void createMentionsContainer() { + mentionContainer = new MentionsContainerView(getContext(), UserConfig.getInstance(currentAccount).getClientUserId(), 0, LaunchActivity.getLastFragment(), null, resourcesProvider) { + @Override + protected void onScrolled(boolean atTop, boolean atBottom) { + if (photoLayout != null) { + photoLayout.checkCameraViewPosition(); + } + } + + @Override + protected void onAnimationScroll() { + if (photoLayout != null) { + photoLayout.checkCameraViewPosition(); + } + } + }; + setupMentionContainer(); + mentionContainer.withDelegate(new MentionsContainerView.Delegate() { + + @Override + public void replaceText(int start, int len, CharSequence replacingString, boolean allowShort) { + replaceWithText(start, len, replacingString, allowShort); + } + + @Override + public Paint.FontMetricsInt getFontMetrics() { + return commentTextView.getEditText().getPaint().getFontMetricsInt(); + } + }); + containerView.addView(mentionContainer, containerView.indexOfChild(frameLayout2), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.BOTTOM)); + mentionContainer.setTranslationY(-commentTextView.getHeight()); + + setupMentionContainer(); + } + + protected void setupMentionContainer() { + mentionContainer.getAdapter().setAllowStickers(false); + mentionContainer.getAdapter().setAllowBots(false); + mentionContainer.getAdapter().setAllowChats(false); + mentionContainer.getAdapter().setSearchInDailogs(true); + if (baseFragment instanceof ChatActivity) { + mentionContainer.getAdapter().setChatInfo(((ChatActivity) baseFragment).getCurrentChatInfo()); + mentionContainer.getAdapter().setNeedUsernames(((ChatActivity) baseFragment).getCurrentChat() != null); + } else { + mentionContainer.getAdapter().setChatInfo(null); + mentionContainer.getAdapter().setNeedUsernames(false); + } + mentionContainer.getAdapter().setNeedBotContext(false); + } } 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 3cdf9726821..df79fe29402 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -36,6 +36,7 @@ import android.provider.MediaStore; import android.provider.Settings; import android.text.TextUtils; +import android.util.Log; import android.util.Pair; import android.util.TypedValue; import android.view.Gravity; @@ -2167,7 +2168,7 @@ protected void dispatchDraw(Canvas canvas) { if (Build.VERSION.SDK_INT >= 21) { super.dispatchDraw(canvas); } else { - int maxY = (int) Math.min(parentAlert.getCommentTextViewTop() + currentPanTranslationY + parentAlert.getContainerView().getTranslationY() - cameraView.getTranslationY(), getMeasuredHeight()); + int maxY = (int) Math.min(parentAlert.getCommentTextViewTop() + currentPanTranslationY + parentAlert.getContainerView().getTranslationY() - cameraView.getTranslationY() - (parentAlert.mentionContainer != null ? parentAlert.mentionContainer.clipBottom() + AndroidUtilities.dp(8) : 0), getMeasuredHeight()); if (cameraAnimationInProgress) { AndroidUtilities.rectTmp.set(animationClipLeft + cameraViewOffsetX * (1f - cameraOpenProgress), animationClipTop + cameraViewOffsetY * (1f - cameraOpenProgress), animationClipRight, Math.min(maxY, animationClipBottom)); } else if (!cameraAnimationInProgress && !cameraOpened) { @@ -2204,7 +2205,7 @@ protected void onDetachedFromWindow() { cameraView.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { - int maxY = (int) Math.min(parentAlert.getCommentTextViewTop() + currentPanTranslationY + parentAlert.getContainerView().getTranslationY() - cameraView.getTranslationY(), view.getMeasuredHeight()); + int maxY = (int) Math.min(parentAlert.getCommentTextViewTop() - (parentAlert.mentionContainer != null ? parentAlert.mentionContainer.clipBottom() + AndroidUtilities.dp(8) : 0) + currentPanTranslationY + parentAlert.getContainerView().getTranslationY() - cameraView.getTranslationY(), view.getMeasuredHeight()); if (cameraOpened) { maxY = view.getMeasuredHeight(); } else if (cameraAnimationInProgress) { @@ -2764,9 +2765,12 @@ protected void checkCameraViewPosition() { int containerHeight = parentAlert.getSheetContainer().getMeasuredHeight(); maxY = (int) (containerHeight - parentAlert.buttonsRecyclerView.getMeasuredHeight() + parentAlert.buttonsRecyclerView.getTranslationY()); + if (parentAlert.mentionContainer != null) { + maxY -= parentAlert.mentionContainer.clipBottom() - AndroidUtilities.dp(6); + } if (topLocal + child.getMeasuredHeight() > maxY) { - cameraViewOffsetBottomY = topLocal + child.getMeasuredHeight() - maxY; + cameraViewOffsetBottomY = Math.min(-AndroidUtilities.dp(5), topLocal - maxY) + child.getMeasuredHeight(); } else { cameraViewOffsetBottomY = 0; } 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 88ee6c00aa3..ee097417a78 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -148,6 +148,9 @@ public ChatAvatarContainer(Context context, BaseFragment baseFragment, boolean n final boolean avatarClickable = parentFragment != null && parentFragment.getChatMode() == 0 && !UserObject.isReplyUser(parentFragment.getCurrentUser()); avatarImageView = new BackupImageView(context) { + + StoriesUtilities.AvatarStoryParams params = new StoriesUtilities.AvatarStoryParams(true); + @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); @@ -160,6 +163,19 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { info.setVisibleToUser(false); } } + + @Override + protected void onDraw(Canvas canvas) { + if (allowDrawStories && animatedEmojiDrawable == null) { + params.originalAvatarRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + params.drawSegments = true; + params.drawInside = true; + params.resourcesProvider = resourcesProvider; + StoriesUtilities.drawAvatarWithStory(parentFragment.getDialogId(), canvas, imageReceiver, params); + } else { + super.onDraw(canvas); + } + } }; if (baseFragment instanceof ChatActivity || baseFragment instanceof TopicsFragment) { sharedMediaPreloader = new SharedMediaLayout.SharedMediaPreloader(baseFragment); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java index c8ec6036760..ee1e89d3c90 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java @@ -13,6 +13,7 @@ import android.graphics.PointF; import android.graphics.RectF; import android.os.Build; +import android.util.Log; import android.view.MotionEvent; import android.view.ViewTreeObserver; import android.widget.FrameLayout; @@ -993,54 +994,37 @@ public static void editBitmap(Context context, String path, Bitmap b, Canvas can if (entities != null && !entities.isEmpty()) { float[] point = new float[4]; - float newScale = 1.0f / sc * scale * stateScale; - float widthScale = b.getWidth() / (float) canvasBitmap.getWidth(); - newScale *= widthScale; - TextPaintView textPaintView = null; for (int a = 0, N = entities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = entities.get(a); - point[0] = entity.x * b.getWidth() + entity.viewWidth * entity.scale / 2; - point[1] = entity.y * b.getHeight() + entity.viewHeight * entity.scale / 2; + point[0] = (entity.x + entity.width / 2) * b.getWidth(); + point[1] = (entity.y + entity.height / 2) * b.getHeight(); point[2] = entity.textViewX * b.getWidth(); point[3] = entity.textViewY * b.getHeight(); matrix.mapPoints(point); - if (entity.type == 0) { - entity.viewWidth = entity.viewHeight = canvasBitmap.getWidth() / 2; - } else if (entity.type == 1) { - entity.fontSize = canvasBitmap.getWidth() / 9; - if (textPaintView == null) { - textPaintView = new TextPaintView(context, new Point(0, 0), entity.fontSize, "", new Swatch(Color.BLACK, 0.85f, 0.1f), 0); - textPaintView.setMaxWidth(canvasBitmap.getWidth() - 20); - } - int type; - if ((entity.subType & 1) != 0) { - type = 0; - } else if ((entity.subType & 4) != 0) { - type = 2; - } else { - type = 1; - } - textPaintView.setType(type); - textPaintView.setText(entity.text); - textPaintView.measure(MeasureSpec.makeMeasureSpec(canvasBitmap.getWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(canvasBitmap.getHeight(), MeasureSpec.AT_MOST)); - entity.viewWidth = textPaintView.getMeasuredWidth(); - entity.viewHeight = textPaintView.getMeasuredHeight(); + final int w = contentWidth, h = contentHeight; + int bw = b.getWidth(), bh = b.getHeight(); + if (orientationOnly == 90 || orientationOnly == 270) { + bw = b.getHeight(); + bh = b.getWidth(); + } + if (entity.type == VideoEditedInfo.MediaEntity.TYPE_TEXT) { + entity.width = entity.width * w / canvasBitmap.getWidth() * scale * stateScale; + entity.height = entity.height * h / canvasBitmap.getHeight() * scale * stateScale; + } else { + entity.viewWidth = (int) (entity.viewWidth / (float) w * bw); + entity.viewHeight = (int) (entity.viewHeight / (float) h * bh); + + entity.width = entity.width * w / bw * scale * stateScale; + entity.height = entity.height * h / bh * scale * stateScale; } - entity.scale *= newScale; - entity.x = (point[0] - entity.viewWidth * entity.scale / 2) / canvasBitmap.getWidth(); - entity.y = (point[1] - entity.viewHeight * entity.scale / 2) / canvasBitmap.getHeight(); + entity.x = point[0] / canvasBitmap.getWidth() - entity.width / 2; + entity.y = point[1] / canvasBitmap.getHeight() - entity.height / 2; entity.textViewX = point[2] / canvasBitmap.getWidth(); entity.textViewY = point[3] / canvasBitmap.getHeight(); - entity.width = entity.viewWidth * entity.scale / canvasBitmap.getWidth(); - entity.height = entity.viewHeight * entity.scale / canvasBitmap.getHeight(); - - entity.textViewWidth = entity.viewWidth / (float) canvasBitmap.getWidth(); - entity.textViewHeight = entity.viewHeight / (float) canvasBitmap.getHeight(); - entity.rotation -= (rotation + orientationOnly) * (Math.PI / 180); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java index 32d0cf3ddea..1cbdf7a7331 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java @@ -137,8 +137,9 @@ public void createCloseButton() { imageView.setImageResource(R.drawable.msg_mini_close_tooltip); imageView.setScaleType(ImageView.ScaleType.CENTER); imageView.setColorFilter(new PorterDuffColorFilter(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_gifSaveHintText), 125), PorterDuff.Mode.MULTIPLY)); - imageView.setOnClickListener(v -> hide(true)); addView(imageView, LayoutHelper.createFrame(34, 34, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, isTopArrow ? 3 : 0, 0, isTopArrow ? 0 : 3)); + + setOnClickListener(v -> hide(true)); } public void setBackgroundColor(int background, int text) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ItemOptions.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ItemOptions.java index ee98672b9c3..4ea5e09ae5f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ItemOptions.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ItemOptions.java @@ -1,5 +1,7 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Context; @@ -150,7 +152,7 @@ public ItemOptions add(int iconResId, CharSequence text, int iconColorKey, int t } ActionBarMenuSubItem subItem = new ActionBarMenuSubItem(context, false, false, resourcesProvider); - subItem.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18 + (LocaleController.isRTL ? 0 : 8)), 0); + subItem.setPadding(dp(18), 0, dp(18 + (LocaleController.isRTL ? 0 : 8)), 0); subItem.setTextAndIcon(text, iconResId); subItem.setColors(Theme.getColor(textColorKey, resourcesProvider), Theme.getColor(iconColorKey, resourcesProvider)); @@ -165,7 +167,7 @@ public ItemOptions add(int iconResId, CharSequence text, int iconColorKey, int t } }); if (minWidthDp > 0) { - subItem.setMinimumWidth(AndroidUtilities.dp(minWidthDp)); + subItem.setMinimumWidth(dp(minWidthDp)); lastLayout.addView(subItem, LayoutHelper.createLinear(minWidthDp, LayoutHelper.WRAP_CONTENT)); } else { lastLayout.addView(subItem, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); @@ -276,10 +278,10 @@ public ItemOptions addText(CharSequence text, int textSizeDp) { final TextView textView = new TextView(context); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSizeDp); textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); - textView.setPadding(AndroidUtilities.dp(13), AndroidUtilities.dp(8), AndroidUtilities.dp(13), AndroidUtilities.dp(8)); + textView.setPadding(dp(13), dp(8), dp(13), dp(8)); textView.setText(text); textView.setTag(R.id.fit_width_tag, 1); - textView.setMaxWidth(AndroidUtilities.dp(200)); + textView.setMaxWidth(dp(200)); lastLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); return this; } @@ -323,7 +325,7 @@ public ItemOptions setBlurBackground(BlurringShader.BlurManager blurManager, flo if (layout instanceof ActionBarPopupWindow.ActionBarPopupWindowLayout) { layout.setBackgroundDrawable( new BlurringShader.StoryBlurDrawer(blurManager, layout, BlurringShader.StoryBlurDrawer.BLUR_TYPE_MENU_BACKGROUND) - .makeDrawable(offsetX + ox + layout.getX(), offsetY + oy + layout.getY(), baseDrawable) + .makeDrawable(offsetX + ox + layout.getX(), offsetY + oy + layout.getY(), baseDrawable, dp(6)) ); } else { for (int i = 0; i < layout.getChildCount(); ++i) { @@ -331,7 +333,7 @@ public ItemOptions setBlurBackground(BlurringShader.BlurManager blurManager, flo if (child instanceof ActionBarPopupWindow.ActionBarPopupWindowLayout) { child.setBackgroundDrawable( new BlurringShader.StoryBlurDrawer(blurManager, child, BlurringShader.StoryBlurDrawer.BLUR_TYPE_MENU_BACKGROUND) - .makeDrawable(offsetX + ox + layout.getX() + child.getX(), offsetY + oy + layout.getY() + child.getY(), baseDrawable) + .makeDrawable(offsetX + ox + layout.getX() + child.getX(), offsetY + oy + layout.getY() + child.getY(), baseDrawable, dp(6)) ); } } @@ -388,7 +390,7 @@ public ItemOptions show() { if (child instanceof ActionBarPopupWindow.ActionBarPopupWindowLayout) { ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout = (ActionBarPopupWindow.ActionBarPopupWindowLayout) child; for (int i = 0; i < popupLayout.getItemsCount(); ++i) { - popupLayout.getItemAt(i).setMinimumWidth(AndroidUtilities.dp(minWidthDp)); + popupLayout.getItemAt(i).setMinimumWidth(dp(minWidthDp)); } } } @@ -460,7 +462,7 @@ public void onDismiss() { } int Y; if (scrimView != null) { - if (forceTop || y + layout.getMeasuredHeight() + AndroidUtilities.dp(16) > AndroidUtilities.displaySize.y) { + if (forceTop || y + layout.getMeasuredHeight() + dp(16) > AndroidUtilities.displaySize.y) { // put above scrimView y -= scrimView.getMeasuredHeight(); y -= layout.getMeasuredHeight(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkActionView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkActionView.java index 8b98e348952..d22f0d272be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkActionView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkActionView.java @@ -435,6 +435,13 @@ public void hideRevokeOption(boolean b) { } } + public void hideOptions() { + optionsView.setVisibility(View.GONE); + linkView.setGravity(Gravity.CENTER); + removeView.setVisibility(View.GONE); + avatarsContainer.setVisibility(View.GONE); + } + private class AvatarsContainer extends FrameLayout { TextView countTextView; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java index 9a987266d7f..ca7fd94f38a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java @@ -467,7 +467,7 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { getMessagesController().getStoriesController().updateStoriesInLists(dialogId, storyItems); final boolean[] undone = new boolean[] { false }; applyBulletin = () -> { - getMessagesController().getStoriesController().updateStoriesPinned(storyItems, pin, null); + getMessagesController().getStoriesController().updateStoriesPinned(dialogId, storyItems, pin, null); }; final Runnable undo = () -> { undone[0] = true; @@ -1159,10 +1159,13 @@ public StoriesTabsView(Context context, Theme.ResourcesProvider resourcesProvide @Override public Tab[] createTabs() { - return new Tab[] { + Tab[] tabs = new Tab[] { new Tab(0, R.raw.msg_stories_saved, LocaleController.getString("ProfileMyStoriesTab", R.string.ProfileMyStoriesTab)), new Tab(1, R.raw.msg_stories_archive, LocaleController.getString("ProfileStoriesArchiveTab", R.string.ProfileStoriesArchiveTab)) }; + tabs[0].customEndFrameMid = 20; + tabs[0].customEndFrameEnd = 40; + return tabs; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java index c122cebc634..8f637faf06f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java @@ -270,6 +270,10 @@ protected void onScrolled(boolean atTop, boolean atBottom) { } + protected void onAnimationScroll() { + + } + public MentionsListView getListView() { return listView; } @@ -321,6 +325,7 @@ public void dispatchDraw(Canvas canvas) { containerPadding = AndroidUtilities.dp(2 + (topPadding ? 2 : 0)); float r = AndroidUtilities.dp(6); + float wasContainerTop = containerTop; if (reversed) { int paddingViewTop = paddedAdapter.paddingViewAttached ? paddedAdapter.paddingView.getTop() : getHeight(); float top = Math.max(0, paddingViewTop + listView.getTranslationY()) + containerPadding; @@ -344,6 +349,9 @@ public void dispatchDraw(Canvas canvas) { rect.bottom += (int) r; } } + if (Math.abs(wasContainerTop - containerTop) > 0.1f) { + onAnimationScroll(); + } if (paint == null) { paint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -504,6 +512,7 @@ private void updateListViewTranslation(boolean forceZeroHeight, boolean animated ); listViewTranslationAnimator.addUpdateListener((anm, val, vel) -> { listView.setTranslationY(val); + onAnimationScroll(); hideT = AndroidUtilities.lerp(fromHideT, toHideT, (val - fromTranslation) / (toTranslation - fromTranslation)); }); if (forceZeroHeight) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntitiesContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntitiesContainerView.java index 0caa6ffb970..15b35a048a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntitiesContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntitiesContainerView.java @@ -1,6 +1,7 @@ package org.telegram.ui.Components.Paint.Views; import android.content.Context; +import android.graphics.Canvas; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; @@ -12,6 +13,8 @@ public class EntitiesContainerView extends FrameLayout { + public boolean drawForThumb; + public interface EntitiesContainerViewDelegate { boolean shouldReceiveTouches(); void onEntityDeselect(); @@ -98,4 +101,12 @@ protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, i super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed); } } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (drawForThumb && child instanceof ReactionWidgetEntityView) { + return true; + } + return super.drawChild(canvas, child, drawingTime); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java index fea750cdc02..1a520a5796d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java @@ -10,6 +10,7 @@ import android.graphics.DashPathEffect; import android.graphics.Paint; import android.os.Build; +import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; @@ -485,7 +486,7 @@ public void pan(float tx, float ty) { if (parent != null) { int newStickyX = STICKY_NONE; if (!lastIsMultitouch) { - if (Math.abs(position.x - parent.getMeasuredWidth() / 2f) <= dp(STICKY_TRIGGER_DP) && position.y < parent.getMeasuredHeight() - dp(112 + 64)) { + if (Math.abs(position.x - parent.getMeasuredWidth() / 2f) <= dp(STICKY_TRIGGER_DP) && position.y < parent.getMeasuredHeight() - dp(112)) { newStickyX = STICKY_CENTER; } else if (Math.abs(position.x - (width() / 2f + getStickyPaddingLeft()) * getScaleX() - dp(STICKY_PADDING_X_DP)) <= dp(STICKY_TRIGGER_DP)) { newStickyX = STICKY_START; @@ -773,6 +774,10 @@ public void onAnimationEnd(Animator animation) { } } + public boolean isSelectedProgress() { + return isSelected() || selectT > 0; + } + private ViewGroup lastSelectionContainer; public void select(ViewGroup selectionContainer) { updateSelect(lastSelectionContainer = selectionContainer, true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java index 193cff35db1..baa8a146f08 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java @@ -234,8 +234,8 @@ public LPhotoPaintView(Context context, Activity activity, int currentAccount, B return -9539985; } else if (key == Theme.key_chat_emojiPanelIcon) { return -9539985; - } else if (key == Theme.key_chat_emojiPanelIconSelected) { - return 0xffffffff; +// } else if (key == Theme.key_chat_emojiPanelIconSelected) { +// return -10177041; } else if (key == Theme.key_windowBackgroundWhiteBlackText) { return -1; } else if (key == Theme.key_featuredStickers_addedIcon) { @@ -459,6 +459,14 @@ protected void onDraw(Canvas canvas) { } CharSequence charSequence = text; charSequence = Emoji.replaceEmoji(charSequence, textPaintView.getFontMetricsInt(), (int) (textPaintView.getFontSize() * .8f), false); + if (charSequence instanceof Spanned) { + Emoji.EmojiSpan[] spans = ((Spanned) charSequence).getSpans(0, charSequence.length(), Emoji.EmojiSpan.class); + if (spans != null) { + for (int i = 0; i < spans.length; ++i) { + spans[i].scale = .85f; + } + } + } textPaintView.setText(charSequence); setTextAlignment(textPaintView, entity.textAlign); Swatch swatch = textPaintView.getSwatch(); @@ -471,8 +479,7 @@ protected void onDraw(Canvas canvas) { view.setX(entity.x * paintingSize.width - entity.viewWidth * (1 - entity.scale) / 2); view.setY(entity.y * paintingSize.height - entity.viewHeight * (1 - entity.scale) / 2); view.setPosition(new Point(view.getX() + entity.viewWidth / 2f, view.getY() + entity.viewHeight / 2f)); - view.setScaleX(entity.scale); - view.setScaleY(entity.scale); + view.setScale(entity.scale); view.setRotation((float) (-entity.rotation / Math.PI * 180)); } } @@ -934,11 +941,13 @@ public boolean isCurrentText() { return currentEntityView instanceof TextPaintView; } - public float getSelectedEntityCenterY() { + public float getSelectedEntityBottom() { if (currentEntityView == null) { - return getY() + entitiesView.getTop() + entitiesView.getMeasuredHeight() / 2f; + return getY() + entitiesView.getMeasuredHeight(); } - return getY() + entitiesView.getTop() + currentEntityView.getPositionY(); + int[] loc = new int[2]; + currentEntityView.getLocationInWindow(loc); + return loc[1] + currentEntityView.getHeight() * entitiesView.getScaleY(); } private TextPaintView createText(boolean select) { @@ -1148,7 +1157,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { int w = (int) (vw * currentCropState.cropPw * child.getScaleX() / currentCropState.cropScale); int h = (int) (vh * currentCropState.cropPh * child.getScaleY() / currentCropState.cropScale); float x = (float) Math.ceil((getMeasuredWidth() - w) / 2f) + transformX; - float y = (getMeasuredHeight() - actionBarHeight2 - AndroidUtilities.dp(48) + getAdditionalBottom() - h) / 2f + AndroidUtilities.dp(8) + status + transformY; + float y = (getMeasuredHeight() - emojiPadding - actionBarHeight2 - AndroidUtilities.dp(48) + getAdditionalBottom() - h) / 2f + AndroidUtilities.dp(8) + status + transformY; canvas.clipRect(Math.max(0, x), Math.max(0, y), Math.min(x + w, getMeasuredWidth()), Math.min(getMeasuredHeight(), y + h)); restore = true; @@ -1403,9 +1412,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { entitiesView.setScaleX(baseScale); entitiesView.setScaleY(baseScale); entitiesView.measure(MeasureSpec.makeMeasureSpec((int) paintingSize.width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) paintingSize.height, MeasureSpec.EXACTLY)); - if (currentEntityView != null) { - currentEntityView.updateSelectionView(); - } + updateEntitiesSelections(); selectionContainerView.measure(MeasureSpec.makeMeasureSpec((int) renderWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) renderHeight, MeasureSpec.EXACTLY)); measureChild(bottomLayout, widthMeasureSpec, heightMeasureSpec); measureChild(weightChooserView, widthMeasureSpec, heightMeasureSpec); @@ -1939,9 +1946,19 @@ public void setTransform(float scale, float trX, float trY, float imageWidth, fl view.setRotation(rotation); view.invalidate(); } + updateEntitiesSelections(); invalidate(); } + public void updateEntitiesSelections() { + for (int i = 0; i < entitiesView.getChildCount(); ++i) { + View child = entitiesView.getChildAt(i); + if (child == currentEntityView || child instanceof EntityView && ((EntityView) child).isSelectedProgress()) { + ((EntityView) child).updateSelectionView(); + } + } + } + @Override public List getMasks() { ArrayList result = null; @@ -2479,6 +2496,26 @@ private void showMenuForEntity(final EntityView entityView) { parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); } + if (entityView instanceof StickerView) { + TextView flipView = new TextView(getContext()); + flipView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + flipView.setBackgroundDrawable(Theme.getSelectorDrawable(false)); + flipView.setGravity(Gravity.CENTER_VERTICAL); + flipView.setEllipsize(TextUtils.TruncateAt.END); + flipView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(16), 0); + flipView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + flipView.setTag(2); + flipView.setText(LocaleController.getString("Flip", R.string.Flip)); + flipView.setOnClickListener(v -> { + ((StickerView) entityView).mirror(true); + + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + }); + parent.addView(flipView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + } + TextView duplicateView = new TextView(getContext()); duplicateView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); duplicateView.setBackgroundDrawable(Theme.getSelectorDrawable(false)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ReactionWidgetEntityView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ReactionWidgetEntityView.java new file mode 100644 index 00000000000..6982f1ddc04 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ReactionWidgetEntityView.java @@ -0,0 +1,377 @@ +package org.telegram.ui.Components.Paint.Views; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.RectF; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.Point; +import org.telegram.ui.Components.Reactions.ReactionImageHolder; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; +import org.telegram.ui.Components.Rect; +import org.telegram.ui.Components.Size; +import org.telegram.ui.Stories.StoryReactionWidgetBackground; + +import java.util.List; +import java.util.Objects; + +public class ReactionWidgetEntityView extends EntityView { + + Size baseSize; + StoryReactionWidgetBackground storyReactionWidgetBackground = new StoryReactionWidgetBackground(this); + StoryReactionWidgetBackground outBackground = new StoryReactionWidgetBackground(this); + ReactionImageHolder reactionHolder = new ReactionImageHolder(this); + ReactionImageHolder nextReactionHolder = new ReactionImageHolder(this); + ReactionsLayoutInBubble.VisibleReaction currentReaction; + AnimatedFloat progressToNext = new AnimatedFloat(this); + AnimatedFloat crossfadeBackgrounds = new AnimatedFloat(this); + boolean mirror; + private float drawScale = 1f; + + int filterColor; + + public ReactionWidgetEntityView(Context context, Point pos, Size baseSize) { + super(context, pos); + this.baseSize = baseSize; + + crossfadeBackgrounds.set(1f, true); + progressToNext.set(1f, true); + List availableReactions = MediaDataController.getInstance(UserConfig.selectedAccount).getReactionsList(); + reactionHolder.setVisibleReaction(currentReaction = ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(findHeartReaction(availableReactions))); + + updatePosition(); + } + + private String findHeartReaction(List availableReactions) { + for (int i = 0; i < availableReactions.size(); i++) { + if (availableReactions.get(i).title.equals("Red Heart")) { + return availableReactions.get(i).reaction; + } + } + return availableReactions.get(0).reaction; + } + + protected void updatePosition() { + float halfWidth = baseSize.width / 2.0f; + float halfHeight = baseSize.height / 2.0f; + setX(getPositionX() - halfWidth); + setY(getPositionY() - halfHeight); + updateSelectionView(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec((int) baseSize.width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) baseSize.height, MeasureSpec.EXACTLY)); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + int padding = getPadding(); + float crossfade = crossfadeBackgrounds.set(1f); + if (crossfade == 1f) { + outBackground = null; + } + canvas.save(); + canvas.scale(drawScale, drawScale, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); + if (outBackground != null) { + outBackground.setAlpha((int) (255 * (1f - crossfade))); + outBackground.setBounds(padding, padding, (int) baseSize.width - padding, (int) baseSize.height - padding); + outBackground.draw(canvas); + } + storyReactionWidgetBackground.setAlpha((int) (255 * crossfade)); + storyReactionWidgetBackground.setBounds(padding, padding, (int) baseSize.width - padding, (int) baseSize.height - padding); + storyReactionWidgetBackground.draw(canvas); + float imageSize = storyReactionWidgetBackground.getBounds().width() * 0.61f; + AndroidUtilities.rectTmp2.set( + (int) (storyReactionWidgetBackground.getBounds().centerX() - imageSize / 2f), + (int) (storyReactionWidgetBackground.getBounds().centerY() - imageSize / 2f), + (int) (storyReactionWidgetBackground.getBounds().centerX() + imageSize / 2f), + (int) (storyReactionWidgetBackground.getBounds().centerY() + imageSize / 2f) + ); + + float progress = progressToNext.set(1); + reactionHolder.setBounds(AndroidUtilities.rectTmp2); + nextReactionHolder.setBounds(AndroidUtilities.rectTmp2); + reactionHolder.setColor(storyReactionWidgetBackground.isDarkStyle() ? Color.WHITE : Color.BLACK); + + if (progress == 1) { + reactionHolder.draw(canvas); + } else { + canvas.save(); + canvas.scale(1f - progress, 1f - progress, AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.top); + nextReactionHolder.setAlpha(1f - progress); + nextReactionHolder.draw(canvas); + canvas.restore(); + + canvas.save(); + canvas.scale(progress, progress, AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.bottom); + reactionHolder.setAlpha(progress); + reactionHolder.draw(canvas); + canvas.restore(); + } + canvas.restore(); + } + + public int getPadding() { + return (int) ((baseSize.height - AndroidUtilities.dp(84)) / 2f); + } + + @Override + protected Rect getSelectionBounds() { + ViewGroup parentView = (ViewGroup) getParent(); + if (parentView == null) { + return new Rect(); + } + float scale = parentView.getScaleX(); + + float side = getMeasuredWidth() * (getScale() + 0.4f); + return new Rect((getPositionX() - side / 2.0f) * scale, (getPositionY() - side / 2.0f) * scale, side * scale, side * scale); + } + + @Override + protected SelectionView createSelectionView() { + return new StickerViewSelectionView(getContext()); + } + + public void setCurrentReaction(ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean animated) { + if (Objects.equals(currentReaction, visibleReaction)) { + return; + } + if (!animated) { + currentReaction = visibleReaction; + reactionHolder.setVisibleReaction(currentReaction); + invalidate(); + } else { + currentReaction = visibleReaction; + nextReactionHolder.setVisibleReaction(currentReaction); + ReactionImageHolder k = reactionHolder; + reactionHolder = nextReactionHolder; + nextReactionHolder = k; + progressToNext.set(0, true); + invalidate(); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + reactionHolder.onAttachedToWindow(true); + nextReactionHolder.onAttachedToWindow(true); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + reactionHolder.onAttachedToWindow(false); + nextReactionHolder.onAttachedToWindow(false); + } + + public ReactionsLayoutInBubble.VisibleReaction getCurrentReaction() { + return currentReaction; + } + + public void mirror(boolean animate) { + mirror = !mirror; + if (!animate) { + storyReactionWidgetBackground.setMirror(mirror, animate); + } else { + boolean[] mirrored = new boolean[] {false}; + ValueAnimator animator = ValueAnimator.ofFloat(0, 1f); + animator.addUpdateListener(animation -> { + float progress = (float) animation.getAnimatedValue(); + if (progress < 0.5f) { + setRotationY(90 * (progress / 0.5f)); + drawScale = 0.7f + 0.3f * (1f - (progress / 0.5f)); + invalidate(); + } else { + if (!mirrored[0]) { + mirrored[0] = true; + storyReactionWidgetBackground.setMirror(mirror, false); + } + progress -= 0.5f; + setRotationY(-90 * (1f - progress / 0.5f)); + drawScale = 0.7f + 0.3f * (progress / 0.5f); + invalidate(); + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!mirrored[0]) { + mirrored[0] = true; + storyReactionWidgetBackground.setMirror(mirror, false); + } + setRotationY(0); + drawScale = 1f; + } + }); + animator.setInterpolator(CubicBezierInterpolator.EASE_OUT); + animator.setDuration(350); + animator.start(); + } + } + + public void changeStyle(boolean animated) { + if (!animated) { + storyReactionWidgetBackground.nextStyle(); + } else { + outBackground = storyReactionWidgetBackground; + storyReactionWidgetBackground = new StoryReactionWidgetBackground(this); + if (!outBackground.isDarkStyle()) { + storyReactionWidgetBackground.nextStyle(); + } + storyReactionWidgetBackground.setMirror(mirror, false); + storyReactionWidgetBackground.updateShadowLayer(getScaleX()); + crossfadeBackgrounds.set(0, true); + } + invalidate(); + } + + public boolean isMirrored() { + return mirror; + } + + public boolean isDark() { + return storyReactionWidgetBackground.isDarkStyle(); + } + +// private void animateBounce() { +// AnimatorSet animatorSet = new AnimatorSet(); +// ValueAnimator inAnimator = ValueAnimator.ofFloat(1, 1.05f); +// inAnimator.setDuration(100); +// inAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); +// +// ValueAnimator outAnimator = ValueAnimator.ofFloat(1.05f, 1f); +// outAnimator.setDuration(250); +// outAnimator.setInterpolator(new OvershootInterpolator()); +// +// ValueAnimator.AnimatorUpdateListener updater = animation -> { +// bounceScale = (float) animation.getAnimatedValue(); +// invalidate(); +// }; +// setClipInParent(false); +// inAnimator.addUpdateListener(updater); +// outAnimator.addUpdateListener(updater); +// animatorSet.playSequentially(inAnimator, outAnimator); +// animatorSet.addListener(new AnimatorListenerAdapter() { +// @Override +// public void onAnimationEnd(Animator animation) { +// bounceScale = 1f; +// invalidate(); +// setClipInParent(true); +// } +// }); +// animatorSet.start(); +// +// if (animationRunnable != null) { +// AndroidUtilities.cancelRunOnUIThread(animationRunnable); +// animationRunnable.run(); +// animationRunnable = null; +// } +// } + + public class StickerViewSelectionView extends SelectionView { + + private RectF arcRect = new RectF(); + + public StickerViewSelectionView(Context context) { + super(context); + } + + @Override + protected int pointInsideHandle(float x, float y) { + float thickness = AndroidUtilities.dp(1.0f); + float radius = AndroidUtilities.dp(19.5f); + + float inset = radius + thickness; + float middle = inset + (getMeasuredHeight() - inset * 2) / 2.0f; + + if (x > inset - radius && y > middle - radius && x < inset + radius && y < middle + radius) { + return SELECTION_LEFT_HANDLE; + } else if (x > inset + (getMeasuredWidth() - inset * 2) - radius && y > middle - radius && x < inset + (getMeasuredWidth() - inset * 2) + radius && y < middle + radius) { + return SELECTION_RIGHT_HANDLE; + } + + float selectionRadius = getMeasuredWidth() / 2.0f; + + if (Math.pow(x - selectionRadius, 2) + Math.pow(y - selectionRadius, 2) < Math.pow(selectionRadius, 2)) { + return SELECTION_WHOLE_HANDLE; + } + + return 0; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int count = canvas.getSaveCount(); + + float alpha = getShowAlpha(); + if (alpha <= 0) { + return; + } else if (alpha < 1) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); + } + + float thickness = AndroidUtilities.dp(1.0f); + float radius = AndroidUtilities.dpf2(5.66f); + + float inset = radius + thickness + AndroidUtilities.dp(15); + float mainRadius = getMeasuredWidth() / 2 - inset; + + arcRect.set(inset, inset, inset + mainRadius * 2, inset + mainRadius * 2); + canvas.drawArc(arcRect, 0, 180, false, paint); + canvas.drawArc(arcRect, 180, 180, false, paint); + + canvas.drawCircle(inset, inset + mainRadius, radius, dotStrokePaint); + canvas.drawCircle(inset, inset + mainRadius, radius - AndroidUtilities.dp(1), dotPaint); + + canvas.drawCircle(inset + mainRadius * 2, inset + mainRadius, radius, dotStrokePaint); + canvas.drawCircle(inset + mainRadius * 2, inset + mainRadius, radius - AndroidUtilities.dp(1), dotPaint); + + canvas.restoreToCount(count); + } + } + + @Override + public boolean allowLongPressOnSelected() { + return true; + } + + @Override + public void setScaleX(float scaleX) { + if (getScaleX() != scaleX) { + super.setScaleX(scaleX); + storyReactionWidgetBackground.updateShadowLayer(scaleX); + invalidate(); + } + } + + @Override + protected float getMaxScale() { + return 1.8f; + } + + @Override + protected float getMinScale() { + return 0.5f; + } + + @Override + protected boolean allowHaptic() { + return false; + } +} 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 5b24da7d9cb..97119d0495d 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 @@ -3,6 +3,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.RectF; +import android.util.Log; import android.view.ViewGroup; import android.widget.FrameLayout; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java index 21620c73465..57e03ac113e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java @@ -34,6 +34,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -44,6 +45,9 @@ public class LimitPreviewView extends LinearLayout { + private float percent; + private final int premiumLimit; + private int currentValue; public int gradientTotalHeight; boolean wasAnimation; CounterView limitIcon; @@ -69,6 +73,10 @@ public class LimitPreviewView extends LinearLayout { private boolean isBoostsStyle; Theme.ResourcesProvider resourcesProvider; + private boolean animateIncrease; + private int animateIncreaseWidth; + float limitIconRotation; + public boolean isStatistic; public LimitPreviewView(@NonNull Context context, int icon, int currentValue, int premiumLimit, Theme.ResourcesProvider resourcesProvider) { @@ -79,8 +87,10 @@ public LimitPreviewView(@NonNull Context context, int icon, int currentValue, in public LimitPreviewView(@NonNull Context context, int icon, int currentValue, int premiumLimit, float inputPercent, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; - final float percent = MathUtils.clamp(inputPercent, 0.1f, 0.9f); + this.percent = MathUtils.clamp(inputPercent, 0.1f, 0.9f); this.icon = icon; + this.currentValue = currentValue; + this.premiumLimit = premiumLimit; setOrientation(VERTICAL); setClipChildren(false); setClipToPadding(false); @@ -88,7 +98,7 @@ public LimitPreviewView(@NonNull Context context, int icon, int currentValue, in setPadding(0, dp(16), 0, 0); limitIcon = new CounterView(context); - setIconValue(currentValue); + setIconValue(currentValue, false); limitIcon.setPadding(dp(24), dp(6), dp(24), dp(14)); addView(limitIcon, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.LEFT)); @@ -145,7 +155,11 @@ public LimitPreviewView(@NonNull Context context, int icon, int currentValue, in @Override protected void dispatchDraw(Canvas canvas) { if (isBoostsStyle) { - grayPaint.setColor(Theme.getColor(Theme.key_graySection, resourcesProvider)); + if (isStatistic) { + grayPaint.setColor(Theme.getColor(Theme.key_listSelector, resourcesProvider)); + } else { + grayPaint.setColor(Theme.getColor(Theme.key_graySection, resourcesProvider)); + } } else { grayPaint.setColor(Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider)); } @@ -200,16 +214,35 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) ); - final int minWidth2 = Math.max(premiumLayout.getMeasuredWidth(), dp(24) + premiumText.getMeasuredWidth() + (premiumCount.getVisibility() == View.VISIBLE ? dp(24) + premiumCount.getMeasuredWidth() : 0)); - width1 = (int) Utilities.clamp(width * percent, width - minWidth2, minWidth1); - defaultLayout.measure( - MeasureSpec.makeMeasureSpec(width1, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) - ); - premiumLayout.measure( - MeasureSpec.makeMeasureSpec(width - width1, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) - ); + if (isBoostsStyle) { + if (percent == 0) { + width1 = 0; + premiumCount.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + defaultText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + } else if (percent < 1f) { + float leftWidth = defaultLayout.getMeasuredWidth() - AndroidUtilities.dp(8); + float rightWidth = premiumLayout.getMeasuredWidth() - AndroidUtilities.dp(8); + float availableWidth = width - leftWidth - rightWidth; + width1 = (int) (leftWidth + availableWidth * percent); + premiumCount.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + defaultText.setTextColor(Color.WHITE); + } else { + width1 = width; + premiumCount.setTextColor(Color.WHITE); + defaultText.setTextColor(Color.WHITE); + } + } else { + final int minWidth2 = Math.max(premiumLayout.getMeasuredWidth(), dp(24) + premiumText.getMeasuredWidth() + (premiumCount.getVisibility() == View.VISIBLE ? dp(24) + premiumCount.getMeasuredWidth() : 0)); + width1 = (int) Utilities.clamp(width * percent, width - minWidth2, minWidth1); + defaultLayout.measure( + MeasureSpec.makeMeasureSpec(width1, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ); + premiumLayout.measure( + MeasureSpec.makeMeasureSpec(width - width1, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ); + } setMeasuredDimension(width, height); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -234,11 +267,12 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { addView(limitsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 30, 0, 0, 14, icon == 0 ? 0 : 12, 14, 0)); } - public void setIconValue(int currentValue) { + public void setIconValue(int currentValue, boolean animated) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append("d ").setSpan(new ColoredImageSpan(icon), 0, 1, 0); spannableStringBuilder.append(Integer.toString(currentValue)); - limitIcon.setText(spannableStringBuilder); + limitIcon.setText(spannableStringBuilder, animated); + limitIcon.requestLayout(); } private float getGlobalXOffset() { @@ -267,12 +301,18 @@ protected void dispatchDraw(Canvas canvas) { @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); - if (!wasAnimation && limitIcon != null && animationCanPlay && !premiumLocked) { + if (animateIncrease || (!wasAnimation && limitIcon != null && animationCanPlay && !premiumLocked)) { int padding = dp(14); - float fromX = 0; + boolean animateIncreaseFinal = animateIncrease; + animateIncrease = false; + float fromX = animateIncreaseFinal ? limitIcon.getTranslationX() : 0; float toX = padding + Math.max(width1, (getMeasuredWidth() - padding * 2) * position) - limitIcon.getMeasuredWidth() / 2f; float fromProgressCenter = 0.5f; float toProgressCenter = 0.5f; + if (toX < padding) { + toX = padding; + fromProgressCenter = toProgressCenter = 0f; + } if (toX > getMeasuredWidth() - padding - limitIcon.getMeasuredWidth()) { toX = getMeasuredWidth() - padding - limitIcon.getMeasuredWidth(); toProgressCenter = 1f; @@ -281,13 +321,20 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { limitIcon.setTranslationX(fromX); limitIcon.setPivotX(limitIcon.getMeasuredWidth() / 2f); limitIcon.setPivotY(limitIcon.getMeasuredHeight()); - limitIcon.setScaleX(0); - limitIcon.setScaleY(0); - limitIcon.createAnimationLayouts(); + if (!animateIncreaseFinal) { + limitIcon.setScaleX(0); + limitIcon.setScaleY(0); + limitIcon.createAnimationLayouts(); + } ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); float finalToX = toX; float finalToProgressCenter = toProgressCenter; + float toWidth = width1; + if (animateIncreaseFinal) { + width1 = animateIncreaseWidth; + } + float finalFromProgressCenter = fromProgressCenter; valueAnimator.addUpdateListener(animation -> { float v = (float) animation.getAnimatedValue(); float moveValue = Math.min(1f, v); @@ -296,25 +343,47 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { wasHaptic = true; limitIcon.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); } - limitIcon.setRotation((v - 1f) * 60); + limitIcon.setRotation(limitIconRotation + (v - 1f) * 60); } else { - limitIcon.setRotation(0); + limitIcon.setRotation(limitIconRotation); } limitIcon.setTranslationX(fromX * (1f - moveValue) + finalToX * moveValue); - float arrowCenter = fromProgressCenter * (1f - moveValue) + finalToProgressCenter * moveValue; + float arrowCenter = finalFromProgressCenter * (1f - moveValue) + finalToProgressCenter * moveValue; limitIcon.setArrowCenter(arrowCenter); float scale = Math.min(1, moveValue * 2f); - limitIcon.setScaleX(scale); - limitIcon.setScaleY(scale); + if (!animateIncreaseFinal) { + limitIcon.setScaleX(scale); + limitIcon.setScaleY(scale); + } else { + width1 = (int) AndroidUtilities.lerp(animateIncreaseWidth, toWidth, moveValue); + limitsContainer.invalidate(); + } limitIcon.setPivotX(limitIcon.getMeasuredWidth() * arrowCenter); }); valueAnimator.setInterpolator(new OvershootInterpolator()); - valueAnimator.setDuration(1000); - valueAnimator.setStartDelay(200); + if (animateIncreaseFinal) { + ValueAnimator valueAnimator1 = ValueAnimator.ofFloat(0, 1f); + valueAnimator1.addUpdateListener(animation -> { + float p = (float) animation.getAnimatedValue(); + float k = 0.5f; + float angle = -7; + limitIconRotation = p < k ? p / k * angle : angle * (1f - (p - k) / (1f - k)); + }); + valueAnimator1.setDuration(500); + valueAnimator1.start(); + valueAnimator.setDuration(600); + } else { + valueAnimator.setDuration(1000); + valueAnimator.setStartDelay(200); + } valueAnimator.start(); wasAnimation = true; + } else if (isBoostsStyle) { + limitIcon.setAlpha(1f); + limitIcon.setScaleX(1f); + limitIcon.setScaleY(1f); } else if (premiumLocked) { int padding = dp(14); float toX = padding + (getMeasuredWidth() - padding * 2) * 0.5f - limitIcon.getMeasuredWidth() / 2f; @@ -331,7 +400,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { limitIcon.setScaleY(1f); } limitIcon.setTranslationX(toX); - } else if (limitIcon != null){ + } else if (limitIcon != null) { limitIcon.setAlpha(0); } } @@ -342,14 +411,14 @@ public void setType(int type) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append("d ").setSpan(new ColoredImageSpan(icon), 0, 1, 0); spannableStringBuilder.append(UserConfig.getInstance(UserConfig.selectedAccount).isPremium() ? "4 GB" : "2 GB"); - limitIcon.setText(spannableStringBuilder); + limitIcon.setText(spannableStringBuilder, false); } premiumCount.setText("4 GB"); } else if (type == LimitReachedBottomSheet.TYPE_ADD_MEMBERS_RESTRICTED) { if (limitIcon != null) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append("d").setSpan(new ColoredImageSpan(icon), 0, 1, 0); - limitIcon.setText(spannableStringBuilder); + limitIcon.setText(spannableStringBuilder, false); } premiumCount.setText(""); } @@ -382,6 +451,41 @@ public void setPremiumLocked() { premiumLocked = true; } + public void setBoosts(TLRPC.TL_stories_boostsStatus boosts, boolean boosted) { + int k = boosts.current_level_boosts; + boolean isZeroLevelBoosts = boosts.current_level_boosts == boosts.boosts; + if ((isZeroLevelBoosts && boosted) || boosts.next_level_boosts == 0) { + percent = 1f; + defaultText.setText(LocaleController.formatString("BoostsLevel", R.string.BoostsLevel, boosts.level - 1)); + premiumCount.setText(LocaleController.formatString("BoostsLevel", R.string.BoostsLevel, boosts.level)); + } else { + percent = MathUtils.clamp((boosts.boosts - k) / (float) (boosts.next_level_boosts - k), 0, 1f); + defaultText.setText(LocaleController.formatString("BoostsLevel", R.string.BoostsLevel, boosts.level)); + premiumCount.setText(LocaleController.formatString("BoostsLevel", R.string.BoostsLevel, boosts.level + 1)); + } + setType(LimitReachedBottomSheet.TYPE_BOOSTS); + defaultCount.setVisibility(View.GONE); + premiumText.setVisibility(View.GONE); + + premiumCount.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + defaultText.setTextColor(Color.WHITE); + + + setIconValue(boosts.boosts, false); + isBoostsStyle = true; + } + + public void increaseCurrentValue(int value, int maxValue) { + currentValue++; + percent = MathUtils.clamp(value / (float) maxValue, 0f, 1f); + animateIncrease = true; + animateIncreaseWidth = width1; + + setIconValue(currentValue, true); + limitsContainer.requestLayout(); + requestLayout(); + } + private class CounterView extends View { Path path = new Path(); @@ -418,12 +522,14 @@ private void updatePath() { int h = getMeasuredHeight() - dp(8); float widthHalf = getMeasuredWidth() * arrowCenter; float x2 = Utilities.clamp(widthHalf + dp(8), getMeasuredWidth(), 0); - float x3 = Utilities.clamp(widthHalf + dp(10), getMeasuredWidth(), 0); + float x3 = Utilities.clamp(widthHalf + dp(10), getMeasuredWidth(), AndroidUtilities.dp(24)); + float x4 = Utilities.clamp(widthHalf - dp(24), getMeasuredWidth(), 0); + float x5 = Utilities.clamp(widthHalf - dp(8), getMeasuredWidth(), 0); path.rewind(); - path.moveTo(widthHalf - dp(24), h - h / 2f - dp(2)); - path.lineTo(widthHalf - dp(24), h); - path.lineTo(widthHalf - dp(8), h); + path.moveTo(x4, h - h / 2f - dp(2)); + path.lineTo(x4, h); + path.lineTo(x5, h); path.lineTo(widthHalf, h + dp(8)); if (arrowCenter < 0.7f) { path.lineTo(x2, h); @@ -476,7 +582,13 @@ protected void onDraw(Canvas canvas) { for (int i = 0; i < animatedLayouts.size(); i++) { AnimatedLayout animatedLayout = animatedLayouts.get(i); canvas.save(); - if (animatedLayout.direction) { + if (animatedLayout.replace) { + canvas.translate(x + animatedLayout.x, y + h * (animatedLayout.progress) - h * (1 - animatedLayout.staticLayouts.size())); + for (int j = 0; j < animatedLayout.staticLayouts.size(); j++) { + canvas.translate(0, -h); + animatedLayout.staticLayouts.get(j).draw(canvas); + } + } else if (animatedLayout.direction) { canvas.translate(x + animatedLayout.x, y - h * 10 * animatedLayout.progress + h * (10 - animatedLayout.staticLayouts.size())); for (int j = 0; j < animatedLayout.staticLayouts.size(); j++) { canvas.translate(0, h); @@ -506,6 +618,9 @@ public void setTranslationX(float translationX) { void createAnimationLayouts() { animatedLayouts.clear(); + if (isBoostsStyle && currentValue == 0) { + return; + } SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text); boolean direction = true; @@ -561,6 +676,55 @@ public void onAnimationEnd(Animator animation) { } } + + void createAnimationLayoutsDiff(CharSequence oldText) { + animatedLayouts.clear(); + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text); + int directionCount = 0; + for (int i = text.length() - 1; i >= 0; i--) { + char oldChar = i < oldText.length() ? oldText.charAt(i) : ' '; + if (oldChar != text.charAt(i) && Character.isDigit(text.charAt(i))) { + AnimatedLayout animatedLayout = new AnimatedLayout(); + animatedLayouts.add(animatedLayout); + animatedLayout.x = textLayout.getSecondaryHorizontal(i); + animatedLayout.replace = true; + if (directionCount >= 1) { + directionCount = 0; + } + directionCount++; + + StaticLayout staticLayoutOld = new StaticLayout("" + oldChar, textPaint, (int) textWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + animatedLayout.staticLayouts.add(staticLayoutOld); + + StaticLayout staticLayout = new StaticLayout("" + text.charAt(i), textPaint, (int) textWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + animatedLayout.staticLayouts.add(staticLayout); + spannableStringBuilder.setSpan(new EmptyStubSpan(), i, i + 1, 0); + } + } + animatedStableLayout = new StaticLayout(spannableStringBuilder, textPaint, (int) textWidth + dp(12), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + for (int i = 0; i < animatedLayouts.size(); i++) { + animationInProgress = true; + AnimatedLayout layout = animatedLayouts.get(i); + layout.valueAnimator = ValueAnimator.ofFloat(0, 1f); + layout.valueAnimator.addUpdateListener(animation -> { + layout.progress = (float) animation.getAnimatedValue(); + invalidate(); + }); + layout.valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + layout.valueAnimator = null; + checkAnimationComplete(); + } + }); + layout.valueAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); + layout.valueAnimator.setDuration(250); + layout.valueAnimator.setStartDelay((animatedLayouts.size() - 1 - i) * 60L); + layout.valueAnimator.start(); + } + } + + private void checkAnimationComplete() { for (int i = 0; i < animatedLayouts.size(); i++) { if (animatedLayouts.get(i).valueAnimator != null) { @@ -572,8 +736,14 @@ private void checkAnimationComplete() { invalidate(); } - public void setText(CharSequence text) { - this.text = text; + public void setText(CharSequence text, boolean animated) { + if (!animated) { + this.text = text; + } else { + CharSequence oldText = this.text; + this.text = text; + createAnimationLayoutsDiff(oldText); + } } public void setArrowCenter(float v) { @@ -585,6 +755,7 @@ public void setArrowCenter(float v) { } private class AnimatedLayout { + public boolean replace; ArrayList staticLayouts = new ArrayList<>(); float progress; public boolean direction; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java index 95adcbaca93..15f1d744ed2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java @@ -1,26 +1,41 @@ package org.telegram.ui.Components.Premium; +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.os.Build; import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.transition.TransitionManager; +import android.transition.TransitionSet; +import android.transition.TransitionValues; +import android.transition.Visibility; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChannelBoostsController; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.LocaleController; @@ -37,14 +52,22 @@ import org.telegram.ui.Cells.GroupCreateUserCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BottomSheetWithRecyclerListView; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ColoredImageSpan; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.FireworksOverlay; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.ScaleStateListAnimator; +import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.Stories.ChannelBoostUtilities; import java.util.ArrayList; import java.util.HashSet; @@ -71,10 +94,16 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { public static final int TYPE_STORIES_WEEK = 15; public static final int TYPE_STORIES_MONTH = 16; public static final int TYPE_BOOSTS = 17; + public static final int TYPE_BOOSTS_FOR_POSTING = 18; + public static final int TYPE_BOOSTS_FOR_USERS = 19; private boolean canSendLink; private int linkRow = -1; private long dialogId; + private TLRPC.TL_stories_boostsStatus boostsStatus; + private ChannelBoostsController.CanApplyBoost canApplyBoost; + private HeaderView headerView; + private boolean isCurrentChat; public static String limitTypeToServerString(int type) { switch (type) { @@ -135,6 +164,8 @@ public static String limitTypeToServerString(int type) { LimitParams limitParams; private boolean isVeryLargeFile; private TLRPC.Chat fromChat; + FireworksOverlay fireworksOverlay; + Runnable statisticClickRunnable; public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, int currentAccount, Theme.ResourcesProvider resourcesProvider) { super(fragment, false, hasFixedSize(type), false, resourcesProvider); @@ -150,6 +181,10 @@ public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, loadInactiveChannels(); } updatePremiumButtonText(); + if (type == TYPE_BOOSTS_FOR_USERS) { + fireworksOverlay = new FireworksOverlay(getContext()); + container.addView(fireworksOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } } @Override @@ -209,6 +244,125 @@ protected void onDraw(Canvas canvas) { if (type == TYPE_ADD_MEMBERS_RESTRICTED) { return; } + if (type == TYPE_BOOSTS_FOR_USERS) { + canApplyBoost.checkTime(); + if (!UserConfig.getInstance(currentAccount).isPremium()) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("PremiumNeeded", R.string.PremiumNeeded)); + builder.setSubtitle(AndroidUtilities.replaceTags(LocaleController.getString("PremiumNeededForBoosting", R.string.PremiumNeededForBoosting))); + builder.setPositiveButton(LocaleController.getString("CheckPhoneNumberYes", R.string.CheckPhoneNumberYes), (dialog, which) -> { + PremiumFeatureBottomSheet featureBottomSheet = new PremiumFeatureBottomSheet(parentFragment, PremiumPreviewFragment.PREMIUM_FEATURE_STORIES, false); + parentFragment.showDialog(featureBottomSheet); + LimitReachedBottomSheet.this.dismiss(); + dialog.dismiss(); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> dialog.dismiss()); + builder.show(); + } else if (canApplyBoost.canApply && canApplyBoost.replaceDialogId == 0) { + boostChannel(); + } else if (canApplyBoost.giftedPremium) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("CantBoostWithGiftedPremium", R.string.CantBoostWithGiftedPremium)); + builder.setSubtitle(AndroidUtilities.replaceTags(LocaleController.formatString("CantBoostWithGiftedPremiumDescription ", R.string.CantBoostWithGiftedPremiumDescription))); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + dialog.dismiss(); + }); + builder.show(); + } else if (canApplyBoost.canApply) { + FrameLayout frameLayout = new FrameLayout(getContext()); + BackupImageView fromAvatar = new BackupImageView(getContext()); + fromAvatar.setRoundRadius(AndroidUtilities.dp(30)); + frameLayout.addView(fromAvatar, LayoutHelper.createFrame(60, 60)); + frameLayout.setClipChildren(false); + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Theme.getColor(Theme.key_dialogBackground)); + Drawable boostDrawable = ContextCompat.getDrawable(getContext(), R.drawable.filled_limit_boost); + View boostIcon = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + float cx = getMeasuredWidth() / 2f; + float cy = getMeasuredHeight() / 2f; + canvas.drawCircle(cx, cy, getMeasuredWidth() / 2f, paint); + PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, getMeasuredWidth(), getMeasuredHeight(), -AndroidUtilities.dp(10), 0); + canvas.drawCircle(cx, cy, getMeasuredWidth() / 2f - AndroidUtilities.dp(2), PremiumGradient.getInstance().getMainGradientPaint()); + float iconSizeHalf = AndroidUtilities.dp(18) / 2f; + boostDrawable.setBounds( + (int) (cx - iconSizeHalf), + (int) (cy - iconSizeHalf), + (int) (cx + iconSizeHalf), + (int) (cy + iconSizeHalf) + ); + boostDrawable.draw(canvas); + } + }; + frameLayout.addView(boostIcon, LayoutHelper.createFrame(28, 28, 0, 34, 34, 0, 0)); + + ImageView imageView = new ImageView(getContext()); + imageView.setImageResource(R.drawable.msg_arrow_avatar); + imageView.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon)); + frameLayout.addView(imageView, LayoutHelper.createFrame(24, 24, Gravity.CENTER)); + + BackupImageView toAvatar = new BackupImageView(getContext()); + toAvatar.setRoundRadius(AndroidUtilities.dp(30)); + frameLayout.addView(toAvatar, LayoutHelper.createFrame(60, 60, 0, 60 + 36, 0, 0, 0)); + FrameLayout containerLayout = new FrameLayout(getContext()); + containerLayout.addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 60, Gravity.CENTER_HORIZONTAL)); + containerLayout.setClipChildren(false); + TextView textView = new TextView(context); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + textView.setLetterSpacing(0.025f); + } + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + containerLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 24, 80, 24, 0)); + + AvatarDrawable fromAvatarDrawable = new AvatarDrawable(); + TLRPC.Chat fromChat = MessagesController.getInstance(currentAccount).getChat(-canApplyBoost.replaceDialogId); + fromAvatarDrawable.setInfo(fromChat); + fromAvatar.setForUserOrChat(fromChat, fromAvatarDrawable); + + AvatarDrawable toAvatarDrawable = new AvatarDrawable(); + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + toAvatarDrawable.setInfo(chat); + toAvatar.setForUserOrChat(chat, toAvatarDrawable); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setView(containerLayout); + textView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("ReplaceBoostChannelDescription", R.string.ReplaceBoostChannelDescription,fromChat.title, chat.title))); + builder.setPositiveButton(LocaleController.getString("Replace", R.string.Replace), (dialog, which) -> { + dialog.dismiss(); + boostChannel(); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> dialog.dismiss()); + builder.show(); + } else if (canApplyBoost.floodWait != 0) { + String timeString; + int time = canApplyBoost.floodWait; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else if (time < 60 * 60){ + timeString = LocaleController.formatPluralString("Minutes", time / 60); + } else if (time / 60 / 60 > 2) { + timeString = LocaleController.formatPluralString("Hours", time / 60 / 60); + } else { + timeString = LocaleController.formatPluralString("Hours", time / 60 / 60) + " " + LocaleController.formatPluralString("Minutes", time % 60); + } + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("CantBoostTooOften", R.string.CantBoostTooOften)); + builder.setSubtitle(AndroidUtilities.replaceTags(LocaleController.formatString("CantBoostTooOftenDescription", R.string.CantBoostTooOftenDescription, timeString))); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + dialog.dismiss(); + }); + builder.show(); + } + return; + } + if (type == TYPE_BOOSTS_FOR_POSTING) { + AndroidUtilities.addToClipboard(getBoostLink()); + dismiss(); + return; + } if (UserConfig.getInstance(currentAccount).isPremium() || MessagesController.getInstance(currentAccount).premiumLocked || isVeryLargeFile) { dismiss(); return; @@ -226,6 +380,10 @@ protected void onDraw(Canvas canvas) { dismiss(); }); premiumButtonView.overlayTextView.setOnClickListener(v -> { + if (type == TYPE_BOOSTS_FOR_USERS) { + dismiss(); + return; + } if (type == TYPE_ADD_MEMBERS_RESTRICTED) { if (selectedChats.isEmpty()) { dismiss(); @@ -246,6 +404,49 @@ protected void onDraw(Canvas canvas) { enterAnimator = new RecyclerItemsEnterAnimator(recyclerListView, true); } + private void boostChannel() { + TransitionSet transitionSet = new TransitionSet(); + transitionSet.addTransition(new Visibility() { + @Override + public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { + AnimatorSet set = new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1f), + ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, AndroidUtilities.dp(20), 0) + ); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + return set; + } + + @Override + public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { + AnimatorSet set = new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofFloat(view, View.ALPHA, view.getAlpha(), 0f), + ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0, -AndroidUtilities.dp(20)) + ); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + return set; + } + }); + transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER); + TransitionManager.beginDelayedTransition(headerView, transitionSet); + MessagesController.getInstance(currentAccount).getBoostsController().applyBoost(dialogId); + limitPreviewView.increaseCurrentValue((boostsStatus.boosts + 1) - boostsStatus.next_level_boosts * boostsStatus.level, boostsStatus.next_level_boosts - boostsStatus.next_level_boosts * boostsStatus.level); + boostsStatus.boosts++; + if (boostsStatus.next_level_boosts == boostsStatus.boosts) { + boostsStatus.level += 1; + boostsStatus.current_level_boosts = boostsStatus.boosts; + } + canApplyBoost.alreadyActive = true; + headerView.recreateTitleAndDescription(); + headerView.title.setText(getBoostsTitleString()); + headerView.description.setText(AndroidUtilities.replaceTags(getBoostsDescriptionString())); + updateButton(); + fireworksOverlay.start(); + fireworksOverlay.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } + private void sendInviteMessages() { String link = null; TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(fromChat.id); @@ -267,7 +468,7 @@ private void sendInviteMessages() { } AndroidUtilities.runOnUIThread(() -> { BulletinFactory factory = BulletinFactory.global(); - if (factory != null) { + if (factory != null) { if (selectedChats.size() == 1) { TLRPC.User user = (TLRPC.User) selectedChats.iterator().next(); factory.createSimpleBulletin(R.raw.voip_invite, @@ -284,7 +485,14 @@ private void sendInviteMessages() { } public void updatePremiumButtonText() { - if (UserConfig.getInstance(currentAccount).isPremium() || MessagesController.getInstance(currentAccount).premiumLocked || isVeryLargeFile) { + if (type == TYPE_BOOSTS_FOR_USERS) { + premiumButtonView.buttonTextView.setText(LocaleController.getString("BoostChannel", R.string.BoostChannel)); + } else if (type == TYPE_BOOSTS_FOR_POSTING) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("d "); + spannableStringBuilder.setSpan(new ColoredImageSpan(R.drawable.msg_copy_filled), 0, 1, 0); + spannableStringBuilder.append(LocaleController.getString("CopyLink", R.string.CopyLink)); + premiumButtonView.buttonTextView.setText(spannableStringBuilder); + } else if (UserConfig.getInstance(currentAccount).isPremium() || MessagesController.getInstance(currentAccount).premiumLocked || isVeryLargeFile) { premiumButtonView.buttonTextView.setText(LocaleController.getString("OK", R.string.OK)); premiumButtonView.hideIcon(); } else { @@ -293,9 +501,9 @@ public void updatePremiumButtonText() { if (limitParams.defaultLimit + 1 == limitParams.premiumLimit) { premiumButtonView.setIcon(R.raw.addone_icon); } else if ( - limitParams.defaultLimit != 0 && limitParams.premiumLimit != 0 && - limitParams.premiumLimit / (float) limitParams.defaultLimit >= 1.6f && - limitParams.premiumLimit / (float) limitParams.defaultLimit <= 2.5f + limitParams.defaultLimit != 0 && limitParams.premiumLimit != 0 && + limitParams.premiumLimit / (float) limitParams.defaultLimit >= 1.6f && + limitParams.premiumLimit / (float) limitParams.defaultLimit <= 2.5f ) { premiumButtonView.setIcon(R.raw.double_icon); } else { @@ -339,7 +547,13 @@ private void leaveFromSelectedGroups() { } private void updateButton() { - if (type == TYPE_ADD_MEMBERS_RESTRICTED) { + if (type == TYPE_BOOSTS_FOR_USERS) { + if (canApplyBoost.alreadyActive) { + premiumButtonView.setOverlayText(LocaleController.getString("OK", R.string.OK), true, true); + } else { + premiumButtonView.clearOverlayText(); + } + } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { premiumButtonView.checkCounterView(); if (!canSendLink) { premiumButtonView.setOverlayText(LocaleController.getString("Close", R.string.Close), true, true); @@ -369,7 +583,7 @@ private static boolean hasFixedSize(int type) { if (type == TYPE_PIN_DIALOGS || type == TYPE_FOLDERS || type == TYPE_CHATS_IN_FOLDER || type == TYPE_LARGE_FILE || type == TYPE_ACCOUNTS || type == TYPE_FOLDER_INVITES || type == TYPE_SHARED_FOLDERS || type == TYPE_STORIES_COUNT || type == TYPE_STORIES_WEEK || - type == TYPE_STORIES_MONTH) { + type == TYPE_STORIES_MONTH || type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_USERS) { return true; } return false; @@ -403,21 +617,35 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int case 7: FrameLayout frameLayout = new FrameLayout(getContext()); TextView linkView = new TextView(context); - linkView.setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(13), AndroidUtilities.dp(40), AndroidUtilities.dp(13)); + linkView.setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(13), AndroidUtilities.dp(50), AndroidUtilities.dp(13)); linkView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); linkView.setEllipsize(TextUtils.TruncateAt.MIDDLE); linkView.setSingleLine(true); frameLayout.addView(linkView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 11, 0, 11, 0)); linkView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), Theme.getColor(Theme.key_graySection, resourcesProvider), ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_listSelector, resourcesProvider), (int) (255 * 0.3f)))); linkView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); - + linkView.setOnClickListener(v -> { + AndroidUtilities.addToClipboard(getBoostLink()); + }); + if (statisticClickRunnable != null) { + ImageView imageView = new ImageView(getContext()); + imageView.setImageResource(R.drawable.msg_stats); + imageView.setColorFilter(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + imageView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + imageView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(20), 0, ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_listSelector, resourcesProvider), (int) (255 * 0.3f)))); + frameLayout.addView(imageView, LayoutHelper.createFrame(40, 40 ,Gravity.RIGHT | Gravity.CENTER_VERTICAL, 15, 0, 15, 0)); + imageView.setOnClickListener(v -> { + statisticClickRunnable.run(); + dismiss(); + }); + } linkView.setText(getBoostLink()); linkView.setGravity(Gravity.CENTER); view = frameLayout; break; default: case 0: - view = new HeaderView(context); + view = headerView = new HeaderView(context); break; case 1: view = new AdminedChannelCell(context, new View.OnClickListener() { @@ -532,8 +760,7 @@ public int getItemCount() { } private String getBoostLink() { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - return "https://" + ChatObject.getPublicUsername(chat) +"?boost"; + return ChannelBoostUtilities.createLink(currentAccount, dialogId); } public void setCurrentValue(int currentValue) { @@ -561,8 +788,25 @@ public void setDialogId(long dialogId) { this.dialogId = dialogId; } + public void setBoostsStats(TLRPC.TL_stories_boostsStatus boostsStatus, boolean isCurrentChat) { + this.boostsStatus = boostsStatus; + this.isCurrentChat = isCurrentChat; + } + + public void setCanApplyBoost(ChannelBoostsController.CanApplyBoost canApplyBoost) { + this.canApplyBoost = canApplyBoost; + updateButton(); + } + + public void showStatisticButtonInLink(Runnable runnable) { + this.statisticClickRunnable = runnable; + } + private class HeaderView extends LinearLayout { + TextView title; + TextView description; + @SuppressLint("SetTextI18n") public HeaderView(Context context) { super(context); @@ -573,7 +817,14 @@ public HeaderView(Context context) { int icon = limitParams.icon; String descriptionStr; boolean premiumLocked = MessagesController.getInstance(currentAccount).premiumLocked; - if (type == TYPE_ADD_MEMBERS_RESTRICTED) { + if (type == TYPE_BOOSTS_FOR_USERS) { + descriptionStr = getBoostsDescriptionString(); + } else if (type == TYPE_BOOSTS_FOR_POSTING) { + descriptionStr = LocaleController.formatString( + "ChannelNeedBoostsDescription", R.string.ChannelNeedBoostsDescription, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts, boostsStatus.next_level_boosts) + ); + } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { premiumLocked = true; if (!canSendLink) { if (ChatObject.isChannelAndNotMegaGroup(fromChat)) { @@ -654,21 +905,31 @@ public HeaderView(Context context) { percent = defaultLimit / (float) premiumLimit; + if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_USERS) { + currentValue = 0; + } + limitPreviewView = new LimitPreviewView(context, icon, currentValue, premiumLimit, percent, resourcesProvider); - limitPreviewView.setBagePosition(position); - limitPreviewView.setType(type); - limitPreviewView.defaultCount.setVisibility(View.GONE); - if (premiumLocked) { - limitPreviewView.setPremiumLocked(); + if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_USERS) { + if (boostsStatus != null) { + limitPreviewView.setBoosts(boostsStatus, canApplyBoost != null && canApplyBoost.alreadyActive); + } } else { - if (UserConfig.getInstance(currentAccount).isPremium() || isVeryLargeFile) { - limitPreviewView.premiumCount.setVisibility(View.GONE); - if (type == TYPE_LARGE_FILE) { - limitPreviewView.defaultCount.setText("2 GB"); - } else { - limitPreviewView.defaultCount.setText(Integer.toString(defaultLimit)); + limitPreviewView.setBagePosition(position); + limitPreviewView.setType(type); + limitPreviewView.defaultCount.setVisibility(View.GONE); + if (premiumLocked) { + limitPreviewView.setPremiumLocked(); + } else { + if (UserConfig.getInstance(currentAccount).isPremium() || isVeryLargeFile) { + limitPreviewView.premiumCount.setVisibility(View.GONE); + if (type == TYPE_LARGE_FILE) { + limitPreviewView.defaultCount.setText("2 GB"); + } else { + limitPreviewView.defaultCount.setText(Integer.toString(defaultLimit)); + } + limitPreviewView.defaultCount.setVisibility(View.VISIBLE); } - limitPreviewView.defaultCount.setVisibility(View.VISIBLE); } } @@ -676,12 +937,15 @@ public HeaderView(Context context) { limitPreviewView.setDelayedAnimation(); } - addView(limitPreviewView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, 0, 0)); - TextView title = new TextView(context); + title = new TextView(context); title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - if (type == TYPE_ADD_MEMBERS_RESTRICTED) { + if (type == TYPE_BOOSTS_FOR_USERS) { + title.setText(getBoostsTitleString()); + } else if (type == TYPE_BOOSTS_FOR_POSTING) { + title.setText(LocaleController.getString("BoostingEnableStories", R.string.BoostingEnableStories)); + } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { if (canSendLink) { title.setText(LocaleController.getString("ChannelInviteViaLink", R.string.ChannelInviteViaLink)); } else { @@ -694,9 +958,35 @@ public HeaderView(Context context) { } title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + title.setGravity(Gravity.CENTER); addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, premiumLocked ? 8 : 22, 0, 10)); - TextView description = new TextView(context); + if (type == TYPE_BOOSTS_FOR_USERS && !isCurrentChat) { + FrameLayout frameLayout = new FrameLayout(getContext()); + frameLayout.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(14), Theme.getColor(Theme.key_windowBackgroundGray))); + BackupImageView backupImageView = new BackupImageView(getContext()); + backupImageView.setRoundRadius(AndroidUtilities.dp(14)); + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + AvatarDrawable avatarDrawable = new AvatarDrawable(); + avatarDrawable.setInfo(chat); + backupImageView.setForUserOrChat(chat, avatarDrawable); + frameLayout.addView(backupImageView, LayoutHelper.createFrame(28, 28)); + TextView textView = new TextView(getContext()); + textView.setText(chat.title); + textView.setSingleLine(true); + textView.setMaxLines(1); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 36, 0, 8, 0)); + + addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 28, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 12)); + ScaleStateListAnimator.apply(frameLayout); + frameLayout.setOnClickListener(v -> { + getBaseFragment().presentFragment(ChatActivity.of(dialogId)); + dismiss(); + }); + } + description = new TextView(context); description.setText(AndroidUtilities.replaceTags(descriptionStr)); description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); description.setGravity(Gravity.CENTER_HORIZONTAL); @@ -705,6 +995,86 @@ public HeaderView(Context context) { updatePremiumButtonText(); } + + public void recreateTitleAndDescription() { + int titleIndex = indexOfChild(title); + int descriptionIndex = indexOfChild(description); + removeView(title); + + title = new TextView(getContext()); + title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + title.setGravity(Gravity.CENTER); + addView(title, titleIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 22, 0, 10)); + + removeView(description); + description = new TextView(getContext()); + description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + description.setGravity(Gravity.CENTER_HORIZONTAL); + description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + addView(description, descriptionIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, 0, 24, 24)); + } + } + + private String getBoostsTitleString() { + if (boostsStatus.level > 0 && !canApplyBoost.alreadyActive) { + return LocaleController.getString("HelpUpgradeChannel", R.string.HelpUpgradeChannel); + } else if (boostsStatus.next_level_boosts == 0) { + return LocaleController.formatString("BoostsMaxLevelReached", R.string.BoostsMaxLevelReached); + } else if (isCurrentChat) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (canApplyBoost.alreadyActive) { + return LocaleController.formatString("YouBoostedChannel2", R.string.YouBoostedChannel2, chat.title); + } else { + return LocaleController.formatString("BoostingEnableStoriesForChannel2", R.string.BoostingEnableStoriesForChannel2, chat.title); + } + } else { + if (canApplyBoost.alreadyActive) { + return LocaleController.getString("YouBoostedChannel", R.string.YouBoostedChannel); + } else { + return LocaleController.getString("BoostingEnableStoriesForChannel", R.string.BoostingEnableStoriesForChannel); + } + } + } + + private String getBoostsDescriptionString() { + boolean isZeroBoostsForNextLevel = boostsStatus.boosts == boostsStatus.current_level_boosts; + if (isZeroBoostsForNextLevel && canApplyBoost.alreadyActive) { + if (boostsStatus.level == 1) { + return LocaleController.formatString("ChannelBoostsJustReachedLevel1", R.string.ChannelBoostsJustReachedLevel1); + } else { + return LocaleController.formatString("ChannelBoostsJustReachedLevelNext", R.string.ChannelBoostsJustReachedLevelNext, + boostsStatus.level, + LocaleController.formatPluralString("BoostStories", boostsStatus.level)); + } + } else { + if (canApplyBoost.alreadyActive) { + if (boostsStatus.level == 0) { + return LocaleController.formatString( + "ChannelNeedBoostsAlreadyBoostedDescriptionLevel1", R.string.ChannelNeedBoostsAlreadyBoostedDescriptionLevel1, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) + ); + } else { + return LocaleController.formatString("ChannelNeedBoostsDescriptionLevelNext", R.string.ChannelNeedBoostsDescriptionLevelNext, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts), + LocaleController.formatPluralString("BoostStories", boostsStatus.level) + ); + } + } else { + if (boostsStatus.level == 0) { + return LocaleController.formatString( + "ChannelNeedBoostsDescriptionLevel1", R.string.ChannelNeedBoostsDescriptionLevel1, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) + ); + } else { + return LocaleController.formatString("ChannelNeedBoostsDescriptionLevelNext", R.string.ChannelNeedBoostsDescriptionLevelNext, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts), + LocaleController.formatPluralString("BoostStories", boostsStatus.level) + ); + } + } + } } private static LimitParams getLimitParams(int type, int currentAccount) { @@ -800,6 +1170,13 @@ private static LimitParams getLimitParams(int type, int currentAccount) { limitParams.descriptionStr = LocaleController.formatString("LimitReachedStoriesMonthly", R.string.LimitReachedStoriesMonthly, limitParams.defaultLimit, limitParams.premiumLimit); limitParams.descriptionStrPremium = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.premiumLimit); limitParams.descriptionStrLocked = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.defaultLimit); + } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_USERS) { + limitParams.defaultLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitDefault; + limitParams.premiumLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitPremium; + limitParams.icon = R.drawable.filled_limit_boost; + limitParams.descriptionStr = LocaleController.formatString("LimitReachedStoriesMonthly", R.string.LimitReachedStoriesMonthly, limitParams.defaultLimit, limitParams.premiumLimit); + limitParams.descriptionStrPremium = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.premiumLimit); + limitParams.descriptionStrLocked = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.defaultLimit); } return limitParams; } @@ -833,7 +1210,7 @@ private void loadAdminedChannels() { } int currentValue = Math.max(chats.size(), limitParams.defaultLimit); - limitPreviewView.setIconValue(currentValue); + limitPreviewView.setIconValue(currentValue, false); limitPreviewView.setBagePosition(currentValue / (float) limitParams.premiumLimit); limitPreviewView.startDelayedAnimation(); })); @@ -868,6 +1245,9 @@ private void updateRows() { } } } + if (type == TYPE_BOOSTS_FOR_POSTING) { + linkRow = rowCount++; + } notifyDataSetChanged(); } @@ -976,7 +1356,7 @@ private void loadInactiveChannels() { } int currentValue = Math.max(inactiveChats.size(), limitParams.defaultLimit); if (limitPreviewView != null) { - limitPreviewView.setIconValue(currentValue); + limitPreviewView.setIconValue(currentValue, false); limitPreviewView.setBagePosition(currentValue / (float) limitParams.premiumLimit); limitPreviewView.startDelayedAnimation(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java index 7d94d33d6cb..68d1f2347e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java @@ -1365,15 +1365,23 @@ public int getNextFrame(Bitmap bitmap) { } private int rawBackgroundBitmapFrame = -1; - public void drawFrame(Canvas canvas, int frame) { - if (rawBackgroundBitmapFrame != frame || backgroundBitmap == null) { - if (backgroundBitmap == null) { - backgroundBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + private Bitmap rawBackgroundBitmap; + + public void cacheFrame(int frame) { + if (rawBackgroundBitmapFrame != frame || rawBackgroundBitmap == null) { + if (rawBackgroundBitmap == null) { + rawBackgroundBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); } - int result = getFrame(nativePtr, rawBackgroundBitmapFrame = frame, backgroundBitmap, width, height, backgroundBitmap.getRowBytes(), true); + int result = getFrame(nativePtr, rawBackgroundBitmapFrame = frame, rawBackgroundBitmap, width, height, rawBackgroundBitmap.getRowBytes(), true); + } + } + + public void drawFrame(Canvas canvas, int frame) { + cacheFrame(frame); + if (rawBackgroundBitmap != null) { + AndroidUtilities.rectTmp2.set(0, 0, width, height); + canvas.drawBitmap(rawBackgroundBitmap, AndroidUtilities.rectTmp2, getBounds(), getPaint()); } - AndroidUtilities.rectTmp2.set(0, 0, width, height); - canvas.drawBitmap(backgroundBitmap, AndroidUtilities.rectTmp2, getBounds(), getPaint()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java index bfda46e4562..e30d22e70b6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java @@ -342,19 +342,21 @@ public void setSelectedMessages(List messages) { private void animateVisible(boolean visible) { if (visible) { - currentPrimaryObject = findPrimaryObject(); - checkCreateReactionsLayout(); - invalidatePosition(false); - setVisibility(VISIBLE); - if (reactionsContainerLayout.isEnabled()) { - messageSet = true; - reactionsContainerLayout.setMessage(currentPrimaryObject, parentFragment.getCurrentChatInfo()); - reactionsContainerLayout.startEnterAnimation(false); - } else { - messageSet = false; - reactionsContainerLayout.setTransitionProgress(1f); - } + post(() -> { + currentPrimaryObject = findPrimaryObject(); + checkCreateReactionsLayout(); + invalidatePosition(false); + + if (reactionsContainerLayout.isEnabled()) { + messageSet = true; + reactionsContainerLayout.setMessage(currentPrimaryObject, parentFragment.getCurrentChatInfo()); + reactionsContainerLayout.startEnterAnimation(false); + } else { + messageSet = false; + reactionsContainerLayout.setTransitionProgress(1f); + } + }); } else { messageSet = false; ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(150); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java index 377fcbefe37..74295e18a62 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java @@ -258,10 +258,10 @@ public void onRecentCleared() { containerView.addView(selectAnimatedEmojiDialog, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, 0)); windowView.addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 16, 16, 16, 16)); windowView.setClipChildren(false); - if (type == TYPE_STORY) { + if (type == TYPE_STORY || (reactionsContainerLayout.getDelegate() != null && reactionsContainerLayout.getDelegate().drawBackground())) { selectAnimatedEmojiDialog.setBackgroundDelegate((canvas, left, top, right, bottom, x, y) -> { AndroidUtilities.rectTmp.set(left, top, right, bottom); - reactionsContainerLayout.getDelegate().drawRoundRect(canvas, AndroidUtilities.rectTmp, 0, containerView.getX() + x, containerView.getY() - AndroidUtilities.statusBarHeight + y); + reactionsContainerLayout.getDelegate().drawRoundRect(canvas, AndroidUtilities.rectTmp, 0, containerView.getX() + x, getBlurOffset() + y, 255,true); }); } if (attachToParent) { @@ -715,7 +715,7 @@ public ContainerView(@NonNull Context context) { @Override public void invalidate() { super.invalidate(); - if (type == TYPE_STORY) { + if (type == TYPE_STORY || (reactionsContainerLayout != null && reactionsContainerLayout.getDelegate() != null && reactionsContainerLayout.getDelegate().drawBackground())) { selectAnimatedEmojiDialog.invalidateSearchBox(); } } @@ -759,8 +759,8 @@ protected void dispatchDraw(Canvas canvas) { transitionReactions.clear(); - if (type == TYPE_STORY) { - reactionsContainerLayout.getDelegate().drawRoundRect(canvas, drawingRect, radius, getX(), getY() - AndroidUtilities.statusBarHeight); + if (type == TYPE_STORY || (reactionsContainerLayout.getDelegate() != null && reactionsContainerLayout.getDelegate().drawBackground())) { + reactionsContainerLayout.getDelegate().drawRoundRect(canvas, drawingRect, radius, getX(), getBlurOffset(), 255, true); } else { shadow.setAlpha((int) (Utilities.clamp(progressClpamped / 0.05f, 1f, 0f) * 255)); shadow.setBounds((int) drawingRect.left - shadowPad.left, (int) drawingRect.top - shadowPad.top, (int) drawingRect.right + shadowPad.right, (int) drawingRect.bottom + shadowPad.bottom); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionImageHolder.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionImageHolder.java index a40e8b720f9..d42a0903f2a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionImageHolder.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionImageHolder.java @@ -31,9 +31,12 @@ public class ReactionImageHolder { ReactionsLayoutInBubble.VisibleReaction reaction; private final int currentAccount = UserConfig.selectedAccount; ReactionsLayoutInBubble.VisibleReaction currentReaction; - private final View parent; + private View parent; private boolean attached; float alpha = 1f; + private boolean isStatic; + int lastColorForFilter; + ColorFilter colorFilter; public ReactionImageHolder(View parent) { this.parent = parent; @@ -52,20 +55,28 @@ public void setVisibleReaction(ReactionsLayoutInBubble.VisibleReaction currentRe } this.currentReaction = currentReaction; + String filter = "60_60"; + if (isStatic) { + filter += "_firstframe"; + } if (currentReaction.emojicon != null) { TLRPC.TL_availableReaction defaultReaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get(currentReaction.emojicon); if (defaultReaction != null) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(defaultReaction.select_animation, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); - imageReceiver.setImage(ImageLocation.getForDocument(defaultReaction.select_animation), "60_60", null, null, svgThumb, 0, "tgs", currentReaction, 0); + imageReceiver.setImage(ImageLocation.getForDocument(defaultReaction.select_animation), filter, null, null, svgThumb, 0, "tgs", currentReaction, 0); // imageReceiver.setAllowStartAnimation(false); // imageReceiver.setAutoRepeatCount(1); } } else { - animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES_LARGE, UserConfig.selectedAccount, currentReaction.documentId); + int type = AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES_LARGE; + if (isStatic) { + type = AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC; + } + animatedEmojiDrawable = new AnimatedEmojiDrawable(type, UserConfig.selectedAccount, currentReaction.documentId); if (attached) { animatedEmojiDrawable.addView(parent); } - animatedEmojiDrawable.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_ATOP)); + animatedEmojiDrawable.setColorFilter(colorFilter = new PorterDuffColorFilter(lastColorForFilter = Color.BLACK, PorterDuff.Mode.SRC_ATOP)); } } @@ -74,6 +85,7 @@ public void draw(Canvas canvas) { if (animatedEmojiDrawable.getImageReceiver() != null) { animatedEmojiDrawable.getImageReceiver().setRoundRadius((int) (bounds.width() * 0.1f)); } + animatedEmojiDrawable.setColorFilter(colorFilter); animatedEmojiDrawable.setBounds(bounds); animatedEmojiDrawable.setAlpha((int) (255 * alpha)); animatedEmojiDrawable.draw(canvas); @@ -110,4 +122,32 @@ public void setAlpha(float alpha) { public void play() { imageReceiver.startAnimation(); } + + public void setParent(View parentView) { + if (this.parent == parentView) { + return; + } + if (attached) { + onAttachedToWindow(false); + this.parent = parentView; + onAttachedToWindow(true); + } else { + this.parent = parentView; + } + + } + + public void setStatic() { + isStatic = true; + } + + public void setColor(int color) { + if (lastColorForFilter != color) { + lastColorForFilter = color; + colorFilter = new PorterDuffColorFilter(lastColorForFilter, PorterDuff.Mode.SRC_ATOP); + if (parent != null) { + parent.invalidate(); + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java index 7c69975f7cd..239e577630d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java @@ -56,4 +56,36 @@ public static CharSequence reactionToCharSequence(TLRPC.Reaction reaction) { } return ""; } + + public static void applyForStoryViews(TLRPC.Reaction oldReaction, TLRPC.Reaction newReaction, TLRPC.StoryViews views) { + boolean found = false; + if (views == null) { + return; + } + for (int i = 0; i < views.reactions.size(); i++) { + TLRPC.ReactionCount reactionCount = views.reactions.get(i); + if (oldReaction != null) { + if (compare(reactionCount.reaction, oldReaction)) { + reactionCount.count--; + if (reactionCount.count <= 0) { + views.reactions.remove(i); + i--; + continue; + } + } + } + if (newReaction != null) { + if (compare(reactionCount.reaction, newReaction)) { + reactionCount.count++; + found = true; + } + } + } + if (!found) { + TLRPC.ReactionCount reactionCount = new TLRPC.TL_reactionCount(); + reactionCount.count = 1; + reactionCount.reaction = newReaction; + views.reactions.add(reactionCount); + } + } } 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 f813b556607..031d0f5a7ed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -716,8 +716,8 @@ protected void dispatchDraw(Canvas canvas) { float sc = transitionProgress; canvas.scale(sc, sc, pivotX, getHeight() / 2f); } - if (type == TYPE_STORY) { - delegate.drawRoundRect(canvas, rect, radius, getX(), getY()); + if (type == TYPE_STORY || delegate.drawBackground()) { + delegate.drawRoundRect(canvas, rect, radius, getX(), getY(), 255, false); } else { canvas.drawRoundRect(rect, radius, radius, bgPaint); } @@ -887,7 +887,12 @@ private void drawBubbles(Canvas canvas, float br, float cPr, float sr, int alpha bgPaint.setAlpha(alpha); shadow.setBounds((int) (cx - br - sPad * cPr), (int) (cy - br - sPad * cPr), (int) (cx + br + sPad * cPr), (int) (cy + br + sPad * cPr)); shadow.draw(canvas); - canvas.drawCircle(cx, cy, br, bgPaint); + if (delegate.drawBackground()) { + rectF.set(cx - br, cy - br, cx + br, cy + br); + delegate.drawRoundRect(canvas, rectF, br, getX(), getY(), alpha, false); + } else { + canvas.drawCircle(cx, cy, br, bgPaint); + } cx = LocaleController.isRTL || mirrorX ? bigCircleOffset - bigCircleRadius : getWidth() - bigCircleOffset + bigCircleRadius; cx += bubblesOffset; @@ -896,7 +901,12 @@ private void drawBubbles(Canvas canvas, float br, float cPr, float sr, int alpha sPad = -AndroidUtilities.dp(1); shadow.setBounds((int) (cx - br - sPad * cPr), (int) (cy - br - sPad * cPr), (int) (cx + br + sPad * cPr), (int) (cy + br + sPad * cPr)); shadow.draw(canvas); - canvas.drawCircle(cx, cy, sr, bgPaint); + if (delegate.drawBackground()) { + rectF.set(cx - sr, cy - sr, cx + sr, cy + sr); + delegate.drawRoundRect(canvas, rectF, sr, getX(), getY(), alpha, false); + } else { + canvas.drawCircle(cx, cy, sr, bgPaint); + } canvas.restore(); shadow.setAlpha(255); @@ -1868,7 +1878,7 @@ default void hideMenu() { } - default void drawRoundRect(Canvas canvas, RectF rect, float radius, float offsetX, float offsetY) { + default void drawRoundRect(Canvas canvas, RectF rect, float radius, float offsetX, float offsetY, int alpha, boolean isWindow) { } @@ -1879,6 +1889,10 @@ default boolean needEnterText() { default void onEmojiWindowDismissed() { } + + default boolean drawBackground() { + return false; + } } @Override 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 9029c2b4eaf..b9c69859d72 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -1263,7 +1263,7 @@ public SharedMediaLayout(Context context, long did, SharedMediaPreloader preload int[] mediaCount = preloader.getLastMediaCount(); topicId = sharedMediaPreloader.topicId; hasMedia = new int[]{mediaCount[0], mediaCount[1], mediaCount[2], mediaCount[3], mediaCount[4], mediaCount[5], topicId == 0 ? commonGroupsCount : 0}; - if (userInfo != null && userInfo.stories_pinned_available || isStoriesView()) { + if (userInfo != null && userInfo.stories_pinned_available || chatInfo != null && chatInfo.stories_pinned_available || isStoriesView()) { initialTab = getInitialTab(); } else if (membersFirst && topicId == 0) { initialTab = TAB_GROUPUSERS; @@ -1497,6 +1497,28 @@ public void onClick(View view) { } }); + if (info != null && !isStoriesView()) { + TLRPC.Chat chat = MessagesController.getInstance(profileActivity.getCurrentAccount()).getChat(info.id); + if (chat != null && chat.admin_rights != null && chat.admin_rights.edit_stories) { + ActionBarMenuSubItem openArchiveItem = new ActionBarMenuSubItem(context, false, true, resourcesProvider); + openArchiveItem.setTextAndIcon(LocaleController.getString(R.string.OpenChannelArchiveStories), R.drawable.msg_archive); + openArchiveItem.setOnClickListener(e -> { + Bundle args = new Bundle(); + args.putInt("type", MediaActivity.TYPE_ARCHIVED_CHANNEL_STORIES); + args.putLong("dialog_id", -info.id); + MediaActivity fragment = new MediaActivity(args, null); + fragment.setChatInfo(info); + profileActivity.presentFragment(fragment); + + if (optionsWindow != null) { + optionsWindow.dismiss(); + } + }); + + popupLayout.addView(openArchiveItem); + } + } + if (hasDifferentTypes) { popupLayout.addView(dividerView); ActionBarMenuSubItem showPhotosItem = new ActionBarMenuSubItem(context, true, false, false, resourcesProvider); @@ -4717,6 +4739,7 @@ public boolean onPreDraw() { } public void setChatInfo(TLRPC.ChatFull chatInfo) { + boolean stories_pinned_available = this.info != null && this.info.stories_pinned_available; info = chatInfo; if (info != null && info.migrated_from_chat_id != 0 && mergeDialogId == 0) { mergeDialogId = -info.migrated_from_chat_id; @@ -4725,6 +4748,13 @@ public void setChatInfo(TLRPC.ChatFull chatInfo) { sharedMediaData[a].endReached[1] = false; } } + if (info != null && (stories_pinned_available != info.stories_pinned_available)) { + if (scrollSlidingTextTabStrip != null) { + scrollSlidingTextTabStrip.setInitialTabId(isArchivedOnlyStoriesView() ? TAB_ARCHIVED_STORIES : TAB_STORIES); + } + updateTabs(true); + switchToCurrentSelectedMode(false); + } } public void setUserInfo(TLRPC.UserFull userInfo) { @@ -4813,7 +4843,7 @@ private void updateTabs(boolean animated) { animated = false; } int changed = 0; - if ((DialogObject.isUserDialog(dialog_id) && !DialogObject.isEncryptedDialog(dialog_id) && (userInfo != null && userInfo.stories_pinned_available || isStoriesView()) && includeStories()) != scrollSlidingTextTabStrip.hasTab(TAB_STORIES)) { + if (((DialogObject.isUserDialog(dialog_id) || DialogObject.isChatDialog(dialog_id)) && !DialogObject.isEncryptedDialog(dialog_id) && (userInfo != null && userInfo.stories_pinned_available || info != null && info.stories_pinned_available || isStoriesView()) && includeStories()) != scrollSlidingTextTabStrip.hasTab(TAB_STORIES)) { changed++; } if (!isStoriesView()) { @@ -4887,15 +4917,22 @@ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues sta if (changed > 3) { idToView = null; } - if (DialogObject.isUserDialog(dialog_id) && !DialogObject.isEncryptedDialog(dialog_id) && (userInfo != null && userInfo.stories_pinned_available || isStoriesView()) && includeStories()) { - if (!scrollSlidingTextTabStrip.hasTab(TAB_STORIES)) { - scrollSlidingTextTabStrip.addTextTab(TAB_STORIES, LocaleController.getString("ProfileStories", R.string.ProfileStories), idToView); - } - if (isStoriesView()) { + if ((DialogObject.isUserDialog(dialog_id) || DialogObject.isChatDialog(dialog_id)) && !DialogObject.isEncryptedDialog(dialog_id) && (userInfo != null && userInfo.stories_pinned_available || info != null && info.stories_pinned_available || isStoriesView()) && includeStories()) { + if (isArchivedOnlyStoriesView()) { if (!scrollSlidingTextTabStrip.hasTab(TAB_ARCHIVED_STORIES)) { scrollSlidingTextTabStrip.addTextTab(TAB_ARCHIVED_STORIES, LocaleController.getString("ProfileStories", R.string.ProfileStories), idToView); } scrollSlidingTextTabStrip.animationDuration = 420; + } else { + if (!scrollSlidingTextTabStrip.hasTab(TAB_STORIES)) { + scrollSlidingTextTabStrip.addTextTab(TAB_STORIES, LocaleController.getString("ProfileStories", R.string.ProfileStories), idToView); + } + if (isStoriesView()) { + if (!scrollSlidingTextTabStrip.hasTab(TAB_ARCHIVED_STORIES)) { + scrollSlidingTextTabStrip.addTextTab(TAB_ARCHIVED_STORIES, LocaleController.getString("ProfileStories", R.string.ProfileStories), idToView); + } + scrollSlidingTextTabStrip.animationDuration = 420; + } } } if (!isStoriesView()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java index 93e361d51af..74cfd24dee4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java @@ -56,7 +56,7 @@ public class ViewPagerFixed extends FrameLayout { private Theme.ResourcesProvider resourcesProvider; public int currentPosition; - public float currentProgress; + public float currentProgress = 1f; int nextPosition; protected View[] viewPages; private int[] viewTypes; @@ -478,9 +478,9 @@ public boolean onTouchEvent(MotionEvent ev) { viewPages[1].setTranslationX(animatingForward ? viewPages[0].getMeasuredWidth() : -viewPages[0].getMeasuredWidth()); } nextPosition = 0; - currentProgress = 0; + currentProgress = 1f; if (tabsView != null) { - tabsView.selectTab(currentPosition, 0, 0); + tabsView.selectTab(nextPosition, currentPosition, currentProgress); } onTabAnimationUpdate(false); } @@ -708,6 +708,10 @@ public static float distanceInfluenceForSnapDuration(float f) { } public void setPosition(int position) { + if (adapter == null) { + currentPosition = position; + onTabAnimationUpdate(false); + } if (tabsAnimation != null) { tabsAnimation.cancel(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java index 25799cfb7ce..5236856cb88 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java @@ -65,7 +65,7 @@ public class SpoilerEffect extends Drawable { private Stack particlesPool = new Stack<>(); private int maxParticles; - float[][] particlePoints = new float[ALPHAS.length][MAX_PARTICLES_PER_ENTITY * 2]; + float[][] particlePoints = new float[ALPHAS.length][MAX_PARTICLES_PER_ENTITY * 5]; private float[] particleRands = new float[RAND_REPEAT]; private int[] renderCount = new int[ALPHAS.length]; @@ -99,6 +99,7 @@ public class SpoilerEffect extends Drawable { private int lastColor; public boolean drawPoints; private static Paint xRefPaint; + private int bitmapSize; private static int measureParticlesPerCharacter() { switch (SharedConfig.getDevicePerformanceClass()) { @@ -320,11 +321,6 @@ public void draw(@NonNull Canvas canvas) { float hdt = particle.velocity * dt / 500f; particle.x += particle.vecX * hdt; particle.y += particle.vecY * hdt; - - int alphaIndex = particle.alpha; - particlePoints[alphaIndex][renderCount[alphaIndex] * 2] = particle.x; - particlePoints[alphaIndex][renderCount[alphaIndex] * 2 + 1] = particle.y; - renderCount[alphaIndex]++; } if (particles.size() < maxParticles) { @@ -358,27 +354,56 @@ public void draw(@NonNull Canvas canvas) { newParticle.alpha = Utilities.fastRandom.nextInt(ALPHAS.length); particles.add(newParticle); - int alphaIndex = newParticle.alpha; - particlePoints[alphaIndex][renderCount[alphaIndex] * 2] = newParticle.x; - particlePoints[alphaIndex][renderCount[alphaIndex] * 2 + 1] = newParticle.y; - renderCount[alphaIndex]++; } } for (int a = enableAlpha ? 0 : ALPHAS.length - 1; a < ALPHAS.length; a++) { int renderCount = 0; - int off = 0; + float paintW = particlePaints[a].getStrokeWidth() / 2f; for (int i = 0; i < particles.size(); i++) { Particle p = particles.get(i); if (visibleRect != null && !visibleRect.contains(p.x, p.y) || p.alpha != a && enableAlpha) { - off++; continue; } - particlePoints[a][(i - off) * 2] = p.x; - particlePoints[a][(i - off) * 2 + 1] = p.y; + particlePoints[a][renderCount] = p.x; + particlePoints[a][renderCount + 1] = p.y; renderCount += 2; + if (p.x < paintW) { + if (renderCount >= particlePoints[a].length - 2) { + continue; + } + particlePoints[a][renderCount] = p.x + bitmapSize; + particlePoints[a][renderCount + 1] = p.y; + renderCount += 2; + } + if (p.x > bitmapSize - paintW) { + if (renderCount >= particlePoints[a].length - 2) { + continue; + } + particlePoints[a][renderCount] = p.x - bitmapSize; + particlePoints[a][renderCount + 1] = p.y; + renderCount += 2; + } + if (p.y < paintW) { + if (renderCount >= particlePoints[a].length - 2) { + continue; + } + particlePoints[a][renderCount] = p.x; + particlePoints[a][renderCount + 1] = p.y + bitmapSize; + renderCount += 2; + } + if (p.y > bitmapSize - paintW) { + if (renderCount >= particlePoints[a].length - 2) { + continue; + } + particlePoints[a][renderCount] = p.x; + particlePoints[a][renderCount + 1] = p.y - bitmapSize; + renderCount += 2; + } + + } canvas.drawPoints(particlePoints[a], 0, renderCount, particlePaints[a]); } @@ -756,6 +781,10 @@ public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, } } + public void setSize(int bitmapSize) { + this.bitmapSize = bitmapSize; + } + private static class Particle { private float x, y; private float vecX, vecY; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java index ac65b446fd0..f12507edc00 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java @@ -540,28 +540,20 @@ private void drawFrame(float Δt) { } private void die() { - try { - if (particlesData != null) { - GLES31.glDeleteBuffers(2, particlesData, 0); - particlesData = null; - } - if (drawProgram != 0) { - GLES31.glDeleteProgram(drawProgram); - drawProgram = 0; - } - if (egl != null) { - egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - egl.eglDestroySurface(eglDisplay, eglSurface); - egl.eglDestroyContext(eglDisplay, eglContext); - } - } catch (Exception e) { - FileLog.e(e); + if (particlesData != null) { + GLES31.glDeleteBuffers(2, particlesData, 0); + particlesData = null; + } + if (drawProgram != 0) { + GLES31.glDeleteProgram(drawProgram); + drawProgram = 0; } - try { - surfaceTexture.release(); - } catch (Exception e) { - FileLog.e(e); + if (egl != null) { + egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + egl.eglDestroySurface(eglDisplay, eglSurface); + egl.eglDestroyContext(eglDisplay, eglContext); } + surfaceTexture.release(); checkGlErrors(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffectBitmapFactory.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffectBitmapFactory.java index 7b6a3a47353..42069a0c2db 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffectBitmapFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffectBitmapFactory.java @@ -59,6 +59,7 @@ Paint getPaint() { for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { SpoilerEffect shaderSpoilerEffect = new SpoilerEffect(); + shaderSpoilerEffect.setSize(size); shaderSpoilerEffect.setBounds(step * i, step * j - AndroidUtilities.dp(5), step * i + step + AndroidUtilities.dp(3), step * j + step + AndroidUtilities.dp(5)); shaderSpoilerEffect.drawPoints = true; shaderSpoilerEffect.particlePoints = new float[SpoilerEffect.ALPHAS.length][particleCount * 2]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 7ef2f7e3f1d..5ab9c4a612a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -83,6 +83,8 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager.widget.ViewPager; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; @@ -197,6 +199,7 @@ import org.telegram.ui.Components.RecyclerAnimationScrollHelper; import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.SearchViewPager; import org.telegram.ui.Components.SharedMediaLayout; import org.telegram.ui.Components.SimpleThemeDescription; @@ -352,6 +355,8 @@ public void updateList(boolean animated) { private ActionBarMenuItem doneItem; private ProxyDrawable proxyDrawable; private HintView2 storyHint; + private boolean canShowStoryHint; + private boolean storyHintShown; private RLottieImageView floatingButton; private FrameLayout floatingButtonContainer; private RLottieImageView floatingButton2; @@ -443,6 +448,7 @@ public void updateList(boolean animated) { private DialogsHintCell dialogsHintCell; private UnconfirmedAuthHintCell authHintCell; private float authHintCellProgress; + private boolean authHintCellAnimating; private boolean dialogsHintCellVisible; private boolean authHintCellVisible; private Long cacheSize, deviceSize; @@ -1622,6 +1628,7 @@ public class DialogsRecyclerView extends BlurredRecyclerView implements StoriesL float animateFromSelectorPosition; boolean animateSwitchingSelector; UserListPoller poller; + public int additionalPadding; public DialogsRecyclerView(Context context, ViewPage page) { super(context); @@ -1959,15 +1966,24 @@ protected void onMeasure(int widthSpec, int heightSpec) { if (hasStories && !actionModeFullyShowed) { t += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); } - if (authHintCell != null && authHintCellProgress != 0) { - t += authHintCell.getMeasuredHeight() * authHintCellProgress; + additionalPadding = 0; + if (authHintCell != null && authHintCellProgress != 0 && !authHintCellAnimating) { + t += authHintCell.getMeasuredHeight(); + additionalPadding += authHintCell.getMeasuredHeight(); } - setTopGlowOffset(t); - setPadding(0, t, 0, 0); - if (hasStories) { - parentPage.progressView.setPaddingTop(t - AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP)); - } else { - parentPage.progressView.setPaddingTop(t); + if (t != getPaddingTop()) { + setTopGlowOffset(t); + setPadding(0, t, 0, 0); + if (hasStories) { + parentPage.progressView.setPaddingTop(t - AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP)); + } else { + parentPage.progressView.setPaddingTop(t); + } + for (int i = 0; i < getChildCount(); i++) { + if (getChildAt(i) instanceof DialogsAdapter.LastEmptyView) { + getChildAt(i).requestLayout(); + } + } } ignoreLayout = false; } @@ -2220,17 +2236,11 @@ public void setAnimationSupportView(RecyclerListView animationSupportListView, f if (anchorView != null) { if (animationSupportListView != null) { int topPadding = this.topPadding; -// if (hasStories) { -// topPadding -= AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); -// } animationSupportListView.setPadding(getPaddingLeft(), topPadding, getPaddingLeft(), getPaddingBottom()); if (anchorView != null) { DialogsAdapter adapter = (DialogsAdapter) animationSupportListView.getAdapter(); int p = adapter.findDialogPosition(anchorView.getDialogId()); int offset = (int) (anchorView.getTop() - anchorListView.getPaddingTop() + scrollOffset); -// if (hasStories) { -// offset += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); -// } if (p >= 0) { boolean hasArchive = parentPage.dialogsType == DIALOGS_TYPE_DEFAULT && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive(); int fixedOffset = adapter.fixScrollGap(this, p, offset, hasArchive, hasStories, canShowFilterTabsView, opened); @@ -2701,7 +2711,13 @@ public void updateStatus(TLRPC.User user, boolean animated) { Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); if (emojiStatusId != null) { statusDrawable.set(emojiStatusId, animated); - actionBar.setRightDrawableOnClick(e -> showSelectStatusDialog()); + actionBar.setRightDrawableOnClick(e -> { + if (dialogStoriesCellVisible && dialogStoriesCell != null && !dialogStoriesCell.isExpanded()) { + scrollToTop(true, true); + return; + } + showSelectStatusDialog(); + }); SelectAnimatedEmojiDialog.preload(currentAccount); } else if (user != null && MessagesController.getInstance(currentAccount).isPremiumUser(user)) { if (premiumStar == null) { @@ -2718,7 +2734,13 @@ public void draw(@NonNull Canvas canvas) { } premiumStar.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_profile_verifiedBackground), PorterDuff.Mode.MULTIPLY)); statusDrawable.set(premiumStar, animated); - actionBar.setRightDrawableOnClick(e -> showSelectStatusDialog()); + actionBar.setRightDrawableOnClick(e -> { + if (dialogStoriesCellVisible && dialogStoriesCell != null && !dialogStoriesCell.isExpanded()) { + scrollToTop(true, true); + return; + } + showSelectStatusDialog(); + }); SelectAnimatedEmojiDialog.preload(currentAccount); } else { statusDrawable.set((Drawable) null, animated); @@ -2877,6 +2899,8 @@ public View createView(final Context context) { authHintCellVisible = false; authHintCellProgress = 0f; authHintCell = null; + dialogsHintCell = null; + dialogsHintCellVisible = false; ActionBarMenu menu = actionBar.createMenu(); if (!onlySelect && searchString == null && folderId == 0) { @@ -4410,12 +4434,16 @@ public void getOutline(View view, Outline outline) { StoryRecorder.getInstance(getParentActivity(), currentAccount) .closeToWhenSent(new StoryRecorder.ClosingViewProvider() { @Override - public void preLayout(Runnable runnable) { + public void preLayout(long dialogId, Runnable runnable) { if (dialogStoriesCell != null) { scrollToTop(false, true); invalidateScrollY = true; fragmentView.invalidate(); - dialogStoriesCell.scrollToFirstCell(); + if (dialogId == 0 || dialogId == getUserConfig().getClientUserId()) { + dialogStoriesCell.scrollToFirstCell(); + } else { + dialogStoriesCell.scrollTo(dialogId); + } viewPages[0].listView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { @@ -4430,20 +4458,19 @@ public boolean onPreDraw() { } @Override - public StoryRecorder.SourceView getView() { - return StoryRecorder.SourceView.fromStoryCell(dialogStoriesCell != null ? dialogStoriesCell.findSelfStoryCell() : null); + public StoryRecorder.SourceView getView(long dialogId) { + return StoryRecorder.SourceView.fromStoryCell(dialogStoriesCell != null ? dialogStoriesCell.findStoryCell(dialogId) : null); } }) .open(StoryRecorder.SourceView.fromFloatingButton(floatingButtonContainer), true); } }); - boolean showStoryHint = false; if (!isArchive() && initialDialogsType == DIALOGS_TYPE_DEFAULT) { if (MessagesController.getInstance(currentAccount).getMainSettings().getBoolean("storyhint", true)) { storyHint = new HintView2(context, HintView2.DIRECTION_RIGHT) .setRounding(8) - .setDuration(-1) + .setDuration(8_000) .setCloseButton(true) .setMaxWidth(165) .setMultilineText(true) @@ -4452,7 +4479,6 @@ public StoryRecorder.SourceView getView() { .setBgColor(getThemedColor(Theme.key_undo_background)) .setOnHiddenListener(() -> MessagesController.getInstance(currentAccount).getMainSettings().edit().putBoolean("storyhint", false).commit()); contentView.addView(storyHint, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 160, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 80, 0)); - showStoryHint = true; } } @@ -4483,9 +4509,6 @@ public void getOutline(View view, Outline outline) { floatingButtonContainer.addView(floatingButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); updateFloatingButtonColor(); updateStoriesPosting(); - if (showStoryHint && storyHint != null && storiesEnabled) { - storyHint.show(); - } searchTabsView = null; @@ -5494,38 +5517,60 @@ private void updateAuthHintCellVisibility(boolean visible) { authHintCell.setVisibility(View.VISIBLE); } authHintCell.setAlpha(1f); + viewPages[0].listView.requestLayout(); - if (fragmentView != null) { - fragmentView.requestLayout(); - } + fragmentView.requestLayout(); notificationsLocker.lock(); + authHintCellAnimating = true; ValueAnimator valueAnimator = ValueAnimator.ofFloat(authHintCellProgress, visible ? 1f : 0); - valueAnimator.addUpdateListener(animation -> { - authHintCellProgress = (float) animation.getAnimatedValue(); - updateContextViewPosition(); - viewPages[0].listView.requestLayout(); - }); - valueAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - notificationsLocker.unlock(); - if (fragmentView != null) { - fragmentView.requestLayout(); - } - authHintCellProgress = visible ? 1f : 0; - if (!visible) { - authHintCell.setVisibility(View.GONE); + + int pos = viewPages[0].layoutManager.findFirstVisibleItemPosition(); + int childTop = 0; + if (pos != RecyclerView.NO_POSITION) { + childTop = viewPages[0].layoutManager.findViewByPosition(pos).getTop(); + childTop += visible ? 0 : -authHintCell.getMeasuredHeight(); + } + int finalChildTop = childTop; + AndroidUtilities.doOnLayout(fragmentView, () -> { + float listDy = authHintCell.getMeasuredHeight(); + if (!visible) { + View view = viewPages[0].layoutManager.findViewByPosition(pos); + //look at real visible views difference + if (view != null) { + int newTop = view.getTop(); + listDy += (finalChildTop - newTop); } } + float finalListDy = listDy; + viewPages[0].listView.setTranslationY(finalListDy * authHintCellProgress); + valueAnimator.addUpdateListener(animation -> { + authHintCellProgress = (float) animation.getAnimatedValue(); + viewPages[0].listView.setTranslationY(finalListDy * authHintCellProgress); + updateContextViewPosition(); + }); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + notificationsLocker.unlock(); + authHintCellAnimating = false; + authHintCellProgress = visible ? 1f : 0; + fragmentView.requestLayout(); + viewPages[0].listView.requestLayout(); + viewPages[0].listView.setTranslationY(0); + if (!visible) { + authHintCell.setVisibility(View.GONE); + } + } + }); + valueAnimator.setDuration(250); + valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + valueAnimator.start(); }); - valueAnimator.setDuration(250); - valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); - valueAnimator.start(); } } private void updateDialogsHint() { - if (dialogsHintCell == null || getContext() == null) { + if (dialogsHintCell == null || fragmentView == null || getContext() == null) { return; } if (!getMessagesController().getUnconfirmedAuthController().auths.isEmpty() && folderId == 0 && initialDialogsType == DIALOGS_TYPE_DEFAULT) { @@ -5533,9 +5578,7 @@ private void updateDialogsHint() { dialogsHintCell.setVisibility(View.GONE); if (authHintCell == null) { authHintCell = new UnconfirmedAuthHintCell(getContext()); - if (fragmentView instanceof ContentView) { - ((ContentView) fragmentView).addView(authHintCell); - } + ((ContentView) fragmentView).addView(authHintCell); } authHintCell.set(DialogsActivity.this, currentAccount); updateAuthHintCellVisibility(true); @@ -6664,6 +6707,10 @@ public boolean presentFragment(BaseFragment fragment) { } } } + if (storyHint != null) { + storyHint.hide(); + } + Bulletin.hideVisible(); return b; } @@ -6760,6 +6807,7 @@ public void onBecomeFullyHidden() { undoView[0].hide(true, 0); } super.onBecomeFullyHidden(); + canShowStoryHint = true; } @Override @@ -6785,6 +6833,12 @@ public void onBecomeFullyVisible() { } } } + updateFloatingButtonOffset(); + if (canShowStoryHint && !storyHintShown && storyHint != null && storiesEnabled) { + storyHintShown = true; + canShowStoryHint = false; + storyHint.show(); + } } private void showArchiveHelp() { @@ -9724,9 +9778,15 @@ private void askForPermissons(boolean alert) { permissons.add(Manifest.permission.GET_ACCOUNTS); } if (Build.VERSION.SDK_INT >= 33) { - permissons.add(Manifest.permission.READ_MEDIA_IMAGES); - permissons.add(Manifest.permission.READ_MEDIA_VIDEO); - permissons.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { + permissons.add(Manifest.permission.READ_MEDIA_IMAGES); + } + if (activity.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) != PackageManager.PERMISSION_GRANTED) { + permissons.add(Manifest.permission.READ_MEDIA_VIDEO); + } + if (activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + permissons.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } } else if ((Build.VERSION.SDK_INT <= 28 || BuildVars.NO_SCOPED_STORAGE) && activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissons.add(Manifest.permission.READ_EXTERNAL_STORAGE); permissons.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java index 750c78fb53a..80d3775b237 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java @@ -38,6 +38,7 @@ import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.StickerSetBulletinLayout; import org.telegram.ui.Components.StickersAlert; +import org.telegram.ui.Stories.StoryReactionWidgetView; import java.util.ArrayList; import java.util.HashMap; @@ -895,6 +896,82 @@ public void cancelAllAnimations() { } } + public boolean showAnimationForWidget(StoryReactionWidgetView widgetView) { + if (drawingObjects.size() > 12) { + return false; + } + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(widgetView.mediaArea.reaction); + String emoji = visibleReaction.emojicon; + if (emoji == null) { + TLRPC.Document document = AnimatedEmojiDrawable.findDocument(currentAccount, visibleReaction.documentId); + emoji = MessageObject.findAnimatedEmojiEmoticon(document); + } + MessageObject messageObject = null; + + + float imageH = widgetView.getMeasuredHeight(); + float imageW = widgetView.getMeasuredWidth(); + View parent = (View) widgetView.getParent(); + if (imageW > parent.getWidth() * 0.5f) { + imageH = imageW = parent.getWidth() * 0.4f; + } +// if (imageH <= 0 || imageW <= 0) { +// return false; +// } + + emoji = unwrapEmoji(emoji); + + int viewId = widgetView.hashCode(); + TLRPC.Document viewDocument = null; + boolean isOutOwner = widgetView.getTranslationX() > contentLayout.getMeasuredWidth() / 2f;//view.getMessageObject().isOutOwner(); + if (visibleReaction.emojicon != null && createDrawingObject(emoji, viewId, viewDocument, messageObject, -1, false, false, imageW, imageH, isOutOwner)) { + if (!drawingObjects.isEmpty()) { + DrawingObject drawingObject = drawingObjects.get(drawingObjects.size() - 1); + drawingObject.isReaction = true; + drawingObject.lastH = imageH; + drawingObject.lastW = imageW; + drawingObject.lastX = widgetView.getTranslationX() - drawingObject.lastW / 2f; + drawingObject.lastY = widgetView.getTranslationY() - drawingObject.lastW * 1.5f; + if (drawingObject.isOut) { + drawingObject.lastX += -drawingObject.lastW * 1.8f; + } else { + drawingObject.lastX += -drawingObject.lastW * 0.2f; + } + } + return true; + } else if (visibleReaction.documentId != 0 && widgetView.getAnimatedEmojiDrawable() != null) { + int sameAnimationCount = 0; + for (int i = 0; i < drawingObjects.size(); i++) { + if (drawingObjects.get(i).documentId == visibleReaction.documentId) { + sameAnimationCount++; + } + } + if (sameAnimationCount >= 4) { + return false; + } + DrawingObject drawingObject = new DrawingObject(); + drawingObject.genericEffect = AnimatedEmojiEffect.createFrom(widgetView.getAnimatedEmojiDrawable(), true, true); + drawingObject.randomOffsetX = imageW / 4 * ((random.nextInt() % 101) / 100f); + drawingObject.randomOffsetY = imageH / 4 * ((random.nextInt() % 101) / 100f); + drawingObject.messageId = viewId; + drawingObject.document = null; + drawingObject.documentId = visibleReaction.documentId; + drawingObject.isOut = isOutOwner; + drawingObject.isReaction = true; + drawingObject.lastH = imageH; + drawingObject.lastW = imageW; + drawingObject.lastX = widgetView.getTranslationX() - drawingObject.lastW / 2f; + drawingObject.lastY = widgetView.getTranslationY() - drawingObject.lastW * 1.5f; + drawingObject.lastX += -drawingObject.lastW * 1.8f; + if (attached) { + drawingObject.genericEffect.setView(contentLayout); + } + drawingObjects.add(drawingObject); + return true; + } + return false; + } + public void setAccount(int currentAccount) { this.currentAccount = currentAccount; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index c4d5fb83297..118cf8c9c82 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -9,6 +9,7 @@ package org.telegram.ui; import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_ACCOUNTS; +import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_BOOSTS_FOR_USERS; import android.Manifest; import android.animation.Animator; @@ -97,6 +98,7 @@ import org.telegram.messenger.BackupAgent; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChannelBoostsController; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.ContactsLoadingObserver; @@ -132,6 +134,8 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBarLayout; +import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.DrawerLayoutContainer; @@ -219,6 +223,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati public static Runnable onResumeStaticCallback; private static final String EXTRA_ACTION_TOKEN = "actions.fulfillment.extra.ACTION_TOKEN"; + public ArrayList sheetFragmentsStack = new ArrayList<>(); private boolean finished; private String videoPath; @@ -948,7 +953,6 @@ private void showAttachMenuBot(TLRPC.TL_attachMenuBot attachMenuBot) { webViewSheet.setParentActivity(this); webViewSheet.requestWebView(currentAccount, attachMenuBot.bot_id, attachMenuBot.bot_id, attachMenuBot.short_name, null, BotWebViewSheet.TYPE_SIMPLE_WEB_VIEW_BUTTON, 0, false, BotWebViewSheet.FLAG_FROM_SIDE_MENU); webViewSheet.show(); - drawerLayoutContainer.closeDrawer(); } @Override @@ -2023,6 +2027,7 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool Integer messageId = null; Long channelId = null; Integer threadId = null; + boolean isBoost = false; Integer commentId = null; int videoTimestamp = -1; boolean hasUrl = false; @@ -2201,6 +2206,10 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool messageId = Utilities.parseInt(segments.get(3)); } } + if (data.getQuery() != null && segments.size() == 2) { + isBoost = data.getQuery().equals("boost"); + channelId = Utilities.parseLong(segments.get(1)); + } } else if (path.startsWith("contact/")) { contactToken = path.substring(8); } else if (path.startsWith("folder/")) { @@ -2246,6 +2255,9 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool attachMenuBotChoose = data.getQueryParameter("choose"); attachMenuBotToOpen = data.getQueryParameter("attach"); threadId = Utilities.parseInt(data.getQueryParameter("thread")); + if (data.getQuery() != null) { + isBoost = data.getQuery().equals("boost"); + } // storyId = Utilities.parseInt(data.getQueryParameter("story")); if (threadId == 0) { threadId = null; @@ -2674,7 +2686,7 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool if (message != null && message.startsWith("@")) { message = " " + message; } - runLinkRequest(intentAccount[0], username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, login, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, 0, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, startApp, progress, forceNotInternalForApps, storyId); + runLinkRequest(intentAccount[0], username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, login, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, 0, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, startApp, progress, forceNotInternalForApps, storyId, isBoost); } else { try (Cursor cursor = getContentResolver().query(intent.getData(), null, null, null, null)) { if (cursor != null) { @@ -3491,9 +3503,10 @@ private void runLinkRequest(final int intentAccount, final String botAppStartParam, final Browser.Progress progress, final boolean forceNotInternalForApps, - final int storyId) { + final int storyId, + final boolean isBoost) { if (state == 0 && ChatActivity.SCROLL_DEBUG_DELAY && progress != null) { - Runnable runnable = () -> runLinkRequest(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, 1, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId); + Runnable runnable = () -> runLinkRequest(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, 1, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost); progress.init(); progress.onCancel(() -> AndroidUtilities.cancelRunOnUIThread(runnable)); AndroidUtilities.runOnUIThread(runnable, 7500); @@ -3503,7 +3516,7 @@ private void runLinkRequest(final int intentAccount, if (account != intentAccount) { switchToAccount(account, true); } - runLinkRequest(account, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, 1, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId); + runLinkRequest(account, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, 1, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost); }).show(); return; } else if (code != null) { @@ -3685,18 +3698,10 @@ private void runLinkRequest(final int intentAccount, TLRPC.TL_messages_getAttachMenuBot getAttachMenuBot = new TLRPC.TL_messages_getAttachMenuBot(); getAttachMenuBot.bot = MessagesController.getInstance(intentAccount).getInputUser(peerId); ConnectionsManager.getInstance(intentAccount).sendRequest(getAttachMenuBot, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { - try { - if (dismissLoading != null) { - dismissLoading.run(); - } - } catch (Exception e) { - FileLog.e(e); - } if (response1 instanceof TLRPC.TL_attachMenuBotsBot) { WebAppDisclaimerAlert.show(this, ignore -> { user.inactive = false; - MediaDataController.getInstance(currentAccount).applyAttachMenuBot((TLRPC.TL_attachMenuBotsBot) response1); - processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, false, storyId, true, user, dismissLoading); + processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, false, storyId, isBoost, user, dismissLoading); TLRPC.TL_messages_toggleBotInAttachMenu botRequest = new TLRPC.TL_messages_toggleBotInAttachMenu(); botRequest.bot = MessagesController.getInstance(intentAccount).getInputUser(peerId); @@ -3712,12 +3717,17 @@ private void runLinkRequest(final int intentAccount, } })); } else { - processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, false, storyId, false, user, dismissLoading); + processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, false, storyId, isBoost, user, dismissLoading); } return; } } + if (isBoost) { + processBoostDialog(peerId, dismissLoading); + return; + } + if (setAsAttachBot != null && attachMenuBotToOpen == null) { TLRPC.User user = MessagesController.getInstance(intentAccount).getUser(peerId); if (user != null && user.bot) { @@ -3941,7 +3951,6 @@ public void didChangeOwner(TLRPC.User user) { }); presentFragment(fragment); } else { - long dialog_id; boolean isBot = false; Bundle args = new Bundle(); @@ -4523,7 +4532,7 @@ public void onError() { } } })); - } else if (channelId != null && messageId != null) { + } else if (channelId != null && (messageId != null || isBoost)) { if (threadId != null) { TLRPC.Chat chat = MessagesController.getInstance(intentAccount).getChat(channelId); if (chat != null) { @@ -4556,9 +4565,13 @@ public void onError() { } else { Bundle args = new Bundle(); args.putLong("chat_id", channelId); - args.putInt("message_id", messageId); + if (messageId != null) { + args.putInt("message_id", messageId); + } TLRPC.Chat chatLocal = MessagesController.getInstance(currentAccount).getChat(channelId); - if (chatLocal != null && chatLocal.forum) { + if (chatLocal != null && isBoost) { + processBoostDialog(-channelId, dismissLoading); + } else if (chatLocal != null && chatLocal.forum) { openForumFromLink(-channelId, 0, messageId, () -> { try { dismissLoading.run(); @@ -4588,7 +4601,9 @@ public void onError() { notFound = false; MessagesController.getInstance(currentAccount).putChats(res.chats, false); TLRPC.Chat chat = res.chats.get(0); - if (chat != null && chat.forum) { + if (chat != null && isBoost) { + processBoostDialog(-channelId, null); + } else if (chat != null && chat.forum) { if (threadId != null) { openForumFromLink(-channelId, threadId, messageId, null); } else { @@ -4675,7 +4690,7 @@ private void processWebAppBot(final int intentAccount, final Browser.Progress progress, final boolean forceNotInternalForApps, final int storyId, - boolean justAdded, + final boolean isBoost, TLRPC.User user, Runnable dismissLoading) { @@ -4689,7 +4704,7 @@ private void processWebAppBot(final int intentAccount, progress.end(); } if (error1 != null) { - AndroidUtilities.runOnUIThread(() -> runLinkRequest(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, null, null, progress, forceNotInternalForApps, storyId)); + AndroidUtilities.runOnUIThread(() -> runLinkRequest(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, null, null, progress, forceNotInternalForApps, storyId, isBoost)); } else { TLRPC.TL_messages_botApp botApp = (TLRPC.TL_messages_botApp) response1; AndroidUtilities.runOnUIThread(() -> { @@ -4702,12 +4717,12 @@ private void processWebAppBot(final int intentAccount, sheet.setParentActivity(LaunchActivity.this); sheet.requestWebView(intentAccount, user.id, user.id, null, null, BotWebViewSheet.TYPE_WEB_VIEW_BOT_APP, 0, false, lastFragment, botApp.app, allowWrite.get(), botAppStartParam, user); sheet.show(); - if (justAdded) { + if (botApp.inactive || forceNotInternalForApps) { sheet.showJustAddedBulletin(); } }; - if (!user.bot_attach_menu && (botApp.inactive || forceNotInternalForApps)) { + if (botApp.inactive || forceNotInternalForApps) { AlertsCreator.createBotLaunchAlert(lastFragment, botApp, user, allowWrite, loadBotSheet); } else { loadBotSheet.run(); @@ -4718,6 +4733,36 @@ private void processWebAppBot(final int intentAccount, } + + private void processBoostDialog(Long peerId, Runnable dismissLoading) { + ChannelBoostsController boostsController = MessagesController.getInstance(currentAccount).getBoostsController(); + boostsController.getBoostsStats(peerId, boostsStatus -> { + if (boostsStatus == null) { + dismissLoading.run(); + return; + } + boostsController.userCanBoostChannel(peerId, canApplyBoost -> { + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(getLastFragment(), this, TYPE_BOOSTS_FOR_USERS, currentAccount, null); + limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); + BaseFragment lastFragment = getLastFragment(); + boolean isCurrentChat = false; + if (lastFragment instanceof ChatActivity) { + isCurrentChat = ((ChatActivity) lastFragment).getDialogId() == peerId; + } + limitReachedBottomSheet.setBoostsStats(boostsStatus, isCurrentChat); + limitReachedBottomSheet.setDialogId(peerId); + limitReachedBottomSheet.show(); + try { + if (dismissLoading != null) { + dismissLoading.run(); + } + } catch (Exception e) { + FileLog.e(e); + } + }); + }); + } + private void processAttachMenuBot(int intentAccount, long peerId, String attachMenuBotChoose, TLRPC.User user, String setAsAttachBot) { TLRPC.TL_messages_getAttachMenuBot getAttachMenuBot = new TLRPC.TL_messages_getAttachMenuBot(); getAttachMenuBot.bot = MessagesController.getInstance(intentAccount).getInputUser(peerId); @@ -5124,6 +5169,9 @@ public void onAnimationEnd(Animator animation) { } public void checkAppUpdate(boolean force) { + if (!BuildVars.isStandaloneApp()) { + return; + } if (!force && BuildVars.DEBUG_VERSION || !force && !BuildVars.CHECK_UPDATES) { return; } @@ -7508,6 +7556,9 @@ public void onRebuildAllFragments(INavigationLayout layout, boolean last) { } public static BaseFragment getLastFragment() { + if (instance != null && !instance.sheetFragmentsStack.isEmpty()) { + return instance.sheetFragmentsStack.get(instance.sheetFragmentsStack.size() - 1).getLastFragment(); + } if (instance != null && instance.getActionBarLayout() != null) { return instance.getActionBarLayout().getLastFragment(); } @@ -7649,7 +7700,7 @@ private void openStories(long[] dialogIds, boolean requestWhenNeeded) { return; } StoriesController storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); - ArrayList stories = new ArrayList<>(onlyArchived ? storiesController.getHiddenList() : storiesController.getDialogListStories()); + ArrayList stories = new ArrayList<>(onlyArchived ? storiesController.getHiddenList() : storiesController.getDialogListStories()); ArrayList peerIds = new ArrayList<>(); ArrayList toLoadPeerIds = new ArrayList<>(); final long[] finalDialogIds; @@ -7686,19 +7737,19 @@ private void openStories(long[] dialogIds, boolean requestWhenNeeded) { }; for (int i = 0; i < toLoadPeerIds.size(); ++i) { long did = toLoadPeerIds.get(i); - TLRPC.TL_stories_getUserStories req = new TLRPC.TL_stories_getUserStories(); - req.user_id = messagesController.getInputUser(did); - if (req.user_id instanceof TLRPC.TL_inputUserEmpty) { + TLRPC.TL_stories_getPeerStories req = new TLRPC.TL_stories_getPeerStories(); + req.peer = messagesController.getInputPeer(did); + if (req.peer instanceof TLRPC.TL_inputPeerEmpty) { loaded[0]--; continue; } - if (req.user_id == null) { + if (req.peer == null) { loaded[0]--; continue; } ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { - if (res instanceof TLRPC.TL_stories_userStories) { - TLRPC.TL_stories_userStories r = (TLRPC.TL_stories_userStories) res; + if (res instanceof TLRPC.TL_stories_peerStories) { + TLRPC.TL_stories_peerStories r = (TLRPC.TL_stories_peerStories) res; messagesController.putUsers(r.users, false); messagesController.getStoriesController().putStories(did, r.stories); whenDone.run(); @@ -7710,9 +7761,10 @@ private void openStories(long[] dialogIds, boolean requestWhenNeeded) { } else { long me = UserConfig.getInstance(currentAccount).getClientUserId(); for (int i = 0; i < stories.size(); ++i) { - TLRPC.TL_userStories userStories = stories.get(i); - if (userStories.user_id != me && !peerIds.contains(userStories.user_id) && storiesController.hasUnreadStories(userStories.user_id)) { - peerIds.add(userStories.user_id); + TLRPC.PeerStories userStories = stories.get(i); + long dialogId = DialogObject.getPeerDialogId(userStories.peer); + if (dialogId != me && !peerIds.contains(dialogId) && storiesController.hasUnreadStories(dialogId)) { + peerIds.add(dialogId); } } if (!peerIds.isEmpty()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index ff9498cc3f7..f8cbb3bb28a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -4018,6 +4018,8 @@ public void afterTextChanged(Editable s) {} if (currentType == AUTH_TYPE_MESSAGE) { if (nextType == AUTH_TYPE_FLASH_CALL || nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_MISSED_CALL) { problemText.setText(LocaleController.getString("DidNotGetTheCodePhone", R.string.DidNotGetTheCodePhone)); + } else if (nextType == AUTH_TYPE_FRAGMENT_SMS) { + problemText.setText(LocaleController.getString("DidNotGetTheCodeFragment", R.string.DidNotGetTheCodeFragment)); } else if (nextType == 0) { problemText.setText(LocaleController.getString("DidNotGetTheCode", R.string.DidNotGetTheCode)); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java index 6b2544bc098..37fe5cc149b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java @@ -2398,7 +2398,7 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { } }); - if (paymentForm.invoice.recurring) { + if (paymentForm.invoice.terms_url != null) { recurrentAcceptCell = new RecurrentPaymentsAcceptCell(context, getResourceProvider()); recurrentAcceptCell.setChecked(paymentForm.invoice.recurring && isAcceptTermsChecked); String str = LocaleController.getString(R.string.PaymentCheckoutAcceptRecurrent); @@ -2406,7 +2406,7 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { int firstIndex = str.indexOf('*'), lastIndex = str.lastIndexOf('*'); if (firstIndex != -1 && lastIndex != -1) { SpannableString acceptTerms = new SpannableString(str.substring(firstIndex + 1, lastIndex)); - acceptTerms.setSpan(new URLSpanNoUnderline(paymentForm.invoice.recurring_terms_url), 0, acceptTerms.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + acceptTerms.setSpan(new URLSpanNoUnderline(paymentForm.invoice.terms_url), 0, acceptTerms.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); sb.replace(firstIndex, lastIndex + 1, acceptTerms); str = str.substring(0, firstIndex) + acceptTerms + str.substring(lastIndex + 1); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index d2b9996029e..7a9fe42d1dc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -1777,10 +1777,7 @@ public void restore() { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; - } else { - windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; windowView.setFocusable(false); @@ -4607,7 +4604,7 @@ protected void dispatchDraw(Canvas canvas) { navigationBarLayoutParams.bottomMargin = -navigationBarHeight / 2; navigationBar.setLayoutParams(navigationBarLayoutParams); } - containerView.setPadding(insets.left, 0, insets.right, 0); + containerView.setPadding(newInsets.getSystemWindowInsetLeft(), 0, newInsets.getSystemWindowInsetRight(), 0); if (actionBar != null) { AndroidUtilities.cancelRunOnUIThread(updateContainerFlagsRunnable); if (isVisible && animationInProgress == 0) { @@ -4636,10 +4633,7 @@ protected void dispatchDraw(Canvas canvas) { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; - } else { - windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } paintingOverlay = new PaintingOverlay(parentActivity); @@ -6045,6 +6039,13 @@ protected boolean captionLimitToast() { @Override protected void setupMentionContainer() { + if (parentChatActivity != null) { + return; + } + mentionContainer.getAdapter().setAllowStickers(false); + mentionContainer.getAdapter().setAllowBots(false); + mentionContainer.getAdapter().setAllowChats(false); + mentionContainer.getAdapter().setSearchInDailogs(true); if (parentChatActivity != null) { mentionContainer.getAdapter().setChatInfo(parentChatActivity.chatInfo); mentionContainer.getAdapter().setNeedUsernames(parentChatActivity.currentChat != null); @@ -10534,7 +10535,7 @@ private void createPaintView() { photoPaintView.keyboardVisible = paintKeyboardNotifier.keyboardVisible(); containerView.invalidate(); height = Math.max(height, photoPaintView.getEmojiPadding(false)); - translateY(photoPaintView.isCurrentText() && height > 0 ? ((AndroidUtilities.displaySize.y - height) / 2f - photoPaintView.getSelectedEntityCenterY()) / 2.5f : 0); + translateY(photoPaintView.isCurrentText() && height > 0 ? (AndroidUtilities.displaySize.y - height - dp(80) - photoPaintView.getSelectedEntityBottom()) : 0); if (paintKeyboardAnimator != null) { paintKeyboardAnimator.cancel(); @@ -14270,10 +14271,7 @@ public boolean openPhoto(final MessageObject messageObject, final TLRPC.FileLoca windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; - } else { - windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } if (chatActivity != null && chatActivity.getCurrentEncryptedChat() != null || avatarsDialogId != 0 && MessagesController.getInstance(currentAccount).isChatNoForwards(-avatarsDialogId) || @@ -16991,100 +16989,6 @@ private int[] applyCrop(Canvas canvas, int containerWidth, int containerHeight, return tempInt; } - private int[] applyCrop(Matrix matrix, 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 == EDIT_MODE_CROP || switchingToMode == EDIT_MODE_CROP || (currentEditMode == EDIT_MODE_FILTER || currentEditMode == EDIT_MODE_PAINT) && switchingToMode == -1) { - cropAnimationValue = 1.0f; - } else if (switchingToMode == EDIT_MODE_NONE) { - 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 == EDIT_MODE_PAINT || switchingToMode == EDIT_MODE_PAINT) { - cropScale /= 1.0f + (cropTransform.getMinScale() - 1.0f) * (1.0f - cropAnimationValue); - } else if (switchingToMode == EDIT_MODE_NONE) { - 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; - } - - matrix.postTranslate(cropTransform.getCropAreaX() * cropAnimationValue, cropTransform.getCropAreaY() * cropAnimationValue); - matrix.postScale(cropScale, cropScale); - matrix.postTranslate(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 == EDIT_MODE_PAINT || switchingToMode == EDIT_MODE_PAINT)) { - matrix.postRotate(rotation); - } else { - matrix.postRotate(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) && sendPhotoType != SELECT_TYPE_NO_SELECT) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index cd00efc1dd3..b0a23d6fd98 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -99,6 +99,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private int paymentsClearRow; private int webSessionsRow; private int botsDetailRow; + private int botsAndWebsitesShadowRow; private int contactsSectionRow; private int contactsDeleteRow; private int contactsSuggestRow; @@ -119,7 +120,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private boolean archiveChats; private boolean[] clear = new boolean[2]; - SessionsActivity sessionsActivityPreload; + private SessionsActivity devicesActivityPreload; + private SessionsActivity webSessionsActivityPreload; @Override public boolean onFragmentCreate() { @@ -144,13 +146,24 @@ public boolean onFragmentCreate() { getUserConfig().loadGlobalTTl(); - sessionsActivityPreload = new SessionsActivity(0); - sessionsActivityPreload.setDelegate(() -> { + devicesActivityPreload = new SessionsActivity(SessionsActivity.TYPE_DEVICES); + devicesActivityPreload.setDelegate(() -> { if (listAdapter != null && sessionsRow >= 0) { listAdapter.notifyItemChanged(sessionsRow); } }); - sessionsActivityPreload.loadSessions(false); + devicesActivityPreload.loadSessions(false); + + webSessionsActivityPreload = new SessionsActivity(SessionsActivity.TYPE_WEB_SESSIONS); + webSessionsActivityPreload.setDelegate(() -> { + if (listAdapter != null) { + int webSessionsCount = webSessionsActivityPreload.getSessionsCount(); + if (webSessionsRow < 0 && webSessionsCount > 0) { + updateRows(); + } + } + }); + webSessionsActivityPreload.loadSessions(false); return true; } @@ -245,10 +258,11 @@ public boolean supportsPredictiveItemAnimations() { } if (position == blockedRow) { presentFragment(new PrivacyUsersActivity()); } else if (position == sessionsRow) { - sessionsActivityPreload.resetFragment(); - presentFragment(sessionsActivityPreload); + devicesActivityPreload.resetFragment(); + presentFragment(devicesActivityPreload); } else if (position == webSessionsRow) { - presentFragment(new SessionsActivity(1)); + webSessionsActivityPreload.resetFragment(); + presentFragment(webSessionsActivityPreload); } else if (position == deleteAccountRow) { if (getParentActivity() == null) { return; @@ -659,8 +673,15 @@ private void updateRows(boolean notify) { passportRow = -1; } paymentsClearRow = rowCount++; - webSessionsRow = rowCount++; - botsDetailRow = rowCount++; + if (webSessionsActivityPreload != null && webSessionsActivityPreload.getSessionsCount() > 0) { + webSessionsRow = rowCount++; + botsDetailRow = rowCount++; + botsAndWebsitesShadowRow = -1; + } else { + webSessionsRow = -1; + botsDetailRow = -1; + botsAndWebsitesShadowRow = rowCount++; + } contactsSectionRow = rowCount++; contactsDeleteRow = rowCount++; contactsSyncRow = rowCount++; @@ -1107,16 +1128,16 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { textCell2.setTextAndValueAndIcon(LocaleController.getString("AutoDeleteMessages", R.string.AutoDeleteMessages), value, true, R.drawable.msg2_autodelete, true); } else if (position == sessionsRow) { String count = ""; - if (sessionsActivityPreload.getSessionsCount() == 0) { + if (devicesActivityPreload.getSessionsCount() == 0) { if (getMessagesController().lastKnownSessionsCount == 0) { showLoading = true; } else { count = String.format(LocaleController.getInstance().getCurrentLocale(), "%d", getMessagesController().lastKnownSessionsCount); } } else { - count = String.format(LocaleController.getInstance().getCurrentLocale(), "%d", sessionsActivityPreload.getSessionsCount()); + count = String.format(LocaleController.getInstance().getCurrentLocale(), "%d", devicesActivityPreload.getSessionsCount()); } - getMessagesController().lastKnownSessionsCount = sessionsActivityPreload.getSessionsCount(); + getMessagesController().lastKnownSessionsCount = devicesActivityPreload.getSessionsCount(); textCell2.setTextAndValueAndIcon(LocaleController.getString("SessionsTitle", R.string.SessionsTitle), count, true, R.drawable.msg2_devices, false); } else if (position == emailLoginRow) { CharSequence val = ""; @@ -1186,7 +1207,7 @@ public int getItemViewType(int position) { return 2; } else if (position == secretWebpageRow || position == contactsSyncRow || position == contactsSuggestRow || position == newChatsRow) { return 3; - } else if (position == privacyShadowRow) { + } else if (position == privacyShadowRow || position == botsAndWebsitesShadowRow) { return 4; } else if (position == autoDeleteMesages || position == sessionsRow || position == emailLoginRow || position == passwordRow || position == passcodeRow || position == blockedRow) { return 5; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index a0ddfbd5324..529c82d74c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -8,6 +8,7 @@ package org.telegram.ui; +import static androidx.core.view.ViewCompat.TYPE_TOUCH; import static org.telegram.messenger.ContactsController.PRIVACY_RULES_TYPE_ADDED_BY_PHONE; import android.Manifest; @@ -15,7 +16,9 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.animation.StateListAnimator; import android.animation.ValueAnimator; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; import android.app.Dialog; @@ -31,6 +34,7 @@ import android.database.DataSetObserver; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Point; @@ -65,8 +69,10 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; +import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.webkit.WebStorage; @@ -194,6 +200,7 @@ import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.Paint.PersistColorPalette; import org.telegram.ui.Components.Premium.GiftPremiumBottomSheet; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.Premium.PremiumPreviewBottomSheet; @@ -216,9 +223,11 @@ import org.telegram.ui.Components.VectorAvatarThumbDrawable; import org.telegram.ui.Components.voip.VoIPHelper; import org.telegram.ui.Stories.ProfileStoriesView; +import org.telegram.ui.Stories.StoriesController; import org.telegram.ui.Stories.StoriesListPlaceProvider; import org.telegram.ui.Stories.StoryViewer; import org.telegram.ui.Stories.recorder.DualCameraView; +import org.telegram.ui.Stories.recorder.StoryRecorder; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -630,6 +639,8 @@ public void openPhotoForEdit(String file, String thumb, boolean isVideo) { private boolean hasFallbackPhoto; private boolean hasCustomPhoto; private ImageReceiver fallbackImage; + private boolean loadingBoostsStats; + private boolean waitCanSendStoryRequest; public static ProfileActivity of(long dialogId) { Bundle bundle = new Bundle(); @@ -649,6 +660,8 @@ public static class AvatarImageView extends BackupImageView { private final RectF rect = new RectF(); private final Paint placeholderPaint; + public boolean drawAvatar = true; + public float bounceScale = 1f; private ImageReceiver foregroundImageReceiver; private float foregroundAlpha; @@ -658,6 +671,7 @@ public static class AvatarImageView extends BackupImageView { ProfileGalleryView avatarsViewPager; private boolean hasStories; + private float progressToInsets = 1f; public void setAvatarsViewPager(ProfileGalleryView avatarsViewPager) { this.avatarsViewPager = avatarsViewPager; @@ -736,11 +750,16 @@ public void setRoundRadius(int value) { @Override protected void onDraw(Canvas canvas) { ImageReceiver imageReceiver = animatedEmojiDrawable != null ? animatedEmojiDrawable.getImageReceiver() : this.imageReceiver; + canvas.save(); + canvas.scale(bounceScale, bounceScale, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); if (imageReceiver != null && (foregroundAlpha < 1f || !drawForeground)) { - int inset = hasStories ? (int) AndroidUtilities.dpf2(3.5f) : 0; + float inset = hasStories ? (int) AndroidUtilities.dpf2(3.5f) : 0; inset *= (1f - progressToExpand); + inset *= progressToInsets; imageReceiver.setImageCoords(inset, inset, getMeasuredWidth() - inset * 2f, getMeasuredHeight() - inset * 2f); - imageReceiver.draw(canvas); + if (drawAvatar) { + imageReceiver.draw(canvas); + } } if (foregroundAlpha > 0f && drawForeground) { if (foregroundImageReceiver.getDrawable() != null) { @@ -754,6 +773,7 @@ protected void onDraw(Canvas canvas) { canvas.drawRoundRect(rect, radius, radius, placeholderPaint); } } + canvas.restore(); } @Override @@ -764,6 +784,16 @@ public void invalidate() { } } + public void setProgressToStoriesInsets(float progressToInsets) { + if (progressToInsets == this.progressToInsets) { + return; + } + this.progressToInsets = progressToInsets; + //if (hasStories) { + invalidate(); + //} + } + public void drawForeground(boolean drawForeground) { this.drawForeground = drawForeground; } @@ -1187,6 +1217,9 @@ public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUn innerListView.scrollBy(0, dyUnconsumed); } } + if (dyConsumed != 0 && type == TYPE_TOUCH) { + hideFloatingButton(dyConsumed > 0); + } } catch (Throwable e) { FileLog.e(e); AndroidUtilities.runOnUIThread(() -> { @@ -1640,6 +1673,7 @@ public boolean onFragmentCreate() { getNotificationCenter().addObserver(this, NotificationCenter.topicsDidLoaded); getNotificationCenter().addObserver(this, NotificationCenter.updateSearchSettings); getNotificationCenter().addObserver(this, NotificationCenter.reloadDialogPhotos); + getNotificationCenter().addObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); updateRowsIds(); if (listAdapter != null) { @@ -1709,6 +1743,7 @@ public void onFragmentDestroy() { getNotificationCenter().removeObserver(this, NotificationCenter.topicsDidLoaded); getNotificationCenter().removeObserver(this, NotificationCenter.updateSearchSettings); getNotificationCenter().removeObserver(this, NotificationCenter.reloadDialogPhotos); + getNotificationCenter().removeObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); if (avatarsViewPager != null) { avatarsViewPager.onDestroy(); @@ -2125,6 +2160,9 @@ public void didChangeOwner(TLRPC.User user) { Bundle args = new Bundle(); args.putLong("chat_id", chatId); args.putBoolean("is_megagroup", chat.megagroup); + if (!chatInfo.can_view_stats) { + args.putBoolean("only_boosts", chat.megagroup); + } StatisticActivity fragment = new StatisticActivity(args); presentFragment(fragment); } else if (id == view_discussion) { @@ -3475,7 +3513,7 @@ public boolean onItemClick(View view, int position) { getMessagesStorage().clearSentMedia(); SharedConfig.setNoSoundHintShowed(false); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); - editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("speedhint").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("bganimationhint").remove("filterhint").remove("n_0").remove("storyprvhint").remove("storyhint").remove("storyhint2").remove("storydualhint").remove("storysvddualhint").remove("stories_camera").remove("dualcam").remove("dualmatrix").remove("dual_available").remove("archivehint").remove("askNotificationsAfter").remove("askNotificationsDuration").remove("viewoncehint").commit(); + editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("speedhint").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("bganimationhint").remove("filterhint").remove("n_0").remove("storyprvhint").remove("storyhint").remove("storyhint2").remove("storydualhint").remove("storysvddualhint").remove("stories_camera").remove("dualcam").remove("dualmatrix").remove("dual_available").remove("archivehint").remove("askNotificationsAfter").remove("askNotificationsDuration").remove("viewoncehint").remove("taptostorysoundhint").commit(); MessagesController.getEmojiSettings(currentAccount).edit().remove("featured_hidden").remove("emoji_featured_hidden").commit(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; @@ -4184,21 +4222,31 @@ protected TextView createTextView() { }; mediaCounterTextView.setAlpha(0.0f); avatarContainer2.addView(mediaCounterTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118, 0, 8, 0)); - storyView = new ProfileStoriesView(context, currentAccount, userId == 0 ? chatId : userId, avatarContainer, avatarImage, resourcesProvider) { + storyView = new ProfileStoriesView(context, currentAccount, getDialogId(), avatarContainer, avatarImage, resourcesProvider) { @Override protected void onTap(StoryViewer.PlaceProvider provider) { - long did = userId == 0 ? chatId : userId; - if (getMessagesController().getStoriesController().hasStories(did)) { + long did = getDialogId(); + StoriesController storiesController = getMessagesController().getStoriesController(); + if (storiesController.hasStories(did) || storiesController.hasUploadingStories(did) || storiesController.isLastUploadingFailed(did)) { getOrCreateStoryViewer().open(context, did, provider); } else if (userInfo != null && userInfo.stories != null && !userInfo.stories.stories.isEmpty() && userId != getUserConfig().clientUserId) { getOrCreateStoryViewer().open(context, userInfo.stories, provider); + } else if (chatInfo != null && chatInfo.stories != null && !chatInfo.stories.stories.isEmpty()) { + getOrCreateStoryViewer().open(context, chatInfo.stories, provider); } else { expandAvatar(); } } }; updateStoriesViewBounds(false); - storyView.setUserFull(userInfo); + if (userInfo != null) { + storyView.setStories(userInfo.stories); + } else if (chatInfo != null) { + storyView.setStories(chatInfo.stories); + } + if (avatarImage != null) { + avatarImage.setHasStories(needInsetForStories()); + } avatarContainer2.addView(storyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); updateProfileData(true); @@ -4386,9 +4434,171 @@ public void onZoomStarted(MessageObject messageObject) { actionBarBackgroundPaint.setColor(getThemedColor(Theme.key_listSelector)); contentView.blurBehindViews.add(sharedMediaLayout); updateTtlIcon(); + + createFloatingActionButton(getContext()); return fragmentView; } + FrameLayout floatingButtonContainer; + RLottieImageView floatingButton; + boolean floatingHidden; + float floatingButtonHideProgress; + boolean showBoostsAlert; + + private final AccelerateDecelerateInterpolator floatingInterpolator = new AccelerateDecelerateInterpolator(); + + private void createFloatingActionButton(Context context) { + if (getDialogId() > 0L) { + return; + } + StoriesController storiesController = getMessagesController().getStoriesController(); + if (!storiesController.canPostStories(getDialogId())) { + return; + } else { + waitCanSendStoryRequest = true; + storiesController.canSendStoryFor(getDialogId(), canSend -> { + waitCanSendStoryRequest = false; + showBoostsAlert = !canSend; + hideFloatingButton(false); + }, false, resourcesProvider); + } + long dialogId = getDialogId(); + floatingButtonContainer = new FrameLayout(context); + floatingButtonContainer.setVisibility(View.VISIBLE); + contentView.addView(floatingButtonContainer, LayoutHelper.createFrame((Build.VERSION.SDK_INT >= 21 ? 56 : 60), (Build.VERSION.SDK_INT >= 21 ? 56 : 60), (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.BOTTOM, LocaleController.isRTL ? 14 : 0, 0, LocaleController.isRTL ? 0 : 14, 14)); + floatingButtonContainer.setOnClickListener(v -> { + if (showBoostsAlert) { + if (loadingBoostsStats) { + return; + } + MessagesController messagesController = MessagesController.getInstance(currentAccount); + loadingBoostsStats = true; + messagesController.getBoostsController().getBoostsStats(dialogId, boostsStatus -> { + loadingBoostsStats = false; + if (boostsStatus == null) { + return; + } + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(lastFragment, lastFragment.getContext(), LimitReachedBottomSheet.TYPE_BOOSTS_FOR_POSTING, currentAccount, resourcesProvider); + limitReachedBottomSheet.setBoostsStats(boostsStatus, false); + limitReachedBottomSheet.setDialogId(dialogId); + limitReachedBottomSheet.showStatisticButtonInLink(() -> { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + Bundle args = new Bundle(); + args.putLong("chat_id", chatId); + args.putBoolean("is_megagroup", chat.megagroup); + args.putBoolean("start_from_boosts", true); + if (chatInfo == null || !chatInfo.can_view_stats) { + args.putBoolean("only_boosts", chat.megagroup); + }; + StatisticActivity fragment = new StatisticActivity(args); + presentFragment(fragment); + }); + limitReachedBottomSheet.show(); + }); + return; + } + StoryRecorder.getInstance(getParentActivity(), currentAccount) + .selectedPeerId(getDialogId()) + .canChangePeer(false) + .closeToWhenSent(new StoryRecorder.ClosingViewProvider() { + @Override + public void preLayout(long dialogId, Runnable runnable) { + avatarImage.setHasStories(needInsetForStories()); + if (dialogId == getDialogId()) { + collapseAvatarInstant(); + } + AndroidUtilities.runOnUIThread(runnable, 30); + } + + @Override + public StoryRecorder.SourceView getView(long dialogId) { + if (dialogId != getDialogId()) { + return null; + } + return StoryRecorder.SourceView.fromAvatarImage(avatarImage); + } + }) + .open(StoryRecorder.SourceView.fromFloatingButton(floatingButtonContainer), true); + }); + + floatingButton = new RLottieImageView(context); + floatingButton.setScaleType(ImageView.ScaleType.CENTER); + floatingButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_actionIcon), PorterDuff.Mode.MULTIPLY)); + if (Build.VERSION.SDK_INT >= 21) { + StateListAnimator animator = new StateListAnimator(); + animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButtonContainer, View.TRANSLATION_Z, AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); + animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButtonContainer, View.TRANSLATION_Z, AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); + floatingButtonContainer.setStateListAnimator(animator); + floatingButtonContainer.setOutlineProvider(new ViewOutlineProvider() { + @SuppressLint("NewApi") + @Override + public void getOutline(View view, Outline outline) { + outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + } + }); + } + floatingButtonContainer.addView(floatingButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + floatingButton.setAnimation(R.raw.write_contacts_fab_icon_camera, 56, 56); + floatingButtonContainer.setContentDescription(LocaleController.getString("AccDescrCaptureStory", R.string.AccDescrCaptureStory)); + updateFloatingButtonColor(); + } + + private void collapseAvatarInstant() { + if (allowPullingDown && currentExpandAnimatorValue > 0) { + layoutManager.scrollToPositionWithOffset(0, AndroidUtilities.dp(88) - listView.getPaddingTop()); + listView.post(() -> { + needLayout(true); + if (expandAnimator.isRunning()) { + expandAnimator.cancel(); + } + setAvatarExpandProgress(1f); + }); + } + } + + private void updateFloatingButtonColor() { + if (getParentActivity() == null) { + return; + } + Drawable drawable; + if (floatingButtonContainer != null) { + drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); + if (Build.VERSION.SDK_INT < 21) { + Drawable shadowDrawable = ContextCompat.getDrawable(getParentActivity(), R.drawable.floating_shadow).mutate(); + shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); + combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + drawable = combinedDrawable; + } + floatingButtonContainer.setBackground(drawable); + } + } + + private void hideFloatingButton(boolean hide) { + if (floatingHidden == hide || floatingButtonContainer == null || waitCanSendStoryRequest) { + return; + } + floatingHidden = hide; + AnimatorSet animatorSet = new AnimatorSet(); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(floatingButtonHideProgress, floatingHidden ? 1f : 0f); + valueAnimator.addUpdateListener(animation -> { + floatingButtonHideProgress = (float) animation.getAnimatedValue(); + updateFloatingButtonOffset(); + }); + animatorSet.playTogether(valueAnimator); + animatorSet.setDuration(300); + animatorSet.setInterpolator(floatingInterpolator); + floatingButtonContainer.setClickable(!hide); + animatorSet.start(); + } + + private void updateFloatingButtonOffset() { + if (floatingButtonContainer != null) { + floatingButtonContainer.setTranslationY(AndroidUtilities.dp(100) * floatingButtonHideProgress); + } + } + private boolean expandAvatar() { if (!AndroidUtilities.isTablet() && !isInLandscapeMode && avatarImage.getImageReceiver().hasNotThumb() && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { openingAvatar = true; @@ -6324,6 +6534,12 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (chatInfo != null && (chatInfo.call == null && !hasVoiceChatItem || chatInfo.call != null && hasVoiceChatItem)) { createActionBarMenu(false); } + if (storyView != null && chatInfo != null) { + storyView.setStories(chatInfo.stories); + } + if (avatarImage != null) { + avatarImage.setHasStories(needInsetForStories()); + } } } else if (id == NotificationCenter.chatInfoDidLoad) { TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; @@ -6355,6 +6571,15 @@ public void didReceivedNotification(int id, int account, final Object... args) { } updateAutoDeleteItem(); updateTtlIcon(); + if (storyView != null && chatInfo != null) { + storyView.setStories(chatInfo.stories); + } + if (avatarImage != null) { + avatarImage.setHasStories(needInsetForStories()); + } + if (sharedMediaLayout != null) { + sharedMediaLayout.setChatInfo(chatInfo); + } } } else if (id == NotificationCenter.closeChats) { removeSelfFromStack(true); @@ -6369,7 +6594,10 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (uid == userId) { userInfo = (TLRPC.UserFull) args[1]; if (storyView != null) { - storyView.setUserFull(userInfo); + storyView.setStories(userInfo.stories); + } + if (avatarImage != null) { + avatarImage.setHasStories(needInsetForStories()); } if (sharedMediaLayout != null) { sharedMediaLayout.setUserInfo(userInfo); @@ -6447,6 +6675,10 @@ public void didReceivedNotification(int id, int account, final Object... args) { } } else if (id == NotificationCenter.reloadDialogPhotos) { updateProfileData(false); + } else if (id == NotificationCenter.storiesUpdated) { + if (avatarImage != null) { + avatarImage.setHasStories(needInsetForStories()); + } } } @@ -6697,7 +6929,6 @@ public float getAvatarAnimationProgress() { public void setAvatarAnimationProgress(float progress) { avatarAnimationProgress = currentExpandAnimatorValue = progress; checkPhotoDescriptionAlpha(); - if (playProfileAnimation == 2) { avatarImage.setProgressToExpand(progress); } @@ -6766,6 +6997,15 @@ public void setAvatarAnimationProgress(float progress) { if (aboutLinkCell != null) { aboutLinkCell.invalidate(); } + + if (getDialogId() > 0) { + if (avatarImage != null) { + avatarImage.setProgressToStoriesInsets(avatarAnimationProgress); + } + if (storyView != null) { + storyView.setProgressToStoriesInsets(avatarAnimationProgress); + } + } } boolean profileTransitionInProgress; @@ -6879,6 +7119,10 @@ public AnimatorSet onCustomTransitionAnimation(final boolean isOpen, final Runna ttlIconView.setAlpha(0f); animators.add(ObjectAnimator.ofFloat(ttlIconView, View.ALPHA, 1.0f)); } + if (floatingButtonContainer != null) { + floatingButtonContainer.setAlpha(0f); + animators.add(ObjectAnimator.ofFloat(floatingButtonContainer, View.ALPHA, 1.0f)); + } boolean onlineTextCrosafade = false; @@ -6943,6 +7187,9 @@ public AnimatorSet onCustomTransitionAnimation(final boolean isOpen, final Runna if (ttlIconView != null) { animators.add(ObjectAnimator.ofFloat(ttlIconView, View.ALPHA, ttlIconView.getAlpha(), 0.0f)); } + if (floatingButtonContainer != null) { + animators.add(ObjectAnimator.ofFloat(floatingButtonContainer, View.ALPHA, 0.0f)); + } boolean crossfadeOnlineText = false; BaseFragment previousFragment = parentLayout.getFragmentStack().size() > 1 ? parentLayout.getFragmentStack().get(parentLayout.getFragmentStack().size() - 2) : null; if (previousFragment instanceof ChatActivity) { @@ -7071,17 +7318,26 @@ public void setChatInfo(TLRPC.ChatFull value) { if (avatarsViewPager != null && !isTopic) { avatarsViewPager.setChatInfo(chatInfo); } + if (storyView != null && chatInfo != null) { + storyView.setStories(chatInfo.stories); + } + if (avatarImage != null) { + avatarImage.setHasStories(needInsetForStories()); + } fetchUsersFromChannelInfo(); } private boolean needInsetForStories() { - return getDialogId() < 0 && getMessagesController().getStoriesController().hasStories(getDialogId()); + return getMessagesController().getStoriesController().hasStories(getDialogId()); } public void setUserInfo(TLRPC.UserFull value) { userInfo = value; if (storyView != null) { - storyView.setUserFull(userInfo); + storyView.setStories(userInfo.stories); + } + if (avatarImage != null) { + avatarImage.setHasStories(needInsetForStories()); } if (sharedMediaLayout != null) { sharedMediaLayout.setUserInfo(userInfo); @@ -7224,6 +7480,9 @@ private void updateRowsIds() { if (!hasMedia && userInfo != null) { hasMedia = userInfo.stories_pinned_available; } + if (!hasMedia && chatInfo != null) { + hasMedia = chatInfo.stories_pinned_available; + } if (userId != 0) { if (LocaleController.isRTL) { @@ -8166,7 +8425,7 @@ private void createActionBarMenu(boolean animated) { otherItem.addSubItem(call_item, R.drawable.msg_voicechat, chat.megagroup && !chat.gigagroup ? LocaleController.getString("StartVoipChat", R.string.StartVoipChat) : LocaleController.getString("StartVoipChannel", R.string.StartVoipChannel)); hasVoiceChatItem = true; } - if (chatInfo.can_view_stats && topicId == 0) { + if ((chatInfo.can_view_stats || getMessagesController().getStoriesController().canPostStories(getDialogId())) && topicId == 0) { otherItem.addSubItem(statistics, R.drawable.msg_stats, LocaleController.getString("Statistics", R.string.Statistics)); } ChatObject.Call call = getMessagesController().getGroupCall(chatId, false); @@ -8184,6 +8443,9 @@ private void createActionBarMenu(boolean animated) { otherItem.addSubItem(delete_topic, R.drawable.msg_delete, LocaleController.getPluralString("DeleteTopics", 1)); } } else { + if (chat.creator || chat.admin_rights != null && chat.admin_rights.edit_stories) { + otherItem.addSubItem(channel_stories, R.drawable.msg_archive, LocaleController.getString(R.string.OpenChannelArchiveStories)); + } if (ChatObject.isPublic(chat)) { otherItem.addSubItem(share, R.drawable.msg_share, LocaleController.getString("BotShare", R.string.BotShare)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/QrActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/QrActivity.java index 2a0b42942ef..f9cc14a7254 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/QrActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/QrActivity.java @@ -106,6 +106,7 @@ public class QrActivity extends BaseFragment { private static final ArrayMap qrColorsMap = new ArrayMap<>(); + private static final int LOGO_OPTIMAL_FRAME = 33; private static List cachedThemes; static { @@ -380,6 +381,7 @@ protected void setDarkTheme(boolean isDark) { } fragmentView.postDelayed(() -> { onItemSelected(currentTheme, 0, true); + logoImageView.getAnimatedDrawable().cacheFrame(LOGO_OPTIMAL_FRAME); }, 17); }, 25); @@ -714,10 +716,8 @@ private void performShare() { themeLayout.setVisibility(View.GONE); closeImageView.setVisibility(View.GONE); - logoImageView.stopAnimation(); + logoImageView.setVisibility(View.GONE); RLottieDrawable drawable = logoImageView.getAnimatedDrawable(); - int currentFrame = drawable.getCurrentFrame(); - drawable.setCurrentFrame(33, false); if (qrView != null) { qrView.setForShare(true); @@ -726,12 +726,13 @@ private void performShare() { fragmentView.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); fragmentView.layout(0, 0, width, height); fragmentView.draw(canvas); + drawable.setBounds(logoImageView.getLeft(), logoImageView.getTop(), logoImageView.getRight(), logoImageView.getBottom()); + drawable.drawFrame(canvas, LOGO_OPTIMAL_FRAME); canvas.setBitmap(null); themeLayout.setVisibility(View.VISIBLE); closeImageView.setVisibility(View.VISIBLE); - drawable.setCurrentFrame(currentFrame, false); - logoImageView.playAnimation(); + logoImageView.setVisibility(View.VISIBLE); ViewGroup parent = (ViewGroup) fragmentView.getParent(); fragmentView.layout(0, 0, parent.getWidth(), parent.getHeight()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java index c4efb321f5a..71836eed4c3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java @@ -1652,9 +1652,8 @@ public void openMedia(MessageObject messageObject, PhotoViewer.PhotoViewerProvid @Override public void onAnimationEnd(Animator animation) { if (photoAnimationEndRunnable != null) { - Runnable r = photoAnimationEndRunnable; + photoAnimationEndRunnable.run(); photoAnimationEndRunnable = null; - r.run(); } } }); @@ -1966,9 +1965,8 @@ private boolean checkPhotoAnimation() { if (photoAnimationInProgress != 0) { if (Math.abs(photoTransitionAnimationStartTime - System.currentTimeMillis()) >= 500) { if (photoAnimationEndRunnable != null) { - Runnable r = photoAnimationEndRunnable; + photoAnimationEndRunnable.run(); photoAnimationEndRunnable = null; - r.run(); } photoAnimationInProgress = 0; } @@ -2119,9 +2117,8 @@ public void onAnimationEnd(Animator animation) { isVisible = false; AndroidUtilities.runOnUIThread(() -> { if (photoAnimationEndRunnable != null) { - Runnable r = photoAnimationEndRunnable; + photoAnimationEndRunnable.run(); photoAnimationEndRunnable = null; - r.run(); } }); } @@ -2163,9 +2160,8 @@ public void onAnimationEnd(Animator animation) { @Override public void onAnimationEnd(Animator animation) { if (photoAnimationEndRunnable != null) { - Runnable r = photoAnimationEndRunnable; + photoAnimationEndRunnable.run(); photoAnimationEndRunnable = null; - r.run(); } } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java index 3f3e42eba8d..288cba7872f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java @@ -81,6 +81,9 @@ public class SessionsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + public static final int TYPE_DEVICES = 0; + public static final int TYPE_WEB_SESSIONS = 1; + private ListAdapter listAdapter; private RecyclerListView listView; private EmptyTextProgressView emptyView; @@ -603,6 +606,10 @@ public void loadSessions(boolean silent) { listAdapter.notifyDataSetChanged(); } + if (delegate != null) { + delegate.sessionsLoaded(); + } + if (repeatLoad > 0) { repeatLoad--; if (repeatLoad > 0) { @@ -1243,7 +1250,7 @@ public void onRequestPermissionsResultFragment(int requestCode, String[] permiss } } - int getSessionsCount() { + public int getSessionsCount() { if (sessions.size() == 0 && loading) { return 0; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java index 8cea04c7bc6..d0eb28908bc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java @@ -17,6 +17,7 @@ import android.util.SparseIntArray; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -38,6 +39,7 @@ import org.json.JSONObject; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.LocaleController; import org.telegram.messenger.LruCache; import org.telegram.messenger.MessageObject; @@ -75,6 +77,7 @@ import org.telegram.ui.Charts.view_data.ChartHeaderView; import org.telegram.ui.Charts.view_data.LineViewData; import org.telegram.ui.Charts.view_data.TransitionParams; +import org.telegram.ui.Components.BottomPagerTabs; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.CombinedDrawable; @@ -83,6 +86,8 @@ import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.ViewPagerFixed; +import org.telegram.ui.Components.voip.VoIPHelper; import java.util.ArrayList; import java.util.Arrays; @@ -90,7 +95,8 @@ public class StatisticActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { - private final TLRPC.ChatFull chat; + private TLRPC.ChatFull chat; + private final long chatId; //mutual private ChartViewData growthData; @@ -133,15 +139,21 @@ public class StatisticActivity extends BaseFragment implements NotificationCente private BaseChartView.SharedUiComponents sharedUi; private LinearLayout progressLayout; private final boolean isMegagroup; + private boolean startFromBoosts; private long maxDateOverview; private long minDateOverview; private AlertDialog[] progressDialog = new AlertDialog[1]; + private ViewPagerFixed viewPagerFixed; + private ChannelBoostLayout boosLayout; + private boolean onlyBoostsStat; public StatisticActivity(Bundle args) { super(args); - long chatId = args.getLong("chat_id"); + chatId = args.getLong("chat_id"); isMegagroup = args.getBoolean("is_megagroup", false); + startFromBoosts = args.getBoolean("start_from_boosts", false); + onlyBoostsStat = args.getBoolean("only_boosts", false); this.chat = getMessagesController().getChatFull(chatId); } @@ -164,16 +176,28 @@ public void run() { @Override public boolean onFragmentCreate() { getNotificationCenter().addObserver(this, NotificationCenter.messagesDidLoad); + getNotificationCenter().addObserver(this, NotificationCenter.chatInfoDidLoad); + if (chat != null) { + loadStatistic(); + } else { + MessagesController.getInstance(currentAccount).loadFullChat(chatId, classGuid, true); + } + return super.onFragmentCreate(); + } + private void loadStatistic() { + if (onlyBoostsStat) { + return; + } TLObject req; if (isMegagroup) { TLRPC.TL_stats_getMegagroupStats getMegagroupStats = new TLRPC.TL_stats_getMegagroupStats(); req = getMegagroupStats; - getMegagroupStats.channel = MessagesController.getInstance(currentAccount).getInputChannel(chat.id); + getMegagroupStats.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); } else { TLRPC.TL_stats_getBroadcastStats getBroadcastStats = new TLRPC.TL_stats_getBroadcastStats(); req = getBroadcastStats; - getBroadcastStats.channel = MessagesController.getInstance(currentAccount).getInputChannel(chat.id); + getBroadcastStats.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); } @@ -212,7 +236,7 @@ public boolean onFragmentCreate() { if (recentPostsAll.size() > 0) { int lastPostId = recentPostsAll.get(0).counters.msg_id; int count = recentPostsAll.size(); - getMessagesStorage().getMessages(-chat.id, 0, false, count, lastPostId, 0, 0, classGuid, 0, false, 0, 0, true, false, null); + getMessagesStorage().getMessages(-chatId, 0, false, count, lastPostId, 0, 0, classGuid, 0, false, 0, 0, true, false, null); } AndroidUtilities.runOnUIThread(() -> { @@ -298,7 +322,6 @@ public boolean onFragmentCreate() { }, null, null, 0, chat.stats_dc, ConnectionsManager.ConnectionTypeGeneric, true); getConnectionsManager().bindRequestToGuid(reqId, classGuid); - return super.onFragmentCreate(); } private void dataLoaded(ChartViewData[] chartsViewData) { @@ -331,6 +354,7 @@ public void onAnimationEnd(Animator animation) { @Override public void onFragmentDestroy() { getNotificationCenter().removeObserver(this, NotificationCenter.messagesDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.chatInfoDidLoad); if (progressDialog[0] != null) { progressDialog[0].dismiss(); progressDialog[0] = null; @@ -381,14 +405,102 @@ public void didReceivedNotification(int id, int account, Object... args) { diffUtilsCallback.update(); } } + } else if (id == NotificationCenter.chatInfoDidLoad) { + TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; + if (chatFull.id == chatId) { + if (chat == null) { + chat = chatFull; + loadStatistic(); + } + } } } @Override public View createView(Context context) { sharedUi = new BaseChartView.SharedUiComponents(); - FrameLayout frameLayout = new FrameLayout(context); - fragmentView = frameLayout; + boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chatId, currentAccount); + BottomPagerTabs storiesTabsView = new BottomPagerTabs(context, getResourceProvider()) { + + @Override + public Tab[] createTabs() { + Tab[] tabs = new Tab[]{ + new Tab(0, R.raw.stats, LocaleController.getString("Statistics", R.string.Statistics)), + new Tab(1, R.raw.boosts, LocaleController.getString("Boosts", R.string.Boosts)) + }; + tabs[1].customEndFrameMid = 25; + tabs[1].customEndFrameEnd = 49; + return tabs; + } + }; + + viewPagerFixed = new ViewPagerFixed(getContext()) { + @Override + protected void onTabAnimationUpdate(boolean manual) { + if (manual) { + return; + } + float progress = currentProgress; + if (currentPosition == 0) { + progress = 1f - progress; + } + storiesTabsView.setScrolling(true); + storiesTabsView.setProgress(progress); + } + }; + + storiesTabsView.setOnTabClick(position -> { + if (viewPagerFixed.scrollToPosition(position)) { + storiesTabsView.setScrolling(false); + storiesTabsView.setProgress(position); + } + }); + FrameLayout statisticLayout = new FrameLayout(context); + if (isChannel) { + boosLayout = new ChannelBoostLayout(StatisticActivity.this, -chatId, getResourceProvider()); + } + boolean showTabs = isChannel && !onlyBoostsStat; + if (showTabs && startFromBoosts) { + viewPagerFixed.setPosition(1); + } + viewPagerFixed.setAdapter(new ViewPagerFixed.Adapter() { + @Override + public int getItemCount() { + if (onlyBoostsStat) { + return 1; + } + if (isChannel) { + return 2; + } + return 1; + } + + @Override + public View createView(int viewType) { + if (onlyBoostsStat) { + return boosLayout; + } + return viewType == 0 ? statisticLayout : boosLayout; + } + + @Override + public int getItemViewType(int position) { + return position; + } + + @Override + public void bindView(View view, int position, int viewType) { + + } + }); + + + FrameLayout contentLayout = new FrameLayout(getContext()); + contentLayout.addView(viewPagerFixed, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 0, 0, 0, showTabs ? 64 : 0)); + if (showTabs) { + contentLayout.addView(storiesTabsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); + } + fragmentView = contentLayout; recyclerListView = new RecyclerListView(context) { int lastH; @@ -429,7 +541,7 @@ protected void onMeasure(int widthSpec, int heightSpec) { progressLayout.addView(loadingTitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 10)); progressLayout.addView(loadingSubtitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); - frameLayout.addView(progressLayout, LayoutHelper.createFrame(240, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 30)); + statisticLayout.addView(progressLayout, LayoutHelper.createFrame(240, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 30)); if (adapter == null) { @@ -509,7 +621,7 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { presentFragment(activity); } else if (i == 1) { Bundle bundle = new Bundle(); - bundle.putLong("chat_id", chat.id); + bundle.putLong("chat_id", chatId); bundle.putInt("message_id", messageObject.getId()); bundle.putBoolean("need_remove_previous_same_chat_activity", false); ChatActivity chatActivity = new ChatActivity(bundle); @@ -535,17 +647,17 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { return false; }); - frameLayout.addView(recyclerListView); + statisticLayout.addView(recyclerListView); 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)); - TLRPC.Chat chatLocal = getMessagesController().getChat(chat.id); + TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); avatarContainer.setChatAvatar(chatLocal); avatarContainer.setTitle(chatLocal.title); - avatarContainer.setSubtitle(LocaleController.getString("Statistics", R.string.Statistics)); + avatarContainer.hideSubtitle(); actionBar.setBackButtonDrawable(new BackDrawable(false)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @@ -1867,7 +1979,7 @@ private void loadMessages() { } } } - req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chat.id); + req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); messagesIsLoading = true; getConnectionsManager().sendRequest(req, (response, error) -> { @@ -2319,7 +2431,7 @@ public OverviewChatData(TLRPC.TL_stats_megagroupStats stats) { dif = (int) (stats.viewers.current - stats.viewers.previous); difPercent = stats.viewers.previous == 0 ? 0 : Math.abs(dif / (float) stats.viewers.previous * 100f); - viewingMembersTitle = LocaleController.getString("ViewingMembers", R.string.ViewingMembers); + viewingMembersTitle = LocaleController.getString("ViewingMembers", R.string.ViewingMembers); viewingMembersPrimary = AndroidUtilities.formatWholeNumber((int) stats.viewers.current, 0); if (dif == 0 || difPercent == 0) { @@ -2444,6 +2556,14 @@ public void setData(OverviewChatData data) { updateColors(); } + public void setData(int index, String primary, String secondary, String title) { + this.primary[index].setText(primary); + this.secondary[index].setText(secondary); + this.title[index].setText(title); + + updateColors(); + } + private void updateColors() { for (int i = 0; i < 4; i++) { primary[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); @@ -2702,4 +2822,12 @@ public boolean isLightStatusBar() { int color = Theme.getColor(Theme.key_windowBackgroundWhite); return ColorUtils.calculateLuminance(color) > 0.7f; } + + @Override + public boolean isSwipeBackEnabled(MotionEvent event) { + if (viewPagerFixed != null && (viewPagerFixed.currentPosition != 0 || viewPagerFixed.currentProgress != 1f)) { + return false; + } + return super.isSwipeBackEnabled(event); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ChannelBoostUtilities.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ChannelBoostUtilities.java new file mode 100644 index 00000000000..8db44201d89 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ChannelBoostUtilities.java @@ -0,0 +1,19 @@ +package org.telegram.ui.Stories; + +import android.text.TextUtils; + +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.MessagesController; +import org.telegram.tgnet.TLRPC; + +public class ChannelBoostUtilities { + public static String createLink(int currentAccount, long dialogId) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + String username = ChatObject.getPublicUsername(chat); + if (!TextUtils.isEmpty(username)) { + return "https://t.me/" + ChatObject.getPublicUsername(chat) + "?boost"; + } else { + return "https://t.me/c/" + -dialogId + "?boost"; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java index 08aa749bd2b..cbbfb850ee8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java @@ -34,10 +34,9 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; @@ -126,7 +125,6 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter DefaultItemAnimator itemAnimator; LinearLayoutManager layoutManager; AnimatedTextView titleView; - boolean progressWasDrawn; boolean drawCircleForce; ArrayList afterNextLayout = new ArrayList<>(); private float collapsedProgress1 = -1; @@ -206,14 +204,11 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { openStoryForCell(cell, false); }; recyclerListView.setOnItemClickListener(itemClickListener); - recyclerListView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - if (collapsedProgress == 0 && overscrollPrgoress == 0) { - onUserLongPressed(view, ((StoryCell) view).dialogId); - } - return false; + recyclerListView.setOnItemLongClickListener((view, position) -> { + if (collapsedProgress == 0 && overscrollPrgoress == 0) { + onUserLongPressed(view, ((StoryCell) view).dialogId); } + return false; }); recyclerListView.setAdapter(adapter); @@ -227,7 +222,6 @@ public boolean onItemClick(View view, int position) { titleView.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); titleView.setTextSize(AndroidUtilities.dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 18 : 20)); addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - ellipsizeSpanAnimator.addView(titleView); titleView.setAlpha(0f); @@ -334,10 +328,10 @@ private void openStoryForCell(StoryCell cell, boolean overscroll) { } return; } - if (!storiesController.hasStories(cell.dialogId) && (!cell.isSelf || !storiesController.hasUploadingStories())) { + if (!storiesController.hasStories(cell.dialogId) && !storiesController.hasUploadingStories(cell.dialogId)) { return; } - TLRPC.TL_userStories userStories = storiesController.getStories(cell.dialogId); + TLRPC.PeerStories userStories = storiesController.getStories(cell.dialogId); long startFromDialogId = cell.dialogId; if (globalCancelable != null) { globalCancelable.cancel(); @@ -437,10 +431,11 @@ public void updateItems(boolean animated, boolean force) { items.add(new Item(UserConfig.getInstance(currentAccount).getClientUserId())); } - ArrayList allStories = type == TYPE_ARCHIVE ? storiesController.getHiddenList() : storiesController.getDialogListStories(); + ArrayList allStories = type == TYPE_ARCHIVE ? storiesController.getHiddenList() : storiesController.getDialogListStories(); for (int i = 0; i < allStories.size(); i++) { - if (allStories.get(i).user_id != UserConfig.getInstance(currentAccount).getClientUserId()) { - items.add(new Item(allStories.get(i).user_id)); + long dialogId = DialogObject.getPeerDialogId(allStories.get(i).peer); + if (dialogId != UserConfig.getInstance(currentAccount).getClientUserId()) { + items.add(new Item(dialogId)); } } int size = items.size(); @@ -452,7 +447,7 @@ public void updateItems(boolean animated, boolean force) { totalCount = Math.max(1, Math.max(storiesController.getTotalStoriesCount(hidden), size)); if (storiesController.hasOnlySelfStories()) { - if (!storiesController.getUploadingStories().isEmpty()) { + if (storiesController.hasUploadingStories(UserConfig.getInstance(currentAccount).getClientUserId())) { String str = LocaleController.getString("UploadingStory", R.string.UploadingStory); int index = str.indexOf("…"); if (index > 0) { @@ -877,7 +872,7 @@ public void onUserLongPressed(View view, long dialogId) { public void openStoryRecorder() { final StoriesController.StoryLimit storyLimit = MessagesController.getInstance(currentAccount).getStoriesController().checkStoryLimit(); if (storyLimit != null) { - fragment.showDialog(new LimitReachedBottomSheet(fragment, getContext(), storyLimit.getLimitReachedType(), currentAccount, fragment.getResourceProvider())); + fragment.showDialog(new LimitReachedBottomSheet(fragment, getContext(), storyLimit.getLimitReachedType(), currentAccount, null)); return; } @@ -899,6 +894,7 @@ public void openStoryRecorder() { EllipsizeSpanAnimator ellipsizeSpanAnimator = new EllipsizeSpanAnimator(this); public void setTitleOverlayText(String titleOverlayText, int textId) { + boolean hasEllipsizedText = false; if (titleOverlayText != null) { hasOverlayText = true; if (overlayTextId != textId) { @@ -910,6 +906,7 @@ public void setTitleOverlayText(String titleOverlayText, int textId) { if (index >= 0) { SpannableString spannableString = SpannableString.valueOf(textToSet); ellipsizeSpanAnimator.wrap(spannableString, index); + hasEllipsizedText = true; textToSet = spannableString; } } @@ -920,6 +917,11 @@ public void setTitleOverlayText(String titleOverlayText, int textId) { overlayTextId = 0; titleView.setText(currentTitle, true); } + if (hasEllipsizedText) { + ellipsizeSpanAnimator.addView(titleView); + } else { + ellipsizeSpanAnimator.removeView(titleView); + } } public void setClipTop(int clipTop) { @@ -944,7 +946,7 @@ public void openSelfStories() { public void onResume() { storiesController.checkExpiredStories(); for (int i = 0; i < items.size(); i++) { - TLRPC.TL_userStories stories = storiesController.getStories(items.get(i).dialogId); + TLRPC.PeerStories stories = storiesController.getStories(items.get(i).dialogId); if (stories != null) { storiesController.preloadUserStories(stories); } @@ -956,6 +958,8 @@ public void setOverscoll(float storiesOverscroll) { invalidate(); recyclerListView.invalidate(); if (overscrollPrgoress != 0) { + setClipChildren(false); + recyclerListView.setClipChildren(false); ((ViewGroup) getParent()).setClipChildren(false); } else { ((ViewGroup) getParent()).setClipChildren(true); @@ -1040,7 +1044,8 @@ public int hashCode() { } } - public StoryCell findSelfStoryCell() { + + public StoryCell findStoryCell(long dialogId) { RecyclerListView parent = recyclerListView; if (currentState == COLLAPSED_STATE) { parent = listViewMini; @@ -1049,7 +1054,7 @@ public StoryCell findSelfStoryCell() { View child = parent.getChildAt(i); if (child instanceof StoryCell) { StoryCell storyCell = (StoryCell) child; - if (storyCell.isSelf) { + if (storyCell.dialogId == dialogId) { return storyCell; } } @@ -1057,6 +1062,8 @@ public StoryCell findSelfStoryCell() { return null; } + + public class StoryCell extends FrameLayout { public boolean drawInParent; public int position; @@ -1093,6 +1100,7 @@ public class StoryCell extends FrameLayout { private boolean isUploadingState; private float overscrollProgress; private boolean selectedForOverscroll; + boolean progressWasDrawn; private final AnimatedFloat failT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); @@ -1141,7 +1149,7 @@ public void setDialogId(long dialogId) { this.dialogId = dialogId; isSelf = dialogId == UserConfig.getInstance(currentAccount).getClientUserId(); - isFail = isSelf && storiesController.isLastUploadingFailed(); + isFail = storiesController.isLastUploadingFailed(dialogId); TLObject object; if (dialogId > 0) { object = user = MessagesController.getInstance(currentAccount).getUser(dialogId); @@ -1161,18 +1169,18 @@ public void setDialogId(long dialogId) { if (mini) { return; } - if (dialogId == UserConfig.getInstance(currentAccount).getClientUserId()) { - textView.setRightDrawable(null); - if (storiesController.isLastUploadingFailed()) { - textView.setText(LocaleController.getString("FailedStory", R.string.FailedStory)); - isUploadingState = false; - } else if (!storiesController.getUploadingStories().isEmpty()) { - StoriesUtilities.applyUploadingStr(textView, true, false); - isUploadingState = true; - } else if (storiesController.getEditingStory() != null) { - StoriesUtilities.applyUploadingStr(textView, true, false); - isUploadingState = true; - } else { + textView.setRightDrawable(null); + if (storiesController.isLastUploadingFailed(dialogId)) { + textView.setText(LocaleController.getString("FailedStory", R.string.FailedStory)); + isUploadingState = false; + } else if (!Utilities.isNullOrEmpty(storiesController.getUploadingStories(dialogId))) { + StoriesUtilities.applyUploadingStr(textView, true, false); + isUploadingState = true; + } else if (storiesController.getEditingStory(dialogId) != null) { + StoriesUtilities.applyUploadingStr(textView, true, false); + isUploadingState = true; + } else { + if (isSelf) { if (animated && isUploadingState && !mini) { View oldTextView = textView; createTextView(); @@ -1213,33 +1221,34 @@ public void onAnimationEnd(Animator animation) { AndroidUtilities.runOnUIThread(animationRunnable, 500); isUploadingState = false; textView.setText(LocaleController.getString("MyStory", R.string.MyStory));//, animated); - } - } else if (user != null) { - String name = user.first_name == null ? "" : user.first_name.trim(); - int index = name.indexOf(" "); - if (index > 0) { - name = name.substring(0, index); - } - if (user.verified) { - if (verifiedDrawable == null) { - verifiedDrawable = createVerifiedDrawable(); + } else if (user != null) { + String name = user.first_name == null ? "" : user.first_name.trim(); + int index = name.indexOf(" "); + if (index > 0) { + name = name.substring(0, index); } - CharSequence text = name; - text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), false); - textView.setText(text); - textView.setRightDrawable(verifiedDrawable); + if (user.verified) { + if (verifiedDrawable == null) { + verifiedDrawable = createVerifiedDrawable(); + } + CharSequence text = name; + text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), false); + textView.setText(text); + textView.setRightDrawable(verifiedDrawable); + } else { + CharSequence text = name; + text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), false); + textView.setText(text); + textView.setRightDrawable(null); + }//, false); } else { - CharSequence text = name; + CharSequence text = chat.title; text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), false); - textView.setText(text); + textView.setText(text);//, false); textView.setRightDrawable(null); - }//, false); - } else { - CharSequence text = chat.title; - text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), false); - textView.setText(text);//, false); - textView.setRightDrawable(null); + } } + } @Override @@ -1294,125 +1303,122 @@ protected void dispatchDraw(Canvas canvas) { if (progressToCollapsed != 0) { canvas.drawCircle(cx, cy, radius + AndroidUtilities.dp(3), backgroundPaint); } - if (isSelf) { - canvas.save(); - canvas.scale(bounceScale, bounceScale, cx, cy); - if (radialProgress == null) { - radialProgress = DialogStoriesCell.this.radialProgress; - } - if (!storiesController.getUploadingAndEditingStories().isEmpty() || (progressWasDrawn && radialProgress != null && radialProgress.getAnimatedProgress() < 0.98f)) { - float uploadingProgress = 0; - boolean closeFriends = false; - if (storiesController.getUploadingAndEditingStories().isEmpty()) { - uploadingProgress = 1f; - closeFriends = lastUploadingCloseFriends; - } else { - for (int i = 0; i < storiesController.getUploadingAndEditingStories().size(); i++) { - uploadingProgress += storiesController.getUploadingAndEditingStories().get(i).progress; - } - uploadingProgress = uploadingProgress / storiesController.getUploadingAndEditingStories().size(); - lastUploadingCloseFriends = closeFriends = storiesController.getUploadingAndEditingStories().get(storiesController.getUploadingAndEditingStories().size() - 1).isCloseFriends(); - } - invalidate(); - if (radialProgress == null) { - if (DialogStoriesCell.this.radialProgress != null) { - radialProgress = DialogStoriesCell.this.radialProgress; - } else { - DialogStoriesCell.this.radialProgress = radialProgress = new RadialProgress(this); - radialProgress.setBackground(null, true, false); - } - } - if (drawAvatar) { - canvas.save(); - canvas.scale(params.getScale(), params.getScale(), params.originalAvatarRect.centerX(), params.originalAvatarRect.centerY()); - avatarImage.setImageCoords(params.originalAvatarRect); - avatarImage.draw(canvas); - canvas.restore(); - } - radialProgress.setDiff(0); - Paint paint = closeFriends ? - StoriesUtilities.getCloseFriendsPaint(avatarImage) : - StoriesUtilities.getActiveCirclePaint(avatarImage, true); - paint.setAlpha(255); - radialProgress.setPaint(paint); - radialProgress.setProgressRect( - (int) (avatarImage.getImageX() - AndroidUtilities.dp(3)), (int) (avatarImage.getImageY() - AndroidUtilities.dp(3)), - (int) (avatarImage.getImageX2() + AndroidUtilities.dp(3)), (int) (avatarImage.getImageY2() + AndroidUtilities.dp(3)) - ); - radialProgress.setProgress(Utilities.clamp(uploadingProgress, 1f, 0), progressWasDrawn); - if (avatarImage.getVisible()) { - radialProgress.draw(canvas); - } - progressWasDrawn = true; - drawCircleForce = true; - invalidate(); - } else { - float failT = this.failT.set(isFail); - if (drawAvatar) { - if (progressWasDrawn) { - animateBounce(); - params.forceAnimateProgressToSegments = true; - params.progressToSegments = 0f; - ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f); - valueAnimator.addUpdateListener(animation -> { - params.progressToSegments = AndroidUtilities.lerp(0, 1f - collapsedProgress2, (float) animation.getAnimatedValue()); - invalidate(); - }); - valueAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - params.forceAnimateProgressToSegments = false; - } - }); - valueAnimator.setDuration(100); - valueAnimator.start(); - } - failT *= params.progressToSegments; - - params.animate = !progressWasDrawn; - params.progressToArc = getArcProgress(cx, radius); - params.isLast = isLast; - params.isFirst = isFirst; - params.crossfadeToDialog = 0; - params.alpha = 1f - failT; - StoriesUtilities.drawAvatarWithStory(dialogId, canvas, avatarImage, storiesController.hasSelfStories(), params); - - if (failT > 0) { - final Paint paint = StoriesUtilities.getErrorPaint(avatarImage); - paint.setStrokeWidth(AndroidUtilities.dp(2)); - paint.setAlpha((int) (0xFF * failT)); - canvas.drawCircle(x + finalSize / 2, y + finalSize / 2, (finalSize / 2 + AndroidUtilities.dp(4)) * params.getScale(), paint); - } + canvas.save(); + canvas.scale(bounceScale, bounceScale, cx, cy); + if (radialProgress == null) { + radialProgress = DialogStoriesCell.this.radialProgress; + } + ArrayList uploadingOrEditingStories = storiesController.getUploadingAndEditingStories(dialogId); + boolean hasUploadingStories = (uploadingOrEditingStories != null && !uploadingOrEditingStories.isEmpty()); + boolean drawProgress = hasUploadingStories || (progressWasDrawn && radialProgress != null && radialProgress.getAnimatedProgress() < 0.98f); + if (drawProgress) { + float uploadingProgress = 0; + boolean closeFriends; + if (!hasUploadingStories) { + uploadingProgress = 1f; + closeFriends = lastUploadingCloseFriends; + } else { + for (int i = 0; i < uploadingOrEditingStories.size(); i++) { + uploadingProgress += uploadingOrEditingStories.get(i).progress; } - progressWasDrawn = false; - if (drawAvatar) { - canvas.save(); - float s = 1f - progressHalf; - canvas.scale(s, s, cx + AndroidUtilities.dp(16), cy + AndroidUtilities.dp(16)); - drawPlus(canvas, cx, cy, 1f); - drawFail(canvas, cx, cy, failT); - canvas.restore(); + uploadingProgress = uploadingProgress / uploadingOrEditingStories.size(); + lastUploadingCloseFriends = closeFriends = uploadingOrEditingStories.get(uploadingOrEditingStories.size() - 1).isCloseFriends(); + } + invalidate(); + if (radialProgress == null) { + if (DialogStoriesCell.this.radialProgress != null) { + radialProgress = DialogStoriesCell.this.radialProgress; + } else { + DialogStoriesCell.this.radialProgress = radialProgress = new RadialProgress(this); + radialProgress.setBackground(null, true, false); } } - canvas.restore(); + if (drawAvatar) { + canvas.save(); + canvas.scale(params.getScale(), params.getScale(), params.originalAvatarRect.centerX(), params.originalAvatarRect.centerY()); + avatarImage.setImageCoords(params.originalAvatarRect); + avatarImage.draw(canvas); + canvas.restore(); + } + radialProgress.setDiff(0); + Paint paint = closeFriends ? + StoriesUtilities.getCloseFriendsPaint(avatarImage) : + StoriesUtilities.getActiveCirclePaint(avatarImage, true); + paint.setAlpha(255); + radialProgress.setPaint(paint); + radialProgress.setProgressRect( + (int) (avatarImage.getImageX() - AndroidUtilities.dp(3)), (int) (avatarImage.getImageY() - AndroidUtilities.dp(3)), + (int) (avatarImage.getImageX2() + AndroidUtilities.dp(3)), (int) (avatarImage.getImageY2() + AndroidUtilities.dp(3)) + ); + radialProgress.setProgress(Utilities.clamp(uploadingProgress, 1f, 0), progressWasDrawn); + if (avatarImage.getVisible()) { + radialProgress.draw(canvas); + } + progressWasDrawn = true; + drawCircleForce = true; + invalidate(); } else { + float failT = this.failT.set(isFail); if (drawAvatar) { - params.animate = true; + if (progressWasDrawn) { + animateBounce(); + params.forceAnimateProgressToSegments = true; + params.progressToSegments = 0f; + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f); + valueAnimator.addUpdateListener(animation -> { + params.progressToSegments = AndroidUtilities.lerp(0, 1f - collapsedProgress2, (float) animation.getAnimatedValue()); + invalidate(); + }); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + params.forceAnimateProgressToSegments = false; + } + }); + valueAnimator.setDuration(100); + valueAnimator.start(); + } + failT *= params.progressToSegments; + + params.animate = !progressWasDrawn; params.progressToArc = getArcProgress(cx, radius); params.isLast = isLast; params.isFirst = isFirst; - if (crossfadeToDialog) { + params.alpha = 1f - failT; + + if (!isSelf && crossfadeToDialog) { params.crossfadeToDialog = crossfadeToDialogId; params.crossfadeToDialogProgress = progressToCollapsed2; } else { params.crossfadeToDialog = 0; } - StoriesUtilities.drawAvatarWithStory(dialogId, canvas, avatarImage, storiesController.hasStories(dialogId), params); -// avatarImage.draw(canvas); + if (isSelf) { + StoriesUtilities.drawAvatarWithStory(dialogId, canvas, avatarImage, storiesController.hasSelfStories(), params); + } else { + StoriesUtilities.drawAvatarWithStory(dialogId, canvas, avatarImage, storiesController.hasStories(dialogId), params); + } + + + if (failT > 0) { + final Paint paint = StoriesUtilities.getErrorPaint(avatarImage); + paint.setStrokeWidth(AndroidUtilities.dp(2)); + paint.setAlpha((int) (0xFF * failT)); + canvas.drawCircle(x + finalSize / 2, y + finalSize / 2, (finalSize / 2 + AndroidUtilities.dp(4)) * params.getScale(), paint); + } + } + progressWasDrawn = false; + if (drawAvatar) { + canvas.save(); + float s = 1f - progressHalf; + canvas.scale(s, s, cx + AndroidUtilities.dp(16), cy + AndroidUtilities.dp(16)); + drawPlus(canvas, cx, cy, 1f); + drawFail(canvas, cx, cy, failT); + canvas.restore(); } } + canvas.restore(); if (crossfadeToDialog && progressToCollapsed2 > 0) { crossfageToAvatarImage.setImageCoords(x, y, finalSize, finalSize); @@ -1532,7 +1538,7 @@ public void invalidate(int l, int t, int r, int b) { } public void drawPlus(Canvas canvas, float cx, float cy, float alpha) { - if (!isSelf || storiesController.hasStories(dialogId) || !storiesController.getUploadingStories().isEmpty()) { + if (!isSelf || storiesController.hasStories(dialogId) || !Utilities.isNullOrEmpty(storiesController.getUploadingStories(dialogId))) { return; } float cx2 = cx + AndroidUtilities.dp(16); @@ -1561,7 +1567,7 @@ public void drawPlus(Canvas canvas, float cx, float cy, float alpha) { } public void drawFail(Canvas canvas, float cx, float cy, float alpha) { - if (!isSelf || alpha <= 0) { + if (alpha <= 0) { return; } float cx2 = cx + AndroidUtilities.dp(17); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/MessageMediaStoryFull.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/MessageMediaStoryFull.java index 3c5952a2bc7..80cc43583d2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/MessageMediaStoryFull.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/MessageMediaStoryFull.java @@ -15,6 +15,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { id = stream.readInt32(exception); storyItem = TLRPC.StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); via_mention = stream.readBool(exception); + peer = MessagesController.getInstance(UserConfig.selectedAccount).getPeer(user_id); } public void serializeToStream(AbstractSerializedData stream) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java index 4b0130062ab..7d20dedd365 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java @@ -1,6 +1,7 @@ package org.telegram.ui.Stories; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.ui.Stories.StoryMediaAreasView.getMediaAreasFor; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -55,14 +56,14 @@ import androidx.core.math.MathUtils; import androidx.recyclerview.widget.ChatListItemAnimator; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -104,6 +105,7 @@ import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.AvatarsImageView; import org.telegram.ui.Components.BackupImageView; @@ -132,8 +134,10 @@ import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RadialProgress; import org.telegram.ui.Components.Reactions.AnimatedEmojiEffect; +import org.telegram.ui.Components.Reactions.ReactionImageHolder; import org.telegram.ui.Components.Reactions.ReactionsEffectOverlay; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; +import org.telegram.ui.Components.Reactions.ReactionsUtils; import org.telegram.ui.Components.ReactionsContainerLayout; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.ShareAlert; @@ -145,6 +149,7 @@ import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.Components.voip.CellFlickerDrawable; +import org.telegram.ui.EmojiAnimationsOverlay; import org.telegram.ui.LaunchActivity; import org.telegram.ui.NotificationsCustomSettingsActivity; import org.telegram.ui.PinchToZoomHelper; @@ -167,6 +172,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Locale; +import java.util.Objects; public class PeerStoriesView extends SizeNotifierFrameLayout implements NotificationCenter.NotificationCenterDelegate { @@ -189,6 +195,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private final StoryCaptionView storyCaptionView; private CaptionContainerView storyEditCaptionView; private final ImageView shareButton; + private AnimatedTextView.AnimatedTextDrawable reactionsCounter; + private AnimatedFloat reactionsCounterProgress; + private boolean reactionsCounterVisible; private long currentImageTime; private long lastDrawTime; private boolean switchEventSent; @@ -200,9 +209,11 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private final ImageReceiver imageReceiver; private final ImageReceiver leftPreloadImageReceiver; private final ImageReceiver rightPreloadImageReceiver; + private final ArrayList preloadReactionHolders = new ArrayList<>();; private Runnable onImageReceiverThumbLoaded; private StoryMediaAreasView storyAreasView; + private EmojiAnimationsOverlay emojiAnimationsOverlay; private SelfStoriesPreviewView.ImageHolder viewsThumbImageReceiver; private float viewsThumbAlpha; @@ -216,7 +227,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica ActionBarMenuSubItem editStoryItem; CustomPopupMenu popupMenu; - TLRPC.TL_userStories userStories; + TLRPC.PeerStories userStories; final ArrayList storyItems; final ArrayList uploadingStories; final SharedResources sharedResources; @@ -227,6 +238,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica int count; private long dialogId; boolean isSelf; + boolean isChannel; private float alpha = 1f; private int previousSelectedPotision = -1; @@ -318,6 +330,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private Runnable reactionsTooltipRunnable; private float viewsThumbScale; private float viewsThumbPivotY; + private boolean userCanSeeViews; public PeerStoriesView(@NonNull Context context, StoryViewer storyViewer, SharedResources sharedResources, Theme.ResourcesProvider resourcesProvider) { super(context); @@ -399,13 +412,27 @@ protected void presentFragment(BaseFragment fragment) { storyViewer.presentFragment(fragment); } } + + @Override + public void showEffect(StoryReactionWidgetView v) { + if (!isSelf && currentStory.storyItem != null) { + ReactionsLayoutInBubble.VisibleReaction newReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(v.mediaArea.reaction); + ReactionsLayoutInBubble.VisibleReaction currentReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(currentStory.storyItem.sent_reaction); + if (!Objects.equals(newReaction, currentReaction)) { + likeStory(newReaction); + } + } + v.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + v.playAnimation(); + emojiAnimationsOverlay.showAnimationForWidget(v); + } }; storyContainer = new HwFrameLayout(context) { AnimatedFloat progressToAudio = new AnimatedFloat(this, 150, CubicBezierInterpolator.DEFAULT); AnimatedFloat progressToFullBlackoutA = new AnimatedFloat(this, 150, CubicBezierInterpolator.DEFAULT); - CellFlickerDrawable loadingDrawable = new CellFlickerDrawable(); + CellFlickerDrawable loadingDrawable = new CellFlickerDrawable(32, 102, 240); AnimatedFloat loadingDrawableAlpha2 = new AnimatedFloat(this); AnimatedFloat loadingDrawableAlpha = new AnimatedFloat(this); { @@ -587,6 +614,10 @@ protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); drawLines(canvas); } + + if (emojiAnimationsOverlay != null) { + emojiAnimationsOverlay.draw(canvas); + } } @Override @@ -671,6 +702,7 @@ private void drawLines(Canvas canvas) { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + emojiAnimationsOverlay.onAttachedToWindow(); Bulletin.addDelegate(this, new Bulletin.Delegate() { @Override public int getTopOffset(int tag) { @@ -705,6 +737,7 @@ public int getBottomOffset(int tag) { @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + emojiAnimationsOverlay.onDetachedFromWindow(); Bulletin.removeDelegate(this); if (delegate != null) { delegate.setBulletinIsVisible(false); @@ -725,10 +758,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } }; storyContainer.setClipChildren(false); -// SurfaceView surfaceView = new SurfaceView(context); -// playerSharedScope.surfaceView = surfaceView; - // storyContainer.addView(surfaceView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - // storyContainer.setClipChildren(false); + emojiAnimationsOverlay = new EmojiAnimationsOverlay(storyContainer, currentAccount); storyContainer.addView(storyAreasView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -874,10 +904,10 @@ public void onEmojiClick(AnimatedEmojiSpan span) { likeButtonContainer.setOnClickListener(v -> { if (currentStory.storyItem != null && currentStory.storyItem.sent_reaction == null) { applyMessageToChat(() -> { - likeStory(); + likeStory(null); }); } else { - likeStory(); + likeStory(null); } }); likeButtonContainer.setOnLongClickListener(v -> { @@ -896,7 +926,7 @@ public void onEmojiClick(AnimatedEmojiSpan span) { }); storiesLikeButton = new StoriesLikeButton(context, sharedResources); storiesLikeButton.setPadding(padding, padding, padding, padding); - likeButtonContainer.addView(storiesLikeButton); + likeButtonContainer.addView(storiesLikeButton, LayoutHelper.createFrame(40, 40, Gravity.LEFT)); ScaleStateListAnimator.apply(likeButtonContainer, 0.3f, 5f); imageReceiver.setAllowLoadingOnAttachedOnly(true); @@ -916,14 +946,11 @@ public void onEmojiClick(AnimatedEmojiSpan span) { MediaActivity mediaActivity = new MediaActivity(args, null); storyViewer.presentFragment(mediaActivity); } else { - Bundle args = new Bundle(); - args.putLong("user_id", dialogId); - ProfileActivity profileActivity = new ProfileActivity(args); - - BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); - params.transitionFromLeft = true; - params.allowNestedScroll = false; - storyViewer.presentFragment(profileActivity); + if (dialogId > 0) { + storyViewer.presentFragment(ProfileActivity.of(dialogId)); + } else { + storyViewer.presentFragment(ChatActivity.of(dialogId)); + } } // LaunchActivity.getLastFragment().showAsSheet(profileActivity, params); @@ -947,26 +974,18 @@ public void onEmojiClick(AnimatedEmojiSpan span) { final boolean[] popupStillVisible = new boolean[] { false }; if (isSelf) { MessagesController.getInstance(currentAccount).getStoriesController().loadBlocklistAtFirst(); + MessagesController.getInstance(currentAccount).getStoriesController().loadSendAs(); MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().load(); } popupMenu = new CustomPopupMenu(getContext(), resourcesProvider, isSelf) { private boolean edit; @Override protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout) { - if (isSelf) { + final boolean userCanEditStory = isSelf || MessagesController.getInstance(currentAccount).getStoriesController().canEditStory(currentStory.storyItem); + boolean canEditStory = isSelf || (isChannel && userCanEditStory); + if (canEditStory || currentStory.uploadingStory != null) { TLRPC.StoryItem storyItem = currentStory.storyItem; if (currentStory.uploadingStory != null) { -// if (currentStory.uploadingStory.failed) { -// ActionBarMenuSubItem item = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_edit, LocaleController.getString("Edit", R.string.Edit), false, resourcesProvider); -// item.setOnClickListener(v -> { -// Activity activity = AndroidUtilities.findActivity(context); -// if (activity == null) { -// return; -// } -// StoryRecorder.getInstance(activity, currentAccount) -// .openEdit(StoryRecorder.SourceView.fromStoryViewer(storyViewer), currentStory.uploadingStory.entry, 0, true); -// }); -// } ActionBarMenuSubItem item = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_cancel, LocaleController.getString("Cancel", R.string.Cancel), false, resourcesProvider); item.setOnClickListener(v -> { if (currentStory.uploadingStory != null) { @@ -983,22 +1002,24 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay } String str = currentStory.isVideo() ? LocaleController.getString("SaveVideo", R.string.SaveVideo) : LocaleController.getString("SaveImage", R.string.SaveImage); - final StoryPrivacyBottomSheet.StoryPrivacy storyPrivacy = new StoryPrivacyBottomSheet.StoryPrivacy(currentAccount, storyItem.privacy); - ActionBarMenuSubItem item = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_view_file, LocaleController.getString("WhoCanSee", R.string.WhoCanSee), false, resourcesProvider); - item.setSubtext(storyPrivacy.toString()); - item.setOnClickListener(v -> { - editPrivacy(storyPrivacy, storyItem); - if (popupMenu != null) { - popupMenu.dismiss(); - } - }); - item.setItemHeight(56); + if (isSelf) { + final StoryPrivacyBottomSheet.StoryPrivacy storyPrivacy = new StoryPrivacyBottomSheet.StoryPrivacy(currentAccount, storyItem.privacy); + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_view_file, LocaleController.getString("WhoCanSee", R.string.WhoCanSee), false, resourcesProvider); + item.setSubtext(storyPrivacy.toString()); + item.setOnClickListener(v -> { + editPrivacy(storyPrivacy, storyItem); + if (popupMenu != null) { + popupMenu.dismiss(); + } + }); + item.setItemHeight(56); - ActionBarPopupWindow.GapView gap = new ActionBarPopupWindow.GapView(getContext(), resourcesProvider, Theme.key_actionBarDefaultSubmenuSeparator); - gap.setTag(R.id.fit_width_tag, 1); - popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + ActionBarPopupWindow.GapView gap = new ActionBarPopupWindow.GapView(getContext(), resourcesProvider, Theme.key_actionBarDefaultSubmenuSeparator); + gap.setTag(R.id.fit_width_tag, 1); + popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + } - if (!unsupported && MessagesController.getInstance(currentAccount).storiesEnabled()) { + if (!unsupported && MessagesController.getInstance(currentAccount).storiesEnabled() && userCanEditStory) { editStoryItem = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_edit, LocaleController.getString("EditStory", R.string.EditStory), false, resourcesProvider); editStoryItem.setOnClickListener(v -> { if (v.getAlpha() < 1) { @@ -1024,6 +1045,10 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay StoryEntry entry = MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().getForEdit(currentStory.storyItem.dialogId, currentStory.storyItem); if (entry == null || entry.file == null || !entry.file.exists()) { entry = StoryEntry.fromStoryItem(currentStory.getPath(), currentStory.storyItem); + entry.editStoryPeerId = dialogId; + } + if (entry != null) { + entry = entry.copy(); } editor.openEdit(StoryRecorder.SourceView.fromStoryViewer(storyViewer), entry, time, true); editor.setOnPrepareCloseListener((t, close, sent) -> { @@ -1064,27 +1089,46 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay openEdit.run(); } }); - if (storiesController.hasUploadingStories() && currentStory.isVideo && !SharedConfig.allowPreparingHevcPlayers()) { + if (storiesController.hasUploadingStories(dialogId) && currentStory.isVideo && !SharedConfig.allowPreparingHevcPlayers()) { editStoryItem.setAlpha(0.5f); } } - final boolean pin = !storyItem.pinned; - ActionBarMenuItem.addItem(popupLayout, pin ? R.drawable.msg_save_story : R.drawable.menu_unsave_story, pin ? LocaleController.getString("SaveToProfile", R.string.SaveToProfile) : LocaleController.getString("ArchiveStory"), false, resourcesProvider).setOnClickListener(v -> { - ArrayList storyItems = new ArrayList<>(); - storyItems.add(storyItem); - MessagesController.getInstance(currentAccount).getStoriesController().updateStoriesPinned(storyItems, pin, success -> { - if (success) { - storyItem.pinned = pin; - BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(pin ? R.raw.contact_check : R.raw.chats_archived, pin ? LocaleController.getString("StoryPinnedToProfile", R.string.StoryPinnedToProfile) : LocaleController.getString("StoryArchivedFromProfile", R.string.StoryArchivedFromProfile)).show(); - } else { - BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(R.raw.error, LocaleController.getString("UnknownError", R.string.UnknownError)).show(); + if (isSelf || (isChannel && MessagesController.getInstance(currentAccount).getStoriesController().canEditStories(storyItem.dialogId))) { + final boolean pin = !storyItem.pinned; + String title; + if (isSelf) { + title = pin ? LocaleController.getString("SaveToProfile", R.string.SaveToProfile) : LocaleController.getString("ArchiveStory", R.string.ArchiveStory); + } else { + title = pin ? LocaleController.getString("SaveToPosts", R.string.SaveToPosts) : LocaleController.getString("RemoveFromPosts", R.string.RemoveFromPosts); + } + ActionBarMenuItem.addItem(popupLayout, pin ? R.drawable.msg_save_story : R.drawable.menu_unsave_story, title, false, resourcesProvider).setOnClickListener(v -> { + ArrayList storyItems = new ArrayList<>(); + storyItems.add(storyItem); + MessagesController.getInstance(currentAccount).getStoriesController().updateStoriesPinned(dialogId, storyItems, pin, success -> { + if (success) { + storyItem.pinned = pin; + if (isSelf) { + BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(pin ? R.raw.contact_check : R.raw.chats_archived, pin ? LocaleController.getString("StoryPinnedToProfile", R.string.StoryPinnedToProfile) : LocaleController.getString("StoryArchivedFromProfile", R.string.StoryArchivedFromProfile)).show(); + } else { + if (pin) { + BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(R.raw.contact_check, + LocaleController.getString("StoryPinnedToPosts", R.string.StoryPinnedToPosts), + LocaleController.getString("StoryPinnedToPostsDescription", R.string.StoryPinnedToPostsDescription) + ).show(); + } else { + BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(R.raw.chats_archived, LocaleController.getString("StoryUnpinnedFromPosts", R.string.StoryUnpinnedFromPosts)).show(); + } + } + } else { + BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(R.raw.error, LocaleController.getString("UnknownError", R.string.UnknownError)).show(); + } + }); + if (popupMenu != null) { + popupMenu.dismiss(); } }); - if (popupMenu != null) { - popupMenu.dismiss(); - } - }); + } if (!unsupported) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_gallery, str, false, resourcesProvider).setOnClickListener(v -> { @@ -1095,10 +1139,20 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay }); } - if (!MessagesController.getInstance(currentAccount).premiumLocked) { + if (!MessagesController.getInstance(currentAccount).premiumLocked && !isChannel) { createStealthModeItem(popupLayout); } + if (isChannel && allowShareLink) { + ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_link, LocaleController.getString("CopyLink", R.string.CopyLink), false, resourcesProvider).setOnClickListener(v -> { + AndroidUtilities.addToClipboard(currentStory.createLink()); + onLickCopied(); + if (popupMenu != null) { + popupMenu.dismiss(); + } + }); + } + if (allowShareLink) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_shareout, LocaleController.getString("BotShare", R.string.BotShare), false, resourcesProvider).setOnClickListener(v -> { shareStory(false); @@ -1108,15 +1162,17 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay }); } - ActionBarMenuSubItem deleteItem = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_delete, LocaleController.getString("Delete", R.string.Delete), false, resourcesProvider); - deleteItem.setSelectorColor(Theme.multAlpha(Theme.getColor(Theme.key_text_RedBold, resourcesProvider), .12f)); - deleteItem.setColors(resourcesProvider.getColor(Theme.key_text_RedBold), resourcesProvider.getColor(Theme.key_text_RedBold)); - deleteItem.setOnClickListener(v -> { - deleteStory(); - if (popupMenu != null) { - popupMenu.dismiss(); - } - }); + if (isSelf || MessagesController.getInstance(currentAccount).getStoriesController().canDeleteStory(currentStory.storyItem)) { + ActionBarMenuSubItem deleteItem = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_delete, LocaleController.getString("Delete", R.string.Delete), false, resourcesProvider); + deleteItem.setSelectorColor(Theme.multAlpha(Theme.getColor(Theme.key_text_RedBold, resourcesProvider), .12f)); + deleteItem.setColors(resourcesProvider.getColor(Theme.key_text_RedBold), resourcesProvider.getColor(Theme.key_text_RedBold)); + deleteItem.setOnClickListener(v -> { + deleteStory(); + if (popupMenu != null) { + popupMenu.dismiss(); + } + }); + } } else { // ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_mute, LocaleController.getString("Mute", R.string.Mute), false, resourcesProvider).setOnClickListener(v -> { // if (popupMenu != null) { @@ -1127,19 +1183,28 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay final String key = NotificationsController.getSharedPrefKey(dialogId, 0); boolean muted = !NotificationsCustomSettingsActivity.areStoriesNotMuted(currentAccount, dialogId); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + TLRPC.User user = null; + TLRPC.Chat chat = null; + TLObject object; + if (dialogId > 0) { + object = user = MessagesController.getInstance(currentAccount).getUser(dialogId); + } else { + object = chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + } + String name = user == null ? (chat == null ? "" : chat.title) : user.first_name.trim(); + int index = name.indexOf(" "); + if (index > 0) { + name = name.substring(0, index); + } + String finalName = name; if (!UserObject.isService(dialogId)) { if (!muted) { ActionBarMenuSubItem item = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_mute, LocaleController.getString("NotificationsStoryMute2", R.string.NotificationsStoryMute2), false, resourcesProvider); item.setOnClickListener(v -> { MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, false).apply(); NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(dialogId, 0); - String name = user == null ? "" : user.first_name.trim(); - int index = name.indexOf(" "); - if (index > 0) { - name = name.substring(0, index); - } - BulletinFactory.of(storyContainer, resourcesProvider).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryMutedHint", R.string.NotificationsStoryMutedHint, name))).setTag(2).show(); + + BulletinFactory.of(storyContainer, resourcesProvider).createUsersBulletin(Arrays.asList(object), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryMutedHint", R.string.NotificationsStoryMutedHint, finalName))).setTag(2).show(); if (popupMenu != null) { popupMenu.dismiss(); } @@ -1150,20 +1215,24 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay item.setOnClickListener(v -> { MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, true).apply(); NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(dialogId, 0); - String name = user == null ? "" : user.first_name.trim(); - int index = name.indexOf(" "); - if (index > 0) { - name = name.substring(0, index); - } - BulletinFactory.of(storyContainer, resourcesProvider).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryUnmutedHint", R.string.NotificationsStoryUnmutedHint, name))).setTag(2).show(); + BulletinFactory.of(storyContainer, resourcesProvider).createUsersBulletin(Arrays.asList(object), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryUnmutedHint", R.string.NotificationsStoryUnmutedHint, finalName))).setTag(2).show(); if (popupMenu != null) { popupMenu.dismiss(); } }); item.setMultiline(false); } - if (user != null && user.contact) { - if (!user.stories_hidden) { + boolean canShowArchive; + boolean storiesIsHidden; + if (dialogId > 0) { + canShowArchive = user != null && user.contact; + storiesIsHidden = user != null && user.stories_hidden; + } else { + canShowArchive = chat != null && !ChatObject.isNotInChat(chat); + storiesIsHidden = chat != null && chat.stories_hidden; + } + if (canShowArchive) { + if (!storiesIsHidden) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_archive, LocaleController.getString("ArchivePeerStories", R.string.ArchivePeerStories), false, resourcesProvider).setOnClickListener(v -> { toggleArchiveForStory(dialogId); if (popupMenu != null) { @@ -1218,7 +1287,7 @@ public void setColorFilter(ColorFilter colorFilter) { } } - if (!MessagesController.getInstance(currentAccount).premiumLocked) { + if (!MessagesController.getInstance(currentAccount).premiumLocked && !isChannel) { createStealthModeItem(popupLayout); } if (allowShareLink) { @@ -1403,14 +1472,11 @@ protected void onDismissed() { muteIconContainer.setOnClickListener(v -> { if (currentStory.hasSound()) { storyViewer.toggleSilentMode(); - } else { - if (soundTooltip == null) { - soundTooltip = new HintView2(context, HintView2.DIRECTION_TOP).setJoint(1, -56); - soundTooltip.setText(LocaleController.getString(R.string.StoryNoSound)); - soundTooltip.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); - storyContainer.addView(soundTooltip, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL_HORIZONTAL | Gravity.TOP, 0, 52, 0, 0)); + if (storyViewer.soundEnabled()) { + MessagesController.getGlobalMainSettings().edit().putInt("taptostorysoundhint", 3).apply(); } - soundTooltip.show(); + } else { + showNoSoundHint(true); } }); @@ -1421,6 +1487,7 @@ protected void onDismissed() { muteIconContainer.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); optionsIconView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); shareButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); + likeButtonContainer.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); View overlay = storyCaptionView.textSelectionHelper.getOverlayView(context); if (overlay != null) { @@ -1518,49 +1585,82 @@ public void onAnimationEnd(Animator animation) { } } - private void likeStory() { + + + private void likeStory(ReactionsLayoutInBubble.VisibleReaction visibleReaction) { if (currentStory.storyItem == null) { return; } - if (currentStory.storyItem.sent_reaction == null) { - TLRPC.TL_availableReaction reaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get("\u2764"); - if (reaction != null) { - drawAnimatedEmojiAsMovingReaction = false; - TLRPC.Document document = reaction.around_animation; - String filer = ReactionsEffectOverlay.getFilterForAroundAnimation(); - reactionEffectImageReceiver.setImage(ImageLocation.getForDocument(document), filer, null, null, null, 0); - if (reactionEffectImageReceiver.getLottieAnimation() != null) { - reactionEffectImageReceiver.getLottieAnimation().setCurrentFrame(0, false, true); - } - drawReactionEffect = true; - ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction); + boolean hasReactionOld = currentStory.storyItem != null && currentStory.storyItem.sent_reaction != null; + TLRPC.Reaction oldReaction = currentStory.storyItem.sent_reaction; + if (currentStory.storyItem.sent_reaction == null || visibleReaction != null) { + if (visibleReaction == null) { + TLRPC.TL_availableReaction reaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get("\u2764"); + if (reaction != null) { + drawAnimatedEmojiAsMovingReaction = false; + TLRPC.Document document = reaction.around_animation; + String filer = ReactionsEffectOverlay.getFilterForAroundAnimation(); + reactionEffectImageReceiver.setImage(ImageLocation.getForDocument(document), filer, null, null, null, 0); + if (reactionEffectImageReceiver.getLottieAnimation() != null) { + reactionEffectImageReceiver.getLottieAnimation().setCurrentFrame(0, false, true); + } + drawReactionEffect = true; + ReactionsLayoutInBubble.VisibleReaction likeReaction = ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction); + storiesController.setStoryReaction(dialogId, currentStory.storyItem, likeReaction); + } + } else { + animateLikeButton(); storiesController.setStoryReaction(dialogId, currentStory.storyItem, visibleReaction); } } else { - View oldLikeButton = storiesLikeButton; - oldLikeButton.animate().alpha(0).scaleX(0.8f).scaleY(0.8f).setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - AndroidUtilities.removeFromParent(oldLikeButton); - } - }).setDuration(150).start(); - int padding = dp(8); - storiesLikeButton = new StoriesLikeButton(getContext(), sharedResources); - storiesLikeButton.setPadding(padding, padding, padding, padding); - storiesLikeButton.setAlpha(0); - storiesLikeButton.setScaleX(0.8f); - storiesLikeButton.setScaleY(0.8f); - storiesLikeButton.animate().alpha(1f).scaleX(1f).scaleY(1f).setDuration(150); - likeButtonContainer.addView(storiesLikeButton); - drawReactionEffect = false; + animateLikeButton(); storiesController.setStoryReaction(dialogId, currentStory.storyItem, null); } + boolean added = false; + boolean counterChanged = false; if (currentStory.storyItem == null || currentStory.storyItem.sent_reaction == null) { + if (hasReactionOld) { + counterChanged = true; + } storiesLikeButton.setReaction(null); } else { + if (!hasReactionOld) { + counterChanged = true; + } storiesLikeButton.setReaction(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(currentStory.storyItem.sent_reaction)); performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + added = true; } + if (isChannel && counterChanged) { + if (currentStory.storyItem.views == null) { + currentStory.storyItem.views = new TLRPC.TL_storyViews(); + } + currentStory.storyItem.views.reactions_count += added ? 1 : -1; + if (currentStory.storyItem.views.reactions_count < 0) { + currentStory.storyItem.views.reactions_count = 0; + } + } + ReactionsUtils.applyForStoryViews(oldReaction, currentStory.storyItem.sent_reaction, currentStory.storyItem.views); + updateUserViews(true); + } + + private void animateLikeButton() { + View oldLikeButton = storiesLikeButton; + oldLikeButton.animate().alpha(0).scaleX(0.8f).scaleY(0.8f).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + AndroidUtilities.removeFromParent(oldLikeButton); + } + }).setDuration(150).start(); + int padding = dp(8); + storiesLikeButton = new StoriesLikeButton(getContext(), sharedResources); + storiesLikeButton.setPadding(padding, padding, padding, padding); + storiesLikeButton.setAlpha(0); + storiesLikeButton.setScaleX(0.8f); + storiesLikeButton.setScaleY(0.8f); + storiesLikeButton.animate().alpha(1f).scaleX(1f).scaleY(1f).setDuration(150); + likeButtonContainer.addView(storiesLikeButton, LayoutHelper.createFrame(40, 40, Gravity.LEFT)); + drawReactionEffect = false; } private ArrayList getAnimatedEmojiSets(StoryItemHolder storyHolder) { @@ -2295,7 +2395,7 @@ private void onLickCopied() { } TLRPC.TL_stories_exportStoryLink exportStoryLink = new TLRPC.TL_stories_exportStoryLink(); exportStoryLink.id = currentStory.storyItem.id; - exportStoryLink.user_id = MessagesController.getInstance(currentAccount).getInputUser(dialogId); + exportStoryLink.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); ConnectionsManager.getInstance(currentAccount).sendRequest(exportStoryLink, new RequestDelegate() { @Override public void run(TLObject response, TLRPC.TL_error error) { @@ -2327,6 +2427,8 @@ public void setDialogId(long dialogId, int selectedPosition) { private void bindInternal(int startFromPosition) { deletedPeer = false; forceUpdateOffsets = true; + userCanSeeViews = false; + isChannel = false; if (dialogId >= 0) { isSelf = dialogId == UserConfig.getInstance(currentAccount).getClientUserId(); TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); @@ -2354,15 +2456,21 @@ private void bindInternal(int startFromPosition) { headerView.titleView.setText(null); } } - if (isActive) { - storiesController.pollViewsForSelfStories(true); - } } else { + isSelf = false; + isChannel = true; + + //TODO uncomment if server support views for channels +// if (storiesController.canEditStories(dialogId)) { +// userCanSeeViews = true; +// } TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); avatarDrawable.setInfo(chat); headerView.backupImageView.getImageReceiver().setForUserOrChat(chat, avatarDrawable); headerView.titleView.setText(chat.title); - TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + } + if (isActive && (isSelf || isChannel)) { + storiesController.pollViewsForSelfStories(dialogId, true); } updateStoryItems(); this.selectedPosition = startFromPosition; @@ -2371,7 +2479,30 @@ private void bindInternal(int startFromPosition) { } currentImageTime = 0; switchEventSent = false; - if (isSelf) { + if (isChannel) { + createSelfPeerView(); + if (chatActivityEnterView != null) { + chatActivityEnterView.setVisibility(View.GONE); + } + if (reactionsCounter == null) { + reactionsCounter = new AnimatedTextView.AnimatedTextDrawable() { + @Override + public void invalidateSelf() { + invalidate(); + } + }; + reactionsCounter.setTextColor(resourcesProvider.getColor(Theme.key_windowBackgroundWhiteBlackText)); + reactionsCounter.setTextSize(AndroidUtilities.dp(14)); + reactionsCounterProgress = new AnimatedFloat(this); + } + if (startFromPosition == -1) { + updateSelectedPosition(); + } + updatePosition(); + count = getStoriesCount(); + storyContainer.invalidate(); + invalidate(); + } else if (isSelf) { createSelfPeerView(); selfView.setVisibility(View.VISIBLE); if (chatActivityEnterView != null) { @@ -2414,6 +2545,7 @@ private void bindInternal(int startFromPosition) { if (startFromPosition == -1) { updateSelectedPosition(); } + updatePosition(); if (chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.VISIBLE); chatActivityEnterView.getEditField().setText(storyViewer.getDraft(dialogId, currentStory.storyItem)); @@ -2430,7 +2562,7 @@ private void bindInternal(int startFromPosition) { if (selfView != null) { selfView.setVisibility(View.GONE); } - updatePosition(); + storyContainer.invalidate(); invalidate(); } @@ -2466,8 +2598,14 @@ private void createUnsupportedContainer() { ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_featuredStickers_buttonText, resourcesProvider), 30)) ); buttonTextView.setOnClickListener(v -> { - if (LaunchActivity.instance != null) { - LaunchActivity.instance.checkAppUpdate(true); + if (BuildVars.isStandaloneApp()) { + if (LaunchActivity.instance != null) { + LaunchActivity.instance.checkAppUpdate(true); + } + } else if (BuildVars.isHuaweiStoreApp()){ + Browser.openUrl(getContext(), BuildVars.HUAWEI_STORE_URL); + } else { + Browser.openUrl(getContext(), BuildVars.PLAYSTORE_APP_URL); } }); linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); @@ -2542,10 +2680,13 @@ private void updateStoryItems() { storyItems.add(storyViewer.storiesList.messageObjects.get(i).storyItem); } } else { - if (storyViewer.overrideUserStories != null && storyViewer.overrideUserStories.user_id == dialogId) { + if (storyViewer.overrideUserStories != null && DialogObject.getPeerDialogId(storyViewer.overrideUserStories.peer) == dialogId) { userStories = storyViewer.overrideUserStories; } else { userStories = storiesController.getStories(dialogId); + if (userStories == null) { + userStories = storiesController.getStoriesFromFullPeer(dialogId); + } } totalStoriesCount = 0; if (userStories != null) { @@ -2553,8 +2694,9 @@ private void updateStoryItems() { storyItems.addAll(userStories.stories); } uploadingStories.clear(); - if (isSelf) { - uploadingStories.addAll(storiesController.getUploadingStories()); + ArrayList list = storiesController.getUploadingStories(dialogId); + if (list != null) { + uploadingStories.addAll(list); } } count = getStoriesCount(); @@ -2641,22 +2783,19 @@ private void deleteStory() { AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), resourcesProvider); builder.setTitle(LocaleController.getString("DeleteStoryTitle", R.string.DeleteStoryTitle)); builder.setMessage(LocaleController.getString("DeleteStorySubtitle", R.string.DeleteStorySubtitle)); - builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - currentStory.cancelOrDelete(); - updateStoryItems(); - if (isActive && count == 0) { - delegate.switchToNextAndRemoveCurrentPeer(); - return; - } - if (selectedPosition >= count) { - selectedPosition = count - 1; - } else if (selectedPosition < 0) { - selectedPosition = 0; - } - updatePosition(); + builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), (dialog, which) -> { + currentStory.cancelOrDelete(); + updateStoryItems(); + if (isActive && count == 0) { + delegate.switchToNextAndRemoveCurrentPeer(); + return; } + if (selectedPosition >= count) { + selectedPosition = count - 1; + } else if (selectedPosition < 0) { + selectedPosition = 0; + } + updatePosition(); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (DialogInterface.OnClickListener) (dialog, which) -> { dialog.dismiss(); @@ -2687,10 +2826,21 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto @Override protected void dispatchDraw(Canvas canvas) { updateViewOffsets(); - if (reactionsLongpressTooltip != null && reactionsLongpressTooltip.shown() && likeButtonContainer.getVisibility() == View.VISIBLE && likeButtonContainer.getAlpha() == 1) { - reactionsLongpressTooltip.setTranslationY(-(getMeasuredHeight() - likeButtonContainer.getY()) - AndroidUtilities.dp(2)); + if (isChannel && reactionsCounter != null) { + reactionsCounter.setBounds(0, 0, getMeasuredWidth(), AndroidUtilities.dp(40)); } super.dispatchDraw(canvas); + float reactionScale = 0; + if (isChannel && reactionsCounter != null) { + canvas.save(); + canvas.translate(getMeasuredWidth() - reactionsCounter.getCurrentWidth() - AndroidUtilities.dp(12), likeButtonContainer.getY()); + reactionScale = reactionsCounterProgress.set(reactionsCounterVisible ? 1f : 0); + canvas.scale(reactionScale, reactionScale, reactionsCounter.getCurrentWidth() / 2f, AndroidUtilities.dp(20)); + reactionsCounter.setAlpha((int) (255 * likeButtonContainer.getAlpha())); + reactionsCounter.draw(canvas); + canvas.restore(); + } + updateButtonsOffsets(reactionScale); if (movingReaction) { float cX = likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; float cY = likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; @@ -2738,6 +2888,21 @@ protected void dispatchDraw(Canvas canvas) { } } + private void updateButtonsOffsets(float reactionScale) { + if (isChannel) { + float x = -reactionsCounter.getCurrentWidth() - AndroidUtilities.dp(4); + x *= reactionScale; + shareButton.setTranslationX(x); + likeButtonContainer.setTranslationX(x); + } else if (isSelf) { + shareButton.setTranslationX(AndroidUtilities.dp(40)); + likeButtonContainer.setTranslationX(0); + } else { + shareButton.setTranslationX(0); + likeButtonContainer.setTranslationX(0); + } + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -2750,6 +2915,9 @@ protected void onAttachedToWindow() { if (chatActivityEnterView != null) { chatActivityEnterView.onResume(); } + for (int i = 0; i < preloadReactionHolders.size(); i++) { + preloadReactionHolders.get(i).onAttachedToWindow(true); + } // sharedResources.muteDrawable.addView(muteIconView); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesListUpdated); @@ -2778,6 +2946,9 @@ protected void onDetachedFromWindow() { emojiReactionEffect.removeView(PeerStoriesView.this); emojiReactionEffect = null; } + for (int i = 0; i < preloadReactionHolders.size(); i++) { + preloadReactionHolders.get(i).onAttachedToWindow(false); + } //sharedResources.muteDrawable.removeView(muteIconView); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesListUpdated); @@ -2805,8 +2976,8 @@ public void didReceivedNotification(int id, int account, Object... args) { selectedPosition = storyItems.size() + uploadingStories.size() - 1; } updatePosition(); - if (isSelf) { - updateUserViews(); + if (isSelf || isChannel) { + updateUserViews(true); } } if (storyViewer.overrideUserStories != null) { @@ -2815,7 +2986,7 @@ public void didReceivedNotification(int id, int account, Object... args) { storiesController.loadSkippedStories(dialogId); } if (editStoryItem != null) { - editStoryItem.animate().alpha(storiesController.hasUploadingStories() && currentStory.isVideo && !SharedConfig.allowPreparingHevcPlayers() ? .5f : 1f).start(); + editStoryItem.animate().alpha(storiesController.hasUploadingStories(dialogId) && currentStory.isVideo && !SharedConfig.allowPreparingHevcPlayers() ? .5f : 1f).start(); } } else if (id == NotificationCenter.emojiLoaded) { storyCaptionView.captionTextview.invalidate(); @@ -2841,18 +3012,23 @@ public Activity getParentActivity() { return activity; } + @Override + public Theme.ResourcesProvider getResourceProvider() { + return new WrappedResourceProvider(resourcesProvider) { + @Override + public void appendColors() { + sparseIntArray.append(Theme.key_dialogBackground, 0xFF1F1F1F); + sparseIntArray.append(Theme.key_windowBackgroundGray, 0xFF333333); + } + }; + } + @Override public boolean presentFragment(BaseFragment fragment) { storyViewer.presentFragment(fragment); return true; } - }, activity, storyLimit.getLimitReachedType(), currentAccount, new WrappedResourceProvider(resourcesProvider) { - @Override - public void appendColors() { - sparseIntArray.append(Theme.key_dialogBackground, 0xFF1F1F1F); - sparseIntArray.append(Theme.key_windowBackgroundGray, 0xFF333333); - } - }); + }, activity, storyLimit.getLimitReachedType(), currentAccount, null); delegate.showDialog(sheet); } } @@ -2870,8 +3046,10 @@ private void checkStealthMode(boolean animated) { int time = stealthMode.active_until_date - ConnectionsManager.getInstance(currentAccount).getCurrentTime(); int minutes = time / 60; int seconds = time % 60; - if (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) < AndroidUtilities.dp(200)) { - chatActivityEnterView.setOverrideHint(LocaleController.formatString("StealthModeActiveHintShort", R.string.StealthModeActiveHintShort, String.format(Locale.US, "%02d:%02d", minutes, seconds)), animated); + String textToMeasure = LocaleController.formatString("StealthModeActiveHint", R.string.StealthModeActiveHintShort, String.format(Locale.US, "%02d:%02d", 99, 99)); + int w = (int) chatActivityEnterView.getEditField().getPaint().measureText(textToMeasure); + if (w * 1.2f >= chatActivityEnterView.getEditField().getMeasuredWidth()) { + chatActivityEnterView.setOverrideHint(LocaleController.formatString("StealthModeActiveHintShort", R.string.StealthModeActiveHintShort, ""), String.format(Locale.US, "%02d:%02d", minutes, seconds), animated); } else { chatActivityEnterView.setOverrideHint(LocaleController.formatString("StealthModeActiveHint", R.string.StealthModeActiveHint, String.format(Locale.US, "%02d:%02d", minutes, seconds)), animated); } @@ -2929,7 +3107,7 @@ private void updatePosition(boolean preload) { imageReceiver.setImage(null, null, ImageLocation.getForPath(uploadingStory.path), filter, null, null, thumbDrawable, 0, null, null, 0); } currentStory.set(uploadingStory); - storyAreasView.set(null); + storyAreasView.set(null, StoryMediaAreasView.getMediaAreasFor(uploadingStory.entry), emojiAnimationsOverlay); allowShare = allowShareLink = false; } else { isUploading = false; @@ -2940,7 +3118,7 @@ private void updatePosition(boolean preload) { return; } TLRPC.StoryItem storyItem = storyItems.get(position); - StoriesController.UploadingStory editingStory = storiesController.findEditingStory(storyItem); + StoriesController.UploadingStory editingStory = storiesController.findEditingStory(dialogId, storyItem); if (editingStory != null) { isEditing = true; imageReceiver.setCrossfadeWithOldImage(false); @@ -2951,7 +3129,7 @@ private void updatePosition(boolean preload) { imageReceiver.setImage(null, null, ImageLocation.getForPath(editingStory.firstFramePath), filter, /*messageObject.strippedThumb*/null, 0, null, null, 0); } currentStory.set(editingStory); - storyAreasView.set(null); + storyAreasView.set(null, StoryMediaAreasView.getMediaAreasFor(editingStory.entry), emojiAnimationsOverlay); currentStory.editingSourceItem = storyItem; allowShare = allowShareLink = false; } else { @@ -2996,8 +3174,8 @@ private void updatePosition(boolean preload) { if (thumbDrawable == null) { thumbDrawable = ImageLoader.createStripedBitmap(storyItem.media.document.thumbs); } - //imageReceiver.setImage(ImageLocation.getForDocument(size, storyItem.media.document), filter, null, null, thumbDrawable, 0, null, storyItem, 0); - imageReceiver.setImage(null, null, ImageLocation.getForDocument(storyItem.media.document), filter + "_pframe", ImageLocation.getForDocument(size, storyItem.media.document), filter, thumbDrawable, 0, null, storyItem, 0); + // imageReceiver.setImage(null, null, ImageLocation.getForDocument(storyItem.media.document), filter + "_pframe", ImageLocation.getForDocument(size, storyItem.media.document), filter, thumbDrawable, 0, null, storyItem, 0); + imageReceiver.setImage(null, null, ImageLocation.getForDocument(size, storyItem.media.document), filter, null, null, thumbDrawable, 0, null, storyItem, 0); } else { TLRPC.Photo photo = storyItem.media != null ? storyItem.media.photo : null; if (photo != null && photo.sizes != null) { @@ -3017,15 +3195,20 @@ private void updatePosition(boolean preload) { } } storyItem.dialogId = dialogId; - storyAreasView.set(preload ? null : storyItem.media_areas); + storyAreasView.set(preload ? null : storyItem, emojiAnimationsOverlay); currentStory.set(storyItem); allowShare = allowShareLink = !unsupported && currentStory.storyItem != null && !(currentStory.storyItem instanceof TLRPC.TL_storyItemDeleted) && !(currentStory.storyItem instanceof TLRPC.TL_storyItemSkipped); if (allowShare) { allowShare = currentStory.allowScreenshots() && currentStory.storyItem.isPublic; } if (allowShareLink) { - final TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - allowShareLink = user != null && UserObject.getPublicUsername(user) != null && currentStory.storyItem.isPublic; + if (isChannel) { + final TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + allowShareLink = chat != null && ChatObject.getPublicUsername(chat) != null; + } else { + final TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + allowShareLink = user != null && UserObject.getPublicUsername(user) != null && currentStory.storyItem.isPublic; + } } NotificationsController.getInstance(currentAccount).processReadStories(dialogId, storyItem.id); } @@ -3037,8 +3220,8 @@ private void updatePosition(boolean preload) { storyViewer.storiesViewPager.checkAllowScreenshots(); imageChanged = true; - if (isSelf) { - updateUserViews(); + if (isSelf || isChannel) { + updateUserViews(false); } final boolean sameId = @@ -3053,11 +3236,12 @@ private void updatePosition(boolean preload) { )) { storyChanged = true; if (chatActivityEnterView != null) { - if (oldStoryItem != null) { + if (oldStoryItem != null && !TextUtils.isEmpty(chatActivityEnterView.getEditField().getText())) { storyViewer.saveDraft(oldStoryItem.dialogId, oldStoryItem, chatActivityEnterView.getEditField().getText()); } chatActivityEnterView.getEditField().setText(storyViewer.getDraft(dialogId, currentStory.storyItem)); } + emojiAnimationsOverlay.clear(); currentImageTime = 0; switchEventSent = false; @@ -3133,7 +3317,7 @@ private void updatePosition(boolean preload) { } else { if (UserObject.isService(dialogId) && chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.GONE); - } else if (!isSelf && chatActivityEnterView != null) { + } else if (!isSelf && !isChannel && chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.VISIBLE); } if (isSelf && selfView != null) { @@ -3164,9 +3348,13 @@ private void updatePosition(boolean preload) { if (delegate != null && isSelectedPeer()) { delegate.onPeerSelected(dialogId, selectedPosition); } - shareButton.setVisibility(allowShare ? View.VISIBLE : View.GONE); - likeButtonContainer.setVisibility(isSelf ? View.GONE : View.VISIBLE); - shareButton.setTranslationX(isSelf ? AndroidUtilities.dp(40) : 0); + if (isChannel) { + shareButton.setVisibility(allowShare ? View.VISIBLE : View.GONE); + likeButtonContainer.setVisibility(isFailed ? View.GONE : View.VISIBLE); + } else { + shareButton.setVisibility(allowShare ? View.VISIBLE : View.GONE); + likeButtonContainer.setVisibility(isSelf ? View.GONE : View.VISIBLE); + } storyViewer.savedPositions.append(dialogId, position); @@ -3246,8 +3434,7 @@ private void updatePosition(boolean preload) { failViewAnimator.cancel(); failViewAnimator = null; } - if (sameId) { - failView.setVisibility(View.VISIBLE); + if (sameId && failView.getVisibility() == View.VISIBLE) { failViewAnimator = failView.animate().alpha(0f).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).withEndAction(() -> failView.setVisibility(View.GONE)); failViewAnimator.start(); } else { @@ -3261,7 +3448,7 @@ private void updatePosition(boolean preload) { FileLog.d("StoryViewer displayed story dialogId=" + dialogId + " storyId=" + currentStory.storyItem.id); } if (isSelf) { - SelfStoryViewsPage.preload(currentAccount, currentStory.storyItem); + SelfStoryViewsPage.preload(currentAccount, dialogId, currentStory.storyItem); } headerView.titleView.setPadding(0, 0, storyViewer.storiesList != null && storyViewer.storiesList.getCount() != linesCount ? AndroidUtilities.dp(56) : 0, 0); @@ -3274,19 +3461,29 @@ private void updatePosition(boolean preload) { } reactionsTooltipRunnable = null; if (reactionsLongpressTooltip == null) { - reactionsLongpressTooltip = new HintView2(getContext(), HintView2.DIRECTION_BOTTOM).setJoint(1, -AndroidUtilities.dp(8)); + reactionsLongpressTooltip = new HintView2(getContext(), HintView2.DIRECTION_BOTTOM).setJoint(1, -22); reactionsLongpressTooltip.setBgColor(ColorUtils.setAlphaComponent(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.13f), 240)); reactionsLongpressTooltip.setBounce(false); reactionsLongpressTooltip.setText(LocaleController.getString("ReactionLongTapHint", R.string.ReactionLongTapHint)); - reactionsLongpressTooltip.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); - addView(reactionsLongpressTooltip, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL_HORIZONTAL | Gravity.TOP, 0, 0, 0, 0)); + reactionsLongpressTooltip.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), AndroidUtilities.dp(1)); + storyContainer.addView(reactionsLongpressTooltip, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 0, BIG_SCREEN ? 0 : 56)); } reactionsLongpressTooltip.show(); SharedConfig.setStoriesReactionsLongPressHintUsed(true); }, 500); } + + if ((soundTooltip == null || !soundTooltip.shown()) && currentStory.hasSound() && !storyViewer.soundEnabled() && MessagesController.getGlobalMainSettings().getInt("taptostorysoundhint", 0) < 2) { + AndroidUtilities.cancelRunOnUIThread(showTapToSoundHint); + AndroidUtilities.runOnUIThread(showTapToSoundHint, 250); + } } + private final Runnable showTapToSoundHint = () -> { + showNoSoundHint(false); + MessagesController.getGlobalMainSettings().edit().putInt("taptostorysoundhint", MessagesController.getGlobalMainSettings().getInt("taptostorysoundhint", 0) + 1).apply(); + }; + private void createReplyDisabledView() { if (replyDisabledTextView != null) { return; @@ -3314,6 +3511,11 @@ private void updatePreloadImages() { uriesToPrepare.clear(); documentsToPrepare.clear(); + for (int i = 0; i < preloadReactionHolders.size(); i++) { + preloadReactionHolders.get(i).onAttachedToWindow(false); + } + preloadReactionHolders.clear(); + for (int i = 0; i < 2; i++) { int position = selectedPosition; ImageReceiver imageReceiver; @@ -3373,6 +3575,18 @@ private void updatePreloadImages() { e.printStackTrace(); } } + + if (storyItem.media_areas != null) { + for (int k = 0; k < storyItem.media_areas.size(); k++) { + if (storyItem.media_areas.get(k) instanceof TLRPC.TL_mediaAreaSuggestedReaction) { + TLRPC.TL_mediaAreaSuggestedReaction reaction = (TLRPC.TL_mediaAreaSuggestedReaction) storyItem.media_areas.get(k); + ReactionImageHolder reactionImageHolder = new ReactionImageHolder(this); + reactionImageHolder.setVisibleReaction(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(reaction.reaction)); + reactionImageHolder.onAttachedToWindow(attachedToWindow); + preloadReactionHolders.add(reactionImageHolder); + } + } + } } } // if (selfAvatarsContainer != null) { @@ -3382,7 +3596,7 @@ private void updatePreloadImages() { } private void setStoryImage(TLRPC.StoryItem storyItem, ImageReceiver imageReceiver, String filter) { - StoriesController.UploadingStory editingStory = storiesController.findEditingStory(storyItem); + StoriesController.UploadingStory editingStory = storiesController.findEditingStory(dialogId, storyItem); if (editingStory != null) { setStoryImage(editingStory, imageReceiver, filter); return; @@ -3438,54 +3652,100 @@ private void cancelWaiting() { } } - private void updateUserViews() { + private void updateUserViews(boolean animated) { TLRPC.StoryItem storyItem = currentStory.storyItem; if (storyItem == null) { storyItem = currentStory.editingSourceItem; } + if (!isChannel && !isSelf) { + return; + } if (storyItem != null) { - if (storyItem.views != null && storyItem.views.views_count > 0) { - int avatarsCount = 0; - int k = 0; - for (int i = 0; i < storyItem.views.recent_viewers.size(); i++) { - TLObject object = MessagesController.getInstance(currentAccount).getUserOrChat(storyItem.views.recent_viewers.get(i)); - if (object != null) { - selfAvatarsView.setObject(avatarsCount, currentAccount, object); - avatarsCount++; - } - if (avatarsCount >= 3) { - break; - } + if (isChannel) { + if (storyItem.views == null) { + storyItem.views = new TLRPC.TL_storyViews(); } - k = avatarsCount; - while (avatarsCount < 3) { - selfAvatarsView.setObject(avatarsCount, currentAccount, null); - avatarsCount++; + if (storyItem.views.views_count <= 0) { + storyItem.views.views_count = 1; } - selfAvatarsView.commitTransition(false); - SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(LocaleController.formatPluralStringComma("Views", storyItem.views.views_count)); if (storyItem.views.reactions_count > 0) { - spannableStringBuilder.append(" d "); - ColoredImageSpan span = new ColoredImageSpan(R.drawable.mini_views_likes); - span.setOverrideColor(0xFFFF2E38); - span.setTopOffset(AndroidUtilities.dp(0.2f)); - spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 2, spannableStringBuilder.length() - 1, 0); - spannableStringBuilder.append(String.valueOf(storyItem.views.reactions_count)); - } - selfStatusView.setText(spannableStringBuilder); - if (k == 0) { - selfAvatarsView.setVisibility(View.GONE); + reactionsCounter.setText(Integer.toString(storyItem.views.reactions_count), animated && reactionsCounterVisible); + reactionsCounterVisible = true; + } else { + reactionsCounterVisible = false; + } + if (!animated) { + reactionsCounterProgress.set(reactionsCounterVisible ? 1f : 0, true); + } + if (storyItem.views.views_count > 0) { + selfStatusView.setText(storyViewer.storiesList == null ? LocaleController.getString("NobodyViews", R.string.NobodyViews) : LocaleController.getString("NobodyViewsArchived", R.string.NobodyViewsArchived)); selfStatusView.setTranslationX(AndroidUtilities.dp(16)); + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); + stringBuilder.append("d "); + ColoredImageSpan span = new ColoredImageSpan(R.drawable.filled_views); + stringBuilder.setSpan(span, stringBuilder.length() - 3, stringBuilder.length() - 2, 0); + stringBuilder.append(AndroidUtilities.formatWholeNumber(storyItem.views.views_count, 0)); + selfStatusView.setText(stringBuilder); } else { - selfAvatarsView.setVisibility(View.VISIBLE); - selfStatusView.setTranslationX(AndroidUtilities.dp(13) + AndroidUtilities.dp(24) + AndroidUtilities.dp(20) * (k - 1) + AndroidUtilities.dp(10)); + selfStatusView.setText(""); } - selfAvatarsContainer.setVisibility(View.VISIBLE); - } else { - selfStatusView.setText(storyViewer.storiesList == null ? LocaleController.getString("NobodyViews", R.string.NobodyViews) : LocaleController.getString("NobodyViewsArchived", R.string.NobodyViewsArchived)); - selfStatusView.setTranslationX(AndroidUtilities.dp(16)); + if (reactionsCounterVisible) { + likeButtonContainer.getLayoutParams().width = (int) (AndroidUtilities.dp(40) + reactionsCounter.getAnimateToWidth() + AndroidUtilities.dp(4)); + ((LayoutParams) likeButtonContainer.getLayoutParams()).rightMargin = AndroidUtilities.dp(10) + AndroidUtilities.dp(40) - likeButtonContainer.getLayoutParams().width; + } else { + likeButtonContainer.getLayoutParams().width = AndroidUtilities.dp(40); + ((LayoutParams) likeButtonContainer.getLayoutParams()).rightMargin = AndroidUtilities.dp(10); + } + likeButtonContainer.requestLayout(); selfAvatarsView.setVisibility(View.GONE); selfAvatarsContainer.setVisibility(View.GONE); + storyAreasView.onStoryItemUpdated(currentStory.storyItem, animated); + } else { + if (storyItem.views != null && storyItem.views.views_count > 0) { + int avatarsCount = 0; + int k = 0; + for (int i = 0; i < storyItem.views.recent_viewers.size(); i++) { + TLObject object = MessagesController.getInstance(currentAccount).getUserOrChat(storyItem.views.recent_viewers.get(i)); + if (object != null) { + selfAvatarsView.setObject(avatarsCount, currentAccount, object); + avatarsCount++; + } + if (avatarsCount >= 3) { + break; + } + } + k = avatarsCount; + while (avatarsCount < 3) { + selfAvatarsView.setObject(avatarsCount, currentAccount, null); + avatarsCount++; + } + selfAvatarsView.commitTransition(false); + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(LocaleController.formatPluralStringComma("Views", storyItem.views.views_count)); + if (storyItem.views.reactions_count > 0) { + spannableStringBuilder.append(" d "); + ColoredImageSpan span = new ColoredImageSpan(R.drawable.mini_views_likes); + span.setOverrideColor(0xFFFF2E38); + span.setTopOffset(AndroidUtilities.dp(0.2f)); + spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 2, spannableStringBuilder.length() - 1, 0); + spannableStringBuilder.append(String.valueOf(storyItem.views.reactions_count)); + } + selfStatusView.setText(spannableStringBuilder); + if (k == 0) { + selfAvatarsView.setVisibility(View.GONE); + selfStatusView.setTranslationX(AndroidUtilities.dp(16)); + } else { + selfAvatarsView.setVisibility(View.VISIBLE); + selfStatusView.setTranslationX(AndroidUtilities.dp(13) + AndroidUtilities.dp(24) + AndroidUtilities.dp(20) * (k - 1) + AndroidUtilities.dp(10)); + } + selfAvatarsContainer.setVisibility(View.VISIBLE); + } else { + selfStatusView.setText(storyViewer.storiesList == null ? LocaleController.getString("NobodyViews", R.string.NobodyViews) : LocaleController.getString("NobodyViewsArchived", R.string.NobodyViewsArchived)); + selfStatusView.setTranslationX(AndroidUtilities.dp(16)); + selfAvatarsView.setVisibility(View.GONE); + selfAvatarsContainer.setVisibility(View.GONE); + } + ((LayoutParams) likeButtonContainer.getLayoutParams()).rightMargin = AndroidUtilities.dp(10); + likeButtonContainer.getLayoutParams().width = AndroidUtilities.dp(40); } } else { selfStatusView.setText(""); @@ -3712,7 +3972,9 @@ public boolean findClickableView(ViewGroup container, float x, float y, boolean } child.getHitRect(AndroidUtilities.rectTmp2); if (child == storyAreasView && !storyAreasView.hasSelected() && (x < dp(60) || x > container.getMeasuredWidth() - dp(60))) { - + if (storyAreasView.hasClickableViews(x, y)) { + return true; + } } else if (keyboardVisible && child == chatActivityEnterView && y > AndroidUtilities.rectTmp2.top) { return true; } else if (!swipeToDissmiss && AndroidUtilities.rectTmp2.contains((int) x, (int) y) && (((child.isClickable() || child == reactionsContainerLayout) && child.isEnabled()) || (chatActivityEnterView != null && child == chatActivityEnterView.getRecordCircle()))) { @@ -3727,10 +3989,14 @@ public boolean findClickableView(ViewGroup container, float x, float y, boolean public void setAccount(int currentAccount) { this.currentAccount = currentAccount; storiesController = MessagesController.getInstance(currentAccount).storiesController; + emojiAnimationsOverlay.setAccount(currentAccount); if (reactionsContainerLayout != null) { reactionsContainerLayout.setCurrentAccount(currentAccount); reactionsContainerLayout.setMessage(null, null); } + if (likesReactionLayout != null) { + likesReactionLayout.setCurrentAccount(currentAccount); + } } public void setActive(boolean active) { @@ -3753,11 +4019,10 @@ public void setActive(long t, boolean active) { updatePreloadImages(); muteIconView.setAnimation(sharedResources.muteDrawable); isActive = true; + headerView.backupImageView.getImageReceiver().setVisible(true, true); if (currentStory.storyItem != null) { FileLog.d("StoryViewer displayed story dialogId=" + dialogId + " storyId=" + currentStory.storyItem.id); } - - //storyViewer.allowScreenshots(allowScreenshots); } else { cancelTextSelection(); muteIconView.clearAnimationDrawable(); @@ -3775,8 +4040,8 @@ public void setActive(long t, boolean active) { imageReceiver.setFileLoadingPriority(isActive ? FileLoader.PRIORITY_HIGH : FileLoader.PRIORITY_NORMAL_UP); leftPreloadImageReceiver.setFileLoadingPriority(isActive ? FileLoader.PRIORITY_NORMAL_UP : FileLoader.PRIORITY_LOW); rightPreloadImageReceiver.setFileLoadingPriority(isActive ? FileLoader.PRIORITY_NORMAL_UP : FileLoader.PRIORITY_LOW); - if (isSelf) { - storiesController.pollViewsForSelfStories(isActive); + if (isSelf || isChannel) { + storiesController.pollViewsForSelfStories(dialogId, isActive); } } } @@ -3997,8 +4262,14 @@ public boolean useSurfaceInViewPagerWorkAround() { return storyViewer.USE_SURFACE_VIEW && Build.VERSION.SDK_INT < 33; } - public void showNoSoundHint() { - muteIconContainer.callOnClick(); + public void showNoSoundHint(boolean nosound) { + if (soundTooltip == null) { + soundTooltip = new HintView2(getContext(), HintView2.DIRECTION_TOP).setJoint(1, -56); + soundTooltip.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + storyContainer.addView(soundTooltip, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL_HORIZONTAL | Gravity.TOP, 0, 52, 0, 0)); + } + soundTooltip.setText(LocaleController.getString(nosound ? R.string.StoryNoSound : R.string.StoryTapToSound)); + soundTooltip.show(); } public boolean checkTextSelectionEvent(MotionEvent ev) { @@ -4046,6 +4317,10 @@ public boolean checkReactionEvent(MotionEvent ev) { return false; } + public boolean viewsAllowed() { + return isSelf || (isChannel && userCanSeeViews); + } + public static class PeerHeaderView extends FrameLayout { public BackupImageView backupImageView; @@ -4367,7 +4642,7 @@ public void clear() { void cancelOrDelete() { if (storyItem != null) { - storiesController.deleteStory(storyItem); + storiesController.deleteStory(dialogId, storyItem); } else if (uploadingStory != null) { uploadingStory.cancel(); } @@ -4378,7 +4653,7 @@ public boolean isEmpty() { } public void checkSendView() { - TLRPC.TL_userStories userStories = PeerStoriesView.this.userStories; + TLRPC.PeerStories userStories = PeerStoriesView.this.userStories; if (userStories == null) { userStories = storiesController.getStories(dialogId); if (userStories == null) { @@ -4433,8 +4708,19 @@ boolean hasSound() { } public String createLink() { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - return String.format(Locale.US, "https://t.me/%s/s/%s", UserObject.getPublicUsername(user), currentStory.storyItem.id); + if (dialogId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (UserObject.getPublicUsername(user) == null) { + return null; + } + return String.format(Locale.US, "https://t.me/%s/s/%s", UserObject.getPublicUsername(user), currentStory.storyItem.id); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (ChatObject.getPublicUsername(chat) == null) { + return null; + } + return String.format(Locale.US, "https://t.me/%s/s/%s", ChatObject.getPublicUsername(chat), currentStory.storyItem.id); + } // return String.format(Locale.US, "tg://resolve?domain=%s&story=%s", user.username, currentStory.storyItem.id); } @@ -4915,7 +5201,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { sharedResources.dimPaint.setAlpha((int) (125 * progressToKeyboard)); canvas.drawRect(0, 0, getMeasuredWidth(), chatActivityEnterView.getY() + chatActivityEnterView.getAnimatedTop(), sharedResources.dimPaint); } - } else if (child == likesReactionLayout && chatActivityEnterView != null) { + } else if (child == likesReactionLayout) { child.setTranslationY(-(likesReactionLayout.getMeasuredHeight() - likesReactionLayout.getPaddingBottom()) + likeButtonContainer.getY() - AndroidUtilities.dp(18)); // if (progressToKeyboard > 0) { // sharedResources.dimPaint.setAlpha((int) (125 * progressToKeyboard)); @@ -5040,8 +5326,9 @@ public void appendColors() { sparseIntArray.put(Theme.key_chat_emojiPanelBackground, ColorUtils.setAlphaComponent(Color.WHITE, 30)); } }); + reactionsContainerLayout.setHint(LocaleController.getString("StoryReactionsHint", R.string.StoryReactionsHint)); reactionsContainerLayout.skipEnterAnimation = true; - addView(reactionsContainerLayout, reactionsContainerIndex, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 52, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 64)); + addView(reactionsContainerLayout, reactionsContainerIndex, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 52 + 20, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 64)); reactionsContainerLayout.setDelegate(new ReactionsContainerLayout.ReactionsContainerDelegate() { @Override public void onReactionClicked(View view, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean longpress, boolean addToRecent) { @@ -5113,7 +5400,7 @@ public void hideMenu() { } @Override - public void drawRoundRect(Canvas canvas, RectF rect, float radius, float offsetX, float offsetY) { + public void drawRoundRect(Canvas canvas, RectF rect, float radius, float offsetX, float offsetY, int alpha, boolean isWindow) { bitmapShaderTools.setBounds(-offsetX, -offsetY, -offsetX + getMeasuredWidth(), -offsetY + getMeasuredHeight()); @@ -5151,7 +5438,7 @@ public void appendColors() { }); likesReactionLayout.setPadding(0, 0, 0, AndroidUtilities.dp(22)); - addView(likesReactionLayout, reactionsContainerIndex, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 52 + 22, Gravity.TOP | Gravity.RIGHT, 0, 0, 12, 64)); + addView(likesReactionLayout, getChildCount() - 1, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 52 + 22, Gravity.TOP | Gravity.RIGHT, 0, 0, 12, 64)); likesReactionLayout.setVisibility(View.GONE); likesReactionLayout.setDelegate(new ReactionsContainerLayout.ReactionsContainerDelegate() { @Override @@ -5169,7 +5456,7 @@ public void onAnimationEnd(Animator animation) { int padding = dp(8); storiesLikeButton = new StoriesLikeButton(getContext(), sharedResources); storiesLikeButton.setPadding(padding, padding, padding, padding); - likeButtonContainer.addView(storiesLikeButton); + likeButtonContainer.addView(storiesLikeButton, LayoutHelper.createFrame(40, 40, Gravity.LEFT)); if (reactionMoveDrawable != null) { reactionMoveDrawable.removeView(PeerStoriesView.this); @@ -5198,6 +5485,14 @@ public void onAnimationEnd(Animator animation) { } } storiesLikeButton.setReaction(visibleReaction); + if (isChannel && currentStory.storyItem.sent_reaction == null) { + if (currentStory.storyItem.views == null) { + currentStory.storyItem.views = new TLRPC.TL_storyViews(); + } + currentStory.storyItem.views.reactions_count++; + ReactionsUtils.applyForStoryViews(null, currentStory.storyItem.sent_reaction, currentStory.storyItem.views); + updateUserViews(true); + } if (visibleReaction.documentId != 0 && storiesLikeButton.emojiDrawable != null) { emojiReactionEffect = AnimatedEmojiEffect.createFrom(storiesLikeButton.emojiDrawable, false, true); emojiReactionEffect.setView(PeerStoriesView.this); @@ -5265,6 +5560,7 @@ public boolean needEnterText() { }); likesReactionLayout.setMessage(null, null); } else { + bringChildToFront(likesReactionLayout); likesReactionLayout.reset(); } likesReactionLayout.setFragment(LaunchActivity.getLastFragment()); @@ -5382,8 +5678,9 @@ private void editPrivacy(StoryPrivacyBottomSheet.StoryPrivacy currentPrivacy, TL .enableSharing(false) // .allowSmallChats(false) .isEdit(true) - .whenSelectedRules((privacy, a, b, whenDone) -> { + .whenSelectedRules((privacy, a, b, sendAs, whenDone) -> { TLRPC.TL_stories_editStory editStory = new TLRPC.TL_stories_editStory(); + editStory.peer = MessagesController.getInstance(currentAccount).getInputPeer(storyItem.dialogId); editStory.id = storyItem.id; editStory.flags |= 4; editStory.privacy_rules = privacy.rules; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java index 0386bb67c27..88fd69c6a20 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java @@ -8,6 +8,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; @@ -35,11 +36,13 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.RadialProgress; import org.telegram.ui.ProfileActivity; import java.util.ArrayList; @@ -56,7 +59,7 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif private final Paint whitePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final int currentAccount; - private final long userId; + private final long dialogId; private final View avatarContainer; private final ProfileActivity.AvatarImageView avatarImage; @@ -70,6 +73,21 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif private final ArrayList circles = new ArrayList<>(); private boolean attached; + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private boolean lastDrawnStateIsFailed; + private RadialProgress radialProgress; + private boolean progressWasDrawn; + private boolean progressIsDone; + private float bounceScale = 1f; + private float progressToInsets = 1f; + + public void setProgressToStoriesInsets(float progressToInsets) { + if (this.progressToInsets == progressToInsets) { + return; + } + this.progressToInsets = progressToInsets; + invalidate(); + } private class StoryCircle { public StoryCircle(TLRPC.StoryItem storyItem) { @@ -112,13 +130,16 @@ public void apply() { } } - public ProfileStoriesView(Context context, int currentAccount, long userId, @NonNull View avatarContainer, ProfileActivity.AvatarImageView avatarImage, Theme.ResourcesProvider resourcesProvider) { + StoriesController storiesController; + + public ProfileStoriesView(Context context, int currentAccount, long dialogId, @NonNull View avatarContainer, ProfileActivity.AvatarImageView avatarImage, Theme.ResourcesProvider resourcesProvider) { super(context); this.currentAccount = currentAccount; - this.userId = userId; + this.dialogId = dialogId; this.avatarContainer = avatarContainer; this.avatarImage = avatarImage; + storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); storiesGradientTools = new StoriesGradientTools(); storiesGradientTools.paint.setStyle(Paint.Style.STROKE); @@ -140,7 +161,8 @@ public ProfileStoriesView(Context context, int currentAccount, long userId, @Non titleDrawable.setCallback(this); clipOutAvatar.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); - + paint.setStrokeWidth(dpf2(2.33f)); + paint.setStyle(Paint.Style.STROKE); updateStories(false, false); } @@ -149,18 +171,18 @@ protected boolean verifyDrawable(@NonNull Drawable who) { return who == titleDrawable || super.verifyDrawable(who); } - private TLRPC.UserFull userFull; - public void setUserFull(TLRPC.UserFull userFull) { - this.userFull = userFull; + private TLRPC.PeerStories peerStories; + public void setStories(TLRPC.PeerStories peerStories) { + this.peerStories = peerStories; updateStories(true, false); } private void updateStories(boolean animated, boolean asUpdate) { - final boolean me = userId == UserConfig.getInstance(currentAccount).getClientUserId(); - TLRPC.TL_userStories userFullStories = userFull != null && !me ? userFull.stories : null; - TLRPC.TL_userStories stateStories = MessagesController.getInstance(currentAccount).getStoriesController().getStories(userId); - final TLRPC.TL_userStories userStories; - if (userId == 0) { + final boolean me = dialogId == UserConfig.getInstance(currentAccount).getClientUserId(); + TLRPC.PeerStories userFullStories = peerStories; + TLRPC.PeerStories stateStories = MessagesController.getInstance(currentAccount).getStoriesController().getStories(dialogId); + final TLRPC.PeerStories userStories; + if (dialogId == 0) { userStories = null; // } else if (stateStories != null) { // userStories = stateStories; @@ -309,7 +331,7 @@ private void updateStories(boolean animated, boolean asUpdate) { } if (index == -1) { - storyItem.dialogId = userId; + storyItem.dialogId = dialogId; StoryCircle circle = new StoryCircle(storyItem); circle.index = i; circle.scale = 1f; @@ -368,6 +390,8 @@ public void setActionBarActionMode(float progress) { private final AnimatedFloat segmentsCountAnimated = new AnimatedFloat(this, 0, 240 * 2, CubicBezierInterpolator.EASE_OUT_QUINT); private final AnimatedFloat segmentsUnreadCountAnimated = new AnimatedFloat(this, 0, 240, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat progressToUploading = new AnimatedFloat(this, 0, 150, CubicBezierInterpolator.DEFAULT); + private final AnimatedFloat progressToFail = new AnimatedFloat(this, 0, 150, CubicBezierInterpolator.DEFAULT); private float newStoryBounceT = 1; private ValueAnimator newStoryBounce; @@ -425,7 +449,8 @@ public void onAnimationEnd(Animator animation) { @Override protected void dispatchDraw(Canvas canvas) { float rright = rightAnimated.set(this.right); - float insetMain = 0; + float insetMain = AndroidUtilities.dpf2(3.5f); + insetMain *= progressToInsets; float ax = avatarContainer.getX() + insetMain * avatarContainer.getScaleX(); float ay = avatarContainer.getY() + insetMain * avatarContainer.getScaleY(); float aw = (avatarContainer.getWidth() - insetMain * 2) * avatarContainer.getScaleX(); @@ -454,13 +479,115 @@ protected void dispatchDraw(Canvas canvas) { Collections.sort(circles, (a, b) -> (int) (b.cachedIndex - a.cachedIndex)); } - final float segmentsAlpha = clamp(1f - expandProgress / 0.2f, 1, 0); - final float segmentsCount = segmentsCountAnimated.set(count); - final float segmentsUnreadCount = segmentsUnreadCountAnimated.set(unreadCount); + float segmentsAlpha = clamp(1f - expandProgress / 0.2f, 1, 0); + boolean isFailed = storiesController.isLastUploadingFailed(dialogId); + boolean isUploading = (storiesController.hasUploadingStories(dialogId) && !isFailed) || progressWasDrawn && !progressIsDone; + + float progressToUploading = this.progressToUploading.set(isUploading); + + canvas.save(); + canvas.scale(bounceScale, bounceScale, rect1.centerX(), rect1.centerY()); -// float cy = lerp(rect1.centerY(), this.cy, expandProgress); float cy = lerp(rect1.centerY(), this.expandY, expandProgress); storiesGradientTools.setBounds(this.left, cy - dp(24), this.right, cy + dp(24)); + if (progressToUploading > 0) { + rect2.set(rect1); + rect2.inset(-dpf2(2.66f + 2.23f / 2), -dpf2(2.66f + 2.23f / 2)); + if (radialProgress == null) { + radialProgress = new RadialProgress(this); + radialProgress.setBackground(null, true, false); + } + float uploadingProgress = 0; + if (!storiesController.hasUploadingStories(dialogId) || storiesController.isLastUploadingFailed(dialogId)) { + uploadingProgress = 1f; + } else { + ArrayList uploadingOrEditingStories = storiesController.getUploadingStories(dialogId); + for (int i = 0; i < uploadingOrEditingStories.size(); i++) { + uploadingProgress += uploadingOrEditingStories.get(i).progress; + } + uploadingProgress = uploadingProgress / uploadingOrEditingStories.size(); + } + radialProgress.setDiff(0); + storiesGradientTools.paint.setAlpha((int) (255 * segmentsAlpha * progressToUploading)); + storiesGradientTools.paint.setStrokeWidth(dpf2(2.33f)); + radialProgress.setPaint(storiesGradientTools.paint); + radialProgress.setProgressRect((int) rect2.left, (int) rect2.top, (int) rect2.right, (int) rect2.bottom); + radialProgress.setProgress(Utilities.clamp(uploadingProgress, 1f, 0.2f), true); + radialProgress.draw(canvas); + progressWasDrawn = true; + boolean oldIsDone = progressIsDone; + progressIsDone = radialProgress.getAnimatedProgress() >= 0.98f; + if (oldIsDone != progressIsDone) { + animateBounce(); + } + } else { + progressWasDrawn = false; + } + if (progressToUploading < 1f) { + segmentsAlpha = clamp(1f - expandProgress / 0.2f, 1, 0) * (1f - progressToUploading); + final float segmentsCount = segmentsCountAnimated.set(count); + final float segmentsUnreadCount = segmentsUnreadCountAnimated.set(unreadCount); + + storiesGradientTools.setBounds(this.left, cy - dp(24), this.right, cy + dp(24)); + if (isFailed) { + rect2.set(rect1); + rect2.inset(-dpf2(2.66f + 2.23f / 2), -dpf2(2.66f + 2.23f / 2)); + final Paint paint = StoriesUtilities.getErrorPaint(rect2); + paint.setStrokeWidth(AndroidUtilities.dp(2)); + paint.setAlpha((int) (255 * segmentsAlpha)); + canvas.drawCircle(rect2.centerX(), rect2.centerY(), rect2.width() / 2f, paint); + } else if (mainCircle != null && segmentsAlpha > 0) { + rect2.set(rect1); + rect2.inset(-dpf2(2.66f + 2.23f / 2), -dpf2(2.66f + 2.23f / 2)); + rect3.set(rect1); + rect3.inset(-dpf2(2.66f + 1.5f / 2), -dpf2(2.66f + 1.5f / 2)); + + final float separatorAngle = lerp(0, (float) (dpf2(2 + 2.23f) / (rect1.width() * Math.PI) * 360f), clamp(segmentsCount - 1, 1, 0) * segmentsAlpha); + final float maxCount = 50; // (float) (AndroidUtilities.dp(60) * Math.PI / dpf2(4)); + + final int mcount = Math.min(count, (int) maxCount); + final float animcount = Math.min(segmentsCount, maxCount); + + final float widthAngle = (360 - Math.max(0, animcount) * separatorAngle) / Math.max(1, animcount); + readPaint.setColor(ColorUtils.blendARGB(0x5affffff, 0x3a000000, actionBarProgress)); + readPaintAlpha = readPaint.getAlpha(); + float a = -90 - separatorAngle / 2f; + + for (int i = 0; i < mcount; ++i) { + final float read = 1f - clamp(segmentsUnreadCount - i, 1, 0); + final float appear = 1f - clamp(mcount - animcount - i, 1, 0); + if (appear < 0) { + continue; + } + + float bounceScale = i == 0 ? 1 + (newStoryBounceT - 1) / 2.5f : 1f; + + if (bounceScale != 1) { + canvas.save(); + canvas.scale(bounceScale, bounceScale, rect2.centerX(), rect2.centerY()); + } + + if (read < 1) { + storiesGradientTools.paint.setAlpha((int) (0xFF * (1f - read) * segmentsAlpha)); + storiesGradientTools.paint.setStrokeWidth(dpf2(2.33f)); + canvas.drawArc(rect2, a, -widthAngle * appear, false, storiesGradientTools.paint); + } + + if (read > 0) { + readPaint.setAlpha((int) (readPaintAlpha * read * segmentsAlpha)); + readPaint.setStrokeWidth(dpf2(1.5f)); + canvas.drawArc(rect3, a, -widthAngle * appear, false, readPaint); + } + + if (bounceScale != 1) { + canvas.restore(); + } + + a -= widthAngle * appear + separatorAngle * appear; + } + } + } + if (expandProgress > 0 && segmentsAlpha < 1) { float ix = 0; w = 0; @@ -500,15 +627,15 @@ protected void dispatchDraw(Canvas canvas) { int wasAlpha = whitePaint.getAlpha(); whitePaint.setAlpha((int) (wasAlpha * expandProgress)); canvas.drawCircle( - circle.cachedRect.centerX(), - circle.cachedRect.centerY(), - Math.min(circle.cachedRect.width(), circle.cachedRect.height()) / 2f + - lerp( - dpf2(2.66f) + storiesGradientTools.paint.getStrokeWidth() / 2f, - dpf2(2.33f) - readPaint.getStrokeWidth() / 2f, - circle.cachedRead - ) * expandProgress, - whitePaint + circle.cachedRect.centerX(), + circle.cachedRect.centerY(), + Math.min(circle.cachedRect.width(), circle.cachedRect.height()) / 2f + + lerp( + dpf2(2.66f) + storiesGradientTools.paint.getStrokeWidth() / 2f, + dpf2(2.33f) - readPaint.getStrokeWidth() / 2f, + circle.cachedRead + ) * expandProgress, + whitePaint ); whitePaint.setAlpha(wasAlpha); } @@ -519,14 +646,14 @@ protected void dispatchDraw(Canvas canvas) { StoryCircle C = nearest(i + 1 < circles.size() ? circles.get(i + 1) : null, i + 2 < circles.size() ? circles.get(i + 2) : null, B); if (A != null && ( - Math.abs(A.borderRect.centerX() - B.borderRect.centerX()) < Math.abs(B.borderRect.width() / 2f - A.borderRect.width() / 2f) || - Math.abs(A.borderRect.centerX() - B.borderRect.centerX()) > A.borderRect.width() / 2f + B.borderRect.width() / 2f + Math.abs(A.borderRect.centerX() - B.borderRect.centerX()) < Math.abs(B.borderRect.width() / 2f - A.borderRect.width() / 2f) || + Math.abs(A.borderRect.centerX() - B.borderRect.centerX()) > A.borderRect.width() / 2f + B.borderRect.width() / 2f )) { A = null; } if (C != null && ( - Math.abs(C.borderRect.centerX() - B.borderRect.centerX()) < Math.abs(B.borderRect.width() / 2f - C.borderRect.width() / 2f) || - Math.abs(C.borderRect.centerX() - B.borderRect.centerX()) > C.borderRect.width() / 2f + B.borderRect.width() / 2f + Math.abs(C.borderRect.centerX() - B.borderRect.centerX()) < Math.abs(B.borderRect.width() / 2f - C.borderRect.width() / 2f) || + Math.abs(C.borderRect.centerX() - B.borderRect.centerX()) > C.borderRect.width() / 2f + B.borderRect.width() / 2f )) { C = null; } @@ -555,55 +682,8 @@ protected void dispatchDraw(Canvas canvas) { } canvas.restore(); } - if (mainCircle != null && segmentsAlpha > 0) { - rect2.set(rect1); - rect2.inset(-dpf2(2.66f + 2.23f / 2), -dpf2(2.66f + 2.23f / 2)); - rect3.set(rect1); - rect3.inset(-dpf2(2.66f + 1.5f / 2), -dpf2(2.66f + 1.5f / 2)); - - final float separatorAngle = lerp(0, (float) (dpf2(2 + 2.23f) / (rect1.width() * Math.PI) * 360f), clamp(segmentsCount - 1, 1, 0) * segmentsAlpha); - final float maxCount = 50; // (float) (AndroidUtilities.dp(60) * Math.PI / dpf2(4)); - - final int mcount = Math.min(count, (int) maxCount); - final float animcount = Math.min(segmentsCount, maxCount); - - final float widthAngle = (360 - Math.max(0, animcount) * separatorAngle) / Math.max(1, animcount); - readPaint.setColor(ColorUtils.blendARGB(0x5affffff, 0x3a000000, actionBarProgress)); - readPaintAlpha = readPaint.getAlpha(); - float a = -90 - separatorAngle / 2f; - for (int i = 0; i < mcount; ++i) { - final float read = 1f - clamp(segmentsUnreadCount - i, 1, 0); - final float appear = 1f - clamp(mcount - animcount - i, 1, 0); - if (appear < 0) { - continue; - } - - float bounceScale = i == 0 ? 1 + (newStoryBounceT - 1) / 2.5f : 1f; - - if (bounceScale != 1) { - canvas.save(); - canvas.scale(bounceScale, bounceScale, rect2.centerX(), rect2.centerY()); - } - - if (read < 1) { - storiesGradientTools.paint.setAlpha((int) (0xFF * (1f - read) * segmentsAlpha)); - storiesGradientTools.paint.setStrokeWidth(dpf2(2.33f)); - canvas.drawArc(rect2, a, -widthAngle * appear, false, storiesGradientTools.paint); - } - if (read > 0) { - readPaint.setAlpha((int) (readPaintAlpha * read * segmentsAlpha)); - readPaint.setStrokeWidth(dpf2(1.5f)); - canvas.drawArc(rect3, a, -widthAngle * appear, false, readPaint); - } - - if (bounceScale != 1) { - canvas.restore(); - } - - a -= widthAngle * appear + separatorAngle * appear; - } - } + canvas.restore(); // float titleAlpha = Math.max(0, (expandProgress - .5f) * 2f); // if (titleAlpha > 0) { @@ -616,6 +696,35 @@ protected void dispatchDraw(Canvas canvas) { // } } + private void animateBounce() { + AnimatorSet animatorSet = new AnimatorSet(); + ValueAnimator inAnimator = ValueAnimator.ofFloat(1, 1.05f); + inAnimator.setDuration(100); + inAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); + + ValueAnimator outAnimator = ValueAnimator.ofFloat(1.05f, 1f); + outAnimator.setDuration(250); + outAnimator.setInterpolator(new OvershootInterpolator()); + + ValueAnimator.AnimatorUpdateListener updater = animation -> { + avatarImage.bounceScale = bounceScale = (float) animation.getAnimatedValue(); + avatarImage.invalidate(); + invalidate(); + }; + inAnimator.addUpdateListener(updater); + outAnimator.addUpdateListener(updater); + animatorSet.playSequentially(inAnimator, outAnimator); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + avatarImage.bounceScale = bounceScale = 1f; + avatarImage.invalidate(); + invalidate(); + } + }); + animatorSet.start(); + } + private void clipCircle(Canvas canvas, StoryCircle circle, StoryCircle nextCircle) { if (nextCircle == null) { return; @@ -895,7 +1004,7 @@ public boolean onTouchEvent(MotionEvent event) { tapY = event.getY(); return true; } else if (event.getAction() == MotionEvent.ACTION_UP) { - if (hit && System.currentTimeMillis() - tapTime <= ViewConfiguration.getTapTimeout() && MathUtils.distance(tapX, tapY, event.getX(), event.getY()) <= AndroidUtilities.dp(12) && !circles.isEmpty()) { + if (hit && System.currentTimeMillis() - tapTime <= ViewConfiguration.getTapTimeout() && MathUtils.distance(tapX, tapY, event.getX(), event.getY()) <= AndroidUtilities.dp(12) && (storiesController.hasUploadingStories(dialogId) || storiesController.hasStories(dialogId) || !circles.isEmpty())) { onTap(provider); return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoriesPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoriesPreviewView.java index c4cd5726981..b87a37045bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoriesPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoriesPreviewView.java @@ -248,7 +248,6 @@ protected void onDraw(Canvas canvas) { imageReceiversTmp.get(i).onDetach(); } imageReceiversTmp.clear(); - // canvas.drawLine(getMeasuredWidth() / 2f, 0, getMeasuredWidth() / 2f, getMeasuredHeight(), new Paint()); } abstract void onDragging(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java index 994d48a14c0..e95b549b8e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java @@ -483,7 +483,8 @@ private void checkLoadMore() { } } - public void setStoryItem(SelfStoryViewsView.StoryItemInternal storyItem) { + public void setStoryItem(long dialogId, SelfStoryViewsView.StoryItemInternal storyItem) { + this.dialogId = dialogId; this.storyItem = storyItem; updateViewsVisibility(); updateViewState(false); @@ -507,7 +508,7 @@ private void updateViewsVisibility() { if (defaultModel != null) { defaultModel.release(); } - defaultModel = new ViewsModel(currentAccount, serverItem, true); + defaultModel = new ViewsModel(currentAccount, dialogId, serverItem, true); defaultModel.reloadIfNeed(state, showContactsFilter, showReactionsSort); defaultModel.loadNext(); MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(serverItem.id, defaultModel); @@ -581,7 +582,7 @@ private void updateViewsVisibility() { ((MarginLayoutParams) shadowView2.getLayoutParams()).topMargin = AndroidUtilities.dp(TOP_PADDING - 17); } - public static void preload(int currentAccount, TLRPC.StoryItem storyItem) { + public static void preload(int currentAccount, long dialogId, TLRPC.StoryItem storyItem) { if (storyItem == null) { return; } @@ -591,7 +592,7 @@ public static void preload(int currentAccount, TLRPC.StoryItem storyItem) { if (model != null) { model.release(); } - model = new ViewsModel(currentAccount, storyItem, true); + model = new ViewsModel(currentAccount, dialogId, storyItem, true); model.loadNext(); MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(storyItem.id, model); } @@ -651,14 +652,14 @@ public void setListBottomPadding(float bottomPadding) { public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.storiesUpdated) { if (storyItem.uploadingStory != null) { - TLRPC.TL_userStories stories = MessagesController.getInstance(currentAccount).storiesController.getStories(UserConfig.getInstance(currentAccount).clientUserId); + TLRPC.PeerStories stories = MessagesController.getInstance(currentAccount).storiesController.getStories(UserConfig.getInstance(currentAccount).clientUserId); if (stories != null) { for (int i = 0; i < stories.stories.size(); i++) { TLRPC.StoryItem storyItem = stories.stories.get(i); if (storyItem.attachPath != null && storyItem.attachPath.equals(this.storyItem.uploadingStory.path)) { this.storyItem.uploadingStory = null; this.storyItem.storyItem = storyItem; - setStoryItem(this.storyItem); + setStoryItem(dialogId, this.storyItem); break; } } @@ -955,6 +956,7 @@ public static class ViewsModel { public int totalCount; TLRPC.StoryItem storyItem; + private long dialogId; int currentAccount; boolean loading; ArrayList views = new ArrayList<>(); @@ -971,9 +973,10 @@ public static class ViewsModel { ArrayList listeners = new ArrayList<>(); FiltersState state = new FiltersState(); - public ViewsModel(int currentAccount, TLRPC.StoryItem storyItem, boolean isDefault) { + public ViewsModel(int currentAccount, long dialogId, TLRPC.StoryItem storyItem, boolean isDefault) { this.currentAccount = currentAccount; this.storyItem = storyItem; + this.dialogId = dialogId; this.totalCount = storyItem.views == null ? 0 : storyItem.views.views_count; if (totalCount < 200) { useLocalFilters = true; @@ -1006,6 +1009,7 @@ public void loadNext() { } TLRPC.TL_stories_getStoryViewsList req = new TLRPC.TL_stories_getStoryViewsList(); req.id = storyItem.id; + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); if (useLocalFilters) { req.q = ""; req.just_contacts = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsView.java index ff177e741f3..94addcd90a2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsView.java @@ -22,6 +22,7 @@ import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; @@ -48,6 +49,7 @@ public class SelfStoryViewsView extends FrameLayout { int keyboardHeight; int animatedKeyboardHeight; + private long dialogId; ViewPagerInner viewPager; ArrayList storyItems = new ArrayList<>(); @@ -197,7 +199,7 @@ public void onTopOffsetChanged(int paddingTop) { item.setTag(position); item.setShadowDrawable(shadowDrawable); item.setPadding(0, AndroidUtilities.dp(16), 0 , 0); - item.setStoryItem(storyItems.get(position)); + item.setStoryItem(dialogId,storyItems.get(position)); // bottomPadding = (selfStoriesPreviewView.getTop() + toHeight + AndroidUtilities.dp(24)); item.setListBottomPadding(bottomPadding); @@ -346,14 +348,18 @@ private void updateTranslation() { viewPagerContainer.setTranslationY(-bottomPadding + getMeasuredHeight() - selfStoriesViewsOffset); } - public void setItems(ArrayList storyItems, int selectedPosition) { + public void setItems(long dialogId, ArrayList storyItems, int selectedPosition) { this.storyItems.clear(); + this.dialogId = dialogId; for (int i = 0; i < storyItems.size(); i++) { this.storyItems.add(new StoryItemInternal(storyItems.get(i))); } - ArrayList uploadingStories = MessagesController.getInstance(storyViewer.currentAccount).storiesController.getUploadingStories(); - for (int i = 0; i < uploadingStories.size(); i++) { - this.storyItems.add(new StoryItemInternal(uploadingStories.get(i))); + long clientUserId = UserConfig.getInstance(UserConfig.selectedAccount).getClientUserId(); + ArrayList uploadingStories = MessagesController.getInstance(storyViewer.currentAccount).storiesController.getUploadingStories(clientUserId); + if (uploadingStories != null) { + for (int i = 0; i < uploadingStories.size(); i++) { + this.storyItems.add(new StoryItemInternal(uploadingStories.get(i))); + } } selfStoriesPreviewView.setItems(this.storyItems, selectedPosition); viewPager.setAdapter(null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java index 165e1e1c4ee..4ad0efb02c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java @@ -2,8 +2,8 @@ import android.content.Intent; import android.content.SharedPreferences; +import android.os.Bundle; import android.text.TextUtils; -import android.util.Log; import android.util.SparseArray; import android.webkit.MimeTypeMap; @@ -20,6 +20,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.DownloadController; import org.telegram.messenger.FileLoader; @@ -46,13 +47,18 @@ import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.EmojiThemes; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.StatisticActivity; import org.telegram.ui.Stories.recorder.DraftsController; import org.telegram.ui.Stories.recorder.StoryEntry; import org.telegram.ui.Stories.recorder.StoryPrivacyBottomSheet; +import org.telegram.ui.Stories.recorder.StoryRecorder; import org.telegram.ui.Stories.recorder.StoryUploadingService; import java.io.File; @@ -68,7 +74,6 @@ import java.util.List; import java.util.Locale; import java.util.Objects; -import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -79,20 +84,20 @@ public class StoriesController { public final static int STATE_UNREAD_CLOSE_FRIEND = 2; private final int currentAccount; - private final ArrayList uploadingStories = new ArrayList<>(); - private final ArrayList uploadingAndEditingStories = new ArrayList<>(); - private final HashMap editingStories = new HashMap<>(); + private final LongSparseArray> uploadingStoriesByDialogId = new LongSparseArray<>(); + private final LongSparseArray> uploadingAndEditingStories = new LongSparseArray<>(); + private final LongSparseArray> editingStories = new LongSparseArray<>(); public LongSparseIntArray dialogIdToMaxReadId = new LongSparseIntArray(); - TLRPC.TL_userStories currentUserStories; + TLRPC.PeerStories currentUserStories; - private ArrayList dialogListStories = new ArrayList<>(); - private ArrayList hiddenListStories = new ArrayList<>(); - private LongSparseArray allStoriesMap = new LongSparseArray(); + private ArrayList dialogListStories = new ArrayList<>(); + private ArrayList hiddenListStories = new ArrayList<>(); + private LongSparseArray allStoriesMap = new LongSparseArray(); private LongSparseIntArray loadingDialogsStories = new LongSparseIntArray(); StoriesStorage storiesStorage; SharedPreferences mainSettings; - final ViewsForSelfStoriesRequester pollingViewsForSelfStoriesRequester; + final LongSparseArray pollingViewsForSelfStoriesRequester = new LongSparseArray<>(); public final static Comparator storiesComparator = Comparator.comparingInt(o -> o.date); @@ -128,7 +133,6 @@ public StoriesController(int currentAccount) { totalStoriesCount = mainSettings.getInt("total_stores", 0); storiesReadLoaded = mainSettings.getBoolean("read_loaded", false); stealthMode = readStealthMode(mainSettings.getString("stories_stealth_mode", null)); - pollingViewsForSelfStoriesRequester = new ViewsForSelfStoriesRequester(this, currentAccount); storiesStorage.getMaxReadIds(longSparseIntArray -> dialogIdToMaxReadId = longSparseIntArray); sortStoriesRunnable = () -> { @@ -177,7 +181,7 @@ private void loadStoriesRead() { if (storiesReadLoaded) { return; } - TLRPC.TL_stories_getAllReadUserStories allReadUserStories = new TLRPC.TL_stories_getAllReadUserStories(); + TLRPC.TL_stories_getAllReadPeerStories allReadUserStories = new TLRPC.TL_stories_getAllReadPeerStories(); ConnectionsManager.getInstance(currentAccount).sendRequest(allReadUserStories, (response, error) -> { TLRPC.Updates updates = (TLRPC.Updates) response; if (updates == null) { @@ -191,20 +195,23 @@ private void loadStoriesRead() { }); } - private void sortDialogStories(ArrayList list) { + private void sortDialogStories(ArrayList list) { fixDeletedAndNonContactsStories(list); - Collections.sort(list, userStoriesComparator); + Collections.sort(list, peerStoriesComparator); } - private void fixDeletedAndNonContactsStories(ArrayList list) { + private void fixDeletedAndNonContactsStories(ArrayList list) { for (int k = 0; k < list.size(); k++) { - TLRPC.TL_userStories userStories = list.get(k); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(userStories.user_id); + TLRPC.PeerStories userStories = list.get(k); + long dialogId = DialogObject.getPeerDialogId(userStories.peer); boolean removed = false; - if (user != null && !isContactOrService(user)) { - list.remove(k); - k--; - removed = true; + if (dialogId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (user != null && !isContactOrService(user)) { + list.remove(k); + k--; + removed = true; + } } for (int i = 0; i < userStories.stories.size(); i++) { if (userStories.stories.get(i) instanceof TLRPC.TL_storyItemDeleted) { @@ -212,7 +219,7 @@ private void fixDeletedAndNonContactsStories(ArrayList lis i--; } } - if (!removed && userStories.stories.isEmpty()) { + if (!removed && userStories.stories.isEmpty() && !hasUploadingStories(dialogId)) { list.remove(k); k--; } @@ -225,13 +232,32 @@ public DraftsController getDraftsController() { } public boolean hasStories(long dialogId) { - if (getSelfUserId() == dialogId && hasUploadingStories()) { + if (dialogId == 0) { + return false; + } + if (hasUploadingStories(dialogId)) { + return true; + } + if (isLastUploadingFailed(dialogId)) { return true; } - TLRPC.TL_userStories stories = allStoriesMap.get(dialogId); + TLRPC.PeerStories stories = allStoriesMap.get(dialogId); + if (stories == null) { + stories = getStoriesFromFullPeer(dialogId); + } return stories != null && !stories.stories.isEmpty(); } + public TLRPC.PeerStories getStoriesFromFullPeer(long dialogId) { + if (dialogId > 0) { + TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); + return userFull == null ? null : userFull.stories; + } else { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + return chatFull == null ? null : chatFull.stories; + } + } + public boolean hasStories() { return (dialogListStories != null && dialogListStories.size() > 0) || hasSelfStories(); } @@ -264,8 +290,8 @@ public void loadHiddenStories() { } public void toggleHidden(long dialogId, boolean hide, boolean request, boolean notify) { - ArrayList removeFrom; - ArrayList insertTo; + ArrayList removeFrom; + ArrayList insertTo; boolean remove = true; if (hide) { // remove = true; @@ -276,9 +302,9 @@ public void toggleHidden(long dialogId, boolean hide, boolean request, boolean n insertTo = dialogListStories; } - TLRPC.TL_userStories removed = null; + TLRPC.PeerStories removed = null; for (int i = 0; i < removeFrom.size(); i++) { - if (removeFrom.get(i).user_id == dialogId) { + if (DialogObject.getPeerDialogId(removeFrom.get(i).peer) == dialogId) { if (remove) { removed = removeFrom.remove(i); } else { @@ -290,7 +316,7 @@ public void toggleHidden(long dialogId, boolean hide, boolean request, boolean n if (removed != null) { boolean found = false; for (int i = 0; i < insertTo.size(); i++) { - if (insertTo.get(i).user_id == dialogId) { + if (DialogObject.getPeerDialogId(insertTo.get(i).peer) == dialogId) { found = true; break; } @@ -306,12 +332,19 @@ public void toggleHidden(long dialogId, boolean hide, boolean request, boolean n } MessagesController.getInstance(currentAccount).checkArchiveFolder(); if (request) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - user.stories_hidden = hide; - MessagesStorage.getInstance(currentAccount).putUsersAndChats(Collections.singletonList(user), null, false, true); - MessagesController.getInstance(currentAccount).putUser(user, false); - TLRPC.TL_contacts_toggleStoriesHidden req = new TLRPC.TL_contacts_toggleStoriesHidden(); - req.id = MessagesController.getInstance(currentAccount).getInputUser(dialogId); + if (dialogId >= 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + user.stories_hidden = hide; + MessagesStorage.getInstance(currentAccount).putUsersAndChats(Collections.singletonList(user), null, false, true); + MessagesController.getInstance(currentAccount).putUser(user, false); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + chat.stories_hidden = hide; + MessagesStorage.getInstance(currentAccount).putUsersAndChats(null, Collections.singletonList(chat), false, true); + MessagesController.getInstance(currentAccount).putChat(chat, false); + } + TLRPC.TL_stories_togglePeerStoriesHidden req = new TLRPC.TL_stories_togglePeerStoriesHidden(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); req.hidden = hide; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { }); @@ -397,52 +430,68 @@ private void processAllStoriesResponse(TLRPC.TL_stories_allStories storiesRespon } if (BuildVars.LOGS_ENABLED) { StringBuilder builder = new StringBuilder(); - for (int i = 0; i < storiesResponse.user_stories.size(); i++) { + for (int i = 0; i < storiesResponse.peer_stories.size(); i++) { if (builder.length() != 0) { builder.append(", "); } - builder.append(storiesResponse.user_stories.get(i).user_id); + long dialogId = DialogObject.getPeerDialogId(storiesResponse.peer_stories.get(i).peer); + builder.append(dialogId); } FileLog.d("StoriesController cache=" + fromCache + " hidden=" + hidden + " processAllStoriesResponse {" + builder + "}"); } MessagesController.getInstance(currentAccount).putUsers(storiesResponse.users, fromCache); + MessagesController.getInstance(currentAccount).putChats(storiesResponse.chats, fromCache); - for (int i = 0; i < storiesResponse.user_stories.size(); i++) { - TLRPC.TL_userStories userStories = storiesResponse.user_stories.get(i); + for (int i = 0; i < storiesResponse.peer_stories.size(); i++) { + TLRPC.PeerStories userStories = storiesResponse.peer_stories.get(i); + long dialogId = DialogObject.getPeerDialogId(userStories.peer); for (int j = 0; j < userStories.stories.size(); j++) { if (userStories.stories.get(j) instanceof TLRPC.TL_storyItemDeleted) { - NotificationsController.getInstance(currentAccount).processDeleteStory(userStories.user_id, userStories.stories.get(j).id); + NotificationsController.getInstance(currentAccount).processDeleteStory(dialogId, userStories.stories.get(j).id); userStories.stories.remove(j); j--; } } if (!userStories.stories.isEmpty()) { - allStoriesMap.put(userStories.user_id, userStories); + allStoriesMap.put(dialogId, userStories); for (int k = 0; k < 2; k++) { - ArrayList storiesList = k == 0 ? hiddenListStories : dialogListStories; + ArrayList storiesList = k == 0 ? hiddenListStories : dialogListStories; for (int j = 0; j < storiesList.size(); j++) { - if (storiesList.get(j).user_id == userStories.user_id) { + if (DialogObject.getPeerDialogId(storiesList.get(j).peer) == dialogId) { storiesList.remove(j); break; } } } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(userStories.user_id); - if (user == null) { - continue; - } - if (user.stories_hidden) { - addUserToHiddenList(userStories); + if (dialogId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (user == null) { + continue; + } + if (user.stories_hidden) { + addUserToHiddenList(userStories); + } else { + dialogListStories.add(userStories); + preloadUserStories(userStories); + } } else { - dialogListStories.add(userStories); - preloadUserStories(userStories); + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (chat == null) { + continue; + } + if (chat.stories_hidden) { + addUserToHiddenList(userStories); + } else { + dialogListStories.add(userStories); + preloadUserStories(userStories); + } } } else { - allStoriesMap.remove(userStories.user_id); + allStoriesMap.remove(dialogId); } } if (!fromCache) { - storiesStorage.saveAllStories(storiesResponse.user_stories, isNext, hidden, () -> { + storiesStorage.saveAllStories(storiesResponse.peer_stories, isNext, hidden, () -> { // if (!hidden) { // FileLog.d("StoriesController all stories loaded"); // allStoriesLoaded = true; @@ -457,13 +506,14 @@ private void processAllStoriesResponse(TLRPC.TL_stories_allStories storiesRespon sortUserStories(); } - private void addUserToHiddenList(TLRPC.TL_userStories userStories) { + private void addUserToHiddenList(TLRPC.PeerStories userStories) { boolean found = false; - if (userStories.user_id == UserConfig.getInstance(currentAccount).getClientUserId()) { + long dialogId = DialogObject.getPeerDialogId(userStories.peer); + if (dialogId == UserConfig.getInstance(currentAccount).getClientUserId()) { return; } for (int i = 0; i < hiddenListStories.size(); i++) { - if (hiddenListStories.get(i).user_id == userStories.user_id) { + if (DialogObject.getPeerDialogId(hiddenListStories.get(i).peer) == dialogId) { found = true; } } @@ -478,7 +528,7 @@ private void sortUserStories() { sortStoriesRunnable.run(); } - public void preloadUserStories(TLRPC.TL_userStories userStories) { + public void preloadUserStories(TLRPC.PeerStories userStories) { int preloadPosition = 0; for (int i = 0; i < userStories.stories.size(); i++) { if (userStories.stories.get(i).id > userStories.max_read_id) { @@ -489,12 +539,13 @@ public void preloadUserStories(TLRPC.TL_userStories userStories) { if (userStories.stories.isEmpty()) { return; } - preloadStory(userStories.user_id, userStories.stories.get(preloadPosition)); + long dialogId = DialogObject.getPeerDialogId(userStories.peer); + preloadStory(dialogId, userStories.stories.get(preloadPosition)); if (preloadPosition > 0) { - preloadStory(userStories.user_id, userStories.stories.get(preloadPosition - 1)); + preloadStory(dialogId, userStories.stories.get(preloadPosition - 1)); } if (preloadPosition < userStories.stories.size() - 1) { - preloadStory(userStories.user_id, userStories.stories.get(preloadPosition + 1)); + preloadStory(dialogId, userStories.stories.get(preloadPosition + 1)); } } @@ -524,85 +575,137 @@ private void preloadStory(long dialogId, TLRPC.StoryItem storyItem) { public void uploadStory(StoryEntry entry, boolean count) { UploadingStory uploadingStory = new UploadingStory(entry); if (count) { + long dialogId = uploadingStory.dialogId; if (entry.isEdit) { - editingStories.put(entry.editStoryId, uploadingStory); + HashMap editigStoriesMap = editingStories.get(dialogId); + if (editigStoriesMap == null) { + editigStoriesMap = new HashMap<>(); + editingStories.put(dialogId, editigStoriesMap); + } + editigStoriesMap.put(entry.editStoryId, uploadingStory); } else { - uploadingStories.add(uploadingStory); + addUploadingStoryToList(dialogId, uploadingStory, uploadingStoriesByDialogId); + } + addUploadingStoryToList(dialogId, uploadingStory, uploadingAndEditingStories); + if (dialogId != UserConfig.getInstance(currentAccount).clientUserId) { + boolean found = false; + for (int i = 0; i < dialogListStories.size(); i++) { + if (DialogObject.getPeerDialogId(dialogListStories.get(i).peer) == dialogId) { + found = true; + TLRPC.PeerStories peerStories = dialogListStories.remove(i); + dialogListStories.add(0, peerStories); + break; + } + } + if (!found) { + for (int i = 0; i < hiddenListStories.size(); i++) { + if (DialogObject.getPeerDialogId(hiddenListStories.get(i).peer) == dialogId) { + found = true; + TLRPC.PeerStories peerStories = hiddenListStories.remove(i); + hiddenListStories.add(0, peerStories); + break; + } + } + } + if (!found) { + TLRPC.PeerStories peerStories = new TLRPC.TL_peerStories(); + peerStories.peer = MessagesController.getInstance(currentAccount).getPeer(dialogId); + allStoriesMap.put(dialogId, peerStories); + dialogListStories.add(0, peerStories); + loadAllStoriesForDialog(dialogId); + } } - uploadingAndEditingStories.add(uploadingStory); } uploadingStory.start(); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); } + private void addUploadingStoryToList(long dialogId, UploadingStory uploadingStory, LongSparseArray> sparseArray) { + ArrayList arrayList = sparseArray.get(dialogId); + if (arrayList == null) { + arrayList = new ArrayList<>(); + sparseArray.put(dialogId, arrayList); + } + arrayList.add(uploadingStory); + } + public void putUploadingDrafts(ArrayList entries) { for (StoryEntry entry : entries) { - uploadingStories.add(new UploadingStory(entry)); + UploadingStory uploadingStory = new UploadingStory(entry); + long dialogId = uploadingStory.dialogId; + addUploadingStoryToList(dialogId, uploadingStory, uploadingStoriesByDialogId); } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); } - public ArrayList getDialogListStories() { + public ArrayList getDialogListStories() { return dialogListStories; } - public TLRPC.TL_userStories getStories(long peerId) { + public TLRPC.PeerStories getStories(long peerId) { return allStoriesMap.get(peerId); } - public ArrayList getUploadingStories() { - return uploadingStories; + public ArrayList getUploadingStories(long dialogId) { + return uploadingStoriesByDialogId.get(dialogId); } - public boolean isLastUploadingFailed() { - if (uploadingStories.isEmpty()) { - return false; + public boolean isLastUploadingFailed(long dialogId) { + ArrayList uploadingStories = uploadingStoriesByDialogId.get(dialogId); + if (uploadingStories != null && !uploadingStories.isEmpty()) { + return uploadingStories.get(uploadingStories.size() - 1).failed; } - return uploadingStories.get(uploadingStories.size() - 1).failed; + return false; } - public ArrayList getUploadingAndEditingStories() { - return uploadingAndEditingStories; + public ArrayList getUploadingAndEditingStories(long dialogId) { + return uploadingAndEditingStories.get(dialogId); } public int getMyStoriesCount() { int count = uploadingAndEditingStories.size(); - TLRPC.TL_userStories userStories = getStories(getSelfUserId()); + TLRPC.PeerStories userStories = getStories(getSelfUserId()); if (userStories != null && userStories.stories != null) { count += userStories.stories.size(); } return count; } - public UploadingStory findEditingStory(TLRPC.StoryItem storyItem) { - if (storyItem == null || storyItem.dialogId != getSelfUserId()) { + public UploadingStory findEditingStory(long dialogId, TLRPC.StoryItem storyItem) { + if (storyItem == null) { return null; } - return editingStories.get(storyItem.id); + HashMap editingStoriesMap = editingStories.get(dialogId); + if (editingStoriesMap == null || editingStoriesMap.isEmpty()) { + return null; + } + return editingStoriesMap.get(storyItem.id); } - public UploadingStory getEditingStory() { - if (editingStories.isEmpty()) { + public UploadingStory getEditingStory(long dialogId) { + HashMap editingStoriesMap = editingStories.get(dialogId); + if (editingStoriesMap == null || editingStoriesMap.isEmpty()) { return null; } - Collection values = editingStories.values(); + Collection values = editingStoriesMap.values(); if (values.isEmpty()) { return null; } return values.iterator().next(); } - private void applyNewStories(TLRPC.TL_userStories stories) { - allStoriesMap.put(stories.user_id, stories); - if (stories.user_id != UserConfig.getInstance(UserConfig.selectedAccount).clientUserId) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(stories.user_id); + private void applyNewStories(TLRPC.PeerStories stories) { + long dialogId = DialogObject.getPeerDialogId(stories.peer); + allStoriesMap.put(dialogId, stories); + if (dialogId != UserConfig.getInstance(UserConfig.selectedAccount).clientUserId) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); applyToList(stories); if (user != null && !user.stories_hidden) { preloadUserStories(stories); } } - FileLog.d("StoriesController applyNewStories " + stories.user_id); - updateStoriesInLists(stories.user_id, stories.stories); + FileLog.d("StoriesController applyNewStories " + dialogId); + updateStoriesInLists(dialogId, stories.stories); } public static TLRPC.StoryItem applyStoryUpdate(TLRPC.StoryItem oldStoryItem, TLRPC.StoryItem newStoryItem) { @@ -638,18 +741,28 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { if (updateStory.story == null) { return; } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(updateStory.user_id); - if (user != null && (isContactOrService(user) || user.self)) { + long dialogId = DialogObject.getPeerDialogId(updateStory.peer); + if (dialogId == 0) { + FileLog.d("StoriesController can't update story dialogId == 0"); + return; + } + TLRPC.User user = null; + if (dialogId > 0) { + user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (user != null && (isContactOrService(user) || user.self)) { + storiesStorage.processUpdate(updateStory); + } + } else { storiesStorage.processUpdate(updateStory); } + TLRPC.User finalUser = user; AndroidUtilities.runOnUIThread(() -> { - TLRPC.TL_userStories currentUserStory = allStoriesMap.get(updateStory.user_id); - FileLog.d("StoriesController update stories for user " + updateStory.user_id); - updateStoriesInLists(updateStory.user_id, Collections.singletonList(updateStory.story)); + TLRPC.PeerStories currentUserStory = allStoriesMap.get(dialogId); + FileLog.d("StoriesController update stories for dialog " + dialogId); + updateStoriesInLists(dialogId, Collections.singletonList(updateStory.story)); ArrayList newStoryItems = new ArrayList<>(); int oldStoriesCount = totalStoriesCount; - long dialogId = updateStory.user_id; boolean notify = false; if (currentUserStory != null) { boolean changed = false; @@ -690,7 +803,7 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { FileLog.d("StoriesController can't add new story isExpired"); return; } - if (user == null || (!user.self && !isContactOrService(user))) { + if (dialogId > 0 && (finalUser == null || (!finalUser.self && !isContactOrService(finalUser)))) { FileLog.d("StoriesController can't add new story user is not contact"); return; } @@ -703,10 +816,10 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { applyToList(currentUserStory); } if (changed) { - if (currentUserStory.stories.isEmpty()) { + if (currentUserStory.stories.isEmpty() && !hasUploadingStories(dialogId)) { dialogListStories.remove(currentUserStory); hiddenListStories.remove(currentUserStory); - allStoriesMap.remove(currentUserStory.user_id); + allStoriesMap.remove(DialogObject.getPeerDialogId(currentUserStory.peer)); totalStoriesCount--; } else { Collections.sort(currentUserStory.stories, storiesComparator); @@ -715,25 +828,25 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { } } else { if (updateStory.story instanceof TLRPC.TL_storyItemDeleted) { - FileLog.d("StoriesController can't add user " + updateStory.user_id + " with new story DELETED"); + FileLog.d("StoriesController can't add user " + dialogId + " with new story DELETED"); return; } if (StoriesUtilities.isExpired(currentAccount, updateStory.story)) { - FileLog.d("StoriesController can't add user " + updateStory.user_id + " with new story isExpired"); + FileLog.d("StoriesController can't add user " + dialogId + " with new story isExpired"); return; } - if (user == null || (!user.self && !isContactOrService(user))) { + if (dialogId > 0 && (finalUser == null || (!finalUser.self && !isContactOrService(finalUser)))) { FileLog.d("StoriesController can't add user cause is not contact"); return; } - currentUserStory = new TLRPC.TL_userStories(); - currentUserStory.user_id = updateStory.user_id; + currentUserStory = new TLRPC.TL_peerStories(); + currentUserStory.peer = updateStory.peer; currentUserStory.stories.add(updateStory.story); FileLog.d("StoriesController add new user with story id=" + updateStory.story.id); applyNewStories(currentUserStory); notify = true; totalStoriesCount++; - loadAllStoriesForDialog(updateStory.user_id); + loadAllStoriesForDialog(dialogId); } if (oldStoriesCount != totalStoriesCount) { mainSettings.edit().putInt("total_stores", totalStoriesCount).apply(); @@ -751,38 +864,50 @@ private boolean isContactOrService(TLRPC.User user) { return user != null && (user.contact || user.id == MessagesController.getInstance(currentAccount).storiesChangelogUserId); } - private void applyToList(TLRPC.TL_userStories currentUserStory) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(currentUserStory.user_id); - if (user == null) { - FileLog.d("StoriesController can't apply story user == null"); - return; + private void applyToList(TLRPC.PeerStories currentUserStory) { + long dialogId = DialogObject.getPeerDialogId(currentUserStory.peer); + TLRPC.User user = null; + TLRPC.Chat chat = null; + if (dialogId > 0) { + user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (user == null) { + FileLog.d("StoriesController can't apply story user == null"); + return; + } + } else { + chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (chat == null) { + FileLog.d("StoriesController can't apply story chat == null"); + return; + } } boolean found = false; for (int i = 0; i < dialogListStories.size(); i++) { - if (dialogListStories.get(i).user_id == currentUserStory.user_id) { + if (DialogObject.getPeerDialogId(dialogListStories.get(i).peer) == dialogId) { dialogListStories.remove(i); found = true; break; } } for (int i = 0; i < hiddenListStories.size(); i++) { - if (hiddenListStories.get(i).user_id == currentUserStory.user_id) { + if (DialogObject.getPeerDialogId(hiddenListStories.get(i).peer) == dialogId) { hiddenListStories.remove(i); found = true; break; } } + boolean hidden = (user != null && user.stories_hidden) || (chat != null && chat.stories_hidden); if (BuildVars.LOGS_ENABLED) { - FileLog.d("StoriesController move user stories to first " + "hidden=" + user.stories_hidden + " did=" + currentUserStory.user_id); + FileLog.d("StoriesController move user stories to first " + "hidden=" + hidden + " did=" + dialogId); } - if (user.stories_hidden) { + if (hidden) { hiddenListStories.add(0, currentUserStory); } else { dialogListStories.add(0, currentUserStory); } if (!found) { - loadAllStoriesForDialog(currentUserStory.user_id); + loadAllStoriesForDialog(dialogId); } MessagesController.getInstance(currentAccount).checkArchiveFolder(); } @@ -795,21 +920,22 @@ private void loadAllStoriesForDialog(long user_id) { } allStoriesLoading.add(user_id); FileLog.d("StoriesController loadAllStoriesForDialog " + user_id); - TLRPC.TL_stories_getUserStories userStories = new TLRPC.TL_stories_getUserStories(); - userStories.user_id = MessagesController.getInstance(currentAccount).getInputUser(user_id); + TLRPC.TL_stories_getPeerStories userStories = new TLRPC.TL_stories_getPeerStories(); + userStories.peer = MessagesController.getInstance(currentAccount).getInputPeer(user_id); ConnectionsManager.getInstance(currentAccount).sendRequest(userStories, (response, error) -> AndroidUtilities.runOnUIThread(() -> { allStoriesLoading.remove(user_id); if (response == null) { return; } - TLRPC.TL_stories_userStories stories_userStories = (TLRPC.TL_stories_userStories) response; + TLRPC.TL_stories_peerStories stories_userStories = (TLRPC.TL_stories_peerStories) response; MessagesController.getInstance(currentAccount).putUsers(stories_userStories.users, false); TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(user_id); - TLRPC.TL_userStories stories = stories_userStories.stories; - allStoriesMap.put(stories.user_id, stories); + TLRPC.PeerStories stories = stories_userStories.stories; + long dialogId = DialogObject.getPeerDialogId(stories.peer); + allStoriesMap.put(dialogId, stories); if (user != null && (isContactOrService(user) || user.self)) { applyToList(stories); - storiesStorage.putUserStories(stories); + storiesStorage.putPeerStories(stories); } FileLog.d("StoriesController processAllStoriesResponse dialogId=" + user_id + " overwrite stories " + stories_userStories.stories.stories.size()); @@ -818,11 +944,12 @@ private void loadAllStoriesForDialog(long user_id) { } public boolean hasSelfStories() { - TLRPC.TL_userStories storyItem = allStoriesMap.get(UserConfig.getInstance(currentAccount).clientUserId); + long clientUserId = UserConfig.getInstance(currentAccount).clientUserId; + TLRPC.PeerStories storyItem = allStoriesMap.get(clientUserId); if (storyItem != null && !storyItem.stories.isEmpty()) { return true; } - if (!uploadingStories.isEmpty()) { + if (!Utilities.isNullOrEmpty(uploadingStoriesByDialogId.get(clientUserId))) { return true; } return false; @@ -830,43 +957,70 @@ public boolean hasSelfStories() { public int getSelfStoriesCount() { int count = 0; - TLRPC.TL_userStories storyItem = allStoriesMap.get(UserConfig.getInstance(currentAccount).clientUserId); + TLRPC.PeerStories storyItem = allStoriesMap.get(UserConfig.getInstance(currentAccount).clientUserId); if (storyItem != null) { count += storyItem.stories.size(); } - count += uploadingStories.size(); + count += uploadingStoriesByDialogId.size(); return count; } - public void deleteStory(TLRPC.StoryItem storyItem) { + public void deleteStory(long dialogId, TLRPC.StoryItem storyItem) { if (storyItem == null || storyItem instanceof TLRPC.TL_storyItemDeleted) { return; } - TLRPC.TL_userStories stories = allStoriesMap.get(getSelfUserId()); - if (stories != null) { - for (int i = 0; i < stories.stories.size(); i++) { - if (stories.stories.get(i).id == storyItem.id) { - stories.stories.remove(i); - if (stories.stories.size() == 0) { - allStoriesMap.remove(getSelfUserId()); - dialogListStories.remove(stories); - hiddenListStories.remove(stories); + for (int k = 0; k < 2; k++) { + TLRPC.PeerStories stories = null; + TLRPC.UserFull userFull = null; + TLRPC.ChatFull chatFull = null; + if (k == 0) { + stories = allStoriesMap.get(dialogId); + } else { + if (dialogId >= 0) { + userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); + if (userFull != null) { + stories = userFull.stories; + } + } else { + chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + if (chatFull != null) { + stories = chatFull.stories; } - break; } } + + if (stories != null) { + for (int i = 0; i < stories.stories.size(); i++) { + if (stories.stories.get(i).id == storyItem.id) { + stories.stories.remove(i); + if (stories.stories.size() == 0 && !hasUploadingStories(dialogId)) { + allStoriesMap.remove(dialogId); + dialogListStories.remove(stories); + hiddenListStories.remove(stories); + } + break; + } + } + } + if (chatFull != null) { + MessagesStorage.getInstance(currentAccount).updateChatInfo(chatFull, false); + } + if (userFull != null) { + MessagesStorage.getInstance(currentAccount).updateUserInfo(userFull, false); + } } TLRPC.TL_stories_deleteStories req = new TLRPC.TL_stories_deleteStories(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); req.id.add(storyItem.id); ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (error == null) { AndroidUtilities.runOnUIThread(this::invalidateStoryLimit); } }); - storiesStorage.deleteStory(getSelfUserId(), storyItem.id); + storiesStorage.deleteStory(dialogId, storyItem.id); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); MessagesController.getInstance(currentAccount).checkArchiveFolder(); - updateDeletedStoriesInLists(getSelfUserId(), Arrays.asList(storyItem)); + updateDeletedStoriesInLists(dialogId, Arrays.asList(storyItem)); } public void deleteStories(ArrayList storyItems) { @@ -874,7 +1028,7 @@ public void deleteStories(ArrayList storyItems) { return; } TLRPC.TL_stories_deleteStories req = new TLRPC.TL_stories_deleteStories(); - TLRPC.TL_userStories stories = allStoriesMap.get(getSelfUserId()); + TLRPC.PeerStories stories = allStoriesMap.get(getSelfUserId()); for (int i = 0; i < storyItems.size(); ++i) { TLRPC.StoryItem storyItem = storyItems.get(i); if (storyItem instanceof TLRPC.TL_storyItemDeleted) { @@ -901,8 +1055,9 @@ public void deleteStories(ArrayList storyItems) { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); } - public void updateStoriesPinned(ArrayList storyItems, boolean pinned, Utilities.Callback whenDone) { + public void updateStoriesPinned(long dialogId, ArrayList storyItems, boolean pinned, Utilities.Callback whenDone) { TLRPC.TL_stories_togglePinned req = new TLRPC.TL_stories_togglePinned(); + TLRPC.PeerStories peerStories = getStories(dialogId); for (int i = 0; i < storyItems.size(); ++i) { TLRPC.StoryItem storyItem = storyItems.get(i); if (storyItem instanceof TLRPC.TL_storyItemDeleted) { @@ -911,10 +1066,20 @@ public void updateStoriesPinned(ArrayList storyItems, boolean p storyItem.pinned = pinned; // todo: do update stories in one go in database req.id.add(storyItem.id); + if (peerStories != null) { + for (int j = 0; j < peerStories.stories.size(); j++) { + if (peerStories.stories.get(j).id == storyItem.id) { + peerStories.stories.get(j).pinned = pinned; + storiesStorage.updateStoryItem(dialogId, storyItem); + } + } + } } FileLog.d("StoriesController updateStoriesPinned"); - updateStoriesInLists(getSelfUserId(), storyItems); + updateStoriesInLists(dialogId, storyItems); + req.pinned = pinned; + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (whenDone != null) { whenDone.run(error == null); @@ -933,22 +1098,19 @@ public void updateStoryItem(long dialogId, TLRPC.StoryItem storyItem) { } public boolean markStoryAsRead(long dialogId, TLRPC.StoryItem storyItem) { - TLRPC.TL_userStories userStories = getStories(dialogId); + TLRPC.PeerStories userStories = getStories(dialogId); if (userStories == null) { - TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); - if (userFull != null) { - userStories = userFull.stories; - } + userStories = getStoriesFromFullPeer(dialogId); } return markStoryAsRead(userStories, storyItem, false); } - public boolean markStoryAsRead(TLRPC.TL_userStories userStories, TLRPC.StoryItem storyItem, boolean profile) { + public boolean markStoryAsRead(TLRPC.PeerStories userStories, TLRPC.StoryItem storyItem, boolean profile) { if (storyItem == null || userStories == null) { return false; } - final long dialogId = userStories.user_id; - if (dialogId == UserConfig.getInstance(currentAccount).getClientUserId()) { + final long dialogId = DialogObject.getPeerDialogId(userStories.peer); + if (storyItem.justUploaded) { storyItem.justUploaded = false; } int currentReadId = dialogIdToMaxReadId.get(dialogId); @@ -961,7 +1123,7 @@ public boolean markStoryAsRead(TLRPC.TL_userStories userStories, TLRPC.StoryItem storiesStorage.updateMaxReadId(dialogId, newReadId); } TLRPC.TL_stories_readStories req = new TLRPC.TL_stories_readStories(); - req.user_id = MessagesController.getInstance(currentAccount).getInputUser(dialogId); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); req.max_id = storyItem.id; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> {}); return true; @@ -975,25 +1137,25 @@ public void markStoriesAsReadFromServer(long dialogId, int maxStoryId) { int maxStoryReadId = Math.max(dialogIdToMaxReadId.get(dialogId, 0), maxStoryId); dialogIdToMaxReadId.put(dialogId, maxStoryReadId); storiesStorage.updateMaxReadId(dialogId, maxStoryReadId); - TLRPC.TL_userStories userStories = getStories(dialogId); + TLRPC.PeerStories userStories = getStories(dialogId); if (userStories == null) { return; } if (maxStoryId > userStories.max_read_id) { userStories.max_read_id = maxStoryId; - Collections.sort(dialogListStories, userStoriesComparator); + Collections.sort(dialogListStories, peerStoriesComparator); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); } }); } public boolean hasUnreadStories(long dialogId) { - TLRPC.TL_userStories userStories = allStoriesMap.get(dialogId); + TLRPC.PeerStories userStories = allStoriesMap.get(dialogId); if (userStories == null) { return false; } if (dialogId == UserConfig.getInstance(currentAccount).getClientUserId()) { - if (!uploadingStories.isEmpty()) { + if (!Utilities.isNullOrEmpty(uploadingStoriesByDialogId.get(dialogId))) { return true; } } @@ -1013,31 +1175,34 @@ public int getUnreadState(long dialogId) { } public int getUnreadState(long dialogId, int storyId) { - TLRPC.TL_userStories userStories = allStoriesMap.get(dialogId); - if (userStories == null) { - TLRPC.UserFull user = MessagesController.getInstance(currentAccount).getUserFull(dialogId); - if (user != null) { - userStories = user.stories; - } + if (dialogId == 0) { + return STATE_READ; } - if (userStories == null) { + TLRPC.PeerStories peerStories = allStoriesMap.get(dialogId); + if (peerStories == null) { + peerStories = getStoriesFromFullPeer(dialogId); + } + if (peerStories == null) { return STATE_READ; } if (dialogId == UserConfig.getInstance(currentAccount).getClientUserId()) { - if (!uploadingStories.isEmpty()) { + if (!Utilities.isNullOrEmpty(uploadingStoriesByDialogId.get(dialogId))) { return STATE_UNREAD; } } boolean hasUnread = false; - int maxReadId = Math.max(userStories.max_read_id, dialogIdToMaxReadId.get(dialogId, 0)); - for (int i = 0; i < userStories.stories.size(); i++) { - if ((storyId == 0 || userStories.stories.get(i).id == storyId) && userStories.stories.get(i).id > maxReadId) { + int maxReadId = Math.max(peerStories.max_read_id, dialogIdToMaxReadId.get(dialogId, 0)); + for (int i = 0; i < peerStories.stories.size(); i++) { + if ((storyId == 0 || peerStories.stories.get(i).id == storyId) && peerStories.stories.get(i).id > maxReadId) { hasUnread = true; - if (userStories.stories.get(i).close_friends) { + if (peerStories.stories.get(i).close_friends) { return STATE_UNREAD_CLOSE_FRIEND; } } } + if (isLastUploadingFailed(dialogId)) { + return STATE_READ; + } if (hasUnread) { return STATE_UNREAD; } @@ -1045,8 +1210,10 @@ public int getUnreadState(long dialogId, int storyId) { return STATE_READ; } - public boolean hasUploadingStories() { - return !uploadingStories.isEmpty() || !editingStories.isEmpty(); + public boolean hasUploadingStories(long dialogId) { + ArrayList uploadingStories = uploadingStoriesByDialogId.get(dialogId); + HashMap editingStoriesMap = editingStories.get(dialogId); + return (uploadingStories != null && !uploadingStories.isEmpty()) || (editingStoriesMap != null && !editingStoriesMap.isEmpty()); } public void cleanup() { @@ -1068,8 +1235,19 @@ public void cleanup() { loadStoriesRead(); } - public void pollViewsForSelfStories(boolean start) { - pollingViewsForSelfStoriesRequester.start(start); + public void pollViewsForSelfStories(long dialogId, boolean start) { + ViewsForPeerStoriesRequester requester = pollingViewsForSelfStoriesRequester.get(dialogId); + if (requester == null) { + requester = new ViewsForPeerStoriesRequester(this, dialogId, currentAccount); + pollingViewsForSelfStoriesRequester.put(dialogId, requester); + } + requester.start(start); + } + + public void stopAllPollers() { + for (int i = 0; i < pollingViewsForSelfStoriesRequester.size(); i++) { + pollingViewsForSelfStoriesRequester.valueAt(i).start(false); + } } HashSet loadingAllStories = new HashSet<>(); @@ -1078,11 +1256,11 @@ void loadSkippedStories(long dialogId) { loadSkippedStories(getStories(dialogId), false); } - void loadSkippedStories(TLRPC.TL_userStories userStories, boolean profile) { + void loadSkippedStories(TLRPC.PeerStories userStories, boolean profile) { if (userStories == null) { return; } - final long dialogId = userStories.user_id; + final long dialogId = DialogObject.getPeerDialogId(userStories.peer); final long key = dialogId * (profile ? -1 : 1); if (loadingAllStories.contains(key)) { return; @@ -1101,10 +1279,10 @@ void loadSkippedStories(TLRPC.TL_userStories userStories, boolean profile) { loadingAllStories.add(key); TLRPC.TL_stories_getStoriesByID stories = new TLRPC.TL_stories_getStoriesByID(); stories.id = storyIdsToLoad; - stories.user_id = MessagesController.getInstance(currentAccount).getInputUser(dialogId); + stories.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); ConnectionsManager.getInstance(currentAccount).sendRequest(stories, (response, error) -> AndroidUtilities.runOnUIThread(() -> { loadingAllStories.remove(key); - TLRPC.TL_userStories userStories2 = profile ? userStories : getStories(dialogId); + TLRPC.PeerStories userStories2 = profile ? userStories : getStories(dialogId); if (userStories2 == null) { return; } @@ -1141,7 +1319,7 @@ public void fillMessagesWithStories(LongSparseArray> me LongSparseArray resolvedStories = new LongSparseArray<>(); public void resolveStoryLink(long peerId, int storyId, Consumer consumer) { - TLRPC.TL_userStories userStoriesLocal = getStories(peerId); + TLRPC.PeerStories userStoriesLocal = getStories(peerId); if (userStoriesLocal != null) { for (int i = 0; i < userStoriesLocal.stories.size(); i++) { if (userStoriesLocal.stories.get(i).id == storyId && !(userStoriesLocal.stories.get(i) instanceof TLRPC.TL_storyItemSkipped)) { @@ -1158,7 +1336,7 @@ public void resolveStoryLink(long peerId, int storyId, Consumer } TLRPC.TL_stories_getStoriesByID stories = new TLRPC.TL_stories_getStoriesByID(); stories.id.add(storyId); - stories.user_id = MessagesController.getInstance(currentAccount).getInputUser(peerId); + stories.peer = MessagesController.getInstance(currentAccount).getInputPeer(peerId); ConnectionsManager.getInstance(currentAccount).sendRequest(stories, new RequestDelegate() { @Override public void run(TLObject res, TLRPC.TL_error error) { @@ -1177,12 +1355,12 @@ public void run(TLObject res, TLRPC.TL_error error) { }); } - public ArrayList getHiddenList() { + public ArrayList getHiddenList() { return hiddenListStories; } public int getUnreadStoriesCount(long dialogId) { - TLRPC.TL_userStories userStories = allStoriesMap.get(dialogId); + TLRPC.PeerStories userStories = allStoriesMap.get(dialogId); for (int i = 0; i < userStories.stories.size(); i++) { if (userStories.max_read_id < userStories.stories.get(i).id) { return userStories.stories.size() - i; @@ -1199,12 +1377,20 @@ public int getTotalStoriesCount(boolean hidden) { } } - public void putStories(long dialogId, TLRPC.TL_userStories stories) { + public void putStories(long dialogId, TLRPC.PeerStories stories) { allStoriesMap.put(dialogId, stories); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - if (isContactOrService(user) || user.self) { - storiesStorage.putUserStories(stories); - applyToList(stories); + if (dialogId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (isContactOrService(user) || user.self) { + storiesStorage.putPeerStories(stories); + applyToList(stories); + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (ChatObject.isInChat(chat)) { + storiesStorage.putPeerStories(stories); + applyToList(stories); + } } } @@ -1222,13 +1408,13 @@ public boolean isLoading(long dialogId) { public void removeContact(long dialogId) { for (int i = 0; i < dialogListStories.size(); i++) { - if (dialogListStories.get(i).user_id == dialogId) { + if (DialogObject.getPeerDialogId(dialogListStories.get(i).peer) == dialogId) { dialogListStories.remove(i); break; } } for (int i = 0; i < hiddenListStories.size(); i++) { - if (hiddenListStories.get(i).user_id == dialogId) { + if (DialogObject.getPeerDialogId(hiddenListStories.get(i).peer) == dialogId) { hiddenListStories.remove(i); break; } @@ -1251,18 +1437,19 @@ public void checkExpiredStories() { checkExpireStories(hiddenListStories); } - private void checkExpireStories(ArrayList dialogListStories) { + private void checkExpireStories(ArrayList dialogListStories) { boolean notify = false; for (int k = 0; k < dialogListStories.size(); k++) { - TLRPC.TL_userStories stories = dialogListStories.get(k); + TLRPC.PeerStories stories = dialogListStories.get(k); + long dialogId = DialogObject.getPeerDialogId(stories.peer); for (int i = 0; i < stories.stories.size(); i++) { if (StoriesUtilities.isExpired(currentAccount, stories.stories.get(i))) { stories.stories.remove(i); i--; } } - if (stories.stories.isEmpty()) { - allStoriesMap.remove(stories.user_id); + if (stories.stories.isEmpty() && !hasUploadingStories(dialogId)) { + allStoriesMap.remove(dialogId); dialogListStories.remove(stories); notify = true; } @@ -1273,7 +1460,7 @@ private void checkExpireStories(ArrayList dialogListStorie } public void checkExpiredStories(long dialogId) { - TLRPC.TL_userStories userStories = getStories(dialogId); + TLRPC.PeerStories userStories = getStories(dialogId); if (userStories == null) { return; } @@ -1283,7 +1470,7 @@ public void checkExpiredStories(long dialogId) { i--; } } - if (userStories.stories.isEmpty()) { + if (userStories.stories.isEmpty() && !hasUnreadStories(dialogId)) { dialogListStories.remove(userStories); hiddenListStories.remove(userStories); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); @@ -1310,7 +1497,7 @@ public void setStoryReaction(long dialogId, TLRPC.StoryItem storyItem, Reactions } TLRPC.TL_stories_sendReaction req = new TLRPC.TL_stories_sendReaction(); req.story_id = storyItem.id; - req.user_id = MessagesController.getInstance(currentAccount).getInputUser(dialogId); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); if (visibleReaction == null) { req.reaction = new TLRPC.TL_reactionEmpty(); // req.flags |= 1; @@ -1350,7 +1537,7 @@ public void updateStoryReaction(long dialogId, int storyId, TLRPC.Reaction react } private TLRPC.StoryItem findStory(long dialogId, int storyId) { - TLRPC.TL_userStories stories = allStoriesMap.get(dialogId); + TLRPC.PeerStories stories = allStoriesMap.get(dialogId); if (stories != null) { for (int i = 0; i < stories.stories.size(); i++) { if (stories.stories.get(i).id == storyId) { @@ -1391,6 +1578,7 @@ public class UploadingStory implements NotificationCenter.NotificationCenterDele public boolean hadFailed; public boolean failed; + long dialogId; public UploadingStory(StoryEntry entry) { this.entry = entry; @@ -1400,6 +1588,16 @@ public UploadingStory(StoryEntry entry) { this.firstFramePath = entry.uploadThumbFile.getAbsolutePath(); } failed = hadFailed = entry.isError; + + if (entry.isEdit) { + dialogId = entry.editStoryPeerId; + } else { + if (entry.peer == null || entry.peer instanceof TLRPC.TL_inputPeerSelf) { + dialogId = UserConfig.getInstance(currentAccount).clientUserId; + } else { + dialogId = DialogObject.getPeerDialogId(entry.peer); + } + } } private void startForeground() { @@ -1488,11 +1686,20 @@ public void cleanup() { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.filePreparingStarted); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileNewChunkAvailable); if (!failed) { - uploadingStories.remove(UploadingStory.this); + ArrayList list = uploadingStoriesByDialogId.get(dialogId); + if (list != null) { + list.remove(UploadingStory.this); + } + } + ArrayList list = uploadingAndEditingStories.get(dialogId); + if (list != null) { + list.remove(UploadingStory.this); } - uploadingAndEditingStories.remove(UploadingStory.this); if (edit) { - editingStories.remove(entry.editStoryId); + HashMap map = editingStories.get(dialogId); + if (map != null) { + map.remove(entry.editStoryId); + } } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); if (entry != null && !entry.isEditSaved && !entryDestroyed) { @@ -1596,7 +1803,7 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { inputMediaVideo.attributes.add(new TLRPC.TL_documentAttributeHasStickers()); } media = inputMediaVideo; - media.nosound_video = entry.muted || !entry.isVideo; + media.nosound_video = entry.audioPath == null && (entry.muted || !entry.isVideo); media.mime_type = "video/mp4"; } else { TLRPC.TL_inputMediaUploadedPhoto inputMediaPhoto = new TLRPC.TL_inputMediaUploadedPhoto(); @@ -1625,6 +1832,7 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { if (edit) { TLRPC.TL_stories_editStory editStory = new TLRPC.TL_stories_editStory(); editStory.id = entry.editStoryId; + editStory.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); if (media != null && entry.editedMedia) { editStory.flags |= 1; @@ -1672,6 +1880,7 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { } else { TLRPC.TL_stories_sendStory sendStory = new TLRPC.TL_stories_sendStory(); sendStory.random_id = random_id; + sendStory.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); sendStory.media = media; sendStory.privacy_rules.addAll(entry.privacyRules); sendStory.pinned = entry.pinned; @@ -1752,7 +1961,7 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { } } } - final long did = UserConfig.getInstance(currentAccount).clientUserId; + final long did = dialogId; if (canceled) { TLRPC.TL_stories_deleteStories stories_deleteStory = new TLRPC.TL_stories_deleteStories(); stories_deleteStory.id.add(storyId); @@ -1762,13 +1971,22 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { } else { if ((storyId == 0 || edit) && storyItem != null) { TLRPC.TL_updateStory tl_updateStory = new TLRPC.TL_updateStory(); - tl_updateStory.user_id = did; + tl_updateStory.peer = MessagesController.getInstance(currentAccount).getPeer(did); tl_updateStory.story = storyItem; AndroidUtilities.runOnUIThread(() -> { MessagesController.getInstance(currentAccount).getStoriesController().processUpdate(tl_updateStory); }); } final TLRPC.StoryItem storyItemFinal = storyItem; + if (storyItemFinal.media != null && storyItemFinal.attachPath != null) { + if (storyItemFinal.media.document != null) { + FileLoader.getInstance(currentAccount).setLocalPathTo(storyItemFinal.media.document, storyItemFinal.attachPath); + } else if (storyItemFinal.media.photo != null) { + TLRPC.Photo photo = storyItemFinal.media.photo; + TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, Integer.MAX_VALUE); + FileLoader.getInstance(currentAccount).setLocalPathTo(size, storyItemFinal.attachPath); + } + } AndroidUtilities.runOnUIThread(() -> { entryDestroyed = true; if (entry.isError) { @@ -1831,7 +2049,7 @@ private void putMessages() { public void cancel() { if (failed) { getDraftsController().delete(entry); - uploadingStories.remove(UploadingStory.this); + uploadingStoriesByDialogId.get(dialogId).remove(UploadingStory.this); } canceled = true; if (entry.wouldBeVideo()) { @@ -1852,21 +2070,18 @@ public boolean isCloseFriends() { private final HashMap[] storiesLists = new HashMap[2]; @Nullable - public StoriesList getStoriesList(long userId, int type) { - return getStoriesList(userId, type, true); + public StoriesList getStoriesList(long dialogId, int type) { + return getStoriesList(dialogId, type, true); } @Nullable - private StoriesList getStoriesList(long userId, int type, boolean createIfNotExist) { - if (type == StoriesList.TYPE_ARCHIVE && userId != getSelfUserId()) { - return null; - } + private StoriesList getStoriesList(long dialogId, int type, boolean createIfNotExist) { if (storiesLists[type] == null) { storiesLists[type] = new HashMap<>(); } - StoriesList list = storiesLists[type].get(userId); + StoriesList list = storiesLists[type].get(dialogId); if (list == null && createIfNotExist) { - storiesLists[type].put(userId, list = new StoriesList(currentAccount, userId, type, this::destroyStoryList)); + storiesLists[type].put(dialogId, list = new StoriesList(currentAccount, dialogId, type, this::destroyStoryList)); } return list; } @@ -1907,10 +2122,10 @@ private static String storyItemMessageIds(List storyItems) { } } - public void updateStoriesInLists(long userId, List storyItems) { - FileLog.d("updateStoriesInLists " + userId + " storyItems[" + storyItems.size() + "] {" + storyItemIds(storyItems) + "}"); - StoriesList pinned = getStoriesList(userId, StoriesList.TYPE_PINNED, false); - StoriesList archived = getStoriesList(userId, StoriesList.TYPE_ARCHIVE, false); + public void updateStoriesInLists(long dialogId, List storyItems) { + FileLog.d("updateStoriesInLists " + dialogId + " storyItems[" + storyItems.size() + "] {" + storyItemIds(storyItems) + "}"); + StoriesList pinned = getStoriesList(dialogId, StoriesList.TYPE_PINNED, false); + StoriesList archived = getStoriesList(dialogId, StoriesList.TYPE_ARCHIVE, false); if (pinned != null) { pinned.updateStories(storyItems); } @@ -1919,10 +2134,10 @@ public void updateStoriesInLists(long userId, List storyItems) } } - public void updateDeletedStoriesInLists(long userId, List storyItems) { - FileLog.d("updateDeletedStoriesInLists " + userId + " storyItems[" + storyItems.size() + "] {" + storyItemIds(storyItems) + "}"); - StoriesList pinned = getStoriesList(userId, StoriesList.TYPE_PINNED, false); - StoriesList archived = getStoriesList(userId, StoriesList.TYPE_ARCHIVE, false); + public void updateDeletedStoriesInLists(long dialogId, List storyItems) { + FileLog.d("updateDeletedStoriesInLists " + dialogId + " storyItems[" + storyItems.size() + "] {" + storyItemIds(storyItems) + "}"); + StoriesList pinned = getStoriesList(dialogId, StoriesList.TYPE_PINNED, false); + StoriesList archived = getStoriesList(dialogId, StoriesList.TYPE_ARCHIVE, false); if (pinned != null) { pinned.updateDeletedStories(storyItems); } @@ -2048,9 +2263,9 @@ private boolean filter(MessageObject msg, boolean photos, boolean videos) { private Utilities.CallbackReturn toLoad; - private StoriesList(int currentAccount, long userId, int type, Utilities.Callback destroy) { + private StoriesList(int currentAccount, long dialogId, int type, Utilities.Callback destroy) { this.currentAccount = currentAccount; - this.dialogId = userId; + this.dialogId = dialogId; this.type = type; this.destroyRunnable = () -> destroy.run(this); @@ -2303,7 +2518,7 @@ public boolean load(boolean force, final int count) { TLObject request; if (type == TYPE_PINNED) { TLRPC.TL_stories_getPinnedStories req = new TLRPC.TL_stories_getPinnedStories(); - req.user_id = MessagesController.getInstance(currentAccount).getInputUser(dialogId); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); if (!loadedObjects.isEmpty()) { req.offset_id = offset_id = loadedObjects.last(); } else { @@ -2313,6 +2528,7 @@ public boolean load(boolean force, final int count) { request = req; } else { TLRPC.TL_stories_getStoriesArchive req = new TLRPC.TL_stories_getStoriesArchive(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); if (!loadedObjects.isEmpty()) { req.offset_id = offset_id = loadedObjects.last(); } else { @@ -2321,7 +2537,7 @@ public boolean load(boolean force, final int count) { req.limit = count; request = req; } - FileLog.d("StoriesList " + type + "{"+dialogId+"} load"); + FileLog.d("StoriesList " + type + "{"+ dialogId +"} load"); loading = true; ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, err) -> { @@ -2333,7 +2549,7 @@ public boolean load(boolean force, final int count) { newMessageObjects.add(toMessageObject(storyItem)); } AndroidUtilities.runOnUIThread(() -> { - FileLog.d("StoriesList " + type + "{"+dialogId+"} loaded {" + storyItemMessageIds(newMessageObjects) + "}"); + FileLog.d("StoriesList " + type + "{"+ dialogId +"} loaded {" + storyItemMessageIds(newMessageObjects) + "}"); MessagesController.getInstance(currentAccount).putUsers(stories.users, false); loading = false; @@ -2402,7 +2618,7 @@ public boolean load(boolean force, final int count) { // } public void updateDeletedStories(List storyItems) { - FileLog.d("StoriesList " + type + "{"+dialogId+"} updateDeletedStories {" + storyItemIds(storyItems) + "}"); + FileLog.d("StoriesList " + type + "{"+ dialogId +"} updateDeletedStories {" + storyItemIds(storyItems) + "}"); if (storyItems == null) { return; } @@ -2430,7 +2646,7 @@ public void updateDeletedStories(List storyItems) { } public void updateStories(List storyItems) { - FileLog.d("StoriesList " + type + "{"+dialogId+"} updateStories {" + storyItemIds(storyItems) + "}"); + FileLog.d("StoriesList " + type + "{"+ dialogId +"} updateStories {" + storyItemIds(storyItems) + "}"); if (storyItems == null) { return; } @@ -2530,28 +2746,38 @@ public int getCount() { } } - private final Comparator userStoriesComparator = (o1, o2) -> { - boolean hasUnread1 = hasUnreadStories(o1.user_id); - boolean hasUnread2 = hasUnreadStories(o2.user_id); - if (hasUnread1 == hasUnread2) { - int service1 = UserObject.isService(o1.user_id) ? 1 : 0; - int service2 = UserObject.isService(o2.user_id) ? 1 : 0; - if (service1 == service2) { - int i1 = isPremium(o1.user_id) ? 1 : 0; - int i2 = isPremium(o2.user_id) ? 1 : 0; - if (i1 == i2) { - int date1 = o1.stories.isEmpty() ? 0 : o1.stories.get(o1.stories.size() - 1).date; - int date2 = o2.stories.isEmpty() ? 0 : o2.stories.get(o2.stories.size() - 1).date; - return date2 - date1; + private final Comparator peerStoriesComparator = (o1, o2) -> { + long dialogId1 = DialogObject.getPeerDialogId(o1.peer); + long dialogId2 = DialogObject.getPeerDialogId(o2.peer); + boolean hasUploading1 = hasUploadingStories(dialogId1); + boolean hasUploading2 = hasUploadingStories(dialogId2); + boolean hasUnread1 = hasUnreadStories(dialogId1); + boolean hasUnread2 = hasUnreadStories(dialogId2); + if (hasUploading1 == hasUploading2) { + if (hasUnread1 == hasUnread2) { + int service1 = UserObject.isService(dialogId1) ? 1 : 0; + int service2 = UserObject.isService(dialogId2) ? 1 : 0; + if (service1 == service2) { + int i1 = isPremium(dialogId1) ? 1 : 0; + int i2 = isPremium(dialogId2) ? 1 : 0; + if (i1 == i2) { + int date1 = o1.stories.isEmpty() ? 0 : o1.stories.get(o1.stories.size() - 1).date; + int date2 = o2.stories.isEmpty() ? 0 : o2.stories.get(o2.stories.size() - 1).date; + return date2 - date1; + } else { + return i2 - i1; + } } else { - return i2 - i1; + return service2 - service1; } } else { - return service2 - service1; + int i1 = hasUnread1 ? 1 : 0; + int i2 = hasUnread2 ? 1 : 0; + return i2 - i1; } } else { - int i1 = hasUnread1 ? 1 : 0; - int i2 = hasUnread2 ? 1 : 0; + int i1 = hasUploading1 ? 1 : 0; + int i2 = hasUploading2 ? 1 : 0; return i2 - i1; } }; @@ -2573,7 +2799,7 @@ public void scheduleSort() { } public boolean hasOnlySelfStories() { - return hasSelfStories() && (getDialogListStories().isEmpty() || (getDialogListStories().size() == 1 && getDialogListStories().get(0).user_id == UserConfig.getInstance(currentAccount).clientUserId)); + return hasSelfStories() && (getDialogListStories().isEmpty() || (getDialogListStories().size() == 1 && DialogObject.getPeerDialogId(getDialogListStories().get(0).peer) == UserConfig.getInstance(currentAccount).clientUserId)); } public void sortHiddenStories() { @@ -2782,7 +3008,9 @@ public StoryLimit checkStoryLimit() { return storyLimitCached; } - ConnectionsManager.getInstance(currentAccount).sendRequest(new TLRPC.TL_stories_canSendStory(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_stories_canSendStory tl_stories_canSendStory = new TLRPC.TL_stories_canSendStory(); + tl_stories_canSendStory.peer = MessagesController.getInstance(currentAccount).getInputPeer(UserConfig.getInstance(currentAccount).getClientUserId()); + ConnectionsManager.getInstance(currentAccount).sendRequest(tl_stories_canSendStory, (res, err) -> AndroidUtilities.runOnUIThread(() -> { storyLimitFetched = true; if (res instanceof TLRPC.TL_boolTrue) { storyLimitCached = null; @@ -2794,6 +3022,63 @@ public StoryLimit checkStoryLimit() { return null; } + public void canSendStoryFor(long dialogId, Consumer consumer, boolean showLimitsBottomSheet, Theme.ResourcesProvider resourcesProvider) { + TLRPC.TL_stories_canSendStory tl_stories_canSendStory = new TLRPC.TL_stories_canSendStory(); + tl_stories_canSendStory.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + ConnectionsManager.getInstance(currentAccount).sendRequest(tl_stories_canSendStory, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + if (err.text.contains("BOOSTS_REQUIRED")) { + if (showLimitsBottomSheet) { + MessagesController messagesController = MessagesController.getInstance(currentAccount); + messagesController.getBoostsController().getBoostsStats(dialogId, boostsStatus -> { + if (boostsStatus == null) { + consumer.accept(false); + return; + } + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(lastFragment, lastFragment.getContext(), LimitReachedBottomSheet.TYPE_BOOSTS_FOR_POSTING, currentAccount, resourcesProvider); + limitReachedBottomSheet.setBoostsStats(boostsStatus, false); + limitReachedBottomSheet.setDialogId(dialogId); + if (canPostStories(dialogId)) { + limitReachedBottomSheet.showStatisticButtonInLink(() -> { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + Bundle args = new Bundle(); + args.putLong("chat_id", -dialogId); + args.putBoolean("is_megagroup", chat.megagroup); + args.putBoolean("start_from_boosts", true); + args.putBoolean("only_boosts", true); + StatisticActivity fragment = new StatisticActivity(args); + BaseFragment lastFragment1 = LaunchActivity.getLastFragment(); + if (lastFragment1 != null) { + if (StoryRecorder.isVisible()) { + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + lastFragment1.showAsSheet(fragment, params); + } else { + lastFragment1.presentFragment(fragment); + } + } + }); + } + limitReachedBottomSheet.show(); + consumer.accept(false); + }); + } else { + consumer.accept(false); + } + } else { + BulletinFactory bulletinFactory = BulletinFactory.global(); + if (bulletinFactory != null) { + bulletinFactory.createErrorBulletin(err.text); + } + consumer.accept(false); + } + } else { + consumer.accept(true); + } + }), ConnectionsManager.RequestFlagDoNotWaitFloodWait); + } + public boolean checkStoryError(TLRPC.TL_error err) { boolean limitUpdate = false; if (err != null && err.text != null) { @@ -2876,4 +3161,108 @@ public boolean active(int currentAccount) { } } } + + public final ArrayList sendAs = new ArrayList<>(); + { sendAs.add(new TLRPC.TL_inputPeerSelf()); } + private boolean loadingSendAs = false; + private boolean loadedSendAs = false; + + public void loadSendAs() { + if (loadingSendAs || loadedSendAs) { + return; + } + loadingSendAs = true; + ConnectionsManager.getInstance(currentAccount).sendRequest(new TLRPC.TL_stories_getChatsToSend(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + sendAs.clear(); + sendAs.add(new TLRPC.TL_inputPeerSelf()); + if (res instanceof TLRPC.TL_messages_chats) { + ArrayList chats = ((TLRPC.TL_messages_chats) res).chats; + MessagesController.getInstance(currentAccount).putChats(chats, false); + for (TLRPC.Chat chat : chats) { + TLRPC.InputPeer peer = MessagesController.getInputPeer(chat); + sendAs.add(peer); + } + } + loadingSendAs = false; + loadedSendAs = true; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesSendAsUpdate); + })); + } + + private void invalidateSendAsList() { + // when channel gets deleted or something else happens... + loadedSendAs = false; + } + + public boolean canEditStories(long dialogId) { + if (dialogId < 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (chat == null) { + return false; + } + return chat.creator || chat.admin_rights != null && chat.admin_rights.edit_stories; + } + return false; + } + + public boolean canPostStories(long dialogId) { + if (dialogId < 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (chat == null) { + return false; + } + return chat.creator || chat.admin_rights != null && chat.admin_rights.post_stories; + } + return false; + } + + public boolean canEditStory(TLRPC.StoryItem storyItem) { + if (storyItem == null) { + return false; + } + if (storyItem.dialogId == getSelfUserId()) { + return false; + } + if (storyItem.dialogId < 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-storyItem.dialogId); + if (chat == null) { + return false; + } + if (chat.creator) { + return true; + } + if (storyItem.out && chat.admin_rights != null && (chat.admin_rights.post_stories || chat.admin_rights.edit_stories)) { + return true; + } + if (!storyItem.out && chat.admin_rights != null && chat.admin_rights.edit_stories) { + return true; + } + } + return false; + } + + public boolean canDeleteStory(TLRPC.StoryItem storyItem) { + if (storyItem == null) { + return false; + } + if (storyItem.dialogId == getSelfUserId()) { + return false; + } + if (storyItem.dialogId < 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-storyItem.dialogId); + if (chat == null) { + return false; + } + if (chat.creator) { + return true; + } + if (storyItem.out && chat.admin_rights != null && (chat.admin_rights.post_stories || chat.admin_rights.delete_stories)) { + return true; + } + if (!storyItem.out && chat.admin_rights != null && chat.admin_rights.delete_stories) { + return true; + } + } + return false; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java index e5ddb45c862..258a6b1efcb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java @@ -107,11 +107,12 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto holder.clipParent = storiesCell; holder.clipTop = holder.clipBottom = 0; holder.alpha = 1; - if (cell.isFail) { + if (cell.isFail && storiesCell.isExpanded()) { final Path path = new Path(); holder.drawClip = (canvas, bounds, alpha, opening) -> { + if (opening) return; path.rewind(); - final float t = opening ? 1f - (float) Math.pow(1f - alpha, 2) : (float) Math.pow(alpha, 2); + final float t = (float) Math.pow(alpha, 2); path.addCircle(bounds.right + dp(7) - dp(14) * t, bounds.bottom + dp(7) - dp(14) * t, dp(11), Path.Direction.CW); canvas.clipPath(path, Region.Op.DIFFERENCE); }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java index 110a54783f4..5158726411c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java @@ -1,8 +1,6 @@ package org.telegram.ui.Stories; -import android.os.Build; import android.text.TextUtils; -import android.util.Log; import androidx.collection.LongSparseArray; @@ -14,24 +12,20 @@ import org.telegram.SQLite.SQLitePreparedStatement; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessageCustomParamsHelper; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.UserConfig; -import org.telegram.messenger.Utilities; import org.telegram.messenger.support.LongSparseIntArray; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -51,7 +45,7 @@ public void getAllStories(Consumer consumer) { storage.getStorageQueue().postRunnable(() -> { SQLiteDatabase database = storage.getDatabase(); SQLiteCursor cursor = null; - ArrayList userStoriesArray = new ArrayList<>(); + ArrayList userStoriesArray = new ArrayList<>(); ArrayList usersToLoad = new ArrayList<>(); ArrayList chatsToLoad = new ArrayList<>(); boolean failed = false; @@ -93,11 +87,11 @@ public void getAllStories(Consumer consumer) { } cursor.dispose(); cursor = null; - TLRPC.TL_userStories userStories; - userStories = new TLRPC.TL_userStories(); + TLRPC.PeerStories userStories; + userStories = new TLRPC.TL_peerStories(); userStories.stories = storyItems; userStories.max_read_id = maxReadId; - userStories.user_id = dialogId; + userStories.peer = MessagesController.getInstance(currentAccount).getPeer(dialogId); userStoriesArray.add(userStories); } } catch (Throwable e) { @@ -113,19 +107,21 @@ public void getAllStories(Consumer consumer) { return; } TLRPC.TL_stories_allStories storiesResponse = new TLRPC.TL_stories_allStories(); - storiesResponse.user_stories = userStoriesArray; + storiesResponse.peer_stories = userStoriesArray; storiesResponse.users = storage.getUsers(usersToLoad); - for (int i = 0; i < storiesResponse.user_stories.size(); i++) { - TLRPC.TL_userStories userStories = storiesResponse.user_stories.get(i); - checkExpiredStories(userStories.user_id, userStories.stories); + storiesResponse.chats = storage.getChats(chatsToLoad); + for (int i = 0; i < storiesResponse.peer_stories.size(); i++) { + TLRPC.PeerStories userStories = storiesResponse.peer_stories.get(i); + long dialogId = DialogObject.getPeerDialogId(userStories.peer); + checkExpiredStories(dialogId, userStories.stories); if (userStories.stories.isEmpty()) { - storiesResponse.user_stories.remove(i); + storiesResponse.peer_stories.remove(i); i--; } Collections.sort(userStories.stories, StoriesController.storiesComparator); } - Collections.sort(storiesResponse.user_stories, Comparator.comparingInt(o -> -o.stories.get(o.stories.size() - 1).date)); + Collections.sort(storiesResponse.peer_stories, Comparator.comparingInt(o -> -o.stories.get(o.stories.size() - 1).date)); AndroidUtilities.runOnUIThread(() -> consumer.accept(storiesResponse)); }); @@ -162,7 +158,7 @@ private void checkExpiredStories(long dialogId, ArrayList stori } - public void putStoriesInternal(long dialogId, TLRPC.TL_userStories userStories) { + public void putStoriesInternal(long dialogId, TLRPC.PeerStories userStories) { SQLiteDatabase database = storage.getDatabase(); try { if (userStories != null) { @@ -232,12 +228,12 @@ public void putStoryInternal(long dialogId, TLRPC.StoryItem storyItem) { } } - public void saveAllStories(ArrayList user_stories, boolean isNext, boolean hidden, Runnable callback) { + public void saveAllStories(ArrayList user_stories, boolean isNext, boolean hidden, Runnable callback) { storage.getStorageQueue().postRunnable(() -> { SQLiteDatabase database = storage.getDatabase(); for (int i = 0; i < user_stories.size(); i++) { - TLRPC.TL_userStories stories = user_stories.get(i); - fillSkippedStories(stories.user_id, stories); + TLRPC.PeerStories stories = user_stories.get(i); + fillSkippedStories(DialogObject.getPeerDialogId(stories.peer), stories); } if (!isNext) { try { @@ -246,12 +242,22 @@ public void saveAllStories(ArrayList user_stories, boolean ArrayList dialogsToDelete = new ArrayList<>(); while (cursor.next()) { long dialogId = cursor.longValue(0); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - if (user == null) { - user = MessagesStorage.getInstance(currentAccount).getUser(dialogId); - } - if (user == null || user.stories_hidden == hidden && !dialogsToDelete.contains(dialogId)) { - dialogsToDelete.add(dialogId); + if (dialogId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (user == null) { + user = MessagesStorage.getInstance(currentAccount).getUser(dialogId); + } + if (user == null || user.stories_hidden == hidden && !dialogsToDelete.contains(dialogId)) { + dialogsToDelete.add(dialogId); + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (chat == null) { + chat = MessagesStorage.getInstance(currentAccount).getChat(-dialogId); + } + if (chat == null || chat.stories_hidden == hidden && !dialogsToDelete.contains(dialogId)) { + dialogsToDelete.add(dialogId); + } } } if (BuildVars.LOGS_ENABLED) { @@ -263,8 +269,8 @@ public void saveAllStories(ArrayList user_stories, boolean } } for (int i = 0; i < user_stories.size(); i++) { - TLRPC.TL_userStories stories = user_stories.get(i); - putStoriesInternal(stories.user_id, stories); + TLRPC.PeerStories stories = user_stories.get(i); + putStoriesInternal(DialogObject.getPeerDialogId(stories.peer), stories); } if (callback != null) { AndroidUtilities.runOnUIThread(callback); @@ -272,7 +278,7 @@ public void saveAllStories(ArrayList user_stories, boolean }); } - private void fillSkippedStories(long user_id, TLRPC.TL_userStories userStories) { + private void fillSkippedStories(long user_id, TLRPC.PeerStories userStories) { try { if (userStories != null) { ArrayList storyItems = userStories.stories; @@ -321,17 +327,17 @@ private TLRPC.StoryItem getStoryInternal(long user_id, int storyId) { } - public void getStories(long dialogId, Consumer consumer) { + public void getStories(long dialogId, Consumer consumer) { storage.getStorageQueue().postRunnable(() -> { - TLRPC.TL_userStories finalUserStories = getStoriesInternal(dialogId); + TLRPC.PeerStories finalUserStories = getStoriesInternal(dialogId); AndroidUtilities.runOnUIThread(() -> consumer.accept(finalUserStories)); }); } - private TLRPC.TL_userStories getStoriesInternal(long dialogId) { + private TLRPC.PeerStories getStoriesInternal(long dialogId) { SQLiteDatabase database = storage.getDatabase(); SQLiteCursor cursor = null; - TLRPC.TL_userStories userStories = null; + TLRPC.PeerStories userStories = null; try { cursor = database.queryFinalized(String.format(Locale.US, "SELECT count, max_read FROM stories_counter WHERE dialog_id = %d", dialogId)); int count = 0; @@ -360,10 +366,10 @@ private TLRPC.TL_userStories getStoriesInternal(long dialogId) { } cursor.dispose(); cursor = null; - userStories = new TLRPC.TL_userStories(); + userStories = new TLRPC.TL_peerStories(); userStories.max_read_id = maxReadId; userStories.stories = storyItems; - userStories.user_id = dialogId; + userStories.peer = MessagesController.getInstance(currentAccount).getPeer(dialogId); } catch (Exception e) { FileLog.e(e); @@ -423,10 +429,18 @@ private void updateStoryItemInternal(long dialogId, TLRPC.StoryItem storyItem) { } public void updateMaxReadId(long dialogId, int max_read_id) { - TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); - if (userFull != null && userFull.stories != null) { - userFull.stories.max_read_id = max_read_id; - storage.updateUserInfo(userFull, false); + if (dialogId > 0) { + TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); + if (userFull != null && userFull.stories != null) { + userFull.stories.max_read_id = max_read_id; + storage.updateUserInfo(userFull, false); + } + } else { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + if (chatFull != null && chatFull.stories != null) { + chatFull.stories.max_read_id = max_read_id; + storage.updateChatInfo(chatFull, false); + } } storage.getStorageQueue().postRunnable(() -> { SQLiteDatabase database = storage.getDatabase(); @@ -443,7 +457,7 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { SQLiteDatabase database = storage.getDatabase(); SQLiteCursor cursor = null; try { - long dialogId = updateStory.user_id; + long dialogId = DialogObject.getPeerDialogId(updateStory.peer); int count = 0; int storyId = updateStory.story.id; boolean storyExist = false; @@ -495,10 +509,10 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { }); } - public void updateStories(TLRPC.TL_userStories currentStories) { + public void updateStories(TLRPC.PeerStories currentStories) { storage.getStorageQueue().postRunnable(() -> { for (int i = 0; i < currentStories.stories.size(); i++) { - updateStoryItemInternal(currentStories.user_id, currentStories.stories.get(i)); + updateStoryItemInternal(DialogObject.getPeerDialogId(currentStories.peer), currentStories.stories.get(i)); } }); } @@ -565,7 +579,7 @@ public void fillMessagesWithStories(LongSparseArray> me long dialogId = messagesWithUnknownStories.keyAt(i); ArrayList messageObjects = messagesWithUnknownStories.valueAt(i); TLRPC.TL_stories_getStoriesByID request = new TLRPC.TL_stories_getStoriesByID(); - request.user_id = MessagesController.getInstance(currentAccount).getInputUser(dialogId); + request.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); for (int j = 0; j < messageObjects.size(); j++) { request.id.add(getStoryId(messageObjects.get(j))); } @@ -612,7 +626,8 @@ public static void applyStory(int currentAccount, long dialogId, MessageObject m } if (messageObject.type == MessageObject.TYPE_STORY || messageObject.type == MessageObject.TYPE_STORY_MENTION) { MessageMediaStoryFull mediaStoryFull = new MessageMediaStoryFull(); - mediaStoryFull.user_id = messageObject.messageOwner.media.user_id; + mediaStoryFull.user_id = DialogObject.getPeerDialogId(messageObject.messageOwner.media.peer); + mediaStoryFull.peer = messageObject.messageOwner.media.peer; mediaStoryFull.id = messageObject.messageOwner.media.id; mediaStoryFull.storyItem = checkExpiredStateLocal(currentAccount, dialogId, storyItem); mediaStoryFull.via_mention = messageObject.messageOwner.media.via_mention; @@ -741,9 +756,9 @@ public void getMaxReadIds(Consumer consumer) { }); } - public void putUserStories(TLRPC.TL_userStories userStories) { + public void putPeerStories(TLRPC.PeerStories userStories) { storage.getStorageQueue().postRunnable(() -> { - putStoriesInternal(userStories.user_id, userStories); + putStoriesInternal(DialogObject.getPeerDialogId(userStories.peer), userStories); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java index 77d8d1f431b..2bc804ded51 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java @@ -23,6 +23,7 @@ import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.ImageLocation; @@ -182,7 +183,7 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv if (progressToSate != 1f) { progressToSate = CubicBezierInterpolator.DEFAULT.getInterpolation(progressToSate); } - float insetTo = params.isStoryCell ? 0 : AndroidUtilities.lerp( + float insetTo = params.isStoryCell && !params.drawInside ? 0 : AndroidUtilities.lerp( getInset(params.prevState, params.animateFromUnreadState), getInset(params.currentState, params.animateFromUnreadState), params.progressToSate @@ -205,7 +206,7 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv } boolean animateOut = params.prevState == STATE_HAS_UNREAD && params.progressToSate != 1f; - float inset = params.isStoryCell ? -AndroidUtilities.dp(4) : 0;//AndroidUtilities.lerp(AndroidUtilities.dp(2), 0, imageScale); + float inset = params.isStoryCell && !params.drawInside ? -AndroidUtilities.dp(4) : 0;//AndroidUtilities.lerp(AndroidUtilities.dp(2), 0, imageScale); if (animateOut) { inset += AndroidUtilities.dp(5) * progressToSate; gradientTools.paint.setAlpha((int) (0xFF * params.alpha * (1f - progressToSate))); @@ -239,9 +240,9 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv } float inset; if (params.drawSegments) { - inset = params.isStoryCell ? -AndroidUtilities.dpf2(3.5f) : 0; + inset = params.isStoryCell && !params.drawInside ? -AndroidUtilities.dpf2(3.5f) : 0; } else { - inset = params.isStoryCell ? -AndroidUtilities.dpf2(2.7f) : 0; + inset = params.isStoryCell && !params.drawInside ? -AndroidUtilities.dpf2(2.7f) : 0; } if (animateOut) { inset += AndroidUtilities.dp(5) * progressToSate; @@ -285,9 +286,9 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv } float inset; if (params.drawSegments) { - inset = params.isStoryCell ? -AndroidUtilities.dpf2(3.5f) : 0; + inset = params.isStoryCell && !params.drawInside ? -AndroidUtilities.dpf2(3.5f) : 0; } else { - inset = params.isStoryCell ? -AndroidUtilities.dpf2(2.7f) : 0; + inset = params.isStoryCell && !params.drawInside ? -AndroidUtilities.dpf2(2.7f) : 0; } boolean animateOut = params.prevState == STATE_PROGRESS && params.progressToSate != 1f; if (animateOut) { @@ -353,7 +354,10 @@ private static void drawSegmentsInternal(Canvas canvas, StoriesController storie } params.globalState = globalState == StoriesController.STATE_READ ? STATE_READ : STATE_HAS_UNREAD; - TLRPC.TL_userStories userStories = storiesController.getStories(params.dialogId); + TLRPC.PeerStories userStories = storiesController.getStories(params.dialogId); + if (userStories == null) { + userStories = storiesController.getStoriesFromFullPeer(params.dialogId); + } int storiesCount; if (params.drawHiddenStoriesAsSegments) { storiesCount = storiesController.getHiddenList().size(); @@ -370,7 +374,7 @@ private static void drawSegmentsInternal(Canvas canvas, StoriesController storie } else { globalPaint = params.isStoryCell ? storyCellGreyPaint[params.isArchive ? 1 : 0] : grayPaint; } - if (storiesCount == 1) { + if (storiesCount <= 1) { Paint localPaint = paint; if (storiesController.hasUnreadStories(params.dialogId)) { localPaint = unreadPaint; @@ -406,7 +410,7 @@ private static void drawSegmentsInternal(Canvas canvas, StoriesController storie for (int i = 0; i < storiesCount; i++) { Paint segmentPaint = params.isStoryCell ? storyCellGreyPaint[params.isArchive ? 1 : 0] : grayPaint; if (params.drawHiddenStoriesAsSegments) { - int userUnreadState = storiesController.getUnreadState(storiesController.getHiddenList().get(storiesCount - 1 - i).user_id); + int userUnreadState = storiesController.getUnreadState(DialogObject.getPeerDialogId(storiesController.getHiddenList().get(storiesCount - 1 - i).peer)); if (userUnreadState == StoriesController.STATE_UNREAD_CLOSE_FRIEND) { segmentPaint = closeFriendsPaint; } else if (userUnreadState == STATE_UNREAD) { @@ -440,16 +444,33 @@ private static void drawSegmentsInternal(Canvas canvas, StoriesController storie } private static int getPredictiveUnreadState(StoriesController storiesController, long dialogId) { - TLRPC.User user = MessagesController.getInstance(UserConfig.selectedAccount).getUser(dialogId); - if (dialogId != UserConfig.getInstance(UserConfig.selectedAccount).clientUserId && user != null && user.stories_max_id > 0 && !user.stories_unavailable) { - int maxReadId = storiesController.dialogIdToMaxReadId.get(dialogId, 0); - if (user.stories_max_id > maxReadId) { - return STATE_HAS_UNREAD; + if (dialogId == 0) { + return STATE_EMPTY; + } + if (dialogId > 0) { + TLRPC.User user = MessagesController.getInstance(UserConfig.selectedAccount).getUser(dialogId); + if (dialogId != UserConfig.getInstance(UserConfig.selectedAccount).clientUserId && user != null && user.stories_max_id > 0 && !user.stories_unavailable) { + int maxReadId = storiesController.dialogIdToMaxReadId.get(dialogId, 0); + if (user.stories_max_id > maxReadId) { + return STATE_HAS_UNREAD; + } else { + return STATE_READ; + } } else { - return STATE_READ; + return STATE_EMPTY; } } else { - return STATE_EMPTY; + TLRPC.Chat chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-dialogId); + if (chat != null && chat.stories_max_id > 0 && !chat.stories_unavailable) { + int maxReadId = storiesController.dialogIdToMaxReadId.get(dialogId, 0); + if (chat.stories_max_id > maxReadId) { + return STATE_HAS_UNREAD; + } else { + return STATE_READ; + } + } else { + return STATE_EMPTY; + } } } @@ -627,6 +648,23 @@ public static Paint getErrorPaint(ImageReceiver avatarImage) { return errorGradientTools.paint; } + public static Paint getErrorPaint(RectF rect) { + if (errorGradientTools == null) { + errorGradientTools = new GradientTools(); + errorGradientTools.isDiagonal = true; + errorGradientTools.isRotate = true; + int orange = Theme.getColor(Theme.key_color_orange); + final int red = Theme.getColor(Theme.key_text_RedBold); + orange = ColorUtils.blendARGB(orange, red, .25f); + errorGradientTools.setColors(orange, red); + errorGradientTools.paint.setStrokeWidth(AndroidUtilities.dpf2(2.3f)); + errorGradientTools.paint.setStyle(Paint.Style.STROKE); + errorGradientTools.paint.setStrokeCap(Paint.Cap.ROUND); + } + errorGradientTools.setBounds(rect.left, rect.top, rect.right, rect.bottom); + return errorGradientTools.paint; + } + public static void setStoryMiniImage(ImageReceiver imageReceiver, TLRPC.StoryItem storyItem) { if (storyItem == null) { return; @@ -656,15 +694,18 @@ public static void setImage(ImageReceiver imageReceiver, TLRPC.StoryItem storyIt if (storyItem.media != null && storyItem.media.document != null) { TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.document.thumbs, Integer.MAX_VALUE); imageReceiver.setImage(ImageLocation.getForDocument(size, storyItem.media.document), filter, null, null, ImageLoader.createStripedBitmap(storyItem.media.document.thumbs), 0, null, storyItem, 0); + imageReceiver.addDecorator(new StoryWidgetsImageDecorator(storyItem)); } else { TLRPC.Photo photo = storyItem.media != null ? storyItem.media.photo : null; if (storyItem.media instanceof TLRPC.TL_messageMediaUnsupported) { Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); bitmap.eraseColor(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.2f)); imageReceiver.setImageBitmap(bitmap); + imageReceiver.addDecorator(new StoryWidgetsImageDecorator(storyItem)); } else if (photo != null && photo.sizes != null) { TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, Integer.MAX_VALUE); imageReceiver.setImage(null, null, ImageLocation.getForPhoto(size, photo), filter, null, null, ImageLoader.createStripedBitmap(photo.sizes), 0, null, storyItem, 0); + imageReceiver.addDecorator(new StoryWidgetsImageDecorator(storyItem)); } else { imageReceiver.clearImage(); } @@ -862,14 +903,14 @@ public void cancel() { } } - public static EnsureStoryFileLoadedObject ensureStoryFileLoaded(TLRPC.TL_userStories stories, Runnable onDoneOrTimeout) { - if (stories == null || stories.stories.isEmpty() || stories.user_id == UserConfig.getInstance(UserConfig.selectedAccount).clientUserId) { + public static EnsureStoryFileLoadedObject ensureStoryFileLoaded(TLRPC.PeerStories stories, Runnable onDoneOrTimeout) { + if (stories == null || stories.stories.isEmpty() || DialogObject.getPeerDialogId(stories.peer) == UserConfig.getInstance(UserConfig.selectedAccount).clientUserId) { onDoneOrTimeout.run(); return null; } TLRPC.StoryItem storyItem = null; StoriesController storiesController = MessagesController.getInstance(UserConfig.selectedAccount).storiesController; - int maxReadId = storiesController.dialogIdToMaxReadId.get(stories.user_id); + int maxReadId = storiesController.dialogIdToMaxReadId.get(DialogObject.getPeerDialogId(stories.peer)); for (int i = 0; i < stories.stories.size(); i++) { if (stories.stories.get(i).id > maxReadId) { @@ -917,7 +958,7 @@ public static EnsureStoryFileLoadedObject ensureStoryFileLoaded(TLRPC.TL_userSto } } - EnsureStoryFileLoadedObject ensureStoryFileLoadedObject = new EnsureStoryFileLoadedObject(storiesController, stories.user_id); + EnsureStoryFileLoadedObject ensureStoryFileLoadedObject = new EnsureStoryFileLoadedObject(storiesController, DialogObject.getPeerDialogId(stories.peer)); ensureStoryFileLoadedObject.runnable = () -> { if (ensureStoryFileLoadedObject.cancelled) { return; @@ -985,6 +1026,7 @@ public static class AvatarStoryParams { public float crossfadeToDialogProgress; public float progressToProgressSegments; public float alpha = 1f; + public boolean drawInside; private long dialogId; public int currentState; @@ -1040,12 +1082,22 @@ public boolean checkOnTouchEvent(MotionEvent event, View view) { child = view; StoriesController storiesController = MessagesController.getInstance(UserConfig.selectedAccount).getStoriesController(); if (event.getAction() == MotionEvent.ACTION_DOWN && originalAvatarRect.contains(event.getX(), event.getY())) { - TLRPC.User user = MessagesController.getInstance(UserConfig.selectedAccount).getUser(dialogId); + TLRPC.User user = null; + TLRPC.Chat chat = null; + if (dialogId > 0) { + user = MessagesController.getInstance(UserConfig.selectedAccount).getUser(dialogId); + } else { + chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-dialogId); + } boolean hasStories; if (drawHiddenStoriesAsSegments) { hasStories = storiesController.hasHiddenStories(); } else { - hasStories = (MessagesController.getInstance(UserConfig.selectedAccount).getStoriesController().hasStories(dialogId) || user != null && !user.stories_unavailable && user.stories_max_id > 0); + if (dialogId > 0) { + hasStories = (MessagesController.getInstance(UserConfig.selectedAccount).getStoriesController().hasStories(dialogId) || user != null && !user.stories_unavailable && user.stories_max_id > 0); + } else { + hasStories = (MessagesController.getInstance(UserConfig.selectedAccount).getStoriesController().hasStories(dialogId) || chat != null && !chat.stories_unavailable && chat.stories_max_id > 0); + } } if (dialogId != UserConfig.getInstance(UserConfig.selectedAccount).clientUserId && hasStories) { if (buttonBounce == null) { @@ -1125,11 +1177,20 @@ private void processOpenStory(View view) { openStory(dialogId, null); return; } - TLRPC.User user = messagesController.getUser(dialogId); - if (user != null && !user.stories_unavailable && user.stories_max_id > 0) { - UserStoriesLoadOperation operation = new UserStoriesLoadOperation(); - operation.load(dialogId, view, this); - return; + if (dialogId > 0) { + TLRPC.User user = messagesController.getUser(dialogId); + if (user != null && !user.stories_unavailable && user.stories_max_id > 0) { + UserStoriesLoadOperation operation = new UserStoriesLoadOperation(); + operation.load(dialogId, view, this); + return; + } + } else { + TLRPC.Chat chat = messagesController.getChat(-dialogId); + if (chat != null && !chat.stories_unavailable && chat.stories_max_id > 0) { + UserStoriesLoadOperation operation = new UserStoriesLoadOperation(); + operation.load(dialogId, view, this); + return; + } } } } @@ -1182,17 +1243,16 @@ void load(long dialogId, View view, AvatarStoryParams params) { storiesController.setLoading(dialogId, true); view.invalidate(); - TLRPC.User user = messagesController.getUser(dialogId); - - TLRPC.TL_stories_getUserStories req = new TLRPC.TL_stories_getUserStories(); - req.user_id = MessagesController.getInstance(currentAccount).getInputUser(dialogId); + TLRPC.TL_stories_getPeerStories req = new TLRPC.TL_stories_getPeerStories(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { boolean openned = false; boolean finished = true; if (response != null) { - TLRPC.TL_stories_userStories stories_userStories = (TLRPC.TL_stories_userStories) response; + TLRPC.TL_stories_peerStories stories_userStories = (TLRPC.TL_stories_peerStories) response; MessagesController.getInstance(currentAccount).putUsers(stories_userStories.users, false); - TLRPC.TL_userStories stories = stories_userStories.stories; + MessagesController.getInstance(currentAccount).putChats(stories_userStories.chats, false); + TLRPC.PeerStories stories = stories_userStories.stories; if (!stories.stories.isEmpty()) { MessagesController.getInstance(currentAccount).getStoriesController().putStories(dialogId, stories); finished = false; @@ -1206,10 +1266,23 @@ void load(long dialogId, View view, AvatarStoryParams params) { } } if (!openned) { - TLRPC.User user2 = messagesController.getUser(dialogId); - user2.stories_unavailable = true; - MessagesStorage.getInstance(currentAccount).putUsersAndChats(Collections.singletonList(user2), null, false, true); - messagesController.putUser(user2, false); + if (dialogId > 0) { + TLRPC.User user2 = messagesController.getUser(dialogId); + if (user2 != null) { + user2.stories_unavailable = true; + MessagesStorage.getInstance(currentAccount).putUsersAndChats(Collections.singletonList(user2), null, false, true); + messagesController.putUser(user2, false); + } + } + + if (dialogId < 0) { + TLRPC.Chat chat = messagesController.getChat(-dialogId); + if (chat != null) { + chat.stories_unavailable = true; + MessagesStorage.getInstance(currentAccount).putUsersAndChats(null, Collections.singletonList(chat), false, true); + messagesController.putChat(chat, false); + } + } } if (finished) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesVolumeContorl.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesVolumeContorl.java index f7c11ef7753..b891e1fbd75 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesVolumeContorl.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesVolumeContorl.java @@ -45,6 +45,27 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { return super.onKeyDown(keyCode, event); } + // unmutes only if muted + public void unmute() { + AudioManager audioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); + int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int minVolume = 0; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { + minVolume = audioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC); + } + int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); + if (currentVolume <= minVolume) { + adjustVolume(true); + } else if (!isVisible) { + currentProgress = currentVolume / (float) maxVolume; + volumeProgress.set(currentProgress, true); + isVisible = true; + invalidate(); + AndroidUtilities.cancelRunOnUIThread(hideRunnuble); + AndroidUtilities.runOnUIThread(hideRunnuble, 2000); + } + } + private void adjustVolume(boolean increase) { AudioManager audioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java index 282a6115999..d9add765775 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java @@ -552,6 +552,7 @@ public class StoryCaptionTextView extends View implements TextSelectionHelper.Si private final PorterDuffColorFilter emojiColorFilter; + boolean shouldCollapse; TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); TextPaint showMorePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); private final Paint xRefPaint = new Paint(); @@ -594,7 +595,7 @@ public int collapsedTextHeight(int height) { } final Layout layout = fullLayout; final int lineCount = layout.getLineCount(); - if (lineCount <= 3) { + if (!shouldCollapse) { return height - (verticalPadding * 2 + textHeight); } int i = Math.min(3, lineCount); @@ -649,7 +650,15 @@ public void measure(int width) { fullLayout = makeTextLayout(textPaint, text, width); textHeight = fullLayout.getHeight(); float space = textPaint.measureText(" "); - if (fullLayout.getLineCount() > 3) { + shouldCollapse = fullLayout.getLineCount() > 3; + if (shouldCollapse && fullLayout.getLineCount() == 4) { + int start = fullLayout.getLineStart(2); + int end = fullLayout.getLineEnd(2); + if (TextUtils.getTrimmedLength(text.subSequence(start, end)) == 0) { + shouldCollapse = false; + } + } + if (shouldCollapse) { float collapsedY = fullLayout.getLineTop(2) + fullLayout.getTopPadding(); if (this == state[0]) { String showMoreText = LocaleController.getString("ShowMore", R.string.ShowMore); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java index b742d6c4ba4..52d690fe453 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java @@ -40,10 +40,12 @@ import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Paint.Views.ReactionWidgetEntityView; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.EmojiAnimationsOverlay; import org.telegram.ui.LocationActivity; import org.telegram.ui.Stories.recorder.HintView2; +import org.telegram.ui.Stories.recorder.StoryEntry; import java.util.ArrayList; @@ -67,6 +69,19 @@ public StoryMediaAreasView(Context context, Theme.ResourcesProvider resourcesPro addView(hintsContainer = new FrameLayout(context)); } + public static ArrayList getMediaAreasFor(StoryEntry entry) { + if (entry == null || entry.mediaEntities == null) { + return null; + } + ArrayList areas = new ArrayList<>(); + for (int i = 0; i < entry.mediaEntities.size(); i++) { + if (entry.mediaEntities.get(i).mediaArea instanceof TLRPC.TL_mediaAreaSuggestedReaction) { + areas.add(entry.mediaEntities.get(i).mediaArea); + } + } + return areas; + } + protected void onHintVisible(boolean hintVisible) { } @@ -77,7 +92,12 @@ protected void presentFragment(BaseFragment fragment) { private ArrayList lastMediaAreas; - public void set(ArrayList mediaAreas) { + public void set(TLRPC.StoryItem storyItem, EmojiAnimationsOverlay animationsOverlay) { + ArrayList mediaAreas = storyItem != null ? storyItem.media_areas : null; + set(storyItem, mediaAreas, animationsOverlay); + } + + public void set(TLRPC.StoryItem storyItem, ArrayList mediaAreas, EmojiAnimationsOverlay animationsOverlay) { if (mediaAreas == lastMediaAreas && (mediaAreas == null || lastMediaAreas == null || mediaAreas.size() == lastMediaAreas.size())) { return; } @@ -112,7 +132,17 @@ public void set(ArrayList mediaAreas) { for (int i = 0; i < mediaAreas.size(); ++i) { TLRPC.MediaArea mediaArea = mediaAreas.get(i); if (mediaArea != null && mediaArea.coordinates != null) { - AreaView areaView = new AreaView(getContext(), this, mediaArea); + View areaView; + if (mediaArea instanceof TLRPC.TL_mediaAreaSuggestedReaction) { + StoryReactionWidgetView storyReactionWidgetView = new StoryReactionWidgetView(getContext(), this, (TLRPC.TL_mediaAreaSuggestedReaction) mediaArea, animationsOverlay); + areaView = storyReactionWidgetView; + if (storyItem != null) { + storyReactionWidgetView.setViews(storyItem.views, false); + } + ScaleStateListAnimator.apply(areaView); + } else { + areaView = new AreaView(getContext(), this, mediaArea); + } areaView.setOnClickListener(this); addView(areaView); @@ -152,6 +182,10 @@ public void onClick(View v) { return; } + if (v instanceof StoryReactionWidgetView) { + showEffect((StoryReactionWidgetView) v); + return; + } if (selectedArea == v) { AndroidUtilities.runOnUIThread(() -> { if (hintView != null) { @@ -250,6 +284,10 @@ protected boolean disablePermissionCheck() { onHintVisible(true); } + public void showEffect(StoryReactionWidgetView v) { + + } + public void closeHint() { if (hintView != null) { hintView.hide(); @@ -367,6 +405,39 @@ public boolean hasSelected() { return selectedArea != null; } + public void onStoryItemUpdated(TLRPC.StoryItem storyItem, boolean animated) { + if (storyItem == null) { + return; + } + for (int i = 0; i < getChildCount(); i++) { + if (getChildAt(i) instanceof StoryReactionWidgetView) { + StoryReactionWidgetView storyReactionWidgetView = (StoryReactionWidgetView) getChildAt(i); + storyReactionWidgetView.setViews(storyItem.views, animated); + } + } + } + + public boolean hasClickableViews(float x, float y) { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child == hintsContainer) { + continue; + } + if (!(child instanceof StoryReactionWidgetView)) { + continue; + } + child.getMatrix().invert(matrix); + point[0] = x; + point[1] = y; + matrix.mapPoints(point); + if (point[0] >= child.getLeft() && point[0] <= child.getRight() && + point[1] >= child.getTop() && point[1] <= child.getBottom()) { + return true; + } + } + return false; + } + public static class AreaView extends View { public final AnimatedFloat highlightAlpha; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryReactionWidgetView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryReactionWidgetView.java new file mode 100644 index 00000000000..95c43914e0b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryReactionWidgetView.java @@ -0,0 +1,154 @@ +package org.telegram.ui.Stories; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.view.Gravity; +import android.view.View; + +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.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.Reactions.AnimatedEmojiEffect; +import org.telegram.ui.Components.Reactions.ReactionImageHolder; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; +import org.telegram.ui.Components.Reactions.ReactionsUtils; +import org.telegram.ui.EmojiAnimationsOverlay; + +public class StoryReactionWidgetView extends StoryMediaAreasView.AreaView { + + private final ReactionsLayoutInBubble.VisibleReaction visibleReaction; + StoryReactionWidgetBackground storyReactionWidgetBackground = new StoryReactionWidgetBackground(this); + ReactionImageHolder holder = new ReactionImageHolder(this); + ImageReceiver preloadSmallReaction = new ImageReceiver(this); + AnimatedFloat progressToCount = new AnimatedFloat(this); + AnimatedTextView.AnimatedTextDrawable animatedTextDrawable = new AnimatedTextView.AnimatedTextDrawable(); + boolean hasCounter; + + public StoryReactionWidgetView(Context context, View parent, TLRPC.TL_mediaAreaSuggestedReaction mediaArea, EmojiAnimationsOverlay overlay) { + super(context, parent, mediaArea); + visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(mediaArea.reaction); + if (mediaArea.flipped) { + storyReactionWidgetBackground.setMirror(true, false); + } + + storyReactionWidgetBackground.updateShadowLayer(getScaleX()); + holder.setVisibleReaction(visibleReaction); + overlay.preload(visibleReaction); + if (visibleReaction.emojicon != null) { + TLRPC.TL_availableReaction r = MediaDataController.getInstance(UserConfig.selectedAccount).getReactionsMap().get(visibleReaction.emojicon); + if (r != null) { + preloadSmallReaction.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", null, "webp", r, 1); + } + } + animatedTextDrawable.setGravity(Gravity.CENTER); + animatedTextDrawable.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + animatedTextDrawable.setTextSize(AndroidUtilities.dp(14)); + + if (mediaArea.dark) { + storyReactionWidgetBackground.nextStyle(); + animatedTextDrawable.setTextColor(Color.WHITE); + } + } + + public void setViews(TLRPC.StoryViews storyViews, boolean animated) { + if (storyViews != null) { + for (int i = 0; i < storyViews.reactions.size(); i++) { + if (ReactionsUtils.compare(storyViews.reactions.get(i).reaction, visibleReaction)) { + boolean animateText = animated && hasCounter; + hasCounter = storyViews.reactions.get(i).count > 0; + animatedTextDrawable.setText(AndroidUtilities.formatWholeNumber(storyViews.reactions.get(i).count, 0), animateText); + if (!animated) { + progressToCount.set(hasCounter ? 1f : 0, true); + } + return; + } + } + } + hasCounter = false; + invalidate(); + if (!animated) { + progressToCount.set(hasCounter ? 1f : 0, true); + } + } + + @Override + public void setScaleX(float scaleX) { + if (getScaleX() != scaleX) { + storyReactionWidgetBackground.updateShadowLayer(scaleX); + super.setScaleX(scaleX); + } + } + + @Override + protected void onDraw(Canvas canvas) { + storyReactionWidgetBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + storyReactionWidgetBackground.draw(canvas); + int imageSize = (int) (getMeasuredWidth() * 0.61f); + float x1 = storyReactionWidgetBackground.getBounds().centerX() - imageSize / 2f; + float y1 = storyReactionWidgetBackground.getBounds().centerY() - imageSize / 2f; + float x2 = storyReactionWidgetBackground.getBounds().centerX() + imageSize / 2f; + float y2 = storyReactionWidgetBackground.getBounds().centerY() + imageSize / 2f; + + float cy = storyReactionWidgetBackground.getBounds().top + storyReactionWidgetBackground.getBounds().height() * 0.427f; + + float countedY1 = cy - imageSize / 2f; + float countedY2 = cy + imageSize / 2f; + + float progress = progressToCount.set(hasCounter ? 1f : 0); + AndroidUtilities.rectTmp2.set( + (int) x1, + (int) AndroidUtilities.lerp(y1, countedY1, progress), + (int) x2, + (int) AndroidUtilities.lerp(y2, countedY2, progress) + ); + holder.setColor(storyReactionWidgetBackground.isDarkStyle() ? Color.WHITE : Color.BLACK); + holder.setBounds(AndroidUtilities.rectTmp2); + holder.draw(canvas); + + float textCy = storyReactionWidgetBackground.getBounds().top + storyReactionWidgetBackground.getBounds().height() * 0.839f; + animatedTextDrawable.setBounds( + storyReactionWidgetBackground.getBounds().left, + (int) (textCy - AndroidUtilities.dp(10)), + storyReactionWidgetBackground.getBounds().right, + (int) (textCy + AndroidUtilities.dp(10)) + ); + canvas.save(); + canvas.scale(progress, progress, storyReactionWidgetBackground.getBounds().centerX(), textCy); + animatedTextDrawable.draw(canvas); + canvas.restore(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + holder.onAttachedToWindow(true); + preloadSmallReaction.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + holder.onAttachedToWindow(false); + preloadSmallReaction.onDetachedFromWindow(); + + } + + public void playAnimation() { + holder.play(); + } + + public AnimatedEmojiDrawable getAnimatedEmojiDrawable() { + return holder.animatedEmojiDrawable; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java index 52c7a32c8a9..b34f0904974 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java @@ -21,7 +21,6 @@ import android.media.AudioManager; import android.net.Uri; import android.os.Build; -import android.text.Editable; import android.util.LongSparseArray; import android.util.SparseArray; import android.view.GestureDetector; @@ -45,11 +44,11 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; -import com.google.android.exoplayer2.util.Log; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.FileStreamLoadOperation; @@ -61,7 +60,6 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.support.LongSparseIntArray; -import org.telegram.messenger.support.SparseLongArray; import org.telegram.messenger.video.VideoPlayerHolderBase; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; @@ -172,7 +170,7 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat private SurfaceView surfaceView; Uri lastUri; PeerStoriesView.VideoPlayerSharedScope currentPlayerScope; - private boolean isClosed; + private boolean isClosed = true; private boolean isRecording; AnimationNotificationsLocker locker = new AnimationNotificationsLocker(); private boolean isWaiting; @@ -184,7 +182,7 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat boolean isSingleStory; StoriesController.StoriesList storiesList; public int dayStoryId; - TLRPC.TL_userStories overrideUserStories; + TLRPC.PeerStories overrideUserStories; boolean reversed; TLRPC.StoryItem singleStory; @@ -221,7 +219,8 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat private boolean isLikesReactions; private float lastStoryContainerHeight; - LongSparseArray replyDrafts = new LongSparseArray<>(); + private static final LongSparseArray replyDrafts = new LongSparseArray<>(); + public boolean fromBottomSheet; public static boolean isShowingImage(MessageObject messageObject) { if (lastStoryItem == null || messageObject.type != MessageObject.TYPE_STORY && !messageObject.isWebpage() || runOpenAnimationAfterLayout) { @@ -260,10 +259,14 @@ public void open(Context context, TLRPC.StoryItem storyItem, PlaceProvider place return; } currentAccount = UserConfig.selectedAccount; - ArrayList peerIds = new ArrayList<>(); - if (storyItem != null) { - peerIds.add(storyItem.dialogId); + if (storyItem.dialogId > 0 && MessagesController.getInstance(currentAccount).getUser(storyItem.dialogId) == null) { + return; + } + if (storyItem.dialogId < 0 && MessagesController.getInstance(currentAccount).getChat(-storyItem.dialogId) == null) { + return; } + ArrayList peerIds = new ArrayList<>(); + peerIds.add(storyItem.dialogId); open(context, storyItem, peerIds, 0, null, null, placeProvider, false); } @@ -284,14 +287,14 @@ public void open(Context context, int startStoryId, StoriesController.StoriesLis open(context, null, peerIds, 0, storiesList, null, placeProvider, false); } - public void open(Context context, TLRPC.TL_userStories userStories, PlaceProvider placeProvider) { + public void open(Context context, TLRPC.PeerStories userStories, PlaceProvider placeProvider) { if (userStories == null || userStories.stories == null || userStories.stories.isEmpty()) { doOnAnimationReadyRunnables.clear(); return; } currentAccount = UserConfig.selectedAccount; ArrayList peerIds = new ArrayList<>(); - peerIds.add(userStories.user_id); + peerIds.add(DialogObject.getPeerDialogId(userStories.peer)); open(context, userStories.stories.get(0), peerIds, 0, null, userStories, placeProvider, false); } @@ -304,7 +307,7 @@ public void open(Context context, TLRPC.StoryItem storyItem, int startStoryId, S } @SuppressLint("WrongConstant") - public void open(Context context, TLRPC.StoryItem storyItem, ArrayList peerIds, int position, StoriesController.StoriesList storiesList, TLRPC.TL_userStories userStories, PlaceProvider placeProvider, boolean reversed) { + public void open(Context context, TLRPC.StoryItem storyItem, ArrayList peerIds, int position, StoriesController.StoriesList storiesList, TLRPC.PeerStories userStories, PlaceProvider placeProvider, boolean reversed) { if (context == null) { doOnAnimationReadyRunnables.clear(); return; @@ -317,7 +320,7 @@ public void open(Context context, TLRPC.StoryItem storyItem, ArrayList pee doOnAnimationReadyRunnables.clear(); return; } - ATTACH_TO_FRAGMENT = !AndroidUtilities.isTablet(); + ATTACH_TO_FRAGMENT = !AndroidUtilities.isTablet() && !fromBottomSheet; USE_SURFACE_VIEW = SharedConfig.useSurfaceInStories && ATTACH_TO_FRAGMENT; messageId = storyItem == null ? 0 : storyItem.messageId; isSingleStory = storyItem != null && storiesList == null && userStories == null; @@ -906,8 +909,9 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { if (peerView != null) { peerView.cancelTextSelection(); } - allowSwipeToReply = !peerView.isSelf; - allowSelfStoriesView = peerView.isSelf && !peerView.unsupported && peerView.currentStory.storyItem != null; + boolean viewsAllowed = peerView != null && peerView.viewsAllowed(); + allowSwipeToReply = !viewsAllowed && peerView != null && !peerView.isChannel; + allowSelfStoriesView = viewsAllowed && !peerView.unsupported && peerView.currentStory.storyItem != null; if (allowSelfStoriesView && keyboardHeight != 0) { allowSelfStoriesView = false; } @@ -1315,6 +1319,7 @@ public void requestPlayer(TLRPC.Document document, Uri uri, long t, PeerStoriesV surfaceView.setVisibility(View.VISIBLE); } } + updatePlayingMode(); } @Override @@ -1612,9 +1617,9 @@ private void checkSelfStoriesView() { for (int i = 0; i < storiesList.messageObjects.size(); i++) { storyItems.add(storiesList.messageObjects.get(i).storyItem); } - selfStoryViewsView.setItems(storyItems, peerStoriesView.getListPosition()); + selfStoryViewsView.setItems(storiesList.dialogId, storyItems, peerStoriesView.getListPosition()); } else { - selfStoryViewsView.setItems(peerStoriesView.getStoryItems(), peerStoriesView.getSelectedPosition()); + selfStoryViewsView.setItems(peerStoriesView.getCurrentPeer(), peerStoriesView.getStoryItems(), peerStoriesView.getSelectedPosition()); } } } @@ -1736,7 +1741,7 @@ private void dispatchVolumeEvent(KeyEvent event) { } PeerStoriesView peerStoriesView = storiesViewPager.getCurrentPeerView(); if (peerStoriesView != null && !peerStoriesView.currentStory.hasSound() && peerStoriesView.currentStory.isVideo()) { - peerStoriesView.showNoSoundHint(); + peerStoriesView.showNoSoundHint(true); return; } volumeControl.onKeyDown(event.getKeyCode(), event); @@ -1754,6 +1759,9 @@ public void toggleSilentMode() { if (peerStoriesView != null) { peerStoriesView.sharedResources.setIconMuted(!soundEnabled(), true); } + if (!isInSilentMode) { + volumeControl.unmute(); + } } private void checkInSilentMode() { @@ -1839,12 +1847,10 @@ private void updateTransitionParams() { } if (transitionViewHolder.view.getParent() instanceof View) { View parent = (View) transitionViewHolder.view.getParent(); - fromX -= fromWidth / 2f; - fromY -= fromHeight / 2f; + fromX = loc[0] + transitionViewHolder.avatarImage.getCenterX() * parent.getScaleX(); + fromY = loc[1] + transitionViewHolder.avatarImage.getCenterY() * parent.getScaleY(); fromWidth *= parent.getScaleX(); fromHeight *= parent.getScaleY(); - fromX += fromWidth / 2f; - fromY += fromHeight / 2f; } animateAvatar = true; } else if (transitionViewHolder.storyImage != null) { @@ -1911,7 +1917,7 @@ public void setOnCloseListener(Runnable listener) { } public boolean isPaused() { - return isPopupVisible || isTranslating || isBulletinVisible || isCaption || isWaiting || isInTouchMode || keyboardVisible || currentDialog != null || allowTouchesByViewpager || isClosed || isRecording || progressToOpen != 1f || selfStoriesViewsOffset != 0 || isHintVisible || (isSwiping && USE_SURFACE_VIEW) || isOverlayVisible || isInTextSelectionMode || isLikesReactions; + return isPopupVisible || isTranslating || isBulletinVisible || isCaption || isWaiting || isInTouchMode || keyboardVisible || currentDialog != null || allowTouchesByViewpager || isClosed || isRecording || progressToOpen != 1f || selfStoriesViewsOffset != 0 || isHintVisible || (isSwiping && USE_SURFACE_VIEW) || isOverlayVisible || isInTextSelectionMode || isLikesReactions || progressToDismiss != 0; } public void updatePlayingMode() { @@ -1973,6 +1979,9 @@ private boolean findClickableView(FrameLayout windowView, float x, float y, bool } public boolean closeKeyboardOrEmoji() { + if (storiesViewPager == null) { + return false; + } final PeerStoriesView peerStoriesView = storiesViewPager.getCurrentPeerView(); if (peerStoriesView != null) { return peerStoriesView.closeKeyboardOrEmoji(); @@ -2204,7 +2213,7 @@ public void release() { preparedPlayers.get(i).release(null); } preparedPlayers.clear(); - MessagesController.getInstance(currentAccount).getStoriesController().pollViewsForSelfStories(false); + MessagesController.getInstance(currentAccount).getStoriesController().stopAllPollers(); if (ATTACH_TO_FRAGMENT) { lockOrientation(false); } @@ -2430,7 +2439,7 @@ public void openFor(BaseFragment fragment, RecyclerListView recyclerListView, Ch } if (messageObject.type == MessageObject.TYPE_STORY_MENTION) { TLRPC.StoryItem storyItem = messageObject.messageOwner.media.storyItem; - storyItem.dialogId = messageObject.messageOwner.media.user_id; + storyItem.dialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.media.peer); storyItem.messageId = messageObject.getId(); open(fragment.getContext(), messageObject.messageOwner.media.storyItem, StoriesListPlaceProvider.of(recyclerListView)); } @@ -2459,7 +2468,7 @@ public void didReceivedNotification(int id, int account, Object... args) { } storyItems.add(storiesList.messageObjects.get(i).storyItem); } - selfStoryViewsView.setItems(storyItems, selectedPosition); + selfStoryViewsView.setItems(storiesList.dialogId, storyItems, selectedPosition); } } } else if (id == NotificationCenter.storiesUpdated) { @@ -2469,16 +2478,17 @@ public void didReceivedNotification(int id, int account, Object... args) { return; } StoriesController storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); - ArrayList allStories = storiesListPlaceProvider.hiddedStories ? storiesController.getHiddenList() : storiesController.getDialogListStories(); + ArrayList allStories = storiesListPlaceProvider.hiddedStories ? storiesController.getHiddenList() : storiesController.getDialogListStories(); boolean changed = false; ArrayList dialogs = storiesViewPager.getDialogIds(); for (int i = 0; i < allStories.size(); i++) { - TLRPC.TL_userStories userStories = allStories.get(i); - if (storiesListPlaceProvider.onlyUnreadStories && !storiesController.hasUnreadStories(userStories.user_id)) { + TLRPC.PeerStories userStories = allStories.get(i); + long dialogId = DialogObject.getPeerDialogId(userStories.peer); + if (storiesListPlaceProvider.onlyUnreadStories && !storiesController.hasUnreadStories(dialogId)) { continue; } - if (!dialogs.contains(userStories.user_id)) { - dialogs.add(userStories.user_id); + if (!dialogs.contains(dialogId)) { + dialogs.add(dialogId); changed = true; } } @@ -2486,6 +2496,9 @@ public void didReceivedNotification(int id, int account, Object... args) { storiesViewPager.getAdapter().notifyDataSetChanged(); } } + if (selfStoryViewsView != null) { + selfStoryViewsView.selfStoriesPreviewView.update(); + } } else if (id == NotificationCenter.openArticle || id == NotificationCenter.articleClosed) { updatePlayingMode(); } @@ -2495,7 +2508,6 @@ public void saveDraft(long dialogId, TLRPC.StoryItem storyItem, CharSequence tex if (dialogId == 0 || storyItem == null) { return; } - Log.d("kek", "saveDraft" + dialogId + "_" + storyItem.id + " " + text); replyDrafts.put(draftHash(dialogId, storyItem), text); } @@ -2503,7 +2515,6 @@ public CharSequence getDraft(long dialogId, TLRPC.StoryItem storyItem) { if (dialogId == 0 || storyItem == null) { return ""; } - Log.d("kek", "getDraft " + dialogId + "_" + storyItem.id + " " + replyDrafts.get(draftHash(dialogId, storyItem), "")); return replyDrafts.get(draftHash(dialogId, storyItem), ""); } @@ -2518,6 +2529,13 @@ private long draftHash(long dialogId, TLRPC.StoryItem oldStoryItem) { return dialogId + (dialogId >> 16) + ((long) oldStoryItem.id << 16); } + public void onResume() { + PeerStoriesView peerView = getCurrentPeerView(); + if (peerView != null) { + getCurrentPeerView().updatePosition(); + } + } + public interface PlaceProvider { boolean findView(long dialogId, int messageId, int storyId, int type, TransitionViewHolder holder); @@ -2570,8 +2588,6 @@ public void clear() { } } - static int queuePointer = 0; - public class VideoPlayerHolder extends VideoPlayerHolderBase { boolean logBuffering; @@ -2597,6 +2613,9 @@ public void onRenderedFirstFrame() { } firstFrameRendered = currentPlayerScope.firstFrameRendered = true; currentPlayerScope.invalidate(); + if (paused && surfaceView != null) { + prepareStub(); + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryWidgetsImageDecorator.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryWidgetsImageDecorator.java new file mode 100644 index 00000000000..20507423e66 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryWidgetsImageDecorator.java @@ -0,0 +1,146 @@ +package org.telegram.ui.Stories; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ImageReceiver; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.Reactions.ReactionImageHolder; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; + +import java.util.ArrayList; + +public class StoryWidgetsImageDecorator extends ImageReceiver.Decorator { + + ArrayList drawingObjects; + public StoryWidgetsImageDecorator(TLRPC.StoryItem storyItem) { + for (int i = 0; i < storyItem.media_areas.size(); i++) { + if (storyItem.media_areas.get(i) instanceof TLRPC.TL_mediaAreaSuggestedReaction) { + if (drawingObjects == null) { + drawingObjects = new ArrayList<>(); + } + drawingObjects.add(new ReactionWidget((TLRPC.TL_mediaAreaSuggestedReaction) storyItem.media_areas.get(i))); + } + } + } + + float imageX; + float imageY; + float imageW; + float imageH; + + + @Override + protected void onDraw(Canvas canvas, ImageReceiver imageReceiver) { + if (drawingObjects == null) { + return; + } + float alpha = imageReceiver.getAlpha(); + float cx = imageReceiver.getCenterX(); + float cy = imageReceiver.getCenterY(); + imageW = imageReceiver.getImageWidth(); + imageH = imageW * 16 / 9f; + imageX = cx - imageW / 2f; + imageY = cy - imageH / 2f; + + canvas.save(); + canvas.clipRect(imageReceiver.getImageX(), imageReceiver.getImageY(), imageReceiver.getImageX2(), imageReceiver.getImageY2()); + for (int i = 0; i < drawingObjects.size(); i++) { + drawingObjects.get(i).draw(canvas, imageReceiver, alpha); + } + canvas.restore(); + } + + @Override + public void onAttachedToWindow(ImageReceiver imageReceiver) { + if (drawingObjects == null) { + return; + } + for (int i = 0; i < drawingObjects.size(); i++) { + drawingObjects.get(i).setParent(imageReceiver.getParentView()); + drawingObjects.get(i).onAttachedToWindow(true); + } + } + + @Override + public void onDetachedFromWidnow() { + if (drawingObjects == null) { + return; + } + for (int i = 0; i < drawingObjects.size(); i++) { + drawingObjects.get(i).onAttachedToWindow(false); + } + } + + public static abstract class DrawingObject { + public abstract void draw(Canvas canvas, ImageReceiver imageReceiver, float alpha); + public abstract void onAttachedToWindow(boolean attached); + public abstract void setParent(View parentView); + } + + public class ReactionWidget extends DrawingObject { + + StoryReactionWidgetBackground storyReactionWidgetBackground = new StoryReactionWidgetBackground(null); + + TLRPC.TL_mediaAreaSuggestedReaction mediaArea; + ReactionImageHolder imageHolder = new ReactionImageHolder(null); + + public ReactionWidget(TLRPC.TL_mediaAreaSuggestedReaction mediaArea) { + this.mediaArea = mediaArea; + if (mediaArea.flipped) { + storyReactionWidgetBackground.setMirror(true, false); + } + if (mediaArea.dark) { + storyReactionWidgetBackground.nextStyle(); + } + imageHolder.setStatic(); + imageHolder.setVisibleReaction(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(mediaArea.reaction)); + } + + public void draw(Canvas canvas, ImageReceiver imageReceiver, float alpha) { + float x = (float) (imageX + imageW * mediaArea.coordinates.x / 100); + float y = (float) (imageY + imageH * mediaArea.coordinates.y / 100); + float w = (float) (imageW * mediaArea.coordinates.w / 100); + float h = (float) (imageH * mediaArea.coordinates.h / 100); + storyReactionWidgetBackground.setBounds( + (int) (x - w / 2f), + (int) (y - h / 2f), + (int) (x + w / 2f), + (int) (y + h / 2f) + ); + storyReactionWidgetBackground.setAlpha((int) (255 * alpha)); + + canvas.save(); + if (mediaArea.coordinates.rotation != 0) { + canvas.rotate((float) mediaArea.coordinates.rotation, x, y); + } + float imageSize = storyReactionWidgetBackground.getBounds().height() * 0.61f; + AndroidUtilities.rectTmp2.set( + (int) (storyReactionWidgetBackground.getBounds().centerX() - imageSize / 2f), + (int) (storyReactionWidgetBackground.getBounds().centerY() - imageSize / 2f), + (int) (storyReactionWidgetBackground.getBounds().centerX() + imageSize / 2f), + (int) (storyReactionWidgetBackground.getBounds().centerY() + imageSize / 2f) + ); + + storyReactionWidgetBackground.updateShadowLayer(1f); + storyReactionWidgetBackground.draw(canvas); + imageHolder.setBounds(AndroidUtilities.rectTmp2); + imageHolder.setAlpha(alpha); + imageHolder.setColor(storyReactionWidgetBackground.isDarkStyle() ? Color.WHITE : Color.BLACK); + imageHolder.draw(canvas); + canvas.restore(); + + } + + public void onAttachedToWindow(boolean attached) { + imageHolder.onAttachedToWindow(attached); + } + + @Override + public void setParent(View parentView) { + imageHolder.setParent(parentView); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/UserListPoller.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/UserListPoller.java index 7f00900d0c9..7edc237b71c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/UserListPoller.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/UserListPoller.java @@ -50,9 +50,9 @@ public void run() { if (!collectedDialogIds.isEmpty()) { ArrayList dialogsFinal = new ArrayList<>(collectedDialogIds); collectedDialogIds.clear(); - TLRPC.TL_users_getStoriesMaxIDs request = new TLRPC.TL_users_getStoriesMaxIDs(); + TLRPC.TL_stories_getPeerMaxIDs request = new TLRPC.TL_stories_getPeerMaxIDs(); for (int i = 0; i < dialogsFinal.size(); i++) { - request.id.add(MessagesController.getInstance(currentAccount).getInputUser(dialogsFinal.get(i))); + request.id.add(MessagesController.getInstance(currentAccount).getInputPeer(dialogsFinal.get(i))); } ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (response != null) { @@ -60,19 +60,33 @@ public void run() { ArrayList usersToUpdate = new ArrayList<>(); ArrayList chatsToUpdate = new ArrayList<>(); for (int i = 0; i < vector.objects.size(); i++) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogsFinal.get(i)); - if (user == null) { - continue; - } - user.stories_max_id = (int) vector.objects.get(i); - if (user.stories_max_id != 0) { - user.flags2 |= 32; + if (dialogsFinal.get(i) > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogsFinal.get(i)); + if (user == null) { + continue; + } + user.stories_max_id = (int) vector.objects.get(i); + if (user.stories_max_id != 0) { + user.flags2 |= 32; + } else { + user.flags2 &= ~32; + } + usersToUpdate.add(user); } else { - user.flags2 &= ~32; + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(dialogsFinal.get(i)); + if (chat == null) { + continue; + } + chat.stories_max_id = (int) vector.objects.get(i); + if (chat.stories_max_id != 0) { + chat.flags2 |= 16; + } else { + chat.flags2 &= ~16; + } + chatsToUpdate.add(chat); } - usersToUpdate.add(user); } - MessagesStorage.getInstance(currentAccount).putUsersAndChats(usersToUpdate, null, true, true); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(usersToUpdate, chatsToUpdate, true, true); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, 0); } })); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ViewsForSelfStoriesRequester.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ViewsForPeerStoriesRequester.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/ui/Stories/ViewsForSelfStoriesRequester.java rename to TMessagesProj/src/main/java/org/telegram/ui/Stories/ViewsForPeerStoriesRequester.java index d501ed4c72e..ab35706413c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ViewsForSelfStoriesRequester.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ViewsForPeerStoriesRequester.java @@ -1,7 +1,5 @@ package org.telegram.ui.Stories; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; @@ -9,21 +7,21 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; -//TODO stories -public class ViewsForSelfStoriesRequester { +public class ViewsForPeerStoriesRequester { - StoriesController storiesController; - int currentAccount; + final StoriesController storiesController; + final int currentAccount; + final long dialogId; int currentReqId; boolean isRunning; - long time; - final Runnable scheduleRequestRunnuble = () -> requestInternal(); + final Runnable scheduleRequestRunnable = () -> requestInternal(); - public ViewsForSelfStoriesRequester(StoriesController storiesController, int currentAccount) { + public ViewsForPeerStoriesRequester(StoriesController storiesController, long dialogId, int currentAccount) { this.currentAccount = currentAccount; this.storiesController = storiesController; + this.dialogId = dialogId; } public void start(boolean start) { @@ -33,14 +31,14 @@ public void start(boolean start) { } } else { isRunning = false; - AndroidUtilities.cancelRunOnUIThread(scheduleRequestRunnuble); + AndroidUtilities.cancelRunOnUIThread(scheduleRequestRunnable); ConnectionsManager.getInstance(currentAccount).cancelRequest(currentReqId, false); currentReqId = 0; } } private boolean requestInternal() { - TLRPC.TL_userStories stories = storiesController.getStories(UserConfig.getInstance(currentAccount).getClientUserId()); + TLRPC.PeerStories stories = storiesController.getStories(dialogId); if (stories == null || stories.stories.isEmpty() || currentReqId != 0) { return false; } @@ -48,11 +46,11 @@ private boolean requestInternal() { for (int i = 0; i < stories.stories.size(); i++) { req.id.add(stories.stories.get(i).id); } - + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); currentReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (response != null) { - TLRPC.TL_userStories currentStories = storiesController.getStories(UserConfig.getInstance(currentAccount).getClientUserId()); + TLRPC.PeerStories currentStories = storiesController.getStories(dialogId); if (currentStories == null || currentStories.stories.isEmpty()) { currentReqId = 0; isRunning = false; @@ -73,8 +71,8 @@ private boolean requestInternal() { } currentReqId = 0; if (isRunning) { - AndroidUtilities.cancelRunOnUIThread(scheduleRequestRunnuble); - AndroidUtilities.runOnUIThread(scheduleRequestRunnuble, 10_000); + AndroidUtilities.cancelRunOnUIThread(scheduleRequestRunnable); + AndroidUtilities.runOnUIThread(scheduleRequestRunnable, 10_000); } })); return true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java index d113056707c..3631309cdca 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java @@ -19,6 +19,7 @@ import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; @@ -79,6 +80,7 @@ public class CaptionContainerView extends FrameLayout { private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); public final EditTextEmoji editText; + private Drawable applyButtonCheck; private CombinedDrawable applyButtonDrawable; public ImageView applyButton; public FrameLayout limitTextContainer; @@ -287,7 +289,9 @@ public void afterTextChanged(Editable s) { applyButton = new BounceableImageView(context); ScaleStateListAnimator.apply(applyButton, 0.05f, 1.25f); - applyButtonDrawable = new CombinedDrawable(Theme.createCircleDrawable(AndroidUtilities.dp(16), Theme.getColor(Theme.key_dialogFloatingButton, resourcesProvider)), context.getResources().getDrawable(R.drawable.input_done).mutate(), 0, AndroidUtilities.dp(1)); + applyButtonCheck = context.getResources().getDrawable(R.drawable.input_done).mutate(); + applyButtonCheck.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingIcon), PorterDuff.Mode.SRC_IN)); + applyButtonDrawable = new CombinedDrawable(Theme.createCircleDrawable(AndroidUtilities.dp(16), Theme.getColor(Theme.key_dialogFloatingButton, resourcesProvider)), applyButtonCheck, 0, AndroidUtilities.dp(1)); applyButtonDrawable.setCustomSize(AndroidUtilities.dp(32), AndroidUtilities.dp(32)); applyButton.setImageDrawable(applyButtonDrawable); applyButton.setScaleType(ImageView.ScaleType.CENTER); @@ -364,7 +368,7 @@ public boolean dispatchTouchEvent(MotionEvent ev) { } } editText.getEditText().requestFocus(); - editText.getEditText().setSelection(editText.getEditText().length(), editText.getEditText().length()); +// editText.getEditText().setSelection(editText.getEditText().length(), editText.getEditText().length()); editText.openKeyboard(); editText.getEditText().setScrollY(0); return true; @@ -632,22 +636,22 @@ public void onAnimationEnd(Animator animation) { ignoreDraw = true; drawBlurBitmap(blurBitmap, 12); ignoreDraw = false; - if (blurBitmap != null && blurBitmap.isRecycled()) { - blurBitmap = null; - return; - } - blurBitmapShader = new BitmapShader(blurBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); - if (blurBitmapMatrix == null) { - blurBitmapMatrix = new Matrix(); + if (blurBitmap != null && !blurBitmap.isRecycled()) { + blurBitmapShader = new BitmapShader(blurBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (blurBitmapMatrix == null) { + blurBitmapMatrix = new Matrix(); + } else { + blurBitmapMatrix.reset(); + } + blurBitmapShader.setLocalMatrix(blurBitmapMatrix); + if (blurPaint == null) { + blurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + blurPaint.setColor(0xffffffff); + } + blurPaint.setShader(blurBitmapShader); } else { - blurBitmapMatrix.reset(); - } - blurBitmapShader.setLocalMatrix(blurBitmapMatrix); - if (blurPaint == null) { - blurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); - blurPaint.setColor(0xffffffff); + blurBitmap = null; } - blurPaint.setShader(blurBitmapShader); } } @@ -957,6 +961,7 @@ public int getSelectionLength() { public void updateColors(Theme.ResourcesProvider resourcesProvider) { this.resourcesProvider = resourcesProvider; + applyButtonCheck.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingIcon), PorterDuff.Mode.SRC_IN)); applyButtonDrawable.setBackgroundDrawable(Theme.createCircleDrawable(AndroidUtilities.dp(16), Theme.getColor(Theme.key_dialogFloatingButton, resourcesProvider))); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java index 15b10cb9b03..6b3f16f6312 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java @@ -495,6 +495,8 @@ public static class StoryDraft { public float audioLeft, audioRight = 1; public float audioVolume = 1; + public TLRPC.InputPeer peer; + public StoryDraft(@NonNull StoryEntry entry) { this.id = entry.draftId; this.date = entry.draftDate; @@ -541,6 +543,8 @@ public StoryDraft(@NonNull StoryEntry entry) { this.audioLeft = entry.audioLeft; this.audioRight = entry.audioRight; this.audioVolume = entry.audioVolume; + + this.peer = entry.peer; } public StoryEntry toEntry() { @@ -624,6 +628,7 @@ public StoryEntry toEntry() { entry.audioLeft = audioLeft; entry.audioRight = audioRight; entry.audioVolume = audioVolume; + entry.peer = peer; return entry; } @@ -732,6 +737,11 @@ public void toStream(AbstractSerializedData stream) { stream.writeFloat(audioRight); stream.writeFloat(audioVolume); } + if (peer != null) { + peer.serializeToStream(stream); + } else { + new TLRPC.TL_inputPeerSelf().serializeToStream(stream); + } } public int getObjectSize() { @@ -906,6 +916,9 @@ public StoryDraft(@NonNull AbstractSerializedData stream, boolean exception) { audioVolume = stream.readFloat(exception); } } + if (stream.remaining() > 0) { + peer = TLRPC.InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java index 994ee0d5080..8b957ff466c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java @@ -96,6 +96,7 @@ import org.telegram.ui.Components.EmojiView; import org.telegram.ui.Components.ExtendedGridLayoutManager; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Paint.Views.ReactionWidgetEntityView; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.Reactions.ReactionImageHolder; @@ -115,6 +116,8 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -1134,12 +1137,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int view = new NoEmojiView(getContext(), currentType == PAGE_TYPE_EMOJI); } else if (viewType == VIEW_TYPE_WIDGETS) { StoryWidgetsCell cell = new StoryWidgetsCell(getContext()); - cell.setOnButtonClickListener(id -> { - if (canShowWidget(id)) { - onWidgetSelected.run(id); - dismiss(); - } - }); + cell.setOnButtonClickListener(EmojiBottomSheet.this::onWidgetClick); view = cell; } else { view = new EmojiListView.EmojiImageView(getContext(), listView); @@ -1271,8 +1269,12 @@ public boolean canShowWidget(Integer id) { return true; } + public boolean canClickWidget(Integer id) { + return true; + } + public boolean hasWidgets() { - return canShowWidget(WIDGET_LOCATION) || canShowWidget(WIDGET_PHOTO); + return canShowWidget(WIDGET_LOCATION) || canShowWidget(WIDGET_AUDIO) || canShowWidget(WIDGET_PHOTO) || canShowWidget(WIDGET_REACTION); } @Override @@ -1294,6 +1296,22 @@ public void didReceivedNotification(int id, int account, Object... args) { } } + private void onWidgetClick(int id) { + if (canClickWidget(id)) { + if (id == WIDGET_AUDIO) { + if (!checkAudioPermission(() -> onWidgetClick(id))) { + return; + } + } + onWidgetSelected.run(id); + dismiss(); + } + } + + protected boolean checkAudioPermission(Runnable granted) { + return true; + } + private final ViewPagerFixed viewPager; private final TabsView tabsView; private float maxPadding = -1; @@ -2565,7 +2583,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } public static final int WIDGET_LOCATION = 0; + public static final int WIDGET_AUDIO = 1; public static final int WIDGET_PHOTO = 2; + public static final int WIDGET_REACTION = 3; private class StoryWidgetsCell extends View { @@ -2582,12 +2602,15 @@ private class StoryWidgetsCell extends View { public StoryWidgetsCell(Context context) { super(context); - setPadding(dp(0), 0, dp(0), 0); - + setPadding(0, 0, 0, 0); if (canShowWidget(WIDGET_LOCATION)) widgets.add(new Button(WIDGET_LOCATION, R.drawable.map_pin3, LocaleController.getString(R.string.StoryWidgetLocation))); + if (canShowWidget(WIDGET_AUDIO)) + widgets.add(new Button(WIDGET_AUDIO, R.drawable.filled_widget_music, LocaleController.getString(R.string.StoryWidgetAudio))); if (canShowWidget(WIDGET_PHOTO)) widgets.add(new Button(WIDGET_PHOTO, R.drawable.files_gallery, LocaleController.getString(R.string.StoryWidgetPhoto))); + if (canShowWidget(WIDGET_REACTION)) + widgets.add(new ReactionWidget()); } private abstract class BaseWidget { @@ -2644,6 +2667,109 @@ public void draw(Canvas canvas, float left, float top) { } } + private class ReactionWidget extends BaseWidget { + + ReactionImageHolder reactionHolder = new ReactionImageHolder(StoryWidgetsCell.this); + ReactionImageHolder nextReactionHolder = new ReactionImageHolder(StoryWidgetsCell.this); + int currentIndex; + AnimatedFloat progressToNext = new AnimatedFloat(StoryWidgetsCell.this); + Timer timeTimer; + + StoryReactionWidgetBackground background = new StoryReactionWidgetBackground(StoryWidgetsCell.this); + ArrayList visibleReactions = new ArrayList<>(); + ReactionWidget() { + id = WIDGET_REACTION; + width = AndroidUtilities.dp(44); + height = AndroidUtilities.dp(36); + + List availableReactions = MediaDataController.getInstance(currentAccount).getReactionsList(); + for (int i = 0; i < Math.min(availableReactions.size(), 8); i++) { + visibleReactions.add(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(availableReactions.get(i))); + } + Collections.sort(visibleReactions, (o1, o2) -> { + int i1 = o1.emojicon != null && o1.emojicon.equals("❤") ? -1 : 0; + int i2 = o2.emojicon != null && o2.emojicon.equals("❤") ? -1 : 0; + return i1 - i2; + }); + if (!visibleReactions.isEmpty()) { + reactionHolder.setVisibleReaction(visibleReactions.get(currentIndex)); + } + + progressToNext.set(1, true); + } + + @Override + void draw(Canvas canvas, float left, float top) { + top -= AndroidUtilities.dp(4); + bounds.set((int) left, (int) top, (int) (left + width), (int) (top + width)); + final float scale = bounce.getScale(.05f); + canvas.save(); + canvas.scale(scale, scale, bounds.centerX(), bounds.centerY()); + background.setBounds((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom); + background.draw(canvas); + float imageSize = AndroidUtilities.dp(30); + AndroidUtilities.rectTmp2.set( + (int) (bounds.centerX() - imageSize / 2f), + (int) (bounds.centerY() - imageSize / 2f), + (int) (bounds.centerX() + imageSize / 2f), + (int) (bounds.centerY() + imageSize / 2f) + ); + float progress = progressToNext.set(1); + nextReactionHolder.setBounds(AndroidUtilities.rectTmp2); + reactionHolder.setBounds(AndroidUtilities.rectTmp2); + if (progress == 1) { + reactionHolder.draw(canvas); + } else { + canvas.save(); + canvas.scale(1f - progress, 1f - progress, bounds.centerX(), bounds.top); + nextReactionHolder.setAlpha(1f - progress); + nextReactionHolder.draw(canvas); + canvas.restore(); + + canvas.save(); + canvas.scale(progress, progress, bounds.centerX(), bounds.bottom); + reactionHolder.setAlpha(progress); + reactionHolder.draw(canvas); + canvas.restore(); + } + canvas.restore(); + } + + @Override + public void onAttachToWindow(boolean attached) { + super.onAttachToWindow(attached); + reactionHolder.onAttachedToWindow(attached); + nextReactionHolder.onAttachedToWindow(attached); + if (timeTimer != null) { + timeTimer.cancel(); + timeTimer = null; + } + if (attached) { + timeTimer = new Timer(); + timeTimer.schedule(new TimerTask() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(() -> { + if (visibleReactions.isEmpty()) { + return; + } + progressToNext.set(0, true); + currentIndex++; + if (currentIndex > visibleReactions.size() - 1) { + currentIndex = 0; + } + ReactionImageHolder k = nextReactionHolder; + nextReactionHolder.setVisibleReaction(visibleReactions.get(currentIndex)); + nextReactionHolder = reactionHolder; + reactionHolder = k; + invalidate(); + }); + } + }, 2000, 2000); + } + } + } + float[] lineWidths; @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/KeyboardNotifier.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/KeyboardNotifier.java index e735d2a47f8..178964bbae9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/KeyboardNotifier.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/KeyboardNotifier.java @@ -76,11 +76,8 @@ public boolean keyboardVisible() { } public void ignore(boolean ignore) { - final boolean update = ignoring && ignore; ignoring = ignore; - if (update) { - update(); - } + update(); } public void fire() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java index 02a0ba6bf8a..c0866846343 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java @@ -1,5 +1,7 @@ package org.telegram.ui.Stories.recorder; +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; import static org.telegram.messenger.AndroidUtilities.lerp; import android.animation.Animator; @@ -23,6 +25,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.SweepGradient; +import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.location.Address; import android.location.Geocoder; @@ -32,6 +35,7 @@ import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; +import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.util.TypedValue; @@ -58,6 +62,7 @@ import com.google.android.gms.vision.Frame; import com.google.android.gms.vision.face.Face; import com.google.android.gms.vision.face.FaceDetector; +import com.google.zxing.common.detector.MathUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; @@ -88,6 +93,7 @@ import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.BlurringShader; import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.ChatActivityEnterViewAnimatedIconView; import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -115,10 +121,14 @@ import org.telegram.ui.Components.Paint.Views.PaintTypefaceListView; import org.telegram.ui.Components.Paint.Views.PaintWeightChooserView; import org.telegram.ui.Components.Paint.Views.PhotoView; +import org.telegram.ui.Components.Paint.Views.ReactionWidgetEntityView; import org.telegram.ui.Components.Paint.Views.StickerView; import org.telegram.ui.Components.Paint.Views.TextPaintView; import org.telegram.ui.Components.Point; import org.telegram.ui.Components.RLottieDrawable; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; +import org.telegram.ui.Components.Reactions.ReactionsUtils; +import org.telegram.ui.Components.ReactionsContainerLayout; import org.telegram.ui.Components.Size; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.SizeNotifierFrameLayoutPhoto; @@ -237,7 +247,7 @@ public void set(float val) { private Theme.ResourcesProvider resourcesProvider; private ActionBarPopupWindow popupWindow; - private ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout; + private PopupWindowLayout popupLayout; private Rect popupRect; private Runnable onDoneButtonClickedListener; @@ -255,6 +265,11 @@ public void set(float val) { private boolean fileFromGallery; private File file; private boolean isVideo; + public ReactionsContainerLayout reactionLayout; + ReactionWidgetEntityView reactionForEntity; + private float reactionShowProgress; + private boolean reactionLayoutShowing; + private boolean invalidateReactionPosition; private BlurringShader.BlurManager blurManager; @SuppressLint("NotifyDataSetChanged") @@ -463,6 +478,7 @@ public void onEntityDeselect() { dismiss(); enteredThroughText = false; } + showReactionsLayout(false); } }) { Paint linePaint = new Paint(); @@ -472,7 +488,7 @@ public void onEntityDeselect() { { setWillNotDraw(false); - linePaint.setStrokeWidth(AndroidUtilities.dp(2)); + linePaint.setStrokeWidth(dp(2)); linePaint.setStyle(Paint.Style.STROKE); linePaint.setColor(Color.WHITE); } @@ -519,11 +535,11 @@ protected void onDraw(Canvas canvas) { linePaint.setAlpha((int) (stickyYAlpha * 0xFF)); float y; if (lastStickyY == EntityView.STICKY_START) { - y = AndroidUtilities.dp(EntityView.STICKY_PADDING_Y_DP); + y = dp(EntityView.STICKY_PADDING_Y_DP); } else if (lastStickyY == EntityView.STICKY_CENTER) { y = getMeasuredHeight() / 2f; } else { - y = getMeasuredHeight() - AndroidUtilities.dp(EntityView.STICKY_PADDING_Y_DP); + y = getMeasuredHeight() - dp(EntityView.STICKY_PADDING_Y_DP); } canvas.drawLine(0, y, getMeasuredWidth(), y, linePaint); } @@ -531,11 +547,11 @@ protected void onDraw(Canvas canvas) { linePaint.setAlpha((int) (stickyXAlpha * 0xFF)); float x; if (lastStickyX == EntityView.STICKY_START) { - x = AndroidUtilities.dp(EntityView.STICKY_PADDING_X_DP); + x = dp(EntityView.STICKY_PADDING_X_DP); } else if (lastStickyX == EntityView.STICKY_CENTER) { x = getMeasuredWidth() / 2f; } else { - x = getMeasuredWidth() - AndroidUtilities.dp(EntityView.STICKY_PADDING_X_DP); + x = getMeasuredWidth() - dp(EntityView.STICKY_PADDING_X_DP); } canvas.drawLine(x, 0, x, getMeasuredHeight(), linePaint); } @@ -572,13 +588,13 @@ public boolean onTouchEvent(MotionEvent event) { // addView(selectionContainerView); topLayout = new FrameLayout(context); - topLayout.setPadding(AndroidUtilities.dp(4), AndroidUtilities.dp(12), AndroidUtilities.dp(4), AndroidUtilities.dp(12)); + topLayout.setPadding(dp(4), dp(12), dp(4), dp(12)); topLayout.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int [] {0x40000000, 0x00000000} )); addView(topLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); undoButton = new ImageView(context); undoButton.setImageResource(R.drawable.photo_undo2); - undoButton.setPadding(AndroidUtilities.dp(3), AndroidUtilities.dp(3), AndroidUtilities.dp(3), AndroidUtilities.dp(3)); + undoButton.setPadding(dp(3), dp(3), dp(3), dp(3)); undoButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); undoButton.setOnClickListener(v -> { if (renderView != null && renderView.getCurrentBrush() instanceof Brush.Shape) { @@ -596,7 +612,7 @@ public boolean onTouchEvent(MotionEvent event) { zoomOutButton = new LinearLayout(context); zoomOutButton.setOrientation(LinearLayout.HORIZONTAL); zoomOutButton.setBackground(Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); - zoomOutButton.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + zoomOutButton.setPadding(dp(8), 0, dp(8), 0); zoomOutText = new TextView(context); zoomOutText.setTextColor(Color.WHITE); zoomOutText.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); @@ -614,7 +630,7 @@ public boolean onTouchEvent(MotionEvent event) { undoAllButton = new TextView(context); undoAllButton.setBackground(Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); - undoAllButton.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + undoAllButton.setPadding(dp(8), 0, dp(8), 0); undoAllButton.setText(LocaleController.getString(R.string.PhotoEditorClearAll)); undoAllButton.setGravity(Gravity.CENTER_VERTICAL); undoAllButton.setTextColor(Color.WHITE); @@ -627,7 +643,7 @@ public boolean onTouchEvent(MotionEvent event) { cancelTextButton = new TextView(context); cancelTextButton.setBackground(Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); cancelTextButton.setText(LocaleController.getString(R.string.Clear)); - cancelTextButton.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + cancelTextButton.setPadding(dp(8), 0, dp(8), 0); cancelTextButton.setGravity(Gravity.CENTER_VERTICAL); cancelTextButton.setTextColor(Color.WHITE); cancelTextButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); @@ -649,7 +665,7 @@ public boolean onTouchEvent(MotionEvent event) { doneTextButton = new TextView(context); doneTextButton.setBackground(Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); doneTextButton.setText(LocaleController.getString(R.string.Done)); - doneTextButton.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + doneTextButton.setPadding(dp(8), 0, dp(8), 0); doneTextButton.setGravity(Gravity.CENTER_VERTICAL); doneTextButton.setTextColor(Color.WHITE); doneTextButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); @@ -668,7 +684,7 @@ public boolean onTouchEvent(MotionEvent event) { { setWillNotDraw(false); colorPickerRainbowPaint.setStyle(Paint.Style.STROKE); - colorPickerRainbowPaint.setStrokeWidth(AndroidUtilities.dp(2)); + colorPickerRainbowPaint.setStrokeWidth(dp(2)); } private void checkRainbow(float cx, float cy) { @@ -709,7 +725,7 @@ protected void onDraw(Canvas canvas) { lerp(barView.getRight(), colorsListView.getRight(), toolsTransformProgress), lerp(barView.getBottom(), colorsListView.getBottom(), toolsTransformProgress) ); - final float radius = lerp(AndroidUtilities.dp(32), AndroidUtilities.dp(24), toolsTransformProgress); + final float radius = lerp(dp(32), dp(24), toolsTransformProgress); canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, toolsPaint); if (barView != null && barView.getChildCount() >= 1 && toolsTransformProgress != 1f) { @@ -745,10 +761,10 @@ protected void onDraw(Canvas canvas) { } checkRainbow(cx, cy); - float rad = Math.min(childWidth, childHeight) / 2f - AndroidUtilities.dp(0.5f); + float rad = Math.min(childWidth, childHeight) / 2f - dp(0.5f); if (colorsListView != null && colorsListView.getChildCount() > 0) { View animateToView = colorsListView.getChildAt(0); - rad = lerp(rad, Math.min(animateToView.getWidth() - animateToView.getPaddingLeft() - animateToView.getPaddingRight(), animateToView.getHeight() - animateToView.getPaddingTop() - animateToView.getPaddingBottom()) / 2f - AndroidUtilities.dp(2f), toolsTransformProgress); + rad = lerp(rad, Math.min(animateToView.getWidth() - animateToView.getPaddingLeft() - animateToView.getPaddingRight(), animateToView.getHeight() - animateToView.getPaddingTop() - animateToView.getPaddingBottom()) / 2f - dp(2f), toolsTransformProgress); } AndroidUtilities.rectTmp.set(cx - rad, cy - rad, cx + rad, cy + rad); canvas.drawArc(AndroidUtilities.rectTmp, 0, 360, false, colorPickerRainbowPaint); @@ -758,30 +774,30 @@ protected void onDraw(Canvas canvas) { colorSwatchOutlinePaint.setColor(colorSwatch.color); colorSwatchOutlinePaint.setAlpha((int) (0xFF * child.getAlpha())); - float rad2 = rad - AndroidUtilities.dp(3f); + float rad2 = rad - dp(3f); PaintColorsListView.drawColorCircle(canvas, cx, cy, rad2, colorSwatchPaint.getColor()); colorSwatchOutlinePaint.setAlpha((int) (colorSwatchOutlinePaint.getAlpha() * toolsTransformProgress * child.getAlpha())); - canvas.drawCircle(cx, cy, rad - (AndroidUtilities.dp(3f) + colorSwatchOutlinePaint.getStrokeWidth()) * (1f - toolsTransformProgress), colorSwatchOutlinePaint); + canvas.drawCircle(cx, cy, rad - (dp(3f) + colorSwatchOutlinePaint.getStrokeWidth()) * (1f - toolsTransformProgress), colorSwatchOutlinePaint); } canvas.restore(); } } }; - bottomLayout.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), 0); + bottomLayout.setPadding(dp(8), dp(8), dp(8), 0); bottomLayout.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int [] {0x00000000, 0x80000000} )); addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 44 + 60, Gravity.BOTTOM)); paintToolsView = new PaintToolsView(context, blurManager != null); - paintToolsView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); + paintToolsView.setPadding(dp(16), 0, dp(16), 0); paintToolsView.setDelegate(this); // paintToolsView.setSelectedIndex(MathUtils.clamp(palette.getCurrentBrush(), 0, Brush.BRUSHES_LIST.size()) + 1); paintToolsView.setSelectedIndex(1); bottomLayout.addView(paintToolsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); textOptionsView = new PaintTextOptionsView(context); - textOptionsView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(8), 0); + textOptionsView.setPadding(dp(16), 0, dp(8), 0); textOptionsView.setVisibility(GONE); textOptionsView.setDelegate(this); post(() -> textOptionsView.setTypeface(PersistColorPalette.getInstance(currentAccount).getCurrentTypeface())); @@ -816,7 +832,7 @@ protected void onDraw(Canvas canvas) { lerp(AndroidUtilities.rectTmp.right, typefaceListView.getRight(), typefaceMenuTransformProgress), lerp(yOffset + AndroidUtilities.rectTmp.bottom, typefaceListView.getBottom() - typefaceListView.getTranslationY(), typefaceMenuTransformProgress) ); - float rad = AndroidUtilities.dp(lerp(32, 16, typefaceMenuTransformProgress)); + float rad = dp(lerp(32, 16, typefaceMenuTransformProgress)); int alpha = typefaceMenuBackgroundPaint.getAlpha(); typefaceMenuBackgroundPaint.setAlpha((int) (alpha * typefaceMenuTransformProgress)); @@ -858,7 +874,7 @@ public void draw(Canvas c) { ); path.rewind(); - path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(32), AndroidUtilities.dp(32), Path.Direction.CW); + path.addRoundRect(AndroidUtilities.rectTmp, dp(32), dp(32), Path.Direction.CW); c.save(); c.clipPath(path); @@ -877,7 +893,7 @@ public void draw(Canvas c) { setupTabsLayout(context); cancelButton = new PaintCancelView(context); - cancelButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + cancelButton.setPadding(dp(8), dp(8), dp(8), dp(8)); cancelButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); bottomLayout.addView(cancelButton, LayoutHelper.createFrame(32, 32, Gravity.BOTTOM | Gravity.LEFT, 12, 0, 0, 4)); cancelButton.setOnClickListener(e -> { @@ -900,7 +916,7 @@ public void draw(Canvas c) { }); doneButton = new PaintDoneView(context); - doneButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + doneButton.setPadding(dp(8), dp(8), dp(8), dp(8)); doneButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); doneButton.setOnClickListener(v -> { if (isColorListShown) { @@ -989,7 +1005,7 @@ public void onColorSelected(int color) { addView(pipetteContainerLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); colorSwatchOutlinePaint.setStyle(Paint.Style.STROKE); - colorSwatchOutlinePaint.setStrokeWidth(AndroidUtilities.dp(2)); + colorSwatchOutlinePaint.setStrokeWidth(dp(2)); setCurrentSwatch(colorSwatch, true); // onBrushSelected(Brush.BRUSHES_LIST.get(MathUtils.clamp(palette.getCurrentBrush(), 0, Brush.BRUSHES_LIST.size()))); @@ -997,7 +1013,7 @@ public void onColorSelected(int color) { updateColors(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - setSystemGestureExclusionRects(Arrays.asList(new Rect(0, (int) (AndroidUtilities.displaySize.y * .35f), AndroidUtilities.dp(100), (int) (AndroidUtilities.displaySize.y * .65)))); + setSystemGestureExclusionRects(Arrays.asList(new Rect(0, (int) (AndroidUtilities.displaySize.y * .35f), dp(100), (int) (AndroidUtilities.displaySize.y * .65)))); } keyboardNotifier = new KeyboardNotifier(parent, keyboardHeight -> { @@ -1012,8 +1028,8 @@ public void onColorSelected(int color) { } keyboardAnimator = new AnimatorSet(); final ArrayList animators = new ArrayList<>(); - animators.add(ObjectAnimator.ofFloat(weightChooserView, View.TRANSLATION_Y, keyboardHeight > 0 ? Math.min(0, -keyboardHeight / 2f - AndroidUtilities.dp(8)) : 0)); - animators.add(ObjectAnimator.ofFloat(bottomLayout, View.TRANSLATION_Y, (keyboardHeight > 0 ? Math.min(0, -keyboardHeight + AndroidUtilities.dp(40)) : 0)/* - (isColorListShown && keyboardVisible ? AndroidUtilities.dp(39) : 0)*/)); + animators.add(ObjectAnimator.ofFloat(weightChooserView, View.TRANSLATION_Y, keyboardHeight > 0 ? Math.min(0, -keyboardHeight / 2f - dp(8)) : 0)); + animators.add(ObjectAnimator.ofFloat(bottomLayout, View.TRANSLATION_Y, (keyboardHeight > 0 ? Math.min(0, -keyboardHeight + dp(40)) : 0)/* - (isColorListShown && keyboardVisible ? AndroidUtilities.dp(39) : 0)*/)); animators.add(ObjectAnimator.ofFloat(tabsLayout, View.ALPHA, keyboardVisible ? 0f : 1f)); animators.add(ObjectAnimator.ofFloat(doneButton, View.ALPHA, keyboardVisible && !isColorListShown ? 0f : 1f)); animators.add(ObjectAnimator.ofFloat(cancelButton, View.ALPHA, keyboardVisible && !isColorListShown ? 0f : 1f)); @@ -1109,7 +1125,7 @@ private LocationView createLocationSticker(TLRPC.MessageMedia location, TLRPC.Me Size paintingSize = getPaintingSize(); Point position = startPositionRelativeToEntity(null); float w = entitiesView.getMeasuredWidth() <= 0 ? this.w : entitiesView.getMeasuredWidth(); - int maxWidth = (int) w - AndroidUtilities.dp(14 + 26 + 18); + int maxWidth = (int) w - dp(14 + 26 + 18); LocationView view = new LocationView(getContext(), position, currentAccount, location, mediaArea, w / 240f, maxWidth, 3, colorSwatch == null ? 0xFFFFFFFF : colorSwatch.color); if (position.x == entitiesView.getMeasuredWidth() / 2f) { view.setStickyX(EntityView.STICKY_CENTER); @@ -1145,7 +1161,7 @@ private TextPaintView createText(boolean select) { view.setStickyY(EntityView.STICKY_CENTER); } view.setDelegate(this); - view.setMaxWidth(w - AndroidUtilities.dp(7 + 7 + 18)); + view.setMaxWidth(w - dp(7 + 7 + 18)); view.setTypeface(PersistColorPalette.getInstance(currentAccount).getCurrentTypeface()); view.setType(PersistColorPalette.getInstance(currentAccount).getCurrentTextType()); entitiesView.addView(view, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); @@ -1273,6 +1289,13 @@ private boolean selectEntity(EntityView entityView, boolean changeOptions) { if (entityView instanceof TextPaintView) { enteredThroughText = true; editSelectedTextEntity(); + } else if (entityView instanceof ReactionWidgetEntityView) { + ReactionWidgetEntityView widgetEntityView = (ReactionWidgetEntityView) entityView; + if (reactionLayoutShowing && reactionForEntity == entityView) { + widgetEntityView.changeStyle(true); + } else { + showReactionsLayoutForView(widgetEntityView); + } } else { showMenuForEntity(currentEntityView); } @@ -1354,6 +1377,133 @@ public void set(float val) { return changed; } + float[] points = new float[2]; + + private void showReactionsLayoutForView(ReactionWidgetEntityView entityView) { + if (reactionForEntity != null && reactionForEntity != entityView && reactionLayout != null) { + ReactionsContainerLayout layout = reactionLayout; + layout.animate().alpha(0).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + AndroidUtilities.removeFromParent(layout); + } + }); + reactionLayout = null; + reactionLayoutShowing = false; + reactionShowProgress = 0f; + } + if (reactionLayout == null) { + reactionLayout = new ReactionsContainerLayout(ReactionsContainerLayout.TYPE_STORY_LIKES, LaunchActivity.getLastFragment(), getContext(), currentAccount, new WrappedResourceProvider(new DarkThemeResourceProvider()) { + @Override + public void appendColors() { + sparseIntArray.put(Theme.key_chat_emojiPanelBackground, ColorUtils.setAlphaComponent(Color.WHITE, 30)); + } + }); + BlurringShader.StoryBlurDrawer reactionBackgroundBlur = new BlurringShader.StoryBlurDrawer(blurManager, reactionLayout, BlurringShader.StoryBlurDrawer.BLUR_TYPE_BACKGROUND); + reactionLayout.setPadding(0, dp(22), 0, dp(22)); + parent.addView(reactionLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 52 + 22 + 22, Gravity.TOP | Gravity.RIGHT, 0, 0, 12, 64)); + Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + backgroundPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, 120)); + reactionLayout.setDelegate(new ReactionsContainerLayout.ReactionsContainerDelegate() { + + BlurringShader.StoryBlurDrawer windowBackgroundBlur; + + @Override + public boolean drawBackground() { + return true; + } + + @Override + public void drawRoundRect(Canvas canvas, RectF rect, float radius, float offsetX, float offsetY, int alpha, boolean isWindow) { + Paint paint; + if (isWindow) { + if (windowBackgroundBlur == null) { + windowBackgroundBlur = new BlurringShader.StoryBlurDrawer(blurManager, reactionLayout.getReactionsWindow().windowView, BlurringShader.StoryBlurDrawer.BLUR_TYPE_BACKGROUND); + } + windowBackgroundBlur.setBounds(-offsetX, -offsetY, + -offsetX + getMeasuredWidth(), + -offsetY + getMeasuredHeight()); + paint = windowBackgroundBlur.paint; + } else { + reactionBackgroundBlur.setBounds(-offsetX, -offsetY, + -offsetX + getMeasuredWidth(), + -offsetY + getMeasuredHeight()); + paint = reactionBackgroundBlur.paint; + } + paint.setAlpha(alpha); + backgroundPaint.setAlpha((int) (0.4f * alpha)); + canvas.drawRoundRect(rect, radius, radius, paint); + canvas.drawRoundRect(rect, radius, radius, backgroundPaint); + //ReactionsContainerLayout.ReactionsContainerDelegate.super.drawRoundRect(canvas, rect, radius, offsetX, offsetY); + } + + @Override + public void onReactionClicked(View view, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean longpress, boolean addToRecent) { + if (reactionForEntity == null) { + return; + } + reactionForEntity.setCurrentReaction(visibleReaction, true); + showReactionsLayout(false); + } + }); + reactionLayout.setMessage(null, null); + } + reactionLayout.setFragment(LaunchActivity.getLastFragment()); + reactionForEntity = entityView; + showReactionsLayout(true); + } + + public void showReactionsLayout(boolean show) { + if (reactionLayoutShowing == show || (!show && reactionLayout == null)) { + return; + } + reactionLayoutShowing = show; + if (show) { + reactionLayout.reset(); + reactionLayout.setVisibility(View.VISIBLE); + reactionLayout.setSelectedReaction(reactionForEntity.getCurrentReaction()); + reactionLayout.getParent().bringChildToFront(reactionLayout); + } else { + reactionForEntity = null; + } + if (show) { + invalidateReactionPosition = true; + parent.invalidate(); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(reactionShowProgress, show ? 1f : 0f); + reactionLayout.setTransitionProgress(reactionShowProgress); + valueAnimator.addUpdateListener(animation -> { + reactionShowProgress = (float) animation.getAnimatedValue(); + reactionLayout.setTransitionProgress(reactionShowProgress); + }); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!show) { + reactionLayout.setVisibility(View.GONE); + reactionLayout.reset(); + } + } + }); + valueAnimator.setDuration(200); + valueAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); + valueAnimator.start(); + } else { + if (reactionLayout.getReactionsWindow() != null) { + reactionLayout.getReactionsWindow().dismissWithAlpha(); + } + reactionLayout.animate().alpha(0).setDuration(150).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + reactionShowProgress = 0; + reactionLayout.setAlpha(1f); + reactionLayout.setVisibility(View.GONE); + reactionLayout.reset(); + } + }).start(); + } + } + + @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean restore = false; @@ -1376,7 +1526,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { int w = (int) (vw * currentCropState.cropPw * child.getScaleX() / currentCropState.cropScale); int h = (int) (vh * currentCropState.cropPh * child.getScaleY() / currentCropState.cropScale); float x = (float) Math.ceil((getMeasuredWidth() - w) / 2f) + transformX; - float y = (getMeasuredHeight() - actionBarHeight2 - AndroidUtilities.dp(48) + getAdditionalBottom() - h) / 2f + AndroidUtilities.dp(8) + status + transformY; + float y = (getMeasuredHeight() - actionBarHeight2 - dp(48) + getAdditionalBottom() - h) / 2f + dp(8) + status + transformY; canvas.clipRect(Math.max(0, x), Math.max(0, y), Math.min(x + w, getMeasuredWidth()), Math.min(getMeasuredHeight(), y + h)); restore = true; @@ -1397,7 +1547,7 @@ private void setupTabsLayout(Context context) { Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); { - linePaint.setStrokeWidth(AndroidUtilities.dp(2)); + linePaint.setStrokeWidth(dp(2)); linePaint.setStyle(Paint.Style.STROKE); linePaint.setStrokeCap(Paint.Cap.ROUND); @@ -1411,7 +1561,7 @@ protected void onDraw(Canvas canvas) { TextView selectedTab = (TextView) getChildAt(tabsSelectedIndex); TextView newSelectedTab = tabsNewSelectedIndex != -1 ? (TextView) getChildAt(tabsNewSelectedIndex) : null; linePaint.setColor(selectedTab.getCurrentTextColor()); - float y = selectedTab.getY() + selectedTab.getHeight() - selectedTab.getPaddingBottom() + AndroidUtilities.dp(3); + float y = selectedTab.getY() + selectedTab.getHeight() - selectedTab.getPaddingBottom() + dp(3); Layout layout = selectedTab.getLayout(); if (layout == null) { return; @@ -1430,7 +1580,7 @@ protected void onDraw(Canvas canvas) { drawTab = new TextView(context); drawTab.setText(LocaleController.getString(R.string.PhotoEditorDraw).toUpperCase()); drawTab.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_ROUNDRECT_6DP)); - drawTab.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + drawTab.setPadding(0, dp(8), 0, dp(8)); drawTab.setTextColor(Color.WHITE); drawTab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); drawTab.setGravity(Gravity.CENTER_HORIZONTAL); @@ -1448,7 +1598,7 @@ protected void onDraw(Canvas canvas) { stickerTab = new TextView(context); stickerTab.setText(LocaleController.getString(R.string.PhotoEditorSticker).toUpperCase()); stickerTab.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_ROUNDRECT_6DP)); - stickerTab.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + stickerTab.setPadding(0, dp(8), 0, dp(8)); stickerTab.setOnClickListener(v -> openStickersView()); stickerTab.setTextColor(Color.WHITE); stickerTab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); @@ -1461,7 +1611,7 @@ protected void onDraw(Canvas canvas) { textTab = new TextView(context); textTab.setText(LocaleController.getString(R.string.PhotoEditorText).toUpperCase()); textTab.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_ROUNDRECT_6DP)); - textTab.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + textTab.setPadding(0, dp(8), 0, dp(8)); textTab.setTextColor(Color.WHITE); textTab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); textTab.setGravity(Gravity.CENTER_HORIZONTAL); @@ -1515,13 +1665,13 @@ private void switchTab(int index) { float scale = 0.6f + 0.4f * (1f - pr); view.setScaleX(scale); view.setScaleY(scale); - view.setTranslationY(AndroidUtilities.dp(16) * Math.min(pr, 0.25f) / 0.25f); + view.setTranslationY(dp(16) * Math.min(pr, 0.25f) / 0.25f); view.setAlpha(1f - Math.min(pr, 0.25f) / 0.25f); scale = 0.6f + 0.4f * pr; newView.setScaleX(scale); newView.setScaleY(scale); - newView.setTranslationY(-AndroidUtilities.dp(16) * Math.min(1f - pr, 0.25f) / 0.25f); + newView.setTranslationY(-dp(16) * Math.min(1f - pr, 0.25f) / 0.25f); newView.setAlpha(1f - Math.min(1f - pr, 0.25f) / 0.25f); } }); @@ -1577,6 +1727,41 @@ public void onDismissAnimationStart() { super.onDismissAnimationStart(); switchTab(wasSelectedIndex); } + + @Override + public boolean canShowWidget(Integer widgetId) { + return true; + } + + @Override + public boolean canClickWidget(Integer widgetId) { + if (widgetId == EmojiBottomSheet.WIDGET_REACTION) { + int widgetsCount = 0; + for (int i = 0; i < entitiesView.getChildCount(); i++) { + if (entitiesView.getChildAt(i) instanceof ReactionWidgetEntityView) { + widgetsCount++; + } + } + if (widgetsCount >= 1 && !UserConfig.getInstance(currentAccount).isPremium()) { + showPremiumBulletin("StoryPremiumWidgets", R.string.StoryPremiumWidgets); + return false; + } + if (widgetsCount >= 5) { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + BulletinFactory.of(container, resourcesProvider).createSimpleBulletin(R.raw.chats_infotip, + LocaleController.getString("LimitReached", R.string.LimitReached), + LocaleController.getString("StoryReactionsWidgetLimit", R.string.StoryReactionsWidgetLimit) + ).show(true); + return false; + } + } + return true; + } + + @Override + protected boolean checkAudioPermission(Runnable granted) { + return PaintView.this.checkAudioPermission(granted); + } }; alert.setBlurDelegate(parent::drawBlurBitmap); boolean[] closing = new boolean[1]; @@ -1603,12 +1788,23 @@ public void onDismissAnimationStart() { } else if (widgetId == EmojiBottomSheet.WIDGET_PHOTO) { alert.dismiss(); onGalleryClick(); + } else if (widgetId == EmojiBottomSheet.WIDGET_AUDIO) { + closing[0] = false; + showAudioAlert(this::onAudioSelect); + } else if (widgetId == EmojiBottomSheet.WIDGET_REACTION) { + forceChanges = true; + ReactionWidgetEntityView reactionWidget = createReactionWidget(true); + appearAnimation(reactionWidget); } }); alert.show(); onOpenCloseStickersAlert(true); } + protected boolean checkAudioPermission(Runnable granted) { + return true; + } + private void showLocationAlert(LocationView editingLocationView, Utilities.Callback2 onLocationSelected) { ChatAttachAlert locationAlert = new ChatAttachAlert(getContext(), new ChatActivity(null) { @Override @@ -1697,6 +1893,71 @@ public void didPressedButton(int button, boolean arg, boolean notify, int schedu locationAlert.show(); } + private void showAudioAlert(Utilities.Callback onAudioSelected) { + final ChatAttachAlert[] audioAlert = new ChatAttachAlert[1]; + ChatActivity chatActivity = new ChatActivity(null) { + @Override + public long getDialogId() { + return 0; + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return resourcesProvider; + } + + @Override + public boolean isKeyboardVisible() { + return false; + } + + @Override + public Activity getParentActivity() { + return AndroidUtilities.findActivity(PaintView.this.getContext()); + } + + @Override + public TLRPC.User getCurrentUser() { + return UserConfig.getInstance(currentAccount).getCurrentUser(); + } + + @Override + public boolean isLightStatusBar() { + return false; + } + + @Override + public void sendAudio(ArrayList audios, CharSequence caption, boolean notify, int scheduleDate) { + if (audios.isEmpty()) { + return; + } + MessageObject msg = audios.get(0); + if (msg == null) { + return; + } + onAudioSelected.run(msg); + if (audioAlert[0] != null) { + audioAlert[0].dismiss(); + } + } + }; + audioAlert[0] = new ChatAttachAlert(getContext(), chatActivity, false, true, false, resourcesProvider); + audioAlert[0].setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { + @Override + public void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument) { + + } + }); + audioAlert[0].setOnDismissListener(di -> { + onOpenCloseStickersAlert(false); + }); + audioAlert[0].setStoryAudioPicker(); + audioAlert[0].init(); + audioAlert[0].show(); + } + + protected void onAudioSelect(MessageObject document) {} + protected void onOpenCloseStickersAlert(boolean open) {} protected void onTextAdd() {} @@ -1720,13 +1981,13 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { float bitmapW; float bitmapH; int fullHeight = AndroidUtilities.displaySize.y - ActionBar.getCurrentActionBarHeight() - getAdditionalTop() - getAdditionalBottom(); - int maxHeight = fullHeight - AndroidUtilities.dp(48); + int maxHeight = fullHeight - dp(48); if (bitmapToEdit != null) { bitmapW = bitmapToEdit.getWidth(); bitmapH = bitmapToEdit.getHeight(); } else { bitmapW = width; - bitmapH = height - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(48); + bitmapH = height - ActionBar.getCurrentActionBarHeight() - dp(48); } float renderWidth = width; @@ -1753,18 +2014,18 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int keyboardPad = Math.max(emojiPadding - parent.getPaddingUnderContainer(), measureKeyboardHeight()); measureChild(overlayLayout, widthMeasureSpec, MeasureSpec.makeMeasureSpec(height - keyboardPad, MeasureSpec.EXACTLY)); - topLayout.setPadding(topLayout.getPaddingLeft(), AndroidUtilities.dp(12), topLayout.getPaddingRight(), topLayout.getPaddingBottom()); + topLayout.setPadding(topLayout.getPaddingLeft(), dp(12), topLayout.getPaddingRight(), topLayout.getPaddingBottom()); measureChild(topLayout, widthMeasureSpec, heightMeasureSpec); ignoreLayout = false; int keyboardSize = 0; - if (!waitingForKeyboardOpen && keyboardSize <= AndroidUtilities.dp(20) && !emojiViewVisible && !isAnimatePopupClosing) { + if (!waitingForKeyboardOpen && keyboardSize <= dp(20) && !emojiViewVisible && !isAnimatePopupClosing) { ignoreLayout = true; hideEmojiView(); ignoreLayout = false; } - if (keyboardSize <= AndroidUtilities.dp(20)) { + if (keyboardSize <= dp(20)) { } else { hideEmojiView(); @@ -1865,14 +2126,23 @@ private void setupEntities() { LocationView locationView = createLocationSticker(entity.mediaGeo, entity.mediaArea, false); locationView.setType(entity.subType, entity.color); view = locationView; + } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_REACTION) { + ReactionWidgetEntityView entityView = createReactionWidget(false); + entityView.setCurrentReaction(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(entity.mediaArea.reaction), false); + if (entity.mediaArea.flipped) { + entityView.mirror(false); + } + if (entity.mediaArea.dark) { + entityView.changeStyle(false); + } + view = entityView; } else { continue; } view.setX(entity.x * w - entity.viewWidth * (1 - entity.scale) / 2); view.setY(entity.y * h - entity.viewHeight * (1 - entity.scale) / 2); view.setPosition(new Point(view.getX() + entity.viewWidth / 2f, view.getY() + entity.viewHeight / 2f)); - view.setScaleX(entity.scale); - view.setScaleY(entity.scale); + view.setScale(entity.scale); view.setRotation((float) (-entity.rotation / Math.PI * 180)); } entitiesView.setVisibility(View.VISIBLE); @@ -2154,6 +2424,15 @@ public Bitmap getBitmap(ArrayList entities, int res } mediaEntity.entities.add(tlentity); } + } else if (entity instanceof ReactionWidgetEntityView) { + skipDrawToBitmap = true; + ReactionWidgetEntityView reactionView = (ReactionWidgetEntityView) entity; + mediaEntity.type = VideoEditedInfo.MediaEntity.TYPE_REACTION; + mediaEntity.mediaArea = new TLRPC.TL_mediaAreaSuggestedReaction(); + mediaEntity.mediaArea.reaction = ReactionsUtils.toTLReaction(reactionView.getCurrentReaction()); + mediaEntity.mediaArea.dark = reactionView.isDark(); + mediaEntity.mediaArea.flipped = reactionView.isMirrored(); + mediaEntity.mediaArea.coordinates = new TLRPC.TL_mediaAreaCoordinates(); } else { continue; } @@ -2191,12 +2470,17 @@ public Bitmap getBitmap(ArrayList entities, int res mediaEntity.viewWidth = (int) (mediaEntity.viewHeight * a); mediaEntity.x = cx - mediaEntity.width / 2f; } - } else if (entity instanceof LocationView) { + } else if (entity instanceof LocationView || entity instanceof ReactionWidgetEntityView) { mediaEntity.mediaArea.coordinates.x = (mediaEntity.x + mediaEntity.width / 2f) * 100; mediaEntity.mediaArea.coordinates.y = (mediaEntity.y + mediaEntity.height / 2f) * 100; if (entity instanceof LocationView) { mediaEntity.mediaArea.coordinates.w = (mediaEntity.width - 2 * ((LocationView) entity).marker.padx * scaleX / (float) entitiesView.getMeasuredWidth()) * 100; mediaEntity.mediaArea.coordinates.h = (mediaEntity.height - 2 * ((LocationView) entity).marker.pady * scaleY / (float) entitiesView.getMeasuredHeight()) * 100; + } else if (entity instanceof ReactionWidgetEntityView){ + float padW = 2 * ((ReactionWidgetEntityView) entity).getPadding() * scaleX / (float) entitiesView.getMeasuredWidth(); + float padH = 2 * ((ReactionWidgetEntityView) entity).getPadding() * scaleX / (float) entitiesView.getMeasuredHeight(); + mediaEntity.mediaArea.coordinates.w = (mediaEntity.width - padW) * 100; + mediaEntity.mediaArea.coordinates.h = (mediaEntity.height - padH) * 100; } mediaEntity.mediaArea.coordinates.rotation = -mediaEntity.rotation / Math.PI * 180; } @@ -2383,12 +2667,12 @@ public void openStickers() { @Override public int getAdditionalTop() { - return AndroidUtilities.dp(48); + return dp(48); } @Override public int getAdditionalBottom() { - return AndroidUtilities.dp(24); + return dp(24); } @Override @@ -2629,7 +2913,7 @@ private void showColorList(boolean show) { float scale = 0.6f + 0.4f * (1f - toolsTransformProgress); barView.setScaleX(scale); barView.setScaleY(scale); - barView.setTranslationY(AndroidUtilities.dp(16) * Math.min(toolsTransformProgress, 0.25f) / 0.25f); + barView.setTranslationY(dp(16) * Math.min(toolsTransformProgress, 0.25f) / 0.25f); barView.setAlpha(1f - Math.min(toolsTransformProgress, 0.25f) / 0.25f); colorsListView.setProgress(toolsTransformProgress, show); @@ -2637,7 +2921,7 @@ private void showColorList(boolean show) { doneButton.setProgress(toolsTransformProgress); cancelButton.setProgress(toolsTransformProgress); - tabsLayout.setTranslationY(AndroidUtilities.dp(32) * toolsTransformProgress); + tabsLayout.setTranslationY(dp(32) * toolsTransformProgress); if (keyboardAnimator != null && keyboardAnimator.isRunning()) { moveBottomLayout[0] = false; } @@ -2645,7 +2929,7 @@ private void showColorList(boolean show) { float progress = show ? toolsTransformProgress : 1f - toolsTransformProgress; doneButton.setAlpha(lerp(doneButtonAlpha, show ? 1f : 0f, progress)); cancelButton.setAlpha(lerp(doneButtonAlpha, show ? 1f : 0f, progress)); - bottomLayout.setTranslationY(bottomLayoutTranslationY - (AndroidUtilities.dp(39)) * progress * (show ? 1 : -1)); + bottomLayout.setTranslationY(bottomLayoutTranslationY - (dp(39)) * progress * (show ? 1 : -1)); } bottomLayout.invalidate(); @@ -2701,6 +2985,14 @@ private void setCurrentSwatch(Swatch swatch, boolean updateInterface) { @Override public boolean onBackPressed() { + if (reactionLayoutShowing) { + if (reactionLayout.getReactionsWindow() != null && reactionLayout.getReactionsWindow().isShowing()) { + reactionLayout.dismissWindow(); + } else { + showReactionsLayout(false); + } + return true; + } if (isColorListShown) { showColorList(false); return true; @@ -2745,6 +3037,47 @@ private PaintView.PopupButton buttonForPopup(String text, int icon, boolean sele return button; } + public void onParentPreDraw() { + if (invalidateReactionPosition) { + invalidateReactionPosition = false; + if (reactionLayout != null && reactionForEntity != null) { + points[0] = reactionForEntity.getMeasuredWidth() / 2f; + points[1] = reactionForEntity.getMeasuredHeight() / 2f; + reactionForEntity.getMatrix().mapPoints(points); + float minY = points[1] - reactionForEntity.getMeasuredHeight() / 2f * reactionForEntity.getScaleX(); + float maxY = points[1] + reactionForEntity.getMeasuredHeight() / 2f * reactionForEntity.getScaleX(); + if (minY < dp(120) && maxY > parent.getMeasuredHeight() - dp(200)) { + reactionLayout.setTop(false); + reactionLayout.setTranslationY(dp(120) - reactionLayout.getMeasuredHeight() + dp(16)); + } else if (minY < dp(120)) { + reactionLayout.setTop(true); + reactionLayout.setTranslationY(points[1] + reactionForEntity.getMeasuredHeight() / 2f * reactionForEntity.getScaleX()); + } else { + reactionLayout.setTop(false); + reactionLayout.setTranslationY(minY - reactionLayout.getMeasuredHeight() + dp(16)); + } + if (points[0] < getMeasuredWidth() / 2f) { + reactionLayout.setMirrorX(true); + float startX = points[0] - reactionForEntity.getMeasuredHeight() / 2f; + float k = reactionLayout.getX() + reactionLayout.getMeasuredWidth() / 2f - startX; + if (k > 0) { + reactionLayout.setBubbleOffset((reactionLayout.getMeasuredWidth() / 2f - k) / 2); + } + } else { + float endX = points[0] + reactionForEntity.getMeasuredHeight() / 2f; + float k = reactionLayout.getX() + reactionLayout.getMeasuredWidth() / 2f - endX; + if (k < 0) { + reactionLayout.setBubbleOffset(-(reactionLayout.getMeasuredWidth() / 2f + k) / 2); + } + // reactionLayout.setBubbleOffset(0); + reactionLayout.setMirrorX(false); + } + + reactionLayout.setTranslationX((parent.getMeasuredWidth() - reactionLayout.getMeasuredWidth()) / 2f); + } + } + } + public void setBlurManager(BlurringShader.BlurManager blurManager) { this.blurManager = blurManager; } @@ -2980,13 +3313,13 @@ public void onAddButtonPressed(View btn) { }); popupLayout.addView(button, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); } - }, this, Gravity.RIGHT | Gravity.TOP, 0, getHeight()); + }, this, Gravity.RIGHT | Gravity.TOP, 0, getHeight(), false); } private void showMenuForEntity(final EntityView entityView) { int[] pos = getCenterLocationInWindow(entityView); int x = pos[0]; - int y = pos[1] - AndroidUtilities.dp(32); + int y = pos[1] - dp(32); showPopup(() -> { LinearLayout parent = new LinearLayout(getContext()); @@ -2994,12 +3327,12 @@ private void showMenuForEntity(final EntityView entityView) { TextView deleteView = new TextView(getContext()); deleteView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); - deleteView.setBackground(Theme.getSelectorDrawable(false)); deleteView.setGravity(Gravity.CENTER_VERTICAL); deleteView.setLines(1); deleteView.setSingleLine(); deleteView.setEllipsize(TextUtils.TruncateAt.END); - deleteView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); + deleteView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + deleteView.setPadding(dp(16), 0, dp(16), 0); deleteView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); deleteView.setTag(0); deleteView.setText(LocaleController.getString("PaintDelete", R.string.PaintDelete)); @@ -3010,17 +3343,17 @@ private void showMenuForEntity(final EntityView entityView) { popupWindow.dismiss(true); } }); - parent.addView(deleteView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + parent.addView(deleteView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); if (entityView instanceof TextPaintView) { TextView editView = new TextView(getContext()); editView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); - editView.setBackground(Theme.getSelectorDrawable(false)); editView.setGravity(Gravity.CENTER_VERTICAL); editView.setLines(1); editView.setSingleLine(); editView.setEllipsize(TextUtils.TruncateAt.END); - editView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); + editView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + editView.setPadding(dp(16), 0, dp(16), 0); editView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); if ((keyboardNotifier.keyboardVisible() && !keyboardNotifier.ignoring) || emojiPadding > 0) { editView.setTag(3); @@ -3047,7 +3380,7 @@ private void showMenuForEntity(final EntityView entityView) { } }); } - parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); } else if (entityView instanceof LocationView) { TextView editView = createActionLayoutButton(1, LocaleController.getString("PaintEdit", R.string.PaintEdit)); editView.setOnClickListener(v -> { @@ -3060,14 +3393,16 @@ private void showMenuForEntity(final EntityView entityView) { popupWindow.dismiss(true); } }); - parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); } - if (entityView instanceof StickerView || entityView instanceof PhotoView) { + if (entityView instanceof StickerView || entityView instanceof PhotoView || entityView instanceof ReactionWidgetEntityView) { TextView flipView = createActionLayoutButton(4, LocaleController.getString("Flip", R.string.Flip)); flipView.setOnClickListener(v -> { if (entityView instanceof StickerView) { ((StickerView) entityView).mirror(true); + } else if (entityView instanceof ReactionWidgetEntityView){ + ((ReactionWidgetEntityView) entityView).mirror(true); } else { ((PhotoView) entityView).mirror(true); } @@ -3075,18 +3410,18 @@ private void showMenuForEntity(final EntityView entityView) { popupWindow.dismiss(true); } }); - parent.addView(flipView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + parent.addView(flipView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); } - if (!(entityView instanceof PhotoView) && !(entityView instanceof LocationView)) { + if (!(entityView instanceof PhotoView) && !(entityView instanceof LocationView) && !(entityView instanceof ReactionWidgetEntityView)) { TextView duplicateView = new TextView(getContext()); duplicateView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); - duplicateView.setBackground(Theme.getSelectorDrawable(false)); duplicateView.setLines(1); duplicateView.setSingleLine(); duplicateView.setEllipsize(TextUtils.TruncateAt.END); duplicateView.setGravity(Gravity.CENTER_VERTICAL); - duplicateView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); + duplicateView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + duplicateView.setPadding(dp(16), 0, dp(16), 0); duplicateView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); duplicateView.setTag(2); duplicateView.setText(LocaleController.getString("PaintDuplicate", R.string.PaintDuplicate)); @@ -3097,7 +3432,17 @@ private void showMenuForEntity(final EntityView entityView) { popupWindow.dismiss(true); } }); - parent.addView(duplicateView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + parent.addView(duplicateView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); + } + + for (int i = 0; i < parent.getChildCount(); ++i) { + View child = parent.getChildAt(i); + child.setBackground(Theme.createRadSelectorDrawable(getThemedColor(Theme.key_listSelector), + i == 0 ? 8 : 0, + i == parent.getChildCount() - 1 ? 8 : 0, + i == parent.getChildCount() - 1 ? 8 : 0, + i == 0 ? 8 : 0 + )); } popupLayout.addView(parent); @@ -3106,18 +3451,18 @@ private void showMenuForEntity(final EntityView entityView) { params.width = LayoutHelper.WRAP_CONTENT; params.height = LayoutHelper.WRAP_CONTENT; parent.setLayoutParams(params); - }, this, Gravity.LEFT | Gravity.TOP, x, y); + }, this, Gravity.LEFT | Gravity.TOP, x, y, true); } private TextView createActionLayoutButton(int tag, String title) { TextView textView = new TextView(getContext()); textView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); - textView.setBackground(Theme.getSelectorDrawable(false)); textView.setGravity(Gravity.CENTER_VERTICAL); textView.setLines(1); textView.setSingleLine(); textView.setEllipsize(TextUtils.TruncateAt.END); - textView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textView.setPadding(dp(16), 0, dp(16), 0); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); textView.setTag(tag); textView.setText(title); @@ -3140,7 +3485,7 @@ private void duplicateEntity(EntityView thisEntityView) { } else if (thisEntityView instanceof TextPaintView) { TextPaintView newTextPaintView = new TextPaintView(getContext(), (TextPaintView) thisEntityView, position); newTextPaintView.setDelegate(this); - newTextPaintView.setMaxWidth(w - AndroidUtilities.dp(7 + 7 + 18)); + newTextPaintView.setMaxWidth(w - dp(7 + 7 + 18)); entitiesView.addView(newTextPaintView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); entityView = newTextPaintView; } else { @@ -3148,7 +3493,8 @@ private void duplicateEntity(EntityView thisEntityView) { } registerRemovalUndo(entityView); - selectEntity(entityView); + selectEntity(null); + appearAnimation(entityView); } private Point startPositionRelativeToEntity(EntityView entityView) { @@ -3159,7 +3505,8 @@ private Point startPositionRelativeToEntity(EntityView entityView) { if (entityView != null) { Point position = entityView.getPosition(); - return new Point(position.x, position.y + entityView.getHeight()); + offset = Math.min(entityView.getHeight(), entityView.getWidth()) * .2f; + return new Point(position.x + offset, position.y + offset); } else { float minimalDistance = 100.0f; if (currentCropState != null) { @@ -3176,7 +3523,7 @@ private Point startPositionRelativeToEntity(EntityView entityView) { Point location = ((EntityView) view).getPosition(); float distance = (float) Math.sqrt(Math.pow(location.x - position.x, 2) + Math.pow(location.y - position.y, 2)); if (distance < minimalDistance) { - offset = view.getHeight(); + offset = Math.min(view.getHeight(), view.getWidth()) * .2f; occupied = true; } } @@ -3184,14 +3531,49 @@ private Point startPositionRelativeToEntity(EntityView entityView) { if (!occupied) { break; } else { - position = new Point(position.x, position.y + offset); + position = new Point(position.x + offset, position.y + offset); } } return position; } } - private void showPopup(Runnable setupRunnable, View parent, int gravity, int x, int y) { + private class PopupWindowLayout extends ActionBarPopupWindow.ActionBarPopupWindowLayout { + public PopupWindowLayout(Context context) { + super(context, resourcesProvider); + } + + private float cx, cy; + private final ButtonBounce bounce = new ButtonBounce(this, 1.5f, 1f, 2f); + public boolean enableBounce = true; + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + cx = ev.getX(); + cy = ev.getY(); + bounce.setPressed(enableBounce); + } else if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + bounce.setPressed(false); + } + return super.dispatchTouchEvent(ev); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + float s = bounce.getScale(.05f); + if (s < 1) { + canvas.save(); + canvas.scale(s, s, cx, cy); + } + super.dispatchDraw(canvas); + if (s < 1) { + canvas.restore(); + } + } + } + + private void showPopup(Runnable setupRunnable, View parent, int gravity, int x, int y, boolean blurAndBounce) { if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); return; @@ -3199,9 +3581,8 @@ private void showPopup(Runnable setupRunnable, View parent, int gravity, int x, if (popupLayout == null) { popupRect = new android.graphics.Rect(); - popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), resourcesProvider); + popupLayout = new PopupWindowLayout(getContext()); popupLayout.setAnimationEnabled(true); - popupLayout.setBackgroundColor(-14145495); popupLayout.setOnTouchListener((v, event) -> { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { if (popupWindow != null && popupWindow.isShowing()) { @@ -3220,6 +3601,7 @@ private void showPopup(Runnable setupRunnable, View parent, int gravity, int x, }); popupLayout.setShownFromBottom(true); } + popupLayout.enableBounce = blurAndBounce; popupLayout.removeInnerViews(); setupRunnable.run(); @@ -3236,7 +3618,7 @@ private void showPopup(Runnable setupRunnable, View parent, int gravity, int x, popupWindow.setOnDismissListener(() -> popupLayout.removeInnerViews()); } - popupLayout.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST)); + popupLayout.measure(MeasureSpec.makeMeasureSpec(dp(1000), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(1000), MeasureSpec.AT_MOST)); popupWindow.setFocusable(true); @@ -3246,6 +3628,17 @@ private void showPopup(Runnable setupRunnable, View parent, int gravity, int x, } popupWindow.showAtLocation(parent, gravity, x, y); popupWindow.startAnimation(popupLayout); + + Drawable baseDrawable = getContext().getResources().getDrawable(R.drawable.popup_fixed_alert3).mutate(); + if (blurAndBounce) { + popupLayout.setBackgroundDrawable( + new BlurringShader.StoryBlurDrawer(blurManager, popupLayout, BlurringShader.StoryBlurDrawer.BLUR_TYPE_MENU_BACKGROUND) + .makeDrawable(x, y, baseDrawable, dpf2(8.3f)) + ); + } else { + popupLayout.setBackgroundDrawable(baseDrawable); + popupLayout.setBackgroundColor(-14145495); + } } private int getThemedColor(int key) { @@ -3490,6 +3883,39 @@ protected void didSetAnimatedSticker(RLottieDrawable drawable) { return view; } + private ReactionWidgetEntityView createReactionWidget(boolean select) { + Size size = new Size(dp(106), dp(106)); + Point position = centerPositionForEntity(); + boolean goodPosition; + //compute best position + if (entitiesView.getMeasuredHeight() > 0) { + do { + goodPosition = true; + for (int i = 0; i < entitiesView.getChildCount(); i++) { + View child = entitiesView.getChildAt(i); + float cx = child.getX() + child.getMeasuredWidth() / 2f; + float cy = child.getY() + child.getMeasuredHeight() / 2f; + if (MathUtils.distance(position.x, position.y, cx, cy) < dp(6)) { + position.x += entitiesView.getMeasuredWidth() * 0.05f; + position.y += entitiesView.getMeasuredHeight() * 0.05f; + position.x = Utilities.clamp(position.x, entitiesView.getMeasuredWidth(), 0); + position.y = Utilities.clamp(position.y, entitiesView.getMeasuredHeight(), 0); + goodPosition = false; + break; + } + } + } while (!goodPosition); + } + ReactionWidgetEntityView view = new ReactionWidgetEntityView(getContext(), position, size); + view.setDelegate(this); + entitiesView.addView(view); + if (select) { + registerRemovalUndo(view); + selectEntity(view); + } + return view; + } + public void removeCurrentEntity() { if (currentEntityView != null) { removeEntity(currentEntityView); @@ -3541,11 +3967,14 @@ public void onEntityDragEnd(boolean delete) { @Override public void onEntityDragStart() { - + if (reactionLayout != null) { + showReactionsLayout(false); + } } @Override public boolean onEntityLongClicked(EntityView entityView) { + showReactionsLayout(false); showMenuForEntity(entityView); return true; } @@ -3662,16 +4091,16 @@ private void showEmojiPopup(int show) { if (keyboardHeight <= 0) { if (AndroidUtilities.isTablet()) { - keyboardHeight = AndroidUtilities.dp(150); + keyboardHeight = dp(150); } else { - keyboardHeight = MessagesController.getGlobalEmojiSettings().getInt("kbd_height", AndroidUtilities.dp(200)); + keyboardHeight = MessagesController.getGlobalEmojiSettings().getInt("kbd_height", dp(200)); } } if (keyboardHeightLand <= 0) { if (AndroidUtilities.isTablet()) { - keyboardHeightLand = AndroidUtilities.dp(150); + keyboardHeightLand = dp(150); } else { - keyboardHeightLand = MessagesController.getGlobalEmojiSettings().getInt("kbd_height_land3", AndroidUtilities.dp(200)); + keyboardHeightLand = MessagesController.getGlobalEmojiSettings().getInt("kbd_height_land3", dp(200)); } } int currentHeight = (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? keyboardHeightLand : keyboardHeight) + parent.getPaddingUnderContainer(); @@ -3789,7 +4218,7 @@ public int measureKeyboardHeight() { @Override public void onSizeChanged(int height, boolean isWidthGreater) { - if (height > AndroidUtilities.dp(50) && keyboardVisible && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isTablet()) { + if (height > dp(50) && keyboardVisible && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isTablet()) { if (isWidthGreater) { keyboardHeightLand = height; MessagesController.getGlobalEmojiSettings().edit().putInt("kbd_height_land3", keyboardHeightLand).commit(); @@ -4042,6 +4471,10 @@ protected void onAttachedToWindow() { @Override protected void onDetachedFromWindow() { destroyed = true; + if (reactionLayout != null) { + AndroidUtilities.removeFromParent(reactionLayout); + reactionLayout = null; + } super.onDetachedFromWindow(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java index 53727c7ee7a..761747a7e3d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java @@ -15,6 +15,7 @@ import android.os.Build; import android.provider.MediaStore; import android.text.TextUtils; +import android.util.Log; import android.util.Pair; import android.util.Size; import android.view.Gravity; @@ -94,7 +95,7 @@ public long getDuration() { if (videoPlayer != null && videoPlayer.getDuration() != C.TIME_UNSET) { return videoPlayer.getDuration(); } - return 0; + return 1L; } public void set(StoryEntry entry) { @@ -179,12 +180,19 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { } }); audioPlayer.preparePlayer(Uri.fromFile(new File(entry.audioPath)), "other"); + + if (videoPlayer != null && getDuration() > 0) { + long startPos = (long) (entry.left * getDuration()); + videoPlayer.seekTo(startPos); + timelineView.setProgress(startPos); + } updateAudioPlayer(true); } } public void setupAudio(MessageObject messageObject, boolean animated) { if (entry != null) { + entry.editedMedia = true; if (messageObject == null || messageObject.messageOwner == null) { entry.audioPath = null; entry.audioAuthor = null; @@ -212,6 +220,9 @@ public void setupAudio(MessageObject messageObject, boolean animated) { } } entry.audioOffset = 0; + if (entry.isVideo) { + entry.audioOffset = (long) (entry.left * getDuration()); + } entry.audioLeft = 0; long scrollDuration = Math.min(entry != null && entry.isVideo ? getDuration() : entry.audioDuration, TimelineView.MAX_SCROLL_DURATION); entry.audioRight = entry.audioDuration == 0 ? 1 : Math.min(1, Math.min(scrollDuration, TimelineView.MAX_SELECT_DURATION) / (float) entry.audioDuration); @@ -255,6 +266,7 @@ public void onVideoLeftChange(float left) { return; } entry.left = left; + entry.editedMedia = true; if (videoPlayer != null && videoPlayer.getDuration() != C.TIME_UNSET) { seekTo((long) (left * videoPlayer.getDuration())); } @@ -266,6 +278,7 @@ public void onVideoRightChange(float right) { return; } entry.right = right; + entry.editedMedia = true; } @Override @@ -274,6 +287,7 @@ public void onAudioLeftChange(float left) { return; } entry.audioLeft = left; + entry.editedMedia = true; updateAudioPlayer(true); } @@ -283,6 +297,7 @@ public void onAudioRightChange(float right) { return; } entry.audioRight = right; + entry.editedMedia = true; updateAudioPlayer(true); } @@ -292,6 +307,7 @@ public void onAudioOffsetChange(long offset) { return; } entry.audioOffset = offset; + entry.editedMedia = true; updateAudioPlayer(true); } @@ -306,6 +322,7 @@ public void onAudioVolumeChange(float volume) { return; } entry.audioVolume = volume; + entry.editedMedia = true; if (audioPlayer != null) { audioPlayer.setVolume(volume); } @@ -594,7 +611,7 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { videoPlayer.setMute(entry.muted); updateAudioPlayer(true); - timelineView.setVideo(uri.toString(), getDuration()); + timelineView.setVideo(entry.getOriginalFile().getAbsolutePath(), getDuration()); timelineView.setVideoLeft(entry.left); timelineView.setVideoRight(entry.right); } @@ -1213,6 +1230,7 @@ public void updatePauseReason(int reasonId, boolean pause) { } // ignores actual player and other reasons to pause a video + // (so that play button doesn't make it play when f.ex. popup is on) public boolean isPlaying() { return !pauseLinks.contains(-9982); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java index 0be5cebb5bc..284dea4193d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java @@ -25,6 +25,7 @@ import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.FileRefController; +import org.telegram.messenger.ImageLoader; import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; @@ -85,6 +86,7 @@ public class StoryEntry extends IStoryPart { public File file; public boolean fileDeletable; public String thumbPath; + public Bitmap thumbPathBitmap; public boolean muted; public float left, right = 1; @@ -488,7 +490,7 @@ public void destroy(boolean draft) { clearFilter(); if (file != null) { if (fileDeletable && (!isEdit || editedMedia)) { - file.delete(); + file.delete(); } file = null; } @@ -505,6 +507,10 @@ public void destroy(boolean draft) { part.file = null; } } + if (thumbPathBitmap != null) { + thumbPathBitmap.recycle(); + thumbPathBitmap = null; + } cancelCheckStickers(); } @@ -513,7 +519,7 @@ public static StoryEntry fromStoryItem(File file, TLRPC.StoryItem storyItem) { entry.isEdit = true; entry.editStoryId = storyItem.id; entry.file = file; - entry.fileDeletable = true; + entry.fileDeletable = false; entry.width = 720; entry.height = 1280; if (storyItem.media instanceof TLRPC.TL_messageMediaPhoto) { @@ -541,7 +547,8 @@ public static StoryEntry fromStoryItem(File file, TLRPC.StoryItem storyItem) { for (int i = 0; i < storyItem.media.document.thumbs.size(); ++i) { TLRPC.PhotoSize photoSize = storyItem.media.document.thumbs.get(i); if (photoSize instanceof TLRPC.TL_photoStrippedSize) { - continue; + entry.thumbPathBitmap = ImageLoader.getStrippedPhotoBitmap(photoSize.bytes, null); + break; } File path = FileLoader.getInstance(entry.currentAccount).getPathToAttach(photoSize, true); if (path != null && path.exists()) { @@ -695,6 +702,14 @@ public void setupGradient(Runnable done) { } }); } + } else if (thumbPathBitmap != null) { + DominantColors.getColors(true, thumbPathBitmap, true, colors -> { + gradientTopColor = colors[0]; + gradientBottomColor = colors[1]; + if (done != null) { + done.run(); + } + }); } } } @@ -1021,4 +1036,85 @@ public void cancelCheckStickers() { ConnectionsManager.getInstance(currentAccount).cancelRequest(checkStickersReqId, true); } } + + public StoryEntry copy() { + StoryEntry newEntry = new StoryEntry(); + newEntry.draftId = draftId; + newEntry.isDraft = isDraft; + newEntry.draftDate = draftDate; + newEntry.editStoryPeerId = editStoryPeerId; + newEntry.editStoryId = editStoryId; + newEntry.isEdit = isEdit; + newEntry.isEditSaved = isEditSaved; + newEntry.fileDuration = fileDuration; + newEntry.editedMedia = editedMedia; + newEntry.editedCaption = editedCaption; + newEntry.editedPrivacy = editedPrivacy; + newEntry.editedMediaAreas = editedMediaAreas; + newEntry.isError = isError; + newEntry.error = error; + newEntry.audioPath = audioPath; + newEntry.audioAuthor = audioAuthor; + newEntry.audioTitle = audioTitle; + newEntry.audioDuration = audioDuration; + newEntry.audioOffset = audioOffset; + newEntry.audioLeft = audioLeft; + newEntry.audioRight = audioRight; + newEntry.audioVolume = audioVolume; + newEntry.editDocumentId = editDocumentId; + newEntry.editPhotoId = editPhotoId; + newEntry.editExpireDate = editExpireDate; + newEntry.isVideo = isVideo; + newEntry.file = file; + newEntry.fileDeletable = fileDeletable; + newEntry.thumbPath = thumbPath; + newEntry.muted = muted; + newEntry.left = left; + newEntry.right = right; + newEntry.duration = duration; + newEntry.width = width; + newEntry.height = height; + newEntry.resultWidth = resultWidth; + newEntry.resultHeight = resultHeight; + newEntry.partsMaxId = partsMaxId; + newEntry.parts.clear(); + newEntry.parts.addAll(parts); + newEntry.peer = peer; + newEntry.invert = invert; + newEntry.matrix.set(matrix); + newEntry.gradientTopColor = gradientTopColor; + newEntry.gradientBottomColor = gradientBottomColor; + newEntry.caption = caption; + newEntry.captionEntitiesAllowed = captionEntitiesAllowed; + newEntry.privacy = privacy; + newEntry.privacyRules.clear(); + newEntry.privacyRules.addAll(privacyRules); + newEntry.pinned = pinned; + newEntry.allowScreenshots = allowScreenshots; + newEntry.period = period; + newEntry.shareUserIds = shareUserIds; + newEntry.silent = silent; + newEntry.scheduleDate = scheduleDate; + newEntry.blurredVideoThumb = blurredVideoThumb; + newEntry.uploadThumbFile = uploadThumbFile; + newEntry.draftThumbFile = draftThumbFile; + newEntry.paintFile = paintFile; + newEntry.paintBlurFile = paintBlurFile; + newEntry.paintEntitiesFile = paintEntitiesFile; + newEntry.averageDuration = averageDuration; + newEntry.mediaEntities = new ArrayList<>(); + if (mediaEntities != null) { + for (int i = 0; i < mediaEntities.size(); ++i) { + newEntry.mediaEntities.add(mediaEntities.get(i).copy()); + } + } + newEntry.stickers = stickers; + newEntry.editStickers = editStickers; + newEntry.filterFile = filterFile; + newEntry.filterState = filterState; + newEntry.thumbBitmap = thumbBitmap; + newEntry.fromCamera = fromCamera; + newEntry.thumbPathBitmap = thumbPathBitmap; + return newEntry; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java index 73b276080fa..df3a45a14b7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java @@ -1,7 +1,7 @@ package org.telegram.ui.Stories.recorder; -import static android.view.View.GONE; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; import static org.telegram.messenger.AndroidUtilities.translitSafe; import android.animation.Animator; @@ -9,40 +9,31 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Shader; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.Build; import android.text.Editable; import android.text.InputType; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.text.SpannedString; -import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; -import android.text.style.DynamicDrawableSpan; -import android.text.style.ImageSpan; -import android.util.Log; import android.util.TypedValue; -import android.view.GestureDetector; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.animation.LinearInterpolator; import android.view.inputmethod.EditorInfo; @@ -52,28 +43,20 @@ import android.widget.ScrollView; import android.widget.TextView; -import androidx.annotation.Keep; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.collection.LongSparseArray; -import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScrollerCustom; import androidx.recyclerview.widget.RecyclerView; -import androidx.viewpager.widget.PagerAdapter; -import androidx.viewpager.widget.ViewPager; -import com.google.zxing.common.detector.MathUtils; +import com.google.android.exoplayer2.util.Consumer; -import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; -import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; @@ -88,7 +71,6 @@ import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; @@ -98,37 +80,32 @@ import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; -import org.telegram.ui.Components.BottomSheetWithRecyclerListView; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.ColoredImageSpan; -import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.GroupCreateSpan; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.RadioButton; import org.telegram.ui.Components.RecyclerListView; -import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.StickerEmptyView; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.ViewPagerFixed; +import org.telegram.ui.LaunchActivity; import org.telegram.ui.Stories.StoriesController; -import org.telegram.ui.UsersSelectActivity; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.Locale; +import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; public class StoryPrivacyBottomSheet extends BottomSheet implements NotificationCenter.NotificationCenterDelegate { @@ -148,6 +125,8 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification public static final int TYPE_EVERYONE = 4; public static final int TYPE_AS_MESSAGE = 5; + public TLRPC.InputPeer selectedPeer; + private final ArrayList excludedEveryone = new ArrayList<>(); private final HashMap> excludedEveryoneByGroup = new HashMap<>(); private int excludedEveryoneCount = 0; @@ -159,6 +138,7 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification private boolean allowScreenshots = true; private boolean keepOnMyPage = false; + private boolean canChangePeer = true; private HashSet mergeUsers(ArrayList users, HashMap> usersByGroup) { HashSet set = new HashSet<>(); @@ -257,59 +237,7 @@ public void setTranslationY(float translationY) { contentView.setClipToPadding(true); addView(contentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); - listView = new RecyclerListView(context, resourcesProvider) { -// private long tapTime; -// private float tapX, tapY; -// @Override -// public boolean dispatchTouchEvent(MotionEvent ev) { -// if (ev.getAction() == MotionEvent.ACTION_DOWN) { -// tapTime = System.currentTimeMillis(); -// tapX = ev.getX(); -// tapY = ev.getY(); -// } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { -// if (MathUtils.distance(tapX, tapY, ev.getX(), ev.getY()) >= AndroidUtilities.touchSlop) { -// tapTime = -1; -// if (searchField.currentDeletingSpan != null) { -// searchField.currentDeletingSpan.cancelDeleteAnimation(); -// searchField.currentDeletingSpan = null; -// } -// } -// } else if (ev.getAction() == MotionEvent.ACTION_UP) { -// if (MathUtils.distance(tapX, tapY, ev.getX(), ev.getY()) <= AndroidUtilities.touchSlop && System.currentTimeMillis() - tapTime <= ViewConfiguration.getTapTimeout() && searchField != null && searchField.spansContainer != null) { -// float x = ev.getX(), y = contentView.getPaddingTop() + ev.getY(); -// x -= searchField.getX(); -// y -= searchField.getY(); -// if (x < 0 || y < 0 || x > searchField.getWidth() || y > searchField.getHeight()) { -// return super.dispatchTouchEvent(ev); -// } -// for (int i = 0; i < searchField.spansContainer.getChildCount(); ++i) { -// View child = searchField.spansContainer.getChildAt(i); -// if (x < child.getX() || y < child.getY() || x >= child.getX() + child.getWidth() || y >= child.getY() + child.getHeight() || !(child instanceof GroupCreateSpan)) { -// continue; -// } -// GroupCreateSpan span = (GroupCreateSpan) child; -// onClick(span); -// break; -// } -// tapTime = -1; -// return true; -// } -// tapTime = -1; -// } else if (ev.getAction() == MotionEvent.ACTION_CANCEL) { -// tapTime = -1; -// if (searchField.currentDeletingSpan != null) { -// searchField.currentDeletingSpan.cancelDeleteAnimation(); -// searchField.currentDeletingSpan = null; -// } -// } -// return super.dispatchTouchEvent(ev); -// } -// -// @Override -// public boolean onTouchEvent(MotionEvent e) { -// return super.onTouchEvent(e); -// } - }; + listView = new RecyclerListView(context, resourcesProvider); listView.setClipToPadding(false); listView.setTranslateSelector(true); listView.setAdapter(adapter = new Adapter(context, resourcesProvider, searchField, StoryPrivacyBottomSheet.this::onBackPressed)); @@ -349,6 +277,16 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat } ItemInner item = items.get(position); if (item.viewType == VIEW_TYPE_USER) { + if (item.sendAs && canChangePeer) { + new ChoosePeerSheet(context, currentAccount, selectedPeer, peer -> { + selectedPeer = peer; + if (onSelectedPeer != null) { + onSelectedPeer.run(selectedPeer); + } + updateItems(true); + }, resourcesProvider).show(); + return; + } // boolean subtitle = LocaleController.isRTL ? x < view.getWidth() - AndroidUtilities.dp(100) : x > AndroidUtilities.dp(100); if (item.type == TYPE_CLOSE_FRIENDS) { if (selectedType == TYPE_CLOSE_FRIENDS || getCloseFriends().isEmpty()) { @@ -536,14 +474,15 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat } } else { keepOnMyPage = cell.isChecked(); + final boolean isChannel = selectedPeer instanceof TLRPC.TL_inputPeerChannel; if (keepOnMyPage) { BulletinFactory.of(container, resourcesProvider) - .createSimpleBulletin(R.raw.msg_story_keep, LocaleController.getString(R.string.StoryEnableKeep), 4) + .createSimpleBulletin(R.raw.msg_story_keep, LocaleController.getString(isChannel ? R.string.StoryChannelEnableKeep : R.string.StoryEnableKeep), 4) .setDuration(5000) .show(true); } else { BulletinFactory.of(container, resourcesProvider) - .createSimpleBulletin(R.raw.fire_on, LocaleController.getString(R.string.StoryDisableKeep), 4) + .createSimpleBulletin(R.raw.fire_on, LocaleController.getString(isChannel ? R.string.StoryChannelDisableKeep : R.string.StoryDisableKeep), 4) .setDuration(5000) .show(true); } @@ -560,6 +499,24 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { listView.invalidate(); } + @Override + protected void onChangeAnimationUpdate(RecyclerView.ViewHolder holder) { + containerView.invalidate(); + contentView.invalidate(); + } + + @Override + protected void onAddAnimationUpdate(RecyclerView.ViewHolder holder) { + containerView.invalidate(); + contentView.invalidate(); + } + + @Override + protected void onRemoveAnimationUpdate(RecyclerView.ViewHolder holder) { + containerView.invalidate(); + contentView.invalidate(); + } + @Override public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) { return true; @@ -928,7 +885,11 @@ public float top() { for (int i = 0; i < listView.getChildCount(); ++i) { View child = listView.getChildAt(i); if (layoutManager.getReverseLayout()) { - top = Math.min(top, contentView.getPaddingTop() + child.getY()); + final float childTop = contentView.getPaddingTop() + child.getY(); + final float a = child.getAlpha(); + if (childTop < top) { + top = AndroidUtilities.lerp(top, childTop, a); + } } else if (child.getTag() instanceof Integer && (int) child.getTag() == 33) { return contentView.getPaddingTop() + child.getBottom() + child.getTranslationY(); } else if (child.getTag() instanceof Integer && (int) child.getTag() == 35) { @@ -1004,9 +965,10 @@ public void applyBlocklist(boolean notify) { private String query; - private ArrayList atTop = new ArrayList<>(); - private ArrayList oldItems = new ArrayList<>(); - private ArrayList items = new ArrayList<>(); + private final ArrayList atTop = new ArrayList<>(); + private final ArrayList oldItems = new ArrayList<>(); + private final ArrayList items = new ArrayList<>(); + public void updateItems(boolean animated) { updateItems(animated, true); } @@ -1022,65 +984,94 @@ public void updateItems(boolean animated, boolean notify) { containsHeader = false; sectionCell.setVisibility(View.GONE); // items.add(ItemInner.asPad(dp(84) + 4 * dp(56) + (sendAsMessageEnabled ? dp(120) : dp(64)))); - items.add(ItemInner.asHeader2( - isEdit ? - LocaleController.getString("StoryPrivacyAlertEditTitle", R.string.StoryPrivacyAlertEditTitle) : - LocaleController.getString("StoryPrivacyAlertTitle", R.string.StoryPrivacyAlertTitle), - storyPeriod != Integer.MAX_VALUE ? - LocaleController.formatPluralString("StoryPrivacyAlertSubtitle", storyPeriod / 3600) : - LocaleController.getString("StoryPrivacyAlertSubtitleProfile", R.string.StoryPrivacyAlertSubtitleProfile) - )); - items.add(item = ItemInner.asType(TYPE_EVERYONE, selectedType == TYPE_EVERYONE, excludedEveryoneCount)); - if (excludedEveryoneCount == 1) { - if (excludedEveryone.size() == 1) { - item.user = MessagesController.getInstance(currentAccount).getUser(excludedEveryone.get(0)); - } else { - for (ArrayList userIds : excludedEveryoneByGroup.values()) { - if (userIds.size() >= 1) { - item.user = MessagesController.getInstance(currentAccount).getUser(userIds.get(0)); - break; + List sendAs = MessagesController.getInstance(currentAccount).getStoriesController().sendAs; + boolean containsPrivacy = true; + if (canChangePeer && (isEdit || sendAs == null || sendAs.size() <= 1)) { + items.add(ItemInner.asHeader2( + isEdit ? + LocaleController.getString("StoryPrivacyAlertEditTitle", R.string.StoryPrivacyAlertEditTitle) : + LocaleController.getString("StoryPrivacyAlertTitle", R.string.StoryPrivacyAlertTitle), + storyPeriod != Integer.MAX_VALUE ? + LocaleController.formatPluralString("StoryPrivacyAlertSubtitle", storyPeriod / 3600) : + LocaleController.getString("StoryPrivacyAlertSubtitleProfile", R.string.StoryPrivacyAlertSubtitleProfile) + )); + } else { + items.add(ItemInner.asHeaderCell(LocaleController.getString(R.string.StoryPrivacyPublishAs))); + if (selectedPeer == null || selectedPeer instanceof TLRPC.TL_inputPeerSelf) { + TLRPC.User me = UserConfig.getInstance(currentAccount).getCurrentUser(); + items.add(ItemInner.asUser(me, false, false).asSendAs()); + } else if (selectedPeer instanceof TLRPC.TL_inputPeerUser) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(selectedPeer.user_id); + items.add(ItemInner.asUser(user, false, false).asSendAs()); + } else if (selectedPeer instanceof TLRPC.TL_inputPeerChannel) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(selectedPeer.channel_id); + items.add(ItemInner.asChat(chat, false).asSendAs()); + containsPrivacy = false; + } else if (selectedPeer instanceof TLRPC.TL_inputPeerChat) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(selectedPeer.chat_id); + items.add(ItemInner.asChat(chat, false).asSendAs()); + containsPrivacy = false; + } + ItemInner section = ItemInner.asShadow(null); + section.resId = containsPrivacy ? 1 : 2; + items.add(section); + if (containsPrivacy) { + items.add(ItemInner.asHeaderCell(LocaleController.getString(R.string.StoryPrivacyWhoCanView))); + } + } + if (containsPrivacy) { + items.add(item = ItemInner.asType(TYPE_EVERYONE, selectedType == TYPE_EVERYONE, excludedEveryoneCount)); + if (excludedEveryoneCount == 1) { + if (excludedEveryone.size() == 1) { + item.user = MessagesController.getInstance(currentAccount).getUser(excludedEveryone.get(0)); + } else { + for (ArrayList userIds : excludedEveryoneByGroup.values()) { + if (userIds.size() >= 1) { + item.user = MessagesController.getInstance(currentAccount).getUser(userIds.get(0)); + break; + } } } } - } - items.add(item = ItemInner.asType(TYPE_CONTACTS, selectedType == TYPE_CONTACTS, excludedContacts.size())); - if (excludedContacts.size() == 1) { - item.user = MessagesController.getInstance(currentAccount).getUser(excludedContacts.get(0)); - } - ArrayList closeFriends = getCloseFriends(); - items.add(item = ItemInner.asType(TYPE_CLOSE_FRIENDS, selectedType == TYPE_CLOSE_FRIENDS, closeFriends.size())); - if (closeFriends.size() == 1 && closeFriends.get(0) instanceof TLRPC.User) { - item.user = (TLRPC.User) closeFriends.get(0); - } - items.add(item = ItemInner.asType(TYPE_SELECTED_CONTACTS, selectedType == TYPE_SELECTED_CONTACTS, selectedContactsCount)); - if (selectedContactsCount == 1) { - if (selectedContacts.size() == 1) { - item.user = MessagesController.getInstance(currentAccount).getUser(selectedContacts.get(0)); - } else { - for (ArrayList userIds : selectedContactsByGroup.values()) { - if (userIds.size() >= 1) { - item.user = MessagesController.getInstance(currentAccount).getUser(userIds.get(0)); - break; + items.add(item = ItemInner.asType(TYPE_CONTACTS, selectedType == TYPE_CONTACTS, excludedContacts.size())); + if (excludedContacts.size() == 1) { + item.user = MessagesController.getInstance(currentAccount).getUser(excludedContacts.get(0)); + } + ArrayList closeFriends = getCloseFriends(); + items.add(item = ItemInner.asType(TYPE_CLOSE_FRIENDS, selectedType == TYPE_CLOSE_FRIENDS, closeFriends.size())); + if (closeFriends.size() == 1 && closeFriends.get(0) instanceof TLRPC.User) { + item.user = (TLRPC.User) closeFriends.get(0); + } + items.add(item = ItemInner.asType(TYPE_SELECTED_CONTACTS, selectedType == TYPE_SELECTED_CONTACTS, selectedContactsCount)); + if (selectedContactsCount == 1) { + if (selectedContacts.size() == 1) { + item.user = MessagesController.getInstance(currentAccount).getUser(selectedContacts.get(0)); + } else { + for (ArrayList userIds : selectedContactsByGroup.values()) { + if (userIds.size() >= 1) { + item.user = MessagesController.getInstance(currentAccount).getUser(userIds.get(0)); + break; + } } } } + int blocklistCount = MessagesController.getInstance(currentAccount).getStoriesController().getBlocklistCount(); + items.add(ItemInner.asShadow(AndroidUtilities.replaceSingleTag( + blocklistCount <= 0 ? + LocaleController.getString("StoryBlockListEmpty") : + LocaleController.formatPluralString("StoryBlockList", blocklistCount), + Theme.key_chat_messageLinkIn, 0, + () -> { + activePage = PAGE_TYPE_BLOCKLIST; + viewPager.scrollToPosition(1); + }, + resourcesProvider + ))); } - int blocklistCount = MessagesController.getInstance(currentAccount).getStoriesController().getBlocklistCount(); - items.add(ItemInner.asShadow(AndroidUtilities.replaceSingleTag( - blocklistCount <= 0 ? - LocaleController.getString("StoryBlockListEmpty") : - LocaleController.formatPluralString("StoryBlockList", blocklistCount), - Theme.key_chat_messageLinkIn, 0, - () -> { - activePage = PAGE_TYPE_BLOCKLIST; - viewPager.scrollToPosition(1); - }, - resourcesProvider - ))); if (!isEdit) { items.add(ItemInner.asCheck(LocaleController.getString(R.string.StoryAllowScreenshots), 0, allowScreenshots)); - items.add(ItemInner.asCheck(LocaleController.getString(R.string.StoryKeep), 1, keepOnMyPage)); - items.add(ItemInner.asShadow(LocaleController.formatPluralString("StoryKeepInfo", (storyPeriod == Integer.MAX_VALUE ? 86400 : storyPeriod) / 3600))); + items.add(ItemInner.asCheck(LocaleController.getString(containsPrivacy ? R.string.StoryKeep : R.string.StoryKeepChannel), 1, keepOnMyPage)); + items.add(ItemInner.asShadow(LocaleController.formatPluralString(containsPrivacy ? "StoryKeepInfo" : "StoryKeepChannelInfo", (storyPeriod == Integer.MAX_VALUE ? 86400 : storyPeriod) / 3600))); } } else if (pageType == PAGE_TYPE_CLOSE_FRIENDS) { headerView.setText(LocaleController.getString("StoryPrivacyAlertCloseFriendsTitle", R.string.StoryPrivacyAlertCloseFriendsTitle)); @@ -1267,6 +1258,8 @@ public void updateItems(boolean animated, boolean notify) { adapter.notifyDataSetChanged(); } } + + this.contentView.invalidate(); } private boolean match(TLObject obj, String q) { @@ -1655,7 +1648,7 @@ public int getTypeOn(MotionEvent e) { return -1; } ItemInner item = items.get(position); - if (item.viewType != VIEW_TYPE_USER) { + if (item.viewType != VIEW_TYPE_USER || item.sendAs) { return -1; } if (LocaleController.isRTL ? e.getX() < getWidth() - AndroidUtilities.dp(100) : e.getX() > AndroidUtilities.dp(100)) { @@ -1677,7 +1670,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { keyboardHeight = StoryPrivacyBottomSheet.super.keyboardHeight; } super.onMeasure(widthMeasureSpec, heightMeasureSpec); - contentView.setPadding(0, AndroidUtilities.statusBarHeight + AndroidUtilities.dp(56), 0, 0); + contentView.setPadding(0, AndroidUtilities.statusBarHeight + (pageType == PAGE_TYPE_SHARE ? 0 : dp(56)), 0, 0); if (wasKeyboardVisible != keyboardVisible) { float searchFieldTop = getSearchFieldTop(); if (keyboardVisible && searchFieldTop + Math.min(dp(150), searchField.resultContainerHeight) > listView.getPaddingTop()) { @@ -1769,7 +1762,7 @@ public Adapter(Context context, Theme.ResourcesProvider resourcesProvider, Searc @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() == VIEW_TYPE_USER || holder.getItemViewType() == VIEW_TYPE_CHECK; + return (holder.getItemViewType() == VIEW_TYPE_USER && canChangePeer) || holder.getItemViewType() == VIEW_TYPE_CHECK; } @NonNull @@ -1788,6 +1781,9 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int view = new UserCell(context, resourcesProvider); } else if (viewType == VIEW_TYPE_HEADER2) { view = new HeaderCell2(context, resourcesProvider); + } else if (viewType == VIEW_TYPE_HEADER_CELL) { + view = new org.telegram.ui.Cells.HeaderCell(context, resourcesProvider); + view.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); } else if (viewType == VIEW_TYPE_NO_USERS) { StickerEmptyView searchEmptyView = new StickerEmptyView(context, null, StickerEmptyView.STICKER_TYPE_SEARCH, resourcesProvider); searchEmptyView.title.setText(LocaleController.getString("NoResult", R.string.NoResult)); @@ -1821,6 +1817,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi final boolean divider = neighbour != null && neighbour.viewType == viewType; if (viewType == VIEW_TYPE_USER) { UserCell userCell = (UserCell) holder.itemView; + userCell.setIsSendAs(item.sendAs, !item.sendAs); if (item.type > 0) { userCell.setType(item.type, item.typeCount, item.user); userCell.setCheckboxAlpha(1f, false); @@ -1833,6 +1830,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi userCell.setChecked(item.checked || item.halfChecked, false); userCell.setDivider(divider); userCell.setRedCheckbox(item.red); + userCell.drawArrow = canChangePeer; } else if (viewType == VIEW_TYPE_SECTION) { } else if (viewType == VIEW_TYPE_HEADER) { @@ -1870,6 +1868,8 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } } else if (viewType == VIEW_TYPE_CHECK) { ((TextCell) holder.itemView).setTextAndCheck(item.text, item.resId == 0 ? allowScreenshots : keepOnMyPage, divider); + } else if (viewType == VIEW_TYPE_HEADER_CELL) { + ((org.telegram.ui.Cells.HeaderCell) holder.itemView).setText(item.text); } } @@ -1935,6 +1935,7 @@ public void bindView(View view, int position, int viewType) { }); MessagesController.getInstance(currentAccount).getStoriesController().loadBlocklist(false); + MessagesController.getInstance(currentAccount).getStoriesController().loadSendAs(); } private void init(Context context) { @@ -1949,6 +1950,7 @@ public int getTopOffset(int tag) { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.contactsDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesBlocklistUpdate); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesSendAsUpdate); backgroundPaint.setColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); fixNavigationBar(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); @@ -2009,6 +2011,7 @@ protected void onItemSelected(View currentPage, View oldPage, int position, int public void dismissInternal() { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.contactsDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesBlocklistUpdate); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesSendAsUpdate); super.dismissInternal(); } @@ -2096,7 +2099,7 @@ private void done(StoryPrivacy privacy, Runnable loaded, boolean ignoreRestricti button.setLoading(true); } if (onDone != null) { - onDone.run(privacy, allowScreenshots, keepOnMyPage, loaded != null ? () -> { + onDone.done(privacy, allowScreenshots, keepOnMyPage, selectedPeer, loaded != null ? () -> { if (button != null) { button.setLoading(false); } @@ -2149,6 +2152,8 @@ public ContainerView(Context context) { private final AnimatedFloat isActionBar = new AnimatedFloat(this, 250, CubicBezierInterpolator.EASE_OUT_QUINT); private float top; + private final Path path = new Path(); + @Override protected void dispatchDraw(Canvas canvas) { View[] views = viewPager.getViewPages(); @@ -2172,7 +2177,9 @@ protected void dispatchDraw(Canvas canvas) { final float r = AndroidUtilities.lerp(dp(14), 0, actionBarT); canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, backgroundPaint); canvas.save(); - canvas.clipRect(AndroidUtilities.rectTmp); + path.rewind(); + path.addRoundRect(AndroidUtilities.rectTmp, r, r, Path.Direction.CW); + canvas.clipPath(path); super.dispatchDraw(canvas); canvas.restore(); } @@ -2214,10 +2221,15 @@ protected boolean canDismissWithSwipe() { return true; } + public interface DoneCallback { + public void done(StoryPrivacy privacy, boolean allowScreenshots, boolean keepInProfile, TLRPC.InputPeer peer, Runnable loaded); + } + private ArrayList warnUsers; - private Utilities.Callback4 onDone; + private DoneCallback onDone; private Utilities.Callback onDismiss; private Utilities.Callback> onDone2; + private Utilities.Callback onSelectedPeer; private boolean applyWhenDismiss = false; private boolean allowSmallChats = true; private boolean isEdit = false; @@ -2225,7 +2237,7 @@ public StoryPrivacyBottomSheet whenDismiss(Utilities.Callback list this.onDismiss = listener; return this; } - public StoryPrivacyBottomSheet whenSelectedRules(Utilities.Callback4 onDone, boolean whenDismiss) { + public StoryPrivacyBottomSheet whenSelectedRules(DoneCallback onDone, boolean whenDismiss) { this.onDone = onDone; this.applyWhenDismiss = whenDismiss; return this; @@ -2234,6 +2246,10 @@ private StoryPrivacyBottomSheet whenSelectedShare(Utilities.Callback onSelectedPeer) { + this.onSelectedPeer = onSelectedPeer; + return this; + } public StoryPrivacyBottomSheet enableSharing(boolean enable) { this.sendAsMessageEnabled = enable; if (viewPager != null) { @@ -2270,6 +2286,18 @@ public StoryPrivacyBottomSheet setWarnUsers(ArrayList users) { return this; } + public StoryPrivacyBottomSheet setPeer(TLRPC.InputPeer inputPeer) { + selectedPeer = inputPeer; + View[] viewPages = viewPager.getViewPages(); + if (viewPages[0] instanceof Page) { + ((Page) viewPages[0]).bind(((Page) viewPages[0]).pageType); + } + if (viewPages[1] instanceof Page) { + ((Page) viewPages[1]).bind(((Page) viewPages[1]).pageType); + } + return this; + } + public StoryPrivacyBottomSheet setValue(StoryPrivacy privacy) { if (privacy == null) { return this; @@ -2318,6 +2346,7 @@ public StoryPrivacyBottomSheet setValue(StoryPrivacy privacy) { public static final int VIEW_TYPE_EMPTY_VIEW = 5; public static final int VIEW_TYPE_SHADOW = 6; public static final int VIEW_TYPE_CHECK = 7; + public static final int VIEW_TYPE_HEADER_CELL = 8; private static class ItemInner extends AdapterWithDiffUtils.Item { @@ -2330,6 +2359,7 @@ private static class ItemInner extends AdapterWithDiffUtils.Item { public boolean checked; public boolean halfChecked; public boolean red; + public boolean sendAs; public int subtractHeight; public int padHeight = -1; @@ -2354,6 +2384,11 @@ public static ItemInner asHeader2(CharSequence title, CharSequence subtitle) { item.text2 = subtitle; return item; } + public static ItemInner asHeaderCell(CharSequence text) { + ItemInner item = new ItemInner(VIEW_TYPE_HEADER_CELL, false); + item.text = text; + return item; + } public static ItemInner asSearchField() { return new ItemInner(VIEW_TYPE_SEARCH, false); } @@ -2419,15 +2454,17 @@ public boolean equals(Object o) { } if (viewType == VIEW_TYPE_PAD && (subtractHeight != i.subtractHeight || padHeight != i.padHeight)) { return false; - } else if (viewType == VIEW_TYPE_USER && (user != i.user || chat != i.chat || type != i.type || typeCount != i.typeCount || checked != i.checked || red != i.red)) { + } else if (viewType == VIEW_TYPE_USER && (user != i.user || chat != i.chat || type != i.type || typeCount != i.typeCount || checked != i.checked || red != i.red || sendAs != i.sendAs)) { return false; } else if (viewType == VIEW_TYPE_HEADER && resId != i.resId) { return false; } else if (viewType == VIEW_TYPE_SECTION && !TextUtils.equals(text, i.text)) { return false; + } else if (viewType == VIEW_TYPE_HEADER_CELL && !TextUtils.equals(text, i.text)) { + return false; } else if (viewType == VIEW_TYPE_HEADER2 && (!TextUtils.equals(text, i.text) || !TextUtils.equals(text2, i.text2))) { return false; - } else if (viewType == VIEW_TYPE_SHADOW && (!TextUtils.equals(text, i.text))) { + } else if (viewType == VIEW_TYPE_SHADOW && (!TextUtils.equals(text, i.text) || resId != i.resId)) { return false; } else if (viewType == VIEW_TYPE_CHECK && (resId != i.resId || !TextUtils.equals(text, i.text) || checked != i.checked)) { return false; @@ -2439,6 +2476,11 @@ public ItemInner red(boolean red) { this.red = red; return this; } + + public ItemInner asSendAs() { + sendAs = true; + return this; + } } private boolean loadedContacts; @@ -2582,6 +2624,10 @@ private static class UserCell extends FrameLayout { private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private boolean sendAs = false; + private boolean needCheck = true; + private boolean drawArrow = true; + public UserCell(Context context, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; @@ -2590,7 +2636,7 @@ public UserCell(Context context, Theme.ResourcesProvider resourcesProvider) { imageView = new BackupImageView(context); imageView.setRoundRadius(AndroidUtilities.dp(20)); - addView(imageView, LayoutHelper.createFrame(40, 40, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 53, 0, 53, 0)); + addView(imageView); titleTextView = new SimpleTextView(context); titleTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); @@ -2598,28 +2644,51 @@ public UserCell(Context context, Theme.ResourcesProvider resourcesProvider) { titleTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); titleTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); NotificationCenter.listenEmojiLoading(titleTextView); - addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 16 : 105, 0, LocaleController.isRTL ? 105 : 16, 0)); + addView(titleTextView); subtitleTextView = new SimpleTextView(context); subtitleTextView.setTextSize(14); subtitleTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); subtitleTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); NotificationCenter.listenEmojiLoading(subtitleTextView); - addView(subtitleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 16 : 105, 0, LocaleController.isRTL ? 105 : 16, 0)); + addView(subtitleTextView); checkBox = new CheckBox2(context, 21, resourcesProvider); checkBox.setColor(Theme.key_dialogRoundCheckBox, Theme.key_checkboxDisabled, Theme.key_dialogRoundCheckBoxCheck); checkBox.setDrawUnchecked(true); checkBox.setDrawBackgroundAsArc(10); - addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 14, 0, 14, 0)); + addView(checkBox); checkBox.setChecked(false, false); checkBox.setVisibility(View.GONE); radioButton = new RadioButton(context); radioButton.setSize(AndroidUtilities.dp(20)); radioButton.setColor(Theme.getColor(Theme.key_checkboxDisabled, resourcesProvider), Theme.getColor(Theme.key_dialogRadioBackgroundChecked, resourcesProvider)); - addView(radioButton, LayoutHelper.createFrame(22, 22, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 15, 0, 15, 0)); + addView(radioButton); radioButton.setVisibility(View.GONE); + + updateLayouts(); + } + + private void updateLayouts() { + imageView.setLayoutParams(LayoutHelper.createFrame(40, 40, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), needCheck ? 53 : 16, 0, needCheck ? 53 : 16, 0)); + titleTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 20 : (needCheck ? 105 : 68), 0, LocaleController.isRTL ? (needCheck ? 105 : 68) : 20, 0)); + subtitleTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 20 : (needCheck ? 105 : 68), 0, LocaleController.isRTL ? (needCheck ? 105 : 68) : 20, 0)); + checkBox.setLayoutParams(LayoutHelper.createFrame(24, 24, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 13, 0, 14, 0)); + radioButton.setLayoutParams(LayoutHelper.createFrame(22, 22, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 14, 0, 15, 0)); + } + + public void setIsSendAs(boolean isSendAs, boolean needsCheck) { + sendAs = isSendAs; + if (needsCheck != needCheck) { + this.needCheck = needsCheck; + updateLayouts(); + } + if (!needCheck) { + radioButton.setVisibility(View.GONE); + checkBox.setVisibility(View.GONE); + } + setWillNotDraw(!(needDivider || (!needCheck && sendAs))); } public void setRedCheckbox(boolean red) { @@ -2664,10 +2733,15 @@ public void setUser(TLRPC.User user) { text = Emoji.replaceEmoji(text, titleTextView.getPaint().getFontMetricsInt(), false); titleTextView.setText(text); isOnline[0] = false; - setSubtitle(LocaleController.formatUserStatus(UserConfig.selectedAccount, user, isOnline)); - subtitleTextView.setTextColor(Theme.getColor(isOnline[0] ? Theme.key_dialogTextBlue2 : Theme.key_dialogTextGray3, resourcesProvider)); + if (sendAs) { + setSubtitle(LocaleController.getString(R.string.VoipGroupPersonalAccount)); + subtitleTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray3, resourcesProvider)); + } else { + setSubtitle(LocaleController.formatUserStatus(UserConfig.selectedAccount, user, isOnline)); + subtitleTextView.setTextColor(Theme.getColor(isOnline[0] ? Theme.key_dialogTextBlue2 : Theme.key_dialogTextGray3, resourcesProvider)); + } - checkBox.setVisibility(View.VISIBLE); + checkBox.setVisibility(needCheck ? View.VISIBLE : View.GONE); checkBox.setAlpha(1f); radioButton.setVisibility(View.GONE); } @@ -2683,8 +2757,17 @@ public void setChat(TLRPC.Chat chat, int participants_count) { isOnline[0] = false; String subtitle; - if (ChatObject.isChannel(chat) && !chat.megagroup) { - if (participants_count > 1) { + if (sendAs) { + if (participants_count <= 0) { + participants_count = chat.participants_count; + } + if (participants_count >= 1) { + subtitle = LocaleController.formatPluralString("Subscribers", participants_count); + } else { + subtitle = LocaleController.getString(R.string.DiscussChannel); + } + } else if (ChatObject.isChannel(chat) && !chat.megagroup) { + if (participants_count >= 1) { subtitle = LocaleController.formatPluralStringComma("Subscribers", participants_count - 1); } else { if (!ChatObject.isPublic(chat)) { @@ -2694,7 +2777,7 @@ public void setChat(TLRPC.Chat chat, int participants_count) { } } } else { - if (participants_count > 1) { + if (participants_count >= 1) { subtitle = LocaleController.formatPluralStringComma("Members", participants_count - 1); } else { if (chat.has_geo) { @@ -2709,7 +2792,7 @@ public void setChat(TLRPC.Chat chat, int participants_count) { setSubtitle(subtitle); subtitleTextView.setTextColor(Theme.getColor(isOnline[0] ? Theme.key_dialogTextBlue2 : Theme.key_dialogTextGray3, resourcesProvider)); - checkBox.setVisibility(View.VISIBLE); + checkBox.setVisibility(needCheck ? View.VISIBLE : View.GONE); radioButton.setVisibility(View.GONE); setCheckboxAlpha(participants_count > 200 ? .3f : 1f, false); } @@ -2784,7 +2867,7 @@ public void setType(int type, int count, TLRPC.User singleUser) { avatarDrawable.setColor(0xFFFFB743, 0xFFF68E34); } checkBox.setVisibility(View.GONE); - radioButton.setVisibility(View.VISIBLE); + radioButton.setVisibility(needCheck ? View.VISIBLE : View.GONE); imageView.setImageDrawable(avatarDrawable); imageView.setRoundRadius(dp(20)); } @@ -2803,15 +2886,39 @@ private void setSubtitle(CharSequence text) { private boolean needDivider; public void setDivider(boolean divider) { - setWillNotDraw(!(needDivider = divider)); + setWillNotDraw(!((needDivider = divider) || (!needCheck && sendAs))); } + private Path arrowPath; + private Paint arrowPaint; + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure( MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(56), MeasureSpec.EXACTLY) + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(sendAs && !needCheck ? 62 : 56), MeasureSpec.EXACTLY) ); + + if (!needCheck && sendAs) { + if (arrowPath == null) { + arrowPath = new Path(); + } else { + arrowPath.rewind(); + } + final float cx = LocaleController.isRTL ? dp(31) : getMeasuredWidth() - dp(31); + final float cy = getMeasuredHeight() / 2f; + final float m = LocaleController.isRTL ? -1 : 1; + arrowPath.moveTo(cx, cy - dp(6)); + arrowPath.lineTo(cx + m * dp(6), cy); + arrowPath.lineTo(cx, cy + dp(6)); + if (arrowPaint == null) { + arrowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + arrowPaint.setStyle(Paint.Style.STROKE); + arrowPaint.setStrokeCap(Paint.Cap.ROUND); + } + arrowPaint.setStrokeWidth(dpf2(1.86f)); + arrowPaint.setColor(Theme.multAlpha(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider), .3f)); + } } @Override @@ -2820,11 +2927,14 @@ protected void onDraw(Canvas canvas) { if (needDivider) { dividerPaint.setColor(Theme.getColor(Theme.key_divider, resourcesProvider)); if (LocaleController.isRTL) { - canvas.drawRect(0, getHeight() - 1, getWidth() - AndroidUtilities.dp(105), getHeight(), dividerPaint); + canvas.drawRect(0, getHeight() - 1, getWidth() - dp(105), getHeight(), dividerPaint); } else { - canvas.drawRect(AndroidUtilities.dp(105), getHeight() - 1, getWidth(), getHeight(), dividerPaint); + canvas.drawRect(dp(105), getHeight() - 1, getWidth(), getHeight(), dividerPaint); } } + if (arrowPath != null && arrowPaint != null && !needCheck && sendAs && drawArrow) { + canvas.drawPath(arrowPath, arrowPaint); + } } } @@ -3939,6 +4049,16 @@ public void didReceivedNotification(int id, int account, Object... args) { } } } + } else if (id == NotificationCenter.storiesSendAsUpdate) { + View[] views = viewPager.getViewPages(); + for (int i = 0; i < views.length; ++i) { + if (views[i] instanceof Page) { + Page page = (Page) views[i]; + if (page.pageType == PAGE_TYPE_SHARE) { + page.updateItems(true); + } + } + } } } @@ -4027,6 +4147,12 @@ private void pullSaved() { allowScreenshots = !MessagesController.getInstance(currentAccount).getMainSettings().getBoolean("story_noforwards", false); keepOnMyPage = MessagesController.getInstance(currentAccount).getMainSettings().getBoolean("story_keep", true); +// +// long peerId = MessagesController.getInstance(currentAccount).getMainSettings().getLong("story_sendas", 0L); +// if (peerId != 0) { +// selectedPeer = new TLRPC.TL_inputPeerChannel(); +// selectedPeer.channel_id = peerId; +// } } private void save() { @@ -4052,6 +4178,194 @@ private void save() { .putString("story_prv_excluded", TextUtils.join(",", excludedContacts)) .putBoolean("story_noforwards", !allowScreenshots) .putBoolean("story_keep", keepOnMyPage) +// .putLong("story_sendas", selectedPeer instanceof TLRPC.TL_inputPeerChannel ? selectedPeer.channel_id : 0) .apply(); } + + public StoryPrivacyBottomSheet setCanChangePeer(boolean canChangePeer) { + this.canChangePeer = canChangePeer; + return this; + } + + public static class ChoosePeerSheet extends BottomSheet { + + private final int currentAccount; + private final List peers; + private final TLRPC.InputPeer selectedPeer; + private final Utilities.Callback onPeerSelected; + + private final RecyclerListView listView; + private final TextView headerView; + + public ChoosePeerSheet(Context context, int currentAccount, TLRPC.InputPeer selected, Utilities.Callback onPeerSelected, Theme.ResourcesProvider resourcesProvider) { + super(context, false, resourcesProvider); + fixNavigationBar(); + + this.currentAccount = currentAccount; + this.peers = MessagesController.getInstance(currentAccount).getStoriesController().sendAs; + this.selectedPeer = selected; + this.onPeerSelected = onPeerSelected; + + containerView = new FrameLayout(context) { + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final AnimatedFloat statusBarT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + @Override + protected void dispatchDraw(Canvas canvas) { + backgroundPaint.setColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + float top = Math.max(0, top()); + top = AndroidUtilities.lerp(top, 0, statusBarT.set(top < AndroidUtilities.statusBarHeight)); + AndroidUtilities.rectTmp.set(backgroundPaddingLeft, top, getWidth() - backgroundPaddingLeft, getHeight() + dp(14)); + final float r = dp(14) * (1f - statusBarT.get()); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, backgroundPaint); + headerView.setTranslationY(Math.max(AndroidUtilities.statusBarHeight + dp(8), dp(14) + top)); + + canvas.save(); + canvas.clipRect(backgroundPaddingLeft, AndroidUtilities.statusBarHeight + dp(14), getWidth() - backgroundPaddingLeft, getHeight()); + super.dispatchDraw(canvas); + canvas.restore(); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getY() < top()) { + dismiss(); + return true; + } + return super.dispatchTouchEvent(ev); + } + }; + + listView = new RecyclerListView(context, resourcesProvider); + listView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, 0); + listView.setAdapter(new Adapter()); + listView.setLayoutManager(new LinearLayoutManager(context)); + containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + listView.setOnItemClickListener((view, pos) -> { + if (pos <= 1) { + return; + } + TLRPC.InputPeer peer = peers.get(pos - 2); + if (peer.channel_id == 0 && peer.chat_id == 0) { + onPeerSelected.run(peer); + dismiss(); + return; + } + AlertDialog progressDialog = new AlertDialog(getContext(), AlertDialog.ALERT_TYPE_SPINNER, resourcesProvider); + progressDialog.showDelayed(200); + MessagesController.getInstance(currentAccount).getStoriesController().canSendStoryFor(DialogObject.getPeerDialogId(peer), aBoolean -> { + progressDialog.dismiss(); + if (aBoolean && onPeerSelected != null) { + onPeerSelected.run(peer); + } + }, true, resourcesProvider); + dismiss(); + + }); + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + containerView.invalidate(); + } + }); + + headerView = new TextView(getContext()); + headerView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + headerView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + headerView.setPadding(backgroundPaddingLeft + dp(22), dp(2), backgroundPaddingLeft + dp(22), dp(14)); + headerView.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + headerView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + headerView.setText(LocaleController.getString(R.string.StoryPrivacyPublishAs)); + containerView.addView(headerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + + private float top() { + float top = containerView.getMeasuredHeight(); + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (child == null) continue; + int position = listView.getChildAdapterPosition(child); + if (position == RecyclerView.NO_POSITION) continue; + if (position > 0) { + top = Math.min(child.getY(), top); + } + } + return top; + } + + @Override + protected boolean canDismissWithSwipe() { + return top() > (int) (AndroidUtilities.displaySize.y * .5f); + } + + private class Adapter extends RecyclerListView.SelectionAdapter { + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == 2; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + if (viewType == 0 || viewType == 1) { + view = new View(getContext()); + int height; + if (viewType == 0) { + height = AndroidUtilities.displaySize.y + AndroidUtilities.statusBarHeight - dp(54 + 56 * 4.5f); + } else { + height = dp(54); + } + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height)); + } else { + view = new UserCell(getContext(), resourcesProvider); + } + return new RecyclerListView.Holder(view); + } + + @Override + public int getItemViewType(int position) { + if (position == 0) { + return 0; + } else if (position == 1) { + return 1; + } + return 2; + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (holder.getItemViewType() == 2) { + UserCell cell = (UserCell) holder.itemView; + cell.setIsSendAs(true, true); + TLRPC.InputPeer peer = peers.get(position - 2); + if (peer instanceof TLRPC.TL_inputPeerSelf) { + cell.setUser(UserConfig.getInstance(currentAccount).getCurrentUser()); + } else if (peer instanceof TLRPC.TL_inputPeerUser) { + cell.setUser(MessagesController.getInstance(currentAccount).getUser(peer.user_id)); + } else if (peer instanceof TLRPC.TL_inputPeerChat) { + cell.setChat(MessagesController.getInstance(currentAccount).getChat(peer.chat_id), 0); + } else if (peer instanceof TLRPC.TL_inputPeerChannel) { + cell.setChat(MessagesController.getInstance(currentAccount).getChat(peer.channel_id), 0); + } + cell.checkBox.setVisibility(View.GONE); + cell.radioButton.setVisibility(View.VISIBLE); + cell.setChecked(selectedPeer == null && position == 2 || did(selectedPeer) == did(peer), false); + cell.setDivider(position != getItemCount() - 1); + } + } + + private long did(TLRPC.InputPeer peer) { + if (peer instanceof TLRPC.TL_inputPeerSelf) { + return UserConfig.getInstance(currentAccount).getClientUserId(); + } + return DialogObject.getPeerDialogId(peer); + } + + @Override + public int getItemCount() { + return 2 + peers.size(); + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java index dbb78bafe7a..538e0c0c9f7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java @@ -178,7 +178,7 @@ public void open() { StoryPrivacyBottomSheet sheet = new StoryPrivacyBottomSheet(getContext(), storyPeriod, resourcesProvider); sheet.setValue(getStoryPrivacy()); sheet.isEdit(false); - sheet.whenSelectedRules((privacy, a, b, whenDone) -> { + sheet.whenSelectedRules((privacy, a, b, sendAs, whenDone) -> { edited = true; CharSequence text = (value = privacy).toString(); textDrawable.setText(text); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java index 73f6565f1e4..31338837225 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java @@ -104,6 +104,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.BasePermissionsActivity; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.BlurringShader; import org.telegram.ui.Components.Bulletin; @@ -130,6 +131,7 @@ import org.telegram.ui.Components.ZoomControlView; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.ProfileActivity; import org.telegram.ui.Stories.DarkThemeResourceProvider; import org.telegram.ui.Stories.DialogStoriesCell; import org.telegram.ui.Stories.PeerStoriesView; @@ -220,6 +222,8 @@ public StoryRecorder(Activity activity, int currentAccount) { private int openType; private float dismissProgress; private Float frozenDismissProgress; + private boolean canChangePeer = true; + long selectedDialogId; public static class SourceView { @@ -232,10 +236,44 @@ public static class SourceView { int iconSize; View view; + protected void show() {} protected void hide() {} protected void drawAbove(Canvas canvas, float alpha) {} + public static SourceView fromAvatarImage(ProfileActivity.AvatarImageView avatarImage) { + if (avatarImage == null || avatarImage.getRootView() == null) { + return null; + } + float scale = ((View)avatarImage.getParent()).getScaleX(); + final float size = avatarImage.getImageReceiver().getImageWidth() * scale; + final float radius = size / 2f; + SourceView src = new SourceView() { + @Override + protected void show() { + avatarImage.drawAvatar = true; + avatarImage.invalidate(); + } + + @Override + protected void hide() { + avatarImage.drawAvatar = false; + avatarImage.invalidate(); + } + }; + final int[] loc = new int[2]; + final float[] locPositon = new float[2]; + avatarImage.getRootView().getLocationOnScreen(loc); + AndroidUtilities.getViewPositionInParent(avatarImage, (ViewGroup) avatarImage.getRootView(), locPositon); + final float x = loc[0] + locPositon[0] + avatarImage.getImageReceiver().getImageX() * scale; + final float y = loc[1] + locPositon[1] + avatarImage.getImageReceiver().getImageY() * scale; + + src.screenRect.set(x, y, x + size, y + size); + src.backgroundImageReceiver = avatarImage.getImageReceiver(); + src.rounding = Math.max(src.screenRect.width(), src.screenRect.height()) / 2f; + return src; + } + public static SourceView fromStoryViewer(StoryViewer storyViewer) { if (storyViewer == null) { return null; @@ -465,7 +503,7 @@ public void close(boolean animated) { } if (outputEntry != null && !outputEntry.isEditSaved) { - if (wasSend && outputEntry.isEdit) { + if (wasSend && outputEntry.isEdit || outputEntry.draftId != 0) { outputEntry.editedMedia = false; } outputEntry.destroy(false); @@ -725,6 +763,9 @@ protected void dispatchDraw(Canvas canvas) { captionContainer.setAlpha(openProgress); } } + if (paintView != null) { + paintView.onParentPreDraw(); + } super.dispatchDraw(canvas); if (restore) { canvas.restore(); @@ -1067,6 +1108,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { MeasureSpec.makeMeasureSpec(paintView.emojiView.getLayoutParams().height, MeasureSpec.EXACTLY) ); } + if (paintView.reactionLayout != null) { + measureChild(paintView.reactionLayout, widthMeasureSpec, heightMeasureSpec); + if (paintView.reactionLayout.getReactionsWindow() != null) { + measureChild(paintView.reactionLayout.getReactionsWindow().windowView, widthMeasureSpec, heightMeasureSpec); + } + } } for (int i = 0; i < getChildCount(); ++i) { @@ -1131,6 +1178,13 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto if (paintView.emojiView != null) { paintView.emojiView.layout(insetLeft, H - insetBottom - paintView.emojiView.getMeasuredHeight(), W - insetRight, H - insetBottom); } + if (paintView.reactionLayout != null) { + paintView.reactionLayout.layout(insetLeft, insetTop, insetLeft + paintView.reactionLayout.getMeasuredWidth(), insetTop + paintView.reactionLayout.getMeasuredHeight()); + View reactionsWindowView = paintView.reactionLayout.getReactionsWindow() != null ? paintView.reactionLayout.getReactionsWindow().windowView : null; + if (reactionsWindowView != null) { + reactionsWindowView.layout(insetLeft, insetTop, insetLeft + reactionsWindowView.getMeasuredWidth(), insetTop + reactionsWindowView.getMeasuredHeight()); + } + } } for (int i = 0; i < getChildCount(); ++i) { @@ -1951,9 +2005,14 @@ public int getBottomOffset(int tag) { applyFilter(null); upload(true); } else { + if (selectedDialogId != 0) { + outputEntry.peer = MessagesController.getInstance(currentAccount).getInputPeer(selectedDialogId); + } previewView.updatePauseReason(3, true); privacySheet = new StoryPrivacyBottomSheet(activity, outputEntry.period, resourcesProvider) .setValue(outputEntry.privacy) + .setPeer(outputEntry.peer) + .setCanChangePeer(canChangePeer) .whenDismiss(privacy -> { if (outputEntry != null) { outputEntry.privacy = privacy; @@ -1961,7 +2020,13 @@ public int getBottomOffset(int tag) { }) .isEdit(false) .setWarnUsers(getUsersFrom(captionEdit.getText())) - .whenSelectedRules((privacy, allowScreenshots, keepInProfile, whenDone) -> { + .whenSelectedPeer(peer -> { + if (outputEntry == null) { + return; + } + outputEntry.peer = peer == null ? new TLRPC.TL_inputPeerSelf() : peer; + }) + .whenSelectedRules((privacy, allowScreenshots, keepInProfile, sendAs, whenDone) -> { if (outputEntry == null) { return; } @@ -1973,6 +2038,7 @@ public int getBottomOffset(int tag) { outputEntry.privacyRules.clear(); outputEntry.privacyRules.addAll(privacy.rules); outputEntry.editedPrivacy = true; + outputEntry.peer = sendAs; applyFilter(() -> { whenDone.run(); upload(true); @@ -2129,7 +2195,7 @@ private void uploadInternal(boolean asStory) { fromSourceView.show(); fromSourceView = null; } - fromSourceView = closingSourceProvider != null ? closingSourceProvider.getView() : null; + fromSourceView = closingSourceProvider != null ? closingSourceProvider.getView(finalSendAsDialogId) : null; if (fromSourceView != null) { openType = fromSourceView.type; containerView.updateBackground(); @@ -2159,7 +2225,7 @@ private void uploadInternal(boolean asStory) { } }; if (closingSourceProvider != null) { - closingSourceProvider.preLayout(runnable); + closingSourceProvider.preLayout(sendAsDialogId, runnable); } else { runnable.run(); } @@ -2235,7 +2301,9 @@ private File prepareThumb(StoryEntry storyEntry, boolean forDraft) { if (paintView != null && paintView.entitiesView != null) { canvas.save(); canvas.scale(scale, scale); + paintView.entitiesView.drawForThumb = true; paintView.entitiesView.draw(canvas); + paintView.entitiesView.drawForThumb = false; canvas.restore(); } @@ -2784,9 +2852,9 @@ public void navigateTo(int page, boolean animated) { animators.add(ObjectAnimator.ofFloat(timelineView, View.ALPHA, page == PAGE_PREVIEW ? 1f : 0)); - animators.add(ObjectAnimator.ofFloat(muteButton, View.ALPHA, page == PAGE_PREVIEW && (isVideo || outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) ? 1f : 0)); + animators.add(ObjectAnimator.ofFloat(muteButton, View.ALPHA, page == PAGE_PREVIEW && isVideo ? 1f : 0)); ((ViewGroup.MarginLayoutParams) playButton.getLayoutParams()).rightMargin = dp(48 + (isVideo ? 48 : 0)); - animators.add(ObjectAnimator.ofFloat(playButton, View.ALPHA, page == PAGE_PREVIEW && isVideo ? 1f : 0)); + animators.add(ObjectAnimator.ofFloat(playButton, View.ALPHA, page == PAGE_PREVIEW && (isVideo || outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) ? 1f : 0)); animators.add(ObjectAnimator.ofFloat(downloadButton, View.ALPHA, page == PAGE_PREVIEW ? 1f : 0)); // animators.add(ObjectAnimator.ofFloat(privacySelector, View.ALPHA, page == PAGE_PREVIEW ? 1f : 0)); @@ -2820,9 +2888,9 @@ public void onAnimationEnd(Animator animation) { hintTextView.setAlpha(page == PAGE_CAMERA && animatedRecording ? 1f : 0); captionContainer.setAlpha(page == PAGE_PREVIEW ? 1f : 0); captionContainer.setTranslationY(page == PAGE_PREVIEW ? 0 : dp(12)); - muteButton.setAlpha(page == PAGE_PREVIEW && (isVideo || outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) ? 1f : 0); + muteButton.setAlpha(page == PAGE_PREVIEW && isVideo ? 1f : 0); ((ViewGroup.MarginLayoutParams) playButton.getLayoutParams()).rightMargin = dp(48 + (isVideo ? 48 : 0)); - playButton.setAlpha(page == PAGE_PREVIEW && isVideo ? 1f : 0); + playButton.setAlpha(page == PAGE_PREVIEW && (isVideo || outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) ? 1f : 0); downloadButton.setAlpha(page == PAGE_PREVIEW ? 1f : 0); // privacySelector.setAlpha(page == PAGE_PREVIEW ? 1f : 0); timelineView.setAlpha(page == PAGE_PREVIEW ? 1f : 0); @@ -3138,6 +3206,11 @@ private void onNavigateStart(int fromPage, int toPage) { previewView.play(true); playButton.drawable.setPause(previewView.isPlaying(), false); titleTextView.setRightPadding(AndroidUtilities.dp(144)); + } else if (outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) { + muteButton.setVisibility(View.GONE); + playButton.setVisibility(View.VISIBLE); + playButton.drawable.setPause(true, false); + titleTextView.setRightPadding(AndroidUtilities.dp(48)); } else { titleTextView.setRightPadding(AndroidUtilities.dp(48)); } @@ -3215,6 +3288,9 @@ private void onNavigateStart(int fromPage, int toPage) { captionEdit.closeKeyboard(); captionEdit.ignoreTouches = true; } + if (previewView != null) { + previewView.updatePauseReason(8, toPage != PAGE_PREVIEW); + } } private void onNavigateEnd(int fromPage, int toPage) { @@ -3285,6 +3361,7 @@ private void onNavigateEnd(int fromPage, int toPage) { MediaDataController.getInstance(currentAccount).loadRecents(MediaDataController.TYPE_IMAGE, false, true, false); MediaDataController.getInstance(currentAccount).loadRecents(MediaDataController.TYPE_FAVE, false, true, false); MessagesController.getInstance(currentAccount).getStoriesController().loadBlocklistAtFirst(); + MessagesController.getInstance(currentAccount).getStoriesController().loadSendAs(); } } @@ -3344,8 +3421,8 @@ public void switchToEditMode(int editMode, boolean animated) { animators.add(ObjectAnimator.ofFloat(paintView.getWeightChooserView(), View.TRANSLATION_X, -AndroidUtilities.dp(32))); } - animators.add(ObjectAnimator.ofFloat(muteButton, View.ALPHA, editMode == EDIT_MODE_NONE && (isVideo || outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) ? 1 : 0)); - animators.add(ObjectAnimator.ofFloat(playButton, View.ALPHA, editMode == EDIT_MODE_NONE && isVideo ? 1 : 0)); + animators.add(ObjectAnimator.ofFloat(muteButton, View.ALPHA, editMode == EDIT_MODE_NONE && isVideo ? 1 : 0)); + animators.add(ObjectAnimator.ofFloat(playButton, View.ALPHA, editMode == EDIT_MODE_NONE && (isVideo || outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) ? 1 : 0)); animators.add(ObjectAnimator.ofFloat(downloadButton, View.ALPHA, editMode == EDIT_MODE_NONE ? 1 : 0)); // animators.add(ObjectAnimator.ofFloat(privacySelector, View.ALPHA, editMode == EDIT_MODE_NONE ? 1 : 0)); @@ -3505,6 +3582,7 @@ public void onEntityDragEnd(boolean delete) { @Override public void onEntityDragStart() { + paintView.showReactionsLayout(false); captionContainer.clearAnimation(); captionContainer.animate().alpha(0f).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); @@ -3519,6 +3597,7 @@ public void onEntityDragStart() { @Override public void onEntityDragMultitouchStart() { multitouch = true; + paintView.showReactionsLayout(false); trash.onDragInfo(false, false); trash.clearAnimation(); trash.animate().alpha(0f).withEndAction(() -> { @@ -3568,9 +3647,45 @@ protected void onOpenCloseStickersAlert(boolean open) { } } + @Override + protected void onAudioSelect(MessageObject messageObject) { + previewView.setupAudio(messageObject, true); + if (outputEntry != null && !isVideo) { + boolean appear = !TextUtils.isEmpty(outputEntry.audioPath); + playButton.drawable.setPause(!previewView.isPlaying(), false); + ((MarginLayoutParams) playButton.getLayoutParams()).rightMargin = dp(48 + (isVideo ? 48 : 0)); + playButton.setVisibility(View.VISIBLE); + playButton.animate().alpha(appear ? 1 : 0).withEndAction(() -> { + if (!appear) { + playButton.setVisibility(View.GONE); + } + }).start(); + } + switchToEditMode(EDIT_MODE_NONE, true); + } + @Override public void onEntityHandleTouched() { + paintView.showReactionsLayout(false); + } + @Override + protected boolean checkAudioPermission(Runnable granted) { + if (activity == null) { + return true; + } + if (Build.VERSION.SDK_INT >= 33) { + if (activity.checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_AUDIO}, 115); + audioGrantedCallback = granted; + return false; + } + } else if (Build.VERSION.SDK_INT >= 23 && activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 115); + audioGrantedCallback = granted; + return false; + } + return true; } }; paintView.setBlurManager(blurManager); @@ -3683,6 +3798,9 @@ private void onSwitchEditModeStart(int fromMode, int toMode) { if (isVideo) { muteButton.setVisibility(View.VISIBLE); playButton.setVisibility(View.VISIBLE); + } else if (outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) { + muteButton.setVisibility(View.GONE); + playButton.setVisibility(View.VISIBLE); } timelineView.setVisibility(View.VISIBLE); } @@ -4146,7 +4264,7 @@ private void requestCameraPermission(boolean force) { drawable.setIconSize(dp(64), dp(64)); cameraViewThumb.setImageDrawable(drawable); if (activity.shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) { - new AlertDialog.Builder(getContext()) + new AlertDialog.Builder(getContext(), resourcesProvider) .setTopAnimation(R.raw.permission_request_camera, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)) .setMessage(AndroidUtilities.replaceTags(LocaleController.getString("PermissionNoCameraWithHint", R.string.PermissionNoCameraWithHint))) .setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialogInterface, i) -> { @@ -4266,6 +4384,7 @@ public static void onRequestPermissionsResult(int requestCode, String[] permissi } } + private Runnable audioGrantedCallback; private void onRequestPermissionsResultInternal(int requestCode, String[] permissions, int[] grantResults) { final boolean granted = grantResults != null && grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED; if (requestCode == 111) { @@ -4285,7 +4404,7 @@ private void onRequestPermissionsResultInternal(int requestCode, String[] permis } } else if (requestCode == 112) { if (!granted) { - new AlertDialog.Builder(getContext()) + new AlertDialog.Builder(getContext(), resourcesProvider) .setTopAnimation(R.raw.permission_request_camera, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)) .setMessage(AndroidUtilities.replaceTags(LocaleController.getString("PermissionNoCameraMicVideo", R.string.PermissionNoCameraMicVideo))) .setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialogInterface, i) -> { @@ -4301,6 +4420,28 @@ private void onRequestPermissionsResultInternal(int requestCode, String[] permis .create() .show(); } + } else if (requestCode == 115) { + if (!granted) { + new AlertDialog.Builder(getContext(), resourcesProvider) + .setTopAnimation(R.raw.permission_request_folder, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.getString("PermissionNoAudioStorageStory", R.string.PermissionNoAudioStorageStory))) + .setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialogInterface, i) -> { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); + activity.startActivity(intent); + } catch (Exception e) { + FileLog.e(e); + } + }) + .setNegativeButton(LocaleController.getString("ContactsPermissionAlertNotNow", R.string.ContactsPermissionAlertNotNow), null) + .create() + .show(); + } + if (granted && audioGrantedCallback != null) { + audioGrantedCallback.run(); + } + audioGrantedCallback = null; } } @@ -4415,8 +4556,8 @@ private void checkBackgroundVisibility() { } public interface ClosingViewProvider { - void preLayout(Runnable runnable); - SourceView getView(); + void preLayout(long dialogId, Runnable runnable); + SourceView getView(long dialogId); } private void openPremium() { @@ -4518,6 +4659,16 @@ public void setIconMuted(boolean muted, boolean animated) { } } + public StoryRecorder selectedPeerId(long dialogId) { + this.selectedDialogId = dialogId; + return this; + } + + public StoryRecorder canChangePeer(boolean b) { + canChangePeer = b; + return this; + } + public static CharSequence cameraBtnSpan(Context context) { SpannableString cameraStr = new SpannableString("c"); Drawable cameraDrawable = context.getResources().getDrawable(R.drawable.story_camera).mutate(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java index 6269e26760f..c3747009b56 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java @@ -28,6 +28,7 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; +import android.util.Log; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; @@ -133,7 +134,7 @@ private long getBaseDuration() { private final RectF audioBounds = new RectF(); private final Path audioClipPath = new Path(); private final Paint waveformPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Path waveformPath = new Path(); + private final WaveformPath waveformPath = new WaveformPath(); private final Paint audioDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Drawable audioIcon; @@ -212,7 +213,7 @@ public TimelineView(Context context, ViewGroup container, View previewContainer, }) .setGravity(Gravity.RIGHT) .forceTop(true) - .translate(dp(6) - (w - uiRight), dp(4) + (!hasVideo ? dp(audioSelected ? 35 : 40) : 0)) + .translate(-(w - uiRight) + dp(18), dp(4) + (!hasVideo ? dp(audioSelected ? 35 : 40) : 0)) .show(); itemOptions.setBlurBackground(blurManager, -previewContainer.getX(), -previewContainer.getY()); @@ -260,12 +261,14 @@ private void setupVideoThumbs() { } } - private final AnimatedFloat loopProgress = new AnimatedFloat(0, this, 0, 200, CubicBezierInterpolator.EASE_BOTH); + private final AnimatedFloat loopProgress = new AnimatedFloat(0, this, 0, 340, CubicBezierInterpolator.EASE_OUT_QUINT); + private long loopProgressFrom = -1; public void setProgress(long progress) { if ( hasVideo && progress < this.progress && progress <= videoDuration * videoLeft + 240 && this.progress + 240 >= videoDuration * videoRight || hasAudio && progress < this.progress && progress <= audioDuration * audioLeft + 240 && this.progress + 240 >= audioDuration * audioRight ) { + loopProgressFrom = -1; loopProgress.set(1, true); } this.progress = progress; @@ -283,14 +286,17 @@ public void setVideoRight(float right) { } public void setAudio(String audioPath, String audioAuthorText, String audioTitleText, long duration, long offset, float left, float right, float volume, boolean animated) { - this.audioPath = audioPath; - if (waveform != null) { - waveform.destroy(); - waveform = null; - waveformIsLoaded = false; - waveformLoaded.set(0, true); + if (!TextUtils.equals(this.audioPath, audioPath)) { + if (waveform != null) { + waveform.destroy(); + waveform = null; + waveformIsLoaded = false; + waveformLoaded.set(0, true); + } + this.audioPath = audioPath; + setupAudioWaveform(); } - setupAudioWaveform(); + this.audioPath = audioPath; hasAudio = !TextUtils.isEmpty(audioPath); if (!hasAudio) { audioSelected = false; @@ -389,7 +395,7 @@ private int detectHandle(MotionEvent event) { final float maxDuration = Math.min(MAX_SCROLL_DURATION, getBaseDuration()); final float minLeft = Math.max(0, scroll - audioOffset) / (float) audioDuration; final float maxRight = Math.min(1, Math.max(0, scroll - audioOffset + maxDuration) / (float) audioDuration); - if (audioLeft > minLeft + .01f || audioRight < maxRight - .01f) { + if (!hasVideo) { return HANDLE_AUDIO_REGION; } else { return HANDLE_AUDIO_SCROLL; @@ -423,19 +429,19 @@ public boolean isDragging() { } private Runnable askExactSeek; - private void setProgressAt(float x, boolean fast) { + private boolean setProgressAt(float x, boolean fast) { if (!hasVideo && !hasAudio) { - return; + return false; } final long scrollWidth = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); final float t = (x - px - ph) / sw; long progress = (long) Utilities.clamp(t * scrollWidth + (!hasVideo ? -audioOffset : 0) + scroll, hasVideo ? videoDuration : audioDuration, 0); if (hasVideo && (progress / (float) videoDuration < videoLeft || progress / (float) videoDuration > videoRight)) { - return; + return false; } if (hasAudio && !hasVideo && (progress / (float) audioDuration < audioLeft || progress / (float) audioDuration > audioRight)) { - return; + return false; } this.progress = progress; invalidate(); @@ -453,6 +459,7 @@ private void setProgressAt(float x, boolean fast) { } }, 150); } + return true; } private float getVideoHeight() { @@ -476,6 +483,7 @@ private float getAudioHeight() { private boolean hadDragChange; private VelocityTracker velocityTracker; private boolean scrollingVideo = true; + private boolean scrolling = false; @Override public boolean onTouchEvent(MotionEvent event) { @@ -483,6 +491,10 @@ public boolean onTouchEvent(MotionEvent event) { return false; } + if (hasVideo && !hasAudio && event.getY() < h - py - getVideoHeight() - py && event.getAction() == MotionEvent.ACTION_DOWN) { + return false; + } + final long now = System.currentTimeMillis(); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (askExactSeek != null) { @@ -564,7 +576,7 @@ public boolean onTouchEvent(MotionEvent event) { } else if (pressHandle == HANDLE_AUDIO_LEFT || pressHandle == HANDLE_AUDIO_RIGHT || pressHandle == HANDLE_AUDIO_REGION) { float d = Δx / sw * (videoScrollDuration / (float) audioDuration); if (pressHandle == HANDLE_AUDIO_LEFT) { - float maxValue = audioRight - MIN_SELECT_DURATION / (float) audioDuration; + float maxValue = audioRight - minAudioSelect() / (float) audioDuration; float minValue = Math.max(0, scroll - audioOffset) / (float) audioDuration; if (!hasVideo) { minValue = Math.max(minValue, audioRight - MAX_SELECT_DURATION / (float) audioDuration); @@ -585,7 +597,7 @@ public boolean onTouchEvent(MotionEvent event) { } } else if (pressHandle == HANDLE_AUDIO_RIGHT) { float maxValue = Math.min(1, Math.max(0, scroll - audioOffset + videoScrollDuration) / (float) audioDuration); - float minValue = audioLeft + MIN_SELECT_DURATION / (float) audioDuration; + float minValue = audioLeft + minAudioSelect() / (float) audioDuration; if (!hasVideo) { maxValue = Math.min(maxValue, audioLeft + MAX_SELECT_DURATION / (float) audioDuration); if (!hadDragChange && d > 0 && audioRight >= (audioLeft + MAX_SELECT_DURATION / (float) audioDuration)) { @@ -617,10 +629,14 @@ public boolean onTouchEvent(MotionEvent event) { delegate.onAudioOffsetChange(audioOffset + (long) (audioLeft * audioDuration)); delegate.onAudioRightChange(audioRight); } + if (delegate != null) { + delegate.onProgressDragChange(true); + } } if (!hasVideo && (progress / (float) audioDuration < audioLeft || progress / (float) audioDuration > audioRight)) { progress = (long) (audioLeft * audioDuration); if (delegate != null) { + delegate.onProgressDragChange(true); delegate.onProgressChange(progress, false); } } @@ -629,46 +645,7 @@ public boolean onTouchEvent(MotionEvent event) { draggingProgress = false; } else if (pressHandle == HANDLE_AUDIO_SCROLL) { float d = Δx / sw * videoScrollDuration; - if (!hasVideo) { - audioOffset = Utilities.clamp(audioOffset + (long) d, 0, (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); - } else if (audioSelected) { - final long mx = (long) Math.max(getBaseDuration(), audioDuration); - final long mn = (long) Math.min(getBaseDuration(), audioDuration); - audioOffset = Utilities.clamp(audioOffset + (long) d, (long) (getBaseDuration() - audioDuration * audioRight), mn - mx); - } else { - audioOffset = Utilities.clamp(audioOffset + (long) d, (long) (getBaseDuration() - audioDuration * audioRight), (long) (-audioLeft * audioDuration)); - } - final float minLeft = Math.max(0, scroll - audioOffset) / (float) audioDuration; - final float maxRight = Math.min(1, Math.max(0, scroll - audioOffset + videoScrollDuration) / (float) audioDuration); - boolean changedLeftRight = false; - final float pastDuration = audioRight - audioLeft; - if (audioLeft < minLeft) { - audioLeft = minLeft; - audioRight = Math.min(1, audioLeft + pastDuration); - changedLeftRight = true; - } - if (audioRight > maxRight) { - audioRight = maxRight; - audioLeft = Math.max(0, audioRight - pastDuration); - changedLeftRight = true; - } - if (delegate != null && changedLeftRight) { - delegate.onAudioLeftChange(audioLeft); - delegate.onAudioRightChange(audioRight); - } - if (!hasVideo && (progress / (float) audioDuration < audioLeft || progress / (float) audioDuration > audioRight)) { - progress = (long) (audioLeft * audioDuration); - if (delegate != null) { - delegate.onProgressChange(progress, false); - } - } - invalidate(); - if (delegate != null) { - delegate.onAudioOffsetChange(audioOffset + (long) (audioLeft * audioDuration)); - } - if (!dragged && delegate != null) { - delegate.onProgressDragChange(true); - } + moveAudioOffset(d); dragged = true; draggingProgress = false; } else if (draggingProgress) { @@ -689,6 +666,7 @@ public boolean onTouchEvent(MotionEvent event) { } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { AndroidUtilities.cancelRunOnUIThread(this.onLongPress); scroller.abortAnimation(); + boolean scrollStopped = true; if (event.getAction() == MotionEvent.ACTION_UP) { if (System.currentTimeMillis() - pressTime <= ViewConfiguration.getTapTimeout() && !dragged) { if (!pressVideo && !audioSelected) { @@ -698,7 +676,12 @@ public boolean onTouchEvent(MotionEvent event) { audioSelected = false; invalidate(); } else { - setProgressAt(event.getX(), false); + long wasProgress = progress; + if (setProgressAt(event.getX(), false) && Math.abs(progress - wasProgress) > 400) { + loopProgressFrom = wasProgress; + loopProgress.set(1, true); + invalidate(); + } } } else if (pressHandle == HANDLE_VIDEO_SCROLL && velocityTracker != null) { velocityTracker.computeCurrentVelocity(1000); @@ -708,7 +691,9 @@ public boolean onTouchEvent(MotionEvent event) { final long videoScrollDuration = Math.min(videoDuration, MAX_SCROLL_DURATION); final int scrollX = (int) (px + scroll / (float) videoScrollDuration * sw); final int maxScrollX = (int) (px + (videoDuration - videoScrollDuration) / (float) videoScrollDuration * sw); - scroller.fling(scrollX, 0, -velocity, 0, px, maxScrollX, 0, 0); + scrolling = true; + scroller.fling(wasScrollX = scrollX, 0, -velocity, 0, px, maxScrollX, 0, 0); + scrollStopped = false; } } else if ((pressHandle == HANDLE_AUDIO_SCROLL || pressHandle == HANDLE_AUDIO_REGION && !dragged) && hasVideo && audioSelected && velocityTracker != null) { velocityTracker.computeCurrentVelocity(1000); @@ -716,10 +701,12 @@ public boolean onTouchEvent(MotionEvent event) { scrollingVideo = false; if (Math.abs(velocity) > dp(100)) { final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); - final int scrollX = (int) (px + audioOffset / (float) videoScrollDuration * sw); + final int scrollX = (int) (px + ph + audioOffset / (float) videoScrollDuration * sw); final long mx = (long) Math.max(getBaseDuration(), audioDuration); final long mn = (long) Math.min(getBaseDuration(), audioDuration); - scroller.fling(scrollX, 0, velocity, 0, (int) (px + ph + (mn - mx) / (float) videoScrollDuration * sw), px + ph, 0, 0); + scrolling = true; + scroller.fling(wasScrollX = scrollX, 0, velocity, 0, (int) (px + ph + (long) ((videoLeft * videoDuration) - (1 * audioDuration)) / (float) videoScrollDuration * sw), (int) (px + ph + (long) ((videoRight * videoDuration) - (0 * audioDuration)) / (float) videoScrollDuration * sw), 0, 0); + scrollStopped = false; } } } @@ -727,7 +714,7 @@ public boolean onTouchEvent(MotionEvent event) { AndroidUtilities.cancelRunOnUIThread(askExactSeek); askExactSeek = null; } - if (dragged && delegate != null) { + if (dragged && scrollStopped && delegate != null) { delegate.onProgressDragChange(false); } dragged = false; @@ -743,10 +730,104 @@ public boolean onTouchEvent(MotionEvent event) { return true; } + private long minAudioSelect() { + return (long) Math.max(MIN_SELECT_DURATION, Math.min(videoDuration, MAX_SELECT_DURATION) * 0.25f); + } + + private void moveAudioOffset(final float d) { + final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); + if (!hasVideo) { + audioOffset = Utilities.clamp(audioOffset + (long) d, 0, (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); + } else if (audioSelected) { + long mx = (long) ((videoRight * videoDuration) - (audioRight * audioDuration)); + long mn = (long) ((videoLeft * videoDuration) - (audioLeft * audioDuration)); + final float wasDuration = Math.min(audioRight - audioLeft, (videoRight - videoLeft) * videoDuration / (float) audioDuration); + if (audioOffset + (long) d > mx) { + audioRight = Utilities.clamp((videoRight * videoDuration - audioOffset - (long) d) / (float) audioDuration, 1, wasDuration); + audioLeft = Utilities.clamp(audioRight - wasDuration, 1, 0); + long mmx = (long) ((videoRight * videoDuration) - (audioRight * audioDuration)); + long mmn = (long) ((videoLeft * videoDuration) - (audioLeft * audioDuration)); + if (mmx < mmn) { + long t = mmx; + mmx = mmn; + mmn = t; + } + audioOffset = Utilities.clamp(audioOffset + (long) d, mmx, mmn); + if (delegate != null) { + delegate.onAudioRightChange(audioRight); + } + } else if (audioOffset + (long) d < mn) { + audioLeft = Utilities.clamp((videoLeft * videoDuration - audioOffset - (long) d) / (float) audioDuration, 1 - wasDuration, 0); + audioRight = Utilities.clamp(audioLeft + wasDuration, 1, 0); + long mmx = (long) ((videoRight * videoDuration) - (audioRight * audioDuration)); + long mmn = (long) ((videoLeft * videoDuration) - (audioLeft * audioDuration)); + if (mmx < mmn) { + long t = mmx; + mmx = mmn; + mmn = t; + } + audioOffset = Utilities.clamp(audioOffset + (long) d, mmx, mmn); + if (delegate != null) { + delegate.onAudioLeftChange(audioLeft); + } + } else { + audioOffset += (long) d; + } + } else { + audioOffset = Utilities.clamp(audioOffset + (long) d, (long) (getBaseDuration() - audioDuration * audioRight), (long) (-audioLeft * audioDuration)); + } +// final float minLeft = Math.max(0, scroll - audioOffset) / (float) audioDuration; +// final float maxRight = Math.min(1, Math.max(0, scroll - audioOffset + videoScrollDuration) / (float) audioDuration); +// boolean changedLeftRight = false; +// final float pastDuration = audioRight - audioLeft; +// if (audioLeft < minLeft) { +// audioLeft = minLeft; +// audioRight = Math.min(1, audioLeft + pastDuration); +// changedLeftRight = true; +// } +// if (audioRight > maxRight) { +// audioRight = maxRight; +// audioLeft = Math.max(0, audioRight - pastDuration); +// changedLeftRight = true; +// } +// if (delegate != null && changedLeftRight) { +// delegate.onAudioLeftChange(audioLeft); +// delegate.onAudioRightChange(audioRight); +// } + if (!hasVideo && (progress / (float) audioDuration < audioLeft || progress / (float) audioDuration > audioRight)) { + progress = (long) (audioLeft * audioDuration); + if (delegate != null) { + delegate.onProgressChange(progress, false); + } + } + invalidate(); + if (delegate != null) { + delegate.onAudioOffsetChange(audioOffset + (long) (audioLeft * audioDuration)); + } + if (!dragged && delegate != null) { + delegate.onProgressDragChange(true); + + if (hasVideo) { + long progressToStart = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + if (Math.abs(progress - progressToStart) > 400) { + loopProgressFrom = progress; + loopProgress.set(1, true); + } + delegate.onProgressChange(progress = progressToStart, false); + } + } else if ((dragged || scrolling) && hasVideo) { + progress = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + if (delegate != null) { + delegate.onProgressChange(progress, false); + } + } + } + + private int wasScrollX; @Override public void computeScroll() { if (scroller.computeScrollOffset()) { - float scrollX = scroller.getCurrX(); + int scrollX = scroller.getCurrX(); final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); if (scrollingVideo) { long wasScroll = scroll; @@ -758,27 +839,105 @@ public void computeScroll() { // delegate.onVideoRightChange(videoRight); // } } else { - audioOffset = (long) ((scrollX - px - ph) / (float) sw * videoScrollDuration); - final float minLeft = Math.max(0, scroll - audioOffset) / (float) audioDuration; - final float maxRight = Math.min(1, Math.max(0, scroll - audioOffset + videoScrollDuration) / (float) audioDuration); - boolean changedLeftRight = false; - final float pastDuration = audioRight - audioLeft; - if (audioLeft < minLeft) { - audioLeft = minLeft; - audioRight = Math.min(1, audioLeft + pastDuration); - changedLeftRight = true; - } - if (audioRight > maxRight) { - audioRight = maxRight; - audioLeft = Math.max(0, audioRight - pastDuration); - changedLeftRight = true; + final float d = ((scrollX - px - ph) / (float) sw * videoScrollDuration) - ((wasScrollX - px - ph) / (float) sw * videoScrollDuration); + moveAudioOffset(d); + } + invalidate(); + wasScrollX = scrollX; + } else if (scrolling) { + scrolling = false; + if (delegate != null) { + delegate.onProgressDragChange(false); + } + } + } + + class WaveformPath extends Path { + + private int lastWaveformCount; + private float lastAnimatedLoaded; + private long lastScrollDuration; + private float lastAudioHeight; + private float lastMaxBar; + private float lastAudioSelected; + private float lastBottom; + private float lastStart; + private float lastLeft; + private float lastRight; + + public void check( + float start, float left, float right, + float audioSelected, + float animatedLoaded, + long scrollDuration, + float audioHeight, + float maxBar, + float bottom + ) { + if (waveform == null) { + rewind(); + return; + } + if (lastWaveformCount != waveform.getCount() || + Math.abs(lastAnimatedLoaded - animatedLoaded) > 0.01f || + lastScrollDuration != scrollDuration || + Math.abs(lastAudioHeight - audioHeight) > 1f || + Math.abs(lastMaxBar - maxBar) > 0.01f || + Math.abs(lastAudioSelected - audioSelected) > 0.1f || + Math.abs(lastBottom - bottom) > 1f || + Math.abs(lastStart - start) > 1f || + Math.abs(lastLeft - left) > 1f || + Math.abs(lastRight - right) > 1f + ) { + lastWaveformCount = waveform.getCount(); + layout( + lastStart = start, lastLeft = left, lastRight = right, + lastAudioSelected = audioSelected, + lastAnimatedLoaded = animatedLoaded, + lastScrollDuration = scrollDuration, + lastMaxBar = maxBar, + lastAudioHeight = audioHeight, + lastBottom = bottom + ); + } + } + + private void layout( + float start, float left, float right, + float audioSelected, + float animatedLoaded, + long scrollDuration, + float maxBar, + float audioHeight, + float bottom + ) { + waveformPath.rewind(); + final float barWidth = Math.round(dpf2(3.3333f)); + int from = Math.max(0, (int) ((left - ph - start) / barWidth)); + int to = Math.min(waveform.getCount() - 1, (int) Math.ceil((right + ph - start) / barWidth)); + for (int i = from; i <= to; ++i) { + float x = start + i * barWidth + dp(2); + float h = maxBar <= 0 ? 0 : waveform.getBar(i) / (float) maxBar * audioHeight * .6f; + if (i < animatedLoaded && i + 1 > animatedLoaded) { + h *= (animatedLoaded - i); + } else if (i > animatedLoaded) { + h = 0; } - if (delegate != null && changedLeftRight) { - delegate.onAudioLeftChange(audioLeft); - delegate.onAudioRightChange(audioRight); + if (x < left || x > right) { + h *= audioSelected; + if (h <= 0) { + continue; + } } + h = Math.max(h, lerp(dpf2(0.66f), dpf2(1.5f), audioSelected)); + AndroidUtilities.rectTmp.set( + x, + lerp(bottom - h, bottom - (audioHeight + h) / 2f, audioSelected), + x + dpf2(1.66f), + lerp(bottom, bottom - (audioHeight - h) / 2f, audioSelected) + ); + waveformPath.addRoundRect(AndroidUtilities.rectTmp, waveformRadii, Path.Direction.CW); } - invalidate(); } } @@ -859,7 +1018,7 @@ protected void dispatchDraw(Canvas canvas) { Path.Direction.CW ); canvas.clipPath(selectedVideoClipPath, Region.Op.DIFFERENCE); - canvas.drawColor(0x80000000); + canvas.drawColor(0x50000000); canvas.restore(); } @@ -902,34 +1061,8 @@ protected void dispatchDraw(Canvas canvas) { final float maxBar = waveformMax.set(waveform.getMaxBar(), !waveformIsLoaded); waveformIsLoaded = waveform.getLoadedCount() > 0; final float animatedLoaded = waveformLoaded.set(waveform.getLoadedCount()); - final float barWidth = Math.round(dpf2(3.3333f)); - waveformPath.rewind(); final float start = px + ph + (audioOffset - scroll) / (float) scrollDuration * sw; - int from = Math.max(0, (int) ((left - ph - start) / barWidth)); - int to = Math.min(waveform.getCount() - 1, (int) Math.ceil((right + ph - start) / barWidth)); - for (int i = from; i <= to; ++i) { - float x = start + i * barWidth + dp(2); - float h = maxBar <= 0 ? 0 : waveform.getBar(i) / (float) maxBar * audioHeight * .6f; - if (i < animatedLoaded && i + 1 > animatedLoaded) { - h *= (animatedLoaded - i); - } else if (i > animatedLoaded) { - h = 0; - } - if (x < left || x > right) { - h *= audioSelected; - if (h <= 0) { - continue; - } - } - h = Math.max(h, lerp(dpf2(0.66f), dpf2(1.5f), audioSelected)); - AndroidUtilities.rectTmp.set( - x, - lerp(bottom - h, bottom - (audioHeight + h) / 2f, audioSelected), - x + dpf2(1.66f), - lerp(bottom, bottom - (audioHeight - h) / 2f, audioSelected) - ); - waveformPath.addRoundRect(AndroidUtilities.rectTmp, waveformRadii, Path.Direction.CW); - } + waveformPath.check(start, left, right, audioSelected, animatedLoaded, scrollDuration, audioHeight, maxBar, bottom); canvas.drawPath(waveformPath, paint); } @@ -994,21 +1127,33 @@ protected void dispatchDraw(Canvas canvas) { final float right = lerp(videoRight * videoDuration, audioOffset + audioRight * audioDuration, hasVideo ? audioSelected : 1); float leftX = px + ph + (left - scroll) / (float) scrollDuration * sw; float rightX = px + ph + (right - scroll) / (float) scrollDuration * sw; + float progressAlpha = (hasAudio && !hasVideo ? audioT : videoT); if (audioT > 0. || videoT > 0.) { - drawRegion(canvas, blurPaint, regionTop, regionBottom, leftX, rightX, hasVideo ? 1 : lerp(.6f, 1f, audioSelected) * audioT); + drawRegion(canvas, blurPaint, regionTop, regionBottom, leftX, rightX, (hasVideo ? 1 : lerp(.6f, 1f, audioSelected) * audioT) * progressAlpha); + if (hasVideo && hasAudio && audioSelected > 0) { + drawRegion( + canvas, + blurPaint, + h - py - videoHeight, + h - py, + ph + px + (videoLeft * videoDuration - scroll) / (float) scrollDuration * sw, + ph + px + (videoRight * videoDuration - scroll) / (float) scrollDuration * sw, + .8f + ); + } // draw progress float loopT = loopProgress.set(0); final float y1 = h - py - videoHeight - (audioHeight + p * videoT) * audioT - dpf2(4.3f); final float y2 = h - py + dpf2(4.3f); if (loopT > 0) { - drawProgress(canvas, y1, y2, (long) (hasVideo ? videoDuration * videoRight : audioDuration * audioRight), loopT); + drawProgress(canvas, y1, y2, loopProgressFrom != -1 ? loopProgressFrom : (long) (hasVideo ? videoDuration * videoRight : audioDuration * audioRight), loopT * progressAlpha); } - drawProgress(canvas, y1, y2, progress, 1f - loopT); + drawProgress(canvas, y1, y2, progress, (1f - loopT) * progressAlpha); } if (dragged) { - long Δd = (long) (dp(86) / (float) sw * scrollDuration * (1f / (1000f / AndroidUtilities.screenRefreshRate))); + long Δd = (long) (dp(32) / (float) sw * scrollDuration * (1f / (1000f / AndroidUtilities.screenRefreshRate))); if (pressHandle == HANDLE_VIDEO_REGION) { int direction = 0; if (videoLeft < (scroll / (float) videoDuration)) { @@ -1032,35 +1177,47 @@ protected void dispatchDraw(Canvas canvas) { delegate.onVideoRightChange(videoRight); } invalidate(); - } else if (!hasVideo && pressHandle == HANDLE_AUDIO_REGION) { + } else if (pressHandle == HANDLE_AUDIO_REGION) { int direction = 0; if (audioLeft < ((-audioOffset + 100) / (float) audioDuration)) { direction = -1; } else if (audioRight >= ((-audioOffset + scrollDuration - 100) / (float) audioDuration)) { direction = +1; } - long wasOffset = audioOffset; - audioOffset = Utilities.clamp(audioOffset - direction * Δd, 0, (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); - float d = -(audioOffset - wasOffset) / (float) audioDuration; - if (d > 0) { - d = Math.min(1 - audioRight, d); - } else { - d = Math.max(0 - audioLeft, d); - } - progress = (long) Utilities.clamp(progress + d * audioDuration, audioDuration, 0); - audioLeft = Utilities.clamp(audioLeft + d, 1, 0); - audioRight = Utilities.clamp(audioRight + d, 1, 0); - if (delegate != null) { - delegate.onAudioLeftChange(audioLeft); - delegate.onAudioRightChange(audioRight); - delegate.onProgressChange(progress, false); + if (direction != 0) { + long wasOffset = audioOffset; + if (this.audioSelected && hasVideo) { + audioOffset = Utilities.clamp(audioOffset - direction * Δd, (long) ((videoRight * videoDuration) - (audioLeft * audioDuration)), (long) ((videoLeft * videoDuration) - (audioRight * audioDuration))); + } else { + audioOffset = Utilities.clamp(audioOffset - direction * Δd, 0, (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); + } + float d = -(audioOffset - wasOffset) / (float) audioDuration; + if (d > 0) { + d = Math.min(1 - audioRight, d); + } else { + d = Math.max(0 - audioLeft, d); + } + if (!hasVideo) { + progress = (long) Utilities.clamp(progress + d * audioDuration, audioDuration, 0); + } + audioLeft = Utilities.clamp(audioLeft + d, 1, 0); + audioRight = Utilities.clamp(audioRight + d, 1, 0); + if (delegate != null) { + delegate.onAudioLeftChange(audioLeft); + delegate.onAudioRightChange(audioRight); + delegate.onProgressChange(progress, false); + } + invalidate(); } - invalidate(); } } } private void drawRegion(Canvas canvas, Paint blurPaint, float top, float bottom, float left, float right, float alpha) { + if (alpha <= 0) { + return; + } + AndroidUtilities.rectTmp.set(left - dp(10), top, right + dp(10), bottom); canvas.saveLayerAlpha(0, 0, w, h, 0xFF, Canvas.ALL_SAVE_FLAG); regionPaint.setAlpha((int) (0xFF * alpha)); @@ -1070,6 +1227,7 @@ private void drawRegion(Canvas canvas, Paint blurPaint, float top, float bottom, final float hw = dp(2), hh = dp(10); Paint handlePaint = blurPaint != null ? blurPaint : regionHandlePaint; + regionHandlePaint.setAlpha(0xFF); handlePaint.setAlpha((int) (0xFF * alpha)); AndroidUtilities.rectTmp.set( left - (dp(10) - hw) / 2f, @@ -1078,6 +1236,10 @@ private void drawRegion(Canvas canvas, Paint blurPaint, float top, float bottom, (top + bottom + hh) / 2f ); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(1), dp(1), handlePaint); + if (blurPaint != null) { + regionHandlePaint.setAlpha((int) (0x30 * alpha)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(1), dp(1), regionHandlePaint); + } AndroidUtilities.rectTmp.set( right + (dp(10) - hw) / 2f, (top + bottom - hh) / 2f, @@ -1085,6 +1247,10 @@ private void drawRegion(Canvas canvas, Paint blurPaint, float top, float bottom, (top + bottom + hh) / 2f ); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(1), dp(1), handlePaint); + if (blurPaint != null) { + regionHandlePaint.setAlpha((int) (0x30 * alpha)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(1), dp(1), regionHandlePaint); + } canvas.restore(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/VolumeSliderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/VolumeSliderView.java index ac60c2d4de7..3ff01db57a7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/VolumeSliderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/VolumeSliderView.java @@ -13,9 +13,11 @@ import android.graphics.drawable.Drawable; import android.text.TextPaint; import android.text.TextUtils; +import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import androidx.annotation.NonNull; @@ -32,6 +34,8 @@ public class VolumeSliderView extends View { private float minVolume = 0; private float maxVolume = 1.5f; private float value; + private boolean valueIsAnimated; + private AnimatedFloat valueAnimated = new AnimatedFloat(this, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT); private Utilities.Callback onValueChange; private final Paint whitePaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -95,9 +99,12 @@ protected void dispatchDraw(Canvas canvas) { canvas.save(); AndroidUtilities.rectTmp.set(0, 0, w, h); + clipPath.rewind(); clipPath.addRoundRect(AndroidUtilities.rectTmp, r, r, Path.Direction.CW); canvas.clipPath(clipPath); + float value = valueIsAnimated ? valueAnimated.set(this.value) : this.value; + canvas.saveLayerAlpha(0, 0, w, h, 0xFF, Canvas.ALL_SAVE_FLAG); text.setBounds(dp(42), -dp(1), w, h - dp(1)); @@ -131,6 +138,7 @@ protected void dispatchDraw(Canvas canvas) { private float lastTouchX; + private long pressTime; @Override public boolean dispatchTouchEvent(MotionEvent event) { @@ -139,18 +147,34 @@ public boolean dispatchTouchEvent(MotionEvent event) { } final float x = event.getX(); - if (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_UP) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + pressTime = System.currentTimeMillis(); + valueIsAnimated = false; + } else if (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_UP) { float pastVolume = this.maxVolume - this.minVolume != 0 ? this.minVolume + this.value * (this.maxVolume - this.minVolume) : 0; - value = Utilities.clamp(value + (x - lastTouchX) / w, 1, 0); + boolean vibrate = true; + if (event.getAction() == MotionEvent.ACTION_UP && (System.currentTimeMillis() - pressTime) < ViewConfiguration.getTapTimeout()) { + valueAnimated.set(value, true); + value = x / w; + valueIsAnimated = true; + vibrate = false; + } else { + value = Utilities.clamp(value + (x - lastTouchX) / w, 1, 0); + valueIsAnimated = false; + } final float volume = this.maxVolume - this.minVolume != 0 ? this.minVolume + this.value * (this.maxVolume - this.minVolume) : 0; - if (volume <= this.minVolume && pastVolume > volume || volume >= this.maxVolume && pastVolume < volume) { - try { - performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - } catch (Exception ignore) {} - } else if (Math.floor(pastVolume * 5) != Math.floor(volume * 5)) { - try { - performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - } catch (Exception ignore) {} + if (vibrate) { + if (volume <= this.minVolume && pastVolume > volume || volume >= this.maxVolume && pastVolume < volume) { + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception ignore) { + } + } else if (Math.floor(pastVolume * 5) != Math.floor(volume * 5)) { + try { + performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception ignore) { + } + } } updateText(volume); if (onValueChange != null) { @@ -166,6 +190,7 @@ private void updateText(float volume) { String string = Math.round(volume * 100) + "%"; if (!TextUtils.equals(text.getText(), string)) { text.cancelAnimation(); + text.setAnimationProperties(.3f, 0, valueIsAnimated ? 320 : 40, CubicBezierInterpolator.EASE_OUT_QUINT); text.setText(string); } } diff --git a/TMessagesProj/src/main/res/raw/boosts.json b/TMessagesProj/src/main/res/raw/boosts.json new file mode 100644 index 00000000000..306770b485e --- /dev/null +++ b/TMessagesProj/src/main/res/raw/boosts.json @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":49,"w":512,"h":512,"nm":"Boost Stroke-Fill","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Flash Fill","sr":1,"ks":{"p":{"a":0,"k":[256.5,255.5,0]},"a":{"a":0,"k":[0.5,-0.5,0]},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.7],"y":[0,0,0]},"t":0,"s":[100,100,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":9,"s":[115,90,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":17,"s":[96,103,100]},{"t":24,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":9,"s":[{"i":[[3.252,-3.913],[0,0],[-6.372,-4.121],[-3.502,0],[0,0],[0,-6.447],[0.136,-0.635],[0,0],[-7.961,-1.328],[-3.313,4.085],[0,0],[6.435,4.061],[3.441,0],[0,0],[0,8.071],[-0.101,0.695],[0,0],[7.988,1.159]],"o":[[0,0],[-5.295,4.958],[2.694,1.742],[0,0],[9.33,0.133],[0,0.643],[0,0],[-1.328,7.961],[5.188,0.865],[0,0],[5.219,-5.007],[-2.673,-1.687],[0,0],[-8.285,0],[0,-0.702],[0,0],[1.159,-7.988],[-5.035,-0.731]],"v":[[45.668,-207.745],[-146.988,-1.258],[-146.115,18.934],[-134.966,20.792],[-67.462,20.703],[-52.191,34.025],[-52.396,35.945],[-69.121,195],[-57.11,211.82],[-43.356,206.61],[148.638,-5.206],[145.709,-25.221],[136.259,-27.828],[70.149,-27.423],[58.335,-43.695],[58.487,-45.794],[71.37,-196.305],[59.007,-212.867]],"c":true}]},{"t":17,"s":[{"i":[[3.252,-3.913],[0,0],[-6.208,-5.159],[-3.412,0],[0,0],[0,-8.071],[0.133,-0.795],[0,0],[-7.961,-1.328],[-3.313,4.085],[0,0],[6.269,5.084],[3.352,0],[0,0],[0,8.071],[-0.101,0.695],[0,0],[7.988,1.159]],"o":[[0,0],[-5.159,6.208],[2.624,2.181],[0,0],[8.071,0],[0,0.806],[0,0],[-1.328,7.961],[5.188,0.865],[0,0],[5.084,-6.269],[-2.603,-2.112],[0,0],[-8.071,0],[0,-0.702],[0,0],[1.159,-7.988],[-5.035,-0.731]],"v":[[52.66,-229.723],[-139.709,1.768],[-137.809,22.348],[-128.469,25.722],[-63.081,25.722],[-48.467,40.336],[-48.666,42.741],[-77.727,216.978],[-65.716,233.798],[-51.962,228.588],[140.819,-9.104],[138.674,-29.66],[129.468,-32.924],[68.348,-32.924],[53.734,-47.538],[53.885,-49.637],[78.363,-218.283],[65.999,-234.845]],"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":"Path","bm":0,"hd":false}],"ip":9,"op":24,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Flash Stroke","parent":1,"sr":1,"ks":{"p":{"a":0,"k":[0.027,-0.157,0]},"a":{"a":0,"k":[0.027,-0.157,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.7,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,-6.681],[0.146,-0.756],[0,0],[-5.153,-0.996],[-2.194,2.841],[0,0],[5.288,4.083],[2.676,0],[0,0],[0,6.681],[-0.119,0.685],[0,0],[5.171,0.899],[2.162,-2.733],[0,0],[-5.24,-4.145],[-2.725,0],[0,0],[0,0],[0,0],[0,0],[8.003,5.767],[0,0],[-16.139,20.399],[0,0],[-16.079,-2.796],[4.211,-24.215],[0,0],[0,0],[0,0],[-7.922,-5.577],[0,0],[15.897,-20.588],[0,0],[16.502,3.188],[-4.662,24.132],[0,0],[0,0]],"o":[[0,0],[6.681,0],[0,0.77],[0,0],[-0.996,5.153],[3.524,0.681],[0,0],[4.083,-5.288],[-2.118,-1.635],[0,0],[-6.681,0],[0,-0.695],[0,0],[0.899,-5.171],[-3.434,-0.597],[0,0],[-4.145,5.24],[2.137,1.69],[0,0],[0,0],[0,0],[0,0],[-9.9,0],[0,0],[-20.399,-16.139],[0,0],[10.126,-12.799],[24.215,4.211],[0,0],[0,0],[0,0],[9.722,0],[0,0],[20.588,15.897],[0,0],[-10.272,13.303],[-24.132,-4.662],[0,0],[0,0],[0,0]],"v":[[-74.271,21.419],[-44.141,21.419],[-32.043,33.516],[-32.263,35.811],[-61.217,185.685],[-53.689,196.818],[-44.365,193.295],[110.79,-7.636],[108.609,-24.605],[101.215,-27.127],[47.573,-27.127],[35.476,-39.225],[35.655,-41.297],[60.85,-186.173],[53.116,-197.164],[44.035,-193.698],[-110.65,1.816],[-108.668,18.809],[-101.162,21.419],[-74.271,21.419],[-76.458,56.417],[-93.96,56.418],[-101.162,56.419],[-128.695,47.533],[-130.385,46.257],[-138.098,-19.901],[16.587,-215.414],[59.113,-231.646],[95.333,-180.176],[74.797,-62.129],[92.349,-62.128],[101.215,-62.127],[128.326,-53.541],[130,-52.307],[138.492,13.755],[-16.663,214.687],[-60.328,231.182],[-95.582,179.046],[-71.895,56.416],[-76.458,56.416]],"c":true}]},{"t":9,"s":[{"i":[[0,0],[0,0],[0,-0.022],[0.001,-0.002],[0,0],[-0.022,-0.003],[-0.009,0.009],[0,0],[0.023,0.013],[0.012,0],[0,0],[0,0.022],[0,0.002],[0,0],[0.022,0.003],[0.009,-0.009],[0,0],[-0.023,-0.014],[-0.012,0],[0,0],[0,0],[23.809,-0.211],[0,0],[5.312,2.228],[0,0],[-10.637,9.86],[0,0],[-11.056,-2.509],[3.568,-22.092],[0.84,-4.503],[-11.124,-0.264],[0,0],[-6.258,-1.811],[0,0],[7.319,-6.64],[0,0],[10.086,2.917],[-4.662,21.904],[0,0],[0,0]],"o":[[0,0],[0.029,0],[0,0.003],[0,0],[-0.004,0.017],[0.015,0.002],[0,0],[0.018,-0.017],[-0.009,-0.005],[0,0],[-0.029,0],[0,-0.002],[0,0],[0.004,-0.017],[-0.015,-0.002],[0,0],[-0.018,0.017],[0.009,0.006],[0,0],[0,0],[0,0],[-10.441,0.092],[-10.634,0],[0,0],[-8.53,-4.092],[0,0],[9.783,-11.908],[16.628,3.773],[0,0],[-1.827,10.675],[12.503,0.296],[10.444,0],[0,0],[8.822,3.823],[0,0],[-10.272,12.074],[-10.245,-2.963],[0,0],[0,0],[0,0]],"v":[[-0.134,-0.888],[-0.004,-0.888],[0.048,-0.848],[0.047,-0.841],[-0.078,-0.348],[-0.046,-0.311],[-0.006,-0.323],[0.663,-0.984],[0.654,-1.04],[0.622,-1.048],[0.391,-1.048],[0.339,-1.088],[0.339,-1.095],[0.448,-1.571],[0.415,-1.607],[0.375,-1.596],[-0.291,-0.953],[-0.283,-0.897],[-0.25,-0.888],[-0.134,-0.888],[-53.385,37.31],[-72.945,21.139],[-102.614,20.606],[-144.005,19.777],[-145.819,18.73],[-139.201,-9.277],[25.139,-186.149],[59.159,-212.552],[67.619,-164.215],[58.92,-43.742],[74.259,-27.544],[105.874,-28.117],[142.036,-27.418],[145.019,-26.128],[145.551,-1.36],[-29.439,192.03],[-58.911,212.353],[-68.415,176.604],[-53.452,37.412],[-53.385,37.31]],"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":9,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Flash Fill 2","sr":1,"ks":{"p":{"a":0,"k":[256.5,255.5,0]},"a":{"a":0,"k":[0.5,-0.5,0]},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.7],"y":[0,0,0]},"t":24,"s":[100,100,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":33,"s":[117,90,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":41,"s":[93,104,100]},{"t":48,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.7,"y":0},"t":24,"s":[{"i":[[3.252,-3.913],[0,0],[-6.208,-5.159],[-3.412,0],[0,0],[0,-8.071],[0.133,-0.795],[0,0],[-7.961,-1.328],[-3.313,4.085],[0,0],[6.269,5.084],[3.352,0],[0,0],[0,8.071],[-0.101,0.695],[0,0],[7.988,1.159]],"o":[[0,0],[-5.159,6.208],[2.624,2.181],[0,0],[8.071,0],[0,0.806],[0,0],[-1.328,7.961],[5.188,0.865],[0,0],[5.084,-6.269],[-2.603,-2.112],[0,0],[-8.071,0],[0,-0.702],[0,0],[1.159,-7.988],[-5.035,-0.731]],"v":[[52.66,-229.723],[-139.709,1.768],[-137.809,22.348],[-128.469,25.722],[-63.081,25.722],[-48.467,40.336],[-48.666,42.741],[-77.727,216.978],[-65.716,233.798],[-51.962,228.588],[140.819,-9.104],[138.674,-29.66],[129.468,-32.924],[68.348,-32.924],[53.734,-47.538],[53.885,-49.637],[78.363,-218.283],[65.999,-234.845]],"c":true}]},{"t":33,"s":[{"i":[[3.252,-3.913],[0,0],[-6.372,-4.121],[-3.502,0],[0,0],[0,-6.447],[0.136,-0.635],[0,0],[-7.961,-1.328],[-3.313,4.085],[0,0],[6.435,4.061],[3.441,0],[0,0],[0,8.071],[-0.101,0.695],[0,0],[7.988,1.159]],"o":[[0,0],[-5.295,4.958],[2.694,1.742],[0,0],[9.33,0.133],[0,0.643],[0,0],[-1.328,7.961],[5.188,0.865],[0,0],[5.219,-5.007],[-2.673,-1.687],[0,0],[-8.285,0],[0,-0.702],[0,0],[1.159,-7.988],[-5.035,-0.731]],"v":[[45.668,-207.745],[-146.988,-1.258],[-146.115,18.934],[-134.966,20.792],[-67.462,20.703],[-52.191,34.025],[-52.396,35.945],[-69.121,195],[-57.11,211.82],[-43.356,206.61],[148.638,-5.206],[145.709,-25.221],[136.259,-27.828],[70.149,-27.423],[58.335,-43.695],[58.487,-45.794],[71.37,-196.305],[59.007,-212.867]],"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":"Path","bm":0,"hd":false}],"ip":24,"op":34,"st":15,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Flash Stroke 2","parent":3,"sr":1,"ks":{"p":{"a":0,"k":[0.027,-0.157,0]},"a":{"a":0,"k":[0.027,-0.157,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":33,"s":[{"i":[[0,0],[0,0],[0,-0.022],[0.001,-0.002],[0,0],[-0.022,-0.003],[-0.009,0.009],[0,0],[0.023,0.013],[0.012,0],[0,0],[0,0.022],[0,0.002],[0,0],[0.022,0.003],[0.009,-0.009],[0,0],[-0.023,-0.014],[-0.012,0],[0,0],[0,0],[23.809,-0.211],[0,0],[5.312,2.228],[0,0],[-10.637,9.86],[0,0],[-11.056,-2.509],[3.568,-22.092],[0.84,-4.503],[-11.124,-0.264],[0,0],[-6.258,-1.811],[0,0],[7.319,-6.64],[0,0],[10.086,2.917],[-4.662,21.904],[0,0],[0,0]],"o":[[0,0],[0.029,0],[0,0.003],[0,0],[-0.004,0.017],[0.015,0.002],[0,0],[0.018,-0.017],[-0.009,-0.005],[0,0],[-0.029,0],[0,-0.002],[0,0],[0.004,-0.017],[-0.015,-0.002],[0,0],[-0.018,0.017],[0.009,0.006],[0,0],[0,0],[0,0],[-10.441,0.092],[-10.634,0],[0,0],[-8.53,-4.092],[0,0],[9.783,-11.908],[16.628,3.773],[0,0],[-1.827,10.675],[12.503,0.296],[10.444,0],[0,0],[8.822,3.823],[0,0],[-10.272,12.074],[-10.245,-2.963],[0,0],[0,0],[0,0]],"v":[[-0.134,-0.888],[-0.004,-0.888],[0.048,-0.848],[0.047,-0.841],[-0.078,-0.348],[-0.046,-0.311],[-0.006,-0.323],[0.663,-0.984],[0.654,-1.04],[0.622,-1.048],[0.391,-1.048],[0.339,-1.088],[0.339,-1.095],[0.448,-1.571],[0.415,-1.607],[0.375,-1.596],[-0.291,-0.953],[-0.283,-0.897],[-0.25,-0.888],[-0.134,-0.888],[-53.385,37.31],[-72.945,21.139],[-102.614,20.606],[-144.005,19.777],[-145.819,18.73],[-139.201,-9.277],[25.139,-186.149],[59.159,-212.552],[67.619,-164.215],[58.92,-43.742],[74.259,-27.544],[105.874,-28.117],[142.036,-27.418],[145.019,-26.128],[145.551,-1.36],[-29.439,192.03],[-58.911,212.353],[-68.415,176.604],[-53.452,37.412],[-53.385,37.31]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":41,"s":[{"i":[[0,0],[0,0],[0,-7.21],[0.158,-0.816],[0,0],[-5.393,-1.042],[-2.296,2.973],[0,0],[5.453,4.21],[2.759,0],[0,0],[0,7.21],[-0.128,0.739],[0,0],[5.412,0.941],[2.263,-2.861],[0,0],[-5.655,-4.474],[-4.017,0.296],[0,0],[0,0],[0,0],[0,0],[8.003,5.767],[0,0],[-16.139,20.399],[0,0],[-16.079,-2.796],[4.211,-24.215],[0,0],[0,0],[0,0],[-7.922,-5.577],[0,0],[15.897,-20.588],[0,0],[16.502,3.188],[-4.662,24.132],[0,0],[0,0]],"o":[[0,0],[7.21,0],[0,0.831],[0,0],[-1.042,5.393],[3.688,0.713],[0,0],[4.21,-5.453],[-2.184,-1.686],[0,0],[-7.21,0],[0,-0.75],[0,0],[0.941,-5.412],[-3.594,-0.625],[0,0],[-4.474,5.654],[2.306,1.824],[0,0],[0,0],[0,0],[0,0],[-9.9,0],[0,0],[-20.399,-16.139],[0,0],[10.126,-12.799],[24.215,4.211],[0,0],[0,0],[0,0],[9.722,0],[0,0],[20.588,15.897],[0,0],[-10.272,13.303],[-24.132,-4.662],[0,0],[0,0],[0,0]],"v":[[-78.828,27.057],[-46.312,27.057],[-33.256,40.112],[-33.493,42.588],[-62.834,194.347],[-54.955,205.999],[-45.197,202.312],[114.3,-7.785],[115.52,-30.089],[104.322,-33.171],[52.573,-34.468],[39.518,-47.524],[39.711,-49.76],[64.923,-194.846],[56.828,-206.349],[47.324,-202.721],[-118.099,-0.349],[-115.936,20.394],[-104.22,27.089],[-78.828,27.057],[-76.458,56.417],[-93.96,56.418],[-101.162,56.419],[-128.695,47.533],[-130.385,46.257],[-138.098,-19.901],[16.587,-215.414],[59.113,-231.646],[95.333,-180.176],[74.797,-62.129],[92.349,-62.128],[101.215,-62.127],[128.326,-53.541],[130,-52.307],[138.492,13.755],[-16.663,214.687],[-60.328,231.182],[-95.582,179.046],[-71.895,56.416],[-76.458,56.416]],"c":true}]},{"t":48,"s":[{"i":[[0,0],[0,0],[0,-6.681],[0.146,-0.756],[0,0],[-5.153,-0.996],[-2.194,2.841],[0,0],[5.288,4.083],[2.676,0],[0,0],[0,6.681],[-0.119,0.685],[0,0],[5.171,0.899],[2.162,-2.733],[0,0],[-5.24,-4.145],[-2.725,0],[0,0],[0,0],[0,0],[0,0],[8.003,5.767],[0,0],[-16.139,20.399],[0,0],[-16.079,-2.796],[4.211,-24.215],[0,0],[0,0],[0,0],[-7.922,-5.577],[0,0],[15.897,-20.588],[0,0],[16.502,3.188],[-4.662,24.132],[0,0],[0,0]],"o":[[0,0],[6.681,0],[0,0.77],[0,0],[-0.996,5.153],[3.524,0.681],[0,0],[4.083,-5.288],[-2.118,-1.635],[0,0],[-6.681,0],[0,-0.695],[0,0],[0.899,-5.171],[-3.434,-0.597],[0,0],[-4.145,5.24],[2.137,1.69],[0,0],[0,0],[0,0],[0,0],[-9.9,0],[0,0],[-20.399,-16.139],[0,0],[10.126,-12.799],[24.215,4.211],[0,0],[0,0],[0,0],[9.722,0],[0,0],[20.588,15.897],[0,0],[-10.272,13.303],[-24.132,-4.662],[0,0],[0,0],[0,0]],"v":[[-74.271,21.419],[-44.141,21.419],[-32.043,33.516],[-32.263,35.811],[-61.217,185.685],[-53.689,196.818],[-44.365,193.295],[110.79,-7.636],[108.609,-24.605],[101.215,-27.127],[47.573,-27.127],[35.476,-39.225],[35.655,-41.297],[60.85,-186.173],[53.116,-197.164],[44.035,-193.698],[-110.65,1.816],[-108.668,18.809],[-101.162,21.419],[-74.271,21.419],[-76.458,56.417],[-93.96,56.418],[-101.162,56.419],[-128.695,47.533],[-130.385,46.257],[-138.098,-19.901],[16.587,-215.414],[59.113,-231.646],[95.333,-180.176],[74.797,-62.129],[92.349,-62.128],[101.215,-62.127],[128.326,-53.541],[130,-52.307],[138.492,13.755],[-16.663,214.687],[-60.328,231.182],[-95.582,179.046],[-71.895,56.416],[-76.458,56.416]],"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":33,"op":180,"st":33,"bm":0}]} diff --git a/TMessagesProj/src/main/res/raw/spoiler_compute.glsl b/TMessagesProj/src/main/res/raw/spoiler_compute.glsl new file mode 100644 index 00000000000..12649abb0f4 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/spoiler_compute.glsl @@ -0,0 +1,39 @@ +#version 310 es + +layout(local_size_x = 256) in; // This can be adjusted + +struct Particle { + vec2 position; + vec2 velocity; + float time; + float duration; +}; + +layout(std430, binding = 0) buffer ParticleBuffer { + Particle particles[]; +}; + +uniform float deltaTime; +uniform vec2 size; + +void main() { + uint id = gl_GlobalInvocationID.x; + + if (id >= uint(particles.length())) + return; + + Particle p = particles[id]; + + p.time += deltaTime * p.duration; + if (p.time >= 1.0) { + p.time = 0.0; + } + + p.velocity += vec2(.5, .5); + p.velocity *= .99; + + p.position += p.velocity; + p.position = fract(p.position / size) * size; + + particles[id] = p; +} diff --git a/TMessagesProj/src/main/res/raw/stats.json b/TMessagesProj/src/main/res/raw/stats.json new file mode 100644 index 00000000000..cbba9609976 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/stats.json @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":32,"w":512,"h":512,"nm":"Stats MAIN","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Column 1","sr":1,"ks":{"p":{"a":0,"k":[106,459.5,0]},"a":{"a":0,"k":[-150,203.5,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"c":true}]},{"i":{"x":0.78,"y":1},"o":{"x":0.7,"y":0},"t":8,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-164.689,56.609],[-134.689,56.609],[-104.689,86.609],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-194.689,86.609]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.4,"y":0},"t":18,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-117.5],[-135,-117.5],[-105,-87.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-87.5]],"c":true}]},{"t":26,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"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":"Rectangle","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Column 2","sr":1,"ks":{"p":{"a":0,"k":[256,459.5,0]},"a":{"a":0,"k":[0,203.5,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":2,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"c":true}]},{"i":{"x":0.78,"y":1},"o":{"x":0.7,"y":0},"t":12,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-45.5],[15,-45.5],[45,-15.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-15.5]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.4,"y":0},"t":21,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-233.5],[15,-233.5],[45,-203.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-203.5]],"c":true}]},{"t":29,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"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":"Rectangle-","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Column 3","sr":1,"ks":{"p":{"a":0,"k":[406,459.5,0]},"a":{"a":0,"k":[150,203.5,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":2,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"c":true}]},{"i":{"x":0.78,"y":1},"o":{"x":0.7,"y":0},"t":14,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[134.289,-184.658],[164.289,-184.658],[194.289,-154.658],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[104.289,-154.658]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.4,"y":0},"t":23,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,29],[165,29],[195,59],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,59]],"c":true}]},{"t":31,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"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":"Rectangle--","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 503731c95c7..3b3dc98adc3 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -50,6 +50,7 @@ You entered the wrong code. Please try again. Didn\'t get the code? Send the code as an SMS + Get a code via Fragment Cancel account reset Somebody with access to **%1$s** has requested to delete your Telegram account and reset your 2-Step Verification password.\n\nIf this wasn\'t you, please enter the code we\'ve just sent you via SMS. You can also cancel this by *changing your phone number*. Reset account @@ -314,6 +315,7 @@ Pinned chats You can pin an unlimited number of archived chats to the top. Hold this button to schedule your message or send it without sound. + Long tap to send your message later. Hide new chats? You are receiving many new chats from users who are not in your Contacts List. Do you want have such chats **automatically muted** and **archived**? GO TO SETTINGS @@ -931,6 +933,9 @@ Post messages Edit messages Delete messages + Post stories + Edit stories + Delete stories Add admins Send anonymously Ban users @@ -3891,6 +3896,7 @@ **Telegram** needs access to location so that you can get directions. Tap Settings -> Permissions, and turn **Location** on. **Telegram** needs access to contacts so that you can share them with your friends. Tap Settings -> Permissions, and turn **Contacts** on. **Telegram** needs storage access so you can upload profile picture. Tap Settings -> Permissions, and turn **Files and media** on. + **Telegram** needs access to music files to upload with your story. Tap Settings -> Permissions, and turn **Music and Audio** on. Telegram needs access to draw above other apps to play videos in Picture-in-Picture mode. Overlay mode lets you use push-to-talk and see who is talking even when you are outside of Telegram. SETTINGS @@ -6874,9 +6880,9 @@ This story is shown to %d contacts. This story is shown to %d contacts. This story is pinned to your profile. - This story is pinned to channel posts. + Story saved to the channel’s profile This story is hidden from your profile. - This story is hidden from channel posts. + Story removed from the channel’s profile Draft Drafts Keep Draft @@ -7011,6 +7017,7 @@ cached story Stories This video has no sound + Tap here to enable sound Drag to delete Release to delete Add text @@ -7145,11 +7152,14 @@ You can post **%1$d** stories in a month.\nSubscribe to **Telegram Premium** to increase this limit to **%2$d**. Sorry, you can’t post more than **%1$d** stories in a month. Deselect All + ADD LOCATION Location Audio Photo Send reaction as a private message Remove Audio + Publish story as + Who can view your story Style Archived Stories Save to Posts @@ -7164,6 +7174,13 @@ Photo will be deleted in **%d** seconds after opening. Video will be deleted in **%d** second after opening. Video will be deleted in **%d** seconds after opening. + Boosters + Link for boosting + Boosts + Level %d + Level + Enable Stories + You can’t add up more than 5 reactions tags to a story. Someone just got access to your messages! Yes, it’s me No, it’s not me! @@ -7182,13 +7199,50 @@ Manage Messages Manage Stories Premium subscribers + Existing Boosts + Boosts to level up + Your channel is currently boosted by these users. + Boost Channel + BOOST + Enable stories for the channel + Enable stories for channel You are about to use a mini app operated by an independent party **not affiliated with Telegram**. You must agree to the Terms of Use of mini apps to continue. I agree to the **Terms of Use** - Saved stories can be viewed by others on the channle’s profile until an admin removes them. - Premuim needed! + Saved stories can be viewed by others on the channel’s profile until an admin removes them. + You boosted the channel + You boosted %s! + Premium needed! + Only **Telegram Premium** subscribers can boost channels. Do you want subscribe to **Telegram Premium?** Replace + You currently boost **%1$s**. Do you want to boost **%2$s** instead? + Can’t boost too often! + You can change the channel you boost only once a day. Next time you can boost is in **%s.** **%s** shortcut added in attachment menu and side menu. **%s** shortcut added in side menu. **%s** shortcut added in attachment menu. Terms of Use + boost expires on %s + Your channel need %s to enable posting stories.\n\nAsk your Premium subscribers to boost your channel with this link: + This channel need %s to enable stories. Help make it possible! + This channel need %1$s to be able post **%2$s** per day. Help make it possible! + This channel need %s more boosts to enable stories. + Help upgrade channel + This channel reached **Level 1** and can now post stories. + This channel reached **Level %1$d** and can now post **%2$s** per day. + No users currently boost your channel + Can’t boost with gifted Premium! + Because your **Telegram Premium** subscription was gifted to you, you can’t use it boost channels. + Maximum Level Reached + **%d** more boost + **%d** more boost + **%d** more boosts + **%d** more boosts + **%d** more boosts + **%d** more boosts + **%d** story + **%d** story + **%d** stories + **%d** stories + **%d** stories + **%d** stories diff --git a/TMessagesProj_App/build.gradle b/TMessagesProj_App/build.gradle index 9f0b2df9d38..9728ec17ee4 100644 --- a/TMessagesProj_App/build.gradle +++ b/TMessagesProj_App/build.gradle @@ -131,9 +131,6 @@ android { sourceSets.release { manifest.srcFile '../TMessagesProj/config/release/AndroidManifest_SDK23.xml' } - sourceSets.standalone { - manifest.srcFile '../TMessagesProj/config/release/AndroidManifest_standalone.xml' - } minSdkVersion 23 ext { abiVersionCode = 2 diff --git a/TMessagesProj_AppHockeyApp/build.gradle b/TMessagesProj_AppHockeyApp/build.gradle index 2f7d61dd679..270b278b335 100644 --- a/TMessagesProj_AppHockeyApp/build.gradle +++ b/TMessagesProj_AppHockeyApp/build.gradle @@ -17,6 +17,7 @@ configurations.all { dependencies { implementation project(':TMessagesProj') implementation 'androidx.multidex:multidex:2.0.1' + implementation 'androidx.core:core:1.10.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' implementation files('../TMessagesProj/libs/libgsaverification-client.aar') @@ -87,6 +88,16 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' ndk.debugSymbolLevel = 'FULL' } + HA_hardcore { + debuggable false + jniDebuggable false + signingConfig signingConfigs.debug + applicationIdSuffix ".beta" + minifyEnabled true + multiDexEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' + ndk.debugSymbolLevel = 'FULL' + } } sourceSets.HA_private { @@ -95,6 +106,9 @@ android { sourceSets.HA_public { manifest.srcFile '../TMessagesProj/config/debug/AndroidManifest.xml' } + sourceSets.HA_hardcore { + manifest.srcFile '../TMessagesProj/config/debug/AndroidManifest.xml' + } flavorDimensions "minApi" diff --git a/TMessagesProj_AppHockeyApp/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java b/TMessagesProj_AppHockeyApp/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java index b578b6196c7..cd31b8a7958 100644 --- a/TMessagesProj_AppHockeyApp/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java +++ b/TMessagesProj_AppHockeyApp/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java @@ -1,10 +1,15 @@ package org.telegram.messenger; import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; import android.os.Build; import android.os.SystemClock; import android.text.TextUtils; +import androidx.core.content.FileProvider; + import com.microsoft.appcenter.AppCenter; import com.microsoft.appcenter.CustomProperties; import com.microsoft.appcenter.analytics.Analytics; @@ -14,7 +19,9 @@ import org.telegram.messenger.regular.BuildConfig; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AlertsCreator; +import java.io.File; import java.util.Locale; public class ApplicationLoaderImpl extends ApplicationLoader { @@ -99,5 +106,41 @@ protected void logDualCameraInternal(boolean success, boolean vendor) { } } + @Override + public boolean checkApkInstallPermissions(final Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !ApplicationLoader.applicationContext.getPackageManager().canRequestPackageInstalls()) { + AlertsCreator.createApkRestrictedDialog(context, null).show(); + return false; + } + return true; + } + + @Override + public boolean openApkInstall(Activity activity, TLRPC.Document document) { + boolean exists = false; + try { + String fileName = FileLoader.getAttachFileName(document); + File f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(document, true); + if (exists = f.exists()) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + if (Build.VERSION.SDK_INT >= 24) { + intent.setDataAndType(FileProvider.getUriForFile(activity, ApplicationLoader.getApplicationId() + ".provider", f), "application/vnd.android.package-archive"); + } else { + intent.setDataAndType(Uri.fromFile(f), "application/vnd.android.package-archive"); + } + try { + activity.startActivityForResult(intent, 500); + } catch (Exception e) { + FileLog.e(e); + } + } + } catch (Exception e) { + FileLog.e(e); + } + return exists; + } + } diff --git a/TMessagesProj_AppStandalone/.gitignore b/TMessagesProj_AppStandalone/.gitignore new file mode 100644 index 00000000000..42afabfd2ab --- /dev/null +++ b/TMessagesProj_AppStandalone/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/TMessagesProj_AppStandalone/build.gradle b/TMessagesProj_AppStandalone/build.gradle new file mode 100644 index 00000000000..4c6df91fafd --- /dev/null +++ b/TMessagesProj_AppStandalone/build.gradle @@ -0,0 +1,142 @@ +apply plugin: 'com.android.application' + +repositories { + mavenCentral() + google() +} + +configurations { + compile.exclude module: 'support-v4' +} + +configurations.all { + exclude group: 'com.google.firebase', module: 'firebase-core' + exclude group: 'androidx.recyclerview', module: 'recyclerview' +} + +dependencies { + implementation project(':TMessagesProj') + implementation 'androidx.multidex:multidex:2.0.1' + implementation 'androidx.core:core:1.10.1' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' + implementation files('../TMessagesProj/libs/libgsaverification-client.aar') +} + +android { + compileSdkVersion 33 + buildToolsVersion '33.0.0' + + defaultConfig.applicationId = APP_PACKAGE + + sourceSets.main.jniLibs.srcDirs = ['../TMessagesProj/jni/'] + + lintOptions { + disable 'MissingTranslation' + disable 'ExtraTranslation' + disable 'BlockedPrivateApi' + } + + dexOptions { + jumboMode = true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + + coreLibraryDesugaringEnabled true + } + + signingConfigs { + debug { + storeFile file("../TMessagesProj/config/release.keystore") + storePassword RELEASE_STORE_PASSWORD + keyAlias RELEASE_KEY_ALIAS + keyPassword RELEASE_KEY_PASSWORD + } + + release { + storeFile file("../TMessagesProj/config/release.keystore") + storePassword RELEASE_STORE_PASSWORD + keyAlias RELEASE_KEY_ALIAS + keyPassword RELEASE_KEY_PASSWORD + } + } + + buildTypes { + standalone { + debuggable false + jniDebuggable false + signingConfig signingConfigs.release + applicationIdSuffix ".web" + minifyEnabled true + multiDexEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' + ndk.debugSymbolLevel = 'FULL' + } + } + + sourceSets.standalone { + manifest.srcFile '../TMessagesProj/config/release/AndroidManifest_standalone.xml' + } + + flavorDimensions "minApi" + + productFlavors { + afat { + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } + ext { + abiVersionCode = 9 + } + sourceSets.standalone { + manifest.srcFile '../TMessagesProj/config/release/AndroidManifest_standalone.xml' + } + } + } + + defaultConfig.versionCode = Integer.parseInt(APP_VERSION_CODE) + + applicationVariants.all { variant -> + variant.outputs.all { output -> + outputFileName = "app.apk" + output.versionCodeOverride = defaultConfig.versionCode * 10 + variant.productFlavors.get(0).abiVersionCode + } + } + + variantFilter { variant -> + def names = variant.flavors*.name + if (variant.buildType.name != "release" && !names.contains("afat")) { + setIgnore(true) + } + } + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 33 + versionName APP_VERSION_NAME + ndkVersion "21.4.7075529" + + multiDexEnabled true + + vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi'] + + externalNativeBuild { + cmake { + version '3.10.2' + arguments '-DANDROID_STL=c++_static', '-DANDROID_PLATFORM=android-16', "-j=16" + } + } + } + + buildFeatures { + buildConfig = true + } + + lintOptions { + checkReleaseBuilds false + } +} + +apply plugin: 'com.google.gms.google-services' diff --git a/TMessagesProj_AppStandalone/google-services.json b/TMessagesProj_AppStandalone/google-services.json new file mode 100644 index 00000000000..640e841b2d2 --- /dev/null +++ b/TMessagesProj_AppStandalone/google-services.json @@ -0,0 +1,98 @@ +{ + "project_info": { + "project_number": "760348033671", + "firebase_url": "https://tmessages2.firebaseio.com", + "project_id": "tmessages2", + "storage_bucket": "tmessages2.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:760348033671:android:f6afd7b67eae3860", + "android_client_info": { + "package_name": "org.telegram.messenger" + } + }, + "oauth_client": [ + { + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyA-t0jLPjUt2FxrA8VPK2EiYHcYcboIR6k" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:760348033671:android:dc022572c167a16c", + "android_client_info": { + "package_name": "org.telegram.messenger.beta" + } + }, + "oauth_client": [ + { + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyA-t0jLPjUt2FxrA8VPK2EiYHcYcboIR6k" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:760348033671:android:7396e651423888c3f66e22", + "android_client_info": { + "package_name": "org.telegram.messenger.web" + } + }, + "oauth_client": [ + { + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyA-t0jLPjUt2FxrA8VPK2EiYHcYcboIR6k" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "760348033671-2hh8ebmuflsnjoc0kldkfells9rhtfni.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/TMessagesProj_AppStandalone/src/main/AndroidManifest.xml b/TMessagesProj_AppStandalone/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..6e6e6011c8c --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java new file mode 100644 index 00000000000..ee444d93520 --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/ApplicationLoaderImpl.java @@ -0,0 +1,77 @@ +package org.telegram.messenger; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; + +import androidx.core.content.FileProvider; + +import org.telegram.messenger.web.BuildConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AlertsCreator; + +import java.io.File; + +public class ApplicationLoaderImpl extends ApplicationLoader { + @Override + protected String onGetApplicationId() { + return BuildConfig.APPLICATION_ID; + } + + + @Override + protected void startAppCenterInternal(Activity context) { + + } + + @Override + protected void checkForUpdatesInternal() { + + } + + protected void appCenterLogInternal(Throwable e) { + + } + + protected void logDualCameraInternal(boolean success, boolean vendor) { + + } + + @Override + public boolean checkApkInstallPermissions(final Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !ApplicationLoader.applicationContext.getPackageManager().canRequestPackageInstalls()) { + AlertsCreator.createApkRestrictedDialog(context, null).show(); + return false; + } + return true; + } + + @Override + public boolean openApkInstall(Activity activity, TLRPC.Document document) { + boolean exists = false; + try { + String fileName = FileLoader.getAttachFileName(document); + File f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(document, true); + if (exists = f.exists()) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + if (Build.VERSION.SDK_INT >= 24) { + intent.setDataAndType(FileProvider.getUriForFile(activity, ApplicationLoader.getApplicationId() + ".provider", f), "application/vnd.android.package-archive"); + } else { + intent.setDataAndType(Uri.fromFile(f), "application/vnd.android.package-archive"); + } + try { + activity.startActivityForResult(intent, 500); + } catch (Exception e) { + FileLog.e(e); + } + } + } catch (Exception e) { + FileLog.e(e); + } + return exists; + } +} diff --git a/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/GoogleVoiceClientActivity.java b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/GoogleVoiceClientActivity.java new file mode 100644 index 00000000000..aa38318ed11 --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/GoogleVoiceClientActivity.java @@ -0,0 +1,19 @@ +/* + * This is the source code of Telegram for Android v. 5.x.x + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2018. + */ + +package org.telegram.messenger; + +import com.google.android.search.verification.client.SearchActionVerificationClientActivity; +import com.google.android.search.verification.client.SearchActionVerificationClientService; + +public class GoogleVoiceClientActivity extends SearchActionVerificationClientActivity { + + public Class getServiceClass() { + return GoogleVoiceClientService.class; + } +} diff --git a/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/GoogleVoiceClientService.java b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/GoogleVoiceClientService.java new file mode 100644 index 00000000000..25af0a81fde --- /dev/null +++ b/TMessagesProj_AppStandalone/src/main/java/org/telegram/messenger/GoogleVoiceClientService.java @@ -0,0 +1,22 @@ +/* + * This is the source code of Telegram for Android v. 5.x.x + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2018. + */ + +package org.telegram.messenger; + +import android.content.Intent; +import android.os.Bundle; + +import com.google.android.search.verification.client.SearchActionVerificationClientService; + +public class GoogleVoiceClientService extends SearchActionVerificationClientService { + + @Override + public void performAction(Intent intent, boolean isVerified, Bundle options) { + AndroidUtilities.googleVoiceClientService_performAction(intent, isVerified, options); + } +} diff --git a/gradle.properties b/gradle.properties index b25f7af8141..b50b7cbea5e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,8 +13,8 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sat Mar 12 05:53:50 MSK 2016 -APP_VERSION_CODE=3872 -APP_VERSION_NAME=10.0.9 +APP_VERSION_CODE=3919 +APP_VERSION_NAME=10.1.0 APP_PACKAGE=org.telegram.messenger RELEASE_KEY_PASSWORD=android RELEASE_KEY_ALIAS=androidkey diff --git a/settings.gradle b/settings.gradle index 9a0eef931d5..dd7a48e7c9c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,3 +2,4 @@ include ':TMessagesProj' include ':TMessagesProj_App' include ':TMessagesProj_AppHuawei' include ':TMessagesProj_AppHockeyApp' +include ':TMessagesProj_AppStandalone'