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 | 1647 +++++++++++++++-- .../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 | 330 ++-- .../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 | 181 +- .../ui/Stories/recorder/TimelineView.java | 428 +++-- .../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, 9539 insertions(+), 2271 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 e03a85d66..04241d3b6 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 cc458d8d8..5d923a3a6 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 @@ public class DefaultItemAnimator extends SimpleItemAnimator { .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 class DefaultItemAnimator extends SimpleItemAnimator { .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 @@ public class DefaultItemAnimator extends SimpleItemAnimator { } + 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 c470a1792..5d4502849 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 class AndroidUtilities { 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 a5297e449..35f9306db 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 @@ import java.io.File; public class ApplicationLoader extends Application { - private static ApplicationLoader applicationLoaderInstance; + public static ApplicationLoader applicationLoaderInstance; @SuppressLint("StaticFieldLeak") public static volatile Context applicationContext; @@ -555,4 +555,11 @@ public class ApplicationLoader extends Application { } + 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 243cf2c9b..0580dd0e9 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 000000000..4fdc97a67 --- /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 fc73ae225..a13d21515 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 @@ public class ChatMessagesMetadataController { 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 f35882672..717f60912 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 class ContactsController extends BaseController { } 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 b63f4a9bd..b52a05a47 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 class DatabaseMigrationHelper { 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 2c1855d0b..5de954d13 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 class FileLoader extends BaseController { } 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 class FileLoader extends BaseController { } } 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 class FileLoader extends BaseController { } 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 class FileLoader extends BaseController { } 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 class FileLoader extends BaseController { 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 c4c8a7607..74c96b113 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 @@ public class FileRefController extends BaseController { 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 @@ public class FileRefController extends BaseController { } } 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 @@ public class FileRefController extends BaseController { 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 ab82c6238..cd19c523f 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 class ImageReceiver implements NotificationCenter.NotificationCenterDeleg 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 class ImageReceiver implements NotificationCenter.NotificationCenterDeleg 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 class ImageReceiver implements NotificationCenter.NotificationCenterDeleg 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 class ImageReceiver implements NotificationCenter.NotificationCenterDeleg 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 class ImageReceiver implements NotificationCenter.NotificationCenterDeleg 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 1b5e48577..06d147fa6 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 class LocaleController { 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 7063e2e12..4fb4d54e5 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, } } 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, } } 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 bf7b11c55..b76c78837 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 @@ import java.util.regex.Pattern; 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 class MediaDataController extends BaseController { 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 class MediaDataController extends BaseController { } 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 class MediaDataController extends BaseController { } 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 class MediaDataController extends BaseController { 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 class MediaDataController extends BaseController { } 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 class MediaDataController extends BaseController { 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 f1bdfc86d..c10e8e1ff 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 class MessageObject { rights.append('\n').append(n.edit_messages ? '+' : '-').append(' '); rights.append(LocaleController.getString("EventLogPromotedEditMessages", R.string.EventLogPromotedEditMessages)); } + if (o.post_stories != n.post_stories) { + rights.append('\n').append(n.post_stories ? '+' : '-').append(' '); + rights.append(LocaleController.getString("EventLogPromotedPostStories", R.string.EventLogPromotedPostStories)); + } + if (o.edit_stories != n.edit_stories) { + rights.append('\n').append(n.edit_messages ? '+' : '-').append(' '); + rights.append(LocaleController.getString("EventLogPromotedEditStories", R.string.EventLogPromotedEditStories)); + } + if (o.delete_stories != n.delete_stories) { + rights.append('\n').append(n.delete_stories ? '+' : '-').append(' '); + rights.append(LocaleController.getString("EventLogPromotedDeleteStories", R.string.EventLogPromotedDeleteStories)); + } } if (o.delete_messages != n.delete_messages) { rights.append('\n').append(n.delete_messages ? '+' : '-').append(' '); @@ -4295,8 +4306,8 @@ public class MessageObject { 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 class MessageObject { 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 class MessageObject { photoHeight = h; } - if (caption != null && !TextUtils.isEmpty(caption)) { - photoHeight += captionHeight; - } - return photoHeight + AndroidUtilities.dp(14); } } @@ -8080,7 +8065,7 @@ public class MessageObject { 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 604202fff..efe605149 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 class MessagesController extends BaseController implements NotificationCe } } + 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 class MessagesController extends BaseController implements NotificationCe } 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 class MessagesController extends BaseController implements NotificationCe updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateReadStories) { TLRPC.TL_updateReadStories updateReadStories = (TLRPC.TL_updateReadStories) baseUpdate; - getStoriesController().markStoriesAsReadFromServer(updateReadStories.user_id, updateReadStories.max_id); + long dialogId = DialogObject.getPeerDialogId(updateReadStories.peer); + getStoriesController().markStoriesAsReadFromServer(dialogId, updateReadStories.max_id); } else if (baseUpdate instanceof TLRPC.TL_updatePeerSettings) { TLRPC.TL_updatePeerSettings update = (TLRPC.TL_updatePeerSettings) baseUpdate; if (contactsIds == null) { @@ -16308,7 +16326,9 @@ public class MessagesController extends BaseController implements NotificationCe } } } else if (baseUpdate instanceof TLRPC.TL_updateSentStoryReaction) { - getStoriesController().updateStoryReaction(((TLRPC.TL_updateSentStoryReaction) baseUpdate).user_id, ((TLRPC.TL_updateSentStoryReaction) baseUpdate).story_id, ((TLRPC.TL_updateSentStoryReaction) baseUpdate).reaction); + TLRPC.TL_updateSentStoryReaction updateReaction = (TLRPC.TL_updateSentStoryReaction) baseUpdate; + long dialogId = DialogObject.getPeerDialogId(updateReaction.peer); + getStoriesController().updateStoryReaction(dialogId, updateReaction.story_id, updateReaction.reaction); } } if (editor != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index 6ffdb36da..b3bb81980 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -96,7 +96,7 @@ public class MessagesStorage extends BaseController { } } - public final static int LAST_DB_VERSION = 133; + public final static int LAST_DB_VERSION = 134; private boolean databaseMigrationInProgress; public boolean showClearDatabaseAlert; private LongSparseIntArray dialogIsForum = new LongSparseIntArray(); @@ -619,7 +619,7 @@ public class MessagesStorage extends BaseController { database.executeFast("CREATE TABLE wallpapers2(uid INTEGER PRIMARY KEY, data BLOB, num INTEGER)").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS wallpapers_num ON wallpapers2(num);").stepThis().dispose(); - database.executeFast("CREATE TABLE unread_push_messages(uid INTEGER, mid INTEGER, random INTEGER, date INTEGER, data BLOB, fm TEXT, name TEXT, uname TEXT, flags INTEGER, PRIMARY KEY(uid, mid))").stepThis().dispose(); + database.executeFast("CREATE TABLE unread_push_messages(uid INTEGER, mid INTEGER, random INTEGER, date INTEGER, data BLOB, fm TEXT, name TEXT, uname TEXT, flags INTEGER, topicId INTEGER, PRIMARY KEY(uid, mid))").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS unread_push_messages_idx_date ON unread_push_messages(date);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS unread_push_messages_idx_random ON unread_push_messages(random);").stepThis().dispose(); @@ -1273,7 +1273,7 @@ public class MessagesStorage extends BaseController { flags |= 2; } - SQLitePreparedStatement state = database.executeFast("REPLACE INTO unread_push_messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO unread_push_messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); state.requery(); state.bindLong(1, message.getDialogId()); state.bindInteger(2, message.getId()); @@ -1296,6 +1296,7 @@ public class MessagesStorage extends BaseController { state.bindString(8, message.localUserName); } state.bindInteger(9, flags); + state.bindInteger(10, MessageObject.getTopicId(message.messageOwner, false)); state.step(); data.reuse(); @@ -3510,7 +3511,7 @@ public class MessagesStorage extends BaseController { cursor = null; database.executeFast("DELETE FROM unread_push_messages WHERE date <= " + maxDate).stepThis().dispose(); - cursor = database.queryFinalized("SELECT data, mid, date, uid, random, fm, name, uname, flags FROM unread_push_messages WHERE 1 ORDER BY date DESC LIMIT 50"); + cursor = database.queryFinalized("SELECT data, mid, date, uid, random, fm, name, uname, flags, topicId FROM unread_push_messages WHERE 1 ORDER BY date DESC LIMIT 50"); while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { @@ -3524,6 +3525,7 @@ public class MessagesStorage extends BaseController { String name = cursor.isNull(6) ? null : cursor.stringValue(6); String userName = cursor.isNull(7) ? null : cursor.stringValue(7); int flags = cursor.intValue(8); + int topicId = cursor.intValue(9); if (MessageObject.getFromChatId(message) == 0) { if (DialogObject.isUserDialog(message.dialog_id)) { message.from_id = new TLRPC.TL_peerUser(); @@ -3539,6 +3541,11 @@ public class MessagesStorage extends BaseController { chatsToLoad.add(-message.dialog_id); } } + if (topicId != 0) { + message.reply_to = new TLRPC.TL_messageReplyHeader(); + message.reply_to.forum_topic = true; + message.reply_to.reply_to_top_id = topicId; + } pushMessages.add(new MessageObject(currentAccount, message, messageText, name, userName, (flags & 1) != 0, (flags & 2) != 0, (message.flags & 0x80000000) != 0, false)); addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad, null); @@ -14230,6 +14237,15 @@ public class MessagesStorage extends BaseController { } } } + if (message.media.peer != null) { + long dialogId = DialogObject.getPeerDialogId(message.media.peer); + if (dialogId > 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 455097950..4e6abca5b 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 class SendMessagesHelper extends BaseController implements NotificationCe 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 class SendMessagesHelper extends BaseController implements NotificationCe } 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 9698bbf1b..88a2d9315 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 @@ public class SharedConfig { 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 class SharedConfig { 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 class SharedConfig { 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 class SharedConfig { 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 class SharedConfig { 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 class SharedConfig { 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 a329c5122..8d41a95e6 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 class VideoEditedInfo { 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 0af9045f5..8b21d037b 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 class AudioBufferConverter { } 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 9bf10baca..e381099e9 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 class VideoPlayerHolderBase { 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 class VideoPlayerHolderBase { } 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 9f20f3329..036d36f17 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 class DefaultAudioRemixer implements AudioRemixer { @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 26062c547..30f07771d 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 class DownMixAudioRemixer implements AudioRemixer { 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 fbb8f1cad..2014e36ac 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 1d5c8f83e..066fcebcc 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { } } } - + public static class WebPageAttribute extends TLObject { public int flags; @@ -12517,6 +12526,9 @@ public class TLRPC { 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 class TLRPC { } 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { 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,6 +15762,276 @@ public class TLRPC { } public static class TL_channelFull extends ChatFull { + public static int constructor = 0x723027bd; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_view_participants = (flags & 8) != 0; + can_set_username = (flags & 64) != 0; + can_set_stickers = (flags & 128) != 0; + hidden_prehistory = (flags & 1024) != 0; + can_set_location = (flags & 65536) != 0; + has_scheduled = (flags & 524288) != 0; + can_view_stats = (flags & 1048576) != 0; + blocked = (flags & 4194304) != 0; + flags2 = stream.readInt32(exception); + can_delete_channel = (flags2 & 1) != 0; + antispam = (flags2 & 2) != 0; + participants_hidden = (flags2 & 4) != 0; + translations_disabled = (flags2 & 8) != 0; + stories_pinned_available = (flags2 & 32) != 0; + id = stream.readInt64(exception); + about = stream.readString(exception); + if ((flags & 1) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + admins_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + kicked_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + banned_count = stream.readInt32(exception); + } + if ((flags & 8192) != 0) { + online_count = stream.readInt32(exception); + } + read_inbox_max_id = stream.readInt32(exception); + read_outbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 8388608) != 0) { + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + } + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + BotInfo object = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bot_info.add(object); + } + if ((flags & 16) != 0) { + migrated_from_chat_id = stream.readInt64(exception); + } + if ((flags & 16) != 0) { + migrated_from_max_id = stream.readInt32(exception); + } + if ((flags & 32) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + if ((flags & 256) != 0) { + stickerset = StickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 512) != 0) { + available_min_id = stream.readInt32(exception); + } + if ((flags & 2048) != 0) { + folder_id = stream.readInt32(exception); + } + if ((flags & 16384) != 0) { + linked_chat_id = stream.readInt64(exception); + } + if ((flags & 32768) != 0) { + location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + slowmode_seconds = stream.readInt32(exception); + } + if ((flags & 262144) != 0) { + slowmode_next_send_date = stream.readInt32(exception); + } + if ((flags & 4096) != 0) { + stats_dc = stream.readInt32(exception); + } + pts = stream.readInt32(exception); + if ((flags & 2097152) != 0) { + call = TL_inputGroupCall.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16777216) != 0) { + ttl_period = stream.readInt32(exception); + } + if ((flags & 33554432) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + pending_suggestions.add(stream.readString(exception)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 134217728) != 0) { + theme_emoticon = stream.readString(exception); + } + if ((flags & 268435456) != 0) { + requests_pending = stream.readInt32(exception); + } + if ((flags & 268435456) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + recent_requesters.add(stream.readInt64(exception)); + } + } + if ((flags & 536870912) != 0) { + default_send_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 1073741824) != 0) { + available_reactions = ChatReactions.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 16) != 0) { + stories = PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_view_participants ? (flags | 8) : (flags &~ 8); + flags = can_set_username ? (flags | 64) : (flags &~ 64); + flags = can_set_stickers ? (flags | 128) : (flags &~ 128); + flags = hidden_prehistory ? (flags | 1024) : (flags &~ 1024); + flags = can_set_location ? (flags | 65536) : (flags &~ 65536); + flags = has_scheduled ? (flags | 524288) : (flags &~ 524288); + flags = can_view_stats ? (flags | 1048576) : (flags &~ 1048576); + flags = blocked ? (flags | 4194304) : (flags &~ 4194304); + stream.writeInt32(flags); + flags2 = can_delete_channel ? (flags2 | 1) : (flags2 &~ 1); + flags2 = antispam ? (flags2 | 2) : (flags2 &~ 2); + flags2 = participants_hidden ? (flags2 | 4) : (flags2 &~ 4); + flags2 = translations_disabled ? (flags2 | 8) : (flags2 &~ 8); + flags2 = stories_pinned_available ? (flags2 | 32) : (flags2 &~ 32); + stream.writeInt32(flags2); + stream.writeInt64(id); + stream.writeString(about); + if ((flags & 1) != 0) { + stream.writeInt32(participants_count); + } + if ((flags & 2) != 0) { + stream.writeInt32(admins_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(kicked_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(banned_count); + } + if ((flags & 8192) != 0) { + stream.writeInt32(online_count); + } + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(read_outbox_max_id); + stream.writeInt32(unread_count); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + if ((flags & 8388608) != 0) { + exported_invite.serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + int count = bot_info.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bot_info.get(a).serializeToStream(stream); + } + if ((flags & 16) != 0) { + stream.writeInt64(migrated_from_chat_id); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_max_id); + } + if ((flags & 32) != 0) { + stream.writeInt32(pinned_msg_id); + } + if ((flags & 256) != 0) { + stickerset.serializeToStream(stream); + } + if ((flags & 512) != 0) { + stream.writeInt32(available_min_id); + } + if ((flags & 2048) != 0) { + stream.writeInt32(folder_id); + } + if ((flags & 16384) != 0) { + stream.writeInt64(linked_chat_id); + } + if ((flags & 32768) != 0) { + location.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(slowmode_seconds); + } + if ((flags & 262144) != 0) { + stream.writeInt32(slowmode_next_send_date); + } + if ((flags & 4096) != 0) { + stream.writeInt32(stats_dc); + } + stream.writeInt32(pts); + if ((flags & 2097152) != 0) { + call.serializeToStream(stream); + } + if ((flags & 16777216) != 0) { + stream.writeInt32(ttl_period); + } + if ((flags & 33554432) != 0) { + stream.writeInt32(0x1cb5c415); + count = pending_suggestions.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(pending_suggestions.get(a)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as.serializeToStream(stream); + } + if ((flags & 134217728) != 0) { + stream.writeString(theme_emoticon); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(requests_pending); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(0x1cb5c415); + count = recent_requesters.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(recent_requesters.get(a)); + } + } + if ((flags & 536870912) != 0) { + default_send_as.serializeToStream(stream); + } + if ((flags & 1073741824) != 0) { + available_reactions.serializeToStream(stream); + } + if ((flags2 & 16) != 0) { + stories.serializeToStream(stream); + } + } + } + + public static class TL_channelFull_layer162 extends TL_channelFull { public static int constructor = 0xf2355507; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -27358,7 +27671,7 @@ public class TLRPC { } public static class TL_invoice extends TLObject { - public static int constructor = 0x3e85a91b; + public static int constructor = 0x5db95a15; public int flags; public boolean test; @@ -27374,18 +27687,24 @@ public class TLRPC { 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) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_invoice", constructor)); - } else { - return null; - } + 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); } - TL_invoice result = new TL_invoice(); - result.readParams(stream, exception); return result; } @@ -27432,8 +27751,95 @@ public class TLRPC { 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); + } + } + + 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; + 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("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); } } @@ -27468,7 +27874,7 @@ public class TLRPC { } } if ((flags & 512) != 0) { - stream.writeString(recurring_terms_url); + stream.writeString(terms_url); } } } @@ -32914,7 +33320,7 @@ public class TLRPC { case 0xc01e857f: result = new TL_updateUserTyping(); break; - case 0xfeb5345a: + case 0xf74e932b: result = new TL_updateReadStories(); break; case 0xebe46819: @@ -33016,7 +33422,7 @@ public class TLRPC { case 0xc32d5b12: result = new TL_updateDeleteChannelMessages(); break; - case 0xe3a73d20: + case 0x7d627683: result = new TL_updateSentStoryReaction(); break; case 0xf227868c: @@ -33037,7 +33443,7 @@ public class TLRPC { case 0x30f443db: result = new TL_updateRecentEmojiStatuses(); break; - case 0x205a4133: + case 0x75b3b798: result = new TL_updateStory(); break; case 0x7063c3db: @@ -34266,7 +34672,7 @@ public class TLRPC { 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { stream.writeInt32(constructor); } } - + public static class TL_updateRecentEmojiStatuses extends Update { public static int constructor = 0x30f443db; @@ -35378,7 +35784,6 @@ public class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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,6 +45562,167 @@ public class TLRPC { } public static class TL_channel extends Chat { + public static int constructor = 0x94f592db; + + public void readParams(AbstractSerializedData stream, boolean exception) { + 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; + 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) { @@ -45179,6 +45752,8 @@ public class TLRPC { 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 class TLRPC { 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 class TLRPC { } public static abstract class ReactionCount extends TLObject { - + public int flags; public int chosen_order; public boolean chosen; //custom @@ -48787,14 +49364,17 @@ public class TLRPC { 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,6 +49420,156 @@ public class TLRPC { } public static class TL_userFull extends UserFull { + public static int constructor = 0xb9b12c6c; + + 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; + 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); + } + 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); + } + 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); + } + if ((flags & 64) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + common_chats_count = stream.readInt32(exception); + if ((flags & 2048) != 0) { + folder_id = stream.readInt32(exception); + } + if ((flags & 16384) != 0) { + ttl_period = stream.readInt32(exception); + } + if ((flags & 32768) != 0) { + theme_emoticon = stream.readString(exception); + } + if ((flags & 65536) != 0) { + private_forward_name = stream.readString(exception); + } + if ((flags & 131072) != 0) { + bot_group_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 262144) != 0) { + bot_broadcast_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + 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); + } + } + 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) { + 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); + 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) { + stream.writeString(about); + } + settings.serializeToStream(stream); + if ((flags & 2097152) != 0) { + personal_photo.serializeToStream(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); + } + if ((flags & 64) != 0) { + stream.writeInt32(pinned_msg_id); + } + stream.writeInt32(common_chats_count); + if ((flags & 2048) != 0) { + stream.writeInt32(folder_id); + } + if ((flags & 16384) != 0) { + stream.writeInt32(ttl_period); + } + if ((flags & 32768) != 0) { + stream.writeString(theme_emoticon); + } + if ((flags & 65536) != 0) { + stream.writeString(private_forward_name); + } + if ((flags & 131072) != 0) { + bot_group_admin_rights.serializeToStream(stream); + } + if ((flags & 262144) != 0) { + bot_broadcast_admin_rights.serializeToStream(stream); + } + 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); + } + } + if ((flags & 16777216) != 0) { + wallpaper.serializeToStream(stream); + } + if ((flags & 33554432) != 0) { + stories.serializeToStream(stream); + } + } + } + + public static class TL_userFull_layer162 extends UserFull { public static int constructor = 0x4fe1cc86; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -48915,7 +49645,7 @@ public class TLRPC { 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); } } @@ -61399,6 +62129,7 @@ public class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { } } - 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 class TLRPC { } } + 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { } } + 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,39 @@ public class TLRPC { } } - - 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) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_userStories", constructor)); - } else { - return null; - } + 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); } - TL_userStories result = new TL_userStories(); - 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); - user_id = stream.readInt64(exception); + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); if ((flags & 1) != 0) { max_read_id = stream.readInt32(exception); } @@ -70129,7 +70984,7 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); stream.writeInt32(flags); - stream.writeInt64(user_id); + peer.serializeToStream(stream); if ((flags & 1) != 0) { stream.writeInt32(max_read_id); } @@ -70142,27 +70997,17 @@ public class TLRPC { } } - public static class TL_stories_userStories extends TLObject { - public static int constructor = 0x37a6ff5f; - - public TL_userStories stories; - public ArrayList users = new ArrayList<>(); - - public static TL_stories_userStories TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_stories_userStories.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_stories_userStories", constructor)); - } else { - return null; - } - } - TL_stories_userStories result = new TL_stories_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) { - stories = TL_userStories.TLdeserialize(stream, stream.readInt32(exception), exception); + flags = stream.readInt32(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); + } int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -70171,6 +71016,76 @@ public class TLRPC { 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); + stream.writeInt64(peer.user_id); + 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); + } + } + } + + public static class TL_stories_peerStories extends TLObject { + public static int constructor = 0xcae68768; + + public PeerStories stories; + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + 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_peerStories", constructor)); + } else { + return null; + } + } + TL_stories_peerStories result = new TL_stories_peerStories(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + stories = PeerStories.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); + } + 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 class TLRPC { 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 class TLRPC { case 0x1158fe3e: result = new TL_stories_allStoriesNotModified(); break; - case 0x519d899e: + case 0x6efc5e81: result = new TL_stories_allStories(); break; } @@ -70236,13 +71157,14 @@ public class TLRPC { } 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 class TLRPC { } 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; } - user_stories.add(object); + 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; + } + chats.add(object); } magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -70291,10 +71228,16 @@ public class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } } - 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { 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,43 @@ public class TLRPC { } } - 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); - } - } - - public static class TL_stories_getPinnedStories extends TLObject { - public static int constructor = 0xb471137; - - public InputUser user_id; - public int offset_id; - public int limit; - - 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); - user_id.serializeToStream(stream); - stream.writeInt32(offset_id); - stream.writeInt32(limit); + peer.serializeToStream(stream); } } public static class TL_updateStory extends Update { - public static int constructor = 0x205a4133; + public static int constructor = 0x75b3b798; - public long user_id; + public Peer peer; public StoryItem story; public void readParams(AbstractSerializedData stream, boolean exception) { - user_id = stream.readInt64(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); - stream.writeInt64(user_id); + peer.serializeToStream(stream); story.serializeToStream(stream); } } - public static class TL_stories_getStoriesArchive extends TLObject { - public static int constructor = 0x1f5bc5d2; + public static class TL_stories_getPinnedStories extends TLObject { + public static int constructor = 0x5821a5dc; + public InputPeer peer; public int offset_id; public int limit; @@ -70679,25 +71637,45 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(offset_id); + stream.writeInt32(limit); + } + } + + public static class TL_stories_getStoriesArchive extends TLObject { + public static int constructor = 0xb4352016; + + public InputPeer peer; + public int offset_id; + public int limit; + + 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); + 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } } - 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 class TLRPC { } } - 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } } + 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 ab2774aa6..f3455275c 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 class ActionBarLayout extends FrameLayout implements INavigationLayout, F } } + @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 class ActionBarLayout extends FrameLayout implements INavigationLayout, F 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 cde9699d6..25c1b8d27 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 abstract class BaseFragment { actionBar.onResume(); } if (storyViewer != null) { + storyViewer.onResume(); storyViewer.updatePlayingMode(); } if (overlayStoryViewer != null) { @@ -814,11 +815,13 @@ public abstract class BaseFragment { } 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 abstract class BaseFragment { 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 abstract class BaseFragment { } } super.dismiss(); + LaunchActivity.instance.sheetFragmentsStack.remove(actionBarLayout[0]); actionBarLayout[0] = null; } @@ -1052,6 +1057,9 @@ public abstract class BaseFragment { 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 efc254aba..52165dfd9 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 @@ public interface INavigationLayout { 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 8a40aa73a..6b42be224 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 class ContactsAdapter extends RecyclerListView.SectionsAdapter { 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 class ContactsAdapter extends RecyclerListView.SectionsAdapter { 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 class ContactsAdapter extends RecyclerListView.SectionsAdapter { 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 class ContactsAdapter extends RecyclerListView.SectionsAdapter { 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 fe12b540f..52d03e089 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 class DialogsAdapter extends RecyclerListView.SelectionAdapter implements 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 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements 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 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements 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 06c3d0ab4..319f5576c 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 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { } 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 fd20b2d43..a332b75f6 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 class ChatActionCell extends BaseCell implements DownloadController.FileD 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 e45c25665..5d8d66473 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate "article".equals(type) || "telegram_bot".equals(type) || "telegram_user".equals(type) || "telegram_channel".equals(type) || "telegram_megagroup".equals(type) || "telegram_voicechat".equals(type) || - "telegram_livestream".equals(type); - 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate str = LocaleController.getString("OpenLink").toUpperCase(); } else if (drawInstantViewType == 17) { str = LocaleController.getString("ViewStory").toUpperCase(); + } else if (drawInstantViewType == 18) { + str = LocaleController.getString("BoostLinkButton", R.string.BoostLinkButton); } else { str = LocaleController.getString("InstantView", R.string.InstantView); } @@ -10610,7 +10618,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 1a746316b..e6515b0a3 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 class DrawerActionCell extends FrameLayout { } 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 8ca76b8cf..dc11ff06a 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.FlickerLoadingView; 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 class SharedPhotoVideoCell2 extends FrameLayout { 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 class SharedPhotoVideoCell2 extends FrameLayout { 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 58325f4af..26e3da62e 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 000000000..d5753612d --- /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 ba35bf6f0..ae50d77e1 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.Calendar; 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not emojiAnimationsOverlay.cancelAllAnimations(); } ReactionsEffectOverlay.dismissAll(); + if (TextUtils.isEmpty(text)) { + hideSendButtonHints(); + AndroidUtilities.cancelRunOnUIThread(showScheduledHintRunnable); + } else if (!bigChange){ + showScheduledHint(); + } } @Override @@ -2007,6 +2017,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (scheduledOrNoSoundHint != null) { scheduledOrNoSoundHint.hide(); } + if (scheduledHint != null) { + scheduledHint.hide(); + } } @Override @@ -2077,16 +2090,38 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesCanStarIds[a].clear(); } scheduledOrNoSoundHint = null; + scheduledHint = null; infoTopView = null; aspectRatioFrameLayout = null; videoTextureView = null; @@ -4931,9 +4967,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + 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 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (scheduledOrNoSoundHint != null) { scheduledOrNoSoundHint.hide(); } + if (scheduledHint != null) { + scheduledHint.hide(); + } } if (fwdRestrictedBottomHint != null) { fwdRestrictedBottomHint.hide(); @@ -9874,6 +9932,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + 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 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + public void onApplyCaption(CharSequence caption) { + chatActivityEnterView.setFieldText(caption, true); + } + @Override public boolean closeKeyboard() { if (chatActivityEnterView != null && isKeyboardVisible()) { @@ -29049,6 +29138,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.showKeyboard(searchItem.getSearchField()); removeKeyboardPositionBeforeTransition(); }, 500); + hideSendButtonHints(); } @Override @@ -29891,7 +29981,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 d34dae86f..06d7ed86a 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 @@ public class ChatRightsEditActivity extends BaseFragment { 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 @@ public class ChatRightsEditActivity extends BaseFragment { }), 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 @@ public class ChatRightsEditActivity extends BaseFragment { 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 @@ public class ChatRightsEditActivity extends BaseFragment { 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 @@ public class ChatRightsEditActivity extends BaseFragment { } 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 @@ public class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { } 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { 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 class ChatRightsEditActivity extends BaseFragment { return VIEW_TYPE_HEADER_CELL; } else if (position == changeInfoRow || position == postMessagesRow || position == editMesagesRow || position == deleteMessagesRow || position == addAdminsRow || position == banUsersRow || position == addUsersRow || position == pinMessagesRow || - position == sendMessagesRow || position == 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 @@ public class ChatRightsEditActivity extends BaseFragment { 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 @@ public class ChatRightsEditActivity extends BaseFragment { 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 3e01f71ed..b9077f469 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 class AlertsCreator { } 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 @@ public class AlertsCreator { 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 bb080cba8..7bdd189fc 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 class AnimatedEmojiDrawable extends Drawable { 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 ab4b10128..e7c20ab13 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 class AnimatedEmojiSpan extends ReplacementSpan { } } - 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 ab5e279da..79a9b1f63 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.AnimatorSet; 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.ImageView; 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 @@ public class BlockingUpdateView extends FrameLayout implements NotificationCente 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; } - } else if (appUpdate.url != null) { - Browser.openUrl(getContext(), appUpdate.url); + 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 (BuildVars.isHuaweiStoreApp()){ + Browser.openUrl(context, BuildVars.HUAWEI_STORE_URL); + } else { + Browser.openUrl(context, BuildVars.PLAYSTORE_APP_URL); } }); @@ -209,7 +209,7 @@ public class BlockingUpdateView extends FrameLayout implements NotificationCente 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 class BlockingUpdateView extends FrameLayout implements NotificationCente } } - 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 class BlockingUpdateView extends FrameLayout implements NotificationCente 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 cc48da38a..26b57060f 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 @@ public class BlurringShader { 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 class BlurringShader { 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 class BlurringShader { @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 7b61e26b3..4b55e6164 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 @@ public class BottomPagerTabs extends View { 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 class BottomPagerTabs extends View { 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 b18155cc2..b0da22c3a 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 androidx.core.graphics.ColorUtils; 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 final class BulletinFactory { 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 64d51ace7..a2c44ec1a 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 @@ import android.view.animation.OvershootInterpolator; 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 class ButtonBounce { }); 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 1272bd641..dc6b81ff0 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific }, 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 b3d904dca..c31e7cbc5 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.graphics.drawable.Drawable; 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.ContactsController; 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.PaymentFormActivity; 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 class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 3cdf97268..df79fe294 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.os.Build; 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 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou 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 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou 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 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou 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 88ee6c00a..ee097417a 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 class ChatAvatarContainer extends FrameLayout implements NotificationCent 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 class ChatAvatarContainer extends FrameLayout implements NotificationCent 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 c8ec60367..ee1e89d3c 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.Paint; 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 class CropView extends FrameLayout implements CropAreaView.AreaViewListen 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(); } - entity.scale *= newScale; + 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.x = (point[0] - entity.viewWidth * entity.scale / 2) / canvasBitmap.getWidth(); - entity.y = (point[1] - entity.viewHeight * entity.scale / 2) / canvasBitmap.getHeight(); + entity.width = entity.width * w / bw * scale * stateScale; + entity.height = entity.height * h / bh * scale * stateScale; + } + + 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 32d0cf3dd..1cbdf7a73 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 class HintView extends FrameLayout { 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 ee98672b9..4ea5e09ae 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 class ItemOptions { } 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 class ItemOptions { } }); 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 class ItemOptions { 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 class ItemOptions { 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 class ItemOptions { 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 class ItemOptions { 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 class ItemOptions { } 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 8b98e3489..d22f0d272 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 class LinkActionView extends LinearLayout { } } + 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 9a987266d..ca7fd94f3 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 class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha 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 class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha @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 c122cebc6..8f637faf0 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 @@ public class MentionsContainerView extends BlurredFrameLayout implements Notific } + protected void onAnimationScroll() { + + } + public MentionsListView getListView() { return listView; } @@ -321,6 +325,7 @@ public class MentionsContainerView extends BlurredFrameLayout implements Notific 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 class MentionsContainerView extends BlurredFrameLayout implements Notific 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 @@ public class MentionsContainerView extends BlurredFrameLayout implements Notific ); 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 0caa6ffb9..15b35a048 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 @@ import org.telegram.messenger.AndroidUtilities; public class EntitiesContainerView extends FrameLayout { + public boolean drawForThumb; + public interface EntitiesContainerViewDelegate { boolean shouldReceiveTouches(); void onEntityDeselect(); @@ -98,4 +101,12 @@ public class EntitiesContainerView extends FrameLayout { 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 fea750cdc..1a520a579 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.Canvas; 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 class EntityView extends FrameLayout { 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 class EntityView extends FrameLayout { } } + 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 193cff35d..baa8a146f 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 class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh } 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 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 000000000..6982f1ddc --- /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 5b24da7d9..97119d049 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 @@ package org.telegram.ui.Components.Paint.Views; 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 21620c734..57e03ac11 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.LocaleController; 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 @@ import java.util.ArrayList; 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 class LimitPreviewView extends LinearLayout { 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 class LimitPreviewView extends LinearLayout { 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 class LimitPreviewView extends LinearLayout { @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 @@ public class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { @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 @@ public class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { limitIcon.setScaleY(1f); } limitIcon.setTranslationX(toX); - } else if (limitIcon != null){ + } else if (limitIcon != null) { limitIcon.setAlpha(0); } } @@ -342,14 +411,14 @@ public class LimitPreviewView extends LinearLayout { 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 class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { int h = getMeasuredHeight() - dp(8); float widthHalf = getMeasuredWidth() * arrowCenter; float x2 = Utilities.clamp(widthHalf + dp(8), getMeasuredWidth(), 0); - float x3 = Utilities.clamp(widthHalf + dp(10), getMeasuredWidth(), 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 @@ public class LimitPreviewView extends LinearLayout { 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 class LimitPreviewView extends LinearLayout { void createAnimationLayouts() { animatedLayouts.clear(); + if (isBoostsStyle && currentValue == 0) { + return; + } SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text); boolean direction = true; @@ -561,6 +676,55 @@ public class LimitPreviewView extends LinearLayout { } } + + 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 @@ public class LimitPreviewView extends LinearLayout { 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 class LimitPreviewView extends LinearLayout { } 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 95adcbaca..15f1d744e 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.AdminedChannelCell; 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } } } + if (type == TYPE_BOOSTS_FOR_POSTING) { + linkRow = rowCount++; + } notifyDataSetChanged(); } @@ -976,7 +1356,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } 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 7d94d33d6..68d1f2347 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 class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma } 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 bfda46e45..e30d22e70 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 class ChatSelectionReactionMenuOverlay extends FrameLayout { 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 377fcbefe..74295e18a 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 class CustomEmojiReactionsWindow { 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 class CustomEmojiReactionsWindow { @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 @@ public class CustomEmojiReactionsWindow { 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 a40e8b720..d42a0903f 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 class ReactionImageHolder { } 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 class ReactionImageHolder { 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 class ReactionImageHolder { 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 7c69975f7..239e57763 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 class ReactionsUtils { } 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 f813b5566..031d0f5a7 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 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } - 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 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 9029c2b4e..b9c69859d 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 class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 class SharedMediaLayout extends FrameLayout implements NotificationCenter } }); + 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 class SharedMediaLayout extends FrameLayout implements NotificationCenter } 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 class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 93e361d51..74cfd24de 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 class ViewPagerFixed extends FrameLayout { 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 class ViewPagerFixed extends FrameLayout { } 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 25799cfb7..5236856cb 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 class SpoilerEffect extends Drawable { 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 class SpoilerEffect extends Drawable { 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 class SpoilerEffect extends Drawable { } } + 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 ac65b446f..f12507edc 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 @@ public class SpoilerEffect2 { } 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; } - try { - surfaceTexture.release(); - } catch (Exception e) { - FileLog.e(e); + 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); + } + 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 7b6a3a473..42069a0c2 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 @@ public class SpoilerEffectBitmapFactory { 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 7ef2f7e3f..5ab9c4a61 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.LinearSmoothScrollerCustom; 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.Reactions.ReactionsLayoutInBubble; 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 DialogsActivity extends BaseFragment implements NotificationCenter. float animateFromSelectorPosition; boolean animateSwitchingSelector; UserListPoller poller; + public int additionalPadding; public DialogsRecyclerView(Context context, ViewPage page) { super(context); @@ -1959,15 +1966,24 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. } 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. } @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 class DialogsActivity extends BaseFragment implements NotificationCenter. .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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. } } } + if (storyHint != null) { + storyHint.hide(); + } + Bulletin.hideVisible(); return b; } @@ -6760,6 +6807,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. undoView[0].hide(true, 0); } super.onBecomeFullyHidden(); + canShowStoryHint = true; } @Override @@ -6785,6 +6833,12 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } } + updateFloatingButtonOffset(); + if (canShowStoryHint && !storyHintShown && storyHint != null && storiesEnabled) { + storyHintShown = true; + canShowStoryHint = false; + storyHint.show(); + } } private void showArchiveHelp() { @@ -9724,9 +9778,15 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 750c78fb5..80d3775b2 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.Reactions.ReactionsLayoutInBubble; 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 class EmojiAnimationsOverlay implements NotificationCenter.NotificationCe } } + 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 c4d5fb832..118cf8c9c 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.AutoDeleteMediaTask; 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.messenger.voip.VoIPService; 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } })); } 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 class LaunchActivity extends BasePermissionsActivity implements INavigati }); presentFragment(fragment); } else { - long dialog_id; boolean isBot = false; Bundle args = new Bundle(); @@ -4523,7 +4532,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } } })); - } 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 class LaunchActivity extends BasePermissionsActivity implements INavigati } 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 class LaunchActivity extends BasePermissionsActivity implements INavigati notFound = false; MessagesController.getInstance(currentAccount).putChats(res.chats, false); TLRPC.Chat chat = res.chats.get(0); - if (chat != null && 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati final Browser.Progress progress, final boolean forceNotInternalForApps, final int storyId, - boolean justAdded, + final boolean isBoost, TLRPC.User user, Runnable dismissLoading) { @@ -4689,7 +4704,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } + + 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 class LaunchActivity extends BasePermissionsActivity implements INavigati } public void checkAppUpdate(boolean force) { + if (!BuildVars.isStandaloneApp()) { + return; + } if (!force && BuildVars.DEBUG_VERSION || !force && !BuildVars.CHECK_UPDATES) { return; } @@ -7508,6 +7556,9 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati }; 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } 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 ff9498cc3..f8cbb3bb2 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 class LoginActivity extends BaseFragment implements NotificationCenter.No 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 6b2544bc0..37fe5cc14 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 class PaymentFormActivity extends BaseFragment implements NotificationCen } }); - 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 class PaymentFormActivity extends BaseFragment implements NotificationCen 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 d2b999602..7a9fe42d1 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 cd00efc1d..b0a23d6fd 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 class PrivacySettingsActivity extends BaseFragment implements Notificatio 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 class PrivacySettingsActivity extends BaseFragment implements Notificatio } 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 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio 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 class PrivacySettingsActivity extends BaseFragment implements Notificatio 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 class PrivacySettingsActivity extends BaseFragment implements Notificatio 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 a0ddfbd53..529c82d74 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.Animator; 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.content.res.Configuration; 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.MotionEvent; 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.LinkSpanDrawable; 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.UndoView; 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. ProfileGalleryView avatarsViewPager; private boolean hasStories; + private float progressToInsets = 1f; public void setAvatarsViewPager(ProfileGalleryView avatarsViewPager) { this.avatarsViewPager = avatarsViewPager; @@ -736,11 +750,16 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @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 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. canvas.drawRoundRect(rect, radius, radius, placeholderPaint); } } + canvas.restore(); } @Override @@ -764,6 +784,16 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } + 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. getMessagesStorage().clearSentMedia(); SharedConfig.setNoSoundHintShowed(false); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); - editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("speedhint").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("bganimationhint").remove("filterhint").remove("n_0").remove("storyprvhint").remove("storyhint").remove("storyhint2").remove("storydualhint").remove("storysvddualhint").remove("stories_camera").remove("dualcam").remove("dualmatrix").remove("dual_available").remove("archivehint").remove("askNotificationsAfter").remove("askNotificationsDuration").remove("viewoncehint").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 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. }; 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. } 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. } } else if (id == NotificationCenter.reloadDialogPhotos) { updateProfileData(false); + } else if (id == NotificationCenter.storiesUpdated) { + if (avatarImage != null) { + avatarImage.setHasStories(needInsetForStories()); + } } } @@ -6697,7 +6929,6 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. public void setAvatarAnimationProgress(float progress) { avatarAnimationProgress = currentExpandAnimatorValue = progress; checkPhotoDescriptionAlpha(); - if (playProfileAnimation == 2) { avatarImage.setProgressToExpand(progress); } @@ -6766,6 +6997,15 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 2a0b42942..f9cc14a72 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 @@ import java.util.List; 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 @@ public class QrActivity extends BaseFragment { } fragmentView.postDelayed(() -> { onItemSelected(currentTheme, 0, true); + logoImageView.getAnimatedDrawable().cacheFrame(LOGO_OPTIMAL_FRAME); }, 17); }, 25); @@ -714,10 +716,8 @@ public class QrActivity extends BaseFragment { 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 @@ public class QrActivity extends BaseFragment { 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 c4efb321f..71836eed4 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 class SecretMediaViewer implements NotificationCenter.NotificationCenterD @Override public void onAnimationEnd(Animator animation) { if (photoAnimationEndRunnable != null) { - Runnable r = photoAnimationEndRunnable; + photoAnimationEndRunnable.run(); photoAnimationEndRunnable = null; - r.run(); } } }); @@ -1966,9 +1965,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD 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 class SecretMediaViewer implements NotificationCenter.NotificationCenterD isVisible = false; AndroidUtilities.runOnUIThread(() -> { if (photoAnimationEndRunnable != null) { - Runnable r = photoAnimationEndRunnable; + photoAnimationEndRunnable.run(); photoAnimationEndRunnable = null; - r.run(); } }); } @@ -2163,9 +2160,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD @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 3f3e42eba..288cba787 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 @@ import java.util.Objects; 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 class SessionsActivity extends BaseFragment implements NotificationCenter listAdapter.notifyDataSetChanged(); } + if (delegate != null) { + delegate.sessionsLoaded(); + } + if (repeatLoad > 0) { repeatLoad--; if (repeatLoad > 0) { @@ -1243,7 +1250,7 @@ public class SessionsActivity extends BaseFragment implements NotificationCenter } } - 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 8cea04c7b..d0eb28908 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.os.Bundle; 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.JSONException; 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.data.StackLinearChartData; 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.LayoutHelper; 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 @@ import java.util.Locale; 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 class StatisticActivity extends BaseFragment implements NotificationCente @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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente }, 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 class StatisticActivity extends BaseFragment implements NotificationCente @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 class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } } } - 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 000000000..8db44201d --- /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 08aa749bd..cbbfb850e 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.DefaultItemAnimator; 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter } 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter if (index >= 0) { SpannableString spannableString = SpannableString.valueOf(textToSet); ellipsizeSpanAnimator.wrap(spannableString, index); + hasEllipsizedText = true; textToSet = spannableString; } } @@ -920,6 +917,11 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter } } - public StoryCell findSelfStoryCell() { + + public StoryCell findStoryCell(long dialogId) { RecyclerListView parent = recyclerListView; if (currentState == COLLAPSED_STATE) { parent = listViewMini; @@ -1049,7 +1054,7 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter return null; } + + public class StoryCell extends FrameLayout { public boolean drawInParent; public int position; @@ -1093,6 +1100,7 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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(); + + 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 { - 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); - } + 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(); - } else { if (drawAvatar) { - params.animate = true; + 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; - 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter } 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter } 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 3c5952a2b..80cc43583 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 class MessageMediaStoryFull extends TLRPC.TL_messageMediaStory { 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 4b0130062..7d20dedd3 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.graphics.ColorUtils; 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.AlertsCreator; 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.RLottieDrawable; 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.URLSpanNoUnderline; 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.Arrays; 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica super.dispatchDraw(canvas); drawLines(canvas); } + + if (emojiAnimationsOverlay != null) { + emojiAnimationsOverlay.draw(canvas); + } } @Override @@ -671,6 +702,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica @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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + emojiAnimationsOverlay.onDetachedFromWindow(); Bulletin.removeDelegate(this); if (delegate != null) { delegate.setBulletinIsVisible(false); @@ -725,10 +758,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } }; 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); } - 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); } - 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - if (!MessagesController.getInstance(currentAccount).premiumLocked) { + if (!MessagesController.getInstance(currentAccount).premiumLocked && !isChannel) { createStealthModeItem(popupLayout); } if (allowShareLink) { @@ -1403,14 +1472,11 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - 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); + 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); } - drawReactionEffect = true; - ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction); + } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (startFromPosition == -1) { updateSelectedPosition(); } + updatePosition(); if (chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.VISIBLE); chatActivityEnterView.getEditField().setText(storyViewer.getDraft(dialogId, currentStory.storyItem)); @@ -2430,7 +2562,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (selfView != null) { selfView.setVisibility(View.GONE); } - updatePosition(); + storyContainer.invalidate(); invalidate(); } @@ -2466,8 +2598,14 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica @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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } + 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica selectedPosition = storyItems.size() + uploadingStories.size() - 1; } updatePosition(); - if (isSelf) { - updateUserViews(); + if (isSelf || isChannel) { + updateUserViews(true); } } if (storyViewer.overrideUserStories != null) { @@ -2815,7 +2986,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica storyViewer.storiesViewPager.checkAllowScreenshots(); imageChanged = true; - if (isSelf) { - updateUserViews(); + if (isSelf || isChannel) { + updateUserViews(false); } final boolean sameId = @@ -3053,11 +3236,12 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica )) { 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - 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); - selfStatusView.setTranslationX(AndroidUtilities.dp(16)); + reactionsCounter.setText(Integer.toString(storyItem.views.reactions_count), animated && reactionsCounterVisible); + reactionsCounterVisible = true; } else { - selfAvatarsView.setVisibility(View.VISIBLE); - selfStatusView.setTranslationX(AndroidUtilities.dp(13) + AndroidUtilities.dp(24) + AndroidUtilities.dp(20) * (k - 1) + AndroidUtilities.dp(10)); + reactionsCounterVisible = false; } - 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 (!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 { + selfStatusView.setText(""); + } + 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica return false; } + public boolean viewsAllowed() { + return isSelf || (isChannel && userCanSeeViews); + } + public static class PeerHeaderView extends FrameLayout { public BackupImageView backupImageView; @@ -4367,7 +4642,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica void cancelOrDelete() { if (storyItem != null) { - storiesController.deleteStory(storyItem); + storiesController.deleteStory(dialogId, storyItem); } else if (uploadingStory != null) { uploadingStory.cancel(); } @@ -4378,7 +4653,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } @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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); likesReactionLayout.setMessage(null, null); } else { + bringChildToFront(likesReactionLayout); likesReactionLayout.reset(); } likesReactionLayout.setFragment(LaunchActivity.getLastFragment()); @@ -5382,8 +5678,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica .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 0386bb67c..88fd69c6a 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 static org.telegram.messenger.Utilities.clamp; 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.MessagesController; 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 class ProfileStoriesView extends View implements NotificationCenter.Notif } } - 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 class ProfileStoriesView extends View implements NotificationCenter.Notif 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif } 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 class ProfileStoriesView extends View implements NotificationCenter.Notif 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 class ProfileStoriesView extends View implements NotificationCenter.Notif @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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif } 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif // } } + 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 class ProfileStoriesView extends View implements NotificationCenter.Notif 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 c4cd57269..b87a37045 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 @@ public abstract class SelfStoriesPreviewView extends View { 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 994d48a14..e95b549b8 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 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente } } - 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 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente ((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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente public int totalCount; TLRPC.StoryItem storyItem; + private long dialogId; int currentAccount; boolean loading; ArrayList views = new ArrayList<>(); @@ -971,9 +973,10 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente } 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 ff177e741..94addcd90 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.FileLog; 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 class SelfStoryViewsView extends FrameLayout { 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 @@ public class SelfStoryViewsView extends FrameLayout { 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 165e1e1c4..4ad0efb02 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 @@ package org.telegram.ui.Stories; 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.AccountInstance; 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.RequestDelegate; 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.Iterator; 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 class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { }); } - 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 @@ public class StoriesController { i--; } } - if (!removed && userStories.stories.isEmpty()) { + if (!removed && userStories.stories.isEmpty() && !hasUploadingStories(dialogId)) { list.remove(k); k--; } @@ -225,13 +232,32 @@ public class StoriesController { } public boolean hasStories(long dialogId) { - if (getSelfUserId() == dialogId && hasUploadingStories()) { + if (dialogId == 0) { + return false; + } + if (hasUploadingStories(dialogId)) { return true; } - TLRPC.TL_userStories stories = allStoriesMap.get(dialogId); + if (isLastUploadingFailed(dialogId)) { + return true; + } + 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 class StoriesController { } 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { } 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 @@ public class StoriesController { } 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 class StoriesController { 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 @@ public class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { } } 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 @@ public class StoriesController { 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 @@ public class StoriesController { } 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 @@ public class StoriesController { } 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { } 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { } 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 class StoriesController { 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 class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 class StoriesController { 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 class StoriesController { } 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 class StoriesController { }); } - 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 class StoriesController { } } - 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 class StoriesController { 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 class StoriesController { 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 @@ public class StoriesController { } 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 class StoriesController { 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 class StoriesController { } 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 class StoriesController { } 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 StoriesController { public boolean hadFailed; public boolean failed; + long dialogId; public UploadingStory(StoryEntry entry) { this.entry = entry; @@ -1400,6 +1588,16 @@ public class StoriesController { 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 class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { } 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 @@ public class StoriesController { } } } - 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 @@ public class StoriesController { } 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 @@ public class StoriesController { 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 class StoriesController { 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 @@ public class StoriesController { } } - 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 class StoriesController { } } - 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 @@ public class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { // } 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 class StoriesController { } 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 class StoriesController { } } - 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 class StoriesController { } 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { } } } + + 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 e5ddb45c8..258a6b1ef 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 class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { 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 110a54783..515872641 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.SQLiteException; 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 class StoriesStorage { 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 class StoriesStorage { } 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 class StoriesStorage { 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 @@ public class StoriesStorage { } - 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 class StoriesStorage { } } - 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 class StoriesStorage { 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 class StoriesStorage { } } 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 class StoriesStorage { }); } - 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 @@ public class StoriesStorage { } - 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 @@ public class StoriesStorage { } 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 @@ public class StoriesStorage { } 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 class StoriesStorage { 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 class StoriesStorage { }); } - 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 class StoriesStorage { 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 class StoriesStorage { } 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 class StoriesStorage { }); } - 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 77d8d1f43..2bc804ded 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 android.widget.TextView; 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 class StoriesUtilities { 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 class StoriesUtilities { } 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 class StoriesUtilities { } 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 class StoriesUtilities { } 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 @@ public class StoriesUtilities { } 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 @@ public class StoriesUtilities { } 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 @@ public class StoriesUtilities { 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 @@ public class StoriesUtilities { } 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 class StoriesUtilities { 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 class StoriesUtilities { 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 class StoriesUtilities { } } - 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 class StoriesUtilities { } } - 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 class StoriesUtilities { public float crossfadeToDialogProgress; public float progressToProgressSegments; public float alpha = 1f; + public boolean drawInside; private long dialogId; public int currentState; @@ -1040,12 +1082,22 @@ public class StoriesUtilities { 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 @@ public class StoriesUtilities { 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 @@ public class StoriesUtilities { 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 @@ public class StoriesUtilities { } } 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 f7c11ef77..b891e1fbd 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 class StoriesVolumeContorl extends View { 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 282a61159..d9add7657 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 StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { } 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 class StoryCaptionView extends NestedScrollView { 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 b742d6c4b..52d690fe4 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.AnimatedFloat; 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 class StoryMediaAreasView extends FrameLayout implements View.OnClickList 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 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList 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 class StoryMediaAreasView extends FrameLayout implements View.OnClickList 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 class StoryMediaAreasView extends FrameLayout implements View.OnClickList return; } + if (v instanceof StoryReactionWidgetView) { + showEffect((StoryReactionWidgetView) v); + return; + } if (selectedArea == v) { AndroidUtilities.runOnUIThread(() -> { if (hintView != null) { @@ -250,6 +284,10 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList onHintVisible(true); } + public void showEffect(StoryReactionWidgetView v) { + + } + public void closeHint() { if (hintView != null) { hintView.hide(); @@ -367,6 +405,39 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList 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 000000000..95c43914e --- /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 52c7a32c8..b34f09049 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.graphics.RectF; 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 androidx.viewpager.widget.ViewPager; 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.SharedConfig; 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat } @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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat surfaceView.setVisibility(View.VISIBLE); } } + updatePlayingMode(); } @Override @@ -1612,9 +1617,9 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat } 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat if (peerStoriesView != null) { peerStoriesView.sharedResources.setIconMuted(!soundEnabled(), true); } + if (!isInSilentMode) { + volumeControl.unmute(); + } } private void checkInSilentMode() { @@ -1839,12 +1847,10 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat } 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat } 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 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat } public boolean closeKeyboardOrEmoji() { + if (storiesViewPager == null) { + return false; + } final PeerStoriesView peerStoriesView = storiesViewPager.getCurrentPeerView(); if (peerStoriesView != null) { return peerStoriesView.closeKeyboardOrEmoji(); @@ -2204,7 +2213,7 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat } 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat } 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat storiesViewPager.getAdapter().notifyDataSetChanged(); } } + if (selfStoryViewsView != null) { + selfStoryViewsView.selfStoriesPreviewView.update(); + } } else if (id == NotificationCenter.openArticle || id == NotificationCenter.articleClosed) { updatePlayingMode(); } @@ -2495,7 +2508,6 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat } } - static int queuePointer = 0; - public class VideoPlayerHolder extends VideoPlayerHolderBase { boolean logBuffering; @@ -2597,6 +2613,9 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat } 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 000000000..20507423e --- /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 7f00900d0..7edc237b7 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 class UserListPoller { 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 class UserListPoller { 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 d501ed4c7..ab3570641 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.messenger.UserConfig; 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 class ViewsForSelfStoriesRequester { } } 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 @@ public class ViewsForSelfStoriesRequester { 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 @@ public class ViewsForSelfStoriesRequester { } 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 d11305670..3631309cd 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.Matrix; 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 class CaptionContainerView extends FrameLayout { 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 class CaptionContainerView extends FrameLayout { } } 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 class CaptionContainerView extends FrameLayout { 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(); + blurBitmap = null; } - blurBitmapShader.setLocalMatrix(blurBitmapMatrix); - if (blurPaint == null) { - blurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); - blurPaint.setColor(0xffffffff); - } - blurPaint.setShader(blurBitmapShader); } } @@ -957,6 +961,7 @@ public class CaptionContainerView extends FrameLayout { 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 15b10cb9b..6b3f16f63 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 class DraftsController { 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 class DraftsController { this.audioLeft = entry.audioLeft; this.audioRight = entry.audioRight; this.audioVolume = entry.audioVolume; + + this.peer = entry.peer; } public StoryEntry toEntry() { @@ -624,6 +628,7 @@ public class DraftsController { entry.audioLeft = audioLeft; entry.audioRight = audioRight; entry.audioVolume = audioVolume; + entry.peer = peer; return entry; } @@ -732,6 +737,11 @@ public class DraftsController { 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 class DraftsController { 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 994ee0d50..8b957ff46 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.EmojiTabsStrip; 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 org.telegram.ui.WrappedResourceProvider; 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. } } + 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. } 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. } } + 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 e735d2a47..178964bba 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 class KeyboardNotifier { } 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 02a0ba6bf..c08668463 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.PorterDuffColorFilter; 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.Layout; 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 androidx.dynamicanimation.animation.SpringForce; 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.AnimatedEmojiDrawable; 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.PaintToolsView; 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai dismiss(); enteredThroughText = false; } + showReactionsLayout(false); } }) { Paint linePaint = new Paint(); @@ -472,7 +488,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai { setWillNotDraw(false); - linePaint.setStrokeWidth(AndroidUtilities.dp(2)); + linePaint.setStrokeWidth(dp(2)); linePaint.setStyle(Paint.Style.STROKE); linePaint.setColor(Color.WHITE); } @@ -519,11 +535,11 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai // 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai { 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai ); 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai }); 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai @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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai @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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai }); 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } }); } - 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } registerRemovalUndo(entityView); - selectEntity(entityView); + selectEntity(null); + appearAnimation(entityView); } private Point startPositionRelativeToEntity(EntityView entityView) { @@ -3159,7 +3505,8 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai }); popupLayout.setShownFromBottom(true); } + popupLayout.enableBounce = blurAndBounce; popupLayout.removeInnerViews(); setupRunnable.run(); @@ -3236,7 +3618,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai @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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai @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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai @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 53727c7ee..761747a7e 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.net.Uri; 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 class PreviewView extends FrameLayout { 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 class PreviewView extends FrameLayout { } }); 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 class PreviewView extends FrameLayout { } } 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 class PreviewView extends FrameLayout { 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 class PreviewView extends FrameLayout { return; } entry.right = right; + entry.editedMedia = true; } @Override @@ -274,6 +287,7 @@ public class PreviewView extends FrameLayout { return; } entry.audioLeft = left; + entry.editedMedia = true; updateAudioPlayer(true); } @@ -283,6 +297,7 @@ public class PreviewView extends FrameLayout { return; } entry.audioRight = right; + entry.editedMedia = true; updateAudioPlayer(true); } @@ -292,6 +307,7 @@ public class PreviewView extends FrameLayout { return; } entry.audioOffset = offset; + entry.editedMedia = true; updateAudioPlayer(true); } @@ -306,6 +322,7 @@ public class PreviewView extends FrameLayout { return; } entry.audioVolume = volume; + entry.editedMedia = true; if (audioPlayer != null) { audioPlayer.setVolume(volume); } @@ -594,7 +611,7 @@ public class PreviewView extends FrameLayout { 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 class PreviewView extends FrameLayout { } // 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 0be5cebb5..284dea419 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.Emoji; 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 class StoryEntry extends IStoryPart { clearFilter(); if (file != null) { if (fileDeletable && (!isEdit || editedMedia)) { - file.delete(); + file.delete(); } file = null; } @@ -505,6 +507,10 @@ public class StoryEntry extends IStoryPart { part.file = null; } } + if (thumbPathBitmap != null) { + thumbPathBitmap.recycle(); + thumbPathBitmap = null; + } cancelCheckStickers(); } @@ -513,7 +519,7 @@ public class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { } }); } + } 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 class StoryEntry extends IStoryPart { 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 73b276080..df3a45a14 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.AnimatorListenerAdapter; 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.LinearLayout; 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.tgnet.TLRPC; 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.Cells.TextInfoPrivacyCell; 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification adapter.notifyDataSetChanged(); } } + + this.contentView.invalidate(); } private boolean match(TLObject obj, String q) { @@ -1655,7 +1648,7 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification @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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification }); MessagesController.getInstance(currentAccount).getStoriesController().loadBlocklist(false); + MessagesController.getInstance(currentAccount).getStoriesController().loadSendAs(); } private void init(Context context) { @@ -1949,6 +1950,7 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification this.onDone2 = onDone2; return this; } + public StoryPrivacyBottomSheet whenSelectedPeer(Utilities.Callback onSelectedPeer) { + this.onSelectedPeer = onSelectedPeer; + return this; + } public StoryPrivacyBottomSheet enableSharing(boolean enable) { this.sendAsMessageEnabled = enable; if (viewPager != null) { @@ -2270,6 +2286,18 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification public boolean checked; public boolean halfChecked; public boolean red; + public boolean sendAs; public int subtractHeight; public int padHeight = -1; @@ -2354,6 +2384,11 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification this.red = red; return this; } + + public ItemInner asSendAs() { + sendAs = true; + return this; + } } private boolean loadedContacts; @@ -2582,6 +2624,10 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } } 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } } + } 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification .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 dbb78bafe..538e0c0c9 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 class StoryPrivacySelector extends View { 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 73f6565f1..313388372 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.AlertDialog; 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.VideoEditTextureView; 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private int openType; private float dismissProgress; private Float frozenDismissProgress; + private boolean canChangePeer = true; + long selectedDialogId; public static class SourceView { @@ -232,10 +236,44 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg captionContainer.setAlpha(openProgress); } } + if (paintView != null) { + paintView.onParentPreDraw(); + } super.dispatchDraw(canvas); if (restore) { canvas.restore(); @@ -1067,6 +1108,12 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg }) .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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg outputEntry.privacyRules.clear(); outputEntry.privacyRules.addAll(privacy.rules); outputEntry.editedPrivacy = true; + outputEntry.peer = sendAs; applyFilter(() -> { whenDone.run(); upload(true); @@ -2129,7 +2195,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } }; if (closingSourceProvider != null) { - closingSourceProvider.preLayout(runnable); + closingSourceProvider.preLayout(sendAsDialogId, runnable); } else { runnable.run(); } @@ -2235,7 +2301,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg @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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg @Override public void onEntityDragMultitouchStart() { multitouch = true; + paintView.showReactionsLayout(false); trash.onDragInfo(false, false); trash.clearAnimation(); trash.animate().alpha(0f).withEndAction(() -> { @@ -3569,8 +3648,44 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } @Override - public void onEntityHandleTouched() { + 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } } + 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } } 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg .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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } } + 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 6269e2676..c3747009b 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.Layout; 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 @@ public class TimelineView extends View { 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 class TimelineView extends View { }) .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 @@ public class TimelineView extends View { } } - 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 class TimelineView extends View { } 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 @@ public class TimelineView extends View { 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 class TimelineView extends View { } 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 @@ public class TimelineView extends View { } }, 150); } + return true; } private float getVideoHeight() { @@ -476,6 +483,7 @@ public class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { } 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 class TimelineView extends View { } } 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 class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { } 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 class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { AndroidUtilities.cancelRunOnUIThread(askExactSeek); askExactSeek = null; } - if (dragged && delegate != null) { + if (dragged && scrollStopped && delegate != null) { delegate.onProgressDragChange(false); } dragged = false; @@ -743,10 +730,104 @@ public class TimelineView extends View { 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 class TimelineView extends View { // 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; - } - if (delegate != null && changedLeftRight) { - delegate.onAudioLeftChange(audioLeft); - delegate.onAudioRightChange(audioRight); - } + 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 (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); + } } } @@ -859,7 +1018,7 @@ public class TimelineView extends View { Path.Direction.CW ); canvas.clipPath(selectedVideoClipPath, Region.Op.DIFFERENCE); - canvas.drawColor(0x80000000); + canvas.drawColor(0x50000000); canvas.restore(); } @@ -902,34 +1061,8 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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); + 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(); } - 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(); } } } 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { (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 @@ public class TimelineView extends View { (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 ac60c2d4d..3ff01db57 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.PorterDuffXfermode; 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 @@ public class VolumeSliderView extends View { 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 @@ public class VolumeSliderView extends View { private float lastTouchX; + private long pressTime; @Override public boolean dispatchTouchEvent(MotionEvent event) { @@ -139,18 +147,34 @@ public class VolumeSliderView extends View { } 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 @@ public class VolumeSliderView extends View { 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 000000000..306770b48 --- /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 000000000..12649abb0 --- /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 000000000..cbba96099 --- /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 503731c95..3b3dc98ad 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 9f0b2df9d..9728ec17e 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 2f7d61dd6..270b278b3 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 b578b6196..cd31b8a79 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 com.microsoft.appcenter.distribute.Distribute; 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 @@ public class ApplicationLoaderImpl extends ApplicationLoader { } } + @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 000000000..42afabfd2 --- /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 000000000..4c6df91fa --- /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 000000000..640e841b2 --- /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 000000000..6e6e6011c --- /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 000000000..ee444d935 --- /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 000000000..aa38318ed --- /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 000000000..25af0a81f --- /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 b25f7af81..b50b7cbea 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 9a0eef931..dd7a48e7c 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'