/* * 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.ui.Cells; import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.AndroidUtilities.dpf2; import static org.telegram.messenger.AndroidUtilities.find; import static org.telegram.messenger.AndroidUtilities.lerp; import static org.telegram.messenger.LocaleController.formatPluralString; import static org.telegram.messenger.LocaleController.formatPluralStringComma; import static org.telegram.messenger.LocaleController.formatString; import static org.telegram.messenger.LocaleController.getString; import static org.telegram.messenger.MessageObject.getMedia; import static org.telegram.messenger.MessageObject.replaceWithLink; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.Keyframe; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.CornerPathEffect; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.Shader; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.text.LineBreaker; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.DynamicDrawableSpan; import android.text.style.LeadingMarginSpan; import android.text.style.StrikethroughSpan; import android.text.style.URLSpan; import android.util.Pair; import android.util.Property; import android.util.SparseArray; import android.util.StateSet; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewStructure; import android.view.Window; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeProvider; import android.view.animation.Interpolator; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import androidx.core.math.MathUtils; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AppGlobalConfig; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BotForumHelper; import org.telegram.messenger.BotInlineKeyboard; import org.telegram.messenger.ChatMessageSharedResources; import org.telegram.messenger.ChatObject; import org.telegram.utils.code.highlight.CodeHighlighting; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.DownloadController; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.FlagSecureReason; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LiteMode; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.RichMessageLayout; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.TranslateController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.WebFile; import org.telegram.messenger.browser.Browser; import org.telegram.messenger.utils.Choreographer60FpsContent; import org.telegram.messenger.utils.CountdownTimer; import org.telegram.messenger.utils.DrawableUtils; import org.telegram.messenger.utils.tlutils.TLKeyboardHelper; import org.telegram.messenger.utils.tlutils.TlUtils; import org.telegram.messenger.video.OldVideoPlayerRewinder; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_keyboard; import org.telegram.tgnet.tl.TL_iv; import org.telegram.tgnet.tl.TL_stars; import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.MessageDrawable; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.AvatarSpan; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AnimatedNumberLayout; import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.AudioVisualizerDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.AvatarsDrawable; import org.telegram.ui.Components.BackgroundGradientDrawable; import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.CheckBoxBase; import org.telegram.ui.Components.ClipRoundedDrawable; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmptyStubSpan; import org.telegram.ui.Components.FloatSeekBarAccessibilityDelegate; import org.telegram.ui.Components.ForegroundColorSpanThemable; import org.telegram.ui.Components.FormattedDateSpan; import org.telegram.ui.Components.ForwardBackground; import org.telegram.ui.Components.InfiniteProgress; import org.telegram.ui.Components.LinkPath; import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.LoadingDrawable; import org.telegram.ui.Components.MediaActionDrawable; import org.telegram.ui.Components.MessageBackgroundDrawable; import org.telegram.ui.Components.MotionBackgroundDrawable; import org.telegram.ui.Components.MsgClockDrawable; import org.telegram.ui.Components.PostRunnableHolder; import org.telegram.ui.Components.Premium.boosts.BoostCounterSpan; import org.telegram.ui.Components.Premium.boosts.cells.msg.GiveawayMessageCell; import org.telegram.ui.Components.Premium.boosts.cells.msg.GiveawayResultsMessageCell; import org.telegram.ui.Components.QuoteHighlight; import org.telegram.ui.Components.QuoteSpan; import org.telegram.ui.Components.RLottieDiceDrawable; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RadialProgress2; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ReplyMessageLine; import org.telegram.ui.Components.RoundVideoPlayingDrawable; import org.telegram.ui.Components.SeekBar; import org.telegram.ui.Components.SeekBarAccessibilityDelegate; import org.telegram.ui.Components.SeekBarWaveform; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.SlotsDrawable; import org.telegram.ui.Components.StaticLayoutEx; import org.telegram.ui.Components.StickerSetLinkIcon; import org.telegram.ui.Components.SuggestionOffer; import org.telegram.ui.Components.SummaryIcon; import org.telegram.ui.Components.Text; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.TimerParticles; import org.telegram.ui.Components.TopicButton; import org.telegram.ui.Components.TopicSeparator; import org.telegram.ui.Components.TornEdge; import org.telegram.ui.Components.TranscribeButton; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanBotCommand; import org.telegram.ui.Components.URLSpanBrowser; import org.telegram.ui.Components.URLSpanMono; import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.VectorAvatarThumbDrawable; import org.telegram.ui.Components.VideoForwardDrawable; import org.telegram.ui.Components.AvatarsListDrawable; import org.telegram.ui.Components.chat.ChatActivityDraftMessageMeasureController; import org.telegram.ui.Components.poll.PollAttachedMediaPack; import org.telegram.ui.Components.poll.PollUtils; import org.telegram.ui.Components.poll.buttons.PollAddButtonDrawable; import org.telegram.ui.Components.poll.buttons.PollButtonDrawable; import org.telegram.ui.Components.poll.PollContentDrawable; import org.telegram.ui.Components.poll.buttons.PollInstantButtonDrawable; import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.Components.spoilers.SpoilerEffect2; import org.telegram.ui.GradientClip; import org.telegram.ui.MultiLayoutTypingAnimator; import org.telegram.ui.PhotoViewer; import org.telegram.ui.PinchToZoomHelper; import org.telegram.ui.SecretMediaViewer; import org.telegram.ui.Stars.StarGiftPatterns; import org.telegram.ui.Stars.StarGiftSheet; import org.telegram.ui.Stars.StarsController; import org.telegram.ui.Stars.StarsIntroActivity; import org.telegram.ui.Stars.StarsReactionsSheet; import org.telegram.ui.Stories.StoriesUtilities; import org.telegram.ui.Stories.StoryViewer; import org.telegram.ui.Stories.recorder.CaptionContainerView; import org.telegram.ui.Stories.recorder.DominantColors; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Stack; import java.util.concurrent.atomic.AtomicReference; import me.vkryl.android.animator.BoolAnimator; import me.vkryl.android.animator.FactorAnimator; import me.vkryl.core.BitwiseUtils; public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate, ImageReceiver.ImageReceiverDelegate, DownloadController.FileDownloadProgressListener, TextSelectionHelper.SelectableView, NotificationCenter.NotificationCenterDelegate, FactorAnimator.Target, IMessageCell { private final static int TIME_APPEAR_MS = 200; private final static int UPLOADING_ALLOWABLE_ERROR = 1024 * 1024; private final static int STICKER_STATUS_OFFSET = 6; private final static float EPHEMERAL_HINT_HEIGHT = 25f; public boolean clipToGroupBounds; public boolean drawForBlur; private boolean flipImage; private boolean visibleOnScreen = true; public boolean shouldCheckVisibleOnScreen; public float parentBoundsTop; public int parentBoundsBottom; public ExpiredStoryView expiredStoryView; private boolean skipFrameUpdate; public ChannelRecommendationsCell channelRecommendationsCell; private final PostRunnableHolder postRunnableHolder = new PostRunnableHolder(); public RadialProgress2 getRadialProgress() { return radialProgress; } boolean enterTransitionInProgress; public void setEnterTransitionInProgress(boolean b) { enterTransitionInProgress = b; invalidate(); } public ReactionsLayoutInBubble.ReactionButton getReactionButton(ReactionsLayoutInBubble.VisibleReaction visibleReaction) { return reactionsLayoutInBubble.getReactionButton(visibleReaction); } // primary message for group // contains caption, reactions etc for all group public MessageObject getPrimaryMessageObject() { MessageObject messageObject = null; if (currentMessageObject != null && currentMessagesGroup != null && currentMessageObject.hasValidGroupId()) { messageObject = currentMessagesGroup.findPrimaryMessageObject(); } if (messageObject != null) { return messageObject; } return currentMessageObject; } @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.startSpoilers) { setSpoilersSuppressed(false); } else if (id == NotificationCenter.stopSpoilers) { setSpoilersSuppressed(true); } else if (id == NotificationCenter.userInfoDidLoad) { if (currentUser != null) { Long uid = (Long) args[0]; if (currentUser.id == uid) { setAvatar(currentMessageObject); } } } else if (id == NotificationCenter.emojiLoaded) { invalidate(); } else if (id == NotificationCenter.didUpdatePremiumGiftStickers) { MessageObject messageObject = currentMessageObject; if (messageObject != null && (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveaway || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults)) { setMessageObject(messageObject, currentMessagesGroup, pinnedBottom, pinnedTop, firstInChat); } } } public void setAvatar(MessageObject messageObject) { if (messageObject == null) { return; } if (isAvatarVisible) { if (messageObject.customAvatarDrawable != null) { avatarImage.setImageBitmap(messageObject.customAvatarDrawable); } else if (currentUser != null) { if (currentUser.photo != null) { currentPhoto = currentUser.photo.photo_small; } else { currentPhoto = null; } avatarDrawable.setInfo(currentAccount, currentUser); avatarImage.setForUserOrChat(currentUser, avatarDrawable, null, LiteMode.isEnabled(LiteMode.FLAGS_CHAT), VectorAvatarThumbDrawable.TYPE_SMALL, false); } else if (currentChat != null) { if (currentChat.photo != null) { currentPhoto = currentChat.photo.photo_small; } else { currentPhoto = null; } if (currentChat.signature_profiles && messageObject.getDialogId() != UserObject.REPLY_BOT) { final long did = DialogObject.getPeerDialogId(messageObject.messageOwner.from_id); if (did >= 0) { final TLRPC.User user = MessagesController.getInstance(messageObject.currentAccount).getUser(did); avatarDrawable.setInfo(currentAccount, user); avatarImage.setForUserOrChat(user, avatarDrawable); } else { final TLRPC.Chat chat = MessagesController.getInstance(messageObject.currentAccount).getChat(-did); avatarDrawable.setInfo(currentAccount, chat); avatarImage.setForUserOrChat(chat, avatarDrawable); } } else { avatarDrawable.setInfo(currentAccount, currentChat); avatarImage.setForUserOrChat(currentChat, avatarDrawable); } } else if (messageObject.isSponsored()) { if (messageObject.sponsoredPhoto != null) { avatarImage.setImage(ImageLocation.getForPhoto(FileLoader.getClosestPhotoSizeWithSize(messageObject.sponsoredPhoto.sizes, dp(50), false, null, true), messageObject.sponsoredPhoto), "50_50", avatarDrawable, null, null, 0); } } else { currentPhoto = null; avatarDrawable.setInfo(messageObject.getFromChatId(), null, null); avatarImage.setImage(null, null, avatarDrawable, null, null, 0); } } else { currentPhoto = null; } } public void setSpoilersSuppressed(boolean s) { for (int i = 0; i < replySpoilers.size(); i++) { SpoilerEffect eff = replySpoilers.get(i); eff.setSuppressUpdates(s); } if (captionLayout != null && captionLayout.textLayoutBlocks != null) { for (int k = 0; k < captionLayout.textLayoutBlocks.size(); k++) { MessageObject.TextLayoutBlock bl = captionLayout.textLayoutBlocks.get(k); for (int i = 0; i < bl.spoilers.size(); i++) { SpoilerEffect eff = bl.spoilers.get(i); eff.setSuppressUpdates(s); } } } if (getMessageObject() != null && getMessageObject().textLayoutBlocks != null) { for (int k = 0; k < getMessageObject().textLayoutBlocks.size(); k++) { MessageObject.TextLayoutBlock bl = getMessageObject().textLayoutBlocks.get(k); for (int i = 0; i < bl.spoilers.size(); i++) { SpoilerEffect eff = bl.spoilers.get(i); eff.setSuppressUpdates(s); } } } } public boolean hasSpoilers() { if (captionLayout != null && captionLayout.textLayoutBlocks != null) { for (MessageObject.TextLayoutBlock bl : captionLayout.textLayoutBlocks) { if (!bl.spoilers.isEmpty()) { return true; } } } if (getMessageObject() != null && getMessageObject().textLayoutBlocks != null) { for (MessageObject.TextLayoutBlock bl : getMessageObject().textLayoutBlocks) { if (!bl.spoilers.isEmpty()) { return true; } } } return false; } private void updateSpoilersVisiblePart(int top, int bottom) { if (captionLayout != null && captionLayout.textLayoutBlocks != null) { for (MessageObject.TextLayoutBlock bl : captionLayout.textLayoutBlocks) { for (SpoilerEffect eff : bl.spoilers) { eff.setVisibleBounds(0, top - bl.textYOffset(captionLayout.textLayoutBlocks, transitionParams) - captionX, getWidth(), bottom - bl.textYOffset(captionLayout.textLayoutBlocks, transitionParams) - captionY); } } } if (replyTextLayout != null) { float off = -replyStartY - replyTextLayout.getHeight(); for (SpoilerEffect eff : replySpoilers) { eff.setVisibleBounds(0, top + off, getWidth(), bottom + off); } } if (getMessageObject() != null && getMessageObject().textLayoutBlocks != null) { for (MessageObject.TextLayoutBlock bl : getMessageObject().textLayoutBlocks) { for (SpoilerEffect eff : bl.spoilers) { eff.setVisibleBounds(0, top - bl.textYOffset(getMessageObject().textLayoutBlocks, transitionParams) - textY, getWidth(), bottom - bl.textYOffset(getMessageObject().textLayoutBlocks, transitionParams) - textY); } } } } public void setScrimReaction(Integer scrimViewReaction) { reactionsLayoutInBubble.setScrimReaction(scrimViewReaction); } public void drawScrimReaction(Canvas canvas, Integer scrimViewReaction, float progress, boolean direction) { if ((currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) && !reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.setScrimProgress(progress, direction); reactionsLayoutInBubble.draw(canvas, transitionParams.animateChangeProgress, scrimViewReaction); } } public void drawScrimReactionPreview(View view, Canvas canvas, int offset, Integer scrimViewReaction, float progress) { if ((currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) && !reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.setScrimProgress(progress); reactionsLayoutInBubble.drawPreview(view, canvas, offset, scrimViewReaction); } } public boolean checkUnreadPollVotes() { if (currentMessageObject == null || currentMessageObject.type != MessageObject.TYPE_POLL) { return false; } TLRPC.MessageMedia m = MessageObject.getMedia(currentMessageObject.messageOwner); if (m instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll poll = (TLRPC.TL_messageMediaPoll) m; return poll.results.has_unread_votes; } return false; } public boolean checkUnreadReactions(float clipTop, int clipBottom) { if (!reactionsLayoutInBubble.hasUnreadReactions) { return false; } float y = getY() + reactionsLayoutInBubble.y; if (y > clipTop && y + reactionsLayoutInBubble.height - dp(16) < clipBottom) { return true; } return false; } public void markReactionsAsRead() { reactionsLayoutInBubble.hasUnreadReactions = false; if (currentMessageObject == null) { return; } currentMessageObject.markReactionsAsRead(); } public void markPollVotesAsRead() { if (currentMessageObject == null) { return; } currentMessageObject.markPollVotesAsRead(); } public void setVisibleOnScreen(boolean visibleOnScreen, float clipTop, float clipBottom) { if (this.visibleOnScreen != visibleOnScreen) { this.visibleOnScreen = visibleOnScreen; checkImageReceiversAttachState(); if (visibleOnScreen) { invalidate(); } } clipTop -= photoImage.getImageY(); clipBottom -= (getMeasuredHeight() - photoImage.getImageY2()); float visibleImageHeight = photoImage.getImageHeight(); if (clipTop > 0) { visibleImageHeight -= clipTop; } if (clipBottom > 0) { visibleImageHeight -= clipBottom; } photoImage.setSkipUpdateFrame(skipFrameUpdate = visibleImageHeight / photoImage.getImageHeight() < 0.25f); } public void setParentBounds(float chatListViewPaddingTop, int blurredViewBottomOffset) { parentBoundsTop = chatListViewPaddingTop; parentBoundsBottom = blurredViewBottomOffset; if (photoImageOutOfBounds) { float top = getY() + getPaddingTop() + photoImage.getImageY(); float bottom = top + photoImage.getImageHeight(); if (bottom >= parentBoundsTop && top <= parentBoundsBottom) { invalidate(); } } } public void setSponsoredMessageVisible(boolean isVisible, boolean animated) { isSponsoredMessageHidden.setValue(!isVisible, animated); } private static final int SPONSORED_MESSAGE_HIDDEN_ANIMATOR_ID = 0; private final BoolAnimator isSponsoredMessageHidden = new BoolAnimator(SPONSORED_MESSAGE_HIDDEN_ANIMATOR_ID, this, CubicBezierInterpolator.EASE_OUT_QUINT, 380); @Override public void onFactorChanged(int id, float factor, float fraction, FactorAnimator callee) { if (id == SPONSORED_MESSAGE_HIDDEN_ANIMATOR_ID) { invalidate(); invalidateOutbounds(); } } public interface ChatMessageCellDelegate { default boolean isReplyOrSelf() { return false; } default boolean canToggleRichMessageCheckbox(ChatMessageCell cell) { return false; } default void didToggleRichMessageCheckbox(ChatMessageCell cell, boolean checked, Runnable revertOnError) { } default void didPressExtendedMediaPreview(ChatMessageCell cell, TL_keyboard.KeyboardInlineButton button) { } default void didPressUserStatus(ChatMessageCell cell, TLRPC.User user, TLRPC.Document document, String giftSlug) { } default void didPressUserAvatar(ChatMessageCell cell, TLRPC.User user, float touchX, float touchY, boolean asForward) { } default boolean didLongPressUserAvatar(ChatMessageCell cell, TLRPC.User user, float touchX, float touchY) { return false; } default void didPressHiddenForward(ChatMessageCell cell) { } default void didPressViaBotNotInline(ChatMessageCell cell, long botId) { } default void didPressViaBot(ChatMessageCell cell, String username) { } default void didPressBoostCounter(ChatMessageCell cell) { } default void didPressChannelAvatar(ChatMessageCell cell, TLRPC.Chat chat, int postId, float touchX, float touchY, boolean asForward) { } default boolean didLongPressChannelAvatar(ChatMessageCell cell, TLRPC.Chat chat, int postId, float touchX, float touchY) { return false; } default void didPressCancelSendButton(ChatMessageCell cell) { } default void didLongPress(ChatMessageCell cell, float x, float y) { } default void didPressReplyMessage(ChatMessageCell cell, int id, float x, float y, boolean longpress) { } default boolean isProgressLoading(ChatMessageCell cell, int type) { return false; } default String getProgressLoadingBotButtonUrl(ChatMessageCell cell) { return null; } default CharacterStyle getProgressLoadingLink(ChatMessageCell cell) { return null; } default void didPressUrl(ChatMessageCell cell, CharacterStyle url, boolean longPress) { } default void didPressCodeCopy(ChatMessageCell cell, MessageObject.TextLayoutBlock block) { } default void didPressChannelRecommendation(ChatMessageCell cell, TLObject chat, boolean longPress) { } default void didPressMoreChannelRecommendations(ChatMessageCell cell) { } default void didPressChannelRecommendationsClose(ChatMessageCell cell) { } default int getChatMode() { return ChatActivity.MODE_DEFAULT; } default void needOpenWebView(MessageObject message, String url, String title, String description, String originalUrl, int w, int h) { } default void didPressWebPage(ChatMessageCell cell, TLRPC.WebPage webpage, String url, boolean safe) { Browser.openUrl(cell.getContext(), url); } default void didPressImage(ChatMessageCell cell, float x, float y, boolean fullPreview) { } default void didPressPollMedia(ChatMessageCell cell, ImageReceiver imageReceiver, TLRPC.PollAnswer answer, TLRPC.MessageMedia media, float x, float y, int unshuffledIndex) { } default void didPressGroupImage(ChatMessageCell cell, ImageReceiver imageReceiver, TLRPC.MessageExtendedMedia media, float x, float y) { } default void didPressSideButton(ChatMessageCell cell) { } default void didQuickShareStart(ChatMessageCell cell, float x, float y) { } default void didQuickShareMove(ChatMessageCell cell, float x, float y) { } default void didQuickShareEnd(ChatMessageCell cell, float x, float y) { } default void didPressOther(ChatMessageCell cell, float otherX, float otherY) { } default void didPressRichDocumentOptions(ChatMessageCell cell, TLRPC.Document document, float x, float y) { } default boolean canSaveRichDocument(ChatMessageCell cell) { return false; } default void didPressSponsoredClose(ChatMessageCell cell) { } default void didPressSummarize(ChatMessageCell cell, boolean byReply) { } default void didPressSponsoredInfo(ChatMessageCell cell, float x, float y) { } default void didPressTime(ChatMessageCell cell) { } default void didPressBotButton(ChatMessageCell cell, TL_keyboard.KeyboardButtonProto button) { } default void didLongPressBotButton(ChatMessageCell cell, TL_keyboard.KeyboardButtonProto button) { } default void didPressCustomBotButton(ChatMessageCell cell, BotInlineKeyboard.ButtonCustom button) { } default void didLongPressCustomBotButton(ChatMessageCell cell, BotInlineKeyboard.ButtonCustom button) { } default void didPressReaction(ChatMessageCell cell, TLRPC.ReactionCount reaction, boolean longpress, float x, float y) { } default void didPressVoteButtons(ChatMessageCell cell, ArrayList buttons, int showCount, int x, int y) { } default boolean didPressToDoButton(ChatMessageCell cell, TLRPC.TodoItem task, boolean enable) { return false; } default boolean didLongPressPollOption(ChatMessageCell cell, TLRPC.PollAnswer answer) { return false; } default boolean didLongPressToDoButton(ChatMessageCell cell, TLRPC.TodoItem task) { return false; } default void didPressAppUpdateButton() { } default void didPressInstantButton(ChatMessageCell cell, int type) { } default boolean openArticlePhoto(ChatMessageCell cell, org.telegram.tgnet.tl.TL_iv.PageBlock block) { return false; } default void didPressShowMore(ChatMessageCell cell) { } default void didPressGiveawayChatButton(ChatMessageCell cell, int pressedPos) { } default void didPressCommentButton(ChatMessageCell cell) { } default void didPressHint(ChatMessageCell cell, int type) { } default void needShowPremiumFeatures(String source) { } default void needShowPremiumBulletin(int type) { } default boolean isAdmin(long uid) { return false; } default boolean isOwner(long uid) { return false; } default String getAdminRank(long uid) { return null; } default boolean needPlayMessage(ChatMessageCell cell, MessageObject messageObject, boolean muted) { return false; } default boolean drawingVideoPlayerContainer() { return false; } default boolean canPerformActions() { return false; } default boolean canPerformReply() { return canPerformActions(); } default boolean onAccessibilityAction(int action, Bundle arguments) { return false; } default void videoTimerReached() { } default void didStartVideoStream(MessageObject message) { } default boolean shouldRepeatSticker(MessageObject message) { return true; } default void setShouldNotRepeatSticker(MessageObject message) { } default TextSelectionHelper.ChatListTextSelectionHelper getTextSelectionHelper() { return null; } default boolean hasSelectedMessages() { return false; } default void needReloadPolls() { } default void onDiceFinished() { } default boolean shouldDrawThreadProgress(ChatMessageCell cell, boolean delayed) { return false; } default PinchToZoomHelper getPinchToZoomHelper() { return null; } default boolean keyboardIsOpened() { return false; } default boolean isLandscape() { return false; } default void invalidateBlur() { } default boolean canDrawOutboundsContent() { return true; } default boolean didPressAnimatedEmoji(ChatMessageCell cell, AnimatedEmojiSpan span) { return false; } default void didPressTopicButton(ChatMessageCell cell) {} default boolean shouldShowTopicButton(ChatMessageCell cell) { return false; } default void didPressDialogButton(ChatMessageCell cell) {} default boolean shouldShowDialogButton(ChatMessageCell cell) { return false; } default void didPressEmojiStatus() { } default boolean doNotShowLoadingReply(MessageObject msg) { return msg != null && msg.getDialogId() == UserObject.REPLY_BOT; } default void didPressAboutRevenueSharingAds() { } default void didPressRevealSensitiveContent(ChatMessageCell cell) { } default void didPressEffect(ChatMessageCell cell) { } default void didPressFactCheckWhat(ChatMessageCell cell, int cx, int cy) { } default void didPressFactCheck(ChatMessageCell cell) { } default void forceUpdate(ChatMessageCell cell, boolean anchorScroll) { } default void forceUpdate(ChatMessageCell cell, boolean anchorScroll, boolean scrollByTop) { forceUpdate(cell, anchorScroll); } default void didTogglePollPreview(ChatMessageCell cell) { } default void forceUpdateNoAnimation(ChatMessageCell cell, boolean anchorScroll) { } default void didPressAdmin(ChatMessageCell cell) { } default void drawPollMode(Canvas canvas, ChatMessageCell cell) { } default boolean allowAddPollOptions() { return false; } default int getAddPollOptionInputFieldHeight(ChatMessageCell cell) { return 0; } default void didPressAddPollOptionButton(ChatMessageCell cell) { } default ChatActivityDraftMessageMeasureController getDraftMessageMeasureController() { return null; } } @Nullable private ChatActivityDraftMessageMeasureController getDraftMessageMeasureController() { return delegate != null ? delegate.getDraftMessageMeasureController() : null; } private final static int DOCUMENT_ATTACH_TYPE_NONE = 0; private final static int DOCUMENT_ATTACH_TYPE_DOCUMENT = 1; private final static int DOCUMENT_ATTACH_TYPE_GIF = 2; private final static int DOCUMENT_ATTACH_TYPE_AUDIO = 3; private final static int DOCUMENT_ATTACH_TYPE_VIDEO = 4; private final static int DOCUMENT_ATTACH_TYPE_MUSIC = 5; private final static int DOCUMENT_ATTACH_TYPE_STICKER = 6; private final static int DOCUMENT_ATTACH_TYPE_ROUND = 7; private final static int DOCUMENT_ATTACH_TYPE_WALLPAPER = 8; private final static int DOCUMENT_ATTACH_TYPE_THEME = 9; private final static int DOCUMENT_ATTACH_TYPE_STORY = 10; public class PollButton { public int x; public int y; public int height; private int percent; private float decimal; private int prevPercent; private float percentProgress; private float prevPercentProgress; private boolean chosen; private int count; private boolean prevChosen; private boolean correct; public float titleX, titleY; public boolean moveTitleByCounter; public StaticLayout title; private Text author; public AnimatedEmojiSpan.EmojiGroupedSpans animatedEmoji; private TLRPC.PollAnswer answer; private TLRPC.TodoItem task; private boolean translated; public int selectorDrawableColor; public Drawable selectorDrawable; public PollButtonDrawable pollButtonDrawable; private AvatarDrawable avatarDrawable; private ImageReceiver avatarImageReceiver; private StaticLayout animateTitle; private AnimatedEmojiSpan.EmojiGroupedSpans animateTitleEmoji; public int animateY; public int animateHeight; public void attach() { if (avatarImageReceiver != null) { avatarImageReceiver.onAttachedToWindow(); } if (pollButtonDrawable != null) { pollButtonDrawable.attach(); } } public void detach() { if (avatarImageReceiver != null) { avatarImageReceiver.onDetachedFromWindow(); } if (pollButtonDrawable != null) { pollButtonDrawable.detach(); } } public void destroy() { detach(); AnimatedEmojiSpan.release(ChatMessageCell.this, animatedEmoji); animatedEmoji = null; AnimatedEmojiSpan.release(ChatMessageCell.this, animateTitleEmoji); animateTitleEmoji = null; } } public static final int INSTANT_BUTTON_TYPE_CONTACT_VIEW = 5; public static final int INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE = 30; public static final int INSTANT_BUTTON_TYPE_CONTACT_ADD = 31; public static final int INSTANT_BUTTON_TYPE_PROFILE = 32; public static final int INSTANT_BUTTON_TYPE_STICKER_SET = 23; public static final int INSTANT_BUTTON_TYPE_EMOJI_SET = 24; public static final int INSTANT_BUTTON_TYPE_VIEW_VOTES_PUBLIC_LIST = 80; public static final int INSTANT_BUTTON_TYPE_VIEW_VOTES_AS_AUTHOR_LIST = 81; public static final int INSTANT_BUTTON_TYPE_BACK_TO_VOTE = 82; public static final int INSTANT_BUTTON_TYPE_VOTE_MULTISELECT = 83; public static final int INSTANT_BUTTON_TYPE_ADD_OPTION = 84; public static final int INSTANT_BUTTON_TYPE_AI_STYLE = 85; private static class InstantViewButton { private int type; private float buttonWidth; private float textX; private StaticLayout layout; private final RectF rect = new RectF(); private ButtonBounce buttonBounce; private Drawable selectorDrawable; } public boolean pinnedTop; public boolean pinnedBottom; public boolean firstInChat; public boolean lastInChatList; public boolean drawPinnedTop; public boolean drawPinnedBottom; private MessageObject.GroupedMessages currentMessagesGroup; private MessageObject.GroupedMessagePosition currentPosition; private boolean groupPhotoInvisible; public final ReactionsLayoutInBubble reactionsLayoutInBubble = new ReactionsLayoutInBubble(this); public final GiveawayMessageCell giveawayMessageCell = new GiveawayMessageCell(this); public final GiveawayResultsMessageCell giveawayResultsMessageCell = new GiveawayResultsMessageCell(this); private boolean playedDice; private long starsPrice; private Text starsPriceText; private LinkPath starsPriceTextPath; private CornerPathEffect starsPriceTextPathEffect; public int starsPriceTopPadding; private long diceStakeOutcome; private Text bottomActionText; private LinkPath bottomActionTextPath; private CornerPathEffect bottomActionTextPathEffect; public int bottomActionPadding; public TopicSeparator topicSeparator; public int topicSeparatorTopPadding; public int askBotForumBottomPadding; private TopicSeparator askBotForumSeparator; private BotAskCellDrawable askBotForumBubble; public SuggestionOffer suggestionOffer; private int suggestionOfferTopPadding; private long effectId; private int effectMessageId; private ButtonBounce effectDrawableBounce; private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable effectDrawable; private boolean invalidateSpoilersParent; public int textX; private int unmovedTextX; private int linkPreviewY; private int factCheckY; public int textY; public int totalHeight; private int additionalTimeOffsetY; private int keyboardHeight; public int linkBlockNum; public int linkExplanationBlockNum; private int linkSelectionBlockNum; private boolean highlightedQuote; private boolean inLayout; private int currentMapProvider; private Rect scrollRect = new Rect(); private int lastVisibleBlockNum; private int firstVisibleBlockNum; private int totalVisibleBlocksCount; private int firstVisibleRichBlock = -1; private int lastVisibleRichBlock = -1; private boolean needNewVisiblePart; private boolean fullyDraw; public int parentWidth; public int parentHeight; public float parentViewTopOffset; private boolean attachedToWindow; public boolean isCellAttachedToWindow() { return attachedToWindow; } private boolean isUpdating; private RadialProgress2 radialProgress; private RadialProgress2 videoRadialProgress; private boolean drawRadialCheckBackground; private int[] pollPhotoImageRadius = new int[4]; private ImageReceiver photoImage; private ImageReceiver blurredPhotoImage; private ColorMatrixColorFilter fancyBlurFilter; private AvatarDrawable contactAvatarDrawable; private Drawable locationLoadingThumb; private Drawable gradientDrawable; private Paint gradientLoadingPaint; private CaptionContainerView.PeriodDrawable oncePeriod; private Paint onceClearPaint; private RLottieDrawable onceFire; private Paint onceRadialPaint; private Paint onceRadialCutPaint; private Paint onceRadialStrokePaint; private int onceRadialPaintColor; private StickerSetLinkIcon stickerSetIcons; private boolean disallowLongPress; private float lastTouchX; private float lastTouchY; public float getLastTouchX() { return lastTouchX; } public float getLastTouchY() { return lastTouchY; } private boolean drawMediaCheckBox; private boolean drawSelectionBackground; private CheckBoxBase mediaCheckBox; private CheckBoxBase checkBox; private boolean checkBoxVisible; private boolean checkBoxAnimationInProgress; private float checkBoxAnimationProgress; private long lastCheckBoxAnimationTime; public int checkBoxTranslation; private AvatarSpan forwardAvatar; private ForwardBackground forwardBg; private LoadingDrawable forwardLoading; public boolean linkPreviewAbove; public boolean captionAbove; private boolean isSmallImage; private boolean drawImageButton; private boolean drawVideoImageButton; private long lastLoadingSizeTotal; private boolean drawVideoSize; private boolean canStreamVideo; private int animatingDrawVideoImageButton; private float animatingDrawVideoImageButtonProgress; private boolean animatingNoSoundPlaying; private int animatingNoSound; private float animatingNoSoundProgress; private int noSoundCenterX; private int forwardNameCenterX; private long lastAnimationTime; private long lastNamesAnimationTime; private int documentAttachType; private TLRPC.Document documentAttach; public boolean drawPhotoImage; private boolean hasFactCheck; private Text factCheckTitle, factCheckWhat; private ButtonBounce factCheckWhatBounce; private ButtonBounce factCheckBounce; private StaticLayout factCheckTextLayout; private StaticLayout factCheckText2Layout; private LinkSpanDrawable.LinkCollector factCheckLinks; private LinkSpanDrawable pressedFactCheckLink; private boolean factCheckTextLayoutLastLineEnd; private Drawable factCheckArrow; private int factCheckArrowColor; private boolean factCheckLarge; private GradientClip clip; private int factCheckTextLayoutLeft; private int factCheckTextLayoutHeight; private int factCheckText2LayoutLeft; private int pollAddButtonHeight; private int factCheckHeight; private int factCheckWidth; private boolean hasLinkPreview; private boolean hasOldCaptionPreview; private boolean hasGamePreview; private boolean hasInvoicePreview; private boolean hasInvoicePrice; public int linkPreviewHeight; private int mediaOffsetY; private int descriptionY; private int durationWidth; private int photosCountWidth; private int descriptionX; private int descriptionLayoutWidth, descriptionLayoutLeft; private int titleX; private int authorLayoutWidth, authorLayoutLeft; private int titleLayoutWidth, titleLayoutLeft; private float siteNameLeft, siteNameLayoutWidth; private int siteNameWidth; private StaticLayout siteNameLayout; private StaticLayout titleLabelLayout; private float titleLabelLayoutWidth, titleLabelLayoutHeight, titleLabelX, titleLabelY; private boolean isTitleLabelPressed; private ButtonBounce titleLabelBounce; private StaticLayout titleLayout; private StaticLayout descriptionLayout; private StaticLayout videoInfoLayout; private StaticLayout photosCountLayout; private StaticLayout authorLayout; private StaticLayout instantViewLayout; private float instantViewLayoutWidth; private float instantViewLayoutLeft; private boolean drawInstantView; private boolean drawContact, drawContactSendMessage, drawContactView, drawContactAdd; private int drawnContactButtonsFlag = 0; private ArrayList contactButtons; private RectF contactRect; private boolean contactPressed; private boolean pollInstantViewTouchesBottom; public int drawInstantViewType; public CharSequence instantViewButtonText; private int imageBackgroundColor; private float imageBackgroundIntensity; private int imageBackgroundGradientColor1; private int imageBackgroundGradientColor2; private int imageBackgroundGradientColor3; private int imageBackgroundGradientRotation = 45; private LinearGradient gradientShader; private MotionBackgroundDrawable motionBackgroundDrawable; private int imageBackgroundSideColor; private int imageBackgroundSideWidth; private boolean drawJoinGroupView; private boolean drawJoinChannelView; private int instantTextX; private int instantTextLeftX; private int instantWidth; private boolean instantTextNewLine; private boolean instantPressed; private boolean instantButtonPressed; private ButtonBounce instantButtonBounce; private int selectorDrawableColor; private final Drawable[] selectorDrawable = new Drawable[2]; private final MaskDrawable[] selectorMaskDrawable = new MaskDrawable[2]; private int[] selectorDrawableMaskType = new int[2]; private RectF instantButtonRect = new RectF(); private LoadingDrawable instantButtonLoading; private final int[] pressedState = new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}; private float animatingLoadingProgressProgress; CharSequence accessibilityText; private boolean accessibilityTextUnread, accessibilityTextContentUnread; private long accessibilityTextFileSize; private boolean wasTranscriptionOpen; private Path instantLinkArrowPath; private Paint instantLinkArrowPaint; private int nameLayoutSelectorColor; private Drawable nameLayoutSelector; private boolean nameLayoutPressed; private boolean boostCounterPressed; private int boostCounterSelectorColor; private Drawable boostCounterLayoutSelector; private int nameStatusSelectorColor; private Drawable nameStatusSelector; private boolean nameStatusPressed; private RoundVideoPlayingDrawable roundVideoPlayingDrawable; private StaticLayout docTitleLayout; private int docTitleWidth; private int docTitleOffsetX; private boolean locationExpired; private AvatarsDrawable groupCallParticipantsAvatars; private Text groupCallParticipantsText; private int highlightCaptionToSetStart = -1, highlightCaptionToSetEnd = -1; private int captionFullWidth; public MessageObject.TextLayoutBlocks captionLayout, prevCaptionLayout; public QuoteHighlight quoteHighlight; private CharSequence currentCaption; public StaticLayout explanationTitleLayout; public MessageObject.TextLayoutBlocks explanationLayout; private CharSequence currentExplanation; private int explanationContentWidth; private int explanationContentHeight; private int explanationHeight; private Drawable closeExplanationDrawable; private int closeExplanationDrawableColor; private int captionOffsetX; private float captionX; public float captionY; private int captionHeight; private int captionWidth; private int addedCaptionHeight; private boolean fitPhotoImage; private StaticLayout infoLayout; private AnimatedTextView.AnimatedTextDrawable animatedInfoLayout; private AnimatedTextView.AnimatedTextDrawable animatedInfoLayout2; private CountdownTimer pollCountDownTimer; private StaticLayout loadingProgressLayout; private long loadingProgressLayoutHash; private int infoX; private int infoWidth; private Text sensitiveText, sensitiveTextShort, sensitiveTextShort2; private String currentUrl; private WebFile currentWebFile; private WebFile lastWebFile; private boolean addedForTest; private boolean hasEmbed; private boolean wasSending; private boolean checkOnlyButtonPressed; private int buttonX; private int buttonY; private int videoButtonX; private int videoButtonY; private int buttonState; private int buttonPressed; private int videoButtonPressed; private int miniButtonPressed; private int otherX; private int otherY; private int lastWidth; private int lastHeight; private int hasMiniProgress; private int miniButtonState; private boolean imagePressed; private boolean otherPressed; private boolean photoNotSet; private RectF deleteProgressRect = new RectF(); private RectF rect = new RectF(); private TLObject photoParentObject; private ImageLocation currentPhotoLocation; private ImageLocation currentPhotoThumbLocation; private TLRPC.PhotoSize currentPhotoObject; private TLRPC.PhotoSize currentPhotoObjectThumb; private BitmapDrawable currentPhotoObjectThumbStripped; private String currentPhotoFilter; private String currentPhotoFilterThumb; private Drawable foreverDrawable; private int foreverDrawableColor = 0xFFFFFFFF; private boolean timePressed; private float timeAlpha = 1.0f; private float actionAlpha = 1.0f; private float controlsAlpha = 1.0f; private long lastControlsAlphaChangeTime; private long totalChangeTime; private boolean mediaWasInvisible; private boolean timeWasInvisible; private AnimatedEmojiSpan pressedEmoji; private LinkSpanDrawable pressedLink; private MessageObject.TextLayoutBlock pressedCopyCode; private int pressedBlock = -1; public LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); private int pressedLinkType; private boolean linkPreviewPressed; private boolean gamePreviewPressed; private ArrayList urlPathCache = new ArrayList<>(); private ArrayList urlPathSelection = new ArrayList<>(); private CharacterStyle highlightPathSpan; private LinkPath highlightPath; private long highlightPathStart; private LoadingDrawable progressLoadingLinkCurrentDrawable; class LoadingDrawableLocation { LoadingDrawable drawable; int blockNum; }; private ArrayList progressLoadingLinkDrawables; private CharacterStyle progressLoadingLink; private Path rectPath = new Path(); private static float[] radii = new float[8]; private boolean useSeekBarWaveform; private SeekBar seekBar; private SeekBarWaveform seekBarWaveform; private SeekBarAccessibilityDelegate seekBarAccessibilityDelegate; private int seekBarX; private int seekBarY; private boolean useTranscribeButton; public TranscribeButton transcribeButton; private float transcribeX, transcribeY; private StaticLayout durationLayout; private double lastTime; private int timeWidthAudio; private int timeAudioX; private StaticLayout songLayout; private int songX; private StaticLayout performerLayout; private int performerX; private final ArrayList oldPollButtons = new ArrayList<>(); public final ArrayList pollButtons = new ArrayList<>(); private PollInstantButtonDrawable pollInstantButtonDrawable; private PollAddButtonDrawable pollAddButtonDrawable; private PollContentDrawable pollContentDrawable; private PollContentDrawable pollExplanationDrawable; private int pollContentWidth; private int pollContentHeight; private int pollContentHeightWithOffset; private float pollAnimationProgress; private float pollAnimationProgressTime; public int firstVisiblePollButton = -1, lastVisiblePollButton = -1; public float resultsPollButtonOffset; private boolean reactionsVisible = true; private boolean pollVoted; private boolean pollAllowAdding; private boolean pollInInputNewOption; private boolean pollWithMediaInAnswers; private boolean pollHideResults; private boolean pollHasResults; private boolean pollHasVoteRestrictions; private boolean pollClosed; private boolean pollResultsPreview; private long lastPollCloseTime; private String closeTimeText; private int closeTimeWidth; private boolean pollVoteInProgress; private boolean vibrateOnPollVote; private boolean pollUnvoteInProgress; private boolean animatePollAnswer; private boolean animatePollAvatars; private boolean animatePollAnswerAlpha; private int pollVoteInProgressNum; private long voteLastUpdateTime; private float voteRadOffset; private float voteCurrentCircleLength; private boolean firstCircleLength; private boolean voteRisingCircleLength; private float voteCurrentProgressTime; private int pressedVoteButton; private boolean pressedVoteIsMedia; private int pollMediaPressedIndex = PollAttachedMediaPack.INDEX_NONE; private TLRPC.Poll lastPoll; private float timerTransitionProgress; private TLRPC.PollResults lastPollResultsObj; private ArrayList lastPollResults; private int lastPollResultsVoters; private TimerParticles timerParticles; private AnimatedFloat timerParticlesAlpha; private int pollHintX; private int pollHintY; private boolean pollHintPressed; private boolean hintButtonVisible; private float hintButtonProgress; private int pollAddButtonPressed; private float lastDrawExplanationX; private float lastDrawExplanationY; private int closeExplanationX; private int closeExplanationY; private boolean closeExplanationPressed; private String lastPostAuthor; private TLRPC.Message lastReplyMessage; private boolean hasPsaHint; private int psaHelpX; private int psaHelpY; private boolean psaHintPressed; private boolean psaButtonVisible; private float psaButtonProgress; private TLRPC.TL_messageReactions lastReactions; private boolean autoPlayingMedia; private ArrayList botButtons = new ArrayList<>(); private Path botButtonPath = new Path(); private float[] botButtonRadii = new float[8]; private HashMap botButtonsByData = new HashMap<>(); private HashMap botButtonsByPosition = new HashMap<>(); private String botButtonsLayout; private int widthForButtons; private boolean drawStartBotTopic; private boolean drawContinueBotTopic; private int pressedBotButton; private SpoilerEffect spoilerPressed; private boolean isSpoilerRevealing; private boolean checkFileLoad; private boolean wasAllChats; private MessageObject currentMessageObject; private MessageObject messageObjectToSet; private MessageObject.GroupedMessages groupedMessagesToSet; private boolean topNearToSet; private boolean bottomNearToSet; private boolean firstInChatToSet; private boolean lastInChatListToSet; public GroupMedia groupMedia; private AnimatorSet shakeAnimation; // private int TAG; public final int currentAccount; private boolean invalidatesParent; public int doNotDrawTaskId = -1; public byte[] doNotDrawPollId; public byte[] drawOnlyPollId; public boolean isChat; public boolean isBotForum; public boolean isSavedChat; public boolean isSavedPreviewChat; public boolean isBot; public boolean isMegagroup; public boolean isForum; public boolean isMonoForum; public boolean isForumGeneral; public boolean isThreadChat; public boolean hasDiscussion; public boolean isPinned; private boolean wasPinned; public boolean isReportChat; public long linkedChatId; public boolean isRepliesChat; public boolean isPinnedChat; private boolean isPressed; private boolean forwardName; private boolean isHighlighted; private boolean isHighlightedAnimated; private int highlightProgress; private float currentSelectedBackgroundAlpha; private long lastHighlightProgressTime; private boolean mediaBackground; private boolean isMedia; private boolean isCheckPressed = true; private boolean wasLayout; private boolean forcedLayout; public boolean isAvatarVisible; private boolean isThreadPost; private boolean drawBackground = true; private int substractBackgroundHeight; private boolean allowAssistant; public MessageDrawable currentBackgroundDrawable; private MessageDrawable currentBackgroundSelectedDrawable; private int backgroundDrawableLeft; private int backgroundDrawableRight; private int backgroundDrawableTop; private int backgroundDrawableBottom; private int viaWidth; private int viaNameWidth; private boolean viaOnly; private TypefaceSpan viaSpan1; private TypefaceSpan viaSpan2; private int availableTimeWidth; private int widthBeforeNewTimeLine; public boolean isAllChats; public boolean isSideMenued; public boolean isSideMenuEnabled; public float sideMenuAlpha; public int sideMenuWidth; public int backgroundWidth = 100; private boolean hasNewLineForTime; public int layoutWidth; public int layoutHeight; private AvatarsListDrawable pollRecentVotersDrawable; private Paint pollCutAvatarPaint; private Paint pollCheckPaint; private Path pollCheckPath; private CheckBoxBase[] pollCheckBox; private InfiniteProgress commentProgress; private LoadingDrawable commentLoading; private float commentProgressAlpha; private long commentProgressLastUpadteTime; private ImageReceiver[] commentAvatarImages; private AvatarDrawable[] commentAvatarDrawables; private boolean[] commentAvatarImagesVisible; private StaticLayout commentLayout; private AnimatedNumberLayout commentNumberLayout; private boolean drawCommentNumber; private int commentArrowX; private int commentUnreadX; private boolean commentDrawUnread; private int commentWidth; private int commentX; private int totalCommentWidth; private int commentNumberWidth; private boolean drawCommentButton; private Rect commentButtonRect = new Rect(); private boolean commentButtonPressed; private ImageReceiver avatarImage; protected AvatarDrawable avatarDrawable; private boolean avatarPressed; private boolean forwardNamePressed; private boolean forwardBotPressed; private ImageReceiver locationImageReceiver; public int replyQuoteDrawableColor; public Drawable quoteDrawable[]; public int[] quoteDrawableColor; public Drawable replyQuoteDrawable; public Drawable quoteArrow; public int quoteArrowColor; public boolean hasReplyQuote; public boolean isReplyQuote; public boolean isReplyTaskOrPollOption; public CheckBoxBase replyTaskCheckbox; public StaticLayout replyNameLayout; public StaticLayout replyTextLayout; private AtomicReference spoilersPatchedReplyTextLayout = new AtomicReference<>(); public ImageReceiver replyImageReceiver; public int replyStartX; public int replyStartY; public float replyHeight; private int replyNameWidth; private int replyNameOffset; private int replyTextWidth; private int replyTextHeight; public int replyTextOffset; public boolean replyTextRTL; public boolean needReplyImage; private boolean replyPressed; private boolean replySelectorPressed, replySelectorCanBePressed; private AnimatedFloat replyPressedFloat; private float replyTouchX, replyTouchY; private TLRPC.PhotoSize currentReplyPhoto; public int instantDrawableColor; public Drawable instantDrawable; public ReplyMessageLine quoteLine, linkLine, replyLine, contactLine, factCheckLine, summaryLine; private int groupCallDrawableColor; private Drawable groupCallDrawable; public boolean drawSummaryReply; public StarsReactionsSheet.Particles summaryParticles; public int summarySelectorColor; public Drawable summaryReplySelector; public Text summaryTitle, summarySubtitle; public int summaryStartX, summaryStartY; private AnimatedFloat translationLoadingFloat; private LinkPath translationLoadingPath; private LoadingDrawable translationLoadingDrawable; private ArrayList translationLoadingDrawableText; private StaticLayout translationLoadingDrawableLayout; private boolean hideSideButtonByQuickShare; private int drawSideButton; private boolean sideButtonVisible; private int drawSideButton2; private boolean sideButtonPressed; private boolean drawSummarizeButton; private boolean summarizeButtonPressed; private int pressedSideButton; private boolean inQuickShareMode; private Path sideButtonPath1, sideButtonPath2; private float[] sideButtonPathCorners1, sideButtonPathCorners2; private static final int SIDE_BUTTON_SPONSORED_CLOSE = 4; private static final int SIDE_BUTTON_SPONSORED_MORE = 5; private float sideStartX, sideStartY; private float summarizeButtonX, summarizeButtonY; private StaticLayout nameLayout; private int nameLayoutWidth; private boolean adminLayoutIsAdmin, adminLayoutIsOwner, adminLayoutIsTag; private StaticLayout adminLayout; private RectF adminLayoutRect = new RectF(); private ButtonBounce adminLayoutBounce; private RectF boostCounterBounds; private BoostCounterSpan boostCounterSpan; private int nameWidth; private float nameOffsetX; private float nameX; private float nameY; private boolean drawName; private boolean drawNameLayout; private boolean drawNameAvatar; private float ephemeralX, ephemeralY; private StaticLayout ephemeralLayout; private int ephemeralWidth; private boolean drawTopic; private TopicButton topicButton; private AvatarDrawable sideAvatarDrawable; private ImageReceiver sideImage; private Text sideNameText; private int sideNameWidth; private Path sideArrow; private Paint sideFillPaint, sideStrokePaint; private ButtonBounce closeSponsoredBounce; private RectF closeSponsoredBounds; private final StaticLayout[] forwardedNameLayout = new StaticLayout[2]; private int forwardedNameWidth; private boolean drawForwardedName; private float forwardNameX; private int forwardNameY; private int forwardHeight; private final float[] forwardNameOffsetX = new float[2]; private float drawTimeX; private float drawTimeY; public StaticLayout timeLayout; public int timeWidth; private int timeTextWidth; public int timeX; public int signWidth; private CharSequence currentTimeString; private boolean drawTime = true; private boolean forceNotDrawTime; private Paint drillHolePaint; private Path drillHolePath; private Path mediaSpoilerPath = new Path(); private float[] mediaSpoilerRadii = new float[8]; @Nullable private SpoilerEffect mediaSpoilerEffect; private float mediaSpoilerRevealProgress; private float mediaSpoilerRevealX; private float mediaSpoilerRevealY; private float mediaSpoilerRevealMaxRadius; private SpoilerEffect2 mediaSpoilerEffect2; private Integer mediaSpoilerEffect2Index; // private Drawable startsAtDrawable; // private Text startsAtText, startsAtTextShorter; private Path photoImageClipPath; private float[] photoImageClipPathRadii; private float unlockAlpha = 1f; private float unlockX; private float unlockY; private StaticLayout unlockLayout; private int unlockTextWidth; private String currentUnlockString; @Nullable private SpoilerEffect unlockSpoilerEffect; private Path unlockSpoilerPath = new Path(); private float[] unlockSpoilerRadii = new float[8]; private StaticLayout viewsLayout; private int viewsTextWidth; private String currentViewsString; private StaticLayout repliesLayout; private int repliesTextWidth; private String currentRepliesString; private TLRPC.User currentUser; private TLRPC.Chat currentChat; private TLRPC.FileLocation currentPhoto; private String currentNameString; private Object currentNameStatus; private long currentNameBotVerificationId; private String nameStatusSlug; public AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable currentNameStatusDrawable; public AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable currentNameEmojiStatusDrawable; private TLRPC.User currentForwardUser; private TLRPC.User currentViaBotUser; private TLRPC.Chat currentForwardChannel; private String currentForwardName; private String currentForwardNameString; private boolean replyPanelIsForward; private boolean animationRunning; private boolean willRemoved; public AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiStack; public AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiReplyStack; public AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiDescriptionStack; public AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiPollQuestion; public AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiPollExplanation; public ButtonBounce replyBounce, contactBounce, summaryBounce; public float replyBounceX, replyBounceY; public Drawable replySelector; public LoadingDrawable replyLoadingDrawable; private Path replyRoundRectPath; public float[] replyBackgroundRadii; public RectF replySelectorRect = new RectF(); public RectF summarySelectorRect = new RectF(); public int replySelectorColor; public float replySelectorRadLeft, replySelectorRadRight; private ButtonBounce linkPreviewBounce; private Drawable linkPreviewSelector; public int linkPreviewSelectorColor; @Nullable private ChatMessageCellDelegate delegate; private MessageBackgroundDrawable backgroundDrawable; public int namesOffset; private int lastSendState; private int lastDeleteDate; private int lastViewsCount; private int lastRepliesCount; private float selectedBackgroundProgress; private boolean lastTranslated; public float viewTop; public int backgroundHeight; public int blurredViewTopOffset; public int blurredViewBottomOffset; private boolean scheduledInvalidate; private final boolean ALPHA_PROPERTY_WORKAROUND = Build.VERSION.SDK_INT == 28; private float alphaInternal = 1f; public final TransitionParams transitionParams = new TransitionParams(); private boolean edited; private boolean imageDrawn; private boolean photoImageOutOfBounds; private boolean wouldBeInPip; private AnimatedFloat roundVideoPlayPipFloat = new AnimatedFloat(this, 200, CubicBezierInterpolator.EASE_OUT); private Paint roundVideoPipPaint; private FlagSecureReason flagSecure; public boolean makeVisibleAfterChange; private Runnable diceFinishCallback = new Runnable() { @Override public void run() { if (delegate != null) { delegate.onDiceFinished(); } } }; private int animateToStatusDrawableParams; private int animateFromStatusDrawableParams; private float statusDrawableProgress; private boolean statusDrawableAnimationInProgress; private ValueAnimator statusDrawableAnimator; private int overideShouldDrawTimeOnMedia; private float toSeekBarProgress; private Runnable invalidateRunnable = new Runnable() { @Override public void run() { checkLocationExpired(); if (locationExpired) { invalidate(); scheduledInvalidate = false; } else { invalidate((int) rect.left - 5, (int) rect.top - 5, (int) rect.right + 5, (int) rect.bottom + 5); if (scheduledInvalidate) { AndroidUtilities.runOnUIThread(invalidateRunnable, 1000); } } } }; private SparseArray accessibilityVirtualViewBounds = new SparseArray<>(); private boolean isRoundVideo; private boolean isPlayingRound; private float roundProgressAlpha; private float roundToPauseProgress; private float roundToPauseProgress2; private float roundPlayingDrawableProgress; private long lastSeekUpdateTime; float seekbarRoundX; float seekbarRoundY; float lastDrawingPlayPauseAlpha; int roundSeekbarTouched; float roundSeekbarOutProgress; float roundSeekbarOutAlpha; private float lastDrawingAudioProgress; private int currentFocusedVirtualView = -1; public boolean drawFromPinchToZoom; private MessageDrawable.PathDrawParams backgroundCacheParams = new MessageDrawable.PathDrawParams(); VideoForwardDrawable videoForwardDrawable; OldVideoPlayerRewinder videoPlayerRewinder; private Theme.ResourcesProvider resourcesProvider; private final boolean canDrawBackgroundInParent; private ChatMessageSharedResources sharedResources; public List replySpoilers = new ArrayList<>(); private final Stack replySpoilersPool = new Stack<>(); private final Path sPath = new Path(); public boolean isBlurred; public BotForumHelper.BotDraftAnimationsPool draftAnimationsPool; public ChatMessageCell(Context context, int currentAccount) { this(context, currentAccount, false, null, null); } public ChatMessageCell(Context context, int currentAccount, boolean canDrawBackgroundInParent, ChatMessageSharedResources sharedResources, Theme.ResourcesProvider resourcesProvider) { super(context); this.currentAccount = currentAccount; this.resourcesProvider = resourcesProvider; this.canDrawBackgroundInParent = canDrawBackgroundInParent; this.sharedResources = sharedResources; if (this.sharedResources == null) { this.sharedResources = new ChatMessageSharedResources(context); } setClipChildren(false); setClipToPadding(false); backgroundDrawable = new MessageBackgroundDrawable(this); avatarImage = new ImageReceiver(); avatarImage.setAllowLoadingOnAttachedOnly(true); avatarImage.setRoundRadius(dp(21)); avatarDrawable = new AvatarDrawable(); replyImageReceiver = new ImageReceiver(this); replyImageReceiver.setAllowLoadingOnAttachedOnly(true); replyImageReceiver.setRoundRadius(dp(4)); locationImageReceiver = new ImageReceiver(this); locationImageReceiver.setAllowLoadingOnAttachedOnly(true); locationImageReceiver.setRoundRadius(dp(26.1f)); TAG = DownloadController.getInstance(currentAccount).generateObserverTag(); contactAvatarDrawable = new AvatarDrawable(); photoImage = new ImageReceiver(this) { @Override public void setRoundRadius(int[] value) { super.setRoundRadius(value); pollPhotoImageRadius[0] = value[0]; pollPhotoImageRadius[1] = value[1]; pollPhotoImageRadius[2] = pollPhotoImageRadius[3] = dp(6); if (pollContentDrawable != null) { pollContentDrawable.imageReceiver.setRoundRadius(pollPhotoImageRadius); } } }; photoImage.setAllowLoadingOnAttachedOnly(true); photoImage.setUseRoundForThumbDrawable(true); photoImage.setDelegate(this); blurredPhotoImage = new ImageReceiver(this); blurredPhotoImage.setAllowLoadingOnAttachedOnly(true); blurredPhotoImage.setUseRoundForThumbDrawable(true); radialProgress = new RadialProgress2(this, resourcesProvider); videoRadialProgress = new RadialProgress2(this, resourcesProvider); videoRadialProgress.setDrawBackground(false); videoRadialProgress.setCircleRadius(dp(15)); seekBar = new SeekBar(this) { @Override protected void onTimestampUpdate(URLSpanNoUnderline link) { setHighlightedSpan(link); } }; seekBar.setDelegate(this); seekBarWaveform = new SeekBarWaveform(context); seekBarWaveform.setDelegate(this); seekBarWaveform.setParentView(this); seekBarAccessibilityDelegate = new FloatSeekBarAccessibilityDelegate() { @Override public float getProgress() { if (currentMessageObject.isMusic()) { return seekBar.getProgress(); } else if (currentMessageObject.isVoice()) { if (useSeekBarWaveform) { return seekBarWaveform.getProgress(); } else { return seekBar.getProgress(); } } else if (currentMessageObject.isRoundVideo()) { return currentMessageObject.audioProgress; } else { return 0f; } } @Override public void setProgress(float progress) { if (currentMessageObject.isMusic()) { seekBar.setProgress(progress); } else if (currentMessageObject.isVoice()) { if (useSeekBarWaveform) { seekBarWaveform.setProgress(progress); } else { seekBar.setProgress(progress); } } else if (currentMessageObject.isRoundVideo()) { if (useSeekBarWaveform) { if (seekBarWaveform != null) { seekBarWaveform.setProgress(progress); } } else { if (seekBar != null) { seekBar.setProgress(progress); } } currentMessageObject.audioProgress = progress; } else { return; } onSeekBarDrag(progress); invalidate(); } }; roundVideoPlayingDrawable = new RoundVideoPlayingDrawable(this, resourcesProvider); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } public void setResourcesProvider(Theme.ResourcesProvider resourcesProvider) { this.resourcesProvider = resourcesProvider; if (radialProgress != null) { radialProgress.setResourcesProvider(resourcesProvider); } if (videoRadialProgress != null) { videoRadialProgress.setResourcesProvider(resourcesProvider); } if (roundVideoPlayingDrawable != null) { roundVideoPlayingDrawable.setResourcesProvider(resourcesProvider); } } public Theme.ResourcesProvider getResourcesProvider() { return resourcesProvider; } private void createPollUI(int answersCount) { if (pollCheckBox == null || pollCheckBox.length != answersCount) { if (pollCheckBox != null) { for (int a = 0; a < pollCheckBox.length; a++) { pollCheckBox[a].onDetachedFromWindow(); } } pollCheckBox = new CheckBoxBase[answersCount]; for (int a = 0; a < pollCheckBox.length; a++) { pollCheckBox[a] = new CheckBoxBase(this, 20, resourcesProvider); pollCheckBox[a].setDrawUnchecked(false); pollCheckBox[a].setCuttingCheck(true); pollCheckBox[a].setBackgroundType(9); } } if (pollRecentVotersDrawable == null) { pollRecentVotersDrawable = new AvatarsListDrawable(currentAccount, this, dp(16), dp(7f), dpf2(1)); } } private void createCommentUI() { if (commentAvatarImages != null) { return; } commentAvatarImages = new ImageReceiver[3]; commentAvatarDrawables = new AvatarDrawable[3]; commentAvatarImagesVisible = new boolean[3]; for (int a = 0; a < commentAvatarImages.length; a++) { commentAvatarImages[a] = new ImageReceiver(this); commentAvatarImages[a].setRoundRadius(dp(12)); commentAvatarDrawables[a] = new AvatarDrawable(); commentAvatarDrawables[a].setTextSize(dp(18)); } } public void resetPressedLink(int type) { if (type != -1) { links.removeLinks(type); } else { links.clear(); } if (factCheckLinks != null) { factCheckLinks.clear(); } pressedEmoji = null; pressedFactCheckLink = null; if (pressedLink == null || pressedLinkType != type && type != -1) { return; } pressedLink = null; pressedLinkType = -1; touchedByExpanation = false; touchedByCaption = false; invalidate(); } private void resetUrlPaths() { if (quoteHighlight != null) { quoteHighlight = null; } if (urlPathSelection.isEmpty()) { return; } urlPathCache.addAll(urlPathSelection); urlPathSelection.clear(); } private LinkPath obtainNewUrlPath() { LinkPath linkPath; if (!urlPathCache.isEmpty()) { linkPath = urlPathCache.get(0); urlPathCache.remove(0); } else { linkPath = new LinkPath(true); } linkPath.reset(); urlPathSelection.add(linkPath); return linkPath; } private int[] getRealSpanStartAndEnd(Spannable buffer, CharacterStyle link) { int start = 0; int end = 0; boolean ok = false; if (link instanceof URLSpanBrowser) { URLSpanBrowser span = (URLSpanBrowser) link; TextStyleSpan.TextStyleRun style = span.getStyle(); if (style != null && style.urlEntity != null) { start = style.urlEntity.offset; end = style.urlEntity.offset + style.urlEntity.length; ok = true; } } if (!ok) { start = buffer.getSpanStart(link); end = buffer.getSpanEnd(link); } return new int[]{start, end}; } private boolean checkQuickShareMotionEvent(MotionEvent event) { if (!inQuickShareMode) { return false; } final int action = event.getAction(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { inQuickShareMode = false; if (delegate != null) { delegate.didQuickShareEnd(this, getEventX(event), getEventY(event)); } return true; } else if (action == MotionEvent.ACTION_MOVE) { if (delegate != null) { delegate.didQuickShareMove(this, getEventX(event), getEventY(event)); } } return true; } private boolean checkAdminMotionEvent(MotionEvent event) { if (adminLayout == null || boostCounterBounds == null || currentUser == null && currentChat == null) { boostCounterPressed = false; return false; } final boolean pressed = boostCounterBounds.contains((int) getEventX(event), (int) getEventY(event)); if (event.getAction() == MotionEvent.ACTION_DOWN) { SpannableString spannableString = new SpannableString(adminLayout.getText()); BoostCounterSpan[] spans = spannableString.getSpans(0, spannableString.length(), BoostCounterSpan.class); boostCounterPressed = pressed && spans != null && spans.length > 0; if (boostCounterPressed) { if (boostCounterLayoutSelector != null) { boostCounterLayoutSelector.setHotspot((int) getEventX(event), (int) getEventY(event)); boostCounterLayoutSelector.setState(pressedState); } } } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { if (event.getAction() == MotionEvent.ACTION_UP && boostCounterPressed) { if (delegate != null) { delegate.didPressBoostCounter(this); } } if (boostCounterLayoutSelector != null) { boostCounterLayoutSelector.setState(StateSet.NOTHING); } boostCounterPressed = false; } return boostCounterPressed; } private CharSequence getAdminAccessibilityText() { if (adminLayout == null || TextUtils.isEmpty(adminLayout.getText())) return null; final SpannableStringBuilder text = new SpannableStringBuilder(adminLayout.getText()); final BoostCounterSpan[] spans = text.getSpans(0, text.length(), BoostCounterSpan.class); for (int i = spans.length - 1; i >= 0; --i) { final int start = text.getSpanStart(spans[i]); final int end = text.getSpanEnd(spans[i]); if (start >= 0 && end >= start) { text.delete(start, end); } } final String label = text.toString().trim(); return TextUtils.isEmpty(label) ? null : label; } private boolean checkNameMotionEvent(MotionEvent event) { if (!drawNameLayout || nameLayout == null || nameLayoutSelector == null || currentUser == null && currentChat == null) { nameLayoutPressed = false; return false; } final boolean pressed = nameLayoutSelector.getBounds().contains((int) getEventX(event), (int) getEventY(event)); if (event.getAction() == MotionEvent.ACTION_DOWN) { nameLayoutPressed = pressed; if (nameLayoutPressed) { nameLayoutSelector.setHotspot((int) getEventX(event), (int) getEventY(event)); nameLayoutSelector.setState(pressedState); } } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { if (event.getAction() == MotionEvent.ACTION_UP && nameLayoutPressed) { if (delegate != null) { if (viaOnly) { if (currentViaBotUser != null && currentViaBotUser.bot_inline_placeholder == null) { delegate.didPressViaBotNotInline(this, currentViaBotUser != null ? currentViaBotUser.id : 0); } else { String username = UserObject.getPublicUsername(currentViaBotUser); delegate.didPressViaBot(this, username != null ? username : currentMessageObject.messageOwner.via_bot_name); } } else if (currentUser != null) { delegate.didPressUserAvatar(this, currentUser, getEventX(event), getEventY(event), false); } else if (currentChat != null) { int id; TLRPC.Chat chat = currentChat; if (currentMessageObject.messageOwner.fwd_from != null) { if (chat == null && (currentMessageObject.messageOwner.fwd_from.flags & 16) != 0) { id = currentMessageObject.messageOwner.fwd_from.saved_from_msg_id; } else { id = currentMessageObject.messageOwner.fwd_from.channel_post; chat = currentForwardChannel; } } else { id = 0; } delegate.didPressChannelAvatar(this, chat != null ? chat : currentChat, id, lastTouchX, lastTouchY, false); } } } nameLayoutSelector.setState(StateSet.NOTHING); nameLayoutPressed = false; } return nameLayoutPressed; } private boolean checkNameStatusMotionEvent(MotionEvent event) { if (!drawNameLayout || nameLayout == null || nameLayoutSelector == null || currentUser == null && currentChat == null || currentNameStatus == null || currentNameStatusDrawable == null) { nameStatusPressed = false; return false; } final boolean pressed = nameStatusSelector.getBounds().contains((int) getEventX(event), (int) getEventY(event)); if (event.getAction() == MotionEvent.ACTION_DOWN) { nameStatusPressed = pressed; if (nameStatusPressed) { nameStatusSelector.setHotspot((int) getEventX(event), (int) getEventY(event)); nameStatusSelector.setState(pressedState); } } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { if (event.getAction() == MotionEvent.ACTION_UP && nameStatusPressed) { if (delegate != null) { if (currentUser != null) { TLRPC.Document document = null; if (currentNameStatusDrawable.getDrawable() instanceof AnimatedEmojiDrawable) { document = ((AnimatedEmojiDrawable) currentNameStatusDrawable.getDrawable()).getDocument(); } delegate.didPressUserStatus(this, currentUser, document, nameStatusSlug); invalidateOutbounds(); } } } nameStatusSelector.setState(StateSet.NOTHING); nameStatusPressed = false; } return nameStatusPressed; } private final Runnable scheduleUpdateRelativeDatesRunnable = this::scheduleUpdateRelativeDates; private final Runnable doUpdateRelativeDatesRunnable = this::doUpdateRelativeDates; private void doUpdateRelativeDates() { postRunnableHolder.cancel(scheduleUpdateRelativeDatesRunnable); postRunnableHolder.cancel(doUpdateRelativeDatesRunnable); scheduleUpdateRelativeDates(); if (currentMessageObject == null) { return; } currentMessageObject.generateLayout(null); if (currentMessageObject.caption != null) { currentMessageObject.caption = null; currentMessageObject.generateCaption(); } if (delegate != null) { delegate.forceUpdateNoAnimation(this, true); } } private void scheduleUpdateRelativeDates() { postRunnableHolder.cancel(scheduleUpdateRelativeDatesRunnable); postRunnableHolder.cancel(doUpdateRelativeDatesRunnable); if (currentMessageObject == null) { return; } final CharSequence text = !TextUtils.isEmpty(currentMessageObject.caption) ? currentMessageObject.caption : currentMessageObject.messageText; if (TextUtils.isEmpty(text)) { return; } final ArrayList relativeDates = FormattedDateSpan.getAllRelativeDates(text); if (relativeDates == null || relativeDates.isEmpty()) { return; } final long currentTimeMillis = System.currentTimeMillis(); //ConnectionsManager.getInstance(currentAccount).getCurrentTimeMillis(); long relativeDateWithMinimalDistance = 0; long minDistance = Long.MAX_VALUE; for (int timestamp : relativeDates) { final long relativeDateTimeMillis = timestamp * 1000L; final long distanceInMillis = Math.abs(relativeDateTimeMillis - currentTimeMillis); if (distanceInMillis < minDistance) { relativeDateWithMinimalDistance = relativeDateTimeMillis; minDistance = distanceInMillis; } } final long nextUpdate; final long d = currentTimeMillis - relativeDateWithMinimalDistance; if (minDistance < (60 + 3) * 1000L) { nextUpdate = d > 0 ? (1000 - d % 1000) : (-d % 1000); } else if (minDistance < ((3600 + 180) * 1000L)) { nextUpdate = d > 0 ? (60000 - d % 60000) : (-d % 60000); } else if (minDistance < ((86400 + 4320) * 1000L)) { nextUpdate = d > 0 ? (3600_000 - d % 3600_000) : (-d % 3600_000); } else { nextUpdate = -1; } if (nextUpdate > 0) { postRunnableHolder.post(doUpdateRelativeDatesRunnable, nextUpdate + 100L); } } private void resetCodeSelectors() { if (currentMessageObject != null && currentMessageObject.textLayoutBlocks != null) { for (int i = 0; i < currentMessageObject.textLayoutBlocks.size(); ++i) { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(i); if (block.copySelector != null) { block.copySelector.setCallback(this); block.copySelector.setState(StateSet.NOTHING); } } } if (captionLayout != null) { for (int i = 0; i < captionLayout.textLayoutBlocks.size(); ++i) { MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(i); if (block.copySelector != null) { block.copySelector.setCallback(this); block.copySelector.setState(StateSet.NOTHING); } } } } private boolean checkRichLayoutMotionEvent(MotionEvent event) { if (currentMessageObject == null || currentMessageObject.richLayout == null) return false; if (currentMessageObject.type != MessageObject.TYPE_ARTICLE) return false; final float textY = getStarsPriceTopPadding() + suggestionOfferTopPadding + getTopicSeparatorTopPadding() + this.textY; event.offsetLocation(-textX, -textY); currentMessageObject.richLayout.setChatMessageCellDelegate(this, this.delegate); final boolean handled = currentMessageObject.richLayout.onTouchEvent(event); event.offsetLocation(textX, textY); return handled; } private boolean checkTextBlockMotionEvent(MotionEvent event) { if (!(currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_EMOJIS || currentMessageObject.type == MessageObject.TYPE_STORY_MENTION) || currentMessageObject.textLayoutBlocks == null || currentMessageObject.textLayoutBlocks.isEmpty() || !(currentMessageObject.messageText instanceof Spannable)) { return false; } if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP && (pressedLinkType == 1 || pressedCopyCode != null)) { int x = (int) getEventX(event); int y = (int) getEventY(event); if (x >= textX && y >= textY && x <= textX + currentMessageObject.textWidth && y <= textY + currentMessageObject.textHeight(transitionParams)) { y -= textY; int blockNum = 0; for (int a = 0; a < currentMessageObject.textLayoutBlocks.size(); a++) { if (currentMessageObject.textLayoutBlocks.get(a).textYOffset(currentMessageObject.textLayoutBlocks, transitionParams) > y) { break; } blockNum = a; } try { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum); x -= textX - (block.isRtl() ? currentMessageObject.textXOffset : 0); y -= block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams); if (!block.quote && block.code && x > 0 && x <= currentMessageObject.textWidth && y >= block.padTop + block.height + block.padBottom - dp(38) && y <= block.padTop + block.height + block.padBottom) { if (event.getAction() == MotionEvent.ACTION_UP) { if (block == pressedCopyCode && delegate != null) { delegate.didPressCodeCopy(this, block); } resetCodeSelectors(); pressedCopyCode = null; } else { pressedCopyCode = block; block.copySelector.setHotspot(x, y); block.copySelector.setCallback(this); block.copySelector.setState(pressedState); } return true; } final int line = block.textLayout.getLineForVertical(y); final int off = block.charactersOffset + block.textLayout.getOffsetForHorizontal(line, x); final float left = block.textLayout.getLineLeft(line); if (left <= x && left + block.textLayout.getLineWidth(line) >= x) { Spannable buffer = (Spannable) currentMessageObject.messageText; CharacterStyle[] link = buffer.getSpans(off, off, ClickableSpan.class); boolean isMono = false; if (link == null || link.length == 0) { link = buffer.getSpans(off, off, URLSpanMono.class); isMono = true; } if (link == null || link.length == 0) { link = buffer.getSpans(off, off, AnimatedEmojiSpan.class); isMono = false; } boolean ignore = false; if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (link[0] instanceof AnimatedEmojiSpan) { if (pressedEmoji == null || pressedEmoji != link[0]) { resetPressedLink(1); pressedEmoji = (AnimatedEmojiSpan) link[0]; pressedLinkType = 1; } } else if (pressedLink == null || pressedLink.getSpan() != link[0]) { links.removeLink(pressedLink); pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); if (block.quote && quoteLine != null) { pressedLink.setColor(Theme.multAlpha(quoteLine.getColor(), Theme.isCurrentThemeDark() ? .13f : .10f)); } linkBlockNum = blockNum; linkExplanationBlockNum = -1; pressedLinkType = 1; try { LinkPath path = pressedLink.obtainNewPath(); int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); pos[0] -= block.charactersOffset; pos[1] -= block.charactersOffset; path.setCurrentLayout(block.textLayout, pos[0], 0); block.textLayout.getSelectionPath(pos[0], pos[1], path); if (pos[1] >= block.charactersEnd) { for (int a = blockNum + 1; a < currentMessageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); CharacterStyle[] nextLink; if (isMono) { nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, URLSpanMono.class); } else { nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, ClickableSpan.class); } if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { break; } path = pressedLink.obtainNewPath(); path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams) - block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams)); int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; nextBlock.textLayout.getSelectionPath(0, p1, path); if (p1 < nextBlock.charactersEnd - 1) { break; } } } if (pos[0] <= block.charactersOffset) { int offsetY = 0; for (int a = blockNum - 1; a >= 0; a--) { MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); CharacterStyle[] nextLink; if (isMono) { nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, URLSpanMono.class); } else { nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, ClickableSpan.class); } if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { break; } path = pressedLink.obtainNewPath(); offsetY -= nextBlock.height; int p0 = pos[0] + block.charactersOffset - nextBlock.charactersOffset; int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; path.setCurrentLayout(nextBlock.textLayout, p0, offsetY); nextBlock.textLayout.getSelectionPath(p0, p1, path); if (p0 > nextBlock.charactersOffset) { break; } } } } catch (Exception e) { FileLog.e(e); } links.addLink(pressedLink, 1); } invalidate(); return true; } else { if (link[0] instanceof AnimatedEmojiSpan && pressedEmoji == link[0]) { if (delegate.didPressAnimatedEmoji(this, pressedEmoji)) { resetPressedLink(1); pressedEmoji = null; return true; } resetPressedLink(1); pressedEmoji = null; } else if (pressedLink != null && link[0] == pressedLink.getSpan()) { delegate.didPressUrl(this, pressedLink.getSpan(), false); resetPressedLink(1); return true; } } } } } catch (Exception e) { FileLog.e(e); } } else { resetPressedLink(1); } } else if (event.getAction() == MotionEvent.ACTION_UP) { pressedCopyCode = null; resetCodeSelectors(); } if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP) { int x = (int) getEventX(event); int y = (int) getEventY(event); if (pressedLink == null && x >= textX && y >= textY && x <= textX + currentMessageObject.textWidth && y <= textY + currentMessageObject.textHeight(transitionParams)) { y -= textY; for (int a = 0; a < currentMessageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); if (block.quoteCollapse && block.collapsedHeight < block.height && y >= block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams) && y < block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams) + block.padTop + block.height(transitionParams) + block.padBottom) { pressedBlock = a; if (block.collapsedBounce == null || block.collapsedBounce.getView() != this) { block.collapsedBounce = new ButtonBounce(this); } block.collapsedBounce.setPressed(event.getAction() == MotionEvent.ACTION_DOWN); break; } } } if (event.getAction() == MotionEvent.ACTION_UP) { if (pressedBlock != -1) { for (int a = 0; a < currentMessageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); if (a == pressedBlock && !transitionParams.animateExpandedQuotes) { MessageObject msg = block.messageObject; if (msg == null) { msg = block.messageObject = getPrimaryMessageObject(); } if (msg != null) { final boolean newCollapsed = !block.collapsed(); msg.expandedQuotes = msg.expandedQuotes == null ? new HashSet<>() : new HashSet<>(msg.expandedQuotes); if (newCollapsed) { msg.expandedQuotes.remove(block.index); } else { msg.expandedQuotes.add(block.index); } if (delegate != null) { delegate.forceUpdate(this, true); } } } } } for (int a = 0; a < currentMessageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); if (block.collapsedBounce != null) { block.collapsedBounce.setPressed(false); } } pressedBlock = -1; } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { for (int a = 0; a < currentMessageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); if (block.collapsedBounce != null) { block.collapsedBounce.setPressed(false); } } pressedBlock = -1; } return pressedBlock != -1; } private boolean checkCaptionMotionEvent(MotionEvent event) { if (!(currentCaption instanceof Spannable) || captionLayout == null || touchedByExpanation) { return false; } if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP && (pressedLinkType == 1 || pressedCopyCode != null)) { int x = (int) getEventX(event); int y = (int) getEventY(event); if (x >= captionX && y >= captionY && x <= captionX + captionLayout.textWidth && y <= captionY + captionLayout.textHeight(transitionParams)) { y -= captionY; int blockNum = 0; for (int a = 0; a < captionLayout.textLayoutBlocks.size(); a++) { if (captionLayout.textLayoutBlocks.get(a).textYOffset(captionLayout.textLayoutBlocks, transitionParams) > y) { break; } blockNum = a; } try { MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(blockNum); x -= captionX - (block.isRtl() ? captionLayout.textXOffset : 0); y -= block.textYOffset(captionLayout.textLayoutBlocks, transitionParams); if (!block.quote && block.code && x > 0 && x <= captionLayout.textWidth && y >= block.padTop + block.height + block.padBottom - dp(38) && y <= block.padTop + block.height + block.padBottom) { if (event.getAction() == MotionEvent.ACTION_UP) { if (block == pressedCopyCode && delegate != null) { delegate.didPressCodeCopy(this, block); } resetCodeSelectors(); pressedCopyCode = null; } else { pressedCopyCode = block; block.copySelector.setHotspot(x, y); block.copySelector.setCallback(this); block.copySelector.setState(pressedState); } touchedByCaption = true; return true; } final int line = block.textLayout.getLineForVertical(y); final int off = block.charactersOffset + block.textLayout.getOffsetForHorizontal(line, x); final float left = block.textLayout.getLineLeft(line); if (left <= x && left + block.textLayout.getLineWidth(line) >= x) { Spannable buffer = (Spannable) currentCaption; CharacterStyle[] link = buffer.getSpans(off, off, ClickableSpan.class); boolean isMono = false; if (link == null || link.length == 0) { link = buffer.getSpans(off, off, URLSpanMono.class); isMono = true; } if (link == null || link.length == 0) { link = buffer.getSpans(off, off, AnimatedEmojiSpan.class); isMono = false; } boolean ignore = false; if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (link[0] instanceof AnimatedEmojiSpan) { if (pressedEmoji == null || pressedEmoji != link[0]) { resetPressedLink(1); pressedEmoji = (AnimatedEmojiSpan) link[0]; pressedLinkType = 1; } } else if (pressedLink == null || pressedLink.getSpan() != link[0]) { links.removeLink(pressedLink); pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); if (block.quote && quoteLine != null) { pressedLink.setColor(Theme.multAlpha(quoteLine.getColor(), Theme.isCurrentThemeDark() ? .13f : .10f)); } linkBlockNum = blockNum; linkExplanationBlockNum = -1; pressedLinkType = 1; try { LinkPath path = pressedLink.obtainNewPath(); int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); pos[0] -= block.charactersOffset; pos[1] -= block.charactersOffset; path.setCurrentLayout(block.textLayout, pos[0], 0); block.textLayout.getSelectionPath(pos[0], pos[1], path); if (pos[1] >= block.charactersEnd) { for (int a = blockNum + 1; a < captionLayout.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = captionLayout.textLayoutBlocks.get(a); CharacterStyle[] nextLink; if (isMono) { nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, URLSpanMono.class); } else { nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, ClickableSpan.class); } if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { break; } path = pressedLink.obtainNewPath(); path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.textYOffset(captionLayout.textLayoutBlocks, transitionParams) - block.textYOffset(captionLayout.textLayoutBlocks, transitionParams)); int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; nextBlock.textLayout.getSelectionPath(0, p1, path); if (p1 < nextBlock.charactersEnd - 1) { break; } } } if (pos[0] <= block.charactersOffset) { int offsetY = 0; for (int a = blockNum - 1; a >= 0; a--) { MessageObject.TextLayoutBlock nextBlock = captionLayout.textLayoutBlocks.get(a); CharacterStyle[] nextLink; if (isMono) { nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, URLSpanMono.class); } else { nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, ClickableSpan.class); } if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { break; } path = pressedLink.obtainNewPath(); offsetY -= nextBlock.height; int p0 = pos[0] + block.charactersOffset - nextBlock.charactersOffset; int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; path.setCurrentLayout(nextBlock.textLayout, p0, offsetY); nextBlock.textLayout.getSelectionPath(p0, p1, path); if (p0 > nextBlock.charactersOffset) { break; } } } } catch (Exception e) { FileLog.e(e); } links.addLink(pressedLink, 1); } invalidate(); touchedByCaption = true; return true; } else { if (link[0] instanceof AnimatedEmojiSpan && pressedEmoji == link[0]) { if (delegate.didPressAnimatedEmoji(this, pressedEmoji)) { resetPressedLink(1); pressedEmoji = null; return true; } resetPressedLink(1); pressedEmoji = null; } else if (pressedLink != null && link[0] == pressedLink.getSpan()) { delegate.didPressUrl(this, pressedLink.getSpan(), false); resetPressedLink(1); return true; } } } } } catch (Exception e) { FileLog.e(e); } } else { resetPressedLink(1); } } else if (event.getAction() == MotionEvent.ACTION_UP) { pressedCopyCode = null; resetCodeSelectors(); } if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP) { int x = (int) getEventX(event); int y = (int) getEventY(event); if (pressedLink == null && x >= captionX && y >= captionY && x <= captionX + captionLayout.textWidth && y <= captionY + captionLayout.textHeight(transitionParams)) { y -= captionY; for (int a = 0; a < captionLayout.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(a); if (block.quoteCollapse && block.collapsedHeight < block.height && y >= block.textYOffset(captionLayout.textLayoutBlocks, transitionParams) && y < block.textYOffset(captionLayout.textLayoutBlocks, transitionParams) + block.padTop + block.height(transitionParams) + block.padBottom) { pressedBlock = a; if (block.collapsedBounce == null || block.collapsedBounce.getView() != this) { block.collapsedBounce = new ButtonBounce(this); } block.collapsedBounce.setPressed(event.getAction() == MotionEvent.ACTION_DOWN); break; } } } if (event.getAction() == MotionEvent.ACTION_UP) { if (pressedBlock != -1) { for (int a = 0; a < captionLayout.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(a); if (a == pressedBlock && !transitionParams.animateExpandedQuotes) { MessageObject msg = getPrimaryMessageObject(); final boolean newCollapsed = !block.collapsed(); msg.expandedQuotes = msg.expandedQuotes == null ? new HashSet<>() : new HashSet<>(msg.expandedQuotes); if (newCollapsed) { msg.expandedQuotes.remove(block.index); } else { msg.expandedQuotes.add(block.index); } if (delegate != null) { delegate.forceUpdate(this, true); } } } } for (int a = 0; a < captionLayout.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(a); if (block.collapsedBounce != null) { block.collapsedBounce.setPressed(false); } } pressedBlock = -1; } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { for (int a = 0; a < captionLayout.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(a); if (block.collapsedBounce != null) { block.collapsedBounce.setPressed(false); } } pressedBlock = -1; } return pressedBlock != -1; } private boolean touchedByExpanation; private boolean touchedByCaption; private boolean checkExplanationMotionEvent(MotionEvent event) { if (!(currentExplanation instanceof Spannable) || explanationLayout == null || pressedBlock != -1 || touchedByCaption) { return false; } if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP && (pressedLinkType == 1 || pressedCopyCode != null)) { int x = (int) getEventX(event); int y = (int) getEventY(event); if (x >= lastDrawExplanationX && y >= lastDrawExplanationY && x <= lastDrawExplanationX + explanationLayout.textWidth && y <= lastDrawExplanationY + explanationLayout.textHeight(transitionParams)) { y -= lastDrawExplanationY; int blockNum = 0; for (int a = 0; a < explanationLayout.textLayoutBlocks.size(); a++) { if (explanationLayout.textLayoutBlocks.get(a).textYOffset(explanationLayout.textLayoutBlocks, transitionParams) > y) { break; } blockNum = a; } try { MessageObject.TextLayoutBlock block = explanationLayout.textLayoutBlocks.get(blockNum); x -= lastDrawExplanationX - (block.isRtl() ? explanationLayout.textXOffset : 0); y -= block.textYOffset(explanationLayout.textLayoutBlocks, transitionParams); final int line = block.textLayout.getLineForVertical(y); final int off = block.charactersOffset + block.textLayout.getOffsetForHorizontal(line, x); final float left = block.textLayout.getLineLeft(line); if (left <= x && left + block.textLayout.getLineWidth(line) >= x) { Spannable buffer = (Spannable) currentExplanation; CharacterStyle[] link = buffer.getSpans(off, off, ClickableSpan.class); boolean isMono = false; if (link == null || link.length == 0) { link = buffer.getSpans(off, off, URLSpanMono.class); isMono = true; } if (link == null || link.length == 0) { link = buffer.getSpans(off, off, AnimatedEmojiSpan.class); isMono = false; } boolean ignore = false; if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (link[0] instanceof AnimatedEmojiSpan) { if (pressedEmoji == null || pressedEmoji != link[0]) { resetPressedLink(1); pressedEmoji = (AnimatedEmojiSpan) link[0]; pressedLinkType = 1; } } else if (pressedLink == null || pressedLink.getSpan() != link[0]) { links.removeLink(pressedLink); pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); if (block.quote && quoteLine != null) { pressedLink.setColor(Theme.multAlpha(quoteLine.getColor(), Theme.isCurrentThemeDark() ? .13f : .10f)); } linkExplanationBlockNum = blockNum; linkBlockNum = -1; pressedLinkType = 1; try { LinkPath path = pressedLink.obtainNewPath(); int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); pos[0] -= block.charactersOffset; pos[1] -= block.charactersOffset; path.setCurrentLayout(block.textLayout, pos[0], 0); block.textLayout.getSelectionPath(pos[0], pos[1], path); if (pos[1] >= block.charactersEnd) { for (int a = blockNum + 1; a < explanationLayout.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = explanationLayout.textLayoutBlocks.get(a); CharacterStyle[] nextLink; if (isMono) { nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, URLSpanMono.class); } else { nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, ClickableSpan.class); } if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { break; } path = pressedLink.obtainNewPath(); path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.textYOffset(explanationLayout.textLayoutBlocks, transitionParams) - block.textYOffset(explanationLayout.textLayoutBlocks, transitionParams)); int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; nextBlock.textLayout.getSelectionPath(0, p1, path); if (p1 < nextBlock.charactersEnd - 1) { break; } } } if (pos[0] <= block.charactersOffset) { int offsetY = 0; for (int a = blockNum - 1; a >= 0; a--) { MessageObject.TextLayoutBlock nextBlock = explanationLayout.textLayoutBlocks.get(a); CharacterStyle[] nextLink; if (isMono) { nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, URLSpanMono.class); } else { nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, ClickableSpan.class); } if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { break; } path = pressedLink.obtainNewPath(); offsetY -= nextBlock.height; int p0 = pos[0] + block.charactersOffset - nextBlock.charactersOffset; int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; path.setCurrentLayout(nextBlock.textLayout, p0, offsetY); nextBlock.textLayout.getSelectionPath(p0, p1, path); if (p0 > nextBlock.charactersOffset) { break; } } } } catch (Exception e) { FileLog.e(e); } links.addLink(pressedLink, 1); } touchedByExpanation = true; invalidate(); return true; } else { if (link[0] instanceof AnimatedEmojiSpan && pressedEmoji == link[0]) { if (delegate.didPressAnimatedEmoji(this, pressedEmoji)) { resetPressedLink(1); pressedEmoji = null; return true; } resetPressedLink(1); pressedEmoji = null; } else if (pressedLink != null && link[0] == pressedLink.getSpan()) { delegate.didPressUrl(this, pressedLink.getSpan(), false); resetPressedLink(1); return true; } } } } } catch (Exception e) { FileLog.e(e); } } else { resetPressedLink(1); } } else if (event.getAction() == MotionEvent.ACTION_UP) { pressedCopyCode = null; resetCodeSelectors(); } return false; } private boolean checkGameMotionEvent(MotionEvent event) { if (!hasGamePreview) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (drawPhotoImage && drawImageButton && buttonState != -1 && x >= buttonX && x <= buttonX + dp(48) && y >= buttonY && y <= buttonY + dp(48) && radialProgress.getIcon() != MediaActionDrawable.ICON_NONE) { buttonPressed = 1; invalidate(); return true; } else if (drawPhotoImage && photoImage.isInsideImage(x, y)) { gamePreviewPressed = true; return true; } else if (descriptionLayout != null && y >= descriptionY) { try { x -= unmovedTextX + dp(10) + descriptionX; y -= descriptionY; final int line = descriptionLayout.getLineForVertical(y); final int off = descriptionLayout.getOffsetForHorizontal(line, x); final float left = descriptionLayout.getLineLeft(line); if (left <= x && left + descriptionLayout.getLineWidth(line) >= x) { Spannable buffer = (Spannable) currentMessageObject.linkDescription; ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); boolean ignore = false; if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { if (pressedLink == null || pressedLink.getSpan() != link[0]) { links.removeLink(pressedLink); pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); linkBlockNum = -10; pressedLinkType = 2; try { LinkPath path = pressedLink.obtainNewPath(); int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); path.setCurrentLayout(descriptionLayout, pos[0], 0); descriptionLayout.getSelectionPath(pos[0], pos[1], path); } catch (Exception e) { FileLog.e(e); } links.addLink(pressedLink, 2); } invalidate(); return true; } } } catch (Exception e) { FileLog.e(e); } } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (pressedLinkType == 2 || gamePreviewPressed || buttonPressed != 0) { if (buttonPressed != 0) { buttonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); didPressButton(true, false); invalidate(); } else if (pressedLink != null) { if (pressedLink.getSpan() instanceof URLSpan) { Browser.openUrl(getContext(), ((URLSpan) pressedLink.getSpan()).getURL()); } else if (pressedLink.getSpan() instanceof ClickableSpan) { ((ClickableSpan) pressedLink.getSpan()).onClick(this); } resetPressedLink(2); } else { gamePreviewPressed = false; for (int a = 0; a < botButtons.size(); a++) { BotButton button = botButtons.get(a); if (TLKeyboardHelper.isType(button.button, TL_keyboard.TL_inlineButtonTypeGame.class)) { playSoundEffect(SoundEffectConstants.CLICK); delegate.didPressBotButton(this, button.button); invalidate(); break; } } resetPressedLink(2); return true; } } else { resetPressedLink(2); } } return false; } private boolean checkTranscribeButtonMotionEvent(MotionEvent event) { return useTranscribeButton && (!isPlayingRound || getVideoTranscriptionProgress() > 0 || wasTranscriptionOpen) && transcribeButton != null && transcribeButton.onTouch(event.getAction(), getEventX(event), getEventY(event)); } private boolean checkLinkPreviewMotionEvent(MotionEvent event) { if (currentMessageObject.type != MessageObject.TYPE_TEXT && currentMessageObject.type != MessageObject.TYPE_STORY_MENTION || !hasLinkPreview) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); if (x >= unmovedTextX && x <= unmovedTextX + backgroundWidth - dp(14) && y >= linkPreviewY && y <= linkPreviewY + linkPreviewHeight + dp(8 + (drawInstantView ? 46 : 0))) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (descriptionLayout != null && y >= descriptionY && !currentMessageObject.preview) { try { int checkX = x - (unmovedTextX + dp(10) + descriptionX); int checkY = y - descriptionY; if (checkY <= descriptionLayout.getHeight()) { final int line = descriptionLayout.getLineForVertical(checkY); final int off = descriptionLayout.getOffsetForHorizontal(line, checkX); final float left = descriptionLayout.getLineLeft(line); if (left <= checkX && left + descriptionLayout.getLineWidth(line) >= checkX) { Spannable buffer = (Spannable) (currentMessageObject.isSponsored() ? currentMessageObject.messageText : currentMessageObject.linkDescription); ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); boolean ignore = false; if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { if (pressedLink == null || pressedLink.getSpan() != link[0]) { links.removeLink(pressedLink); pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); pressedLink.setColor(hasLinkPreview && linkLine != null && currentMessageObject != null && !currentMessageObject.isOutOwner() ? Theme.multAlpha(linkLine.getColor(), .10f) : getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); linkBlockNum = -10; pressedLinkType = 2; startCheckLongPress(); try { LinkPath path = pressedLink.obtainNewPath(); int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); path.setCurrentLayout(descriptionLayout, pos[0], 0); descriptionLayout.getSelectionPath(pos[0], pos[1], path); } catch (Exception e) { FileLog.e(e); } links.addLink(pressedLink, 2); } invalidate(); return true; } } } } catch (Exception e) { FileLog.e(e); } } if (pressedLink == null) { int side = dp(48); boolean area2 = false; if (miniButtonState >= 0) { int offset = dp(27); area2 = x >= buttonX + offset && x <= buttonX + offset + side && y >= buttonY + offset && y <= buttonY + offset + side; } if (area2) { miniButtonPressed = 1; invalidate(); return true; } else if (drawVideoImageButton && buttonState != -1 && x >= videoButtonX && x <= videoButtonX + dp(26 + 8) + Math.max(infoWidth, docTitleWidth) && y >= videoButtonY && y <= videoButtonY + dp(30)) { videoButtonPressed = 1; invalidate(); return true; } else if (drawPhotoImage && currentMessageObject.sponsoredMedia != null && photoImage.isInsideImage(x, y) || drawPhotoImage && drawImageButton && (buttonState != -1 || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) && (!checkOnlyButtonPressed && photoImage.isInsideImage(x, y) || x >= buttonX && x <= buttonX + dp(48) && y >= buttonY && y <= buttonY + dp(48) && radialProgress.getIcon() != MediaActionDrawable.ICON_NONE)) { buttonPressed = 1; invalidate(); if (currentMessageObject.sponsoredMedia != null && (MessageObject.isGifDocument(currentMessageObject.sponsoredMedia.document) || currentMessageObject.sponsoredMedia.photo != null)) { if (selectorDrawable[0] != null && selectorDrawable[0].getBounds().contains(x, y)) { selectorDrawable[0].setHotspot(x, y); selectorDrawable[0].setState(pressedState); } if (linkPreviewSelector != null && linkPreviewSelector.getBounds().contains(x, y)) { linkPreviewSelector.setHotspot(x, y); linkPreviewSelector.setState(pressedState); } setInstantButtonPressed(true); if (linkPreviewBounce != null) { linkPreviewBounce.setPressed(true); } } return true; } else { instantPressed = true; selectorDrawableMaskType[0] = 0; if (selectorDrawable[0] != null && selectorDrawable[0].getBounds().contains(x, y)) { selectorDrawable[0].setHotspot(x, y); selectorDrawable[0].setState(pressedState); } if (linkPreviewSelector != null && linkPreviewSelector.getBounds().contains(x, y)) { linkPreviewSelector.setHotspot(x, y); linkPreviewSelector.setState(pressedState); } setInstantButtonPressed(true); if (linkPreviewBounce != null) { linkPreviewBounce.setPressed(true); } invalidate(); return true; } // else if (documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT && drawPhotoImage && photoImage.isInsideImage(x, y)) { // linkPreviewPressed = true; // TLRPC.WebPage webPage = MessageObject.getMedia(currentMessageObject.messageOwner).webpage; // if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && buttonState == -1 && SharedConfig.isAutoplayGifs() && (photoImage.getAnimation() == null || !TextUtils.isEmpty(webPage.embed_url))) { // linkPreviewPressed = false; // return false; // } // return true; // } } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (instantPressed) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { if (!MediaController.getInstance().isPlayingMessage(currentMessageObject) || MediaController.getInstance().isMessagePaused()) { delegate.needPlayMessage(this, currentMessageObject, false); } else { MediaController.getInstance().pauseMessage(currentMessageObject); } } else if (drawInstantView || currentMessageObject != null && currentMessageObject.currentEvent != null && currentMessageObject.currentEvent.action instanceof TLRPC.TL_channelAdminLogEventActionEditMessage) { if (delegate != null) { delegate.didPressInstantButton(this, drawInstantViewType); } } else if (drawPhotoImage && (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || authorLayout == null && titleLayout == null && descriptionLayout == null && siteNameLayout == null)) { if (delegate != null) { delegate.didPressImage(this, lastTouchX, lastTouchY, true); } } else if (currentMessageObject != null && !currentMessageObject.preview) { TLRPC.WebPage webPage = MessageObject.getMedia(currentMessageObject.messageOwner).webpage; if (webPage != null && !TextUtils.isEmpty(webPage.embed_url)/* && TextUtils.isEmpty(WebPlayerView.getYouTubeVideoId(webPage.embed_url))*/) { if (delegate != null) { delegate.needOpenWebView(currentMessageObject, webPage.embed_url, webPage.site_name, webPage.title, webPage.url, webPage.embed_width, webPage.embed_height); } } else if (webPage != null) { if (delegate != null) { delegate.didPressWebPage(this, webPage, webPage.url, MessageObject.getMedia(currentMessageObject.messageOwner).safe); } else { Browser.openUrl(getContext(), webPage.url); } } } playSoundEffect(SoundEffectConstants.CLICK); if (selectorDrawable[0] != null) { selectorDrawable[0].setState(StateSet.NOTHING); } if (linkPreviewSelector != null) { linkPreviewSelector.setState(StateSet.NOTHING); } if (linkPreviewBounce != null) { linkPreviewBounce.setPressed(false); } setInstantButtonPressed(instantPressed = false); invalidate(); } else if (pressedLinkType == 2 || buttonPressed != 0 || miniButtonPressed != 0 || videoButtonPressed != 0 || linkPreviewPressed) { if (videoButtonPressed == 1) { videoButtonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); didPressButton(true, true); invalidate(); } else if (buttonPressed != 0) { buttonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); if (drawVideoImageButton || buttonState == -1 && documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || currentMessageObject.sponsoredMedia != null) { didClickedImage(); } else { didPressButton(true, false); } invalidate(); } else if (miniButtonPressed != 0) { miniButtonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); didPressMiniButton(true); invalidate(); } else if (pressedLink != null) { if (pressedLink.getSpan() instanceof URLSpan) { delegate.didPressUrl(this, pressedLink.getSpan(), false); } else if (pressedLink.getSpan() instanceof ClickableSpan) { ((ClickableSpan) pressedLink.getSpan()).onClick(this); } resetPressedLink(2); } else if (pressedEmoji != null && delegate.didPressAnimatedEmoji(this, pressedEmoji)) { pressedEmoji = null; resetPressedLink(2); } else { if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && drawImageButton) { if (buttonState == -1) { if (SharedConfig.isAutoplayGifs() && !currentMessageObject.isRepostPreview) { delegate.didPressImage(this, lastTouchX, lastTouchY, false); } else { buttonState = 2; currentMessageObject.gifState = 1; photoImage.setAllowStartAnimation(false); photoImage.stopAnimation(); radialProgress.setIcon(getIconForCurrentState(), false, true); invalidate(); playSoundEffect(SoundEffectConstants.CLICK); } } else if (buttonState == 2 || buttonState == 0) { didPressButton(true, false); playSoundEffect(SoundEffectConstants.CLICK); } } else if (!currentMessageObject.preview) { TLRPC.WebPage webPage = MessageObject.getMedia(currentMessageObject.messageOwner).webpage; if (webPage != null && !TextUtils.isEmpty(webPage.embed_url)) { delegate.needOpenWebView(currentMessageObject, webPage.embed_url, webPage.site_name, webPage.title, webPage.url, webPage.embed_width, webPage.embed_height); } else if (buttonState == -1 || buttonState == 3) { delegate.didPressImage(this, lastTouchX, lastTouchY, false); playSoundEffect(SoundEffectConstants.CLICK); } else if (webPage != null) { if (delegate != null) { delegate.didPressWebPage(this, webPage, webPage.url, MessageObject.getMedia(currentMessageObject.messageOwner).safe); } else { Browser.openUrl(getContext(), webPage.url); } } } resetPressedLink(2); return true; } } else if (!hadLongPress) { hadLongPress = false; resetPressedLink(2); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (instantButtonPressed) { if (selectorDrawable[0] != null) { selectorDrawable[0].setHotspot(x, y); } if (linkPreviewSelector != null) { linkPreviewSelector.setHotspot(x, y); } } } } return false; } private boolean pressedEffect = false; private boolean checkEffectMotionEvent(MotionEvent event) { if (currentMessageObject == null || currentMessageObject.getEffect() == null) { return false; } int x = (int) (getTimeX() - dp(effectId == 0 ? 0 : 14 + 4) + timeWidth * (currentMessageObject.sendPreview ? 1f - timeAlpha : 0f)); int y = (int) getTimeY(); x -= dp(2); y -= dp(2); AndroidUtilities.rectTmp.set(x, y, x + dp(16) + timeWidth, y + dp(16)); final boolean hit = AndroidUtilities.rectTmp.contains(getEventX(event), getEventY(event)); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (hit) { if (effectDrawableBounce == null) { effectDrawableBounce = new ButtonBounce(this); } pressedEffect = true; } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { pressedEffect = hit; } else if (event.getAction() == MotionEvent.ACTION_UP) { if (pressedEffect && delegate != null) { delegate.didPressEffect(this); } pressedEffect = false; } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { pressedEffect = false; } if (effectDrawableBounce != null) { effectDrawableBounce.setPressed(pressedEffect); } return pressedEffect; } private boolean factCheckWhatPressed; private boolean factCheckPressed; private boolean checkFactCheckMotionEvent(MotionEvent event) { if (!hasFactCheck || factCheckTitle == null || factCheckWhat == null) { return false; } if (factCheckWhatBounce == null) { factCheckWhatBounce = new ButtonBounce(this); } if (factCheckBounce == null) { factCheckBounce = new ButtonBounce(this); factCheckBounce.setAdditionalInvalidate(this::invalidateOutbounds); } final float right = getBackgroundDrawableRight() + (transitionParams != null ? transitionParams.deltaRight : 0) - dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) - getExtraTextX(); int x, y; if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { x = (int) captionX; } else if (currentMessageObject.isOutOwner()) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { x -= Math.max(0, x + Math.max(replyNameWidth, replyTextWidth) + dp(14) - AndroidUtilities.displaySize.x); } } else { if (mediaBackground) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { x = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } x += transitionParams.deltaLeft; x -= dp(1.33f); y = this.factCheckY; final int width = (int) (right - x); final int ex = (int) getEventX(event); final int ey = (int) getEventY(event); final int bx = (int) (x + dp(10) + factCheckTitle.getCurrentWidth() + dp(4)); final int by = (int) (y + dp(4.33f)); AndroidUtilities.rectTmp.set(bx, by, bx + factCheckWhat.getCurrentWidth() + dp(4), by + dp(17.33f)); final boolean whatHit = AndroidUtilities.rectTmp.contains(getEventX(event), getEventY(event)); AndroidUtilities.rectTmp.set(x, y, x + width, y + factCheckHeight); boolean allHit = !whatHit && !hadLongPress && pressedFactCheckLink == null && AndroidUtilities.rectTmp.contains(getEventX(event), getEventY(event)); if ((allHit && !hadLongPress || pressedFactCheckLink != null) && factCheckTextLayout != null) { if (factCheckLinks == null) { factCheckLinks = new LinkSpanDrawable.LinkCollector(this); factCheckLinks.setAdditionalInvalidate(this::invalidateOutbounds); } final int textX = x + dp(10) - factCheckTextLayoutLeft; final int textY = y + dp(22); if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP && pressedFactCheckLink != null) { if (ex >= textX && ey >= textY && ex <= textX + width && ey <= textY + factCheckTextLayout.getHeight()) { try { final int line = factCheckTextLayout.getLineForVertical(ey - textY); final int off = factCheckTextLayout.getOffsetForHorizontal(line, ex - textX); final float left = factCheckTextLayout.getLineLeft(line); if (left <= ex - textX && left + factCheckTextLayout.getLineWidth(line) >= ex - textX) { Spannable buffer = (Spannable) factCheckTextLayout.getText(); CharacterStyle[] link = buffer.getSpans(off, off, ClickableSpan.class); boolean isMono = false; if (link == null || link.length == 0) { link = buffer.getSpans(off, off, URLSpanMono.class); isMono = true; } boolean ignore = false; if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (pressedFactCheckLink == null || pressedFactCheckLink.getSpan() != link[0]) { factCheckLinks.removeLink(pressedFactCheckLink); pressedFactCheckLink = new LinkSpanDrawable(link[0], resourcesProvider, ex - textX, ey - textY, spanSupportsLongPress(link[0])); if (factCheckLine != null) { pressedFactCheckLink.setColor(Theme.multAlpha(factCheckLine.getColor(), .10f)); } try { LinkPath path = pressedFactCheckLink.obtainNewPath(); int[] pos = getRealSpanStartAndEnd(buffer, pressedFactCheckLink.getSpan()); path.setCurrentLayout(factCheckTextLayout, pos[0], 0); factCheckTextLayout.getSelectionPath(pos[0], pos[1], path); } catch (Exception e) { FileLog.e(e); } factCheckLinks.addLink(pressedFactCheckLink, 1); allHit = false; } invalidate(); } else { if (pressedFactCheckLink != null && link[0] == pressedFactCheckLink.getSpan()) { delegate.didPressUrl(this, pressedFactCheckLink.getSpan(), false); resetPressedLink(1); factCheckWhatPressed = false; factCheckPressed = false; pressedFactCheckLink = null; } } } } } catch (Exception e) { FileLog.e(e); } } else { resetPressedLink(1); } } } allHit = factCheckLarge && allHit; if (event.getAction() == MotionEvent.ACTION_DOWN) { factCheckWhatPressed = whatHit; factCheckPressed = allHit; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { factCheckWhatPressed = whatHit; factCheckPressed = allHit; } else if (event.getAction() == MotionEvent.ACTION_UP) { if (factCheckWhatPressed) { if (delegate != null) { delegate.didPressFactCheckWhat(this, (int) (bx + dp(4) + factCheckWhat.getCurrentWidth() / 2f), by); } } else if (factCheckPressed && !transitionParams.animateFactCheckExpanded) { if (delegate != null) { delegate.didPressFactCheck(this); } } factCheckWhatPressed = false; factCheckPressed = false; } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { factCheckWhatPressed = false; factCheckPressed = false; if (factCheckLinks != null) { factCheckLinks.clear(); } pressedFactCheckLink = null; } factCheckWhatBounce.setPressed(factCheckWhatPressed); factCheckBounce.setPressed(factCheckPressed); return factCheckWhatPressed || factCheckPressed || pressedFactCheckLink != null; } private boolean checkPollMediaMotionEvent(MotionEvent event) { if (currentMessageObject == null || currentMessageObject.type != MessageObject.TYPE_POLL || currentMessageObject.isSending()) { return false; } final int action = event.getAction(); final int x = (int) getEventX(event); final int y = (int) getEventY(event); boolean result = false; if (pollContentDrawable != null) { if (pollContentDrawable.isMusic() && pollContentDrawable.isPlaying()) { if (pollContentDrawable.seekBarOnTouch(action, x, y)) { if (action == MotionEvent.ACTION_DOWN) { getParent().requestDisallowInterceptTouchEvent(true); } disallowLongPress = true; invalidate(); return true; } } if (pollContentDrawable.isMusic() || pollContentDrawable.isFile()) { if (pollContentDrawable.miniButtonOnTouch(action, x, y)) { disallowLongPress = true; invalidate(); return true; } } } if (currentMessageObject.expandedExplanation && pollExplanationDrawable != null) { if (pollExplanationDrawable.isMusic() && pollExplanationDrawable.isPlaying()) { if (pollExplanationDrawable.seekBarOnTouch(action, x, y)) { if (action == MotionEvent.ACTION_DOWN) { getParent().requestDisallowInterceptTouchEvent(true); } disallowLongPress = true; invalidate(); return true; } } if (pollExplanationDrawable.isMusic() || pollExplanationDrawable.isFile()) { if (pollExplanationDrawable.miniButtonOnTouch(action, x, y)) { disallowLongPress = true; invalidate(); return true; } } } if (action == MotionEvent.ACTION_DOWN) { pollMediaPressedIndex = PollAttachedMediaPack.INDEX_NONE; if (pollContentDrawable != null && pollContentDrawable.isHasMedia() && pollContentDrawable.getBounds().contains(x, y)) { pollMediaPressedIndex = PollAttachedMediaPack.INDEX_DESCRIPTION; result = true; invalidate(); } else if (currentMessageObject.expandedExplanation && pollExplanationDrawable != null && pollExplanationDrawable.isHasMedia() && pollExplanationDrawable.getBounds().contains(x, y)) { pollMediaPressedIndex = PollAttachedMediaPack.INDEX_EXPLANATION; result = true; invalidate(); } } else if (action == MotionEvent.ACTION_MOVE) { result = pollMediaPressedIndex != PollAttachedMediaPack.INDEX_NONE; } else if (action == MotionEvent.ACTION_UP) { if (pollMediaPressedIndex != PollAttachedMediaPack.INDEX_NONE) { playSoundEffect(SoundEffectConstants.CLICK); if (pollMediaPressedIndex == PollAttachedMediaPack.INDEX_DESCRIPTION) { didClickedPollImage(this, pollContentDrawable.getImageReceiver(), null, pollContentDrawable.getMedia(), x, y, PollAttachedMediaPack.INDEX_DESCRIPTION); } else if (pollMediaPressedIndex == PollAttachedMediaPack.INDEX_EXPLANATION) { didClickedPollImage(this, pollExplanationDrawable.getImageReceiver(), null, pollExplanationDrawable.getMedia(), x, y, PollAttachedMediaPack.INDEX_EXPLANATION); } pollMediaPressedIndex = PollAttachedMediaPack.INDEX_NONE; invalidate(); result = true; } } return result; } private void resetPollButtonSelectors() { if (pollButtons != null) { for (int a = 0; a < pollButtons.size(); a++) { PollButton button = pollButtons.get(a); button.selectorDrawable.setState(StateSet.NOTHING); } } if (pollAddButtonDrawable != null) { pollAddButtonDrawable.resetSelectors(); } } private boolean checkPollButtonMotionEvent(MotionEvent event) { if (currentMessageObject.eventId != 0 || (pollVoteInProgress || pollUnvoteInProgress) && !currentMessageObject.isTodo() || pollButtons.isEmpty() || currentMessageObject.type != MessageObject.TYPE_POLL || !currentMessageObject.isSent()) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); boolean result = false; if (event.getAction() == MotionEvent.ACTION_DOWN) { pressedVoteButton = -1; pollHintPressed = false; pollAddButtonPressed = -1; closeExplanationPressed = false; resetPressedLink(4); if (closeExplanationX != -1 && closeExplanationY != -1 && Math.abs(x - closeExplanationX) < dp(20) && Math.abs(y - closeExplanationY) < dp(20)) { closeExplanationPressed = true; result = true; resetPollButtonSelectors(); invalidate(); } else if (hintButtonVisible && pollHintX != -1 && x >= pollHintX && x <= pollHintX + dp(40) && y >= pollHintY && y <= pollHintY + dp(40)) { pollHintPressed = true; result = true; selectorDrawableMaskType[0] = 3; if (selectorDrawable[0] != null) { selectorDrawable[0].setBounds(pollHintX - dp(8), pollHintY - dp(8), pollHintX + dp(32), pollHintY + dp(32)); selectorDrawable[0].setHotspot(x, y); selectorDrawable[0].setState(pressedState); } resetPollButtonSelectors(); invalidate(); } else if (currentMessageObject.forceShowPollResults) { // make buttons is non clickable when preview results resetPollButtonSelectors(); invalidate(); } else { resetPollButtonSelectors(); for (int a = 0; a < pollButtons.size(); a++) { PollButton button = pollButtons.get(a); int y2 = button.y + namesOffset - dp(13); if (button.title != null && button.title.getText() instanceof Spannable && x >= button.titleX && y >= button.titleY && !currentMessageObject.preview) { try { int checkX = x - (int) button.titleX; int checkY = y - (int) button.titleY; if (checkY <= button.title.getHeight()) { final int line = button.title.getLineForVertical(checkY); final int off = button.title.getOffsetForHorizontal(line, checkX); final float left = button.title.getLineLeft(line); if (left <= checkX && left + button.title.getLineWidth(line) >= checkX) { Spannable buffer = (Spannable) button.title.getText(); ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); boolean ignore = false; if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { if (pressedLink == null || pressedLink.getSpan() != link[0]) { links.removeLink(pressedLink); pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); linkBlockNum = a; pressedLinkType = 4; startCheckLongPress(); try { LinkPath path = pressedLink.obtainNewPath(); int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); path.setCurrentLayout(button.title, pos[0], 0); button.title.getSelectionPath(pos[0], pos[1], path); } catch (Exception e) { FileLog.e(e); } links.addLink(pressedLink, 4); } result = true; invalidate(); break; } } } } catch (Exception e) { FileLog.e(e); } } if (x >= button.x && x <= button.x + backgroundWidth - dp(31) && y >= y2 && y <= y2 + button.height + dp(26)) { pressedVoteButton = a; pressedVoteIsMedia = button.pollButtonDrawable != null && button.pollButtonDrawable.isHasMedia() && x > button.x + backgroundWidth - dp(31 + 36 + 9 + 5); if (/*!pollVoted && !pollClosed &&*/ !pressedVoteIsMedia) { selectorDrawableMaskType[0] = 1; // if (Build.VERSION.SDK_INT >= 21 && selectorDrawable[0] != null) { // selectorDrawable[0].setBounds(button.x - dp(9), y2, button.x + backgroundWidth - dp(22), y2 + button.height + dp(26)); // selectorDrawable[0].setHotspot(x, y); // selectorDrawable[0].setState(pressedState); // } button.selectorDrawable.setHotspot(x, y); button.selectorDrawable.setState(pressedState); invalidate(); } result = true; break; } } if (!result && pollAllowAdding && pollAddButtonDrawable != null) { pollAddButtonPressed = pollAddButtonDrawable.checkMotionPressed(x, y); if (pollAddButtonPressed != -1) { result = true; } } } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (pollAddButtonPressed != PollAddButtonDrawable.MOTION_NONE) { playSoundEffect(SoundEffectConstants.CLICK); if (currentMessageObject != null && delegate != null) { if (pollAddButtonPressed == PollAddButtonDrawable.MOTION_ALL) { delegate.didPressAddPollOptionButton(this); } } pollAddButtonPressed = PollAddButtonDrawable.MOTION_NONE; resetPollButtonSelectors(); } else if (closeExplanationPressed) { playSoundEffect(SoundEffectConstants.CLICK); didPressVoteHint(); closeExplanationPressed = false; resetPollButtonSelectors(); } else if (pollHintPressed) { playSoundEffect(SoundEffectConstants.CLICK); didPressVoteHint(); pollHintPressed = false; pollAddButtonPressed = -1; resetPollButtonSelectors(); } else if (pressedLink != null) { if (pressedLink.getSpan() instanceof URLSpan) { delegate.didPressUrl(this, pressedLink.getSpan(), false); } else if (pressedLink.getSpan() instanceof ClickableSpan) { ((ClickableSpan) pressedLink.getSpan()).onClick(this); } resetPressedLink(4); } else if (pressedVoteButton != -1) { playSoundEffect(SoundEffectConstants.CLICK); resetPollButtonSelectors(); if (pressedVoteIsMedia) { PollButton button = pollButtons.get(pressedVoteButton); didClickedPollImage(this, button.pollButtonDrawable.getImageReceiver(), button.answer, button.answer.media, event.getX(), event.getY(), button.answer.unshuffled_index); } else if (currentMessageObject.scheduled) { Toast.makeText(getContext(), getString(currentMessageObject.isTodo() ? R.string.MessageScheduledTodo : R.string.MessageScheduledVote), Toast.LENGTH_LONG).show(); } else { PollButton button = pollButtons.get(pressedVoteButton); TLRPC.PollAnswer answer = button.answer; if (pollVoted || pollClosed) { ArrayList answers = new ArrayList<>(); answers.add(answer); delegate.didLongPressPollOption(this, answer); } else if (pollHasVoteRestrictions) { ArrayList answers = new ArrayList<>(); answers.add(answer); delegate.didPressVoteButtons(this, answers, button.count, button.x + dp(50), button.y + namesOffset); } else { if (lastPoll != null && lastPoll.multiple_choice) { if (currentMessageObject.checkedVotes.contains(answer)) { currentMessageObject.checkedVotes.remove(answer); pollCheckBox[pressedVoteButton].setChecked(false, true); } else { currentMessageObject.checkedVotes.add(answer); pollCheckBox[pressedVoteButton].setChecked(true, true); } checkInstantButtonForPoll(true); } else { pollVoteInProgressNum = pressedVoteButton; pollVoteInProgress = true; voteCurrentProgressTime = 0.0f; firstCircleLength = true; voteCurrentCircleLength = 360; voteRisingCircleLength = false; if (button.task != null) { toggleTodoCheck(pressedVoteButton, true); } else { vibrateOnPollVote = true; ArrayList answers = new ArrayList<>(); answers.add(answer); delegate.didPressVoteButtons(this, answers, -1, 0, 0); } } } } pressedVoteButton = -1; invalidate(); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if ((pressedVoteButton != -1 || pollHintPressed) && selectorDrawable[0] != null) { selectorDrawable[0].setHotspot(x, y); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { resetPollButtonSelectors(); } return result; } public void didPressVoteHint() { /* if (delegate != null) { delegate.didPressHint(this, 0); } */ if (currentMessageObject != null) { currentMessageObject.expandedExplanation = !currentMessageObject.expandedExplanation; if (delegate != null) { delegate.forceUpdate(this, true); } } } private boolean checkInstantButtonMotionEvent(MotionEvent event) { if (!currentMessageObject.isSponsored() && !currentMessageObject.isUnsupported() && (!drawInstantView || currentMessageObject.type == MessageObject.TYPE_TEXT)) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (drawInstantView && instantButtonRect.contains(x, y)) { selectorDrawableMaskType[0] = lastPoll != null ? 2 : 0; instantPressed = true; if (selectorDrawable[0] != null) { if (instantButtonRect.contains(x, y)) { selectorDrawable[0].setHotspot(x, y); selectorDrawable[0].setState(pressedState); setInstantButtonPressed(true); } } invalidate(); return true; } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (instantPressed) { if (delegate != null) { if (lastPoll != null) { if (currentMessageObject.scheduled) { Toast.makeText(getContext(), getString(R.string.MessageScheduledVoteResults), Toast.LENGTH_LONG).show(); } else { if (pollInInputNewOption) { delegate.didPressInstantButton(this, ChatMessageCell.INSTANT_BUTTON_TYPE_ADD_OPTION); } else if (drawInstantViewType == INSTANT_BUTTON_TYPE_VIEW_VOTES_PUBLIC_LIST) { delegate.didPressInstantButton(this, INSTANT_BUTTON_TYPE_VIEW_VOTES_PUBLIC_LIST); } else if (drawInstantViewType == INSTANT_BUTTON_TYPE_VOTE_MULTISELECT) { if (!currentMessageObject.checkedVotes.isEmpty()) { pollVoteInProgressNum = -1; pollVoteInProgress = true; vibrateOnPollVote = true; voteCurrentProgressTime = 0.0f; firstCircleLength = true; voteCurrentCircleLength = 360; voteRisingCircleLength = false; } delegate.didPressVoteButtons(this, currentMessageObject.checkedVotes, -1, 0, namesOffset); } else if (drawInstantViewType == INSTANT_BUTTON_TYPE_VIEW_VOTES_AS_AUTHOR_LIST) { currentMessageObject.forceShowPollResults = true; pollVoteInProgress = true; delegate.didTogglePollPreview(this); } else if (drawInstantViewType == INSTANT_BUTTON_TYPE_BACK_TO_VOTE) { currentMessageObject.forceShowPollResults = false; delegate.didTogglePollPreview(this); } } } else { delegate.didPressInstantButton(this, drawInstantViewType); } } playSoundEffect(SoundEffectConstants.CLICK); if (selectorDrawable[0] != null) { selectorDrawable[0].setState(StateSet.NOTHING); } setInstantButtonPressed(instantPressed = false); invalidate(); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (instantButtonPressed && selectorDrawable[0] != null) { selectorDrawable[0].setHotspot(x, y); } } return false; } private boolean checkContactMotionEvent(MotionEvent event) { if (currentMessageObject.type != MessageObject.TYPE_CONTACT) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (contactButtons != null && contactButtons.size() > 1) { for (int i = 0; i < contactButtons.size(); i++) { InstantViewButton instantViewButton = contactButtons.get(i); if (instantViewButton.rect.contains(x, y)) { if (instantViewButton.buttonBounce == null) { instantViewButton.buttonBounce = new ButtonBounce(this); } instantViewButton.buttonBounce.setPressed(true); if (instantViewButton.selectorDrawable != null) { instantViewButton.selectorDrawable.setHotspot(x, y); instantViewButton.selectorDrawable.setState(pressedState); } invalidate(); return true; } } } if (contactRect.contains(x, y)) { contactPressed = true; contactBounce.setPressed(true); if (selectorDrawable[0] != null) { selectorDrawable[0].setHotspot(x, y); selectorDrawable[0].setState(pressedState); } invalidate(); return true; } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (contactPressed) { if (delegate != null) { if (contactButtons != null && contactButtons.size() == 1) { delegate.didPressInstantButton(this, contactButtons.get(0).type); } else { delegate.didPressInstantButton(this, INSTANT_BUTTON_TYPE_CONTACT_VIEW); } } playSoundEffect(SoundEffectConstants.CLICK); if (selectorDrawable[0] != null) { selectorDrawable[0].setState(StateSet.NOTHING); } contactPressed = false; contactBounce.setPressed(false); invalidate(); } else if (contactButtons != null && contactButtons.size() > 1) { for (int i = 0; i < contactButtons.size(); i++) { InstantViewButton instantViewButton = contactButtons.get(i); if (instantViewButton.buttonBounce != null && instantViewButton.buttonBounce.isPressed()) { if (delegate != null) { delegate.didPressInstantButton(this, instantViewButton.type); } if (instantViewButton.selectorDrawable != null) { instantViewButton.selectorDrawable.setState(StateSet.NOTHING); } instantViewButton.buttonBounce.setPressed(false); playSoundEffect(SoundEffectConstants.CLICK); invalidate(); } } } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (contactPressed && selectorDrawable[0] != null) { selectorDrawable[0].setHotspot(x, y); } else if (contactButtons != null && contactButtons.size() > 1) { for (int i = 0; i < contactButtons.size(); i++) { InstantViewButton instantViewButton = contactButtons.get(i); if (instantViewButton.buttonBounce != null && instantViewButton.buttonBounce.isPressed()) { if (instantViewButton.selectorDrawable != null) { instantViewButton.selectorDrawable.setHotspot(x, y); } break; } } } } return false; } private boolean checkTitleLabelMotion(MotionEvent event) { if (!currentMessageObject.isSponsored() || !currentMessageObject.sponsoredCanReport) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (x >= titleLabelX - dp(6) && x <= titleLabelX + titleLabelLayoutWidth + dp(6) && y >= titleLabelY - dp(2) && y <= titleLabelY + titleLabelLayoutHeight + dp(2)) { if (titleLabelBounce != null) { titleLabelBounce.setPressed(true); } isTitleLabelPressed = true; return true; } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (isTitleLabelPressed) { if (delegate != null) { delegate.didPressAboutRevenueSharingAds(); } if (titleLabelBounce != null) { titleLabelBounce.setPressed(false); } playSoundEffect(SoundEffectConstants.CLICK); isTitleLabelPressed = false; } } return false; } private void invalidateWithParent() { if (currentMessagesGroup != null && getParent() != null) { ((ViewGroup) getParent()).invalidate(); } invalidate(); } private boolean checkCommentButtonMotionEvent(MotionEvent event) { if (!drawCommentButton) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); if (currentPosition != null && ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0 || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0)) { ViewGroup parent = (ViewGroup) getParent(); boolean r = false; for (int a = 0, N = parent.getChildCount(); a < N; a++) { View view = parent.getChildAt(a); if (view != this && view instanceof ChatMessageCell) { ChatMessageCell cell = (ChatMessageCell) view; if (cell.drawCommentButton && cell.currentMessagesGroup == currentMessagesGroup && (cell.currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (cell.currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { MotionEvent childEvent = MotionEvent.obtain(0, 0, event.getActionMasked(), getEventX(event) + getLeft() - cell.getLeft(), getEventY(event) + getTop() - cell.getTop(), 0); r = cell.checkCommentButtonMotionEvent(childEvent); childEvent.recycle(); break; } } } return r; } if (event.getAction() == MotionEvent.ACTION_DOWN) { if (commentButtonRect.contains(x, y)) { if (currentMessageObject.isSent()) { selectorDrawableMaskType[1] = 2; commentButtonPressed = true; if (selectorDrawable[1] != null) { selectorDrawable[1].setHotspot(x, y); selectorDrawable[1].setState(pressedState); } invalidateWithParent(); } return true; } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (commentButtonPressed) { if (delegate != null) { if (isRepliesChat) { delegate.didPressSideButton(this); } else { delegate.didPressCommentButton(this); } } playSoundEffect(SoundEffectConstants.CLICK); if (selectorDrawable[1] != null) { selectorDrawable[1].setState(StateSet.NOTHING); } commentButtonPressed = false; invalidateWithParent(); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (commentButtonPressed && selectorDrawable[1] != null) { selectorDrawable[1].setHotspot(x, y); } } return false; } private boolean checkSponsoredCloseMotionEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN && closeSponsoredBounds != null && closeSponsoredBounce != null && closeSponsoredBounds.contains(getEventX(event), getEventY(event))) { closeSponsoredBounce.setPressed(true); return true; } else if (event.getAction() == MotionEvent.ACTION_UP) { if (closeSponsoredBounce != null && closeSponsoredBounce.isPressed()) { if (delegate != null) { delegate.didPressSponsoredClose(this); } } if (closeSponsoredBounce != null) { closeSponsoredBounce.setPressed(false); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { if (closeSponsoredBounce != null) { closeSponsoredBounce.setPressed(false); } } return closeSponsoredBounce != null && closeSponsoredBounce.isPressed(); } private boolean checkOtherButtonMotionEvent(MotionEvent event) { if ((documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) && currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { return false; } boolean allow = currentMessageObject.type == MessageObject.TYPE_PHONE_CALL; if (!allow) { allow = !( documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT && currentMessageObject.type != MessageObject.TYPE_CONTACT && documentAttachType != DOCUMENT_ATTACH_TYPE_MUSIC && documentAttachType != DOCUMENT_ATTACH_TYPE_VIDEO && documentAttachType != DOCUMENT_ATTACH_TYPE_GIF && currentMessageObject.type != MessageObject.TYPE_GIF || hasGamePreview || hasInvoicePreview ); } if (!allow) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); boolean result = false; if (event.getAction() == MotionEvent.ACTION_DOWN) { if (currentMessageObject.type == MessageObject.TYPE_PHONE_CALL) { int idx = currentMessageObject.isVideoCall() ? 1 : 0; if (x >= otherX && x <= otherX + (LocaleController.isRTL ? 0 : backgroundWidth - dp(70)) + dp(30 + (idx == 0 ? 2 : 0)) && y >= otherY - dp(14) && y <= otherY + dp(50)) { otherPressed = true; result = true; selectorDrawableMaskType[0] = 4; if (selectorDrawable[0] != null) { int cx = otherX + (LocaleController.isRTL ? 0 : backgroundWidth - dp(70)) + dp((idx == 0 ? 2 : 0)) + Theme.chat_msgInCallDrawable[idx].getIntrinsicWidth() / 2; int cy = otherY + Theme.chat_msgInCallDrawable[idx].getIntrinsicHeight() / 2; selectorDrawable[0].setBounds(cx - dp(20), cy - dp(20), cx + dp(20), cy + dp(20)); selectorDrawable[0].setHotspot(x, y); selectorDrawable[0].setState(pressedState); } invalidate(); } } else { if (x >= otherX - dp(20) && x <= otherX + dp(20) && y >= otherY - dp(4) && y <= otherY + dp(30)) { otherPressed = true; result = true; invalidate(); } } } else { if (event.getAction() == MotionEvent.ACTION_UP) { if (otherPressed) { if (currentMessageObject.type == MessageObject.TYPE_PHONE_CALL && selectorDrawable[0] != null) { selectorDrawable[0].setState(StateSet.NOTHING); } otherPressed = false; playSoundEffect(SoundEffectConstants.CLICK); delegate.didPressOther(this, otherX, otherY); invalidate(); result = true; } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (currentMessageObject.type == MessageObject.TYPE_PHONE_CALL && otherPressed && selectorDrawable[0] != null) { selectorDrawable[0].setHotspot(x, y); } } } return result; } private void setInstantButtonPressed(boolean pressed) { if (instantButtonBounce == null) { instantButtonBounce = new ButtonBounce(this); } instantButtonBounce.setPressed(instantButtonPressed = pressed); } private void resetContactButtonsPressedState() { contactPressed = false; if (contactBounce != null) { contactBounce.setPressed(false); } if (selectorDrawable[0] != null) { selectorDrawable[0].setState(StateSet.NOTHING); } if (contactButtons != null) { for (int i = 0; i < contactButtons.size(); i++) { InstantViewButton instantViewButton = contactButtons.get(i); if (instantViewButton.buttonBounce != null) { instantViewButton.buttonBounce.setPressed(false); } if (instantViewButton.selectorDrawable != null) { instantViewButton.selectorDrawable.setState(StateSet.NOTHING); } } } } private boolean checkDateMotionEvent(MotionEvent event) { if (!currentMessageObject.isImportedForward()) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); boolean result = false; if (event.getAction() == MotionEvent.ACTION_DOWN) { if (x >= drawTimeX && x <= drawTimeX + timeWidth && y >= drawTimeY && y <= drawTimeY + dp(20)) { timePressed = true; result = true; invalidate(); } } else { if (event.getAction() == MotionEvent.ACTION_UP) { if (timePressed) { timePressed = false; playSoundEffect(SoundEffectConstants.CLICK); delegate.didPressTime(this); invalidate(); result = true; } } } return result; } private boolean checkRoundSeekbar(MotionEvent event) { if (!MediaController.getInstance().isPlayingMessage(currentMessageObject) || !MediaController.getInstance().isMessagePaused()) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (x >= seekbarRoundX - dp(20) && x <= seekbarRoundX + dp(20) && y >= seekbarRoundY - dp(20) && y <= seekbarRoundY + dp(20)) { getParent().requestDisallowInterceptTouchEvent(true); cancelCheckLongPress(); roundSeekbarTouched = 1; invalidate(); } else { float localX = x - photoImage.getCenterX(); float localY = y - photoImage.getCenterY(); float r2 = (photoImage.getImageWidth() - dp(64)) / 2; if (localX * localX + localY * localY < photoImage.getImageWidth() / 2 * photoImage.getImageWidth() / 2 && localX * localX + localY * localY > r2 * r2) { getParent().requestDisallowInterceptTouchEvent(true); cancelCheckLongPress(); roundSeekbarTouched = 1; invalidate(); } } } else if (roundSeekbarTouched == 1 && event.getAction() == MotionEvent.ACTION_MOVE) { float localX = x - photoImage.getCenterX(); float localY = y - photoImage.getCenterY(); float a = (float) Math.toDegrees(Math.atan2(localY, localX)) + 90; if (a < 0) { a += 360; } float p = a / 360f; if (Math.abs(currentMessageObject.audioProgress - p) > 0.9f) { if (roundSeekbarOutAlpha == 0) { try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); } catch (Exception ignored) {} } roundSeekbarOutAlpha = 1f; roundSeekbarOutProgress = currentMessageObject.audioProgress; } long currentTime = System.currentTimeMillis(); if (currentTime - lastSeekUpdateTime > 100) { MediaController.getInstance().seekToProgress(currentMessageObject, p); lastSeekUpdateTime = currentTime; } currentMessageObject.audioProgress = p; updatePlayingMessageProgress(); } if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { if (roundSeekbarTouched != 0) { if (event.getAction() == MotionEvent.ACTION_UP) { float localX = x - photoImage.getCenterX(); float localY = y - photoImage.getCenterY(); float a = (float) Math.toDegrees(Math.atan2(localY, localX)) + 90; if (a < 0) { a += 360; } float p = a / 360f; currentMessageObject.audioProgress = p; MediaController.getInstance().seekToProgress(currentMessageObject, p); updatePlayingMessageProgress(); } MediaController.getInstance().playMessage(currentMessageObject); roundSeekbarTouched = 0; getParent().requestDisallowInterceptTouchEvent(false); } } return roundSeekbarTouched != 0; } private boolean checkPhotoImageMotionEvent(MotionEvent event) { if (!drawPhotoImage && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT || currentMessageObject.isSending() && buttonState != 1) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); boolean result = false; if (event.getAction() == MotionEvent.ACTION_DOWN) { boolean area2 = false; int side = dp(48); if (miniButtonState >= 0) { int offset = dp(27); area2 = x >= buttonX + offset && x <= buttonX + offset + side && y >= buttonY + offset && y <= buttonY + offset + side; } boolean allowClickButtons = currentMessageObject == null || !currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || buttonState == 1; if (area2) { miniButtonPressed = 1; invalidate(); result = true; } else if (buttonState != -1 && radialProgress.getIcon() != MediaActionDrawable.ICON_NONE && x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side && allowClickButtons) { buttonPressed = 1; invalidate(); result = true; } else if (drawVideoImageButton && buttonState != -1 && x >= videoButtonX && x <= videoButtonX + dp(26 + 8) + Math.max(infoWidth, docTitleWidth) && y >= videoButtonY && y <= videoButtonY + dp(30) && allowClickButtons) { videoButtonPressed = 1; invalidate(); result = true; } else { if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { if (x >= photoImage.getImageX() && x <= photoImage.getImageX() + backgroundWidth - dp(50) && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight()) { imagePressed = true; result = true; } } else if (!currentMessageObject.isAnyKindOfSticker() || currentMessageObject.getInputStickerSet() != null || currentMessageObject.isAnimatedEmoji() || currentMessageObject.isDice()) { if (x >= photoImage.getImageX() && x <= photoImage.getImageX() + photoImage.getImageWidth() && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight()) { if (isRoundVideo) { if ((x - photoImage.getCenterX()) * (x - photoImage.getCenterX()) + (y - photoImage.getCenterY()) * (y - photoImage.getCenterY()) < (photoImage.getImageWidth() / 2f) * (photoImage.getImageWidth() / 2)) { imagePressed = true; result = true; } } else { imagePressed = true; result = true; } } if (currentMessageObject.type == MessageObject.TYPE_CONTACT) { long uid = MessageObject.getMedia(currentMessageObject.messageOwner).user_id; TLRPC.User user = null; if (uid != 0) { user = MessagesController.getInstance(currentAccount).getUser(uid); } if (user == null) { imagePressed = false; result = false; } } } } if (imagePressed) { if (currentMessageObject.isSendError()) { imagePressed = false; result = false; } else if (currentMessageObject.type == MessageObject.TYPE_GIF && buttonState == -1 && SharedConfig.isAutoplayGifs() && !currentMessageObject.isRepostPreview && photoImage.getAnimation() == null) { imagePressed = false; result = false; } } } else { if (event.getAction() == MotionEvent.ACTION_UP) { if (videoButtonPressed == 1) { videoButtonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); didPressButton(true, true); invalidate(); } else if (buttonPressed == 1) { buttonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); if (drawVideoImageButton) { didClickedImage(); } else { didPressButton(true, false); } invalidate(); } else if (miniButtonPressed == 1) { miniButtonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); didPressMiniButton(true); invalidate(); } else if (imagePressed) { imagePressed = false; if (buttonState == -1 || buttonState == 1 && isRoundVideo || buttonState == 2 || buttonState == 3 || drawVideoImageButton) { playSoundEffect(SoundEffectConstants.CLICK); didClickedImage(); } else if (buttonState == 0) { playSoundEffect(SoundEffectConstants.CLICK); didPressButton(true, false); } invalidate(); } } } return result; } private boolean checkAudioMotionEvent(MotionEvent event) { if (documentAttachType != DOCUMENT_ATTACH_TYPE_AUDIO && documentAttachType != DOCUMENT_ATTACH_TYPE_MUSIC && (documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && !currentMessageObject.isVoiceTranscriptionOpen())) { return false; } if (AndroidUtilities.isAccessibilityScreenReaderEnabled()) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); boolean result; if (useSeekBarWaveform) { result = seekBarWaveform.onTouch(event.getAction(), getEventX(event) - seekBarX - dp(13), getEventY(event) - seekBarY); } else { if (MediaController.getInstance().isPlayingMessage(currentMessageObject) || currentMessageObject != null && documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject.isVoiceTranscriptionOpen()) { result = seekBar.onTouch(event.getAction(), getEventX(event) - seekBarX, getEventY(event) - seekBarY); } else { result = false; } } if (result) { if (!useSeekBarWaveform && event.getAction() == MotionEvent.ACTION_DOWN) { getParent().requestDisallowInterceptTouchEvent(true); } else if (useSeekBarWaveform && !seekBarWaveform.isStartDraging() && event.getAction() == MotionEvent.ACTION_UP) { didPressButton(true, false); } disallowLongPress = true; invalidate(); } else { int side = dp(36); boolean area = false; boolean area2 = false; if (miniButtonState >= 0) { int offset = dp(27); area2 = x >= buttonX + offset && x <= buttonX + offset + side && y >= buttonY + offset && y <= buttonY + offset + side; } if (!area2 && (currentMessageObject == null || !currentMessageObject.hasMediaSpoilers() || currentMessageObject.isVoice() || currentMessageObject.isMediaSpoilersRevealed)) { if (buttonState == 0 || buttonState == 1 || buttonState == 2) { area = x >= buttonX - dp(12) && x <= buttonX - dp(12) + backgroundWidth && y >= (drawInstantView ? buttonY : namesOffset + mediaOffsetY) && y <= (drawInstantView ? buttonY + side : namesOffset + mediaOffsetY + dp(82)); } else { area = x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side; } } if (event.getAction() == MotionEvent.ACTION_DOWN) { if (area || area2) { if (area) { buttonPressed = 1; } else { miniButtonPressed = 1; } invalidate(); result = true; } } else if (buttonPressed != 0) { if (event.getAction() == MotionEvent.ACTION_UP) { buttonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); didPressButton(true, false); invalidate(); } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { buttonPressed = 0; invalidate(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!area) { buttonPressed = 0; invalidate(); } } } else if (miniButtonPressed != 0) { if (event.getAction() == MotionEvent.ACTION_UP) { miniButtonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); didPressMiniButton(true); invalidate(); } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { miniButtonPressed = 0; invalidate(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!area2) { miniButtonPressed = 0; invalidate(); } } } } return result; } public boolean checkSpoilersMotionEvent(MotionEvent event, int n) { if (n > 15 || getParent() == null) { return false; } if (currentMessageObject.hasValidGroupId() && currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { ViewGroup parent = (ViewGroup) getParent(); for (int i = 0; i < parent.getChildCount(); i++) { View v = parent.getChildAt(i); if (v instanceof ChatMessageCell) { ChatMessageCell cell = (ChatMessageCell) v; MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); MessageObject.GroupedMessagePosition position = cell.getCurrentPosition(); if (group != null && group.groupId == currentMessagesGroup.groupId && (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (position.flags & MessageObject.POSITION_FLAG_LEFT) != 0) { if (cell != this) { event.offsetLocation(this.getLeft() - cell.getLeft(), this.getTop() - cell.getTop()); boolean result = cell.checkSpoilersMotionEvent(event, n + 1); event.offsetLocation(-(this.getLeft() - cell.getLeft()), -(this.getTop() - cell.getTop())); return result; } } } } } if (isSpoilerRevealing) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); int act = event.getActionMasked(); if (act == MotionEvent.ACTION_DOWN) { if (x >= textX && y >= textY && x <= textX + currentMessageObject.textWidth && y <= textY + currentMessageObject.textHeight(transitionParams)) { List blocks = currentMessageObject.textLayoutBlocks; for (int i = 0; i < blocks.size(); i++) { if (blocks.get(i).textYOffset(currentMessageObject.textLayoutBlocks, transitionParams) > y) { break; } MessageObject.TextLayoutBlock block = blocks.get(i); int offX = block.isRtl() ? (int) currentMessageObject.textXOffset : 0; for (SpoilerEffect eff : block.spoilers) { if (eff.getBounds().contains(x - textX + offX, (int) (y - textY - block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams)))) { spoilerPressed = eff; return true; } } } } if (captionLayout != null && x >= captionX && y >= captionY && x <= captionX + captionLayout.textWidth && y <= captionY + captionLayout.textHeight(transitionParams)) { List blocks = captionLayout.textLayoutBlocks; for (int i = 0; i < blocks.size(); i++) { if (blocks.get(i).textYOffset(captionLayout.textLayoutBlocks, transitionParams) > y) { break; } MessageObject.TextLayoutBlock block = blocks.get(i); int offX = block.isRtl() ? (int) captionLayout.textXOffset : 0; for (SpoilerEffect eff : block.spoilers) { if (eff.getBounds().contains((int) (x - captionX + offX), (int) (y - captionY - block.textYOffset(captionLayout.textLayoutBlocks, transitionParams)))) { spoilerPressed = eff; return true; } } } } if (explanationLayout != null && x >= lastDrawExplanationX && y > lastDrawExplanationY && x <= lastDrawExplanationX + explanationLayout.textWidth && y <= lastDrawExplanationY + explanationLayout.textHeight(transitionParams)) { final List blocks = explanationLayout.textLayoutBlocks; for (int i = 0; i < blocks.size(); i++) { if (blocks.get(i).textYOffset(explanationLayout.textLayoutBlocks, transitionParams) > y) { break; } MessageObject.TextLayoutBlock block = blocks.get(i); int offX = block.isRtl() ? (int) explanationLayout.textXOffset : 0; for (SpoilerEffect eff : block.spoilers) { if (eff.getBounds().contains((int) (x - lastDrawExplanationX + offX), (int) (y - lastDrawExplanationY - block.textYOffset(explanationLayout.textLayoutBlocks, transitionParams)))) { spoilerPressed = eff; return true; } } } } } else if (act == MotionEvent.ACTION_UP && spoilerPressed != null) { playSoundEffect(SoundEffectConstants.CLICK); sPath.rewind(); if (explanationLayout != null) { for (MessageObject.TextLayoutBlock block : explanationLayout.textLayoutBlocks) { for (SpoilerEffect eff : block.spoilers) { Rect b = eff.getBounds(); sPath.addRect(b.left, b.top + block.textYOffset(explanationLayout.textLayoutBlocks, transitionParams), b.right, b.bottom + block.textYOffset(explanationLayout.textLayoutBlocks, transitionParams), Path.Direction.CW); } } } if (captionLayout != null) { for (MessageObject.TextLayoutBlock block : captionLayout.textLayoutBlocks) { for (SpoilerEffect eff : block.spoilers) { Rect b = eff.getBounds(); sPath.addRect(b.left, b.top + block.textYOffset(captionLayout.textLayoutBlocks, transitionParams), b.right, b.bottom + block.textYOffset(captionLayout.textLayoutBlocks, transitionParams), Path.Direction.CW); } } } else if (currentMessageObject.textLayoutBlocks != null) { for (MessageObject.TextLayoutBlock block : currentMessageObject.textLayoutBlocks) { for (SpoilerEffect eff : block.spoilers) { Rect b = eff.getBounds(); sPath.addRect(b.left, b.top + block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams), b.right, b.bottom + block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams), Path.Direction.CW); } } } sPath.computeBounds(rect, false); float width = rect.width(), height = rect.height(); float rad = (float) Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); isSpoilerRevealing = true; spoilerPressed.setOnRippleEndCallback(() -> post(() -> { isSpoilerRevealing = false; getMessageObject().isSpoilersRevealed = true; if (explanationLayout != null) { for (MessageObject.TextLayoutBlock block : explanationLayout.textLayoutBlocks) { block.spoilers.clear(); } } if (captionLayout != null) { for (MessageObject.TextLayoutBlock block : captionLayout.textLayoutBlocks) { block.spoilers.clear(); } } else if (currentMessageObject.textLayoutBlocks != null) { for (MessageObject.TextLayoutBlock block : currentMessageObject.textLayoutBlocks) { block.spoilers.clear(); } } invalidate(); })); if (explanationLayout != null) { for (MessageObject.TextLayoutBlock block : explanationLayout.textLayoutBlocks) { int offX = block.isRtl() ? (int) explanationLayout.textXOffset : 0; for (SpoilerEffect eff : block.spoilers) { eff.startRipple(x - lastDrawExplanationX + offX, y - block.textYOffset(explanationLayout.textLayoutBlocks, transitionParams) - lastDrawExplanationY, rad); } } } if (captionLayout != null) { for (MessageObject.TextLayoutBlock block : captionLayout.textLayoutBlocks) { int offX = block.isRtl() ? (int) captionLayout.textXOffset : 0; for (SpoilerEffect eff : block.spoilers) { eff.startRipple(x - captionX + offX, y - block.textYOffset(captionLayout.textLayoutBlocks, transitionParams) - captionY, rad); } } } else if (currentMessageObject.textLayoutBlocks != null) { for (MessageObject.TextLayoutBlock block : currentMessageObject.textLayoutBlocks) { int offX = block.isRtl() ? (int) currentMessageObject.textXOffset : 0; for (SpoilerEffect eff : block.spoilers) { eff.startRipple(x - textX + offX, y - block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams) - textY, rad); } } } if (getParent() instanceof RecyclerListView) { ViewGroup vg = (ViewGroup) getParent(); for (int i = 0; i < vg.getChildCount(); i++) { View ch = vg.getChildAt(i); if (ch instanceof ChatMessageCell) { ChatMessageCell cell = (ChatMessageCell) ch; if (cell.getMessageObject() != null && cell.getMessageObject().getReplyMsgId() == getMessageObject().getId()) { if (!cell.replySpoilers.isEmpty()) { cell.replySpoilers.get(0).setOnRippleEndCallback(() -> post(() -> { cell.getMessageObject().replyMessageObject.isSpoilersRevealed = true; cell.replySpoilers.clear(); cell.invalidate(); })); for (SpoilerEffect eff : cell.replySpoilers) { eff.startRipple(eff.getBounds().centerX(), eff.getBounds().centerY(), rad); } } } } } } spoilerPressed = null; return true; } return false; } private boolean checkBotButtonMotionEvent(MotionEvent event) { if (botButtons.isEmpty()) { return false; } int x = (int) getEventX(event); int y = (int) getEventY(event); boolean result = false; if (event.getAction() == MotionEvent.ACTION_DOWN) { final int widthForButtons = getWidthForButtons(); int addX; if (currentMessageObject.isOutOwner()) { addX = getMeasuredWidth() - widthForButtons - dp(10); } else { addX = backgroundDrawableLeft + dp(mediaBackground ? 1 : 7); } for (int a = 0; a < botButtons.size(); a++) { BotButton button = botButtons.get(a); int y2 = button.y + layoutHeight - dp(2); if (x >= button.x * widthForButtons + addX && x <= button.x * widthForButtons + addX + button.width * widthForButtons && y >= y2 && y <= y2 + button.height) { pressedBotButton = a; invalidateOutbounds(); result = true; if (button.selectorDrawable == null) { button.selectorDrawable = Theme.createRadSelectorDrawable(getThemedColor(Theme.key_chat_serviceBackgroundSelector), 6, 6); button.selectorDrawable.setCallback(this); button.selectorDrawable.setBounds((int) (button.x * widthForButtons) + addX, y2, (int) (button.x * widthForButtons) + addX + (int) (button.width * widthForButtons), y2 + button.height); } button.selectorDrawable.setHotspot(x, y); button.selectorDrawable.setState(pressedState); button.setPressed(!button.isLocked); final int longPressedBotButton = pressedBotButton; postDelayed(() -> { if (longPressedBotButton == pressedBotButton) { BotButton button2 = botButtons.get(pressedBotButton); if (button2 != null) { if (button2.selectorDrawable != null) { button2.selectorDrawable.setState(StateSet.NOTHING); } button2.setPressed(false); if (!currentMessageObject.scheduled) { if (button2.buttonCustom != null) { cancelCheckLongPress(); if (delegate != null) { delegate.didLongPressCustomBotButton(this, button2.buttonCustom); } } else if (button2.button != null) { cancelCheckLongPress(); if (delegate != null) { delegate.didLongPressBotButton(this, button2.button); } } } } pressedBotButton = -1; invalidateOutbounds(); } }, ViewConfiguration.getLongPressTimeout() - 1); break; } } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (pressedBotButton != -1) { playSoundEffect(SoundEffectConstants.CLICK); BotButton button = botButtons.get(pressedBotButton); if (button.selectorDrawable != null) { button.selectorDrawable.setState(StateSet.NOTHING); } button.setPressed(false); if (currentMessageObject.scheduled) { Toast.makeText(getContext(), getString(R.string.MessageScheduledBotAction), Toast.LENGTH_LONG).show(); } else { if (delegate != null && !button.isLocked) { if (button.buttonCustom != null) { delegate.didPressCustomBotButton(this, button.buttonCustom); } else if (button.button != null) { delegate.didPressBotButton(this, button.button); } } } pressedBotButton = -1; invalidateOutbounds(); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { if (pressedBotButton != -1) { BotButton button = botButtons.get(pressedBotButton); if (button.selectorDrawable != null) { button.selectorDrawable.setState(StateSet.NOTHING); } button.setPressed(false); pressedBotButton = -1; invalidateOutbounds(); } } return result; } private boolean checkSummaryTouchEvent(MotionEvent event) { if (!drawSummaryReply || summaryTitle == null || summaryBounce == null || delegate == null) return false; float x = getEventX(event); float y = getEventY(event); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (summarySelectorRect.contains(x, y)) { summaryBounce.setPressed(true); if (summaryReplySelector != null) { summaryReplySelector.setHotspot(x, y); summaryReplySelector.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}); } } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (summaryBounce.isPressed() && !summarySelectorRect.contains(x, y)) { summaryBounce.setPressed(false); if (summaryReplySelector != null) { summaryReplySelector.setState(new int[]{}); } } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (summaryBounce.isPressed()) { delegate.didPressSummarize(this, true); } summaryBounce.setPressed(false); if (summaryReplySelector != null) { summaryReplySelector.setState(new int[]{}); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { summaryBounce.setPressed(false); if (summaryReplySelector != null) { summaryReplySelector.setState(new int[]{}); } } return summaryBounce.isPressed(); } private boolean checkAdminTouchEvent(MotionEvent event) { if (adminLayout == null || delegate == null || !delegate.canPerformActions()) return false; final boolean hit = adminLayoutRect.contains(event.getX(), event.getY()); if (adminLayoutBounce == null) adminLayoutBounce = new ButtonBounce(this); if (event.getAction() == MotionEvent.ACTION_DOWN) { adminLayoutBounce.setPressed(hit); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!hit) adminLayoutBounce.setPressed(false); } else if (event.getAction() == MotionEvent.ACTION_UP) { if (adminLayoutBounce.isPressed()) { delegate.didPressAdmin(this); } adminLayoutBounce.setPressed(false); } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { adminLayoutBounce.setPressed(false); } return adminLayoutBounce.isPressed(); } private boolean checkReplyTouchEvent(MotionEvent event) { if (replyNameLayout == null || delegate == null || !delegate.canPerformReply()) return false; float x = getEventX(event); float y = getEventY(event); int replyEnd; if (currentMessageObject.shouldDrawWithoutBackground()) { replyEnd = replyStartX + Math.max(replyNameWidth, replyTextWidth); } else { replyEnd = replyStartX + backgroundDrawableRight; } if (event.getAction() == MotionEvent.ACTION_DOWN) { if (x >= replyStartX && x <= replyEnd && y >= replyStartY && y <= replyStartY + replyHeight) { replyPressed = true; getParent().requestDisallowInterceptTouchEvent(false); replyTouchX = x; replyTouchY = y + getY(); if (replySelector != null) { replySelector.setHotspot(x, y); replySelectorPressed = false; replySelectorCanBePressed = true; postDelayed(() -> { if (replyPressed && !replySelectorPressed && replySelectorCanBePressed) { replySelectorPressed = true; replySelector.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}); } }, ViewConfiguration.getTapTimeout() / 6); invalidate(); } if (replyBounce != null) { replyBounce.setPressed(true); replyBounceX = x; replyBounceY = y; } startCheckLongPress(); return true; } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (replyPressed) { cancelCheckLongPress(); replyPressed = false; if (replySelector != null) { if (!replySelectorPressed) { replySelector.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}); post(() -> { replySelector.setState(new int[]{}); invalidate(); }); } else { replySelector.setState(new int[]{}); } replySelectorPressed = false; replySelectorCanBePressed = false; invalidate(); } if (replyBounce != null) { replyBounce.setPressed(false); } playSoundEffect(SoundEffectConstants.CLICK); if (replyPanelIsForward) { if (delegate != null) { if (currentForwardChannel != null) { delegate.didPressChannelAvatar(this, currentForwardChannel, currentMessageObject.messageOwner.fwd_from.channel_post, lastTouchX, lastTouchY, false); } else if (currentForwardUser != null) { delegate.didPressUserAvatar(this, currentForwardUser, lastTouchX, lastTouchY, false); } else if (currentForwardName != null) { delegate.didPressHiddenForward(this); } } } else { if (delegate != null && (currentMessageObject.hasValidReplyMessageObject() || currentMessageObject.isReplyToStory() || hasReplyQuote || currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.reply_to != null && currentMessageObject.messageOwner.reply_to.reply_from != null)) { delegate.didPressReplyMessage(this, currentMessageObject.getReplyMsgId(), x, y, false); } } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { replyPressed = false; replySelectorPressed = false; if (replySelector != null) { replySelector.setState(new int[]{}); } invalidate(); if (replyBounce != null) { replyBounce.setPressed(false); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!(x >= replyStartX && x <= replyEnd && y >= replyStartY && y <= replyStartY + replyHeight)) { replyPressed = false; replySelectorPressed = false; replySelectorCanBePressed = false; if (replySelector != null) { replySelector.setState(new int[]{}); } invalidate(); if (replyBounce != null) { replyBounce.setPressed(false); } } else if (replySelector != null && replySelectorCanBePressed && Math.sqrt(Math.pow(x - replyTouchX, 2) + Math.pow((y + getY()) - replyTouchY, 2)) > 0.75f) { replySelectorCanBePressed = false; } } return replyPressed; } @Override public boolean onTouchEvent(MotionEvent event) { if (currentMessageObject == null || delegate != null && !delegate.canPerformActions() || animationRunning) { if (currentMessageObject != null && currentMessageObject.preview) { return checkTextSelection(event); } else { boolean r_reply = checkReplyTouchEvent(event); boolean r_text = r_reply || checkTextSelection(event); return r_reply || super.onTouchEvent(event); } } if (checkTextSelection(event)) { return true; } if (checkRoundSeekbar(event)) { return true; } if (checkReactionsTouchEvent(event)) { return true; } if (videoPlayerRewinder != null && videoPlayerRewinder.rewindCount > 0) { if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { getParent().requestDisallowInterceptTouchEvent(false); videoPlayerRewinder.cancelRewind(); return false; } return true; } disallowLongPress = false; lastTouchX = getEventX(event); lastTouchY = getEventY(event); backgroundDrawable.setTouchCoords(lastTouchX, lastTouchY); boolean result = checkSpoilersMotionEvent(event, 0); if (!result) { result = checkTextBlockMotionEvent(event); } if (!result) { result = checkRichLayoutMotionEvent(event); } if (currentMessageObject != null && currentMessageObject.richLayout != null && (currentMessageObject.richLayout.isHorizontallyDragging() || currentMessageObject.richLayout.isPressingLink())) { disallowLongPress = true; cancelCheckLongPress(); } if (!result && channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { result = channelRecommendationsCell.checkTouchEvent(event); if (result) { disallowLongPress = true; } } if (!result) { result = checkQuickShareMotionEvent(event); } if(!result) { result = checkAdminMotionEvent(event); } if (!result) { result = checkNameMotionEvent(event); } if (!result) { result = checkNameStatusMotionEvent(event); } if (!result) { result = checkPinchToZoom(event); } if (!result) { result = checkDateMotionEvent(event); } if (!result) { result = checkTextSelection(event); } if (!result && topicButton != null) { result = topicButton.onTouchEvent(event); } if (!result && topicSeparator != null) { result = topicSeparator.onTouchEvent(event, true); } if (!result) { result = checkOtherButtonMotionEvent(event); } if (!result) { result = checkSponsoredCloseMotionEvent(event); } if (!result) { result = checkCaptionMotionEvent(event); } if (!result) { result = checkExplanationMotionEvent(event); } if (!result) { result = checkTranscribeButtonMotionEvent(event); } if (!result) { result = checkAudioMotionEvent(event); } if (!result) { result = checkTitleLabelMotion(event); } if (!result) { result = checkContactMotionEvent(event); } if (!result) { result = checkLinkPreviewMotionEvent(event); } if (!result) { result = checkInstantButtonMotionEvent(event); } if (!result) { result = checkCommentButtonMotionEvent(event); } if (!result) { result = checkGameMotionEvent(event); } if (!result) { result = checkEffectMotionEvent(event); } if (!result) { result = checkPhotoImageMotionEvent(event); } if (!result) { result = checkBotButtonMotionEvent(event); } if (!result) { result = checkPollMediaMotionEvent(event); } if (!result) { result = checkPollButtonMotionEvent(event); } if (!result) { result = giveawayMessageCell.checkMotionEvent(event); } if (!result) { result = giveawayResultsMessageCell.checkMotionEvent(event); } if (!result) { result = checkFactCheckMotionEvent(event); } if (!result && groupMedia != null) { result = groupMedia.onTouchEvent(event); } if (!result) { result = checkReplyTouchEvent(event); } if (!result) { result = checkSummaryTouchEvent(event); } if (!result) { result = checkAdminTouchEvent(event); } if (event.getAction() == MotionEvent.ACTION_CANCEL) { spoilerPressed = null; buttonPressed = 0; miniButtonPressed = 0; pressedBotButton = -1; pressedVoteButton = -1; pollMediaPressedIndex = PollAttachedMediaPack.INDEX_NONE; pollHintPressed = false; pollAddButtonPressed = -1; closeExplanationPressed = false; psaHintPressed = false; linkPreviewPressed = false; otherPressed = false; sideButtonPressed = false; summarizeButtonPressed = false; pressedSideButton = 0; imagePressed = false; timePressed = false; gamePreviewPressed = false; instantPressed = commentButtonPressed = false; setInstantButtonPressed(false); resetContactButtonsPressedState(); if (titleLabelBounce != null) { titleLabelBounce.setPressed(false); } for (int a = 0; a < selectorDrawable.length; a++) { if (selectorDrawable[a] != null) { selectorDrawable[a].setState(StateSet.NOTHING); } } if (linkPreviewSelector != null) { linkPreviewSelector.setState(StateSet.NOTHING); } if (nameStatusSelector != null) { nameStatusSelector.setState(StateSet.NOTHING); } if (nameLayoutSelector != null) { nameLayoutSelector.setState(StateSet.NOTHING); } resetCodeSelectors(); if (linkPreviewBounce != null) { linkPreviewBounce.setPressed(false); } result = false; if (hadLongPress) { if (pressedLinkType != 2) { hadLongPress = false; } pressedLink = null; pressedFactCheckLink = null; pressedEmoji = null; pressedLinkType = -1; } else { resetPressedLink(-1); } } updateRadialProgressBackground(); if (!disallowLongPress && result && event.getAction() == MotionEvent.ACTION_DOWN) { startCheckLongPress(); } if (event.getAction() != MotionEvent.ACTION_DOWN && event.getAction() != MotionEvent.ACTION_MOVE) { cancelCheckLongPress(); } if (!result) { final float x = getEventX(event); final float y = getEventY(event); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (delegate == null || delegate.canPerformActions()) { if (isAvatarVisible && avatarImage.isInsideImage(x, y + getTop())) { avatarPressed = true; result = true; } else if (psaButtonVisible && hasPsaHint && x >= psaHelpX && x <= psaHelpX + dp(40) && y >= psaHelpY && y <= psaHelpY + dp(40)) { psaHintPressed = true; createSelectorDrawable(0); selectorDrawableMaskType[0] = 3; if (selectorDrawable[0] != null) { selectorDrawable[0].setBounds(psaHelpX - dp(8), psaHelpY - dp(8), psaHelpX + dp(32), psaHelpY + dp(32)); selectorDrawable[0].setHotspot(x, y); selectorDrawable[0].setState(pressedState); } result = true; invalidate(); } else if (drawForwardedName && forwardedNameLayout[0] != null && x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + forwardHeight) { if (viaWidth != 0 && x >= forwardNameX + viaNameWidth + dp(4)) { forwardBotPressed = true; } else { if (forwardBg != null) { forwardBg.setPressed(true); } forwardNamePressed = true; } result = true; } else if (drawNameLayout && nameLayout != null && viaWidth != 0 && x >= nameX + viaNameWidth && x <= nameX + viaNameWidth + viaWidth && y >= nameY - dp(4) && y <= nameY + dp(20)) { forwardBotPressed = true; result = true; } else if ( sideButtonVisible && drawSideButton != 0 && x >= sideStartX - dp(24) && x <= sideStartX + dp(40) && y >= sideStartY - dp(drawSummarizeButton ? 6 : 24) && y <= sideStartY + dp(38 + (drawSideButton == 3 && commentLayout != null ? 18 : 0) + (drawSideButton2 == SIDE_BUTTON_SPONSORED_MORE ? 38 : 0)) ) { if (currentMessageObject.isSent()) { if (currentMessageObject.isSponsored()) { if (y > sideStartY + dp(32) && drawSideButton2 == SIDE_BUTTON_SPONSORED_MORE) { pressedSideButton = SIDE_BUTTON_SPONSORED_MORE; } else { pressedSideButton = SIDE_BUTTON_SPONSORED_CLOSE; } } else { pressedSideButton = drawSideButton; } sideButtonPressed = true; } result = true; invalidate(); } else if ( sideButtonVisible && drawSummarizeButton && x >= summarizeButtonX - dp(4) && x <= summarizeButtonX + dp(40) && y >= summarizeButtonY - dp(4) && y <= summarizeButtonY + dp(40) ) { summarizeButtonPressed = true; result = true; invalidate(); } if (result) { startCheckLongPress(); } } } else { if (event.getAction() != MotionEvent.ACTION_MOVE) { cancelCheckLongPress(); } if (avatarPressed) { if (event.getAction() == MotionEvent.ACTION_UP) { avatarPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { if (currentUser != null) { if (currentUser.id == 0) { delegate.didPressHiddenForward(this); } else { delegate.didPressUserAvatar(this, currentUser, lastTouchX, lastTouchY, false); } } else if (currentChat != null) { int id; TLRPC.Chat chat = currentChat; if (currentMessageObject.messageOwner.fwd_from != null) { if ((currentMessageObject.messageOwner.fwd_from.flags & 16) != 0) { id = currentMessageObject.messageOwner.fwd_from.saved_from_msg_id; } else { id = currentMessageObject.messageOwner.fwd_from.channel_post; chat = currentForwardChannel; } } else { id = 0; } delegate.didPressChannelAvatar(this, chat != null ? chat : currentChat, id, lastTouchX, lastTouchY, false); } else if (currentMessageObject != null) { delegate.didPressInstantButton(this, drawInstantViewType); } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { avatarPressed = false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (isAvatarVisible && !avatarImage.isInsideImage(x, y + getTop())) { avatarPressed = false; } } } else if (psaHintPressed) { if (event.getAction() == MotionEvent.ACTION_UP) { playSoundEffect(SoundEffectConstants.CLICK); delegate.didPressHint(this, 1); psaHintPressed = false; if (selectorDrawable[0] != null) { selectorDrawable[0].setState(StateSet.NOTHING); } invalidate(); } } else if (forwardNamePressed) { if (event.getAction() == MotionEvent.ACTION_UP) { forwardNamePressed = false; if (forwardBg != null) { forwardBg.setPressed(false); } playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { if (currentForwardChannel != null) { int postId = 0; if (currentMessageObject.messageOwner.fwd_from != null) { postId = currentMessageObject.messageOwner.fwd_from.channel_post; } delegate.didPressChannelAvatar(this, currentForwardChannel, postId, lastTouchX, lastTouchY, true); } else if (currentForwardUser != null) { delegate.didPressUserAvatar(this, currentForwardUser, lastTouchX, lastTouchY, true); } else if (currentForwardName != null) { delegate.didPressHiddenForward(this); } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { forwardNamePressed = false; if (forwardBg != null) { forwardBg.setPressed(false); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!(x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + forwardHeight)) { forwardNamePressed = false; if (forwardBg != null) { forwardBg.setPressed(false); } } } } else if (forwardBotPressed) { if (event.getAction() == MotionEvent.ACTION_UP) { forwardBotPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { if (currentViaBotUser != null && currentViaBotUser.bot_inline_placeholder == null) { delegate.didPressViaBotNotInline(this, currentViaBotUser != null ? currentViaBotUser.id : 0); } else { String username = UserObject.getPublicUsername(currentViaBotUser); delegate.didPressViaBot(this, username != null ? username : currentMessageObject.messageOwner.via_bot_name); } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { forwardBotPressed = false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (drawForwardedName && forwardedNameLayout[0] != null) { if (!(x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + forwardHeight)) { forwardBotPressed = false; } } else { if (!(x >= nameX + viaNameWidth && x <= nameX + viaNameWidth + viaWidth && y >= nameY - dp(4) && y <= nameY + dp(20))) { forwardBotPressed = false; } } } } else if (sideButtonPressed) { if (event.getAction() == MotionEvent.ACTION_UP) { playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { if (pressedSideButton == SIDE_BUTTON_SPONSORED_CLOSE) { delegate.didPressSponsoredClose(this); } else if (pressedSideButton == SIDE_BUTTON_SPONSORED_MORE) { delegate.didPressSponsoredInfo(this, x, y); } else if (pressedSideButton == 3) { delegate.didPressCommentButton(this); } else { delegate.didPressSideButton(this); } } sideButtonPressed = false; summarizeButtonPressed = false; pressedSideButton = 0; } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { sideButtonPressed = false; summarizeButtonPressed = false; pressedSideButton = 0; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!( sideButtonVisible && x >= sideStartX - dp(24) && x <= sideStartX + dp(40) && y >= sideStartY - dp(drawSummarizeButton ? 6 : 24) && y <= sideStartY + dp(38 + (drawSideButton == 3 && commentLayout != null ? 18 : 0) + (drawSideButton2 == SIDE_BUTTON_SPONSORED_MORE ? 38 : 0)) )) { sideButtonPressed = false; pressedSideButton = 0; } } invalidate(); } else if (summarizeButtonPressed) { if (event.getAction() == MotionEvent.ACTION_UP) { playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { delegate.didPressSummarize(this, false); } sideButtonPressed = false; summarizeButtonPressed = false; pressedSideButton = 0; } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { sideButtonPressed = false; summarizeButtonPressed = false; pressedSideButton = 0; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!( sideButtonVisible && x >= summarizeButtonX - dp(4) && x <= summarizeButtonX + dp(40) && y >= summarizeButtonY - dp(4) && y <= summarizeButtonY + dp(40) )) { sideButtonPressed = false; summarizeButtonPressed = false; pressedSideButton = 0; } } invalidate(); } } } return result; } private boolean checkReactionsTouchEvent(MotionEvent event) { if (currentMessageObject.hasValidGroupId() && currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { ViewGroup parent = (ViewGroup) getParent(); if (parent == null) { return false; } for (int i = 0; i < parent.getChildCount(); i++) { View v = parent.getChildAt(i); if (v instanceof ChatMessageCell) { ChatMessageCell cell = (ChatMessageCell) v; MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); MessageObject.GroupedMessagePosition position = cell.getCurrentPosition(); if (group != null && group.groupId == currentMessagesGroup.groupId && (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (position.flags & MessageObject.POSITION_FLAG_LEFT) != 0) { if (cell == this) { return reactionsLayoutInBubble.checkTouchEvent(event); } else { event.offsetLocation(this.getLeft() - cell.getLeft(), this.getTop() - cell.getTop()); boolean result = cell.reactionsLayoutInBubble.checkTouchEvent(event); event.offsetLocation(-(this.getLeft() - cell.getLeft()), -(this.getTop() - cell.getTop())); return result; } } } } return false; } return reactionsLayoutInBubble.checkTouchEvent(event); } private boolean checkPinchToZoom(MotionEvent ev) { PinchToZoomHelper pinchToZoomHelper = delegate == null ? null : delegate.getPinchToZoomHelper(); if (currentMessageObject == null || !photoImage.hasNotThumb() || pinchToZoomHelper == null || currentMessageObject.isSticker() || currentMessageObject.isAnimatedEmoji() || (currentMessageObject.isVideo() && !autoPlayingMedia) || isRoundVideo || currentMessageObject.isAnimatedSticker() || (currentMessageObject.isDocument() && !currentMessageObject.isGif()) || currentMessageObject.needDrawBluredPreview()) { return false; } return pinchToZoomHelper.checkPinchToZoom(ev, this, photoImage, null, null, currentMessageObject, mediaSpoilerEffect2 == null ? 0 : mediaSpoilerEffect2.getAttachIndex(this)); } private boolean checkTextSelection(MotionEvent event) { if (delegate == null) return false; TextSelectionHelper.ChatListTextSelectionHelper textSelectionHelper = delegate.getTextSelectionHelper(); if (textSelectionHelper == null || textSelectionHelper.isMenuEmpty()) { return false; } boolean hasTextBlocks = currentMessageObject.textLayoutBlocks != null && !currentMessageObject.textLayoutBlocks.isEmpty(); boolean hasRichLayout = currentMessageObject.richLayout != null && !currentMessageObject.richLayout.textBlocks.isEmpty(); if (!hasTextBlocks && !hasCaptionLayout() && !hasRichLayout) { return false; } if ((!drawSelectionBackground && currentMessagesGroup == null) || (currentMessagesGroup != null && !delegate.hasSelectedMessages())) { return false; } if (currentMessageObject.hasValidGroupId() && currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { ViewGroup parent = (ViewGroup) getParent(); if (parent == null) { return false; } for (int i = 0; i < parent.getChildCount(); i++) { View v = parent.getChildAt(i); if (v instanceof ChatMessageCell) { ChatMessageCell cell = (ChatMessageCell) v; MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); MessageObject.GroupedMessagePosition position = cell.getCurrentPosition(); if (group != null && group.groupId == currentMessagesGroup.groupId && (position.flags & captionFlag()) != 0 && (position.flags & MessageObject.POSITION_FLAG_LEFT) != 0) { textSelectionHelper.setMaybeTextCord((int) cell.captionX, (int) cell.captionY); textSelectionHelper.setMessageObject(cell); if (cell == this) { return textSelectionHelper.onTouchEvent(event); } else { event.offsetLocation(this.getLeft() - cell.getLeft(), this.getTop() - cell.getTop()); boolean result = textSelectionHelper.onTouchEvent(event); event.offsetLocation(-(this.getLeft() - cell.getLeft()), -(this.getTop() - cell.getTop())); return result; } } } } return false; } else { if ((currentMessageObject != null && !currentMessageObject.preview) && factCheckTextLayout != null && getEventY(event) >= factCheckY) { textSelectionHelper.setIsDescription(false); textSelectionHelper.setIsFactCheck(true); textSelectionHelper.setIsRich(false); int x, y; if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { x = (int) captionX; } else if (currentMessageObject.isOutOwner()) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { x -= Math.max(0, x + Math.max(replyNameWidth, replyTextWidth) + dp(14) - AndroidUtilities.displaySize.x); } } else { if (mediaBackground) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { x = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } x += transitionParams.deltaLeft; x -= dp(1.33f); y = this.factCheckY; textSelectionHelper.setMaybeTextCord(x + dp(10) - factCheckTextLayoutLeft, y + dp(22)); } else if (hasCaptionLayout()) { textSelectionHelper.setIsDescription(false); textSelectionHelper.setIsFactCheck(false); textSelectionHelper.setIsRich(false); textSelectionHelper.setMaybeTextCord((int) captionX, (int) captionY); } else if ((currentMessageObject != null && !currentMessageObject.preview) && descriptionLayout != null && (linkPreviewAbove ? getEventY(event) < textY : getEventY(event) > descriptionY)) { textSelectionHelper.setIsDescription(true); textSelectionHelper.setIsFactCheck(false); textSelectionHelper.setIsRich(false); int linkX; if (hasGamePreview) { linkX = unmovedTextX - dp(10); } else if (hasInvoicePreview) { linkX = unmovedTextX + dp(1); } else { linkX = unmovedTextX + dp(1); } textSelectionHelper.setMaybeTextCord(linkX + dp(10) + descriptionX, descriptionY); } else if (hasRichLayout) { textSelectionHelper.setIsDescription(false); textSelectionHelper.setIsFactCheck(false); textSelectionHelper.setIsRich(true); textSelectionHelper.setMaybeTextCord(textX, textY); } else { textSelectionHelper.setIsDescription(false); textSelectionHelper.setIsFactCheck(false); textSelectionHelper.setIsRich(false); textSelectionHelper.setMaybeTextCord(textX, textY); } textSelectionHelper.setMessageObject(this); } return textSelectionHelper.onTouchEvent(event); } private void updateSelectionTextPosition() { if (getDelegate() != null && getDelegate().getTextSelectionHelper() != null && getDelegate().getTextSelectionHelper().isSelected(currentMessageObject)) { int textSelectionType = getDelegate().getTextSelectionHelper().getTextSelectionType(this); if (textSelectionType == TextSelectionHelper.ChatListTextSelectionHelper.TYPE_DESCRIPTION) { int linkX; if (hasGamePreview) { linkX = unmovedTextX - dp(10); } else if (hasInvoicePreview) { linkX = unmovedTextX + dp(1); } else { linkX = unmovedTextX + dp(1); } getDelegate().getTextSelectionHelper().updateTextPosition(linkX + dp(10) + descriptionX, descriptionY); } else if (textSelectionType == TextSelectionHelper.ChatListTextSelectionHelper.TYPE_CAPTION) { updateCaptionLayout(); getDelegate().getTextSelectionHelper().updateTextPosition((int) captionX, (int) captionY); } else if (textSelectionType == TextSelectionHelper.ChatListTextSelectionHelper.TYPE_FACTCHECK) { int x, y; if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { x = (int) captionX; } else if (currentMessageObject.isOutOwner()) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { x -= Math.max(0, x + Math.max(replyNameWidth, replyTextWidth) + dp(14) - AndroidUtilities.displaySize.x); } } else { if (mediaBackground) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { x = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } x += transitionParams.deltaLeft; x -= dp(1.33f); y = this.factCheckY; updateCaptionLayout(); getDelegate().getTextSelectionHelper().updateTextPosition(x + dp(10) - factCheckTextLayoutLeft, y + dp(22)); } else { getDelegate().getTextSelectionHelper().updateTextPosition(textX, textY); } } } public ArrayList getPollButtons() { return pollButtons; } public void toggleTodoCheck(int index, boolean vibrate) { if (index < 0 || index >= pollButtons.size()) return; final PollButton button = pollButtons.get(index); if (delegate.didPressToDoButton(this, button.task, !button.chosen)) { try { if (vibrate) performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignored) {} final long dialogId = currentMessageObject.getDialogId(); final long send_as = ChatObject.getSendAsPeerId(MessagesController.getInstance(currentAccount).getChat(dialogId), MessagesController.getInstance(currentAccount).getChatFull(dialogId), true); final TLRPC.TL_messageMediaToDo media = (TLRPC.TL_messageMediaToDo) MessageObject.getMedia(currentMessageObject); MessageObject.toggleTodo(currentAccount, send_as, media, button.task.id, !button.chosen, ConnectionsManager.getInstance(currentAccount).getCurrentTime()); if (!button.chosen) { final TLObject obj = MessagesController.getInstance(currentAccount).getUserOrChat(send_as); button.avatarDrawable.setInfo(obj); button.avatarImageReceiver.setForUserOrChat(obj, button.avatarDrawable); button.author = new Text(DialogObject.getName(obj), 12); } pollCheckBox[index].setChecked(!button.chosen, true); if (animatedInfoLayout != null) { if (!currentMessageObject.isOutOwner() && currentMessageObject.getDialogId() >= 0 && !media.todo.others_can_complete) { final String by = DialogObject.getName(currentMessageObject.getFromChatId()); animatedInfoLayout.setText(formatPluralStringComma("TodoCompletedBy", media.todo.list.size(), MessageObject.getCompletionsCount(media), by)); } else { animatedInfoLayout.setText(formatPluralStringComma("TodoCompleted", media.todo.list.size(), MessageObject.getCompletionsCount(media))); } } button.chosen = !button.chosen; invalidate(); } else { pollVoteInProgress = false; } } public void syncTodoCheck(int index, ChatMessageCell from) { if (pollCheckBox == null || index < 0 || index >= pollCheckBox.length || pollCheckBox[index] == null) return; if (from == null || from.pollCheckBox == null || index < 0 || index >= from.pollCheckBox.length || from.pollCheckBox[index] == null) return; final CheckBoxBase fromCheckBox = from.pollCheckBox[index]; final CheckBoxBase toCheckBox = pollCheckBox[index]; toCheckBox.cancelCheckAnimator(); toCheckBox.setProgress(fromCheckBox.getProgress()); toCheckBox.setChecked(fromCheckBox.isChecked(), true); } public void updatePlayingMessageProgress() { if (currentMessageObject == null) { return; } if (videoPlayerRewinder != null && videoPlayerRewinder.rewindCount != 0 && videoPlayerRewinder.rewindByBackSeek) { currentMessageObject.audioProgress = videoPlayerRewinder.getVideoProgress(); } if (currentMessageObject.isPoll()) { if (pollContentDrawable != null) { pollContentDrawable.updatePlayingMessageProgress(); } if (pollExplanationDrawable != null) { pollExplanationDrawable.updatePlayingMessageProgress(); } } if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { if (seekBar != null) { seekBar.clearTimestamps(); } if (infoLayout != null && (PhotoViewer.isPlayingMessage(currentMessageObject) || MediaController.getInstance().isGoingToShowMessageObject(currentMessageObject))) { return; } double duration = 0; AnimatedFileDrawable animation = photoImage.getAnimation(); if (animation != null) { duration = currentMessageObject.audioPlayerDuration = animation.getDurationMs() / 1000; if (currentMessageObject.messageOwner.ttl > 0 && currentMessageObject.messageOwner.destroyTime == 0 && !currentMessageObject.needDrawBluredPreview() && currentMessageObject.isVideo() && animation.hasBitmap()) { delegate.didStartVideoStream(currentMessageObject); } } if (duration == 0) { duration = currentMessageObject.getDuration(); } if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { duration -= duration * currentMessageObject.audioProgress; } else if (animation != null) { if (duration != 0) { duration -= animation.getCurrentProgressMs() / 1000; } if (delegate != null && animation.getCurrentProgressMs() >= 3000) { delegate.videoTimerReached(); } } if (lastTime != duration) { String str = AndroidUtilities.formatShortDuration((int) duration); infoWidth = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); infoLayout = new StaticLayout(str, Theme.chat_infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); lastTime = duration; } } else if (isRoundVideo) { if (useSeekBarWaveform) { if (!seekBarWaveform.isDragging()) { seekBarWaveform.setProgress(currentMessageObject.audioProgress, true); } } else { if (!seekBar.isDragging()) { seekBar.setProgress(currentMessageObject.audioProgress); seekBar.setBufferedProgress(currentMessageObject.bufferedProgress); } seekBar.clearTimestamps(); } double duration = 0; TLRPC.Document document = currentMessageObject.getDocument(); if (document != null) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeVideo) { duration = attribute.duration; break; } } } if (overridenDuration >= 0) { duration = overridenDuration; } else if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { duration = Math.max(0, duration - currentMessageObject.audioProgressSec); } if (lastTime != duration) { lastTime = duration; String timeString = AndroidUtilities.formatLongDuration((int) duration); timeWidthAudio = (int) Math.ceil(Theme.chat_timePaint.measureText(timeString)); durationLayout = new StaticLayout(timeString, Theme.chat_timePaint, timeWidthAudio, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } if (currentMessageObject.audioProgress != 0) { lastDrawingAudioProgress = currentMessageObject.audioProgress; if (lastDrawingAudioProgress > 0.9f) { lastDrawingAudioProgress = 1f; } } invalidate(); } else if (documentAttach != null) { boolean needInvalidate = false; if (useSeekBarWaveform) { if (!seekBarWaveform.isDragging()) { seekBarWaveform.setProgress(currentMessageObject.audioProgress, true); } needInvalidate = true; } else { if (!seekBar.isDragging()) { seekBar.setProgress(currentMessageObject.audioProgress); seekBar.setBufferedProgress(currentMessageObject.bufferedProgress); } seekBar.updateTimestamps(currentMessageObject, null); } double duration = 0; if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { needInvalidate = true; } if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { if (overridenDuration >= 0) { duration = overridenDuration; } else if (!MediaController.getInstance().isPlayingMessage(currentMessageObject)) { for (int a = 0; a < documentAttach.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeAudio) { duration = attribute.duration; break; } } } else { duration = currentMessageObject.audioProgressSec; } if (lastTime != duration) { lastTime = duration; String timeString = AndroidUtilities.formatLongDuration((int) duration); timeWidthAudio = (int) Math.ceil(Theme.chat_audioTimePaint.measureText(timeString)); durationLayout = new StaticLayout(timeString, Theme.chat_audioTimePaint, timeWidthAudio, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } needInvalidate = true; } else { int currentProgress = 0; duration = currentMessageObject.getDuration(); if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { currentProgress = currentMessageObject.audioProgressSec; } if (lastTime != currentProgress) { lastTime = currentProgress; String timeString = AndroidUtilities.formatShortDuration(currentProgress, (int) duration); int timeWidth = (int) Math.ceil(Theme.chat_audioTimePaint.measureText(timeString)); durationLayout = new StaticLayout(timeString, Theme.chat_audioTimePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } } if (needInvalidate) { invalidate(); } } } private long overridenDuration = -1; public void overrideDuration(long duration) { overridenDuration = duration; } public void setFullyDraw(boolean draw) { fullyDraw = draw; } public void setParentViewSize(int parentW, int parentH) { parentWidth = parentW; parentHeight = parentH; backgroundHeight = parentH; if (currentMessageObject != null && (hasGradientService() && currentMessageObject.shouldDrawWithoutBackground()) || currentBackgroundDrawable != null && currentBackgroundDrawable.getGradientShader() != null) { invalidate(); } } public void copyVisiblePartTo(ChatMessageCell cell) { if (cell == null) return; cell.setVisiblePart(childPosition, visibleHeight, visibleParent, visibleParentOffset, visibleTop, parentWidth, parentHeight, blurredViewTopOffset, blurredViewBottomOffset, childPosition2); } public void copyParamsTo(ChatMessageCell cell) { if (cell == null) return; cell.isChat = isChat; cell.isReportChat = isReportChat; cell.isSavedChat = isSavedChat; cell.isSavedPreviewChat = isSavedPreviewChat; cell.isBot = isBot; cell.isMegagroup = isMegagroup; cell.isForum = isForum; cell.isMonoForum = isMonoForum; cell.isForumGeneral = isForumGeneral; cell.isThreadChat = isThreadChat; cell.hasDiscussion = hasDiscussion; cell.isPinned = isPinned; cell.linkedChatId = linkedChatId; cell.isRepliesChat = isRepliesChat; cell.isPinnedChat = isPinnedChat; cell.isAllChats = isAllChats; cell.isSideMenued = isSideMenued; cell.isSideMenuEnabled = isSideMenuEnabled; cell.sideMenuAlpha = sideMenuAlpha; cell.sideMenuWidth = sideMenuWidth; } public int childPosition; public int childPosition2; public int visibleHeight; public int visibleParent; public float visibleParentOffset; public float visibleTop; public void setVisiblePart( int position, int height, int parent, float parentOffset, float visibleTop, int parentW, int parentH, int blurredViewTopOffset, int blurredViewBottomOffset, int position2 ) { this.childPosition = position; this.visibleHeight = height; this.visibleParent = parent; this.parentWidth = parentW; this.parentHeight = parentH; this.visibleTop = visibleTop; this.visibleParentOffset = parentOffset; this.backgroundHeight = parentH; this.blurredViewTopOffset = blurredViewTopOffset; this.blurredViewBottomOffset = blurredViewBottomOffset; this.childPosition2 = position2; if ((!botButtons.isEmpty() || channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) && viewTop != visibleTop) { invalidate(); } viewTop = visibleTop; if (parent != parentHeight || parentOffset != this.parentViewTopOffset) { this.parentViewTopOffset = parentOffset; parentHeight = parent; } if (currentMessageObject != null && (hasGradientService() && currentMessageObject.shouldDrawWithoutBackground())) { invalidate(); } if (currentMessageObject != null && currentMessageObject.textLayoutBlocks != null) { int p = position - textY; int newFirst = -1, newLast = -1, newCount = 0; int startBlock = 0; for (int a = 0; a < currentMessageObject.textLayoutBlocks.size(); a++) { if (currentMessageObject.textLayoutBlocks.get(a).textYOffset(currentMessageObject.textLayoutBlocks, transitionParams) > p) { break; } startBlock = a; } for (int a = startBlock; a < currentMessageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); float y = block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams); if (intersect(y, y + block.padTop + block.height(transitionParams) + block.padBottom, p, p + height)) { if (newFirst == -1) { newFirst = a; } newLast = a; newCount++; } else if (y > p) { break; } } if (lastVisibleBlockNum != newLast || firstVisibleBlockNum != newFirst || totalVisibleBlocksCount != newCount) { lastVisibleBlockNum = newLast; firstVisibleBlockNum = newFirst; totalVisibleBlocksCount = newCount; invalidate(); } else if (animatedEmojiStack != null) { for (int i = 0; i < animatedEmojiStack.holders.size(); i++) { AnimatedEmojiSpan.AnimatedEmojiHolder holder = animatedEmojiStack.holders.get(i); if (holder != null && holder.skipDraw) { float top = parentBoundsTop - getY() - holder.drawingYOffset; float bottom = parentBoundsBottom - getY() - holder.drawingYOffset; if (!holder.outOfBounds(top, bottom)) { invalidate(); break; } } } } } if (currentMessageObject != null && currentMessageObject.richLayout != null) { final RichMessageLayout layout = currentMessageObject.richLayout; final int p = position - textY; int newFirst = -1, newLast = -1; for (int a = 0; a < layout.blocks.size(); a++) { final RichMessageLayout.RichBlock block = layout.blocks.get(a); if (!block.currVisible && !block.prevVisible) continue; final float y = block.currY; final float h = block.getHeight(); if (intersect(y, y + h, p, p + height)) { if (newFirst == -1) newFirst = a; newLast = a; } else if (y > p + height) { break; } } if (firstVisibleRichBlock != newFirst || lastVisibleRichBlock != newLast) { firstVisibleRichBlock = newFirst; lastVisibleRichBlock = newLast; invalidate(); } } if (!pollButtons.isEmpty()) { int newPollFirst = -1, newPollLast = -1; for (int a = 0; a < pollButtons.size(); ++a) { final PollButton btn = pollButtons.get(a); if (intersect(btn.y + namesOffset, btn.y + namesOffset + btn.height, childPosition, childPosition + visibleHeight)) { if (newPollFirst == -1) { newPollFirst = a; } newPollLast = a; } } if (lastVisiblePollButton != newPollLast || firstVisiblePollButton != newPollFirst) { lastVisiblePollButton = newPollLast; firstVisiblePollButton = newPollFirst; invalidate(); } } if (drawSummarizeButton) { float y = getPaddingTop() + dp(8); y = Math.max(Math.min(-childPosition2 + dp(4), sideStartY - dp(42)), y); if (Math.abs(summarizeButtonY - y) >= 1) { invalidate(); } } final boolean reactionsVisible = intersect(reactionsLayoutInBubble.y, reactionsLayoutInBubble.y + reactionsLayoutInBubble.height, childPosition, childPosition + visibleHeight); if (this.reactionsVisible != reactionsVisible) { this.reactionsVisible = reactionsVisible; invalidate(); } } private boolean intersect(float left1, float right1, float left2, float right2) { if (left1 <= left2) { return right1 >= left2; } return left1 <= right2; } public static StaticLayout generateStaticLayout(CharSequence text, TextPaint paint, int maxWidth, int smallWidth, int linesCount, int maxLines) { SpannableStringBuilder stringBuilder = new SpannableStringBuilder(text); int addedChars = 0; StaticLayout layout = new StaticLayout(text, paint, smallWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); for (int a = 0; a < linesCount; a++) { Layout.Directions directions = layout.getLineDirections(a); if (layout.getLineLeft(a) != 0 || layout.isRtlCharAt(layout.getLineStart(a)) || layout.isRtlCharAt(layout.getLineEnd(a))) { maxWidth = smallWidth; } int pos = layout.getLineEnd(a); if (pos == text.length()) { break; } pos--; if (stringBuilder.charAt(pos + addedChars) == ' ') { stringBuilder.replace(pos + addedChars, pos + addedChars + 1, "\n"); } else if (stringBuilder.charAt(pos + addedChars) != '\n') { stringBuilder.insert(pos + addedChars, "\n"); addedChars++; } if (a == layout.getLineCount() - 1 || a == maxLines - 1) { break; } } return StaticLayoutEx.createStaticLayout(stringBuilder, paint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, dp(1), false, TextUtils.TruncateAt.END, maxWidth, maxLines, true); } private void didClickedPollImage(ChatMessageCell cell, ImageReceiver imageReceiver, TLRPC.PollAnswer answer, TLRPC.MessageMedia media, float x, float y, int unshuffledIndex) { /*if (unshuffledIndex == PollAttachedMediaPack.INDEX_DESCRIPTION) { if (pollContentDrawable != null && pollContentDrawable.getMedia() != null && pollContentDrawable.getMedia().document != null && (pollContentDrawable.isFile() || pollContentDrawable.isMusic())) { FileLoader.getInstance(currentAccount).loadFile(pollContentDrawable.getMedia().document, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); invalidate(); } return; }*/ if (delegate != null) { delegate.didPressPollMedia(cell, imageReceiver, answer, media, x, y, unshuffledIndex); } } private void didClickedImage() { if (currentMessageObject.hasMediaSpoilers() && !currentMessageObject.needDrawBluredPreview() && !currentMessageObject.isMediaSpoilersRevealed) { if (delegate != null && currentMessageObject.isSensitive()) { delegate.didPressRevealSensitiveContent(this); return; } startRevealMedia(lastTouchX, lastTouchY); return; } if (currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW) { if (currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.media != null && !currentMessageObject.messageOwner.media.extended_media.isEmpty() && currentMessageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup) { final TLRPC.TL_replyInlineMarkup replyInlineMarkup = (TLRPC.TL_replyInlineMarkup) currentMessageObject.messageOwner.reply_markup; for (TL_keyboard.KeyboardInlineButtonRow row : replyInlineMarkup.rows) { for (TL_keyboard.KeyboardInlineButton button : row.buttons) { delegate.didPressExtendedMediaPreview(this, button); return; } } } } else if (currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.isAnyKindOfSticker()) { if (buttonState == -1) { delegate.didPressImage(this, lastTouchX, lastTouchY, false); } else if (buttonState == 0) { didPressButton(true, false); } } else if (currentMessageObject.type == MessageObject.TYPE_CONTACT) { long uid = MessageObject.getMedia(currentMessageObject.messageOwner).user_id; TLRPC.User user = null; if (uid != 0) { user = MessagesController.getInstance(currentAccount).getUser(uid); } delegate.didPressUserAvatar(this, user, lastTouchX, lastTouchY, false); } else if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { if (buttonState != -1) { didPressButton(true, false); } else { if (!MediaController.getInstance().isPlayingMessage(currentMessageObject) || MediaController.getInstance().isMessagePaused()) { delegate.needPlayMessage(this, currentMessageObject, false); } else { MediaController.getInstance().pauseMessage(currentMessageObject); } } } else if (currentMessageObject.type == MessageObject.TYPE_GIF) { if (buttonState == -1 || buttonState == 1 && canStreamVideo && autoPlayingMedia) { //if (SharedConfig.isAutoplayGifs()) { delegate.didPressImage(this, lastTouchX, lastTouchY, false); /*} else { buttonState = 2; currentMessageObject.gifState = 1; photoImage.setAllowStartAnimation(false); photoImage.stopAnimation(); radialProgress.setIcon(getIconForCurrentState(), false, true); invalidate(); }*/ } else if (buttonState == 2 || buttonState == 0) { didPressButton(true, false); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || currentMessageObject.hasVideoQualities()) { if (buttonState == -1 || drawVideoImageButton && (autoPlayingMedia || currentMessageObject != null && currentMessageObject.hasVideoQualities() || SharedConfig.streamMedia && canStreamVideo)) { delegate.didPressImage(this, lastTouchX, lastTouchY, false); } else if (drawVideoImageButton) { didPressButton(true, true); } else if (buttonState == 0 || buttonState == 3) { didPressButton(true, false); } } else if (currentMessageObject.type == MessageObject.TYPE_GEO || currentMessageObject.type == MessageObject.TYPE_POLL || currentMessageObject.type == MessageObject.TYPE_STORY || currentMessageObject.type == MessageObject.TYPE_STORY_MENTION) { delegate.didPressImage(this, lastTouchX, lastTouchY, false); } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { if (buttonState == -1) { delegate.didPressImage(this, lastTouchX, lastTouchY, false); } } else if (currentMessageObject.sponsoredMedia != null) { if (delegate != null) { delegate.didPressImage(this, lastTouchX, lastTouchY, false); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { if (buttonState == -1) { TLRPC.WebPage webPage = MessageObject.getMedia(currentMessageObject.messageOwner).webpage; if (webPage != null) { if (webPage.embed_url != null && webPage.embed_url.length() != 0) { delegate.needOpenWebView(currentMessageObject, webPage.embed_url, webPage.site_name, webPage.description, webPage.url, webPage.embed_width, webPage.embed_height); } else { Browser.openUrl(getContext(), webPage.url); } } } } else if (hasInvoicePreview) { if (buttonState == -1) { delegate.didPressImage(this, lastTouchX, lastTouchY, false); } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // open message options then if (delegate != null) { if (currentMessageObject.type == MessageObject.TYPE_PHONE_CALL) { delegate.didLongPress(this, 0, 0); } else { delegate.didPressOther(this, otherX, otherY); } } } } private void updateSecretTimeText(MessageObject messageObject) { if (messageObject == null || !messageObject.needDrawBluredPreview()) { return; } CharSequence str = messageObject.getSecretTimeString(); if (str == null) { return; } if (str instanceof String) { infoWidth = (int) Math.ceil(Theme.chat_infoPaint.measureText((String) str)); CharSequence str2 = TextUtils.ellipsize(str, Theme.chat_infoPaint, infoWidth, TextUtils.TruncateAt.END); infoLayout = new StaticLayout(str2, Theme.chat_infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else { infoLayout = new StaticLayout(str, Theme.chat_infoBoldPaint, getMeasuredWidth() > 0 ? getMeasuredWidth() : 9999, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); infoWidth = infoLayout.getLineCount() > 0 ? (int) infoLayout.getLineWidth(0) : 0; } invalidate(); } private boolean isPhotoDataChanged(MessageObject object) { if (object.type == MessageObject.TYPE_TEXT || object.type == MessageObject.TYPE_MUSIC) { return false; } if (object.type == MessageObject.TYPE_GEO) { if (currentUrl == null) { return true; } double lat = object.messageOwner.media.geo.lat; double lon = object.messageOwner.media.geo._long; String url; int provider; if ((int) object.getDialogId() == 0) { if (SharedConfig.mapPreviewType == 0) { provider = -1; } else if (SharedConfig.mapPreviewType == 1) { provider = 4; } else if (SharedConfig.mapPreviewType == 3) { provider = 1; } else { provider = -1; } } else { provider = -1; } if (object.messageOwner.media instanceof TLRPC.TL_messageMediaGeoLive) { int photoWidth = backgroundWidth - dp(21); int photoHeight = dp(195); int offset = 268435456; double rad = offset / Math.PI; double y = Math.round(offset - rad * Math.log((1 + Math.sin(lat * Math.PI / 180.0)) / (1 - Math.sin(lat * Math.PI / 180.0))) / 2) - (dp(10.3f) << (21 - 15)); lat = (Math.PI / 2.0 - 2 * Math.atan(Math.exp((y - offset) / rad))) * 180.0 / Math.PI; url = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), false, 15, provider); } else if (!TextUtils.isEmpty(object.messageOwner.media.title)) { int photoWidth = backgroundWidth - dp(21); int photoHeight = dp(195); url = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), true, 15, provider); } else { int photoWidth = backgroundWidth - dp(12); int photoHeight = dp(195); url = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), true, 15, provider); } return !url.equals(currentUrl); } else if (currentPhotoObject == null || currentPhotoObject.location instanceof TLRPC.TL_fileLocationUnavailable) { return ( object.type == MessageObject.TYPE_PHOTO || object.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW || object.type == MessageObject.TYPE_ROUND_VIDEO || object.type == MessageObject.TYPE_VIDEO || object.type == MessageObject.TYPE_GIF || object.isAnyKindOfSticker() ); } else if (currentMessageObject != null && photoNotSet) { File cacheFile = FileLoader.getInstance(currentAccount).getPathToMessage(currentMessageObject.messageOwner); return cacheFile.exists(); } return false; } private int getRepliesCount() { if (currentMessagesGroup != null && !currentMessagesGroup.messages.isEmpty()) { MessageObject messageObject = currentMessagesGroup.messages.get(0); return messageObject.getRepliesCount(); } return currentMessageObject.getRepliesCount(); } private ArrayList getRecentRepliers() { if (currentMessagesGroup != null && !currentMessagesGroup.messages.isEmpty()) { MessageObject messageObject = currentMessagesGroup.messages.get(0); if (messageObject.messageOwner.replies != null) { return messageObject.messageOwner.replies.recent_repliers; } } if (currentMessageObject.messageOwner.replies != null) { return currentMessageObject.messageOwner.replies.recent_repliers; } return null; } public void updateAnimatedEmojis() { if (!imageReceiversAttachState || currentMessageObject == null) { return; } int cache = currentMessageObject.wasJustSent ? AnimatedEmojiDrawable.getCacheTypeForEnterView() : AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES; if (captionLayout != null && captionLayout.textLayoutBlocks != null) { animatedEmojiStack = AnimatedEmojiSpan.update(cache, this, false, animatedEmojiStack, captionLayout.textLayoutBlocks); } else { animatedEmojiStack = AnimatedEmojiSpan.update(cache, this, delegate == null || !delegate.canDrawOutboundsContent(), animatedEmojiStack, currentMessageObject.textLayoutBlocks); } if (currentMessageObject.type == MessageObject.TYPE_ARTICLE && currentMessageObject.richLayout != null) { currentMessageObject.richLayout.invalidateAnimatedEmojiInParent = delegate == null || !delegate.canDrawOutboundsContent(); currentMessageObject.richLayout.updateAnimatedEmojis(cache); } } private boolean isUserDataChanged() { if (currentMessageObject != null && (!hasLinkPreview && MessageObject.getMedia(currentMessageObject.messageOwner) != null && MessageObject.getMedia(currentMessageObject.messageOwner).webpage instanceof TLRPC.TL_webPage)) { return true; } if (currentMessageObject == null || currentUser == null && currentChat == null) { return false; } if (lastSendState != currentMessageObject.messageOwner.send_state) { return true; } if (lastDeleteDate != currentMessageObject.messageOwner.destroyTime) { return true; } if (lastViewsCount != currentMessageObject.messageOwner.views) { return true; } if (lastRepliesCount != getRepliesCount()) { return true; } if (lastReactions != currentMessageObject.messageOwner.reactions) { return true; } updateCurrentUserAndChat(); TLRPC.FileLocation newPhoto = null; if (isAvatarVisible) { if (currentUser != null && currentUser.photo != null) { newPhoto = currentUser.photo.photo_small; } else if (currentChat != null && currentChat.photo != null) { newPhoto = currentChat.photo.photo_small; } } if (replyTextLayout == null && currentMessageObject.replyMessageObject != null) { if (!isThreadChat || currentMessageObject.replyMessageObject.messageOwner.fwd_from == null || currentMessageObject.replyMessageObject.messageOwner.fwd_from.channel_post == 0) { return true; } } if (currentPhoto == null && newPhoto != null || currentPhoto != null && newPhoto == null || currentPhoto != null && (currentPhoto.local_id != newPhoto.local_id || currentPhoto.volume_id != newPhoto.volume_id)) { return true; } TLRPC.PhotoSize newReplyPhoto = null; if (replyNameLayout != null && currentMessageObject.replyMessageObject != null) { TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(currentMessageObject.replyMessageObject.photoThumbs, 40); if (photoSize != null && !currentMessageObject.replyMessageObject.isAnyKindOfSticker()) { newReplyPhoto = photoSize; } } if (currentReplyPhoto == null && newReplyPhoto != null) { return true; } String newNameString = isNeedAuthorName() ? getAuthorName() : null; if (currentNameString == null && newNameString != null || currentNameString != null && newNameString == null || currentNameString != null && !currentNameString.equals(newNameString)) { return true; } if (drawForwardedName && currentMessageObject.needDrawForwarded()) { newNameString = currentMessageObject.getForwardedName(); return currentForwardNameString == null && newNameString != null || currentForwardNameString != null && newNameString == null || currentForwardNameString != null && !currentForwardNameString.equals(newNameString); } return false; } public ImageReceiver getPhotoImage() { return photoImage; } public ImageReceiver getPhotoImage(int index) { if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_POLL) { if (index == PollAttachedMediaPack.INDEX_DESCRIPTION) { return pollContentDrawable != null ? pollContentDrawable.getImageReceiver() : null; } else if (index == PollAttachedMediaPack.INDEX_EXPLANATION) { return pollExplanationDrawable != null ? pollExplanationDrawable.getImageReceiver() : null; } else if (pollButtons != null) { for (PollButton btn : pollButtons) { if (btn.pollButtonDrawable != null && btn.answer != null && btn.answer.unshuffled_index == index) { return btn.pollButtonDrawable.getImageReceiver(); } } } } if (groupMedia != null) { return groupMedia.getPhotoImage(index); } return photoImage; } public ImageReceiver getBlurredPhotoImage() { return blurredPhotoImage; } public int getNoSoundIconCenterX() { return noSoundCenterX; } public int getForwardNameCenterX() { if (currentUser != null && currentUser.id == 0) { return (int) avatarImage.getCenterX(); } return (int) (forwardNameX + forwardNameCenterX); } public int getChecksX() { return layoutWidth - dp(SharedConfig.bubbleRadius >= 10 ? 27.3f : 25.3f); } public int getChecksY() { if (currentMessageObject.shouldDrawWithoutBackground()) { return (int) (drawTimeY - getThemedDrawable(Theme.key_drawable_msgStickerCheck).getIntrinsicHeight()); } else { return (int) (drawTimeY - Theme.chat_msgMediaCheckDrawable.getIntrinsicHeight()); } } private AudioVisualizerDrawable overridenAudioVisualizer; public void overrideAudioVisualizer(AudioVisualizerDrawable audioVisualizerDrawable) { this.overridenAudioVisualizer = audioVisualizerDrawable; } public TLRPC.User getCurrentUser() { return currentUser; } public TLRPC.Chat getCurrentChat() { return currentChat; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (observersGroup != null) { observersGroup.removeAllObservers(); observersGroup = null; } cancelShakeAnimation(); if (checkBox != null) { checkBox.onDetachedFromWindow(); } if (pollContentDrawable != null) { pollContentDrawable.detach(); } if (pollExplanationDrawable != null) { pollExplanationDrawable.detach(); } if (pollCountDownTimer != null) { pollCountDownTimer.stop(); pollCountDownTimer = null; } if (currentMessageObject.richLayout != null) { currentMessageObject.richLayout.detach(this); } if (transitionParams.animateOutRichLayout != null) { transitionParams.animateOutRichLayout.detach(this); } for (PollButton btn : pollButtons) { btn.detach(); } if (groupCallParticipantsAvatars != null) { groupCallParticipantsAvatars.onDetachedFromWindow(); } if (mediaCheckBox != null) { mediaCheckBox.onDetachedFromWindow(); } if (pollCheckBox != null) { for (int a = 0; a < pollCheckBox.length; a++) { pollCheckBox[a].onDetachedFromWindow(); } } if (replyTaskCheckbox != null) { replyTaskCheckbox.onDetachedFromWindow(); } attachedToWindow = false; if (groupMedia != null) { groupMedia.onDetachedFromWindow(); } avatarImage.onDetachedFromWindow(); if (sideImage != null) { sideImage.onDetachedFromWindow(); } if (topicButton != null) { topicButton.detach(); } if (topicSeparator != null) { topicSeparator.detach(); } checkImageReceiversAttachState(); if (addedForTest && currentUrl != null && currentWebFile != null) { ImageLoader.getInstance().removeTestWebFile(currentUrl); addedForTest = false; } if (stickerSetIcons != null) { stickerSetIcons.detach(this); } DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); if (getDelegate() != null && getDelegate().getTextSelectionHelper() != null) { getDelegate().getTextSelectionHelper().onChatMessageCellDetached(this); } transitionParams.onDetach(); if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { Theme.getCurrentAudiVisualizerDrawable().setParentView(null); } if (statusDrawableAnimator != null) { statusDrawableAnimator.removeAllListeners(); statusDrawableAnimator.cancel(); } reactionsLayoutInBubble.onDetachFromWindow(); statusDrawableAnimationInProgress = false; if (flagSecure != null) { flagSecure.detach(); } if (currentNameStatusDrawable != null) { currentNameStatusDrawable.detach(); } if (currentNameEmojiStatusDrawable != null) { currentNameEmojiStatusDrawable.detach(); } if (mediaSpoilerEffect2 != null) { mediaSpoilerEffect2.detach(this); } if (channelRecommendationsCell != null) { channelRecommendationsCell.onDetachedFromWindow(); } Choreographer60FpsContent.getInstance().removeFrameCallback(invalidateOutboundsRunnable); } private NotificationCenter.ObserversGroup observersGroup; @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (observersGroup != null) { observersGroup.removeAllObservers(); observersGroup = null; } observersGroup = NotificationCenter.getInstance(currentAccount) .createObserversGroup(this) .add(NotificationCenter.userInfoDidLoad) .addGlobal(NotificationCenter.startSpoilers) .addGlobal(NotificationCenter.stopSpoilers) .addGlobal(NotificationCenter.emojiLoaded) .addGlobal(NotificationCenter.didUpdatePremiumGiftStickers); if (currentMessageObject != null) { currentMessageObject.animateComments = false; if (currentMessageObject.richLayout != null) { currentMessageObject.richLayout.attach(this); } } if (transitionParams.animateOutRichLayout != null) { transitionParams.animateOutRichLayout.attach(this); } if (groupCallParticipantsAvatars != null) { groupCallParticipantsAvatars.onAttachedToWindow(); } if (pollContentDrawable != null) { pollContentDrawable.attach(); } if (pollExplanationDrawable != null) { pollExplanationDrawable.attach(); } for (PollButton btn : pollButtons) { btn.attach(); } if (messageObjectToSet != null) { messageObjectToSet.animateComments = false; setMessageContent(messageObjectToSet, groupedMessagesToSet, bottomNearToSet, topNearToSet, firstInChatToSet, lastInChatListToSet); messageObjectToSet = null; groupedMessagesToSet = null; } if (checkBox != null) { checkBox.onAttachedToWindow(); } if (mediaCheckBox != null) { mediaCheckBox.onAttachedToWindow(); } if (topicSeparator != null) { topicSeparator.attach(); } if (replyTaskCheckbox != null) { replyTaskCheckbox.onAttachedToWindow(); } if (pollCheckBox != null) { for (int a = 0; a < pollCheckBox.length; a++) { pollCheckBox[a].onAttachedToWindow(); } } if (topicButton != null) { topicButton.attach(); } attachedToWindow = true; animationOffsetX = 0; slidingOffsetX = 0; checkBoxTranslation = 0; updateTranslation(); avatarImage.setParentView((View) getParent()); avatarImage.onAttachedToWindow(); if (sideImage != null) { sideImage.onAttachedToWindow(); } checkImageReceiversAttachState(); if (currentMessageObject != null) { setAvatar(currentMessageObject); } if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO && autoPlayingMedia) { animatingNoSoundPlaying = MediaController.getInstance().isPlayingMessage(currentMessageObject); animatingNoSoundProgress = animatingNoSoundPlaying ? 0.0f : 1.0f; animatingNoSound = 0; } else { animatingNoSoundPlaying = false; animatingNoSoundProgress = 0; animatingDrawVideoImageButtonProgress = (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) && drawVideoSize ? 1.0f : 0.0f; } if (getDelegate() != null && getDelegate().getTextSelectionHelper() != null) { getDelegate().getTextSelectionHelper().onChatMessageCellAttached(this); } if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { boolean showSeekbar = MediaController.getInstance().isPlayingMessage(currentMessageObject); toSeekBarProgress = showSeekbar ? 1f : 0f; } reactionsLayoutInBubble.onAttachToWindow(); if (flagSecure != null) { flagSecure.attach(); } if (groupMedia != null) { groupMedia.onAttachedToWindow(); } updateFlagSecure(); if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW && unlockLayout != null) { invalidate(); } if (currentNameStatusDrawable != null) { currentNameStatusDrawable.attach(); } if (currentNameEmojiStatusDrawable != null) { currentNameEmojiStatusDrawable.attach(); } if (mediaSpoilerEffect2 != null) { if (mediaSpoilerEffect2.destroyed) { mediaSpoilerEffect2 = makeSpoilerEffect(); if (mediaSpoilerEffect2Index != null) { mediaSpoilerEffect2.reassignAttach(this, mediaSpoilerEffect2Index); } } else { mediaSpoilerEffect2.attach(this); } } if (channelRecommendationsCell != null) { channelRecommendationsCell.onAttachedToWindow(); } if (stickerSetIcons != null) { stickerSetIcons.attach(this); } } protected SpoilerEffect2 makeSpoilerEffect() { return SpoilerEffect2.getInstance(this); } public void copySpoilerEffect2AttachIndexFrom(ChatMessageCell cell) { if (cell != null && cell.mediaSpoilerEffect2 != null) { mediaSpoilerEffect2Index = cell.mediaSpoilerEffect2.getAttachIndex(cell); if (mediaSpoilerEffect2 != null) { mediaSpoilerEffect2.reassignAttach(this, mediaSpoilerEffect2Index); } } } boolean imageReceiversAttachState; boolean imageReceiversVisibleState; private void checkImageReceiversAttachState() { boolean newAttachState = attachedToWindow; if (newAttachState != imageReceiversAttachState) { imageReceiversAttachState = newAttachState; if (newAttachState) { radialProgress.onAttachedToWindow(); videoRadialProgress.onAttachedToWindow(); if (pollRecentVotersDrawable != null) { pollRecentVotersDrawable.attach(); } if (pollButtons != null) { for (PollButton button : pollButtons) { button.attach(); } } if (pollContentDrawable != null) { pollContentDrawable.attach(); } if (pollExplanationDrawable != null) { pollExplanationDrawable.attach(); } if (commentAvatarImages != null) { for (int a = 0; a < commentAvatarImages.length; a++) { commentAvatarImages[a].onAttachedToWindow(); } } giveawayMessageCell.onAttachedToWindow(); giveawayResultsMessageCell.onAttachedToWindow(); replyImageReceiver.onAttachedToWindow(); locationImageReceiver.onAttachedToWindow(); blurredPhotoImage.onAttachedToWindow(); if (photoImage.onAttachedToWindow()) { if (drawPhotoImage) { updateButtonState(false, false, false); } } else { updateButtonState(false, false, false); } animatedEmojiReplyStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiReplyStack, replyTextLayout); animatedEmojiDescriptionStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiDescriptionStack, descriptionLayout); updateAnimatedEmojis(); } else { radialProgress.onDetachedFromWindow(); videoRadialProgress.onDetachedFromWindow(); if (pollRecentVotersDrawable != null) { pollRecentVotersDrawable.detach(); } if (pollContentDrawable != null) { pollContentDrawable.detach(); } if (pollExplanationDrawable != null) { pollExplanationDrawable.detach(); } if (pollButtons != null) { for (PollButton button : pollButtons) { button.detach(); } } if (commentAvatarImages != null) { for (int a = 0; a < commentAvatarImages.length; a++) { commentAvatarImages[a].onDetachedFromWindow(); } } replyImageReceiver.onDetachedFromWindow(); locationImageReceiver.onDetachedFromWindow(); photoImage.onDetachedFromWindow(); blurredPhotoImage.onDetachedFromWindow(); giveawayMessageCell.onDetachedFromWindow(); giveawayResultsMessageCell.onDetachedFromWindow(); AnimatedEmojiSpan.release(this, animatedEmojiDescriptionStack); AnimatedEmojiSpan.release(this, animatedEmojiReplyStack); AnimatedEmojiSpan.release(this, animatedEmojiStack); } } boolean newVisibleState = attachedToWindow && (visibleOnScreen || !shouldCheckVisibleOnScreen); if (newVisibleState != imageReceiversVisibleState) { imageReceiversVisibleState = newVisibleState; if (newVisibleState) { fileAttach(true, currentMessageObject); } else { fileDetach(currentMessageObject); } } } private void fileAttach(boolean checkUI, final MessageObject messageObject) { if (photoImage != null) { photoImage.setFileLoadingPriority(FileLoader.PRIORITY_NORMAL); } if (checkUI && messageObject != null && (isRoundVideo || messageObject.isVideo())) { checkVideoPlayback(true, null); } if (messageObject != null && !messageObject.mediaExists) { int canDownload = DownloadController.getInstance(currentAccount).canDownloadMediaType(messageObject); TLRPC.Document document = messageObject.getDocument(); boolean loadDocumentFromImageReceiver = MessageObject.isStickerDocument(document) || MessageObject.isAnimatedStickerDocument(document, true) || MessageObject.isGifDocument(document) || MessageObject.isRoundVideoDocument(document) || messageObject.hasVideoQualities(); if (!loadDocumentFromImageReceiver && !isSmallImage) { TLRPC.PhotoSize photo = document == null ? FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()) : null; if (canDownload == 2 || canDownload == 1 && messageObject.isVideo()) { if (canDownload != 2 && document != null && !messageObject.shouldEncryptPhotoOrVideo() && messageObject.canStreamVideo()) { FileLoader.getInstance(currentAccount).loadFile(document, messageObject, FileLoader.PRIORITY_NORMAL, 0); } } else if (canDownload != 0) { if (document != null) { FileLoader.getInstance(currentAccount).loadFile(document, messageObject, FileLoader.PRIORITY_NORMAL, (MessageObject.isVideoDocument(document) || messageObject.isVoiceOnce() || messageObject.isRoundOnce()) && messageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); } else if (photo != null) { FileLoader.getInstance(currentAccount).loadFile(ImageLocation.getForObject(photo, messageObject.photoThumbsObject), messageObject, null, FileLoader.PRIORITY_NORMAL, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); } } if (checkUI) { updateButtonState(false, false, false); } } if (messageObject.hasVideoQualities()) { if (messageObject.highestQuality != null && !messageObject.highestQuality.isManifestCached()) { FileLoader.getInstance(currentAccount).loadFile(messageObject.highestQuality.manifestDocument, messageObject, FileLoader.PRIORITY_NORMAL, 0); } if (messageObject.thumbQuality != null && !messageObject.thumbQuality.isManifestCached()) { FileLoader.getInstance(currentAccount).loadFile(messageObject.thumbQuality.manifestDocument, messageObject, FileLoader.PRIORITY_NORMAL, 0); } } } } private void fileDetach(MessageObject messageObject) { if (photoImage != null) { photoImage.setFileLoadingPriority(FileLoader.PRIORITY_LOW); } cancelLoading(messageObject); } private void cancelLoading(MessageObject messageObject) { if (messageObject != null && !messageObject.mediaExists && !messageObject.putInDownloadsStore && !DownloadController.getInstance(currentAccount).isDownloading(messageObject.messageOwner.id) && !PhotoViewer.getInstance().isVisible()) { TLRPC.Document document = messageObject.getDocument(); boolean loadDocumentFromImageReceiver = MessageObject.isStickerDocument(document) || MessageObject.isAnimatedStickerDocument(document, true) || MessageObject.isGifDocument(document) || MessageObject.isRoundVideoDocument(document); if (!loadDocumentFromImageReceiver) { if (document != null) { FileLoader.getInstance(currentAccount).cancelLoadFile(document); } else { TLRPC.PhotoSize photo = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); if (photo != null) { FileLoader.getInstance(currentAccount).cancelLoadFile(photo); } } } } } public MultiLayoutTypingAnimator botDraftTypingAnimator; private void setMessageContent(MessageObject messageObject, MessageObject.GroupedMessages groupedMessages, boolean bottomNear, boolean topNear, boolean firstInChat, boolean lastInChatList) { if (messageObject.checkLayout() || currentPosition != null && lastHeight != AndroidUtilities.displaySize.y) { currentMessageObject = null; } messageObject.isOutOwnerCached = null; boolean widthChanged = lastWidth != getParentWidth(); lastHeight = AndroidUtilities.displaySize.y; lastWidth = getParentWidth(); isRoundVideo = messageObject != null && messageObject.isRoundVideo(); mediaSpoilerRevealProgress = 0f; TLRPC.Message newReply = messageObject.hasValidReplyMessageObject() ? messageObject.replyMessageObject.messageOwner : null; boolean messageIdChanged = currentMessageObject == null || currentMessageObject.getId() != messageObject.getId(); boolean messageChanged = currentMessageObject != messageObject || messageObject.forceUpdate || (isRoundVideo && isPlayingRound != (MediaController.getInstance().isPlayingMessage(currentMessageObject) && delegate != null && !delegate.keyboardIsOpened())); boolean dataChanged = currentMessageObject != null && currentMessageObject.getId() == messageObject.getId() && lastSendState == MessageObject.MESSAGE_SEND_STATE_EDITING && messageObject.isSent() || currentMessageObject == messageObject && (isUserDataChanged() || photoNotSet) || lastPostAuthor != messageObject.messageOwner.post_author || wasPinned != isPinned || newReply != lastReplyMessage || messageObject.translated != lastTranslated; boolean groupChanged = groupedMessages != currentMessagesGroup; boolean pollChanged = false; if (!messageIdChanged && currentMessageObject != null) { int oldStableId = messageObject.stableId; messageObject.copyStableParams(currentMessageObject); if (currentMessageObject.isSavedFiltered && messageObject.isSavedFiltered || isSideMenued) { messageObject.stableId = oldStableId; } } accessibilityText = null; if (drawCommentButton || useTranscribeButton || drawSideButton == 3 && !((hasDiscussion && messageObject.isLinkedToChat(linkedChatId) || isRepliesChat) && (currentPosition == null || currentPosition.siblingHeights == null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 || currentPosition.siblingHeights != null && (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0))) { dataChanged = true; } if (!messageChanged && messageObject.isDice()) { setCurrentDiceValue(isUpdating); } if (!messageChanged && messageObject.isPoll()) { ArrayList newResults = null; TLRPC.Poll newPoll = null; int newVoters = 0; if (MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll mediaPoll = (TLRPC.TL_messageMediaPoll) MessageObject.getMedia(messageObject.messageOwner); newResults = mediaPoll.results.results; newPoll = mediaPoll.poll; newVoters = mediaPoll.results.total_voters; } if (newResults != null && lastPollResults != null && newVoters != lastPollResultsVoters) { pollChanged = true; } if (!pollChanged && newResults != lastPollResults) { pollChanged = true; } if (!pollChanged && (messageObject.forceShowPollResults != pollResultsPreview)) { pollChanged = true; } if (lastPoll != newPoll && (lastPoll != null && lastPoll.closed) != newPoll.closed) { pollChanged = true; if (!(pollVoted)) { pollVoteInProgress = true; vibrateOnPollVote = false; } } animatePollAvatars = false; if (pollChanged && attachedToWindow) { pollAnimationProgressTime = 0.0f; if ((pollVoted || pollResultsPreview) && !(messageObject.isVoted() || messageObject.forceShowPollResults)) { pollUnvoteInProgress = true; } animatePollAvatars = lastPollResultsVoters == 0 || lastPollResultsVoters != 0 && newVoters == 0; } if (!messageIdChanged && newPoll != null && lastPoll != null && lastPoll.quiz && newPoll.quiz && currentMessageObject != null && !pollVoted && messageObject != null && messageObject.isVoted()) { TLRPC.TL_messageMediaPoll mediaPoll = (TLRPC.TL_messageMediaPoll) MessageObject.getMedia(messageObject.messageOwner); if (mediaPoll.results != null && !mediaPoll.results.results.isEmpty()) { TLRPC.PollAnswerVoters chosenAnswer = null; int a; final int count = mediaPoll.results.results.size(); for (a = 0; a < count; a++) { TLRPC.PollAnswerVoters answer = mediaPoll.results.results.get(a); if (answer.chosen) { chosenAnswer = answer; break; } } if (chosenAnswer != null) { sendAccessibilityEventForVirtualView(MessageAccessibilityNodeProvider.POLL_BUTTONS_START + a, AccessibilityEvent.TYPE_VIEW_SELECTED, getString(chosenAnswer.correct ? R.string.AccDescrQuizCorrectAnswer : R.string.AccDescrQuizIncorrectAnswer)); } } } } if (!groupChanged && groupedMessages != null) { MessageObject.GroupedMessagePosition newPosition; if (groupedMessages.messages.size() > 1) { newPosition = currentMessagesGroup.getPosition(currentMessageObject); } else { newPosition = null; } groupChanged = newPosition != currentPosition; } if (!messageChanged && effectId != messageObject.getEffectId()) { messageChanged = true; } if (messageObject.updateSideMenuEnabled(isSideMenuEnabled)) { messageChanged = true; } if (messageChanged || dataChanged || groupChanged || pollChanged || widthChanged && messageObject.isPoll() || isPhotoDataChanged(messageObject) || pinnedBottom != bottomNear || pinnedTop != topNear) { postRunnableHolder.clear(); if (stickerSetIcons != null) { stickerSetIcons.readyToDie(); } wasPinned = isPinned; pinnedBottom = bottomNear; this.firstInChat = firstInChat; this.lastInChatList = lastInChatList; pinnedTop = topNear; if (currentMessageObject != null && currentMessageObject != messageObject && currentMessageObject.richLayout != null) { currentMessageObject.richLayout.detach(this); } currentMessageObject = messageObject; currentMessagesGroup = groupedMessages; wasAllChats = isAllChats; lastTime = -2; lastPostAuthor = messageObject.messageOwner.post_author; if (messageIdChanged || groupChanged) { isHighlightedAnimated = false; wasTranscriptionOpen = false; if (highlightedQuote) { resetUrlPaths(); } highlightedQuote = false; } widthBeforeNewTimeLine = -1; if (currentMessagesGroup != null && (currentMessagesGroup.posArray.size() > 1)) { currentPosition = currentMessagesGroup.getPosition(currentMessageObject); if (currentPosition == null) { currentMessagesGroup = null; } } else { currentMessagesGroup = null; currentPosition = null; } if (currentMessagesGroup == null || currentMessagesGroup.isDocuments) { drawPinnedTop = pinnedTop; drawPinnedBottom = pinnedBottom; } else { drawPinnedTop = pinnedTop && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); drawPinnedBottom = pinnedBottom && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0); } boolean wasPlayingRound = isPlayingRound; isPlayingRound = isRoundVideo && MediaController.getInstance().isPlayingMessage(currentMessageObject) && delegate != null && !delegate.keyboardIsOpened() && !delegate.isLandscape(); photoImage.setCrossfadeWithOldImage(false); photoImage.setCrossfadeDuration(ImageReceiver.DEFAULT_CROSSFADE_DURATION); photoImage.setCrossfadeByScale(0); photoImage.setGradientBitmap(null); photoImage.clearDecorators(); photoImage.setInvalidateAll(false); linkPreviewY = 0; factCheckY = 0; lastTranslated = messageObject.translated; lastSendState = messageObject.messageOwner.send_state; lastDeleteDate = messageObject.messageOwner.destroyTime; lastViewsCount = messageObject.messageOwner.views; lastRepliesCount = getRepliesCount(); if (messageIdChanged) { isPressed = false; isCheckPressed = true; playedDice = false; } gamePreviewPressed = false; sideButtonPressed = false; pressedSideButton = 0; hasNewLineForTime = false; flipImage = false; isThreadPost = isThreadChat && messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.channel_post != 0 && messageObject.messageOwner.reply_to == null; isAvatarVisible = needDrawAvatar() && (currentPosition == null || currentPosition.edge); boolean drawAvatar = needDrawAvatar(); if (messageObject.customAvatarDrawable != null || messageObject.forceAvatar || messageObject.messageOwner.guestchat_via_from != null) { isAvatarVisible = true; drawAvatar = true; } wasLayout = false; groupPhotoInvisible = false; animatingDrawVideoImageButton = 0; drawVideoSize = false; canStreamVideo = false; animatingNoSound = 0; drawSideButton2 = 0; if (messageObject.isSponsored()) { drawSideButton = 4; if (messageObject.sponsoredCanReport) { drawSideButton2 = 5; } } else if (messageObject.searchType == ChatActivity.SEARCH_PUBLIC_POSTS) { drawSideButton = checkNeedDrawShareButton(messageObject) ? 2 : 0; } else if (messageObject.searchType == ChatActivity.SEARCH_MY_MESSAGES) { drawSideButton = 0; } else if (MessagesController.getInstance(currentAccount).isPeerNoForwards(messageObject.getDialogId()) || (messageObject.messageOwner != null && messageObject.messageOwner.noforwards)) { drawSideButton = 0; if (isPinnedChat && !isRepliesChat && !messageObject.isSponsored()) { if (currentMessagesGroup != null && currentPosition != null) { final boolean last = (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & (messageObject.isOutOwner() ? MessageObject.POSITION_FLAG_LEFT : MessageObject.POSITION_FLAG_RIGHT)) != 0; if (currentMessagesGroup.isDocuments || last) { drawSideButton = 2; } } else { drawSideButton = 2; } } } else { drawSideButton = !isRepliesChat && checkNeedDrawShareButton(messageObject) ? 1 : 0; if (isPinnedChat || drawSideButton == 1 && (messageObject.messageOwner.fwd_from != null && !messageObject.isOutOwner() && messageObject.messageOwner.fwd_from.saved_from_peer != null && messageObject.getDialogId() == UserConfig.getInstance(currentAccount).getClientUserId() || messageObject.isSaved)) { drawSideButton = 2; } } drawSummarizeButton = TranslateController.isSummarizable(messageObject); hasReplyQuote = false; isReplyQuote = false; isReplyTaskOrPollOption = false; replyNameLayout = null; drawSummaryReply = false; adminLayout = null; ephemeralLayout = null; ephemeralWidth = 0; adminLayoutIsAdmin = adminLayoutIsOwner = adminLayoutIsTag = false; boostCounterBounds = null; boostCounterSpan = null; checkOnlyButtonPressed = false; replyTextLayout = null; AnimatedEmojiSpan.release(this, animatedEmojiReplyStack); lastReplyMessage = null; hasEmbed = false; autoPlayingMedia = false; replyNameWidth = 0; replyTextWidth = 0; replyTextHeight = 0; viaWidth = 0; viaNameWidth = 0; viaOnly = false; addedCaptionHeight = 0; pollAddButtonHeight = 0; currentReplyPhoto = null; currentUser = null; currentChat = null; currentViaBotUser = null; instantViewLayout = null; drawNameLayout = false; drawNameAvatar = false; linkPreviewAbove = false; captionAbove = currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.invert_media || groupedMessages != null && groupedMessages.captionAbove; isSmallImage = false; lastLoadingSizeTotal = 0; if (scheduledInvalidate) { AndroidUtilities.cancelRunOnUIThread(invalidateRunnable); scheduledInvalidate = false; } links.clear(); pressedLink = null; pressedEmoji = null; pressedLinkType = -1; messageObject.forceUpdate = false; drawPhotoImage = false; drawMediaCheckBox = false; hasLinkPreview = false; hasFactCheck = false; hasOldCaptionPreview = false; hasGamePreview = false; hasInvoicePreview = false; hasInvoicePrice = false; closeExplanationX = -1; closeExplanationY = -1; instantPressed = commentButtonPressed = false; gradientDrawable = null; if (groupMedia != null && messageObject.type != MessageObject.TYPE_PAID_MEDIA) { groupMedia.onDetachedFromWindow(); groupMedia = null; } setInstantButtonPressed(false); if (!pollChanged) { for (int a = 0; a < selectorDrawable.length; a++) { if (selectorDrawable[a] != null) { selectorDrawable[a].setVisible(false, false); selectorDrawable[a].setState(StateSet.NOTHING); } } } resetContactButtonsPressedState(); if (titleLabelBounce != null) { titleLabelBounce.setPressed(false); } drawnContactButtonsFlag = 0; drawContact = false; drawContactView = false; drawContactSendMessage = false; drawContactAdd = false; spoilerPressed = null; isSpoilerRevealing = false; linkPreviewPressed = false; buttonPressed = 0; additionalTimeOffsetY = 0; miniButtonPressed = 0; pressedBotButton = -1; pressedVoteButton = -1; pollHintPressed = false; pollAddButtonPressed = -1; pollMediaPressedIndex = PollAttachedMediaPack.INDEX_NONE; closeExplanationPressed = false; psaHintPressed = false; linkPreviewHeight = 0; factCheckHeight = 0; mediaOffsetY = 0; documentAttachType = DOCUMENT_ATTACH_TYPE_NONE; documentAttach = null; descriptionLayout = null; titleLayout = null; videoInfoLayout = null; photosCountLayout = null; siteNameLayout = null; titleLabelLayout = null; authorLayout = null; captionFullWidth = 0; prevCaptionLayout = captionLayout; captionLayout = null; captionWidth = 0; captionHeight = 0; captionOffsetX = 0; currentCaption = null; explanationLayout = null; explanationTitleLayout = null; currentExplanation = null; explanationHeight = 0; docTitleLayout = null; groupCallParticipantsText = null; if (groupCallParticipantsAvatars != null) { groupCallParticipantsAvatars.onDetachedFromWindow(); groupCallParticipantsAvatars = null; } if (pollCountDownTimer != null) { pollCountDownTimer.stop(); pollCountDownTimer = null; } drawImageButton = false; drawVideoImageButton = false; currentPhotoLocation = null; currentPhotoThumbLocation = null; currentPhotoObject = null; photoParentObject = null; currentPhotoObjectThumb = null; currentPhotoObjectThumbStripped = null; if (messageChanged || messageIdChanged || dataChanged) { currentPhotoFilter = null; } buttonState = -1; miniButtonState = -1; hasMiniProgress = 0; if (addedForTest && currentUrl != null && currentWebFile != null) { ImageLoader.getInstance().removeTestWebFile(currentUrl); } addedForTest = false; photoNotSet = false; drawBackground = true; drawName = false; useSeekBarWaveform = false; useTranscribeButton = false; drawInstantView = false; drawInstantViewType = 0; instantViewTypeIsGiftAuction = null; instantDrawable = null; instantDrawableColor = 0; groupCallDrawable = null; groupCallDrawableColor = 0; instantViewButtonText = null; drawForwardedName = false; drawCommentButton = false; photoImage.setSideClip(0); photoImage.setAspectFit(false); photoImage.setRoundRadiusEnabled(true); fitPhotoImage = false; gradientShader = null; motionBackgroundDrawable = null; pollContentHeight = 0; pollContentHeightWithOffset = 0; imageBackgroundColor = 0; imageBackgroundGradientColor1 = 0; imageBackgroundGradientColor2 = 0; imageBackgroundIntensity = 0; imageBackgroundGradientColor3 = 0; imageBackgroundGradientRotation = 45; imageBackgroundSideColor = 0; mediaBackground = false; isMedia = false; if (expiredStoryView != null) { expiredStoryView.visible = false; } photoImage.animatedFileDrawableRepeatMaxCount = 0; hasPsaHint = messageObject.messageOwner.fwd_from != null && !TextUtils.isEmpty(messageObject.messageOwner.fwd_from.psa_type); if (hasPsaHint) { createSelectorDrawable(0); } botDraftTypingAnimator = draftAnimationsPool != null ? draftAnimationsPool.getAnimator(messageObject.getFromChatId(), messageObject.getId(), messageObject.isBotPendingDraft) : null; if (botDraftTypingAnimator != null) { // For TYPE_ARTICLE the rich layout is built further down and feeds its own // RichBlock list to the animator — skip the text-block setBlocks here. if (messageObject.type != MessageObject.TYPE_ARTICLE) { botDraftTypingAnimator.setBlocks(messageObject.textLayoutBlocks); } if (!messageObject.isBotPendingDraft) { final long did = messageObject.getDialogId(); final int mid = messageObject.getId(); botDraftTypingAnimator.setOnFinishListener(() -> { if (draftAnimationsPool != null) { draftAnimationsPool.removeAnimator(did, mid); } }); } } photoImage.setAlpha(1.0f); if ((messageChanged || dataChanged) && !pollUnvoteInProgress) { for (PollButton btn : pollButtons) { btn.destroy(); } oldPollButtons.clear(); oldPollButtons.addAll(pollButtons); pollButtons.clear(); } int captionNewLine = 0; availableTimeWidth = 0; photoImage.setForceLoading(false); photoImage.setNeedsQualityThumb(false); photoImage.setShouldGenerateQualityThumb(false); photoImage.setAllowDecodeSingleFrame(false); photoImage.setColorFilter(null); photoImage.setMediaStartEndTime(-1, -1); boolean canChangeRadius = true; if (messageIdChanged || messageObject.reactionsChanged || wasPlayingRound != isPlayingRound) { messageObject.reactionsChanged = false; boolean isTag = messageObject.messageOwner != null && messageObject.messageOwner.reactions != null && messageObject.messageOwner.reactions.reactions_as_tags; if (messageObject.shouldDrawReactions() && !messageObject.isExpiredStory() && (currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0))) { boolean isSmall = !messageObject.shouldDrawReactionsInLayout(); if (currentPosition != null) { MessageObject primaryMessage = groupedMessages.findPrimaryMessageObject(); if (!isTag && primaryMessage.messageOwner != null) { isTag = primaryMessage.messageOwner.reactions != null && primaryMessage.messageOwner.reactions.reactions_as_tags; } reactionsLayoutInBubble.setMessage(groupedMessages.findPrimaryMessageObject(), !messageObject.shouldDrawReactionsInLayout(), isTag, resourcesProvider); } else { reactionsLayoutInBubble.setMessage(messageObject, isSmall, isTag, resourcesProvider); } } else { reactionsLayoutInBubble.setMessage(null, false, false, resourcesProvider); } } if (messageChanged) { firstVisibleBlockNum = 0; lastVisibleBlockNum = 0; if (currentMessageObject != null && currentMessageObject.textLayoutBlocks != null && currentMessageObject.textLayoutBlocks.size() > 1) { needNewVisiblePart = true; } } boolean linked = false; if (currentMessagesGroup != null && currentMessagesGroup.messages.size() > 0) { MessageObject object = currentMessagesGroup.messages.get(0); if (object.isLinkedToChat(linkedChatId)) { linked = true; } } else { linked = messageObject.isLinkedToChat(linkedChatId); } if ((hasDiscussion && linked || isRepliesChat && !messageObject.isOutOwner()) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) && messageObject.searchType == 0 && !messageObject.isEphemeral()) { int commentCount = getRepliesCount(); if (!messageObject.shouldDrawWithoutBackground() && !messageObject.isAnimatedEmoji()) { drawCommentButton = true; int avatarsOffset = 0; String comment; if (commentProgress == null) { commentProgress = new InfiniteProgress(dp(7)); } if (isRepliesChat) { comment = getString("ViewInChat", R.string.ViewInChat); } else { if (LocaleController.isRTL) { comment = commentCount == 0 ? getString("LeaveAComment", R.string.LeaveAComment) : formatPluralString("CommentsCount", commentCount); } else { comment = commentCount == 0 ? getString("LeaveAComment", R.string.LeaveAComment) : LocaleController.getPluralString("CommentsNoNumber", commentCount); } ArrayList recentRepliers = getRecentRepliers(); if (commentCount != 0 && recentRepliers != null && !recentRepliers.isEmpty()) { createCommentUI(); int size = recentRepliers.size(); for (int a = 0; a < commentAvatarImages.length; a++) { if (a < size) { commentAvatarImages[a].setImageCoords(0, 0, dp(24), dp(24)); long id = MessageObject.getPeerId(recentRepliers.get(a)); TLRPC.User user; TLRPC.Chat chat; if (DialogObject.isUserDialog(id)) { user = MessagesController.getInstance(currentAccount).getUser(id); chat = null; } else if (DialogObject.isChatDialog(id)) { user = null; chat = MessagesController.getInstance(currentAccount).getChat(-id); } else { user = null; chat = null; } final int A = a; post(() -> { if (user != null) { commentAvatarDrawables[A].setInfo(currentAccount, user); commentAvatarImages[A].setForUserOrChat(user, commentAvatarDrawables[A]); } else if (chat != null) { commentAvatarDrawables[A].setInfo(currentAccount, chat); commentAvatarImages[A].setForUserOrChat(chat, commentAvatarDrawables[A]); } else { commentAvatarDrawables[A].setInfo(id, "", ""); } }); commentAvatarImagesVisible[a] = true; avatarsOffset += a == 0 ? 2 : 17; } else if (size != 0) { commentAvatarImages[a].setImageBitmap((Drawable) null); commentAvatarImagesVisible[a] = false; } } } else if (commentAvatarImages != null) { for (int a = 0; a < commentAvatarImages.length; a++) { commentAvatarImages[a].setImageBitmap((Drawable) null); commentAvatarImagesVisible[a] = false; } } } commentWidth = totalCommentWidth = (int) Math.ceil(Theme.chat_commentTextPaint.measureText(comment)); commentLayout = new StaticLayout(comment, Theme.chat_commentTextPaint, commentWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (commentCount != 0 && !LocaleController.isRTL) { drawCommentNumber = true; if (commentNumberLayout == null) { commentNumberLayout = new AnimatedNumberLayout(this, Theme.chat_commentTextPaint); commentNumberLayout.setNumber(commentCount, false); } else { commentNumberLayout.setNumber(commentCount, messageObject.animateComments); } messageObject.animateComments = false; commentNumberWidth = commentNumberLayout.getWidth(); totalCommentWidth += commentNumberWidth + dp(4); } else { drawCommentNumber = false; if (commentNumberLayout != null) { commentNumberLayout.setNumber(1, false); } } totalCommentWidth += dp(70 + avatarsOffset); } else { if (!isRepliesChat && commentCount > 0) { String comment = LocaleController.formatShortNumber(commentCount, null); commentWidth = totalCommentWidth = (int) Math.ceil(Theme.chat_stickerCommentCountPaint.measureText(comment)); commentLayout = new StaticLayout(comment, Theme.chat_stickerCommentCountPaint, commentWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else { commentLayout = null; } drawCommentNumber = false; drawSideButton = isRepliesChat ? 2 : 3; } } else { commentLayout = null; drawCommentNumber = false; } if (messageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { drawBackground = true; drawForwardedName = false; hasReplyQuote = false; isReplyQuote = false; isReplyTaskOrPollOption = false; replyNameLayout = null; replyTextLayout = null; drawSummaryReply = false; forwardedNameLayout[0] = null; forwardedNameLayout[1] = null; drawName = false; if (channelRecommendationsCell == null) { channelRecommendationsCell = new ChannelRecommendationsCell(this); } channelRecommendationsCell.setMessageObject(messageObject); } else if (messageObject.isExpiredStory()) { if (!messageIdChanged) { requestLayout(); } drawBackground = true; if (expiredStoryView == null) { expiredStoryView = new ExpiredStoryView(); } expiredStoryView.visible = true; expiredStoryView.measure(this); totalHeight = expiredStoryView.height + dp(8); backgroundWidth = expiredStoryView.width; measureTime(currentMessageObject); backgroundWidth += timeWidth + dp(12); drawForwardedName = false; hasReplyQuote = false; isReplyQuote = false; isReplyTaskOrPollOption = false; replyNameLayout = null; replyTextLayout = null; drawSummaryReply = false; forwardedNameLayout[0] = null; forwardedNameLayout[1] = null; drawName = false; } else if (messageObject.type == MessageObject.TYPE_TEXT || messageObject.type == MessageObject.TYPE_ARTICLE || messageObject.type == MessageObject.TYPE_STORY_MENTION || messageObject.isGiveawayOrGiveawayResults() || messageObject.isSponsored()) { drawForwardedName = !isRepliesChat; int maxWidth; boolean measuredReactions = false; final boolean isArticle = messageObject.type == MessageObject.TYPE_ARTICLE; if (AndroidUtilities.isTablet()) { maxWidth = AndroidUtilities.getMinTabletSide() - dp((isArticle ? 40 : 80) + (isSideMenuEnabled ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 42 : 0)); } else { maxWidth = Math.min(getParentWidth(), AndroidUtilities.displaySize.y) - dp((isArticle ? 40 : 80) + (isSideMenuEnabled ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 42 : 0)); } drawName = drawAvatar || isPinnedChat || isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || (messageObject.messageOwner.peer_id != null && messageObject.messageOwner.peer_id.channel_id != 0 && (!messageObject.isOutOwner() || messageObject.isSupergroup())) || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null; availableTimeWidth = maxWidth; if (messageObject.isRoundVideo()) { availableTimeWidth -= Math.ceil(Theme.chat_audioTimePaint.measureText("00:00")) + (messageObject.isOutOwner() ? 0 : dp(64)); } measureTime(messageObject); int timeMore = timeWidth + dp(6); if (messageObject.isQuickReply() && !messageObject.isSendError()) { timeMore -= dp(3); } else if (messageObject.isOutOwner()) { timeMore += dp(20.5f); } timeMore += getExtraTimeX(); hasGamePreview = MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame && MessageObject.getMedia(messageObject.messageOwner).game instanceof TLRPC.TL_game; hasInvoicePrice = hasInvoicePreview = MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice; if (hasInvoicePrice) { TLRPC.TL_messageMediaInvoice invoice = (TLRPC.TL_messageMediaInvoice) MessageObject.getMedia(messageObject.messageOwner); if (StarsController.currency.equals(invoice.currency)) { hasInvoicePrice = false; } } hasLinkPreview = !messageObject.isRestrictedMessage && MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage && MessageObject.getMedia(messageObject.messageOwner).webpage instanceof TLRPC.TL_webPage; TLRPC.WebPage webpage = hasLinkPreview ? MessageObject.getMedia(messageObject.messageOwner).webpage : null; if (messageObject.isStoryMention()) { hasLinkPreview = true; webpage = messageObject.getStoryMentionWebpage(); } drawInstantView = hasLinkPreview && webpage.cached_page != null; String siteName = hasLinkPreview ? webpage.site_name : null; hasEmbed = hasLinkPreview && !TextUtils.isEmpty(webpage.embed_url) && !messageObject.isGif() && !"instagram".equalsIgnoreCase(siteName); boolean slideshow = false; String webpageType = webpage != null ? webpage.type : null; TLRPC.Document androidThemeDocument = null; TL_stories.StoryItem storyItem = null; TLRPC.ThemeSettings androidThemeSettings = null; ArrayList stickers = null; long emoji_id = 0; TLRPC.TL_webPageAttributeStarGiftAuction starGiftAuction = null; TL_stars.StarGift stargift = null; boolean stickersTextColor = false; if (messageObject.isGiveawayOrGiveawayResults()) { hasLinkPreview = true; } instantDrawable = null; if (!drawInstantView) { if (messageObject.isUnsupported()) { drawInstantView = true; drawInstantViewType = 21; } else if (messageObject.isSponsored()) { drawInstantView = true; hasLinkPreview = true; instantViewButtonText = messageObject.sponsoredButtonText; drawInstantViewType = 1; } else if (messageObject.isGiveawayOrGiveawayResults()) { drawInstantView = true; drawInstantViewType = 19; } else if ("telegram_channel_boost".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 18; } else if ("telegram_group_boost".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 22; } else if ("telegram_giftcode".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 20; } else if ("telegram_livestream".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 11; } else if ("telegram_voicechat".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 9; } else if ("telegram_videochat".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 25; } else if ("telegram_channel".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 1; } else if ("telegram_channel_direct".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 29; } else if ("telegram_user".equals(webpageType)) { boolean isProfile = false; if (webpage != null && webpage.url != null) { Uri data = Uri.parse(webpage.url); if (data != null && data.getBooleanQueryParameter("profile", false)) { isProfile = true; } } drawInstantView = true; if (isProfile) { drawInstantViewType = INSTANT_BUTTON_TYPE_PROFILE; } else { drawInstantViewType = 13; } } else if ("telegram_aicomposetone".equals(webpageType)) { drawInstantView = true; drawInstantViewType = INSTANT_BUTTON_TYPE_AI_STYLE; final TLRPC.TL_webPageAttributeAiComposeTone attr = find(webpage.attributes, TLRPC.TL_webPageAttributeAiComposeTone.class); emoji_id = attr != null ? attr.emoji_id : 0; } else if ("telegram_nft".equals(webpageType)) { for (int b = 0, N2 = webpage.attributes.size(); b < N2; b++) { final TLRPC.WebPageAttribute attribute_ = webpage.attributes.get(b); if (!(attribute_ instanceof TLRPC.TL_webPageAttributeUniqueStarGift)) { continue; } final TLRPC.TL_webPageAttributeUniqueStarGift attribute = (TLRPC.TL_webPageAttributeUniqueStarGift) attribute_; if (attribute.gift instanceof TL_stars.TL_starGiftUnique) { drawInstantView = true; drawInstantViewType = 26; stargift = attribute.gift; } break; } } else if ("telegram_megagroup".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 2; } else if ("telegram_message".equals(webpageType) || "photo".equals(webpageType) && webpage != null && Browser.isTMe(webpage.url)) { drawInstantView = true; drawInstantViewType = 3; } else if ("telegram_community".equals(webpageType) || "telegram_chatlist".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 14; } else if ("telegram_botapp".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 15; } else if ("telegram_theme".equals(webpageType)) { for (int b = 0, N2 = MessageObject.getMedia(messageObject.messageOwner).webpage.attributes.size(); b < N2; b++) { TLRPC.WebPageAttribute attribute_ = MessageObject.getMedia(messageObject.messageOwner).webpage.attributes.get(b); if (!(attribute_ instanceof TLRPC.TL_webPageAttributeTheme)) { continue; } TLRPC.TL_webPageAttributeTheme attribute = (TLRPC.TL_webPageAttributeTheme) attribute_; ArrayList documents = attribute.documents; for (int a = 0, N = documents.size(); a < N; a++) { TLRPC.Document document = documents.get(a); if ("application/x-tgtheme-android".equals(document.mime_type)) { drawInstantView = true; drawInstantViewType = 7; androidThemeDocument = document; break; } } if (drawInstantView) { break; } if (attribute.settings != null) { drawInstantView = true; drawInstantViewType = 7; androidThemeSettings = attribute.settings; break; } } } else if ("telegram_story".equals(webpageType)) { for (int b = 0, N2 = webpage.attributes.size(); b < N2; b++) { TLRPC.WebPageAttribute attribute_ = webpage.attributes.get(b); if (!(attribute_ instanceof TLRPC.TL_webPageAttributeStory)) { continue; } drawInstantView = true; drawInstantViewType = 17; TLRPC.TL_webPageAttributeStory attribute = (TLRPC.TL_webPageAttributeStory) attribute_; storyItem = attribute.storyItem; if (storyItem != null) { storyItem.messageId = messageObject.getId(); storyItem.dialogId = DialogObject.getPeerDialogId(attribute.peer); if (storyItem instanceof TL_stories.TL_storyItemDeleted) { drawInstantView = false; hasLinkPreview = false; drawInstantViewType = 0; } } else { drawInstantView = false; hasLinkPreview = false; drawInstantViewType = 0; } break; } } else if ("telegram_background".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 6; try { Uri url = Uri.parse(MessageObject.getMedia(messageObject.messageOwner).webpage.url); imageBackgroundIntensity = Utilities.parseInt(url.getQueryParameter("intensity")); String bgColor = url.getQueryParameter("bg_color"); String rotation = url.getQueryParameter("rotation"); if (rotation != null) { imageBackgroundGradientRotation = Utilities.parseInt(rotation); } if (TextUtils.isEmpty(bgColor)) { TLRPC.Document document = messageObject.getDocument(); if (document != null && "image/png".equals(document.mime_type)) { bgColor = "ffffff"; } if (imageBackgroundIntensity == 0) { imageBackgroundIntensity = 50; } } if (bgColor != null) { imageBackgroundColor = Integer.parseInt(bgColor.substring(0, 6), 16) | 0xff000000; int averageColor = imageBackgroundColor; if (bgColor.length() >= 13 && AndroidUtilities.isValidWallChar(bgColor.charAt(6))) { imageBackgroundGradientColor1 = Integer.parseInt(bgColor.substring(7, 13), 16) | 0xff000000; averageColor = AndroidUtilities.getAverageColor(imageBackgroundColor, imageBackgroundGradientColor1); } if (bgColor.length() >= 20 && AndroidUtilities.isValidWallChar(bgColor.charAt(13))) { imageBackgroundGradientColor2 = Integer.parseInt(bgColor.substring(14, 20), 16) | 0xff000000; } if (bgColor.length() == 27 && AndroidUtilities.isValidWallChar(bgColor.charAt(20))) { imageBackgroundGradientColor3 = Integer.parseInt(bgColor.substring(21), 16) | 0xff000000; } if (imageBackgroundIntensity < 0) { imageBackgroundSideColor = 0xff111111; } else { imageBackgroundSideColor = AndroidUtilities.getPatternSideColor(averageColor); } photoImage.setColorFilter(new PorterDuffColorFilter(AndroidUtilities.getPatternColor(averageColor), PorterDuff.Mode.SRC_IN)); photoImage.setAlpha(Math.abs(imageBackgroundIntensity) / 100.0f); } else { String color = url.getLastPathSegment(); if (color != null && color.length() >= 6) { imageBackgroundColor = Integer.parseInt(color.substring(0, 6), 16) | 0xff000000; if (color.length() >= 13 && AndroidUtilities.isValidWallChar(color.charAt(6))) { imageBackgroundGradientColor1 = Integer.parseInt(color.substring(7, 13), 16) | 0xff000000; } if (color.length() >= 20 && AndroidUtilities.isValidWallChar(color.charAt(13))) { imageBackgroundGradientColor2 = Integer.parseInt(color.substring(14, 20), 16) | 0xff000000; } if (color.length() == 27 && AndroidUtilities.isValidWallChar(color.charAt(20))) { imageBackgroundGradientColor3 = Integer.parseInt(color.substring(21), 16) | 0xff000000; } currentPhotoObject = new TLRPC.TL_photoSizeEmpty(); currentPhotoObject.type = "s"; currentPhotoObject.w = dp(180); currentPhotoObject.h = dp(150); currentPhotoObject.location = new TLRPC.TL_fileLocationUnavailable(); } } } catch (Exception ignore) { } } else if ("telegram_auction".equals(webpageType)) { final TLRPC.TL_webPageAttributeStarGiftAuction attr = TlUtils.findFirstInstance(webpage.attributes, TLRPC.TL_webPageAttributeStarGiftAuction.class); drawInstantView = true; drawInstantViewType = 26; if (attr != null) { instantViewTypeIsGiftAuction = attr.gift; stargift = attr.gift; starGiftAuction = attr; } } else if ("telegram_stickerset".equals(webpageType)) { final TLRPC.TL_webPageAttributeStickerSet attr = TlUtils.findFirstInstance(webpage.attributes, TLRPC.TL_webPageAttributeStickerSet.class); drawInstantView = true; if (attr != null && attr.emojis) { drawInstantViewType = 24; } else { drawInstantViewType = 23; } isSmallImage = true; if (attr != null) { stickers = attr.stickers; stickersTextColor = attr.text_color; } } else if ("telegram_collection".equals(webpageType)) { TLRPC.TL_webPageAttributeStarGiftCollection attr = TlUtils.findFirstInstance(webpage.attributes, TLRPC.TL_webPageAttributeStarGiftCollection.class); drawInstantView = true; drawInstantViewType = 28; isSmallImage = true; if (attr != null) { stickers = attr.icons; stickersTextColor = false; } } else if ("telegram_call".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 27; } } else if (siteName != null) { siteName = siteName.toLowerCase(); if ((siteName.equals("instagram") || siteName.equals("twitter") || "telegram_album".equals(webpageType) || "telegram_story_album".equals(webpageType)) && webpage.cached_page instanceof TL_iv.TL_page && (webpage.photo instanceof TLRPC.TL_photo || MessageObject.isVideoDocument(webpage.document))) { drawInstantView = false; slideshow = true; ArrayList blocks = MessageObject.getMedia(messageObject.messageOwner).webpage.cached_page.blocks; int count = 1; for (int a = 0; a < blocks.size(); a++) { TL_iv.PageBlock block = blocks.get(a); if (block instanceof TL_iv.pageBlockSlideshow) { TL_iv.pageBlockSlideshow b = (TL_iv.pageBlockSlideshow) block; count = b.items.size(); } else if (block instanceof TL_iv.pageBlockCollage) { TL_iv.pageBlockCollage b = (TL_iv.pageBlockCollage) block; count = b.items.size(); } } String str = formatString("Of", R.string.Of, 1, count); photosCountWidth = (int) Math.ceil(Theme.chat_durationPaint.measureText(str)); photosCountLayout = new StaticLayout(str, Theme.chat_durationPaint, photosCountWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } } if (messageObject.isRepostPreview) { drawInstantView = false; } backgroundWidth = maxWidth; if (hasLinkPreview && !linkPreviewAbove || hasGamePreview || hasInvoicePreview || maxWidth - messageObject.getLastLineWidth() < timeMore) { backgroundWidth = Math.max(backgroundWidth, messageObject.getLastLineWidth()) + dp(31); backgroundWidth = Math.max(backgroundWidth, timeWidth + dp(31)); } else { int diff = backgroundWidth - messageObject.getLastLineWidth(); if (diff >= 0 && diff <= timeMore) { backgroundWidth = backgroundWidth + timeMore - diff + dp(31); } else { backgroundWidth = Math.max(backgroundWidth, messageObject.getLastLineWidth() + timeMore) + dp(31); } } availableTimeWidth = backgroundWidth - dp(31); if (messageObject.isRoundVideo()) { availableTimeWidth -= Math.ceil(Theme.chat_audioTimePaint.measureText("00:00")) + (messageObject.isOutOwner() ? 0 : dp(64)); } setMessageObjectInternal(messageObject); giveawayMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth); giveawayResultsMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth); if (messageObject.type == MessageObject.TYPE_ARTICLE) { if (messageObject.richLayout == null) { messageObject.richLayout = new RichMessageLayout(messageObject, maxWidth, null); } if (isCellAttachedToWindow()) { messageObject.richLayout.attach(this); } messageObject.richLayout.setTypingAnimator(botDraftTypingAnimator); if (botDraftTypingAnimator != null) { botDraftTypingAnimator.setBlocks(messageObject.richLayout.getAnimatorBlocks()); } backgroundWidth = messageObject.richLayout.getMinWidth() + getExtraTextX() * 2; } else if (messageObject.isSponsored()) { if (AndroidUtilities.isTablet()) { backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - dp(50), dp(270)); } else { backgroundWidth = Math.min(getParentWidth() - dp(50), dp(270)); } } else { backgroundWidth = messageObject.textWidth + getExtraTextX() * 2 + (hasGamePreview || hasInvoicePreview ? dp(10) : 0); } if (messageObject.isSponsored()) { totalHeight = dp(22.5f); } else if (messageObject.type == MessageObject.TYPE_ARTICLE) { totalHeight = messageObject.richLayout.getHeight() + dp(19.5f) + namesOffset; } else { totalHeight = messageObject.textHeight() + dp(19.5f) + namesOffset; } if (!reactionsLayoutInBubble.isSmall) { int availableWidth = maxWidth; if (messageObject.isGiveaway()) { availableWidth = giveawayMessageCell.getMeasuredWidth(); } else if (messageObject.isGiveawayResults()) { availableWidth = giveawayResultsMessageCell.getMeasuredWidth(); } measuredReactions = true; reactionsLayoutInBubble.measure(availableWidth, Gravity.LEFT); if (!reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height + dp(8); if (reactionsLayoutInBubble.width > backgroundWidth) { backgroundWidth = reactionsLayoutInBubble.width; } totalHeight += reactionsLayoutInBubble.totalHeight; } } if (drawPinnedTop) { namesOffset -= dp(1); } if (currentMessageObject != null && currentMessageObject.hasCodeAtTop && namesOffset > 0) { totalHeight += dp(5); } int maxChildWidth = backgroundWidth; maxChildWidth = Math.max(maxChildWidth, nameWidth); maxChildWidth = Math.max(maxChildWidth, sideNameWidth); maxChildWidth = Math.max(maxChildWidth, forwardedNameWidth); maxChildWidth = Math.max(maxChildWidth, replyNameWidth); maxChildWidth = Math.max(maxChildWidth, ephemeralWidth); if (drawSummaryReply && summaryTitle != null && summarySubtitle != null) { maxChildWidth = Math.max(maxChildWidth, dp(20) + (int) Math.max(summaryTitle.getWidth(), summarySubtitle.getWidth())); } maxChildWidth = Math.max(maxChildWidth, replyTextWidth); if (commentLayout != null && drawSideButton != 3) { maxChildWidth = Math.max(maxChildWidth, totalCommentWidth); } int maxWebWidth = 0; if (hasLinkPreview || hasGamePreview || hasInvoicePreview) { int linkPreviewMaxWidth; if (currentMessageObject.isRepostPreview) { linkPreviewMaxWidth = currentMessageObject.getMaxMessageTextWidth(); } else if (AndroidUtilities.isTablet()) { linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - dp(80 + (isSideMenued ? 68 : drawAvatar ? 52 : 0)); } else { linkPreviewMaxWidth = getParentWidth() - dp(80 + (isSideMenued ? 68 : drawAvatar ? 52 : 0)); } if (drawSideButton != 0) { linkPreviewMaxWidth -= dp(currentMessageObject.isSaved && currentMessageObject.isOutOwner() ? 25 : 20); } int site_name_additionalWidth = 0; CharSequence site_name; CharSequence titleLabel = null; String title; CharSequence author; String description; TLObject peerPhoto = null; TLRPC.Photo photo; TLRPC.Document document; TLRPC.Photo documentCover = null; WebFile webDocument; int duration; boolean smallImage; String type; final int smallImageSide = dp(48), smallSideMargin = dp(10); CharSequence overrideDescrption = null; if (messageObject.isSponsored()) { if (messageObject.sponsoredCanReport) { site_name = getString(R.string.SponsoredMessageAd); titleLabel = getString(R.string.SponsoredMessageAdWhatIsThis); } else if (messageObject.sponsoredRecommended) { site_name = getString(R.string.SponsoredMessage2Recommended); } else { site_name = getString(R.string.SponsoredMessage2); } title = messageObject.customName != null ? messageObject.customName : getAuthorName(); webDocument = null; overrideDescrption = messageObject.messageText; description = overrideDescrption != null ? overrideDescrption.toString() : null; author = null; document = null; photo = messageObject.sponsoredPhoto; isSmallImage = photo != null || peerPhoto != null; smallImage = true; duration = 0; type = null; if (messageObject.sponsoredMedia != null) { if (messageObject.sponsoredMedia instanceof TLRPC.TL_messageMediaDocument) { TLRPC.TL_messageMediaDocument media = (TLRPC.TL_messageMediaDocument) messageObject.sponsoredMedia; document = media.document; duration = (int) MessageObject.getDocumentDuration(media.document); } else if (messageObject.sponsoredMedia instanceof TLRPC.TL_messageMediaPhoto) { TLRPC.TL_messageMediaPhoto media = (TLRPC.TL_messageMediaPhoto) messageObject.sponsoredMedia; photo = media.photo; } smallImage = false; isSmallImage = false; } linkPreviewAbove = false; } else if (drawInstantViewType == 19) { site_name = null; title = null; webDocument = null; description = null; photo = null; author = null; document = null; duration = 0; type = null; isSmallImage = false; linkPreviewAbove = false; smallImage = false; } else if (drawInstantViewType == 17) { site_name = null; TLRPC.User user = storyItem == null ? null : MessagesController.getInstance(currentAccount).getUser(storyItem.dialogId); if (storyItem instanceof TL_stories.TL_storyItemDeleted) { site_name_additionalWidth += dp(14); site_name = StoriesUtilities.createExpiredStoryString(); } else if (user != null) { site_name = UserObject.getUserName(user); } else { site_name = webpage == null ? null : webpage.title; } title = null; description = storyItem != null ? storyItem.caption : (webpage == null ? null : webpage.description); author = null; document = storyItem != null && storyItem.media != null && storyItem.media.document != null ? storyItem.media.document : (webpage == null ? null : webpage.document); photo = storyItem != null && storyItem.media != null && storyItem.media.photo != null ? storyItem.media.photo : (webpage == null ? null : webpage.photo); webDocument = null; type = webpage == null ? null : webpage.type; duration = storyItem != null && storyItem.media != null && storyItem.media.document != null ? (int) MessageObject.getDocumentDuration(storyItem.media.document) : 0; smallImage = false; isSmallImage = false; linkPreviewAbove = currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.invert_media; } else if (hasLinkPreview) { TLRPC.TL_webPage webPage = (TLRPC.TL_webPage) webpage; site_name = webPage.site_name; title = drawInstantViewType != 6 && drawInstantViewType != 7 ? webPage.title : null; if (instantViewTypeIsGiftAuction != null) { if (instantViewTypeIsGiftAuction.auction_start_date > ConnectionsManager.getInstance(currentAccount).getCurrentTime()) { title = getString(R.string.Gift2LinkUpcomingAuction); } else { title = getString(R.string.Gift2LinkGiftAuction); } } author = drawInstantViewType != 6 && drawInstantViewType != 7 ? webPage.author : null; description = drawInstantViewType != 6 && drawInstantViewType != 7 ? webPage.description : null; photo = webPage.photo; webDocument = null; if (drawInstantViewType == 7) { if (androidThemeSettings != null) { document = new DocumentObject.ThemeDocument(androidThemeSettings); } else { document = androidThemeDocument; } } else { document = webPage.document; } if (photo != null && document != null && webPage.video_cover_photo) { documentCover = photo; photo = null; } type = webPage.type; duration = webPage.duration; if (site_name != null && photo != null && site_name.toString().toLowerCase().equals("instagram")) { linkPreviewMaxWidth = Math.max(AndroidUtilities.displaySize.y / 3, currentMessageObject.textWidth); } final boolean isSmallImageType = isSmallImageLinkPreviewType(type); smallImage = !slideshow && (!drawInstantView || drawInstantViewType == 1 || drawInstantViewType == 29 || drawInstantViewType == 2 || drawInstantViewType == 9 || drawInstantViewType == 11 || drawInstantViewType == 25 || drawInstantViewType == 13 || drawInstantViewType == 18 || drawInstantViewType == 20 || drawInstantViewType == 22 || drawInstantViewType == INSTANT_BUTTON_TYPE_PROFILE || drawInstantViewType == INSTANT_BUTTON_TYPE_AI_STYLE) && document == null && isSmallImageType || (drawInstantViewType == 23 || drawInstantViewType == 24 || drawInstantViewType == 28) && stickers != null && !stickers.isEmpty(); TLRPC.MessageMedia media = MessageObject.getMedia(messageObject.messageOwner); if (media != null && !(drawInstantViewType == 23 || drawInstantViewType == 24 || drawInstantViewType == 28 || drawInstantViewType == 25)) { if (media.force_large_media) { smallImage = false; } if (media.force_small_media) { smallImage = true; } } linkPreviewAbove = currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.invert_media; isSmallImage = smallImage && type != null && currentMessageObject.photoThumbs != null || (drawInstantViewType == 23 || drawInstantViewType == 24 || drawInstantViewType == 28) && stickers != null && !stickers.isEmpty() || emoji_id != 0; } else if (hasInvoicePreview) { TLRPC.TL_messageMediaInvoice invoice = (TLRPC.TL_messageMediaInvoice) MessageObject.getMedia(messageObject.messageOwner); site_name = MessageObject.getMedia(messageObject.messageOwner).title; title = null; description = null; photo = null; author = null; document = null; if (invoice.webPhoto instanceof TLRPC.TL_webDocument) { webDocument = WebFile.createWithWebDocument(invoice.webPhoto); } else { webDocument = null; } duration = 0; type = "invoice"; isSmallImage = false; linkPreviewAbove = false; smallImage = false; } else { TLRPC.TL_game game = MessageObject.getMedia(messageObject.messageOwner).game; site_name = game.title; title = null; webDocument = null; description = TextUtils.isEmpty(messageObject.messageText) ? game.description : null; photo = game.photo; author = null; document = game.document; duration = 0; type = "game"; isSmallImage = false; linkPreviewAbove = false; smallImage = false; } if (drawInstantViewType == 18) { site_name = getString("BoostChannel", R.string.BoostChannel); } else if (drawInstantViewType == 22) { site_name = getString("BoostGroup", R.string.BoostGroup); } else if (drawInstantViewType == 11) { site_name = getString("VoipChannelVoiceChat", R.string.VoipChannelVoiceChat); } else if (drawInstantViewType == 25) { site_name = getString("VoipGroupVoiceChat", R.string.VoipGroupVoiceChat); } else if (drawInstantViewType == 9) { site_name = getString("VoipGroupVideoChat", R.string.VoipGroupVideoChat); } else if (drawInstantViewType == 6) { site_name = getString("ChatBackground", R.string.ChatBackground); } else if ("telegram_theme".equals(webpageType)) { site_name = getString("ColorTheme", R.string.ColorTheme); } if (stargift != null) { description = null; } int additinalWidth = dp(20); if (hasInvoicePreview) { additinalWidth = 0; } if (drawInstantViewType == 17) { additinalWidth += dp(20); } int restLinesCount = 3; linkPreviewMaxWidth -= additinalWidth; if (currentMessageObject.photoThumbs == null && photo != null) { currentMessageObject.generateThumbs(true); } totalHeight += giveawayMessageCell.getMeasuredHeight(); linkPreviewHeight += giveawayMessageCell.getMeasuredHeight(); totalHeight += giveawayResultsMessageCell.getMeasuredHeight(); linkPreviewHeight += giveawayResultsMessageCell.getMeasuredHeight(); maxChildWidth = Math.max(maxChildWidth, giveawayMessageCell.getMeasuredWidth()); maxChildWidth = Math.max(maxChildWidth, giveawayResultsMessageCell.getMeasuredWidth()); if (site_name != null) { try { int width = (int) Math.ceil(Theme.chat_replyNamePaint.measureText(site_name.toString()) + 1 + site_name_additionalWidth); int restLines = 0; if (!isSmallImage) { siteNameLayout = new StaticLayout(site_name, Theme.chat_replyNamePaint, Math.min(width, linkPreviewMaxWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else { restLines = restLinesCount; siteNameLayout = generateStaticLayout(site_name, Theme.chat_replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - smallImageSide - smallSideMargin, restLinesCount, 1); restLinesCount -= siteNameLayout.getLineCount(); } siteNameLeft = siteNameLayout.getWidth(); siteNameLayoutWidth = 0; for (int i = 0; i < siteNameLayout.getLineCount(); ++i) { int left = (int) siteNameLayout.getLineLeft(i); if (i > 0 && (siteNameLeft == 0) != (left == 0)) { siteNameLayoutWidth = siteNameLayout.getWidth(); } siteNameLeft = Math.min(siteNameLeft, left); siteNameLayoutWidth = Math.max(siteNameLayoutWidth, siteNameLayout.getLineWidth(i)); } int height = siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1); linkPreviewHeight += height; totalHeight += height; int layoutWidth = 0; for (int a = 0; a < siteNameLayout.getLineCount(); ++a) { int lineLeft = (int) Math.max(0, siteNameLayout.getLineLeft(a)); int lineWidth; if (lineLeft != 0) { lineWidth = siteNameLayout.getWidth() - lineLeft; } else { int max = linkPreviewMaxWidth; if (a < restLines || lineLeft != 0 && isSmallImage) { max -= smallImageSide + smallSideMargin; } lineWidth = (int) Math.min(max, Math.ceil(siteNameLayout.getLineWidth(a))); } if (a < restLines || lineLeft != 0 && isSmallImage) { lineWidth += smallImageSide + smallSideMargin; } layoutWidth = Math.max(layoutWidth, lineWidth); } siteNameWidth = width = layoutWidth; maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); maxWebWidth = Math.max(maxWebWidth, width + additinalWidth); } catch (Exception e) { FileLog.e(e); } } if (titleLabel != null) { try { int width = (int) Math.ceil(Theme.chat_titleLabelTextPaint.measureText(titleLabel.toString())); titleLabelLayout = new StaticLayout(titleLabel, Theme.chat_titleLabelTextPaint, Math.min(width, linkPreviewMaxWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); titleLabelLayoutWidth = titleLabelLayout.getLineWidth(0); titleLabelLayoutHeight = titleLabelLayout.getLineBottom(0); maxChildWidth = Math.max(maxChildWidth, siteNameWidth + width + additinalWidth); maxWebWidth = Math.max(maxWebWidth, siteNameWidth + width + additinalWidth); } catch (Exception e) { FileLog.e(e); } } boolean titleIsRTL = false; if (title != null) { try { titleX = Integer.MAX_VALUE; if (linkPreviewHeight != 0) { linkPreviewHeight += dp(2); totalHeight += dp(2); } int restLines = 0; CharSequence titleCs = title; try { titleCs = Emoji.replaceEmoji(title, Theme.chat_replyNamePaint.getFontMetricsInt(), false); } catch (Exception ignore) { } int maxLines = 4; if (currentMessageObject.isRepostPreview) { maxLines = 1; } if (!isSmallImage) { titleLayout = StaticLayoutEx.createStaticLayout(titleCs, Theme.chat_replyNamePaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, maxLines); } else { restLines = restLinesCount; titleLayout = generateStaticLayout(titleCs, Theme.chat_replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - smallImageSide - smallSideMargin, restLinesCount, maxLines); restLinesCount -= titleLayout.getLineCount(); } titleLayoutWidth = 0; titleLayoutLeft = titleLayout.getWidth(); for (int a = 0; a < titleLayout.getLineCount(); a++) { titleLayoutLeft = (int) Math.min(titleLayoutLeft, titleLayout.getLineLeft(a)); float width = titleLayout.getLineWidth(a); if (a < restLines || titleLayoutLeft != 0 && isSmallImage) { width += smallImageSide + smallSideMargin; } titleLayoutWidth = (int) Math.max(titleLayoutWidth, width); } maxChildWidth = Math.max(maxChildWidth, titleLayoutWidth + additinalWidth); maxWebWidth = Math.max(maxWebWidth, titleLayoutWidth + additinalWidth); titleIsRTL = titleLayoutLeft != 0; int height = titleLayout.getLineBottom(titleLayout.getLineCount() - 1); linkPreviewHeight += height; totalHeight += height; } catch (Exception e) { FileLog.e(e); } } if (titleIsRTL && isSmallImage) { linkPreviewMaxWidth -= dp(48); } if (author != null && title == null) { try { if (linkPreviewHeight != 0) { linkPreviewHeight += dp(2); totalHeight += dp(2); } try { author = Emoji.replaceEmoji(author, Theme.chat_replyNamePaint.getFontMetricsInt(), false); } catch (Exception ignore) { } if (restLinesCount == 3 && (!isSmallImage || description == null)) { authorLayout = new StaticLayout(author, Theme.chat_replyNamePaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else { authorLayout = generateStaticLayout(author, Theme.chat_replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - smallImageSide - smallSideMargin, restLinesCount, 1); restLinesCount -= authorLayout.getLineCount(); } authorLayoutLeft = authorLayout.getWidth(); authorLayoutWidth = 0; for (int i = 0; i < authorLayout.getLineCount(); ++i) { int left = (int) authorLayout.getLineLeft(i); if (i > 0 && (authorLayoutLeft == 0) != (left == 0)) { authorLayoutWidth = authorLayout.getWidth(); } authorLayoutLeft = (int) Math.min(authorLayoutLeft, left); authorLayoutWidth = (int) Math.max(authorLayoutWidth, authorLayout.getLineWidth(i)); } int height = authorLayout.getLineBottom(authorLayout.getLineCount() - 1); linkPreviewHeight += height; totalHeight += height; maxChildWidth = Math.max(maxChildWidth, authorLayoutWidth + additinalWidth); maxWebWidth = Math.max(maxWebWidth, authorLayoutWidth + additinalWidth); } catch (Exception e) { FileLog.e(e); } } if (description != null) { try { descriptionX = 0; currentMessageObject.generateLinkDescription(); if (linkPreviewHeight != 0) { linkPreviewHeight += dp(2); totalHeight += dp(2); } int restLines = 0; boolean allowAllLines = site_name != null && site_name.toString().toLowerCase().equals("twitter"); CharSequence text = overrideDescrption != null ? overrideDescrption : messageObject.linkDescription; boolean isRTL = AndroidUtilities.isRTL(text); int maxLines = allowAllLines ? 100 : (currentMessageObject.isRepostPreview ? 3 : 6); if (restLinesCount == 3 && !isSmallImage) { descriptionLayout = StaticLayoutEx.createStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, maxLines); } else { restLines = restLinesCount; descriptionLayout = generateStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth - (isRTL ? smallImageSide + 2 * smallSideMargin : 0), linkPreviewMaxWidth - smallImageSide - 2 * smallSideMargin, restLinesCount, maxLines); } animatedEmojiDescriptionStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiDescriptionStack, descriptionLayout); int height = descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); linkPreviewHeight += height; totalHeight += height; descriptionLayoutWidth = 0; int descriptionLayoutLeft = descriptionLayout.getWidth(), descriptionLayoutRight = 0; for (int a = 0; a < descriptionLayout.getLineCount(); a++) { descriptionLayoutLeft = (int) Math.min(descriptionLayoutLeft, descriptionLayout.getLineLeft(a)); int addright = 0; if (a < restLines || restLines != 0 && descriptionLayoutLeft != 0 && isSmallImage) { addright = smallImageSide + smallSideMargin; } descriptionLayoutRight = (int) Math.max(descriptionLayoutRight, descriptionLayout.getLineRight(a) + addright); } descriptionLayoutWidth = Math.abs(descriptionLayoutRight - descriptionLayoutLeft); this.descriptionLayoutLeft = descriptionLayoutLeft; if (maxWebWidth < descriptionLayoutWidth + additinalWidth) { maxWebWidth = descriptionLayoutWidth + additinalWidth; } maxChildWidth = Math.max(maxChildWidth, descriptionLayoutWidth + additinalWidth); } catch (Exception e) { FileLog.e(e); } } if (smallImage && (descriptionLayout == null && titleLayout == null)) { smallImage = false; isSmallImage = false; } int maxPhotoWidth = smallImage ? smallImageSide : linkPreviewMaxWidth; if (drawInstantViewType == 17) { if (storyItem != null && storyItem.media != null) { int side = (int) (maxPhotoWidth * 16f / 9f); if (storyItem.media.document != null) { document = storyItem.media.document; currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, side); if (currentMessageObject.strippedThumb == null) { currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 40); } else { currentPhotoObjectThumbStripped = currentMessageObject.strippedThumb; } if (currentPhotoObject != null && (currentPhotoObject.w == 0 || currentPhotoObject.h == 0)) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { currentPhotoObject.w = attribute.w; currentPhotoObject.h = attribute.h; break; } } if (currentPhotoObject.w == 0 || currentPhotoObject.h == 0) { currentPhotoObject.w = dp(150); currentPhotoObject.h = (int) (currentPhotoObject.w / 9f * 16f); } } documentAttach = document; } else if (storyItem.media.photo != null) { photo = storyItem.media.photo; currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, side); if (currentMessageObject.strippedThumb == null) { currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 40); } else { currentPhotoObjectThumbStripped = currentMessageObject.strippedThumb; } } photoParentObject = storyItem; documentAttachType = DOCUMENT_ATTACH_TYPE_STORY; } } else if (document != null) { if (MessageObject.isRoundVideoDocument(document)) { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); photoParentObject = document; documentAttach = document; isSmallImage = smallImage = false; documentAttachType = DOCUMENT_ATTACH_TYPE_ROUND; } else if (MessageObject.isGifDocument(document, messageObject.hasValidGroupId())) { if (!messageObject.isGame() && !(SharedConfig.isAutoplayGifs() && !messageObject.isRepostPreview)) { messageObject.gifState = 1; } photoImage.setAllowStartAnimation(messageObject.gifState != 1); currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); if (currentPhotoObject != null) { photoParentObject = document; } else if (photo != null) { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 90); photoParentObject = photo; } if (currentPhotoObject != null && (currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || currentPhotoObject.w == 0 || currentPhotoObject.h == 0)) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeImageSize || attribute instanceof TLRPC.TL_documentAttributeVideo) { currentPhotoObject.w = attribute.w; currentPhotoObject.h = attribute.h; break; } } if (currentPhotoObject.w == 0 || currentPhotoObject.h == 0) { currentPhotoObject.w = currentPhotoObject.h = dp(150); } } documentAttach = document; documentAttachType = DOCUMENT_ATTACH_TYPE_GIF; } else if (MessageObject.isVideoDocument(document)) { if (documentCover != null) { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(documentCover.sizes, AndroidUtilities.getPhotoSize(), true); currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(documentCover.sizes, 40); photoParentObject = documentCover; } else if (photo != null) { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, AndroidUtilities.getPhotoSize(), true); currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 40); photoParentObject = photo; } if (currentPhotoObject == null) { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 320); currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 40); photoParentObject = document; } if (currentPhotoObject == currentPhotoObjectThumb) { currentPhotoObjectThumb = null; } if (currentMessageObject.strippedThumb != null) { currentPhotoObjectThumb = null; currentPhotoObjectThumbStripped = currentMessageObject.strippedThumb; } if (currentPhotoObject == null) { currentPhotoObject = new TLRPC.TL_photoSize(); currentPhotoObject.type = "s"; currentPhotoObject.location = new TLRPC.TL_fileLocationUnavailable(); } if (currentPhotoObject != null && (currentPhotoObject.w == 0 || currentPhotoObject.h == 0 || currentPhotoObject instanceof TLRPC.TL_photoStrippedSize)) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeVideo) { if (currentPhotoObject instanceof TLRPC.TL_photoStrippedSize) { float scale = Math.max(attribute.w, attribute.w) / 50.0f; currentPhotoObject.w = (int) (attribute.w / scale); currentPhotoObject.h = (int) (attribute.h / scale); } else { currentPhotoObject.w = attribute.w; currentPhotoObject.h = attribute.h; } break; } } if (currentPhotoObject.w == 0 || currentPhotoObject.h == 0) { currentPhotoObject.w = currentPhotoObject.h = dp(150); } } createDocumentLayout(0, messageObject); } else if (MessageObject.isStickerDocument(document) || MessageObject.isAnimatedStickerDocument(document, true)) { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); photoParentObject = document; if (currentPhotoObject != null && (currentPhotoObject.w == 0 || currentPhotoObject.h == 0)) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { currentPhotoObject.w = attribute.w; currentPhotoObject.h = attribute.h; break; } } if (currentPhotoObject.w == 0 || currentPhotoObject.h == 0) { currentPhotoObject.w = currentPhotoObject.h = dp(150); } } documentAttach = document; isSmallImage = smallImage = false; documentAttachType = DOCUMENT_ATTACH_TYPE_STICKER; } else if (drawInstantViewType == 6) { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 320); photoParentObject = document; if (currentPhotoObject != null && (currentPhotoObject.w == 0 || currentPhotoObject.h == 0)) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { currentPhotoObject.w = attribute.w; currentPhotoObject.h = attribute.h; break; } } if (currentPhotoObject.w == 0 || currentPhotoObject.h == 0) { currentPhotoObject.w = currentPhotoObject.h = dp(150); } } documentAttach = document; isSmallImage = smallImage = false; documentAttachType = DOCUMENT_ATTACH_TYPE_WALLPAPER; String str = AndroidUtilities.formatFileSize(documentAttach.size); durationWidth = (int) Math.ceil(Theme.chat_durationPaint.measureText(str)); videoInfoLayout = new StaticLayout(str, Theme.chat_durationPaint, durationWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else if (drawInstantViewType == 7) { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 700); if (currentMessageObject.strippedThumb == null) { currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 40); } else { currentPhotoObjectThumbStripped = currentMessageObject.strippedThumb; } photoParentObject = document; if (currentPhotoObject != null && (currentPhotoObject.w == 0 || currentPhotoObject.h == 0)) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { currentPhotoObject.w = attribute.w; currentPhotoObject.h = attribute.h; break; } } if (currentPhotoObject.w == 0 || currentPhotoObject.h == 0) { currentPhotoObject.w = currentPhotoObject.h = dp(150); } } isSmallImage = smallImage = false; documentAttach = document; documentAttachType = DOCUMENT_ATTACH_TYPE_THEME; } else { calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); if (backgroundWidth < maxWidth + dp(20)) { backgroundWidth = maxWidth + dp(20); } if (MessageObject.isVoiceDocument(document)) { createDocumentLayout(backgroundWidth - dp(10), messageObject); mediaOffsetY = (linkPreviewAbove ? 0 : currentMessageObject.textHeight(transitionParams)) + dp(8) + linkPreviewHeight; totalHeight += dp(44 + (hasLinkPreview ? 4 : (linkPreviewAbove ? -4 : 0))); linkPreviewHeight += dp(44 + (hasLinkPreview ? 4 : 0)); maxWidth = maxWidth - dp(86); if (AndroidUtilities.isTablet()) { maxChildWidth = Math.max(maxChildWidth, Math.min(AndroidUtilities.getMinTabletSide() - dp(isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0), dp(220)) - dp(30) + additinalWidth); } else { maxChildWidth = Math.max(maxChildWidth, Math.min(getParentWidth() - dp(isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0), dp(220)) - dp(30) + additinalWidth); } calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); } else if (MessageObject.isMusicDocument(document)) { int durationWidth = createDocumentLayout(backgroundWidth - dp(10), messageObject); mediaOffsetY = (linkPreviewAbove ? 0 : currentMessageObject.textHeight(transitionParams)) + dp(8) + linkPreviewHeight; totalHeight += dp(56 + (linkPreviewAbove ? -4 : 0)); linkPreviewHeight += dp(60); maxWidth = maxWidth - dp(86); maxChildWidth = Math.max(maxChildWidth, durationWidth + additinalWidth + dp(86 + 8)); if (songLayout != null && songLayout.getLineCount() > 0) { maxChildWidth = (int) Math.max(maxChildWidth, songLayout.getLineWidth(0) + additinalWidth + dp(86)); } if (performerLayout != null && performerLayout.getLineCount() > 0) { maxChildWidth = (int) Math.max(maxChildWidth, performerLayout.getLineWidth(0) + additinalWidth + dp(86)); } calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); } else { createDocumentLayout(backgroundWidth - dp(86 + 24 + 58), messageObject); drawImageButton = true; if (drawPhotoImage) { totalHeight += dp(86 + 14); linkPreviewHeight += dp(86); photoImage.setImageCoords(0, totalHeight + namesOffset, dp(86), dp(86)); } else { mediaOffsetY = (linkPreviewAbove ? 0 : currentMessageObject.textHeight(transitionParams)) + dp(8) + linkPreviewHeight; photoImage.setImageCoords(0, totalHeight + namesOffset - dp(14), dp(56), dp(56)); totalHeight += dp(50 + 14 + (linkPreviewAbove ? -4 : 0)); linkPreviewHeight += dp(50); if (docTitleLayout != null && docTitleLayout.getLineCount() > 1) { int h = (docTitleLayout.getLineCount() - 1) * dp(16); totalHeight += h; linkPreviewHeight += h; } } } } } else if (peerPhoto != null) { checkOnlyButtonPressed = false; if (peerPhoto instanceof TLRPC.User) { TLRPC.UserProfilePhoto userProfilePhoto = ((TLRPC.User) peerPhoto).photo; photoParentObject = userProfilePhoto; currentPhotoObjectThumbStripped = userProfilePhoto.strippedBitmap; } else if (peerPhoto instanceof TLRPC.Chat) { TLRPC.ChatPhoto chatPhoto = ((TLRPC.Chat) peerPhoto).photo; photoParentObject = chatPhoto; currentPhotoObjectThumbStripped = chatPhoto.strippedBitmap; } } else if (photo != null) { boolean isPhoto = type != null && type.equals("photo"); currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, isPhoto || !smallImage ? AndroidUtilities.getPhotoSize() : maxPhotoWidth, !isPhoto); photoParentObject = messageObject.photoThumbsObject; checkOnlyButtonPressed = !isPhoto; if (currentMessageObject.strippedThumb == null) { currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40); } else { currentPhotoObjectThumbStripped = currentMessageObject.strippedThumb; } if (currentPhotoObjectThumb == currentPhotoObject) { currentPhotoObjectThumb = null; } } else if (webDocument != null) { if (!webDocument.mime_type.startsWith("image/")) { webDocument = null; } drawImageButton = false; } if (documentAttachType != DOCUMENT_ATTACH_TYPE_MUSIC && documentAttachType != DOCUMENT_ATTACH_TYPE_AUDIO && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { if (stargift != null) { final int size = dp(220); drawImageButton = false; drawPhotoImage = true; if (linkPreviewHeight != 0) { linkPreviewHeight += dp(2); totalHeight += dp(2); } totalHeight += size + dp(12); linkPreviewHeight += size; maxChildWidth = Math.max(maxChildWidth, size + additinalWidth); photoImage.setImageCoords(0, 0, size, size); currentPhotoFilter = "220_220"; currentPhotoFilterThumb = "220_220_b"; StarGiftSheet.StarGiftDrawableIcon starGiftDrawableIcon = new StarGiftSheet.StarGiftDrawableIcon(this, stargift, 220, 1.0f).setRounding(dp(12)).setPatternsType(StarGiftPatterns.TYPE_LINK_PREVIEW); if (starGiftAuction != null) { starGiftDrawableIcon.setGradient(starGiftAuction.center_color, starGiftAuction.edge_color); starGiftDrawableIcon.setAuctionStateTextColor(starGiftAuction.text_color); starGiftDrawableIcon.setCountdownRemainingTime(starGiftAuction.gift.auction_start_date, starGiftAuction.end_date); } photoImage.setImageBitmap(starGiftDrawableIcon); clearBlurredImage(blurredPhotoImage); } else if (currentPhotoObject != null || currentPhotoLocation != null || webDocument != null || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || documentAttachType == DOCUMENT_ATTACH_TYPE_THEME || (drawInstantViewType == 23 || drawInstantViewType == 24 || drawInstantViewType == 28) && stickers != null && !stickers.isEmpty() || emoji_id != 0) { drawImageButton = photo != null && !smallImage || type != null && (type.equals("photo") || type.equals("document") && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER || type.equals("gif") || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER); if (isSmallImage) { drawImageButton = false; } if (linkPreviewHeight != 0) { linkPreviewHeight += dp(2); totalHeight += dp(2); } if (emoji_id != 0) { maxPhotoWidth = dp(45); } else if (imageBackgroundSideColor != 0) { maxPhotoWidth = dp(208); } else if (currentPhotoObject instanceof TLRPC.TL_photoSizeEmpty && currentPhotoObject.w != 0) { maxPhotoWidth = currentPhotoObject.w; } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || documentAttachType == DOCUMENT_ATTACH_TYPE_THEME) { if (AndroidUtilities.isTablet()) { maxPhotoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.5f); } else { maxPhotoWidth = (int) (getParentWidth() * 0.5f); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { maxPhotoWidth = AndroidUtilities.roundMessageSize; photoImage.setAllowDecodeSingleFrame(true); } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_STORY) { maxPhotoWidth /= 2; } if (hasInvoicePreview && maxPhotoWidth < messageObject.textWidth) { maxPhotoWidth = messageObject.textWidth + dp(22); } maxChildWidth = Math.max(maxChildWidth, maxPhotoWidth - (hasInvoicePreview ? dp(12) : 0) + additinalWidth); if (currentPhotoObject != null) { currentPhotoObject.size = -1; if (currentPhotoObjectThumb != null) { currentPhotoObjectThumb.size = -1; } } else if (webDocument != null) { webDocument.size = -1; } if (imageBackgroundSideColor != 0) { imageBackgroundSideWidth = maxChildWidth - dp(13); } int width; int height; if (smallImage || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { width = height = maxPhotoWidth; photoImage.setInvalidateAll(true); } else { if (hasGamePreview || hasInvoicePreview) { if (hasInvoicePreview) { width = 640; height = 360; for (int a = 0, N = webDocument.attributes.size(); a < N; a++) { TLRPC.DocumentAttribute attribute = webDocument.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { width = attribute.w; height = attribute.h; break; } } } else { width = 640; height = 360; } float scale = width / (float) (maxPhotoWidth - dp(2)); width /= scale; height /= scale; } else { if (drawInstantViewType == 7) { width = 560; height = 678; } else if (currentPhotoObject != null) { width = currentPhotoObject.w; height = currentPhotoObject.h; } else { width = 30; height = 50; } float scale = width / (float) (maxPhotoWidth - dp(2)); width /= scale; height /= scale; if (site_name == null || site_name != null && !site_name.toString().toLowerCase().equals("instagram") && documentAttachType == 0) { if (height > AndroidUtilities.displaySize.y / 3) { height = AndroidUtilities.displaySize.y / 3; } } else { if (height > AndroidUtilities.displaySize.y / 2) { height = AndroidUtilities.displaySize.y / 2; } } if (imageBackgroundSideColor != 0) { scale = height / (float) dp(160); width /= scale; height /= scale; } if (height < dp(60)) { height = dp(60); } } } if (isSmallImage) { if (dp(50) > linkPreviewHeight) { totalHeight += dp(50) - linkPreviewHeight + dp(8); linkPreviewHeight = dp(50); } linkPreviewHeight -= dp(8); } else { totalHeight += height + dp(12); linkPreviewHeight += height; } if (documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER && imageBackgroundSideColor == 0) { photoImage.setImageCoords(0, 0, Math.max(maxChildWidth - dp(13), width), height); } else { photoImage.setImageCoords(0, 0, width, height); } int w = (int) (width / AndroidUtilities.density); int h = (int) (height / AndroidUtilities.density); currentPhotoFilter = String.format(Locale.US, "%d_%d", w, h); currentPhotoFilterThumb = String.format(Locale.US, "%d_%d_b", w, h); if (emoji_id != 0) { photoImage.setImageBitmap(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES_LARGE, currentAccount, emoji_id)); } else if ((drawInstantViewType == 23 || drawInstantViewType == 24 || drawInstantViewType == 28) && stickers != null && !stickers.isEmpty()) { if (stickerSetIcons == null || !stickerSetIcons.equals(stickers)) { if (stickerSetIcons != null) { stickerSetIcons.detach(this); } stickerSetIcons = new StickerSetLinkIcon(currentAccount, currentMessageObject.isOutOwner(), stickers, stickersTextColor); if (attachedToWindow) { stickerSetIcons.attach(this); } } if (stickerSetIcons != null) { stickerSetIcons.keepAlive(); } photoImage.setImageBitmap(stickerSetIcons); } else if (webDocument != null) { /*TODO*/ photoImage.setImage(ImageLocation.getForWebFile(webDocument), currentPhotoFilter, null, null, webDocument.size, null, messageObject, 1); } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER) { if (messageObject.mediaExists) { photoImage.setImage(ImageLocation.getForDocument(documentAttach), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObject, document), "b1", 0, "jpg", messageObject, 1); } else { photoImage.setImage(null, null, ImageLocation.getForDocument(currentPhotoObject, document), "b1", 0, "jpg", messageObject, 1); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_THEME) { if (document instanceof DocumentObject.ThemeDocument) { photoImage.setImage(ImageLocation.getForDocument(document), currentPhotoFilter, null, "b1", 0, "jpg", messageObject, 1); } else { photoImage.setImage(ImageLocation.getForDocument(currentPhotoObject, document), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObjectThumb, document), "b1", currentPhotoObjectThumbStripped, 0, "jpg", messageObject, 1); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_STORY) { if (document != null) { photoImage.setImage(ImageLocation.getForDocument(currentPhotoObject, document), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObjectThumb, document), "b1", currentPhotoObjectThumbStripped, 0, "jpg", messageObject, 1); } else if (photo != null) { photoImage.setImage(ImageLocation.getForPhoto(currentPhotoObject, photo), currentPhotoFilter, ImageLocation.getForPhoto(currentPhotoObjectThumb, photo), "b1", currentPhotoObjectThumbStripped, 0, "jpg", messageObject, 1); } if (currentPhotoObject != null && (currentPhotoObject.gradientTopColor != 0 && currentPhotoObject.gradientBottomColor != 0)) { gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[] { currentPhotoObject.gradientTopColor, currentPhotoObject.gradientBottomColor }); } else if (currentPhotoObjectThumbStripped != null && currentPhotoObjectThumbStripped.getBitmap() != null) { final int[] colors = DominantColors.getColorsSync(false, currentPhotoObjectThumbStripped.getBitmap(), Theme.isCurrentThemeDark()); gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors); if (currentPhotoObject != null) { currentPhotoObject.gradientTopColor = colors[0]; currentPhotoObject.gradientBottomColor = colors[1]; } } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER) { boolean isWebpSticker = messageObject.isSticker(); if (!SharedConfig.loopStickers() && messageObject.isVideoSticker()) { photoImage.animatedFileDrawableRepeatMaxCount = 1; } if (SharedConfig.loopStickers() || (isWebpSticker && !messageObject.isVideoSticker())) { photoImage.setAutoRepeat(1); } else { currentPhotoFilter = String.format(Locale.US, "%d_%d_nr_messageId=%d", w, h, messageObject.stableId); photoImage.setAutoRepeat(delegate != null && delegate.shouldRepeatSticker(messageObject) ? 2 : 3); } photoImage.setImage(ImageLocation.getForDocument(documentAttach), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObject, documentAttach), "b1", documentAttach.size, "webp", messageObject, 1); } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { photoImage.setNeedsQualityThumb(true); photoImage.setShouldGenerateQualityThumb(true); if (!isSmallImage && !currentMessageObject.isHiddenSensitive() && (documentCover == null || currentMessageObject.isLivePhoto()) && SharedConfig.isAutoplayVideo() && !currentMessageObject.isRepostPreview && (!currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || currentMessageObject.revealingMediaSpoilers) && ( (currentMessageObject.mediaExists || currentMessageObject.attachPathExists) || messageObject.canStreamVideo() && DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject) )) { photoImage.setAllowDecodeSingleFrame(true); photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); photoImage.setImage(ImageLocation.getForDocument(documentAttach), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObjectThumb, documentAttach), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, documentAttach.size, null, messageObject, 0); autoPlayingMedia = true; } else { if (currentPhotoObjectThumb != null || currentPhotoObjectThumbStripped != null) { photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); } else { photoImage.setImage(null, null, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); } } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { photoImage.setAllowDecodeSingleFrame(true); boolean autoDownload = false; if (MessageObject.isRoundVideoDocument(document)) { photoImage.setRoundRadius(AndroidUtilities.roundMessageSize / 2); canChangeRadius = false; autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject); } else if (MessageObject.isGifDocument(document, messageObject.hasValidGroupId())) { autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject); } if (currentMessageObject.isHiddenSensitive()) { autoDownload = false; } String filter = currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter; if ((messageObject.mediaExists || autoDownload) && !currentMessageObject.isRepostPreview) { autoPlayingMedia = true; TLRPC.VideoSize videoSize = MessageObject.getDocumentVideoThumb(document); if (!messageObject.mediaExists && videoSize != null && (currentPhotoObject == null || currentPhotoObjectThumb == null)) { photoImage.setImage(ImageLocation.getForDocument(document), document.size < 1024 * 32 ? null : ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForDocument(videoSize, documentAttach), null, ImageLocation.getForDocument(currentPhotoObject != null ? currentPhotoObject : currentPhotoObjectThumb, documentAttach), currentPhotoObject != null ? filter : currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, 0); } else { photoImage.setImage(ImageLocation.getForDocument(document), document.size < 1024 * 32 ? null : ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForDocument(currentPhotoObject, documentAttach), filter, ImageLocation.getForDocument(currentPhotoObjectThumb, documentAttach), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, 0); } } else { photoImage.setImage(null, null, ImageLocation.getForDocument(currentPhotoObject, documentAttach), filter, 0, null, currentMessageObject, 0); } } else { boolean photoExist = messageObject.mediaExists; String fileName = FileLoader.getAttachFileName(currentPhotoObject); if (hasGamePreview || photoExist || DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName) || currentMessageObject.isSponsored()) { photoNotSet = false; if (currentPhotoLocation != null) { photoImage.setImage(currentPhotoLocation, currentPhotoFilter, currentPhotoThumbLocation, currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); } else { photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); } } else { photoNotSet = true; if (currentPhotoObjectThumb != null || currentPhotoObjectThumbStripped != null) { photoImage.setImage(null, null, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), String.format(Locale.US, "%d_%d_b", w, h), currentPhotoObjectThumbStripped, 0, null, messageObject, 0); } else { photoImage.setImageBitmap((Drawable) null); } } } clearBlurredImage(blurredPhotoImage); if (photoImage.getBitmap() != null && !photoImage.getBitmap().isRecycled() && (currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed || fitPhotoImage)) { blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(photoImage.getBitmap(), currentMessageObject.isRoundVideo())); blurredPhotoImage.setColorFilter(getFancyBlurFilter()); } drawPhotoImage = true; if ((type != null && type.equals("video") || documentAttachType == DOCUMENT_ATTACH_TYPE_STORY) && duration != 0) { String str = AndroidUtilities.formatShortDuration(duration); durationWidth = (int) Math.ceil(Theme.chat_durationPaint.measureText(str)); videoInfoLayout = new StaticLayout(str, Theme.chat_durationPaint, durationWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else if (hasGamePreview) { boolean showGameOverlay = true; try { long bot_id = messageObject.messageOwner.via_bot_id != 0 ? messageObject.messageOwner.via_bot_id : messageObject.messageOwner.from_id.user_id; if (bot_id != 0) { TLRPC.User botUser = MessagesController.getInstance(currentAccount).getUser(bot_id); if (botUser != null && botUser.username != null && botUser.username.equals("donate")) { showGameOverlay = false; } } } catch (Exception e) { } if (showGameOverlay) { String str = getString(R.string.AttachGame).toUpperCase(); durationWidth = (int) Math.ceil(Theme.chat_gamePaint.measureText(str)); videoInfoLayout = new StaticLayout(str, Theme.chat_gamePaint, durationWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } } } else { photoImage.setImageBitmap((Drawable) null); clearBlurredImage(blurredPhotoImage); linkPreviewHeight -= dp(4); totalHeight += dp(4); } if (hasInvoicePreview && hasInvoicePrice) { CharSequence str; if ((MessageObject.getMedia(messageObject.messageOwner).flags & 4) != 0) { str = getString(R.string.PaymentReceipt).toUpperCase(); } else { str = getString(MessageObject.getMedia(messageObject.messageOwner).test ? R.string.PaymentTestInvoice : R.string.PaymentInvoice).toUpperCase(); } String price = LocaleController.getInstance().formatCurrencyString(MessageObject.getMedia(messageObject.messageOwner).total_amount, MessageObject.getMedia(messageObject.messageOwner).currency); SpannableStringBuilder stringBuilder = new SpannableStringBuilder(price + " " + str); stringBuilder = StarsIntroActivity.replaceStars(stringBuilder); stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.bold()), 0, price.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); videoInfoLayout = new StaticLayout(stringBuilder, Theme.chat_shipmentPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); durationWidth = (int) (videoInfoLayout.getLineCount() > 0 ? videoInfoLayout.getLineWidth(0) : 0); if (!drawPhotoImage) { totalHeight += dp(6); int timeWidthTotal = timeWidth + dp(14 + (messageObject.isOutOwner() ? 20 : 0)); if (durationWidth + timeWidthTotal > maxWidth) { maxChildWidth = Math.max(durationWidth, maxChildWidth); totalHeight += dp(12); } else { maxChildWidth = Math.max(durationWidth + timeWidthTotal, maxChildWidth); } } } if (hasGamePreview && messageObject.textHeight(transitionParams) != 0) { linkPreviewHeight += messageObject.textHeight(transitionParams) + dp(6); totalHeight += dp(4); } calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); } if (!hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { linkPreviewHeight += dp(6); totalHeight += dp(6); } if (!hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults() && ( currentPhotoObject != null || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO ) && (authorLayout != null || descriptionLayout != null || titleLayout != null || siteNameLayout != null)) { linkPreviewHeight += dp(2.66f); } totalHeight += dp(2 + (!drawInstantView ? 4 : 0)); createInstantViewButton(); } else { photoImage.setImageBitmap((Drawable) null); calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); clearBlurredImage(blurredPhotoImage); if (messageObject.isUnsupported()) { createInstantViewButton(); } } totalHeight += layoutFactCheck(maxWidth - dp(30)); if (hasFactCheck) { maxChildWidth = Math.max(maxChildWidth, factCheckWidth); calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); } } else if (messageObject.type == MessageObject.TYPE_PHONE_CALL) { createSelectorDrawable(0); drawName = false; drawForwardedName = false; drawPhotoImage = false; if (AndroidUtilities.isTablet()) { backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(270)); } else { backgroundWidth = Math.min(getParentWidth() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(270)); } availableTimeWidth = backgroundWidth - dp(31); int maxWidth = getMaxNameWidth() - dp(50); if (maxWidth < 0) { maxWidth = dp(10); } String time = LocaleController.getInstance().getFormatterDay().format((long) (messageObject.messageOwner.date) * 1000); final boolean isMissed, isBusy, video; final int duration; final ArrayList other_participants; if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPhoneCall) { final TLRPC.TL_messageActionPhoneCall call = (TLRPC.TL_messageActionPhoneCall) messageObject.messageOwner.action; isMissed = call.reason instanceof TLRPC.TL_phoneCallDiscardReasonMissed; isBusy = call.reason instanceof TLRPC.TL_phoneCallDiscardReasonBusy; video = call.video; duration = call.duration; other_participants = null; } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionConferenceCall) { final TLRPC.TL_messageActionConferenceCall call = (TLRPC.TL_messageActionConferenceCall) messageObject.messageOwner.action; isMissed = call.missed; isBusy = !call.active; video = call.video; duration = call.duration; other_participants = call.other_participants; } else { isMissed = false; isBusy = false; video = false; duration = 0; other_participants = null; } String text = getCallMessageText(messageObject, isMissed, isBusy, video); if (duration > 0) { time += ", " + LocaleController.formatCallDuration(duration); } titleLayout = new StaticLayout(TextUtils.ellipsize(text, Theme.chat_audioTitlePaint, maxWidth, TextUtils.TruncateAt.END), Theme.chat_audioTitlePaint, maxWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); docTitleLayout = new StaticLayout(TextUtils.ellipsize(time, Theme.chat_contactPhonePaint, maxWidth - dp(19), TextUtils.TruncateAt.END), Theme.chat_contactPhonePaint, maxWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); docTitleWidth = (int) docTitleLayout.getLineWidth(0); if (other_participants != null && other_participants.size() > 0) { if (groupCallParticipantsAvatars == null) { groupCallParticipantsAvatars = new AvatarsDrawable(this, false); groupCallParticipantsAvatars.setSize(dp(14)); groupCallParticipantsAvatars.setAvatarsTextSize(dp(18)); groupCallParticipantsAvatars.width = dp(50); groupCallParticipantsAvatars.height = dp(16); if (isCellAttachedToWindow()) { groupCallParticipantsAvatars.onAttachedToWindow(); } } final HashSet dialogIds = new HashSet(); // if (!currentMessageObject.isOutOwner()) { dialogIds.add(currentMessageObject.getDialogId()); // } if (currentMessageObject.isOutOwner()) { dialogIds.add(UserConfig.getInstance(currentAccount).getClientUserId()); } for (int i = 0; i < Math.min(3, other_participants.size()); ++i) { dialogIds.add(DialogObject.getPeerDialogId(other_participants.get(i))); } final int count = Math.min(3, dialogIds.size()); groupCallParticipantsAvatars.setCount(count); int i = 0; for (long did : dialogIds) { groupCallParticipantsAvatars.setObject(i, currentAccount, MessagesController.getInstance(currentAccount).getUserOrChat(did)); i++; if (i >= count) break; } groupCallParticipantsAvatars.commitTransition(false); groupCallParticipantsText = new Text(formatPluralStringComma("ConferenceCallOther", dialogIds.size()), 13); } else { groupCallParticipantsText = null; } final float timeWidth = docTitleWidth + (groupCallParticipantsText == null ? 0 : groupCallParticipantsText.getCurrentWidth()); if (timeWidth > (maxWidth - dp(19 + 30))) { final int needsMore = (int) (timeWidth - (maxWidth - dp(19 + 30))); backgroundWidth += needsMore; availableTimeWidth = backgroundWidth - dp(31); } setMessageObjectInternal(messageObject); totalHeight = dp(65) + namesOffset; if (drawPinnedTop) { namesOffset -= dp(1); } if (!reactionsLayoutInBubble.isSmall) { if (!reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.measure(backgroundWidth - dp(32), Gravity.LEFT); reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height; if (backgroundWidth - dp(32) - reactionsLayoutInBubble.lastLineX < timeWidth) { reactionsLayoutInBubble.totalHeight += dp(12); reactionsLayoutInBubble.positionOffsetY += -dp(12); } totalHeight += dp(6) + reactionsLayoutInBubble.totalHeight; } } } else if (messageObject.type == MessageObject.TYPE_CONTACT) { drawContact = true; drawName = isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null; drawForwardedName = !isRepliesChat; drawPhotoImage = true; photoImage.setRoundRadius(dp(22)); canChangeRadius = false; if (AndroidUtilities.isTablet()) { backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(270)); } else { backgroundWidth = Math.min(getParentWidth() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(270)); } availableTimeWidth = backgroundWidth - dp(31); long uid = MessageObject.getMedia(messageObject.messageOwner).user_id; TLRPC.User user = null; if (uid != 0) { user = MessagesController.getInstance(currentAccount).getUser(uid); } int maxWidth = getMaxNameWidth() - dp(80); if (maxWidth < 0) { maxWidth = dp(10); } boolean hasName; if (user != null) { contactAvatarDrawable.setInfo(currentAccount, user); hasName = true; } else if (!TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).first_name) || !TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).last_name)) { contactAvatarDrawable.setInfo(0, MessageObject.getMedia(messageObject.messageOwner).first_name, MessageObject.getMedia(messageObject.messageOwner).last_name); hasName = true; } else { hasName = false; } photoImage.setForUserOrChat(user, hasName ? contactAvatarDrawable : Theme.chat_contactDrawable[messageObject.isOutOwner() ? 1 : 0], messageObject); CharSequence phone; if (!TextUtils.isEmpty(messageObject.vCardData)) { phone = messageObject.vCardData; } else { if (user != null && !TextUtils.isEmpty(user.phone)) { phone = PhoneFormat.getInstance().format("+" + user.phone); } else { phone = MessageObject.getMedia(messageObject.messageOwner).phone_number; if (!TextUtils.isEmpty(phone)) { phone = PhoneFormat.getInstance().format((String) phone); } else { phone = getString("NumberUnknown", R.string.NumberUnknown); } } } if (user != null || !TextUtils.isEmpty(messageObject.vCardData) || MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaContact) { if (user != null) { drawContactSendMessage = true; drawContactAdd = !user.contact; } else { drawContactView = true; } } CharSequence currentNameString = ContactsController.formatName(MessageObject.getMedia(messageObject.messageOwner).first_name, MessageObject.getMedia(messageObject.messageOwner).last_name).replace('\n', ' '); if (currentNameString.length() == 0) { currentNameString = MessageObject.getMedia(messageObject.messageOwner).phone_number; if (currentNameString == null) { currentNameString = ""; } } titleLayout = new StaticLayout(TextUtils.ellipsize(currentNameString, Theme.chat_contactNamePaint, maxWidth, TextUtils.TruncateAt.END), Theme.chat_contactNamePaint, maxWidth + dp(4), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); docTitleLayout = new StaticLayout(phone, Theme.chat_contactPhonePaint, maxWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, dp(1), false); setMessageObjectInternal(messageObject); if (drawForwardedName && messageObject.needDrawForwarded() && (currentPosition == null || currentPosition.minY == 0)) { namesOffset += dp(5); } else if (drawNameLayout && messageObject.getReplyMsgId() == 0) { namesOffset += dp(7); } totalHeight = dp(65) + namesOffset + docTitleLayout.getHeight(); if (drawPinnedTop) { namesOffset -= dp(1); } if (drawContactSendMessage || drawContactAdd || drawContactView) { createContactButtons(); } else { if (docTitleLayout.getLineCount() > 0) { int timeLeft = backgroundWidth - dp(40 + 18 + 44 + 8) - (int) Math.ceil(docTitleLayout.getLineWidth(docTitleLayout.getLineCount() - 1)); if (timeLeft < timeWidth) { totalHeight += dp(8); } } } if (!reactionsLayoutInBubble.isSmall) { if (!reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.measure(backgroundWidth - dp(32), Gravity.LEFT); reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height; if (backgroundWidth - dp(32) - reactionsLayoutInBubble.lastLineX < timeWidth) { reactionsLayoutInBubble.totalHeight += dp(12); reactionsLayoutInBubble.positionOffsetY += -dp(12); } totalHeight += reactionsLayoutInBubble.totalHeight; } } } else if (messageObject.type == MessageObject.TYPE_VOICE) { drawForwardedName = !isRepliesChat; drawName = ( isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null || isSideMenuEnabled && !messageObject.isOutOwner() && (isForum || isMonoForum && isAllChats) ); int maxWidth; if (AndroidUtilities.isTablet()) { backgroundWidth = maxWidth = Math.min(AndroidUtilities.getMinTabletSide() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(270)); } else { backgroundWidth = maxWidth = Math.min(getParentWidth() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(270)); } createDocumentLayout(backgroundWidth, messageObject); setMessageObjectInternal(messageObject); totalHeight = dp(70) + namesOffset; if (drawPinnedTop) { namesOffset -= dp(1); } if (!reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(maxWidth - (messageObject.isOutOwner() ? dp(32) : dp(24)), Gravity.LEFT); if (!reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height; if (TextUtils.isEmpty(messageObject.caption)) { reactionsLayoutInBubble.totalHeight += dp(12); } else { reactionsLayoutInBubble.totalHeight += dp(8); } if (reactionsLayoutInBubble.width > backgroundWidth) { backgroundWidth = reactionsLayoutInBubble.width; } int timeMore = timeWidth + dp(6); if (messageObject.isQuickReply() && !messageObject.isSendError()) { timeMore -= dp(3); } else if (messageObject.isOutOwner()) { timeMore += dp(20.5f); } timeMore += getExtraTimeX(); if (reactionsLayoutInBubble.lastLineX + timeMore >= backgroundWidth) { reactionsLayoutInBubble.totalHeight += dp(12); reactionsLayoutInBubble.positionOffsetY -= dp(12); } totalHeight += reactionsLayoutInBubble.totalHeight; } } } else if (messageObject.type == MessageObject.TYPE_MUSIC) { drawForwardedName = !isRepliesChat && messageObject.messageOwner.fwd_from != null; drawName = isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || (messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); int maxWidth; if (AndroidUtilities.isTablet()) { maxWidth = AndroidUtilities.getMinTabletSide() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)); backgroundWidth = Math.min(dp(270), maxWidth); } else { maxWidth = getParentWidth() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)); backgroundWidth = Math.min(dp(270), maxWidth); } if (currentPosition != null) { backgroundWidth = maxWidth; } int durationWidth = createDocumentLayout(maxWidth, messageObject); setMessageObjectInternal(messageObject); totalHeight = dp(82) + namesOffset; if (dp(76) + durationWidth >= backgroundWidth - timeWidth - dp(12)) { totalHeight += dp(14); } if (currentPosition != null && currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { totalHeight -= dp(6); mediaOffsetY -= dp(6); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { totalHeight -= dp(6); } } if (drawPinnedTop) { namesOffset -= dp(1); } if (!reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(maxWidth - dp(24), Gravity.LEFT); if (!reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height + dp(12); measureTime(messageObject); if (reactionsLayoutInBubble.width > backgroundWidth) { backgroundWidth = reactionsLayoutInBubble.width; } if (reactionsLayoutInBubble.lastLineX + timeWidth + dp(24) > backgroundWidth) { reactionsLayoutInBubble.totalHeight += dp(12); reactionsLayoutInBubble.positionOffsetY -= dp(12); } if (!messageObject.isRestrictedMessage && messageObject.caption != null) { reactionsLayoutInBubble.positionOffsetY += dp(14); } totalHeight += reactionsLayoutInBubble.totalHeight; } } } else if (messageObject.type == MessageObject.TYPE_POLL) { setMessageContentIfPoll(messageObject, messageIdChanged); } else if (messageObject.type == MessageObject.TYPE_PAID_MEDIA) { drawName = isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || (messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); drawForwardedName = !isRepliesChat; if (groupMedia == null) { groupMedia = new GroupMedia(this); } groupMedia.setOverrideWidth(-1); groupMedia.setMessageObject(messageObject, pinnedBottom, pinnedTop); backgroundWidth = groupMedia.width + dp(8 + 9); availableTimeWidth = backgroundWidth - dp(31); measureTime(messageObject); if (drawCommentButton && totalCommentWidth + dp(28) > backgroundWidth) { backgroundWidth = totalCommentWidth + dp(28); groupMedia.setOverrideWidth(backgroundWidth - dp(8 + 9)); } int timeWidthTotal = timeWidth + dp((SharedConfig.bubbleRadius >= 10 ? 22 : 18) + (messageObject.isOutOwner() ? 20 : 0) + 20); if (timeWidthTotal > backgroundWidth) { backgroundWidth = timeWidthTotal; groupMedia.setOverrideWidth(backgroundWidth - dp(8 + 9)); } mediaBackground = false; int widthForCaption = backgroundWidth - dp(20); int additionHeight = 0; currentCaption = messageObject.caption; if (currentCaption != null) { try { captionFullWidth = widthForCaption; widthForCaption -= getExtraTextX() * 2; captionLayout = new MessageObject.TextLayoutBlocks(getPrimaryMessageObject(), currentCaption, Theme.chat_msgTextPaint, widthForCaption); captionLayout.bounceFrom(prevCaptionLayout); captionWidth = captionLayout.textWidth; captionHeight = captionLayout.textHeight(); addedCaptionHeight = captionHeight + dp(9); if (captionWidth > widthForCaption) { groupMedia.setOverrideWidth(captionWidth + getExtraTextX() * 2 + dp(20) - dp(8 + 9) + dp(14)); } if (!captionAbove && (captionLayout.hasCodeAtBottom || captionLayout.hasQuoteAtBottom)) { captionHeight += dp(14); addedCaptionHeight += dp(14); } if (currentPosition == null || (currentPosition.flags & captionFlag()) != 0) { additionHeight += addedCaptionHeight; int widthToCheck = Math.max(captionWidth, backgroundWidth - dp(20)); if ((reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) && !shouldDrawTimeOnMedia() && widthToCheck + dp(2) - captionLayout.lastLineWidth < timeWidthTotal + getExtraTimeX() && !hasFactCheck) { additionHeight += dp(14); addedCaptionHeight += dp(14); captionNewLine = 1; } } else { captionLayout = null; } } catch (Exception e) { FileLog.e(e); } } int additionalTop = 0; if (captionLayout != null && captionAbove) { additionalTop = captionLayout.textHeight() + dp(8); } setMessageObjectInternal(messageObject); if (backgroundWidth > groupMedia.width + dp(8 + 9)) { groupMedia.setOverrideWidth(backgroundWidth - dp(8 + 9)); groupMedia.updateHolders(messageObject); } groupMedia.updateHolders(messageObject); backgroundWidth = groupMedia.width + dp(8 + 9); if (backgroundWidth < timeWidthTotal) { backgroundWidth = timeWidthTotal; } setMessageObjectInternal(messageObject); totalHeight = groupMedia.height + dp(14) + namesOffset + additionHeight; if (currentPosition != null && currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { totalHeight -= dp(6); mediaOffsetY -= dp(6); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { totalHeight -= dp(6); } } if (drawPinnedTop) { namesOffset -= dp(1); } if (!reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(backgroundWidth - dp(24), Gravity.LEFT); if (!reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height + dp(12); measureTime(messageObject); if (reactionsLayoutInBubble.width > backgroundWidth) { backgroundWidth = reactionsLayoutInBubble.width; } if (reactionsLayoutInBubble.lastLineX + timeWidth + dp(24) > backgroundWidth) { reactionsLayoutInBubble.totalHeight += dp(12); reactionsLayoutInBubble.positionOffsetY -= dp(12); } if (!messageObject.isRestrictedMessage && messageObject.caption != null) { reactionsLayoutInBubble.positionOffsetY += dp(!drawCommentButton ? 14 : 1); } totalHeight += reactionsLayoutInBubble.totalHeight; } } int y = 0; if (drawPinnedTop) { namesOffset -= dp(documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT ? 2 : 1); } if (drawPinnedTop && !messageObject.isOutOwner()) { totalHeight += dp(documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT ? 2 : 0); } if (namesOffset > 0) { y = dp(9 + 4); totalHeight += dp(4); } else { y = dp(5); totalHeight -= dp(4); } int x; if (currentMessageObject.isOutOwner()) { if (mediaBackground) { x = layoutWidth - backgroundWidth - dp(3); } else { x = layoutWidth - backgroundWidth + dp(6); } } else { if ((isChat || currentMessageObject.isRepostPreview) && isAvatarVisible && !isPlayingRound) { x = dp(63); } else { x = dp(15); } } x -= dp(2); groupMedia.x = x; groupMedia.y = y + namesOffset + additionalTop; } else { drawForwardedName = (messageObject.messageOwner.fwd_from != null && !(messageObject.isAnyKindOfSticker() && messageObject.isDice())) || messageObject.type == MessageObject.TYPE_STORY; if (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { drawName = (isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isRepostPreview || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null || isSideMenuEnabled && !messageObject.isOutOwner() && (isMonoForum && isAllChats || isForum)) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); } mediaBackground = isMedia = messageObject.type != MessageObject.TYPE_FILE; drawImageButton = true; drawPhotoImage = true; int photoWidth = 0; int photoHeight = 0; int additionHeight = 0; if (messageObject.gifState != 2 && !(SharedConfig.isAutoplayGifs() && !messageObject.isRepostPreview) && (messageObject.type == MessageObject.TYPE_GIF || messageObject.type == MessageObject.TYPE_ROUND_VIDEO)) { messageObject.gifState = 1; } photoImage.setAllowDecodeSingleFrame(true); if (messageObject.isVideo()) { photoImage.setAllowStartAnimation(true); } else if (messageObject.isRoundVideo()) { MessageObject playingMessage = MediaController.getInstance().getPlayingMessageObject(); photoImage.setAllowStartAnimation(playingMessage == null || !playingMessage.isRoundVideo()); } else { photoImage.setAllowStartAnimation(messageObject.gifState == 0); } photoImage.setForcePreview(messageObject.needDrawBluredPreview()); if (messageObject.type == MessageObject.TYPE_FILE) { if (currentPosition == null) { backgroundWidth = messageObject.getMaxMessageTextWidth(); } else { if (AndroidUtilities.isTablet()) { backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(300)); } else { backgroundWidth = Math.min(getParentWidth() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(300)); } if (checkNeedDrawShareButton(messageObject)) { backgroundWidth -= dp(20); } } int maxTextWidth = 0; int maxWidth = backgroundWidth - dp(86 + (currentPosition == null ? 0 : 52)); if (currentPosition == null) { captionFullWidth = backgroundWidth - getExtraTextX() * 2; currentCaption = messageObject.caption; if (!TextUtils.isEmpty(currentCaption)) { try { captionLayout = new MessageObject.TextLayoutBlocks(getPrimaryMessageObject(), currentCaption, Theme.chat_msgTextPaint, captionFullWidth); captionLayout.bounceFrom(prevCaptionLayout); updateSeekBarWaveformWidth(null); } catch (Exception e) { FileLog.e(e); } } if (captionLayout != null) { maxTextWidth = Math.max(captionLayout.textWidth, maxTextWidth); } if (maxWidth > maxTextWidth) { maxWidth = Math.max(maxTextWidth, backgroundWidth - dp(86 + 52)); } } createDocumentLayout(maxWidth, messageObject); if (currentPosition != null) { captionFullWidth = backgroundWidth - dp(41); } if (docTitleLayout != null) { for (int a = 0, N = docTitleLayout.getLineCount(); a < N; a++) { maxTextWidth = Math.max(maxTextWidth, (int) Math.ceil(docTitleLayout.getLineWidth(a) + docTitleLayout.getLineLeft(a)) + dp(86 + (drawPhotoImage ? 52 : 22))); } } if (infoLayout != null) { for (int a = 0, N = infoLayout.getLineCount(); a < N; a++) { maxTextWidth = Math.max(maxTextWidth, infoWidth + dp(86 + (drawPhotoImage ? 52 : 22))); } } if (captionLayout != null) { maxTextWidth = Math.max(captionLayout.textWidth + getExtraTextX() * 2 + dp(31), maxTextWidth); } if (!reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(captionFullWidth, Gravity.LEFT); if (!reactionsLayoutInBubble.isEmpty) { maxTextWidth = Math.max(maxTextWidth, reactionsLayoutInBubble.width + dp(31)); } } if (maxTextWidth > backgroundWidth && currentPosition == null) { backgroundWidth = maxTextWidth; maxWidth = maxTextWidth - dp(31); } availableTimeWidth = maxWidth; if (drawPhotoImage) { photoWidth = dp(86); photoHeight = dp(86); availableTimeWidth -= photoWidth; } else { photoWidth = dp(56); photoHeight = dp(56); if (docTitleLayout != null && docTitleLayout.getLineCount() > 1) { photoHeight += (docTitleLayout.getLineCount() - 1) * dp(16); } if (TextUtils.isEmpty(messageObject.caption) && infoLayout != null) { int lineCount = infoLayout.getLineCount(); measureTime(messageObject); int timeLeft = backgroundWidth - dp(40 + 18 + 56 + 8) - infoWidth; if (reactionsLayoutInBubble.isSmall || reactionsLayoutInBubble.isEmpty) { if (timeLeft < timeWidth) { photoHeight += dp(12); } else if (lineCount == 1) { photoHeight += dp(4); } } } } if (!reactionsLayoutInBubble.isSmall && !reactionsLayoutInBubble.isEmpty) { if (!drawPhotoImage) { reactionsLayoutInBubble.positionOffsetY += dp(2); } reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height + dp(!drawPhotoImage || captionLayout == null ? 8 : 0); measureTime(messageObject); if (drawPhotoImage && captionLayout == null) { reactionsLayoutInBubble.totalHeight += dp(8); } int timeLeft = backgroundWidth - reactionsLayoutInBubble.lastLineX - dp(42); if (timeLeft < timeWidth) { reactionsLayoutInBubble.totalHeight += dp(captionLayout == null ? 15 : 12); reactionsLayoutInBubble.positionOffsetY -= dp(15); } if (currentPosition == null && captionLayout != null) { additionHeight += dp(12); } additionHeight += reactionsLayoutInBubble.totalHeight; } } else if (messageObject.type == MessageObject.TYPE_GEO) { TLRPC.GeoPoint point = MessageObject.getMedia(messageObject.messageOwner).geo; double lat = point.lat; double lon = point._long; int provider; if ((int) messageObject.getDialogId() == 0) { if (SharedConfig.mapPreviewType == 0) { provider = -1; } else if (SharedConfig.mapPreviewType == 1) { provider = 4; } else if (SharedConfig.mapPreviewType == 3) { provider = 1; } else { provider = -1; } } else { provider = -1; } if (MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaGeoLive) { if (AndroidUtilities.isTablet()) { backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(252 + 37)); } else { backgroundWidth = Math.min(getParentWidth() - dp(59 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(252 + 37)); } backgroundWidth -= dp(4); if (checkNeedDrawShareButton(messageObject)) { backgroundWidth -= dp(20); } int maxWidth = backgroundWidth - dp(37); availableTimeWidth = maxWidth; maxWidth -= dp(54); photoWidth = backgroundWidth - dp(17); photoHeight = dp(195); int offset = 268435456; double rad = offset / Math.PI; double y = Math.round(offset - rad * Math.log((1 + Math.sin(lat * Math.PI / 180.0)) / (1 - Math.sin(lat * Math.PI / 180.0))) / 2) - (dp(10.3f) << (21 - 15)); lat = (Math.PI / 2.0 - 2 * Math.atan(Math.exp((y - offset) / rad))) * 180.0 / Math.PI; currentUrl = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), false, 15, provider); lastWebFile = currentWebFile; currentWebFile = WebFile.createWithGeoPoint(lat, lon, point.access_hash, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), 15, Math.min(2, (int) Math.ceil(AndroidUtilities.density))); photoImage.setCrossfadeWithOldImage(true); if (!(locationExpired = isCurrentLocationTimeExpired(messageObject))) { mediaBackground = false; additionHeight = dp(56); AndroidUtilities.runOnUIThread(invalidateRunnable, 1000); scheduledInvalidate = true; } else { backgroundWidth -= dp(9); } docTitleLayout = new StaticLayout(TextUtils.ellipsize(getString("AttachLiveLocation", R.string.AttachLiveLocation), Theme.chat_locationTitlePaint, maxWidth, TextUtils.TruncateAt.END), Theme.chat_locationTitlePaint, maxWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); updateCurrentUserAndChat(); if (currentUser != null) { contactAvatarDrawable.setInfo(currentAccount, currentUser); locationImageReceiver.setForUserOrChat(currentUser, contactAvatarDrawable); } else if (currentChat != null) { if (currentChat.photo != null) { currentPhoto = currentChat.photo.photo_small; } contactAvatarDrawable.setInfo(currentAccount, currentChat); locationImageReceiver.setForUserOrChat(currentChat, contactAvatarDrawable); } else { locationImageReceiver.setImage(null, null, contactAvatarDrawable, null, null, 0); } infoLayout = new StaticLayout(TextUtils.ellipsize(LocaleController.formatLocationUpdateDate(messageObject.messageOwner.edit_date != 0 ? messageObject.messageOwner.edit_date : messageObject.messageOwner.date), Theme.chat_locationAddressPaint, maxWidth + dp(2), TextUtils.TruncateAt.END), Theme.chat_locationAddressPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else if (!TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).title)) { if (AndroidUtilities.isTablet()) { backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(252 + 37)); } else { backgroundWidth = Math.min(getParentWidth() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(252 + 37)); } backgroundWidth -= dp(4); if (checkNeedDrawShareButton(messageObject)) { backgroundWidth -= dp(20); } int maxWidth = backgroundWidth - dp(34); availableTimeWidth = maxWidth; photoWidth = backgroundWidth - dp(17); photoHeight = dp(195); mediaBackground = false; currentUrl = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), true, 15, provider); currentWebFile = WebFile.createWithGeoPoint(point, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), 15, Math.min(2, (int) Math.ceil(AndroidUtilities.density))); docTitleLayout = StaticLayoutEx.createStaticLayout(MessageObject.getMedia(messageObject.messageOwner).title, Theme.chat_locationTitlePaint, maxWidth + dp(4), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth, 1); additionHeight += dp(50); int lineCount = docTitleLayout.getLineCount(); if (!TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).address)) { infoLayout = StaticLayoutEx.createStaticLayout(MessageObject.getMedia(messageObject.messageOwner).address, Theme.chat_locationAddressPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth, 1); measureTime(messageObject); int timeLeft = backgroundWidth - (int) Math.ceil(infoLayout.getLineWidth(0)) - dp(24); boolean isRtl = infoLayout.getLineLeft(0) > 0; if (isRtl || timeLeft < timeWidth + dp(20 + (messageObject.isOutOwner() ? 20 : 0))) { additionHeight += dp(isRtl ? 10 : 8); } } else { infoLayout = null; } } else { if (AndroidUtilities.isTablet()) { backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(252 + 37)); } else { backgroundWidth = Math.min(getParentWidth() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)), dp(252 + 37)); } backgroundWidth -= dp(4); if (checkNeedDrawShareButton(messageObject)) { backgroundWidth -= dp(20); } availableTimeWidth = backgroundWidth - dp(34); photoWidth = backgroundWidth - dp(8); photoHeight = dp(195); currentUrl = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), true, 15, provider); currentWebFile = WebFile.createWithGeoPoint(point, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), 15, Math.min(2, (int) Math.ceil(AndroidUtilities.density))); } if ((int) messageObject.getDialogId() == 0) { if (SharedConfig.mapPreviewType == 0) { currentMapProvider = 2; } else if (SharedConfig.mapPreviewType == 1) { currentMapProvider = 1; } else if (SharedConfig.mapPreviewType == 3) { currentMapProvider = 1; } else { currentMapProvider = -1; } } else { currentMapProvider = MessagesController.getInstance(messageObject.currentAccount).mapProvider; } if (locationLoadingThumb == null) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(R.raw.map_placeholder, Theme.key_chat_outLocationIcon, (Theme.isCurrentThemeDark() ? 3 : 6) * .12f); svgThumb.setAspectCenter(true); locationLoadingThumb = new ClipRoundedDrawable(svgThumb); } if (locationLoadingThumb instanceof ClipRoundedDrawable && ((ClipRoundedDrawable) locationLoadingThumb).getDrawable() instanceof SvgHelper.SvgDrawable) { SvgHelper.SvgDrawable drawable = (SvgHelper.SvgDrawable) ((ClipRoundedDrawable) locationLoadingThumb).getDrawable(); drawable.setColorKey(messageObject.isOutOwner() ? Theme.key_chat_outLocationIcon : Theme.key_chat_inLocationIcon, resourcesProvider); } photoImage.setCrossfadeDuration(2 * ImageReceiver.DEFAULT_CROSSFADE_DURATION); photoImage.setCrossfadeByScale(.05f); if (currentMapProvider == -1) { photoImage.setImage(null, null, null, null, messageObject, 0); } else if (currentMapProvider == 2) { if (currentWebFile != null) { ImageLocation lastLocation; if (messageObject.lastGeoWebFileLoaded instanceof ImageLocation) { lastLocation = (ImageLocation) messageObject.lastGeoWebFileLoaded; } else { lastLocation = null; } messageObject.lastGeoWebFileSet = ImageLocation.getForWebFile(currentWebFile); photoImage.setImage(ImageLocation.getForWebFile(currentWebFile), null, lastLocation, null, locationLoadingThumb, messageObject, 0); } } else { if (currentMapProvider == 3 || currentMapProvider == 4) { ImageLoader.getInstance().addTestWebFile(currentUrl, currentWebFile); addedForTest = true; } if (currentUrl != null) { photoImage.setImage(currentUrl, null, locationLoadingThumb, null, 0); } } if (!reactionsLayoutInBubble.isSmall && !reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.measure(backgroundWidth - dp(16), Gravity.LEFT); reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height + dp(14); measureTime(messageObject); if (reactionsLayoutInBubble.lastLineX + timeWidth + dp(24) > backgroundWidth) { reactionsLayoutInBubble.totalHeight += dp(12); reactionsLayoutInBubble.positionOffsetY -= dp(12); } additionHeight += reactionsLayoutInBubble.totalHeight; } } else if (messageObject.type == MessageObject.TYPE_EMOJIS) { drawBackground = false; photoWidth = (int) messageObject.textWidth; photoHeight = (int) messageObject.textHeight(transitionParams) + dp(32); backgroundWidth = photoWidth + dp(14); availableTimeWidth = photoWidth - dp(12); int maxWidth; if (AndroidUtilities.isTablet()) { maxWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.4f); } else { maxWidth = (int) (Math.min(getParentWidth(), AndroidUtilities.displaySize.y) * 0.5f); } maxWidth = Math.max(backgroundWidth, maxWidth); if (!reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(maxWidth, currentMessageObject.isOutOwner() ? Gravity.RIGHT : Gravity.LEFT); reactionsLayoutInBubble.drawServiceShaderBackground = 1f; reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height;// + dp(8); additionHeight += reactionsLayoutInBubble.totalHeight + dp(8); reactionsLayoutInBubble.positionOffsetY += dp(8); } additionHeight -= dp(17); } else if (messageObject.isAnyKindOfSticker()) { drawBackground = false; boolean isWebpSticker = messageObject.type == MessageObject.TYPE_STICKER; TLRPC.Document stickerDocument = messageObject.getDocument(); if (stickerDocument != null) { for (int a = 0; a < stickerDocument.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = stickerDocument.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { photoWidth = attribute.w; photoHeight = attribute.h; break; } if (attribute instanceof TLRPC.TL_documentAttributeVideo) { photoWidth = attribute.w; photoHeight = attribute.h; break; } } } if ((messageObject.isAnimatedSticker() || messageObject.isVideoSticker()) && photoWidth == 0 && photoHeight == 0) { photoWidth = photoHeight = 512; } if (messageObject.isAnimatedAnimatedEmoji()) { photoWidth = Math.max(512, photoWidth); photoHeight = Math.max(512, photoHeight); if (MessageObject.isTextColorEmoji(messageObject.getDocument())) { photoImage.setColorFilter(getAdaptiveEmojiColorFilter(0, getThemedColor(Theme.key_windowBackgroundWhiteBlackText))); } } float maxHeight; int maxWidth; if (AndroidUtilities.isTablet()) { maxHeight = maxWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.4f); } else { maxHeight = maxWidth = (int) (Math.min(getParentWidth(), AndroidUtilities.displaySize.y) * 0.5f); } String filter; if (messageObject.isAnimatedEmoji() || messageObject.isDice()) { float zoom = MessagesController.getInstance(currentAccount).animatedEmojisZoom; photoWidth = (int) ((photoWidth / 512.0f) * maxWidth * zoom); photoHeight = (int) ((photoHeight / 512.0f) * maxHeight * zoom); } else { if (photoWidth == 0) { photoHeight = (int) maxHeight; photoWidth = photoHeight + dp(100); } photoHeight *= maxWidth / (float) photoWidth; photoWidth = (int) maxWidth; if (photoHeight > maxHeight) { photoWidth *= maxHeight / photoHeight; photoHeight = (int) maxHeight; } } Object parentObject = messageObject; int w = (int) (photoWidth / AndroidUtilities.density); int h = (int) (photoHeight / AndroidUtilities.density); boolean shouldRepeatSticker = delegate != null && delegate.shouldRepeatSticker(messageObject); if (currentMessageObject.strippedThumb == null) { currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40); } else { currentPhotoObjectThumbStripped = currentMessageObject.strippedThumb; } photoParentObject = messageObject.photoThumbsObject; Drawable thumb = null; if (messageObject.isDice()) { filter = String.format(Locale.US, "%d_%d_dice_%s_%s", w, h, messageObject.getDiceEmoji(), messageObject.toString()); photoImage.setAutoRepeat(2); String emoji = currentMessageObject.getDiceEmoji(); TLRPC.TL_messages_stickerSet stickerSet = MediaDataController.getInstance(currentAccount).getStickerSetByEmojiOrName(emoji); if (stickerSet != null) { if (stickerSet.documents.size() > 0) { int value = currentMessageObject.getDiceValue(); if (value <= 0) { TLRPC.Document document = stickerSet.documents.get(0); if ("\uD83C\uDFB0".equals(emoji)) { currentPhotoObjectThumb = null; } else { currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 40); } photoParentObject = document; } } } } else if (messageObject.isAnimatedEmoji()) { if (!LiteMode.isEnabled(LiteMode.FLAG_ANIMATED_EMOJI_CHAT)) { filter = String.format(Locale.US, "%d_%d_nr_messageId=%d" + messageObject.emojiAnimatedStickerColor, w, h, messageObject.stableId); thumb = DocumentObject.getCircleThumb(.4f, Theme.key_chat_serviceBackground, resourcesProvider, 0.65f); photoImage.setAutoRepeat(3); messageObject.loadAnimatedEmojiDocument(); } else if (messageObject.emojiAnimatedSticker == null && messageObject.emojiAnimatedStickerId != null) { filter = String.format(Locale.US, "%d_%d_nr_messageId=%d" + messageObject.emojiAnimatedStickerColor, w, h, messageObject.stableId); thumb = DocumentObject.getCircleThumb(.4f, Theme.key_chat_serviceBackground, resourcesProvider, 0.65f); photoImage.setAutoRepeat(1); messageObject.loadAnimatedEmojiDocument(); } else { filter = String.format(Locale.US, "%d_%d_nr_messageId=%d" + messageObject.emojiAnimatedStickerColor, w, h, messageObject.stableId); if (MessageObject.isAnimatedEmoji(messageObject.emojiAnimatedSticker)) { photoImage.setAutoRepeat(1); } else { photoImage.setAutoRepeat(shouldRepeatSticker ? 2 : 3); } parentObject = MessageObject.getInputStickerSet(messageObject.emojiAnimatedSticker); if (messageObject.emojiAnimatedStickerId != null) { photoImage.setCrossfadeWithOldImage(true); } } } else if (SharedConfig.loopStickers() || (isWebpSticker && !messageObject.isVideoSticker())) { filter = String.format(Locale.US, "%d_%d", w, h); photoImage.setAutoRepeat(1); } else { filter = String.format(Locale.US, "%d_%d_nr_messageId=%d", w, h, messageObject.stableId); photoImage.setAutoRepeat(shouldRepeatSticker ? 2 : 3); } documentAttachType = DOCUMENT_ATTACH_TYPE_STICKER; availableTimeWidth = photoWidth - dp(14); backgroundWidth = photoWidth + dp(12); photoImage.setRoundRadius(0); canChangeRadius = false; if (!messageObject.isOutOwner() && MessageObject.isPremiumSticker(messageObject.getDocument())) { flipImage = true; } if (messageObject.getDocument() != null) { if (messageObject.isVideoSticker()) { photoImage.setImage(ImageLocation.getForDocument(messageObject.getDocument()), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), "b1", messageObject.pathThumb, messageObject.getDocument().size, isWebpSticker ? "webp" : null, parentObject, 1); if (!loopStickers()) { photoImage.animatedFileDrawableRepeatMaxCount = 1; } } else if (messageObject.pathThumb != null) { photoImage.setImage(ImageLocation.getForDocument(messageObject.getDocument()), filter, messageObject.pathThumb, messageObject.getDocument().size, isWebpSticker ? "webp" : null, parentObject, 1); } else if (messageObject.attachPathExists) { photoImage.setImage(ImageLocation.getForPath(messageObject.messageOwner.attachPath), filter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), "b1", thumb != null ? thumb : currentPhotoObjectThumbStripped, messageObject.getDocument().size, isWebpSticker ? "webp" : null, parentObject, 1); } else if (messageObject.getDocument().id != 0) { photoImage.setImage(ImageLocation.getForDocument(messageObject.getDocument()), filter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), "b1", thumb != null ? thumb : currentPhotoObjectThumbStripped, messageObject.getDocument().size, isWebpSticker ? "webp" : null, parentObject, 1); } else { photoImage.setImage(null, null, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), "b1", thumb, 0, null, messageObject, 0); } } else { photoImage.setImage(null, null, thumb, null, messageObject, 0); } if (!reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(maxWidth + dp(36), currentMessageObject.isOutOwner() && (currentMessageObject.isAnimatedEmoji() || currentMessageObject.isAnyKindOfSticker()) ? Gravity.RIGHT : Gravity.LEFT); reactionsLayoutInBubble.drawServiceShaderBackground = 1f; reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height + dp(8); additionHeight += reactionsLayoutInBubble.totalHeight; if (!currentMessageObject.isAnimatedEmoji()) { reactionsLayoutInBubble.positionOffsetY += dp(4); } } clearBlurredImage(blurredPhotoImage); if (photoImage.getBitmap() != null && !photoImage.getBitmap().isRecycled() && (currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed || fitPhotoImage)) { blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(photoImage.getBitmap(), currentMessageObject.isRoundVideo())); blurredPhotoImage.setColorFilter(getFancyBlurFilter()); } } else { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize(true)); photoParentObject = messageObject.photoThumbsObject; boolean useFullWidth = false; if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { documentAttach = messageObject.getDocument(); documentAttachType = DOCUMENT_ATTACH_TYPE_ROUND; } else { if (AndroidUtilities.isTablet()) { photoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); } else { if ( currentPhotoObject != null && ( messageObject.type == MessageObject.TYPE_PHOTO || messageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW || messageObject.type == MessageObject.TYPE_VIDEO || messageObject.type == MessageObject.TYPE_GIF ) && currentPhotoObject.w >= currentPhotoObject.h ) { photoWidth = Math.min(getParentWidth(), AndroidUtilities.displaySize.y) - dp(64 + (checkNeedDrawShareButton(messageObject) ? 10 : 0)); useFullWidth = true; } else { photoWidth = (int) (Math.min(getParentWidth(), AndroidUtilities.displaySize.y) * 0.7f); } } } photoHeight = photoWidth + dp(100); if (!useFullWidth) { if (messageObject.type != MessageObject.TYPE_ROUND_VIDEO && checkNeedDrawShareButton(messageObject)) { photoWidth -= dp(20); } if (photoWidth > AndroidUtilities.getPhotoSize()) { photoWidth = AndroidUtilities.getPhotoSize(); } if (photoHeight > AndroidUtilities.getPhotoSize()) { photoHeight = AndroidUtilities.getPhotoSize(); } } else if (currentMessageObject != null && !currentMessageObject.isOutOwner() && isSideMenuPossibleLeftMargin()) { photoWidth -= dp(ChatActivity.SIDE_MENU_WIDTH); } else if (isSideMenuEnabled) { photoWidth -= dp(ChatActivity.SIDE_MENU_WIDTH); } else if (drawAvatar) { photoWidth -= dp(52); } boolean needQualityPreview = false; if (messageObject.type == MessageObject.TYPE_PHOTO || messageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW) { // photo updateSecretTimeText(messageObject); currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40); } else if (messageObject.type == MessageObject.TYPE_VIDEO || messageObject.type == MessageObject.TYPE_GIF) { createDocumentLayout(0, messageObject); currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40); updateSecretTimeText(messageObject); needQualityPreview = true; } else if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40); needQualityPreview = true; } if (currentMessageObject.strippedThumb != null) { currentPhotoObjectThumb = null; currentPhotoObjectThumbStripped = currentMessageObject.strippedThumb; } int w; int h; if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { if (isPlayingRound && !messageObject.isVoiceTranscriptionOpen()) { w = h = AndroidUtilities.roundPlayingMessageSize(isSideMenued); } else { w = h = AndroidUtilities.roundMessageSize; } } else { TLRPC.PhotoSize size = currentPhotoObject != null ? currentPhotoObject : currentPhotoObjectThumb; int imageW = 0; int imageH = 0; if (messageObject.hasExtendedMediaPreview()) { TLRPC.TL_messageExtendedMediaPreview preview = (TLRPC.TL_messageExtendedMediaPreview) messageObject.messageOwner.media.extended_media.get(0); if (preview.w != 0 && preview.h != 0) { imageW = preview.w; imageH = preview.h; } else if (preview.thumb != null) { imageW = preview.thumb.w; imageH = preview.thumb.h; } } else if (size != null && !(size instanceof TLRPC.TL_photoStrippedSize)) { imageW = size.w; imageH = size.h; } else if (documentAttach != null) { for (int a = 0, N = documentAttach.attributes.size(); a < N; a++) { TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeVideo) { imageW = attribute.w; imageH = attribute.h; } } } PointF point = getMessageSize(imageW, imageH, photoWidth, photoHeight); w = (int) point.x; h = (int) point.y; } if (currentPhotoObject != null && "s".equals(currentPhotoObject.type)) { currentPhotoObject = null; } if (currentPhotoObject != null && currentPhotoObject == currentPhotoObjectThumb) { if (messageObject.type == MessageObject.TYPE_PHOTO || messageObject.hasVideoCover() && !messageObject.isLivePhoto() || messageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW) { currentPhotoObjectThumb = null; currentPhotoObjectThumbStripped = null; } else { currentPhotoObject = null; } } if (needQualityPreview) { if (!messageObject.needDrawBluredPreview() && (currentPhotoObject == null || currentPhotoObject == currentPhotoObjectThumb) && (currentPhotoObjectThumb == null || !"m".equals(currentPhotoObjectThumb.type))) { photoImage.setNeedsQualityThumb(true); photoImage.setShouldGenerateQualityThumb(true); } } if (currentMessagesGroup == null && messageObject.caption != null && !captionAbove) { mediaBackground = false; } if ((w == 0 || h == 0) && messageObject.type == MessageObject.TYPE_GIF) { TLRPC.Document document = messageObject.getDocument(); if (document != null) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeImageSize || attribute instanceof TLRPC.TL_documentAttributeVideo) { float scale = (float) attribute.w / (float) photoWidth; w = (int) (attribute.w / scale); h = (int) (attribute.h / scale); if (h > photoHeight) { float scale2 = h; h = photoHeight; scale2 /= h; w = (int) (w / scale2); } else if (h < dp(120)) { h = dp(120); float hScale = (float) attribute.h / h; if (attribute.w / hScale < photoWidth) { w = (int) (attribute.w / hScale); } } break; } } } } if (w == 0 || h == 0) { w = h = dp(150); } if (messageObject.type == MessageObject.TYPE_VIDEO) { if (w < infoWidth + dp(16 + 24)) { w = infoWidth + dp(16 + 24); } } if (messageObject.type == MessageObject.TYPE_STORY || messageObject.type == MessageObject.TYPE_STORY_MENTION) { w = (int) Math.min(AndroidUtilities.displaySize.x * 0.53, dp(300)); h = (int) (w * 16f / 9f); } if (commentLayout != null && drawSideButton != 3 && w < totalCommentWidth + dp(10)) { w = totalCommentWidth + dp(10); } if (currentMessagesGroup != null) { int firstLineWidth = 0; int dWidth = getGroupPhotosWidth(); for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } availableTimeWidth = firstLineWidth - dp(35); } else { availableTimeWidth = photoWidth - dp(14); } if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { availableTimeWidth = (int) (AndroidUtilities.roundMessageSize - Math.ceil(Theme.chat_audioTimePaint.measureText("00:00")) - dp(46)); } measureTime(messageObject); int timeWidthTotal = timeWidth + dp((SharedConfig.bubbleRadius >= 10 ? 22 : 18) + (messageObject.isOutOwner() ? 20 : 0)); if (w < timeWidthTotal) { w = timeWidthTotal; } if (messageObject.isRoundVideo()) { w = h = Math.min(w, h); drawBackground = messageObject.isVoiceTranscriptionOpen(); mediaBackground = !drawBackground; if (drawBackground) { h = 0; } photoImage.setRoundRadius(w / 2); canChangeRadius = false; } else if (messageObject.needDrawBluredPreview() && !messageObject.hasExtendedMediaPreview()) { if (AndroidUtilities.isTablet()) { w = (int) (AndroidUtilities.getMinTabletSide() * 0.6f); } else { w = (int) (Math.min(getParentWidth(), AndroidUtilities.displaySize.y) * 0.6f); } h = (int) (0.61f * w); } int widthForCaption = 0; int widthCaptionMin = -1; boolean fixPhotoWidth = false; if (currentMessagesGroup != null) { float maxHeight = Math.max(getParentWidth(), AndroidUtilities.displaySize.y) * 0.5f; int dWidth = getGroupPhotosWidth(); w = (int) Math.ceil(currentPosition.pw / 1000.0f * dWidth); if (currentPosition.minY != 0 && (messageObject.isOutOwner() && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 || !messageObject.isOutOwner() && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0)) { int firstLineWidth = 0; int currentLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil(position.pw / 1000.0f * dWidth) + (position.leftSpanOffset != 0 ? Math.ceil(position.leftSpanOffset / 1000.0f * dWidth) : 0); } else if (position.minY == currentPosition.minY) { currentLineWidth += Math.ceil((position.pw) / 1000.0f * dWidth) + (position.leftSpanOffset != 0 ? Math.ceil(position.leftSpanOffset / 1000.0f * dWidth) : 0); } else if (position.minY > currentPosition.minY) { break; } } w += firstLineWidth - currentLineWidth; } w -= dp(9); if (currentMessageObject != null && !currentMessageObject.isOutOwner() && isSideMenuPossibleLeftMargin()) { w -= dp(ChatActivity.SIDE_MENU_WIDTH); } else if (isAvatarVisible) { w -= dp(48); } if (currentPosition.siblingHeights != null) { h = 0; for (int a = 0; a < currentPosition.siblingHeights.length; a++) { h += (int) Math.ceil(maxHeight * currentPosition.siblingHeights[a]); } h += (currentPosition.maxY - currentPosition.minY) * Math.round(7 * AndroidUtilities.density); //TODO fix } else { h = (int) Math.ceil(maxHeight * currentPosition.ph); } backgroundWidth = w; if ((currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0) { w -= dp(8); } else if ((currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) == 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { w -= dp(11); } else if ((currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0) { w -= dp(10); } else { w -= dp(9); } photoWidth = w; if (!currentPosition.edge) { photoWidth += dp(10); } photoHeight = h; if (currentPosition == null || (currentPosition.flags & captionFlag()) != 0) { widthForCaption += photoWidth - dp(15); } boolean checkCaption = true; if ((currentPosition.flags & captionFlag()) != 0 || captionAbove || currentMessagesGroup.hasSibling && (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { if (currentPosition == null || (currentPosition.flags & captionFlag()) != 0) { widthForCaption += getAdditionalWidthForPosition(currentPosition); } int count = Math.min(currentMessagesGroup.posArray.size(), currentMessagesGroup.messages.size()); for (int i = 0; i < count; i++) { MessageObject m = currentMessagesGroup.messages.get(i); MessageObject.GroupedMessagePosition rowPosition = currentMessagesGroup.posArray.get(i); if (rowPosition != currentPosition && (rowPosition.flags & captionFlag()) != 0) { w = (int) Math.ceil(rowPosition.pw / 1000.0f * dWidth); if (rowPosition.minY != 0 && (messageObject.isOutOwner() && (rowPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 || !messageObject.isOutOwner() && (rowPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0)) { int firstLineWidth = 0; int currentLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil(position.pw / 1000.0f * dWidth) + (position.leftSpanOffset != 0 ? Math.ceil(position.leftSpanOffset / 1000.0f * dWidth) : 0); } else if (position.minY == rowPosition.minY) { currentLineWidth += Math.ceil((position.pw) / 1000.0f * dWidth) + (position.leftSpanOffset != 0 ? Math.ceil(position.leftSpanOffset / 1000.0f * dWidth) : 0); } else if (position.minY > rowPosition.minY) { break; } } w += firstLineWidth - currentLineWidth; } w -= dp(9); if ((rowPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0 && (rowPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0) { w -= dp(8); } else if ((rowPosition.flags & MessageObject.POSITION_FLAG_RIGHT) == 0 && (rowPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { w -= dp(11); } else if ((rowPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0) { w -= dp(10); } else { w -= dp(9); } if (((isChat || m.isRepostPreview) && !isThreadPost && !m.isOutOwner() || m.forceAvatar || m.messageOwner.guestchat_via_from != null || m.getDialogId() == UserObject.VERIFY) && m.needDrawAvatar() && (rowPosition == null || rowPosition.edge)) { w -= dp(48); } w += getAdditionalWidthForPosition(rowPosition); if (!rowPosition.edge) { w += dp(10); } widthForCaption += w; if (rowPosition.minX < currentPosition.minX || currentMessagesGroup.hasSibling && rowPosition.minY != rowPosition.maxY) { captionOffsetX -= w; } } if (checkCaption) { if (m.caption != null) { if (currentCaption != null) { currentCaption = null; checkCaption = false; } else { currentCaption = m.caption; } } } } if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && currentCaption != null) { currentMessagesGroup.cachedWidthForCaption = widthForCaption; } else if (currentMessagesGroup.cachedWidthForCaption > 0) { widthForCaption = currentMessagesGroup.cachedWidthForCaption; } } } else { photoHeight = h; photoWidth = w; currentCaption = messageObject.caption; int minCaptionWidth = currentMessageObject.getMaxMessageTextWidth(); if (!messageObject.needDrawBluredPreview() && (currentCaption != null || (!reactionsLayoutInBubble.isEmpty && !reactionsLayoutInBubble.isSmall)) && photoWidth < minCaptionWidth) { widthForCaption = minCaptionWidth; fixPhotoWidth = true; } else { widthForCaption = photoWidth - dp(10); } backgroundWidth = photoWidth + dp(8); if (!mediaBackground) { backgroundWidth += dp(9); } } if (currentCaption != null) { try { captionFullWidth = widthForCaption; widthForCaption -= getExtraTextX() * 2; captionLayout = new MessageObject.TextLayoutBlocks(getPrimaryMessageObject(), currentCaption, Theme.chat_msgTextPaint, widthForCaption); captionLayout.bounceFrom(prevCaptionLayout); if (fixPhotoWidth) { captionWidth = captionLayout.textWidth; // feature: blur on sides, instead of cropping photo // if (!currentMessageObject.isVideo() && !currentMessageObject.isGif() && captionWidth > photoWidth - dp(10)) { // fitPhotoImage = true; // photoImage.setAspectFit(true); // photoImage.setRoundRadiusEnabled(false); // } if (captionWidth > widthForCaption) { captionWidth = widthForCaption; } } else { captionWidth = widthForCaption; } if (widthCaptionMin > 0 && captionWidth > widthCaptionMin) { photoWidth += captionWidth - widthCaptionMin; backgroundWidth += captionWidth - widthCaptionMin; } captionHeight = captionLayout.textHeight(); addedCaptionHeight = captionHeight + dp(9); if (!captionAbove && (captionLayout.hasCodeAtBottom || captionLayout.hasQuoteAtBottom)) { captionHeight += dp(14); addedCaptionHeight += dp(14); } if (currentPosition == null || (currentPosition.flags & captionFlag()) != 0) { additionHeight += addedCaptionHeight; int widthToCheck = Math.max(captionWidth, photoWidth - dp(10)); if ((reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) && !shouldDrawTimeOnMedia() && widthToCheck + dp(2) - captionLayout.lastLineWidth < timeWidthTotal + getExtraTimeX() && !hasFactCheck) { additionHeight += dp(14); addedCaptionHeight += dp(14); captionNewLine = 1; } } else { captionLayout = null; } } catch (Exception e) { FileLog.e(e); } } int addedFactCheckHeight = layoutFactCheck(widthForCaption - dp(30)); if (currentPosition == null && hasFactCheck) { additionHeight += dp(12) + addedFactCheckHeight; } if (highlightCaptionToSetStart >= 0 && captionLayout != null) { highlight(highlightCaptionToSetStart, highlightCaptionToSetEnd, captionLayout.textLayoutBlocks); } highlightCaptionToSetStart = highlightCaptionToSetEnd = -1; if (!reactionsLayoutInBubble.isSmall) { boolean useBackgroundWidth = backgroundWidth - dp(24) > widthForCaption; int maxWidth = Math.max(backgroundWidth - dp(36), widthForCaption); reactionsLayoutInBubble.measure(maxWidth, Gravity.LEFT); if (!reactionsLayoutInBubble.isEmpty) { if (isRoundVideo) { reactionsLayoutInBubble.drawServiceShaderBackground = 1f - getVideoTranscriptionProgress(); } else if (shouldDrawTimeOnMedia()) { reactionsLayoutInBubble.drawServiceShaderBackground = 1f; } int heightLocal = reactionsLayoutInBubble.height; if (captionLayout == null) { heightLocal += dp(12); heightLocal += dp(4); } else { heightLocal += dp(12); reactionsLayoutInBubble.positionOffsetY += dp(12); } reactionsLayoutInBubble.totalHeight = heightLocal; additionHeight += reactionsLayoutInBubble.totalHeight; if (isRoundVideo && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen()) { reactionsLayoutInBubble.positionOffsetY += dp(8); } if (!shouldDrawTimeOnMedia()) { int widthToCheck = Math.min(maxWidth, reactionsLayoutInBubble.width + timeWidthTotal + getExtraTimeX() + dp(2)); float lastLineWidth = reactionsLayoutInBubble.lastLineX; if (!shouldDrawTimeOnMedia() && widthToCheck - lastLineWidth < timeWidthTotal + getExtraTimeX()) { additionHeight += dp(14); reactionsLayoutInBubble.totalHeight += dp(14); reactionsLayoutInBubble.positionOffsetY -= dp(14); captionNewLine = 1; if (!useBackgroundWidth && captionWidth < reactionsLayoutInBubble.width) { captionWidth = reactionsLayoutInBubble.width; } } else if (!useBackgroundWidth) { if (reactionsLayoutInBubble.lastLineX + timeWidthTotal > captionWidth) { captionWidth = reactionsLayoutInBubble.lastLineX + timeWidthTotal; } if (reactionsLayoutInBubble.width > captionWidth) { captionWidth = reactionsLayoutInBubble.width; } } } } } int minWidth = (int) (Theme.chat_infoPaint.measureText("100%") + dp(100/*48*/)/* + timeWidth*/); if (currentMessagesGroup == null && (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) && photoWidth < minWidth) { photoWidth = minWidth; backgroundWidth = photoWidth + dp(8); if (!mediaBackground) { backgroundWidth += dp(9); } } if (fixPhotoWidth && photoWidth < captionWidth + dp(10)) { photoWidth = captionWidth + dp(10); backgroundWidth = photoWidth + dp(8); if (!mediaBackground) { backgroundWidth += dp(9); } } if (messageChanged || messageIdChanged || dataChanged) { currentPhotoFilter = currentPhotoFilterThumb = String.format(Locale.US, "%d_%d", (int) (w / AndroidUtilities.density), (int) (h / AndroidUtilities.density)); if ( messageObject.photoThumbs != null && messageObject.photoThumbs.size() > 1 || messageObject.type == MessageObject.TYPE_VIDEO || messageObject.type == MessageObject.TYPE_GIF || messageObject.type == MessageObject.TYPE_ROUND_VIDEO ) { if (messageObject.needDrawBluredPreview()) { photoImage.setColorFilter(getFancyBlurFilter()); if (!messageObject.isRoundOnce()) { currentPhotoFilter += "_b2"; } if (messageObject.isRoundOnce()) { currentPhotoFilterThumb += "_b2r"; } else { currentPhotoFilterThumb += "_b2"; } } else { currentPhotoFilterThumb += "_b"; } } } else { String filterNew = String.format(Locale.US, "%d_%d", (int) (w / AndroidUtilities.density), (int) (h / AndroidUtilities.density)); if (!messageObject.needDrawBluredPreview() && !filterNew.equals(currentPhotoFilter)) { ImageLocation location = ImageLocation.getForObject(currentPhotoObject, photoParentObject); if (location != null) { String key = location.getKey(photoParentObject, null, false) + "@" + currentPhotoFilter; if (ImageLoader.getInstance().isInMemCache(key, false)) { currentPhotoObjectThumb = currentPhotoObject; currentPhotoFilterThumb = currentPhotoFilter; currentPhotoFilter = filterNew; } } } else if (messageObject.needDrawBluredPreview()) { photoImage.setColorFilter(getFancyBlurFilter()); } } boolean noSize = false; if (messageObject.type == MessageObject.TYPE_VIDEO || messageObject.type == MessageObject.TYPE_GIF || messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { noSize = true; } if (currentPhotoObject != null && !noSize && currentPhotoObject.size == 0) { currentPhotoObject.size = -1; } if (currentPhotoObjectThumb != null && !noSize && currentPhotoObjectThumb.size == 0) { currentPhotoObjectThumb.size = -1; } if (!currentMessageObject.isHiddenSensitive() && SharedConfig.isAutoplayVideo() && (!currentMessageObject.hasVideoCover() || currentMessageObject.isLivePhoto()) && !currentMessageObject.isRepostPreview && (!currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || currentMessageObject.revealingMediaSpoilers) && (messageObject.type == MessageObject.TYPE_VIDEO /*|| messageObject.type == MessageObject.TYPE_STORY && messageObject.getDocument() != null*/) && !messageObject.needDrawBluredPreview() && ((currentMessageObject.mediaExists || currentMessageObject.attachPathExists) || messageObject.canStreamVideo() && DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject)) ) { if (currentPosition != null) { autoPlayingMedia = (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0; } else { autoPlayingMedia = true; } } final int cacheType = currentMessageObject.shouldEncryptPhotoOrVideo() ? ImageLoader.CACHE_TYPE_ENCRYPTED : ImageLoader.CACHE_TYPE_NONE; if (currentMessageObject.sendPreviewEntry != null) { photoImage.setCrossfadeWithOldImage(false); if (currentMessageObject.sendPreviewEntry.thumbPath != null) { photoImage.setImage(ImageLocation.getForPath(currentMessageObject.sendPreviewEntry.thumbPath), null, null, null, null, null, currentMessageObject.sendPreviewEntry.thumb, 0, null, messageObject, 0); } else if (currentMessageObject.sendPreviewEntry.path != null) { if (currentMessageObject.sendPreviewEntry.isVideo && !currentMessageObject.sendPreviewEntry.isLivePhoto()) { photoImage.setImage(ImageLocation.getForPath("vthumb://" + currentMessageObject.sendPreviewEntry.imageId + ":" + currentMessageObject.sendPreviewEntry.path), null, null, null, null, null, currentMessageObject.sendPreviewEntry.thumb, 0, null, messageObject, 0); } else { photoImage.setOrientation(currentMessageObject.sendPreviewEntry.orientation, currentMessageObject.sendPreviewEntry.invert, true); photoImage.setImage(ImageLocation.getForPath("thumb://" + currentMessageObject.sendPreviewEntry.imageId + ":" + currentMessageObject.sendPreviewEntry.path), null, null, null, null, null, currentMessageObject.sendPreviewEntry.thumb, 0, null, messageObject, 0); } } } else if (autoPlayingMedia) { photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); TLRPC.Document document = messageObject.getDocument(); if (messageObject.hasVideoQualities() && messageObject.thumbQuality != null) { document = messageObject.thumbQuality.document; } final String filter = currentMessageObject.isLivePhoto() ? ImageLoader.AUTOPLAY_FILTER_NONLOOP : ImageLoader.AUTOPLAY_FILTER; if (currentMessageObject.videoEditedInfo != null && currentMessageObject.videoEditedInfo.canAutoPlaySourceVideo() && document != null) { photoImage.setImage(ImageLocation.getForPath(currentMessageObject.videoEditedInfo.originalPath), filter, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObjectThumb, document), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, 0); photoImage.setMediaStartEndTime(currentMessageObject.videoEditedInfo.startTime / 1000, currentMessageObject.videoEditedInfo.endTime / 1000); } else if (messageObject.cachedQuality != null) { if (!messageIdChanged && !dataChanged) { photoImage.setCrossfadeWithOldImage(true); } photoImage.setImage(ImageLocation.getForVideoPath(messageObject.cachedQuality.uri.getPath()), filter, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObjectThumb, document), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, messageObject.getDocument().size, null, messageObject, 0); } else if (document != null) { if (!messageIdChanged && !dataChanged) { photoImage.setCrossfadeWithOldImage(true); } photoImage.setImage(ImageLocation.getForDocument(document), filter, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObjectThumb, document), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, messageObject.getDocument().size, null, messageObject, 0); } } else if (messageObject.type == MessageObject.TYPE_STORY || messageObject.type == MessageObject.TYPE_STORY_MENTION) { TL_stories.StoryItem storyItem = messageObject.messageOwner.media.storyItem; if (storyItem != null) { if (storyItem instanceof TL_stories.TL_storyItemDeleted) { photoImage.setImageBitmap(StoriesUtilities.getExpiredStoryDrawable()); } else { StoriesUtilities.setImage(photoImage, storyItem); } } else { photoImage.clearImage(); } } else if (messageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW) { photoImage.setImage(null, null, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, currentMessageObject, cacheType); } else if (messageObject.type == MessageObject.TYPE_PHOTO) { if (messageObject.useCustomPhoto) { photoImage.setImageBitmap(getResources().getDrawable(R.drawable.theme_preview_image)); } else { if (currentPhotoObject != null) { boolean photoExist = true; String fileName = FileLoader.getAttachFileName(currentPhotoObject); if (messageObject.mediaExists) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); } else { photoExist = false; } if (photoExist || !currentMessageObject.loadingCancelled && DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, currentPhotoObject.size, null, currentMessageObject, cacheType); } else { photoNotSet = true; if (currentPhotoObjectThumb != null || currentPhotoObjectThumbStripped != null) { photoImage.setImage(null, null, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, currentMessageObject, cacheType); } else { photoImage.setImageBitmap((Drawable) null); } } } else { photoImage.setImageBitmap((Drawable) null); } } } else if (messageObject.type == MessageObject.TYPE_GIF || messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { String fileName = FileLoader.getAttachFileName(messageObject.getDocument()); int localFile = 0; if (messageObject.attachPathExists) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); localFile = 1; } else if (messageObject.mediaExists) { localFile = 2; } boolean autoDownload = false; TLRPC.Document document = messageObject.getDocument(); if (MessageObject.isGifDocument(document, messageObject.hasValidGroupId()) || messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject); } if (messageObject.isHiddenSensitive()) { autoDownload = false; } TLRPC.VideoSize videoSize = MessageObject.getDocumentVideoThumb(document); if (((MessageObject.isGifDocument(document, messageObject.hasValidGroupId()) && messageObject.videoEditedInfo == null) || (!messageObject.isSending() && !messageObject.isEditing())) && (localFile != 0 || FileLoader.getInstance(currentAccount).isLoadingFile(fileName) || autoDownload)) { if (localFile != 1 && !messageObject.needDrawBluredPreview() && (localFile != 0 || messageObject.canStreamVideo() && autoDownload)) { autoPlayingMedia = true; if (!messageIdChanged) { photoImage.setCrossfadeWithOldImage(true); photoImage.setCrossfadeDuration(250); } if (localFile == 0 && videoSize != null && (currentPhotoObject == null || currentPhotoObjectThumb == null)) { photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForDocument(videoSize, documentAttach), null, ImageLocation.getForDocument(currentPhotoObject != null ? currentPhotoObject : currentPhotoObjectThumb, documentAttach), currentPhotoObject != null ? currentPhotoFilter : currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, cacheType); } else { if (isRoundVideo && !messageIdChanged && photoImage.hasStaticThumb()) { photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, null, null, photoImage.getStaticThumb(), document.size, null, messageObject, messageObject.isRoundOnce() ? cacheType : 0); } else { photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, cacheType); } } } else if (localFile == 1) { photoImage.setImage(ImageLocation.getForPath(messageObject.isSendError() ? null : messageObject.messageOwner.attachPath), null, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, cacheType); } else { if (videoSize != null && (currentPhotoObject == null || currentPhotoObjectThumb == null)) { photoImage.setImage(ImageLocation.getForDocument(document), null, ImageLocation.getForDocument(videoSize, documentAttach), null, ImageLocation.getForDocument(currentPhotoObject != null ? currentPhotoObject : currentPhotoObjectThumb, documentAttach), currentPhotoObject != null ? currentPhotoFilter : currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, cacheType); } else { photoImage.setImage(ImageLocation.getForDocument(document), null, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, messageObject.isRoundOnce() ? cacheType : 0); } } } else { if (messageObject.videoEditedInfo != null && messageObject.type == MessageObject.TYPE_ROUND_VIDEO && !currentMessageObject.needDrawBluredPreview()) { photoImage.setImage(ImageLocation.getForPath(messageObject.videoEditedInfo.originalPath), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); photoImage.setMediaStartEndTime(currentMessageObject.videoEditedInfo.startTime / 1000, currentMessageObject.videoEditedInfo.endTime / 1000); } else { if (!messageIdChanged && !currentMessageObject.needDrawBluredPreview()) { photoImage.setCrossfadeWithOldImage(true); photoImage.setCrossfadeDuration(250); } photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, cacheType); } } } else { if (messageObject.videoEditedInfo != null && messageObject.type == MessageObject.TYPE_ROUND_VIDEO && !currentMessageObject.needDrawBluredPreview()) { photoImage.setImage(ImageLocation.getForPath(messageObject.videoEditedInfo.originalPath), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, cacheType); photoImage.setMediaStartEndTime(currentMessageObject.videoEditedInfo.startTime / 1000, currentMessageObject.videoEditedInfo.endTime / 1000); } else { if (!messageIdChanged && !currentMessageObject.needDrawBluredPreview()) { photoImage.setCrossfadeWithOldImage(true); photoImage.setCrossfadeDuration(250); } photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, cacheType); } } } clearBlurredImage(blurredPhotoImage); if (photoImage.getBitmap() != null && !photoImage.getBitmap().isRecycled() && (currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed || fitPhotoImage)) { blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(photoImage.getBitmap(), currentMessageObject.isRoundVideo())); blurredPhotoImage.setColorFilter(getFancyBlurFilter()); } setMessageObjectInternal(messageObject); if (drawForwardedName && messageObject.needDrawForwarded() && (currentPosition == null || currentPosition.minY == 0)) { if (messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { namesOffset += dp(5); } } else if (drawNameLayout && (messageObject.getReplyMsgId() == 0 || isThreadChat && messageObject.getReplyTopMsgId() == 0)) { namesOffset += dp(7); } totalHeight = photoHeight + dp(14) + namesOffset + additionHeight; if (messageObject.isVoiceTranscriptionOpen()) { totalHeight += dp(70 - 14); } if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0 && !currentMessageObject.isDocument() && currentMessageObject.type != MessageObject.TYPE_EMOJIS) { totalHeight -= dp(3); } if (currentMessageObject.isDice()) { totalHeight += dp(21); additionalTimeOffsetY = dp(21); } int additionalTop = 0; if (currentPosition != null && !currentMessageObject.isDocument()) { photoWidth += getAdditionalWidthForPosition(currentPosition); if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { photoHeight += dp(4); additionalTop -= dp(4); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { photoHeight += dp(1); } } else if (currentPosition != null && currentMessageObject.isDocument()) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && !messageObject.isOutOwner() && !drawPhotoImage) { totalHeight -= dp(2); } } if (captionLayout != null && captionAbove && (currentPosition == null || (currentPosition.flags & captionFlag()) != 0)) { additionalTop = captionLayout.textHeight() + dp(8); } int y = 0; if (currentMessageObject.type != MessageObject.TYPE_EMOJIS) { if (drawPinnedTop) { namesOffset -= dp(documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT ? 2 : 1); } if (drawPinnedTop && !messageObject.isOutOwner()) { totalHeight += dp(documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT ? 2 : 0); } // if (drawPinnedBottom && !messageObject.isOutOwner()) { // totalHeight += dp(documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT ? 1 : 0); // } if (namesOffset > 0) { y = dp(7); totalHeight -= dp(2); } else { y = dp(5); totalHeight -= dp(4); } } if (currentPosition != null && currentMessagesGroup.isDocuments && currentMessagesGroup.messages.size() > 1) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { totalHeight -= dp(drawPhotoImage ? 3 : 6); mediaOffsetY -= dp(drawPhotoImage ? 3 : 6); y -= dp(drawPhotoImage ? 3 : 6); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { totalHeight -= dp(drawPhotoImage ? 3 : 6); } } if (messageObject.isRoundVideo() && messageObject.isVoiceTranscriptionOpen()) { photoImage.setImageCoords(0, dp(13), dp(44), dp(44)); } else { photoImage.setImageCoords(0, y + namesOffset + additionalTop, photoWidth, photoHeight); } if (messageObject.hasMediaSpoilers() && SpoilerEffect2.supports()) { if (mediaSpoilerEffect2 == null && attachedToWindow) { mediaSpoilerEffect2 = makeSpoilerEffect(); if (mediaSpoilerEffect2Index != null) { mediaSpoilerEffect2.reassignAttach(this, mediaSpoilerEffect2Index); } } } else { if (mediaSpoilerEffect2 != null) { mediaSpoilerEffect2.detach(this); mediaSpoilerEffect2 = null; } } invalidate(); } if ((currentPosition == null || currentMessageObject.isMusic() || currentMessageObject.type == MessageObject.TYPE_PAID_MEDIA || currentMessageObject.isDocument()) && !messageObject.isSponsored() && !messageObject.isAnyKindOfSticker() && addedCaptionHeight == 0 && !messageObject.isExpiredStory() && !messageObject.isUnsupported()) { int addCaptionLayoutWidth = 0; int width = backgroundWidth; if ((currentMessageObject.type == MessageObject.TYPE_VOICE || isRoundVideo) && messageObject.isVoiceTranscriptionOpen() && messageObject.getFactCheck() == null) { if (AndroidUtilities.isTablet()) { width = AndroidUtilities.getMinTabletSide() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)); } else { width = getParentWidth() - dp(50 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)); } } if (drawSideButton != 0 && isRoundVideo) { width -= dp(24); } int widthForCaption = width - dp(31 + (currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO ? 14 : 0)) - getExtraTextX() * 2; if (!messageObject.isRestrictedMessage && captionLayout == null && (messageObject.caption != null || messageObject.isVoiceTranscriptionOpen())) { currentCaption = messageObject.isVoiceTranscriptionOpen() ? messageObject.getVoiceTranscription() : messageObject.caption; if (currentCaption != null && !TextUtils.isEmpty(messageObject.messageOwner.voiceTranscription) && currentMessageObject.isVoiceTranscriptionOpen() && !currentMessageObject.messageOwner.voiceTranscriptionFinal) { currentCaption += " "; if (!(currentCaption instanceof Spannable)) { currentCaption = new SpannableString(currentCaption); } ((SpannableString) currentCaption).setSpan(new TranscribeButton.LoadingPointsSpan(), currentCaption.length() - 1, currentCaption.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } try { captionFullWidth = widthForCaption; captionLayout = new MessageObject.TextLayoutBlocks(getPrimaryMessageObject(), currentCaption, Theme.chat_msgTextPaint, widthForCaption); captionLayout.bounceFrom(prevCaptionLayout); updateSeekBarWaveformWidth(null); } catch (Exception e) { FileLog.e(e); } } if (highlightCaptionToSetStart >= 0 && captionLayout != null) { highlight(highlightCaptionToSetStart, highlightCaptionToSetEnd, captionLayout.textLayoutBlocks); } highlightCaptionToSetStart = highlightCaptionToSetEnd = -1; if ((currentMessageObject.type == MessageObject.TYPE_FILE || currentMessageObject.type == MessageObject.TYPE_VOICE) && currentPosition == null) { totalHeight += layoutFactCheck(widthForCaption); if (hasFactCheck) { totalHeight += dp(6 + (captionLayout == null ? 18 : 8)); } } if (captionLayout != null || currentMessageObject.type == MessageObject.TYPE_VOICE || currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { try { if (messageObject.isVoiceTranscriptionOpen() && captionLayout != null) { float startMaxWidth = backgroundWidth - dp(31) - dp(10) - getExtraTextX() * 2, maxWidth = startMaxWidth; maxWidth = Math.max(maxWidth, captionLayout.textWidth); backgroundWidth += maxWidth - startMaxWidth; } int width2 = backgroundWidth - dp(31); Float lastCaptionLineWidth = null; if (captionLayout != null) { lastCaptionLineWidth = (float) captionLayout.lastLineWidth; } else if (currentMessageObject.type == MessageObject.TYPE_VOICE) { lastCaptionLineWidth = (float) dp(64); } if (lastCaptionLineWidth != null) { if (captionLayout != null) { captionWidth = width2; captionHeight = captionLayout.textHeight(); } totalHeight += captionHeight + (currentMessageObject.type != MessageObject.TYPE_POLL ? dp(9) : 0); if (captionLayout != null && (captionLayout.hasCodeAtBottom || captionLayout.hasQuoteAtBottom)) { captionHeight += dp(10); totalHeight += dp(10); } if (currentMessageObject.type != MessageObject.TYPE_POLL && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) && (currentPosition == null || (currentPosition.flags & captionFlag()) != 0)) { int timeWidthTotal = timeWidth + (messageObject.isOutOwner() ? dp(20) : 0) + getExtraTimeX(); if (width2 - dp(8) - lastCaptionLineWidth < timeWidthTotal || hasFactCheck) { totalHeight += dp(14); if (captionLayout != null) { captionHeight += dp(14); captionNewLine = 2; } } } } } catch (Exception e) { FileLog.e(e); } } if (captionLayout != null && currentMessageObject.type == MessageObject.TYPE_POLL) { TLRPC.MessageMedia m = MessageObject.getMedia(messageObject.messageOwner); if (pollButtons != null && m instanceof TLRPC.TL_messageMediaPoll) { for (PollButton button : pollButtons) { button.y += captionHeight; } } } } if (currentMessageObject.eventId != 0 && !currentMessageObject.isMediaEmpty() && MessageObject.getMedia(currentMessageObject.messageOwner).webpage != null) { int linkPreviewMaxWidth = backgroundWidth - dp(41); hasOldCaptionPreview = true; linkPreviewHeight = 0; TLRPC.WebPage webPage = MessageObject.getMedia(currentMessageObject.messageOwner).webpage; try { int width = siteNameWidth = (int) Math.ceil(Theme.chat_replyNamePaint.measureText(webPage.site_name) + 1); siteNameLayout = new StaticLayout(webPage.site_name, Theme.chat_replyNamePaint, Math.min(width, linkPreviewMaxWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); siteNameLeft = siteNameLayoutWidth = 0; for (int i = 0; i < siteNameLayout.getLineCount(); ++i) { siteNameLeft = siteNameLayout.getLineLeft(i); siteNameLayoutWidth = siteNameLayout.getLineWidth(i); } int height = siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1); linkPreviewHeight += height; totalHeight += height; } catch (Exception e) { FileLog.e(e); } try { descriptionX = 0; if (linkPreviewHeight != 0) { totalHeight += dp(2); } descriptionLayout = StaticLayoutEx.createStaticLayout(webPage.description, Theme.chat_replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, 6); int height = descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); linkPreviewHeight += height; totalHeight += height; boolean hasNonRtl = false; for (int a = 0; a < descriptionLayout.getLineCount(); a++) { int lineLeft = (int) Math.ceil(descriptionLayout.getLineLeft(a)); if (lineLeft != 0) { if (descriptionX == 0) { descriptionX = -lineLeft; } else { descriptionX = Math.max(descriptionX, -lineLeft); } } else { hasNonRtl = true; } } if (hasNonRtl) { descriptionX = 0; } } catch (Exception e) { FileLog.e(e); } if ( messageObject.type == MessageObject.TYPE_PHOTO || messageObject.type == MessageObject.TYPE_VIDEO || messageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW ) { totalHeight += dp(6); } totalHeight += dp(17); if (captionNewLine != 0) { totalHeight -= dp(14); if (captionNewLine == 2) { captionHeight -= dp(14); } } } for (BotButton botButton : botButtons) { if (botButton.animatedEmojiDrawable != null) { botButton.animatedEmojiDrawable.clear(); } } botButtons.clear(); if (messageIdChanged) { botButtonsByData.clear(); botButtonsByPosition.clear(); botButtonsLayout = null; } drawStartBotTopic = false; drawContinueBotTopic = false; final BotInlineKeyboard.Source inlineButtons; if (lastInChatList && isAllChats && isBotForum && !isPinnedChat && lastSendState == 0) { if (messageObject.getTopicId() > 0) { BotInlineKeyboard.Builder b = new BotInlineKeyboard.Builder(); b.addKeyboardSource(messageObject.getInlineBotButtons()); b.addSeparator(); b.addContinueThreadKeyboard(); inlineButtons = b.build(); drawContinueBotTopic = true; } else { inlineButtons = messageObject.getInlineBotButtons(); } drawStartBotTopic = true; } else { inlineButtons = messageObject.getInlineBotButtons(); } final int separatorHeight = dp(4 + 4); if (!messageObject.isRestrictedMessage && !messageObject.isRepostPreview && (currentPosition == null || currentMessagesGroup != null && currentMessagesGroup.isDocuments && currentPosition.last) && (inlineButtons != null) && !messageObject.hasExtendedMedia()) { int rows, separators; if (inlineButtons != null) { rows = inlineButtons.getRowsCount(); separators = 0; for (int a = 0; a < rows; a++) { if (inlineButtons.hasSeparator(a)) { separators++; } } } else { rows = 1; separators = 0; } substractBackgroundHeight = keyboardHeight = dp(44 + 4) * rows + dp(1) + separatorHeight * separators; widthForButtons = backgroundWidth - dp(mediaBackground ? 0 : 9); boolean fullWidth = false; if (messageObject.wantedBotKeyboardWidth > widthForButtons) { int maxButtonWidth = -dp(10 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : drawAvatar ? 52 : 0)); if (AndroidUtilities.isTablet()) { maxButtonWidth += AndroidUtilities.getMinTabletSide(); } else { maxButtonWidth += Math.min(getParentWidth(), AndroidUtilities.displaySize.y) - dp(5); } widthForButtons = Math.max(backgroundWidth, Math.min(messageObject.wantedBotKeyboardWidth, maxButtonWidth)); } int maxButtonsWidth = 0; HashMap oldByData = new HashMap<>(botButtonsByData); HashMap oldByPosition; if (messageObject.botButtonsLayout != null && botButtonsLayout != null && botButtonsLayout.equals(messageObject.botButtonsLayout.toString())) { oldByPosition = new HashMap<>(botButtonsByPosition); } else { if (messageObject.botButtonsLayout != null) { botButtonsLayout = messageObject.botButtonsLayout.toString(); } oldByPosition = null; } botButtonsByData.clear(); if (inlineButtons != null) { int separatorsHeight = 0; for (int row = 0; row < rows; row++) { int buttonsCount = inlineButtons.getColumnsCount(row); if (buttonsCount == 0) { continue; } int buttonWidth = (widthForButtons - dp(5) * (buttonsCount - 1) - dp(2)) / buttonsCount; for (int column = 0; column < buttonsCount; column++) { BotInlineKeyboard.Button inlineButton = inlineButtons.getButton(row, column); BotButton botButton = new BotButton(this::invalidateOutbounds); botButton.buttonImpl = inlineButton; if (inlineButton instanceof BotInlineKeyboard.ButtonBot) { botButton.button = ((BotInlineKeyboard.ButtonBot) inlineButton).button; } else if (inlineButton instanceof BotInlineKeyboard.ButtonCustom) { botButton.buttonCustom = (BotInlineKeyboard.ButtonCustom) inlineButton; if (currentMessageObject != null && ChatObject.canManageMonoForum(currentAccount, currentMessageObject.getDialogId()) && !ChatObject.canUserDoChannelDirectAdminAction(currentAccount, currentMessageObject.getDialogId(), ChatObject.ACTION_POST) && (botButton.buttonCustom.id == BotInlineKeyboard.ButtonCustom.SUGGESTION_ACCEPT || botButton.buttonCustom.id == BotInlineKeyboard.ButtonCustom.SUGGESTION_EDIT)) { botButton.isLocked = true; } } final long emojiId = inlineButton.getIconEmoji(); final int iconRes = inlineButton.getIconRes(); if (emojiId != 0) { botButton.animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, currentAccount, emojiId); botButton.animatedEmojiDrawable.addView(this::invalidateOutbounds); botButton.animatedEmojiDrawable.setColorFilter(new PorterDuffColorFilter(0xFFFFFFFF, PorterDuff.Mode.SRC_IN)); } else if (iconRes != 0) { botButton.iconDrawable = getResources().getDrawable(iconRes); botButton.iconDrawable.setColorFilter(new PorterDuffColorFilter(0xFFFFFFFF, PorterDuff.Mode.SRC_IN)); } String key = botButton.button != null ? Utilities.bytesToHex(botButton.button.getData()) : ""; String position = row + "_" + column; BotButton oldButton; if (oldByPosition != null) { oldButton = oldByPosition.get(position); } else { oldButton = oldByData.get(key); } if (oldButton != null) { botButton.progressAlpha = oldButton.progressAlpha; botButton.angle = oldButton.angle; botButton.lastUpdateTime = oldButton.lastUpdateTime; } else { botButton.lastUpdateTime = System.currentTimeMillis(); } botButtonsByData.put(key, botButton); botButtonsByPosition.put(position, botButton); botButton.x = (float) column * (buttonWidth + dp(5)) / widthForButtons; botButton.y = row * dp(44 + 4) + dp(2.5f) + separatorsHeight; botButton.width = (float) buttonWidth / widthForButtons; botButton.height = dp(44); if (column == 0) { botButton.positionFlags |= MessageObject.POSITION_FLAG_LEFT; } if (column == buttonsCount - 1) { botButton.positionFlags |= MessageObject.POSITION_FLAG_RIGHT; } if (row == 0) { botButton.positionFlags |= MessageObject.POSITION_FLAG_TOP; } if (row == rows - 1) { botButton.positionFlags |= MessageObject.POSITION_FLAG_BOTTOM; } CharSequence buttonText; TextPaint botButtonPaint = (TextPaint) getThemedPaint(Theme.key_paint_chatBotButton); if (TLKeyboardHelper.isType(botButton.button, TL_keyboard.TL_inlineButtonTypeBuy.class) && (MessageObject.getMedia(messageObject.messageOwner).flags & 4) != 0) { buttonText = getString(R.string.PaymentReceipt); } else { buttonText = inlineButton.getText(); } if (inlineButton instanceof BotInlineKeyboard.ButtonCustom) { if (((BotInlineKeyboard.ButtonCustom) inlineButton).id == BotInlineKeyboard.ButtonCustom.OPEN_MESSAGE_THREAD) { buttonText = new SpannableStringBuilder(buttonText).append(">"); final ColoredImageSpan span = new ColoredImageSpan(R.drawable.msg_inputarrow); span.setScale(.8f, .8f); span.setAlpha(0.6f); ((SpannableStringBuilder) buttonText).setSpan(span, buttonText.length() - 1, buttonText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } if (TLKeyboardHelper.isType(botButton.button, TL_keyboard.TL_inlineButtonTypeBuy.class) && MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) { buttonText = StarsIntroActivity.replaceStars(buttonText); } if (TLKeyboardHelper.isType(botButton.button, TL_keyboard.TL_inlineButtonTypeCopy.class)) { buttonText = new SpannableStringBuilder("c ").append(buttonText); final ColoredImageSpan span = new ColoredImageSpan(R.drawable.menu_copy_s); span.setScale(.9f, .9f); ((SpannableStringBuilder) buttonText).setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } buttonText = Emoji.replaceEmoji(buttonText, botButtonPaint.getFontMetricsInt(), false); if (oldButton != null && oldButton.title != null && TextUtils.equals(oldButton.title.getText(), buttonText)) { botButton.title = oldButton.title; } else { botButton.title = new Text(buttonText, botButtonPaint); } botButtons.add(botButton); if (column == buttonsCount - 1) { maxButtonsWidth = Math.max(maxButtonsWidth, (int) (botButton.x * widthForButtons) + (int) (botButton.width * widthForButtons)); } final TL_keyboard.TL_inlineButtonTypeUrl buttonTypeUrl = TLKeyboardHelper.getType(botButton.button, TL_keyboard.TL_inlineButtonTypeUrl.class); if (messageObject.isFromUser() && buttonTypeUrl != null) { try { final Uri uri = Uri.parse(buttonTypeUrl.url); final String host = uri.getHost().toLowerCase(); botButton.isInviteButton = (uri.getQueryParameter("startgroup") != null && ( ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) && ("t.me".equals(host) || "telegram.me".equals(host) || "telegram.dog".equals(host)) || "tg".equals(uri.getScheme()) && (buttonTypeUrl.url.startsWith("tg:resolve") || buttonTypeUrl.url.startsWith("tg://resolve")) )); } catch (Exception ignore) { } } } if (inlineButtons.hasSeparator(row)) { BotButton botButton = new BotButton(this::invalidateParentForce); botButton.isSeparator = true; botButton.y = row * dp(44 + 4) + dp(2.5f) + separatorsHeight + dp(44 + 5); botButton.height = dp(2); botButton.width = (float) (widthForButtons - dp(2)) / widthForButtons;; botButtons.add(botButton); separatorsHeight += separatorHeight; } } } widthForButtons = maxButtonsWidth; } else { substractBackgroundHeight = 0; keyboardHeight = 0; } if (drawCommentButton) { totalHeight += dp(shouldDrawTimeOnMedia() ? 41.3f : 43); createSelectorDrawable(1); } if (hasFactCheck && currentPosition != null) { totalHeight += dp(2 + (reactionsLayoutInBubble.isEmpty ? 18 : 0)) + factCheckHeight; } if (drawPinnedBottom && drawPinnedTop) { totalHeight -= dp(2); } else if (drawPinnedBottom) { totalHeight -= dp(1); } else if (drawPinnedTop && pinnedBottom && currentPosition != null && currentPosition.siblingHeights == null) { totalHeight -= dp(1); } if (!mediaBackground) { if (messageObject.type == MessageObject.TYPE_TEXT) { totalHeight -= dp(2); } if (drawPinnedBottom) { totalHeight -= dp(1); } if (drawPinnedTop) { totalHeight -= dp(1); } } if (messageObject.type != MessageObject.TYPE_EMOJIS) { if (messageObject.isAnyKindOfSticker() && totalHeight < dp(70)) { additionalTimeOffsetY = dp(70) - totalHeight; totalHeight += additionalTimeOffsetY; } else if (messageObject.isAnimatedEmoji()) { additionalTimeOffsetY = dp(16); totalHeight += dp(16); } } if (!drawPhotoImage) { photoImage.setImageBitmap((Drawable) null); clearBlurredImage(blurredPhotoImage); } if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { if (MessageObject.isDocumentHasThumb(documentAttach)) { TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(documentAttach.thumbs, dp(22), true, null, false); TLRPC.PhotoSize image = FileLoader.getClosestPhotoSizeWithSize(documentAttach.thumbs, dp(44), true, thumb, true); radialProgress.setImageOverlay(image, thumb, documentAttach, messageObject); } else { String artworkUrl = messageObject.getArtworkUrl(true); if (!TextUtils.isEmpty(artworkUrl)) { radialProgress.setImageOverlay(artworkUrl); } else { radialProgress.setImageOverlay(null, null, null); } } } else { radialProgress.setImageOverlay(null, null, null); } calculateUnlockXY(); if (canChangeRadius) { int tl, tr, bl, br; int minRad = dp(4); int rad; if (SharedConfig.bubbleRadius > 2) { rad = dp(SharedConfig.bubbleRadius - 2); } else { rad = dp(SharedConfig.bubbleRadius); } int nearRad = Math.min(dp(3), rad); tl = tr = bl = br = rad; if (minRad > tl) { minRad = tl; } if (hasLinkPreview || hasGamePreview || hasInvoicePreview) { tl = tr = bl = br = minRad; } if (forwardedNameLayout[0] != null || replyNameLayout != null || drawNameLayout) { tl = tr = minRad; } if (drawCommentButton || botButtons != null && !botButtons.isEmpty() || hasFactCheck) { bl = br = minRad; } if (captionLayout != null) { if (captionAbove && !(getMedia(messageObject) instanceof TLRPC.TL_messageMediaPoll)) { tl = tr = minRad; } else { bl = br = minRad; } } if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { tr = br = minRad; } if (currentPosition != null && currentMessagesGroup != null) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) == 0) { tr = br = minRad; } if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { tl = bl = minRad; } if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { bl = br = minRad; } if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { tl = tr = minRad; } } if (pinnedTop && (captionLayout == null || !captionAbove)) { if (currentMessageObject.isOutOwner()) { tr = nearRad; } else { tl = nearRad; } } if (pinnedBottom && (captionLayout == null || captionAbove)) { if (currentMessageObject.isOutOwner()) { br = nearRad; } else { bl = nearRad; } } if (!mediaBackground && !currentMessageObject.isOutOwner()) { bl = nearRad; } if (currentMessageObject.type == MessageObject.TYPE_GEO && (MessageObject.getMedia(currentMessageObject) instanceof TLRPC.TL_messageMediaVenue || !locationExpired && MessageObject.getMedia(currentMessageObject) instanceof TLRPC.TL_messageMediaGeoLive)) { br = bl = nearRad; } if (documentAttachType == DOCUMENT_ATTACH_TYPE_STORY) { tl = tr = br = bl = 0; } photoImage.setRoundRadius(tl, tr, br, bl); } updateAnimatedEmojis(); if (stickerSetIcons != null && stickerSetIcons.die()) { stickerSetIcons.detach(this); stickerSetIcons = null; } prevCaptionLayout = null; final int starsPriceMessagesCount; final long starsPrice; final long diceStakeOutcome = currentMessageObject == null || !playedDice ? 0 : currentMessageObject.getStakedDiceWinAmount(); if (currentMessageObject != null && currentMessageObject.getDialogId() < 0) { starsPrice = 0; starsPriceMessagesCount = 0; } else if (currentMessagesGroup != null) { long totalPrice = 0; int totalCount = 0; for (MessageObject msg : currentMessagesGroup.messages) { final long messagePrice = msg == null || msg.messageOwner == null ? 0 : msg.messageOwner.paid_message_stars; totalPrice += messagePrice; if (messagePrice > 0) { totalCount++; } } starsPrice = totalPrice; starsPriceMessagesCount = totalCount; } else { starsPriceMessagesCount = 1; starsPrice = currentMessageObject == null || currentMessageObject.messageOwner == null ? 0 : currentMessageObject.messageOwner.paid_message_stars; } if (this.starsPrice != starsPrice) { this.starsPrice = starsPrice; if (starsPrice > 0 && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0)) { final CharSequence text; if (currentMessageObject.isOutOwner()) { if (starsPriceMessagesCount > 1) { text = formatPluralStringComma("PaidMessageActionOutMany", (int) starsPrice, formatPluralStringComma("PaidMessageActionMessages", starsPriceMessagesCount)); } else { text = formatPluralStringComma("PaidMessageActionOut", (int) starsPrice); } } else { TLObject fromObject = currentMessageObject.getForwardedFromPeerObject(); if (fromObject == null) { fromObject = currentMessageObject.getFromPeerObject(); } if (currentMessageObject.getDialogId() > 0) { text = replaceWithLink(formatPluralStringComma("PaidMessageActionIn", (int) starsPrice), "un1", fromObject); } else { if (starsPriceMessagesCount > 1) { text = replaceWithLink(formatPluralStringComma("PaidMessageAction", (int) starsPrice), "un1", fromObject); } else { text = replaceWithLink(formatPluralStringComma("PaidMessageActionMany", (int) starsPrice, formatPluralStringComma("PaidMessageActionMessages", starsPriceMessagesCount)), "un1", fromObject); } } } starsPriceText = new Text(text, 14, AndroidUtilities.bold()) .multiline(3) .setMaxWidth(currentMessageObject.getMaxMessageTextWidth()) .align(Layout.Alignment.ALIGN_CENTER) .lineSpacing(dp(2)); if (starsPriceTextPath == null) { starsPriceTextPath = new LinkPath(); starsPriceTextPath.setUseCornerPathImplementation(true); starsPriceTextPathEffect = new CornerPathEffect(dp(16)); } else { starsPriceTextPath.rewind(); } starsPriceTextPath.setPadding(dp(9), dp(2.66f)); starsPriceTopPadding = (int) (starsPriceText.getHeight() + dp(6.66f + 9)); starsPriceTextPath.setCurrentLayout(starsPriceText.getLayout(), 0, 0); starsPriceText.getLayout().getSelectionPath(0, text.length(), starsPriceTextPath); starsPriceTextPath.closeRects(); } else { starsPriceText = null; starsPriceTopPadding = 0; } } if (this.diceStakeOutcome != diceStakeOutcome) { this.diceStakeOutcome = diceStakeOutcome; if (diceStakeOutcome != 0) { final CharSequence text; if (currentMessageObject.isOutOwner() && !currentMessageObject.isForwarded()) { if (diceStakeOutcome > 0) { text = StarsIntroActivity.replaceDiamond(formatString(R.string.StakeDiceActionYouWon, StarsIntroActivity.formatTON(diceStakeOutcome)), 0.825f); } else { text = StarsIntroActivity.replaceDiamond(formatString(R.string.StakeDiceActionYouLost, StarsIntroActivity.formatTON(-diceStakeOutcome)), 0.825f); } } else { final TLObject fromObject = currentMessageObject.getFromPeerObject(); if (diceStakeOutcome > 0) { text = StarsIntroActivity.replaceDiamond(replaceWithLink(formatString(R.string.StakeDiceActionWon, StarsIntroActivity.formatTON(diceStakeOutcome)), "un1", fromObject), 0.825f); } else { text = StarsIntroActivity.replaceDiamond(replaceWithLink(formatString(R.string.StakeDiceActionLost, StarsIntroActivity.formatTON(-diceStakeOutcome)), "un1", fromObject), 0.825f); } } bottomActionText = new Text(text, 14, AndroidUtilities.bold()) .multiline(3) .setMaxWidth(currentMessageObject.getMaxMessageTextWidth()) .align(Layout.Alignment.ALIGN_CENTER) .lineSpacing(dp(2)); if (bottomActionTextPath == null) { bottomActionTextPath = new LinkPath(); bottomActionTextPath.setUseCornerPathImplementation(true); bottomActionTextPathEffect = new CornerPathEffect(dp(16)); } else { bottomActionTextPath.rewind(); } bottomActionTextPath.setPadding(dp(9), dp(2.66f)); bottomActionPadding = (int) (bottomActionText.getHeight() + dp(6.66f)); bottomActionTextPath.setCurrentLayout(bottomActionText.getLayout(), 0, 0); bottomActionText.getLayout().getSelectionPath(0, text.length(), bottomActionTextPath); bottomActionTextPath.closeRects(); } else { bottomActionText = null; bottomActionPadding = 0; } } suggestionOffer = null; suggestionOfferTopPadding = 0; if (currentMessageObject != null && currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.suggested_post != null && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0)) { suggestionOffer = new SuggestionOffer(currentAccount, this, resourcesProvider); suggestionOffer.update(currentMessageObject); suggestionOfferTopPadding = suggestionOffer.getHeight() + dp(8); } //if (lastInChatList && lastSendState == 0 && isAllChats && isBotForum && !isPinnedChat && (currentPosition == null /*|| (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0*/)) { // if (askBotForumSeparator == null) { // askBotForumSeparator = new TopicSeparator(currentAccount, this, resourcesProvider, true); // } // askBotForumSeparator.setText(""); // // if (askBotForumBubble == null) { // askBotForumBubble = new BotAskCellDrawable(getContext(), currentAccount, resourcesProvider); // } // // askBotForumBubble.set(messageObject.getDialogId()); // askBotForumBottomPadding = dp(40) + askBotForumBubble.getBubbleHeight(); // //} else { // askBotForumBottomPadding = 0; //} if (firstInChat && isAllChats && isSideMenued && (isForum || isMonoForum) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0)) { topicSeparatorTopPadding = dp(33); if (topicSeparator == null) { topicSeparator = new TopicSeparator(currentAccount, this, resourcesProvider, true); topicSeparator.setOnClickListener(() -> { if (delegate != null) { delegate.didPressSideButton(this); } }); } if (!topicSeparator.update(currentMessageObject)) { topicSeparator.detach(); topicSeparator = null; topicSeparatorTopPadding = 0; } else if (attachedToWindow) { topicSeparator.attach(); } } else { if (topicSeparator != null) { topicSeparator.detach(); topicSeparator = null; } topicSeparatorTopPadding = 0; } if ((getPaddingTop() != starsPriceTopPadding + topicSeparatorTopPadding + suggestionOfferTopPadding) || (getPaddingBottom() != askBotForumBottomPadding)) { setPadding(0, starsPriceTopPadding + topicSeparatorTopPadding + suggestionOfferTopPadding, 0, askBotForumBottomPadding); } oldPollButtons.clear(); if (mediaSpoilerEffect != null && !(needReplyImage && currentMessageObject != null && currentMessageObject.hasValidReplyMessageObject() && currentMessageObject.replyMessageObject.hasMediaSpoilers())) { mediaSpoilerEffect = null; } if (unlockSpoilerEffect != null && unlockLayout == null) { unlockSpoilerEffect = null; } scheduleUpdateRelativeDates(); } if (messageIdChanged) { currentUrl = null; currentWebFile = null; lastWebFile = null; loadingProgressLayout = null; animatingLoadingProgressProgress = 0; lastLoadingSizeTotal = 0; selectedBackgroundProgress = 0f; if (statusDrawableAnimator != null) { statusDrawableAnimator.removeAllListeners(); statusDrawableAnimator.cancel(); } if (translationLoadingFloat != null) { translationLoadingFloat.set(0, true); } if (translationLoadingPath != null) { translationLoadingPath.reset(); translationLoadingPath = null; } if (translationLoadingDrawable != null) { translationLoadingDrawable.reset(); translationLoadingDrawable = null; } if (timerParticlesAlpha != null) { timerParticlesAlpha.set(currentMessageObject != null && currentMessageObject.needDrawBluredPreview() && currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.destroyTime != 0 && MediaController.getInstance().isPlayingMessage(currentMessageObject), true); } transitionParams.lastStatusDrawableParams = -1; statusDrawableAnimationInProgress = false; if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { boolean showSeekbar = MediaController.getInstance().isPlayingMessage(currentMessageObject); toSeekBarProgress = showSeekbar ? 1f : 0f; } if (seekBar != null) { seekBar.updateTimestamps(currentMessageObject, null); } seekBarWaveform.setProgress(0); if (currentNameStatusDrawable != null) { currentNameStatusDrawable.play(); } if (replyLine != null) { replyLine.resetAnimation(); } quoteHighlight = null; } if (transcribeButton != null) { transcribeButton.setOpen(currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionOpen && currentMessageObject.messageOwner.voiceTranscriptionFinal && TranscribeButton.isVideoTranscriptionOpen(currentMessageObject), !messageIdChanged); transcribeButton.setLoading(TranscribeButton.isTranscribing(currentMessageObject), !messageIdChanged); transcribeButton.setLock(TranscribeButton.showTranscribeLock(currentMessageObject), !messageIdChanged); } updateWaveform(); updateButtonState(false, !messageIdChanged && !messageObject.cancelEditing, true); if (!currentMessageObject.loadingCancelled && buttonState == 2 && documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO && DownloadController.getInstance(currentAccount).canDownloadMedia(messageObject)) { FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); buttonState = 4; radialProgress.setIcon(getIconForCurrentState(), false, false); } if (delegate != null && delegate.getTextSelectionHelper() != null && !messageIdChanged && messageChanged && messageObject != null && !messageObject.preview) { delegate.getTextSelectionHelper().checkDataChanged(messageObject); } accessibilityVirtualViewBounds.clear(); transitionParams.updatePhotoImageX = true; highlightCaptionToSetStart = highlightCaptionToSetEnd = -1; updateFlagSecure(); } public void checkPollFileState() { if (currentMessageObject != null && currentMessageObject.isPoll()) { if (pollExplanationDrawable != null) { pollExplanationDrawable.checkFileState(); } if (pollContentDrawable != null) { pollContentDrawable.checkFileState(); } } } private void setMessageContentIfPoll(final MessageObject messageObject, boolean messageIdChanged) { if (timerParticles == null) { timerParticles = new TimerParticles(); } pollResultsPreview = false; createSelectorDrawable(0); drawName = true; drawForwardedName = !isRepliesChat; drawPhotoImage = false; int maxWidth = Math.min(dp(500), messageObject.getMaxMessageTextWidth()); backgroundWidth = maxWidth + dp(31); TLRPC.MessageMedia m = MessageObject.getMedia(messageObject.messageOwner); TLRPC.TL_textWithEntities title; String subtitle; boolean todo, quiz, public_voters, multiple_choice; int total_voters; if (m instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll media = (TLRPC.TL_messageMediaPoll) m; todo = false; quiz = media.poll.quiz; public_voters = media.poll.public_voters; multiple_choice = media.poll.multiple_choice; total_voters = media.results.total_voters; timerTransitionProgress = media.poll.close_date - ConnectionsManager.getInstance(currentAccount).getCurrentTime() < 60 ? 0.0f : 1.0f; pollClosed = media.poll.closed; pollResultsPreview = messageObject.forceShowPollResults; pollHideResults = media.poll.hide_results_until_close; title = media.poll.question; if (pollClosed) { subtitle = getString(R.string.FinalResults); } else if (media.poll.quiz) { subtitle = getString(media.poll.public_voters ? R.string.QuizPoll : R.string.AnonymousQuizPoll); } else if (media.poll.public_voters) { subtitle = getString(R.string.PublicPoll); } else { subtitle = getString(R.string.AnonymousPoll); } lastPoll = media.poll; lastPollResults = media.results.results; lastPollResultsObj = media.results; lastPollResultsVoters = media.results.total_voters; currentExplanation = messageObject.quizExplanation; if (currentExplanation == null && !TextUtils.isEmpty(media.results.solution)) { messageObject.generateExplanation(); currentExplanation = messageObject.quizExplanation; } if (currentExplanation != null) { if (closeExplanationDrawable == null) { closeExplanationDrawable = getContext().getResources().getDrawable(R.drawable.msg_close).mutate(); } int explanationWidth = backgroundWidth - dp(38); explanationContentWidth = explanationWidth - dp(10 + 8); explanationContentHeight = 0; if (media.results != null && media.results.solution_media != null) { if (pollExplanationDrawable == null) { pollExplanationDrawable = new PollContentDrawable(currentAccount, this, resourcesProvider, true); } String attachPath = PollAttachedMediaPack.getAttachPath(messageObject.messageOwner, PollAttachedMediaPack.INDEX_EXPLANATION); pollExplanationDrawable.setMedia(messageObject, media.results.solution_media, messageObject, explanationWidth, attachPath, !messageIdChanged); if (pollExplanationDrawable.isHasMedia()) { explanationContentHeight = pollExplanationDrawable.getHeightForWidth(explanationWidth); } if (isCellAttachedToWindow()) { pollExplanationDrawable.attach(); } } explanationTitleLayout = new StaticLayout( TextUtils.ellipsize(getString(R.string.QuizExplanationTitle), Theme.chat_replyNamePaint, maxWidth - dp(30), TextUtils.TruncateAt.END), Theme.chat_replyNamePaint, maxWidth - dp(30), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); explanationLayout = new MessageObject.TextLayoutBlocks(messageObject, currentExplanation, Theme.chat_quoteTextPaint, explanationWidth - dp(11)); explanationHeight = explanationLayout.textHeight() + dp(26 + 8 + 3) + (explanationContentHeight > 0 ? explanationContentHeight + dp(8 + 6) : 0); animatedEmojiPollExplanation = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiPollExplanation, explanationLayout.textLayoutBlocks); } } else { TLRPC.TL_messageMediaToDo media = (TLRPC.TL_messageMediaToDo) m; todo = true; quiz = false; public_voters = true; multiple_choice = true; timerTransitionProgress = 1.0f; pollClosed = false; pollHideResults = false; title = media.todo.title; total_voters = 0; subtitle = getString(media.todo.others_can_complete && messageObject.getDialogId() != UserConfig.getInstance(currentAccount).getClientUserId() ? R.string.MessageGroupTodoList : R.string.MessageTodoList); } if (messageObject.translated && messageObject.messageOwner != null && messageObject.messageOwner.translatedPoll != null && messageObject.messageOwner.translatedPoll.question != null) { title = messageObject.messageOwner.translatedPoll.question; } pollAllowAdding = false; pollInInputNewOption = false; pollWithMediaInAnswers = false; pollVoted = messageObject.isVoted(); pollHasResults = messageObject.hasVoteResults(); pollHasVoteRestrictions = BitwiseUtils.hasFlag(PollUtils.getVoteRestrictedFlags(messageObject), PollUtils.VOTE_RESTRICTED_BY_COUNTRY_FLAG | PollUtils.VOTE_RESTRICTED_NOT_SUBSCRIBED_FLAG | PollUtils.VOTE_RESTRICTED_NOT_SUBSCRIBED_24H_FLAG); if (pollVoted) { messageObject.checkedVotes.clear(); } CharSequence questionText = new SpannableStringBuilder(title.text); questionText = Emoji.replaceEmoji(questionText, Theme.chat_audioTitlePaint.getFontMetricsInt(), false); if (title.entities != null) { questionText = MessageObject.replaceAnimatedEmoji(questionText, title.entities, Theme.chat_audioTitlePaint.getFontMetricsInt(), true); MessageObject.addEntitiesToText(questionText, title.entities, currentMessageObject.isOutOwner(), false, false, false); } titleLayout = new StaticLayout(questionText, Theme.chat_audioTitlePaint, maxWidth + dp(2) - getExtraTextX() * 2, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); animatedEmojiPollQuestion = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiPollQuestion, titleLayout); boolean titleRtl = false; if (titleLayout != null) { for (int a = 0, N = titleLayout.getLineCount(); a < N; a++) { if (titleLayout.getLineLeft(a) > 0) { titleRtl = true; break; } } } docTitleLayout = new StaticLayout(TextUtils.ellipsize(subtitle, Theme.chat_timePaint, maxWidth, TextUtils.TruncateAt.END), Theme.chat_timePaint, maxWidth + dp(2) - getExtraTextX() * 2, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (docTitleLayout != null && docTitleLayout.getLineCount() > 0) { if (titleRtl && !LocaleController.isRTL) { docTitleOffsetX = (int) Math.ceil(maxWidth - docTitleLayout.getLineWidth(0)); } else if (!titleRtl && LocaleController.isRTL) { docTitleOffsetX = -(int) Math.ceil(docTitleLayout.getLineLeft(0)); } else { docTitleOffsetX = 0; } } int w = maxWidth - dp(messageObject.isOutOwner() ? 28 : 8); if (!isBot) { TextPaint textPaint = !public_voters && !multiple_choice ? Theme.chat_livePaint : Theme.chat_locationAddressPaint; CharSequence votes; if (todo) { TLRPC.TL_messageMediaToDo media = (TLRPC.TL_messageMediaToDo) m; if (!currentMessageObject.isOutOwner() && currentMessageObject.getDialogId() >= 0 && !media.todo.others_can_complete) { final String by = DialogObject.getName(currentMessageObject.getFromChatId()); votes = formatPluralStringComma("TodoCompletedBy", media.todo.list.size(), MessageObject.getCompletionsCount(media), by); } else { votes = formatPluralStringComma("TodoCompleted", media.todo.list.size(), MessageObject.getCompletionsCount(media)); } } else if (quiz) { votes = TextUtils.ellipsize(total_voters == 0 ? getString(R.string.NoVotesQuiz) : formatPluralString("Answer", total_voters), textPaint, w, TextUtils.TruncateAt.END); } else { votes = TextUtils.ellipsize(total_voters == 0 ? getString(R.string.NoVotes) : formatPluralString("Vote", total_voters), textPaint, w, TextUtils.TruncateAt.END); } boolean hasPollCloseTimer = false; if (!pollClosed && m instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll media = (TLRPC.TL_messageMediaPoll) m; if (media.poll.close_date > 0) { final int timeDiff = media.poll.close_date - ConnectionsManager.getInstance(currentAccount).getCurrentTime(); if (timeDiff > 0) { final boolean resultsHidden = media.poll.hide_results_until_close && !media.poll.creator; hasPollCloseTimer = true; if (pollCountDownTimer == null) { pollCountDownTimer = new CountdownTimer((sec) -> { if (animatedInfoLayout2 != null) { animatedInfoLayout2.setText(LocaleController.formatPollEndTime((int) sec, resultsHidden), true); } }); } pollCountDownTimer.start(timeDiff); if (animatedInfoLayout2 == null) { animatedInfoLayout2 = new AnimatedTextView.AnimatedTextDrawable(false, true, true); animatedInfoLayout2.setCallback(this); animatedInfoLayout2.setGravity(Gravity.CENTER); animatedInfoLayout2.setOverrideFullWidth(AndroidUtilities.displaySize.x); } animatedInfoLayout2.setTextSize(dp(11)); animatedInfoLayout2.setTextColor((!public_voters && !multiple_choice ? Theme.chat_livePaint : Theme.chat_locationAddressPaint).getColor()); animatedInfoLayout2.setText(LocaleController.formatPollEndTime(timeDiff, resultsHidden), !messageIdChanged); } } } if (!hasPollCloseTimer) { if (pollCountDownTimer != null) { pollCountDownTimer.stop(); } animatedInfoLayout2 = null; } if (animatedInfoLayout == null) { animatedInfoLayout = new AnimatedTextView.AnimatedTextDrawable(false, true, true); animatedInfoLayout.setCallback(this); animatedInfoLayout.setGravity(Gravity.CENTER); animatedInfoLayout.setOverrideFullWidth(AndroidUtilities.displaySize.x); } animatedInfoLayout.setTextSize(dp(13)); animatedInfoLayout.setTextColor((!public_voters && !multiple_choice ? Theme.chat_livePaint : Theme.chat_locationAddressPaint).getColor()); animatedInfoLayout.setText(votes, !messageIdChanged); infoLayout = null; } measureTime(messageObject); createPollUI(todo ? 30 : MessagesController.getInstance(currentAccount).config.pollAnswersMax.get()); if (m instanceof TLRPC.TL_messageMediaPoll && ((TLRPC.TL_messageMediaPoll) m).results != null) { final TLRPC.TL_messageMediaPoll media = (TLRPC.TL_messageMediaPoll) m; if (pollRecentVotersDrawable != null) { pollRecentVotersDrawable.set(media.results.recent_voters, !messageIdChanged); } } else if (pollRecentVotersDrawable != null) { pollRecentVotersDrawable.set(null, false); } int maxVote = 0; if (!animatePollAnswer && pollVoteInProgress && vibrateOnPollVote) { try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignored) {} } animatePollAnswer = attachedToWindow && (pollVoteInProgress || pollUnvoteInProgress); animatePollAnswerAlpha = animatePollAnswer && m instanceof TLRPC.TL_messageMediaPoll; ArrayList previousPollButtons = oldPollButtons, previousPollButtons2 = null; ArrayList sortedPollButtons = new ArrayList<>(); if (!pollButtons.isEmpty()) { previousPollButtons = previousPollButtons2 = new ArrayList<>(pollButtons); for (PollButton btn : pollButtons) { btn.destroy(); } pollButtons.clear(); if (!animatePollAnswer) { animatePollAnswer = attachedToWindow && (pollVoted || pollClosed || pollResultsPreview); } if (pollAnimationProgress > 0 && pollAnimationProgress < 1.0f) { for (int b = 0, N2 = previousPollButtons.size(); b < N2; b++) { PollButton button = previousPollButtons.get(b); button.percent = (int) Math.ceil(button.prevPercent + (button.percent - button.prevPercent) * pollAnimationProgress); button.percentProgress = button.prevPercentProgress + (button.percentProgress - button.prevPercentProgress) * pollAnimationProgress; } } } pollAnimationProgress = animatePollAnswer ? 0.0f : 1.0f; byte[] votingFor; if (!animatePollAnswerAlpha) { pollVoteInProgress = false; pollVoteInProgressNum = -1; votingFor = SendMessagesHelper.getInstance(currentAccount).isSendingVote(currentMessageObject); } else { votingFor = null; } int height = (messageObject.expandedExplanation ? explanationHeight : 0) + (titleLayout != null ? titleLayout.getHeight() : 0); int restPercent = 100; boolean hasDifferent = false; int previousPercent = 0; int emojisCount = 0; if (m instanceof TLRPC.TL_messageMediaPoll) { captionAbove = true; TLRPC.TL_messageMediaPoll media = (TLRPC.TL_messageMediaPoll) m; if (media.attached_media != null) { if (pollContentDrawable == null) { pollContentDrawable = new PollContentDrawable(currentAccount, this, resourcesProvider, false); pollContentDrawable.imageReceiver.setRoundRadius(pollPhotoImageRadius); } final int mediaWidth = backgroundWidth - dp(13) - dp(2) - dp(2); String attachPath = PollAttachedMediaPack.getAttachPath(messageObject.messageOwner, PollAttachedMediaPack.INDEX_DESCRIPTION); pollContentDrawable.setMedia(messageObject, media.attached_media, messageObject, mediaWidth, attachPath, !messageIdChanged); if (pollContentDrawable.isHasMedia()) { pollContentWidth = mediaWidth; pollContentHeight = pollContentDrawable.getHeightForWidth(pollContentWidth); pollContentHeightWithOffset = pollContentHeight + dp(4) + dp(4); height += pollContentHeightWithOffset; } if (isCellAttachedToWindow()) { pollContentDrawable.attach(); } } TlUtils.calculateAnswerShuffleHash(media.poll, UserConfig.getInstance(currentAccount).getClientUserId()); final ArrayList answers = media.poll.shuffled_answers != null ? media.poll.shuffled_answers : media.poll.answers; for (int a = 0, N = media.poll.answers.size(); a < N; a++) { final TLRPC.PollAnswer pollAnswer = media.poll.answers.get(a); if (pollAnswer.media != null) { pollWithMediaInAnswers = true; break; } } for (int a = 0, N = answers.size(); a < N; a++) { TLRPC.PollAnswer pollAnswer = answers.get(a); boolean translated = false; if (currentMessageObject.translated && currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.translatedPoll != null) { for (TLRPC.PollAnswer translatedPollAnswer : currentMessageObject.messageOwner.translatedPoll.answers) { if (Arrays.equals(translatedPollAnswer.option, pollAnswer.option)) { translated = true; pollAnswer = translatedPollAnswer; break; } } } CharSequence answerText = new SpannableStringBuilder(pollAnswer.text.text); answerText = Emoji.replaceEmoji(answerText, Theme.chat_audioTitlePaint.getFontMetricsInt(), false, null, DynamicDrawableSpan.ALIGN_BOTTOM, 1.0f, emojisCount); if (pollAnswer.text.entities != null) { answerText = MessageObject.replaceAnimatedEmoji(answerText, pollAnswer.text.entities, Theme.chat_audioPerformerPaint.getFontMetricsInt(), true, 1.2f, emojisCount); MessageObject.addEntitiesToText(answerText, pollAnswer.text.entities, currentMessageObject.isOutOwner(), false, false, false); } emojisCount += (answerText instanceof Spannable ? ((Spannable) answerText).getSpans(0, answerText.length(), Emoji.EmojiSpan.class).length + ((Spannable) answerText).getSpans(0, answerText.length(), AnimatedEmojiSpan.class).length : 0); PollButton prevButton = null; if (previousPollButtons != null) { for (int i = 0; i < previousPollButtons.size(); ++i) { PollButton b = previousPollButtons.get(i); if (b.answer == pollAnswer || b.answer != null && Arrays.equals(previousPollButtons.get(i).answer.option, pollAnswer.option)) { prevButton = previousPollButtons.get(i); break; } } } PollButton button = new PollButton(); if (prevButton != null) { button.selectorDrawableColor = prevButton.selectorDrawableColor; button.selectorDrawable = prevButton.selectorDrawable; } else { button.selectorDrawable = Theme.createRadSelectorDrawable(button.selectorDrawableColor = getThemedColor(Theme.key_listSelector), 0, 0); } if (prevButton != null) { button.pollButtonDrawable = prevButton.pollButtonDrawable; prevButton.pollButtonDrawable = null; } if (button.pollButtonDrawable == null) { button.pollButtonDrawable = new PollButtonDrawable(currentAccount, this); } String attachPath = PollAttachedMediaPack.getAttachPath(messageObject.messageOwner, pollAnswer.unshuffled_index); button.pollButtonDrawable.setHasMediaPadding(pollWithMediaInAnswers); button.pollButtonDrawable.setMedia(messageObject, pollAnswer.media, messageObject, attachPath, !messageIdChanged); if (isCellAttachedToWindow()) { button.attach(); } button.selectorDrawable.setCallback(this); button.answer = pollAnswer; final int titleMaxWidth = maxWidth - dp(48 + (pollWithMediaInAnswers ? 48 : 0)); button.title = new StaticLayout(answerText, Theme.chat_audioPerformerPaint, titleMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); button.moveTitleByCounter = false; button.animatedEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, button.animatedEmoji, button.title); button.y = height + dp(52); button.height = button.title.getHeight(); button.translated = translated; if (prevButton != null && prevButton.translated != translated) { button.animateTitle = prevButton.title; button.animateTitleEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, button.animateTitleEmoji, button.animateTitle); button.animateY = prevButton.y; button.animateHeight = prevButton.height; } pollButtons.add(button); sortedPollButtons.add(button); height += button.height + dp(26.66f); final int titleLinesCount = button.title.getLineCount(); final float titleLastLineWidth = titleLinesCount > 0 ? button.title.getLineWidth(titleLinesCount - 1) : 0; final boolean isTitleRtl = titleLinesCount > 0 && button.title.getParagraphDirection(0) == Layout.DIR_RIGHT_TO_LEFT; final float titleLastLineAvail = titleMaxWidth - dp(10) - titleLastLineWidth; boolean votersWasSet = false; if (!media.results.results.isEmpty()) { for (int b = 0, N2 = media.results.results.size(); b < N2; b++) { TLRPC.PollAnswerVoters answer = media.results.results.get(b); if (Arrays.equals(button.answer.option, answer.option)) { if (button.pollButtonDrawable != null) { final boolean isCouterVisible = !isBot && (pollVoted || pollResultsPreview || pollClosed || (pollHasVoteRestrictions && (!pollHideResults || pollHasResults))); button.pollButtonDrawable.setVotersVisible(isCouterVisible, prevButton != null && !messageIdChanged); button.pollButtonDrawable.setVotersCount(answer.voters, prevButton != null && !messageIdChanged); button.pollButtonDrawable.setRecentVoters(answer.recent_voters, prevButton != null && !messageIdChanged); final float votersCountWidth = button.pollButtonDrawable.getVotersCountTargetWidth(); button.moveTitleByCounter = isTitleRtl && titleLinesCount == 1 && (titleLastLineAvail - dp(10)) > votersCountWidth; if (isCouterVisible && (votersCountWidth > titleLastLineAvail || isTitleRtl && !button.moveTitleByCounter)) { button.height += dp(22); height += dp(22); } votersWasSet = true; } button.chosen = answer.chosen; button.count = answer.voters; button.correct = answer.correct; if ((pollVoted || pollClosed || pollResultsPreview || (pollHasVoteRestrictions && (!pollHideResults || pollHasResults))) && media.results.total_voters > 0) { float percent = MathUtils.clamp(answer.voters / (float) media.results.total_voters, 0, 1); button.decimal = 100 * percent; button.percent = (int) button.decimal; button.decimal -= button.percent; } else { button.percent = 0; button.decimal = 0; } if (previousPercent == 0) { previousPercent = button.percent; } else if (button.percent != 0 && previousPercent != button.percent) { hasDifferent = true; } restPercent -= button.percent; maxVote = Math.max(button.percent, maxVote); break; } } } if (!votersWasSet) { button.pollButtonDrawable.setVotersVisible(false, prevButton != null && !messageIdChanged); } if (previousPollButtons2 != null) { for (int b = 0, N2 = previousPollButtons2.size(); b < N2; b++) { PollButton prevButton2 = previousPollButtons2.get(b); if (Arrays.equals(button.answer.option, prevButton2.answer.option)) { button.prevPercent = prevButton2.percent; button.prevPercentProgress = prevButton2.percentProgress; button.prevChosen = prevButton2.chosen; break; } } } if (votingFor != null && button.answer.option.length > 0 && Arrays.binarySearch(votingFor, button.answer.option[0]) >= 0) { pollVoteInProgressNum = a; pollVoteInProgress = true; vibrateOnPollVote = true; votingFor = null; } final boolean isVotedButHiddenResults = pollVoted && !pollHasResults && pollHideResults; if (isVotedButHiddenResults) { pollCheckBox[a].setChecked(button.chosen, false); } else if (currentMessageObject.checkedVotes.contains(button.answer)) { pollCheckBox[a].setChecked(true, false); } else { pollCheckBox[a].setChecked(false, false); } pollCheckBox[a].checkScale = 0.85f; } final boolean canAddPollAnswers = delegate != null && delegate.allowAddPollOptions() && media.poll.open_answers && !pollClosed && !messageObject.scheduled && !messageObject.isForwarded() && (media.poll.answers.size() < MessagesController.getInstance(currentAccount).config.pollAnswersMax.get()); if (canAddPollAnswers) { if (pollAddButtonDrawable == null) { pollAddButtonDrawable = new PollAddButtonDrawable(getContext(), resourcesProvider); pollAddButtonDrawable.setupCallbacks(this); } pollAllowAdding = true; final int pollAddHeight = delegate != null ? delegate.getAddPollOptionInputFieldHeight(this) : 0; pollInInputNewOption = pollAddHeight > 0; pollAddButtonDrawable.setIsEditEnabled(pollInInputNewOption, !messageIdChanged); pollAddButtonHeight = Math.max(dp(44.33f), pollAddHeight); height += pollAddButtonHeight; } for (PollButton btn : previousPollButtons) { btn.detach(); btn.pollButtonDrawable = null; } checkInstantButtonForPoll(!messageIdChanged); } else if (m instanceof TLRPC.TL_messageMediaToDo) { TLRPC.TL_messageMediaToDo media = (TLRPC.TL_messageMediaToDo) m; for (int a = 0, N = media.todo.list.size(); a < N; a++) { TLRPC.TodoItem task = media.todo.list.get(a); boolean translated = false; // if (currentMessageObject.translated && currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.translatedPoll != null) { // for (TLRPC.PollAnswer translatedPollAnswer : currentMessageObject.messageOwner.translatedPoll.answers) { // if (Arrays.equals(translatedPollAnswer.option, pollAnswer.option)) { // translated = true; // pollAnswer = translatedPollAnswer; // break; // } // } // } CharSequence answerText = new SpannableStringBuilder(task.title.text); answerText = Emoji.replaceEmoji(answerText, Theme.chat_audioTitlePaint.getFontMetricsInt(), false, null, DynamicDrawableSpan.ALIGN_BOTTOM, 1.0f, emojisCount); if (task.title.entities != null) { answerText = MessageObject.replaceAnimatedEmoji(answerText, task.title.entities, Theme.chat_audioPerformerPaint.getFontMetricsInt(), true, 1.2f, emojisCount); MessageObject.addEntitiesToText(answerText, task.title.entities, currentMessageObject.isOutOwner(), false, false, false); } emojisCount += (answerText instanceof Spannable ? ((Spannable) answerText).getSpans(0, answerText.length(), Emoji.EmojiSpan.class).length + ((Spannable) answerText).getSpans(0, answerText.length(), AnimatedEmojiSpan.class).length : 0); PollButton prevButton = null; if (previousPollButtons != null) { for (int i = 0; i < previousPollButtons.size(); ++i) { PollButton b = previousPollButtons.get(i); if (b.task == task || b.task != null && b.task.id == task.id) { prevButton = b; break; } } } Boolean sending = SendMessagesHelper.getInstance(currentAccount).getSendingTodoValue(messageObject, task); PollButton button = new PollButton(); button.author = prevButton != null ? prevButton.author : null; if (prevButton != null) { button.selectorDrawableColor = prevButton.selectorDrawableColor; button.selectorDrawable = prevButton.selectorDrawable; } else { button.selectorDrawable = Theme.createRadSelectorDrawable(button.selectorDrawableColor = getThemedColor(Theme.key_listSelector), 0, 0); } button.selectorDrawable.setCallback(this); if (prevButton != null) { button.avatarDrawable = prevButton.avatarDrawable; button.avatarImageReceiver = prevButton.avatarImageReceiver; prevButton.avatarDrawable = null; prevButton.avatarImageReceiver = null; } if (button.avatarDrawable == null) { button.avatarDrawable = new AvatarDrawable(); } if (button.avatarImageReceiver == null) { button.avatarImageReceiver = new ImageReceiver(this); button.avatarImageReceiver.setRoundRadius(dp(20)); } if (isCellAttachedToWindow()) { button.attach(); } button.chosen = false; if (!media.completions.isEmpty()) { for (TLRPC.TodoCompletion completion : media.completions) { if (completion.id == task.id) { button.chosen = true; TLObject obj = MessagesController.getInstance(currentAccount).getUserOrChat(DialogObject.getPeerDialogId(completion.completed_by)); button.avatarDrawable.setInfo(obj); button.avatarImageReceiver.setForUserOrChat(obj, button.avatarDrawable); button.author = new Text(DialogObject.getName(obj), 12); break; } } } if (sending != null) { button.chosen = sending; } if (button.chosen && !messageObject.canCompleteTodo()) { if (!(answerText instanceof SpannableStringBuilder)) { answerText = new SpannableStringBuilder(answerText); } ((SpannableStringBuilder) answerText).setSpan(new StrikethroughSpan(), 0, answerText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } button.task = task; button.title = new StaticLayout(answerText, Theme.chat_audioPerformerPaint, maxWidth - dp(48 - 2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); button.animatedEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, button.animatedEmoji, button.title); button.y = height + dp(52); button.height = button.title.getHeight(); button.translated = translated; if (prevButton != null && prevButton.translated != translated) { button.animateTitle = prevButton.title; button.animateTitleEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, button.animateTitleEmoji, button.animateTitle); button.animateY = prevButton.y; button.animateHeight = prevButton.height; } pollButtons.add(button); sortedPollButtons.add(button); height += button.height + dp(26.66f); pollCheckBox[a].setChecked(button.chosen, !messageIdChanged); pollCheckBox[a].checkScale = 1f; } for (PollButton btn : previousPollButtons) { if (btn.avatarImageReceiver != null) { btn.avatarImageReceiver.onDetachedFromWindow(); btn.avatarImageReceiver = null; } } } normalizePollPercents(hasDifferent, restPercent, sortedPollButtons); int width = backgroundWidth - dp(76); for (int b = 0, N2 = pollButtons.size(); b < N2; b++) { PollButton button = pollButtons.get(b); int div = 100; // maxVote; button.percentProgress = Math.max(dp(5) / (float) width, div != 0 ? button.percent / (float) div : 0); } setMessageObjectInternal(messageObject); pollInstantViewTouchesBottom = false; if (isBot && !drawInstantView) { height -= dp(10); } else if (public_voters || multiple_choice || true) { pollInstantViewTouchesBottom = true; height += dp(13); } totalHeight = dp(46 + 27) + namesOffset + height; if (drawPinnedTop) { namesOffset -= dp(1); } instantTextNewLine = false; if (public_voters || multiple_choice) { int instantTextWidth = 0; for (int a = 0; a < 3; a++) { String str; if (a == 0) { str = getString(R.string.PollViewResultsNoCaps); } else if (a == 1) { str = getString(R.string.PollSubmitVotesNoCaps); } else { str = getString(R.string.NoVotes); } instantTextWidth = Math.max(instantTextWidth, (int) Math.ceil(Theme.chat_instantViewPaint.measureText(str))); } int timeWidthTotal = timeWidth + (messageObject.isOutOwner() ? dp(20) : 0) + getExtraTimeX(); if (!reactionsLayoutInBubble.isSmall && reactionsLayoutInBubble.isEmpty && timeWidthTotal >= (backgroundWidth - dp(76) - instantTextWidth) / 2) { totalHeight += dp(18); instantTextNewLine = true; } } if (!reactionsLayoutInBubble.isSmall) { if (!reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.measure(maxWidth, Gravity.LEFT); totalHeight += reactionsLayoutInBubble.height + dp(12); int timeWidthTotal = timeWidth + (messageObject.isOutOwner() ? dp(20) : 0) + getExtraTimeX(); if (timeWidthTotal >= (backgroundWidth - dp(24) - reactionsLayoutInBubble.lastLineX)) { totalHeight += dp(16); reactionsLayoutInBubble.positionOffsetY -= dp(16); } } } } private void checkInstantButtonForPoll(boolean animated) { if (currentMessageObject == null) { return; } final MessageObject messageObject = currentMessageObject; final TLRPC.MessageMedia m = getMedia(messageObject); final TLRPC.TL_messageMediaPoll media; if (m instanceof TLRPC.TL_messageMediaPoll) { media = (TLRPC.TL_messageMediaPoll) m; } else { return; } CharSequence instantViewText = null; int instantViewType = 0; boolean hasCheckedCheckboxes = false; if (pollCheckBox != null) { for (int a = 0, N = Math.min(media.poll.answers.size(), pollCheckBox.length); a < N; a++) { if (pollCheckBox[a] != null && pollCheckBox[a].isChecked()) { hasCheckedCheckboxes = true; } } } final TLRPC.PollResults results = media.results; final boolean canViewHiddenResultsWithoutVote = !pollVoted && !pollClosed && pollHasResults && results != null && results.total_voters != 0 && media.poll.creator; //pollHideResults; final boolean canVote = !pollVoted && !pollClosed && !pollHasVoteRestrictions; final boolean isAnonymousPoll = !media.poll.public_voters; if (pollInInputNewOption) { instantViewType = INSTANT_BUTTON_TYPE_ADD_OPTION; instantViewText = getString(R.string.PollButtonSave); } else { if (canViewHiddenResultsWithoutVote && !(media.poll.multiple_choice && canVote && hasCheckedCheckboxes)) { if (isAnonymousPoll) { if (messageObject.forceShowPollResults) { instantViewType = INSTANT_BUTTON_TYPE_BACK_TO_VOTE; instantViewText = AndroidUtilities.replaceArrows(getString(R.string.PollViewBack), false, -dp(8f / 3f), 0, 1.0f); } else { instantViewType = INSTANT_BUTTON_TYPE_VIEW_VOTES_AS_AUTHOR_LIST; instantViewText = AndroidUtilities.replaceArrows(formatPluralString("PollViewVotesAsAdmin", results.total_voters), false); } } else { instantViewType = INSTANT_BUTTON_TYPE_VIEW_VOTES_PUBLIC_LIST; instantViewText = formatString(R.string.PollViewVotesX, results.total_voters); } } else if (media.poll.multiple_choice && canVote) { instantViewType = INSTANT_BUTTON_TYPE_VOTE_MULTISELECT; instantViewText = getString(R.string.PollSubmitVotesNoCaps); } else if (!isBot && media.poll.public_voters && (pollVoted && (!pollHideResults || pollHasResults) || pollClosed && media.results.total_voters != 0)) { instantViewType = INSTANT_BUTTON_TYPE_VIEW_VOTES_PUBLIC_LIST; instantViewText = formatString(R.string.PollViewVotesX, results.total_voters); } } if (instantViewType != 0) { if (pollInstantButtonDrawable == null) { pollInstantButtonDrawable = new PollInstantButtonDrawable(this, resourcesProvider); pollInstantButtonDrawable.setupCallbacks(this); } instantViewButtonText = instantViewText; pollInstantButtonDrawable.setButtonText(instantViewText, animated); drawInstantView = true; drawInstantViewType = instantViewType; createInstantViewButton(); } checkPollVoteSendingStatus(animated); } public void checkPollVoteSendingStatus(boolean animated) { if (pollInstantButtonDrawable != null && currentMessageObject != null && currentMessageObject.isPoll()) { TLRPC.MessageMedia media = MessageObject.getMedia(currentMessageObject); boolean multipleChoice = false; if (media instanceof TLRPC.TL_messageMediaPoll) { multipleChoice =((TLRPC.TL_messageMediaPoll) media).poll.multiple_choice; } pollInstantButtonDrawable.setLoading(multipleChoice && SendMessagesHelper.getInstance(currentAccount).isSendingVote(currentMessageObject) != null, animated); } } private boolean loopStickers() { return LiteMode.isEnabled(LiteMode.FLAG_ANIMATED_STICKERS_CHAT); } private void calculateUnlockXY() { if (currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW && unlockLayout != null) { unlockX = backgroundDrawableLeft + (photoImage.getImageWidth() - unlockLayout.getWidth()) / 2f; unlockY = backgroundDrawableTop + photoImage.getImageY() + (photoImage.getImageHeight() - unlockLayout.getHeight()) / 2f; } } private void updateFlagSecure() { if (flagSecure == null) { Activity activity = AndroidUtilities.findActivity(getContext()); Window window = activity == null ? null : activity.getWindow(); if (window != null) { flagSecure = new FlagSecureReason(window, () -> currentMessageObject != null && currentMessageObject.messageOwner != null && ( currentMessageObject.type == MessageObject.TYPE_PAID_MEDIA && (groupMedia == null || !groupMedia.hidden) || currentMessageObject.messageOwner.noforwards && !currentMessageObject.isEphemeral() || currentMessageObject.isVoiceOnce() || currentMessageObject.hasRevealedExtendedMedia() ) ); if (attachedToWindow) { flagSecure.attach(); } } } if (flagSecure != null) { flagSecure.invalidate(); } } public void checkVideoPlayback(boolean allowStart, Bitmap thumb) { if (currentMessageObject.isVideo()) { if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { photoImage.setAllowStartAnimation(false); photoImage.stopAnimation(); } else { photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); } } else { if (allowStart) { MessageObject playingMessage = MediaController.getInstance().getPlayingMessageObject(); allowStart = playingMessage == null || !playingMessage.isRoundVideo(); } photoImage.setAllowStartAnimation(allowStart); if (thumb != null) { photoImage.startCrossfadeFromStaticThumb(thumb); } if (allowStart) { photoImage.startAnimation(); } else { photoImage.stopAnimation(); } } } private boolean hadLongPress = false; private static boolean spanSupportsLongPress(CharacterStyle span) { return span instanceof URLSpanMono || span instanceof URLSpan; } @Override protected boolean onLongPress() { if (isRoundVideo && isPlayingRound && MediaController.getInstance().isPlayingMessage(currentMessageObject)) { float touchRadius = (lastTouchX - photoImage.getCenterX()) * (lastTouchX - photoImage.getCenterX()) + (lastTouchY - photoImage.getCenterY()) * (lastTouchY - photoImage.getCenterY()); float r1 = (photoImage.getImageWidth() / 2f) * (photoImage.getImageWidth() / 2f); if (touchRadius < r1 && (lastTouchX > photoImage.getCenterX() + photoImage.getImageWidth() / 4f || lastTouchX < photoImage.getCenterX() - photoImage.getImageWidth() / 4f)) { boolean forward = lastTouchX > photoImage.getCenterX(); if (videoPlayerRewinder == null) { videoForwardDrawable = new VideoForwardDrawable(true); videoPlayerRewinder = new OldVideoPlayerRewinder() { @Override protected void onRewindCanceled() { onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0)); videoForwardDrawable.setShowing(false); } @Override protected void updateRewindProgressUi(long timeDiff, float progress, boolean rewindByBackSeek) { videoForwardDrawable.setTime(Math.abs(timeDiff)); if (rewindByBackSeek) { currentMessageObject.audioProgress = progress; updatePlayingMessageProgress(); } } @Override protected void onRewindStart(boolean rewindForward) { videoForwardDrawable.setDelegate(new VideoForwardDrawable.VideoForwardDrawableDelegate() { @Override public void onAnimationEnd() { } @Override public void invalidate() { ChatMessageCell.this.invalidate(); } }); videoForwardDrawable.setOneShootAnimation(false); videoForwardDrawable.setLeftSide(!rewindForward); videoForwardDrawable.setShowing(true); invalidate(); } }; getParent().requestDisallowInterceptTouchEvent(true); } videoPlayerRewinder.startRewind(MediaController.getInstance().getVideoPlayer(), forward, MediaController.getInstance().getPlaybackSpeed(false)); return false; } } if (replySelector != null) { replySelectorPressed = false; replySelector.setState(StateSet.NOTHING); invalidate(); } if (summaryBounce != null) { summaryBounce.setPressed(false); } if (summaryReplySelector != null) { summaryReplySelector.setState(StateSet.NOTHING); } if (nameStatusSelector != null) { nameStatusSelector.setState(StateSet.NOTHING); } if (nameLayoutSelector != null) { nameLayoutSelector.setState(StateSet.NOTHING); } if (boostCounterLayoutSelector != null) { boostCounterLayoutSelector.setState(StateSet.NOTHING); } resetCodeSelectors(); if (replyBounce != null) { replyBounce.setPressed(false); } if (adminLayoutBounce != null) { adminLayoutBounce.setPressed(false); } if (titleLabelBounce != null) { titleLabelBounce.setPressed(false); } if (factCheckWhatBounce != null) { factCheckWhatBounce.setPressed(false); } forwardNamePressed = false; if (forwardBg != null) { forwardBg.setPressed(false); } pressedEffect = false; if (effectDrawableBounce != null) { effectDrawableBounce.setPressed(pressedEffect); } if (pressedEmoji != null) { // hadLongPress = true; // if (delegate.didPressAnimatedEmoji(this, pressedEmoji)) { // pressedEmoji = null; // resetPressedLink(-1); // return true; // } pressedEmoji = null; } if (pressedVoteButton != -1) { final PollButton button = pollButtons.get(pressedVoteButton); if (delegate != null && button != null) { if (button.task != null) { if (delegate.didLongPressToDoButton(this, button.task)) { return true; } } if (button.answer != null) { if (delegate.didLongPressPollOption(this, button.answer)) { return true; } } } } if (pressedFactCheckLink != null) { if (pressedFactCheckLink.getSpan() instanceof URLSpanMono) { hadLongPress = true; delegate.didPressUrl(this, pressedFactCheckLink.getSpan(), true); return true; } else if (pressedFactCheckLink.getSpan() instanceof URLSpanNoUnderline) { URLSpanNoUnderline url = (URLSpanNoUnderline) pressedFactCheckLink.getSpan(); if (ChatActivity.isClickableLink(url.getURL()) || url.getURL().startsWith("/")) { hadLongPress = true; delegate.didPressUrl(this, pressedFactCheckLink.getSpan(), true); return true; } } else if (pressedFactCheckLink.getSpan() instanceof URLSpan) { hadLongPress = true; delegate.didPressUrl(this, pressedFactCheckLink.getSpan(), true); return true; } } if (pressedLink != null) { if (pressedLink.getSpan() instanceof URLSpanMono) { hadLongPress = true; delegate.didPressUrl(this, pressedLink.getSpan(), true); return true; } else if (pressedLink.getSpan() instanceof URLSpanNoUnderline) { URLSpanNoUnderline url = (URLSpanNoUnderline) pressedLink.getSpan(); if (ChatActivity.isClickableLink(url.getURL()) || url.getURL().startsWith("/") || url.getURL().startsWith("tel:")) { hadLongPress = true; delegate.didPressUrl(this, pressedLink.getSpan(), true); return true; } } else if (pressedLink.getSpan() instanceof URLSpan) { hadLongPress = true; delegate.didPressUrl(this, pressedLink.getSpan(), true); return true; } } resetPressedLink(-1); if (buttonPressed != 0 || miniButtonPressed != 0 || videoButtonPressed != 0 || pressedBotButton != -1) { buttonPressed = 0; miniButtonPressed = 0; videoButtonPressed = 0; pressedBotButton = -1; invalidate(); } if (replyPressed && !replyPanelIsForward) { hadLongPress = true; replyPressed = false; if (replySelector != null) { if (!replySelectorPressed) { replySelector.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}); post(() -> { replySelector.setState(new int[]{}); invalidate(); }); } else { replySelector.setState(new int[]{}); } replySelectorPressed = false; replySelectorCanBePressed = false; invalidate(); } if (replyBounce != null) { replyBounce.setPressed(false); } playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null && (currentMessageObject.hasValidReplyMessageObject() || currentMessageObject.isReplyToStory() || hasReplyQuote || currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.reply_to != null && currentMessageObject.messageOwner.reply_to.reply_from != null)) { delegate.didPressReplyMessage(this, currentMessageObject.getReplyMsgId(), replyBounceX, replyBounceY, true); } return true; } linkPreviewPressed = false; imagePressed = false; timePressed = false; gamePreviewPressed = false; giveawayMessageCell.setButtonPressed(false); giveawayResultsMessageCell.setButtonPressed(false); resetContactButtonsPressedState(); if (pressedVoteButton != -1 || pollHintPressed || psaHintPressed || instantPressed || otherPressed || commentButtonPressed) { instantPressed = commentButtonPressed = false; setInstantButtonPressed(false); pressedVoteButton = -1; pollHintPressed = false; pollAddButtonPressed = -1; closeExplanationPressed = false; psaHintPressed = false; otherPressed = false; for (int a = 0; a < selectorDrawable.length; a++) { if (selectorDrawable[a] != null) { selectorDrawable[a].setState(StateSet.NOTHING); } } if (linkPreviewSelector != null) { linkPreviewSelector.setState(StateSet.NOTHING); } if (linkPreviewBounce != null) { linkPreviewBounce.setPressed(false); } invalidate(); } if (delegate != null) { boolean handled = false; if (avatarPressed) { if (currentUser != null) { if (currentUser.id != 0) { handled = delegate.didLongPressUserAvatar(this, currentUser, lastTouchX, lastTouchY); } } else if (currentChat != null) { final int id; if (currentMessageObject.messageOwner.fwd_from != null) { if ((currentMessageObject.messageOwner.fwd_from.flags & 16) != 0) { id = currentMessageObject.messageOwner.fwd_from.saved_from_msg_id; } else { id = currentMessageObject.messageOwner.fwd_from.channel_post; } } else { id = 0; } handled = delegate.didLongPressChannelAvatar(this, currentChat, id, lastTouchX, lastTouchY); } } else if (sideButtonPressed) { if (pressedSideButton != SIDE_BUTTON_SPONSORED_CLOSE && pressedSideButton != SIDE_BUTTON_SPONSORED_MORE && pressedSideButton != 3 && pressedSideButton != 2 ) { delegate.didQuickShareStart(this, lastTouchX, lastTouchY); sideButtonPressed = false; pressedSideButton = 0; inQuickShareMode = true; handled = true; return false; } } if (!handled) { delegate.didLongPress(this, lastTouchX, lastTouchY); } } sideButtonPressed = false; pressedSideButton = 0; return true; } public void showHintButton(boolean show, boolean animated, int type) { if (type == -1 || type == 0) { if (hintButtonVisible == show) { return; } hintButtonVisible = show; if (!animated) { hintButtonProgress = show ? 1.0f : 0.0f; } else { invalidate(); } } if (type == -1 || type == 1) { if (psaButtonVisible == show) { return; } psaButtonVisible = show; if (!animated) { psaButtonProgress = show ? 1.0f : 0.0f; } else { setInvalidatesParent(true); invalidate(); } } } public void setCheckPressed(boolean value, boolean pressed) { isCheckPressed = value; isPressed = pressed; updateRadialProgressBackground(); if (useSeekBarWaveform) { seekBarWaveform.setSelected(isDrawSelectionBackground()); } else { seekBar.setSelected(isDrawSelectionBackground()); } invalidate(); } public void setInvalidateSpoilersParent(boolean invalidateSpoilersParent) { this.invalidateSpoilersParent = invalidateSpoilersParent; } public void setInvalidatesParent(boolean value) { invalidatesParent = value; } private boolean invalidateParentForce() { return ( !links.isEmpty() || !reactionsLayoutInBubble.isEmpty || currentMessageObject != null && currentMessageObject.preview ); } private final Runnable invalidateOutboundsRunnable = this::invalidateOutbounds; public void invalidateOutbounds() { if (delegate == null || !delegate.canDrawOutboundsContent()) { if (getParent() instanceof View) { ((View) getParent()).invalidate(); } } else { super.invalidate(); } } @Override public void invalidate() { if (currentMessageObject == null) { return; } if (super.invalidateCallback != null) { super.invalidateCallback.run(); } if (overrideInvalidate != null) { overrideInvalidate.run(); return; } if (invalidateListener != null) { invalidateListener.run(); } super.invalidate(); if ((invalidatesParent || currentMessagesGroup != null && invalidateParentForce()) && getParent() != null) { View parent = (View) getParent(); if (parent.getParent() != null) { parent.invalidate(); parent = (View) parent.getParent(); parent.invalidate(); } } if (isBlurred && delegate != null) { delegate.invalidateBlur(); } } @Override public void invalidateLite() { if (currentMessageObject == null) { return; } if (overrideInvalidate != null) { overrideInvalidate.run(); return; } if (invalidateListener != null) { invalidateListener.run(); } super.invalidate(); if ((invalidatesParent || currentMessagesGroup != null && invalidateParentForce()) && getParent() != null) { View parent = (View) getParent(); if (parent.getParent() != null) { parent.invalidate(); parent = (View) parent.getParent(); parent.invalidate(); } } if (isBlurred && delegate != null) { delegate.invalidateBlur(); } } private Runnable overrideInvalidate; public void setOverrideInvalidate(Runnable callback) { overrideInvalidate = callback; } private Runnable invalidateListener; public void setInvalidateListener(Runnable listener) { invalidateListener = listener; } @Override public void invalidate(int l, int t, int r, int b) { if (currentMessageObject == null) { return; } if (overrideInvalidate != null) { overrideInvalidate.run(); return; } if (invalidateListener != null) { invalidateListener.run(); } super.invalidate(l, t, r, b); if (invalidatesParent) { if (getParent() != null) { View parent = (View) getParent(); parent.invalidate((int) getX() + l, (int) getY() + t, (int) getX() + r, (int) getY() + b); } } if (isBlurred && delegate != null) { delegate.invalidateBlur(); } } public boolean isHighlightedAnimated() { return isHighlightedAnimated; } public void setHighlightedAnimated() { isHighlightedAnimated = true; highlightProgress = 1000; lastHighlightProgressTime = System.currentTimeMillis(); invalidate(); if (getParent() != null) { ((View) getParent()).invalidate(); } } public boolean isHighlighted() { return isHighlighted; } public void setHighlighted(boolean value) { if (isHighlighted == value) { return; } isHighlighted = value; if (value) { quoteHighlight = null; } if (!isHighlighted) { lastHighlightProgressTime = System.currentTimeMillis(); isHighlightedAnimated = true; highlightProgress = 300; } else { isHighlightedAnimated = false; highlightProgress = 0; } updateRadialProgressBackground(); if (useSeekBarWaveform) { seekBarWaveform.setSelected(isDrawSelectionBackground()); } else { seekBar.setSelected(isDrawSelectionBackground()); } invalidate(); if (getParent() != null) { ((View) getParent()).invalidate(); } } @Override public void setPressed(boolean pressed) { super.setPressed(pressed); updateRadialProgressBackground(); if (useSeekBarWaveform) { seekBarWaveform.setSelected(isDrawSelectionBackground()); } else { seekBar.setSelected(isDrawSelectionBackground()); } invalidate(); } private void updateRadialProgressBackground() { if (drawRadialCheckBackground) { return; } boolean forcePressed = (isHighlighted || isPressed || isPressed()) && (!drawPhotoImage || !photoImage.hasBitmapImage()); radialProgress.setPressed(forcePressed || buttonPressed != 0, false); if (hasMiniProgress != 0) { radialProgress.setPressed(forcePressed || miniButtonPressed != 0, true); } videoRadialProgress.setPressed(forcePressed || videoButtonPressed != 0, false); } @Override public void onSeekBarPressed() { requestDisallowInterceptTouchEvent(true); } @Override public void onSeekBarReleased() { requestDisallowInterceptTouchEvent(false); } @Override public boolean isSeekBarDragAllowed() { return currentMessageObject == null || !currentMessageObject.isVoiceOnce(); } @Override public boolean reverseWaveform() { return currentMessageObject != null && currentMessageObject.isVoiceOnce(); } @Override public void onSeekBarDrag(float progress) { if (currentMessageObject == null) { return; } currentMessageObject.audioProgress = progress; MediaController.getInstance().seekToProgress(currentMessageObject, progress); updatePlayingMessageProgress(); } @Override public void onSeekBarContinuousDrag(float progress) { if (currentMessageObject == null) { return; } currentMessageObject.audioProgress = progress; currentMessageObject.audioProgressSec = (int) (currentMessageObject.getDuration() * progress); updatePlayingMessageProgress(); } public boolean isAnimatingPollAnswer() { return animatePollAnswerAlpha; } private void updateWaveform() { if (currentMessageObject == null || documentAttachType != DOCUMENT_ATTACH_TYPE_AUDIO && documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND) { return; } byte[] waveform = currentMessageObject.getWaveform(); useSeekBarWaveform = waveform != null; if (seekBarWaveform != null) { seekBarWaveform.setWaveform(waveform); } useTranscribeButton = ( currentMessageObject != null && !currentMessageObject.isQuickReply() && !currentMessageObject.isRepostPreview && (!currentMessageObject.isOutOwner() || currentMessageObject.isSent()) && ( UserConfig.getInstance(currentAccount).isPremium() || TranscribeButton.isFreeTranscribeInChat(currentMessageObject) || MessagesController.getInstance(currentAccount).transcribeAudioTrialWeeklyNumber > 0 && currentMessageObject.getDuration() <= MessagesController.getInstance(currentAccount).transcribeAudioTrialDurationMax && ( currentMessageObject.messageOwner != null && ( !TextUtils.isEmpty(currentMessageObject.messageOwner.voiceTranscription) || currentMessageObject.messageOwner.voiceTranscriptionFinal ) || TranscribeButton.canTranscribeTrial(currentMessageObject) || true ) || MessagesController.getInstance(currentAccount).transcribeAudioTrialWeeklyNumber <= 0 && !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !MessagesController.getInstance(currentAccount).didPressTranscribeButtonEnough() && !currentMessageObject.isOutOwner() && ( currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionForce || currentMessageObject.getDuration() >= 60 ) ) && ( currentMessageObject.isVoice() && useSeekBarWaveform || currentMessageObject.isRoundVideo() ) && currentMessageObject.messageOwner != null && !(MessageObject.getMedia(currentMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage) && (currentMessageObject.messageOwner.media == null || currentMessageObject.messageOwner.media.ttl_seconds == 0) ); updateSeekBarWaveformWidth(null); } private int seekBarWaveformTranslateX; private int seekBarTranslateX; private void updateSeekBarWaveformWidth(Canvas canvas) { seekBarWaveformTranslateX = 0; seekBarTranslateX = 0; int offset = -dp(92 + (hasLinkPreview ? 10 : 0)); if (transitionParams.animateBackgroundBoundsInner && (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND)) { int fromBackgroundWidth = this.backgroundWidth; int toBackgroundWidth = (int) (this.backgroundWidth - transitionParams.toDeltaLeft + transitionParams.toDeltaRight); int backgroundWidth = (int) (this.backgroundWidth - transitionParams.deltaLeft + transitionParams.deltaRight); if (isRoundVideo && !drawBackground) { backgroundWidth += getVideoTranscriptionProgress() * dp(8); toBackgroundWidth += dp(8); } if (!(transitionParams.toDeltaLeft != 0 || transitionParams.toDeltaRight != 0)) { toBackgroundWidth = backgroundWidth; } if (seekBarWaveform != null) { if (transitionParams.animateUseTranscribeButton) { seekBarWaveform.setSize( backgroundWidth + offset - (int) (dp(34) * getUseTranscribeButtonProgress()) - dp(hasLinkPreview ? 10 : 0), dp(30), fromBackgroundWidth + offset + (!useTranscribeButton ? -dp(34) : 0), toBackgroundWidth + offset + (useTranscribeButton ? -dp(34) : 0) ); } else { seekBarWaveform.setSize( backgroundWidth + offset - (int) (dp(34) * getUseTranscribeButtonProgress()) - dp(hasLinkPreview ? 10 : 0), dp(30), fromBackgroundWidth + offset - (int) (dp(34) * getUseTranscribeButtonProgress()), toBackgroundWidth + offset - (int) (dp(34) * getUseTranscribeButtonProgress()) ); } } if (seekBar != null) { seekBar.setSize(backgroundWidth - (int) (getUseTranscribeButtonProgress() * dp(34)) - dp((documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC ? 65 : 72) + (hasLinkPreview ? 20 : 0)), dp(30)); } } else { if (seekBarWaveform != null) { if (transitionParams.animateUseTranscribeButton) { seekBarWaveform.setSize( backgroundWidth + offset - (int) (dp(34) * getUseTranscribeButtonProgress()) - dp(hasLinkPreview ? 10 : 0), dp(30), backgroundWidth + offset + (!useTranscribeButton ? -dp(34) : 0) - dp(hasLinkPreview ? 10 : 0), backgroundWidth + offset + (useTranscribeButton ? -dp(34) : 0) ); } else { seekBarWaveform.setSize( backgroundWidth + offset - (int) (dp(34) * getUseTranscribeButtonProgress()) - dp(hasLinkPreview ? 10 : 0), dp(30) ); } } if (seekBar != null) { seekBar.setSize(backgroundWidth - (int) (getUseTranscribeButtonProgress() * dp(34)) - dp((documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC ? 65 : 72) + (hasLinkPreview ? 20 : 0)), dp(30)); } } } private int createDocumentLayout(int maxWidth, MessageObject messageObject) { if (messageObject.sponsoredMedia != null) { documentAttach = messageObject.sponsoredMedia.document; } else if (messageObject.type == MessageObject.TYPE_TEXT) { TLRPC.MessageMedia media = MessageObject.getMedia(messageObject.messageOwner); TLRPC.WebPage webpage = media == null ? null : media.webpage; documentAttach = webpage == null ? null : webpage.document; } else { documentAttach = messageObject.getDocument(); } if (documentAttach == null) { return 0; } if (MessageObject.isVoiceDocument(documentAttach)) { documentAttachType = DOCUMENT_ATTACH_TYPE_AUDIO; double duration = 0; for (int a = 0; a < documentAttach.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeAudio) { duration = attribute.duration; break; } } widthBeforeNewTimeLine = maxWidth - dp(76 + 18) - (int) Math.ceil(Theme.chat_audioTimePaint.measureText("00:00")); availableTimeWidth = maxWidth - dp(18); measureTime(messageObject); int minSize = dp(40 + 14 + 20 + 90 + 10) + timeWidth; if (!hasLinkPreview) { String timeString = AndroidUtilities.formatLongDuration((int) duration); int w = (int) Math.ceil(Theme.chat_audioTimePaint.measureText(timeString)); backgroundWidth = Math.min(maxWidth, minSize + w); } seekBarWaveform.setMessageObject(messageObject); return 0; } else if (MessageObject.isVideoDocument(documentAttach)) { documentAttachType = DOCUMENT_ATTACH_TYPE_VIDEO; if (!messageObject.needDrawBluredPreview()) { updatePlayingMessageProgress(); String str; str = String.format("%s", AndroidUtilities.formatFileSize(documentAttach.size)); docTitleWidth = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); docTitleLayout = new StaticLayout(str, Theme.chat_infoPaint, docTitleWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } return 0; } else if (MessageObject.isMusicDocument(documentAttach)) { documentAttachType = DOCUMENT_ATTACH_TYPE_MUSIC; maxWidth = maxWidth - dp(92); if (maxWidth < 0) { maxWidth = dp(100); } CharSequence stringFinal = TextUtils.ellipsize(messageObject.getMusicTitle().replace('\n', ' '), Theme.chat_audioTitlePaint, maxWidth - dp(12), TextUtils.TruncateAt.END); songLayout = new StaticLayout(stringFinal, Theme.chat_audioTitlePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (songLayout.getLineCount() > 0) { songX = -(int) Math.ceil(songLayout.getLineLeft(0)); int songLayoutWidth = (int) songLayout.getLineWidth(0); if (songLayoutWidth + dp(92 + 12) > backgroundWidth) { backgroundWidth = songLayoutWidth + dp(92 + 12); } } stringFinal = TextUtils.ellipsize(messageObject.getMusicAuthor().replace('\n', ' '), Theme.chat_audioPerformerPaint, maxWidth, TextUtils.TruncateAt.END); performerLayout = new StaticLayout(stringFinal, Theme.chat_audioPerformerPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (performerLayout.getLineCount() > 0) { performerX = -(int) Math.ceil(performerLayout.getLineLeft(0)); int performerLayoutWidth = (int) performerLayout.getLineWidth(0); if (performerLayoutWidth + dp(92 + 12) > backgroundWidth) { backgroundWidth = performerLayoutWidth + dp(92 + 12); } } double duration = 0; for (int a = 0; a < documentAttach.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeAudio) { duration = attribute.duration; break; } } int durationWidth = (int) Math.ceil(Theme.chat_audioTimePaint.measureText(AndroidUtilities.formatShortDuration((int) duration, (int) duration))); widthBeforeNewTimeLine = backgroundWidth - dp(10 + 76) - durationWidth; availableTimeWidth = backgroundWidth - dp(28); return durationWidth; } else if (MessageObject.isGifDocument(documentAttach, messageObject.hasValidGroupId())) { documentAttachType = DOCUMENT_ATTACH_TYPE_GIF; if (!messageObject.needDrawBluredPreview()) { String str = getString("AttachGif", R.string.AttachGif); infoWidth = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); infoLayout = new StaticLayout(str, Theme.chat_infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); str = String.format("%s", AndroidUtilities.formatFileSize(documentAttach.size)); docTitleWidth = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); docTitleLayout = new StaticLayout(str, Theme.chat_infoPaint, docTitleWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } return 0; } else { drawPhotoImage = documentAttach.mime_type != null && (documentAttach.mime_type.toLowerCase().startsWith("image/") || documentAttach.mime_type.toLowerCase().startsWith("video/mp4")) || MessageObject.isDocumentHasThumb(documentAttach); if (!drawPhotoImage) { maxWidth += dp(30); } documentAttachType = DOCUMENT_ATTACH_TYPE_DOCUMENT; String name = FileLoader.getDocumentFileName(documentAttach); if (name.length() == 0) { name = getString("AttachDocument", R.string.AttachDocument); } docTitleLayout = StaticLayoutEx.createStaticLayout(name, Theme.chat_docNamePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.MIDDLE, maxWidth, 2, false); docTitleOffsetX = Integer.MIN_VALUE; int width; if (docTitleLayout != null && docTitleLayout.getLineCount() > 0) { int maxLineWidth = 0; for (int a = 0; a < docTitleLayout.getLineCount(); a++) { maxLineWidth = Math.max(maxLineWidth, (int) Math.ceil(docTitleLayout.getLineWidth(a))); docTitleOffsetX = Math.max(docTitleOffsetX, (int) Math.ceil(-docTitleLayout.getLineLeft(a))); } width = Math.min(maxWidth, maxLineWidth); } else { width = maxWidth; docTitleOffsetX = 0; } String str = AndroidUtilities.formatFileSize(documentAttach.size) + " " + FileLoader.getDocumentExtension(documentAttach); infoWidth = Math.min(maxWidth - dp(30), (int) Math.ceil(Theme.chat_infoPaint.measureText("000.0 mm / " + AndroidUtilities.formatFileSize(documentAttach.size)))); CharSequence str2 = TextUtils.ellipsize(str, Theme.chat_infoPaint, infoWidth, TextUtils.TruncateAt.END); try { if (infoWidth < 0) { infoWidth = dp(10); } infoLayout = new StaticLayout(str2, Theme.chat_infoPaint, infoWidth + dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } catch (Exception e) { FileLog.e(e); } if (drawPhotoImage) { currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 320); currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40); if (currentMessageObject.isHiddenSensitive() || (DownloadController.getInstance(currentAccount).getAutodownloadMask() & DownloadController.AUTODOWNLOAD_TYPE_PHOTO) == 0) { currentPhotoObject = null; } if (currentPhotoObject == null || currentPhotoObject == currentPhotoObjectThumb) { currentPhotoObject = null; photoImage.setNeedsQualityThumb(true); photoImage.setShouldGenerateQualityThumb(true); } else if (currentMessageObject.strippedThumb != null) { currentPhotoObjectThumb = null; currentPhotoObjectThumbStripped = currentMessageObject.strippedThumb; } currentPhotoFilter = "86_86_b"; photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, messageObject.photoThumbsObject), "86_86", ImageLocation.getForObject(currentPhotoObjectThumb, messageObject.photoThumbsObject), currentPhotoFilter, currentPhotoObjectThumbStripped, 0, null, messageObject, 1); } return width; } } private void calcBackgroundWidth(int maxWidth, int timeMore, int maxChildWidth) { if (currentMessageObject.isSponsored()) { backgroundWidth = maxChildWidth + dp(31); return; } boolean newLineForTime; int lastLineWidth = (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) ? currentMessageObject.getLastLineWidth() : reactionsLayoutInBubble.lastLineX; if (!reactionsLayoutInBubble.isEmpty && !reactionsLayoutInBubble.isSmall) { newLineForTime = maxWidth - lastLineWidth < timeMore || currentMessageObject.hasRtl; if (hasInvoicePreview) { totalHeight += dp(14); } } else { newLineForTime = !linkPreviewAbove && (hasLinkPreview && !currentMessageObject.isSponsored() || hasFactCheck || hasOldCaptionPreview || hasGamePreview || hasInvoicePreview) || maxWidth - lastLineWidth < timeMore || currentMessageObject.hasRtl; } int newLineForTimeDp = 14; if (currentMessageObject.isUnsupported()) { newLineForTime = true; } if ((reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) && currentMessageObject.richLayout != null && currentMessageObject.richLayout.forceNewLineForTime()) { newLineForTime = true; } if ( currentMessageObject.hasCodeAtBottom && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) || currentMessageObject.hasQuoteAtBottom && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) || currentMessageObject.isGiveawayOrGiveawayResults() ) { newLineForTime = true; newLineForTimeDp = 18; } if (newLineForTime) { totalHeight += dp(newLineForTimeDp); hasNewLineForTime = true; backgroundWidth = Math.max(maxChildWidth, lastLineWidth) + dp(31); backgroundWidth = Math.max(backgroundWidth, (currentMessageObject.isOutOwner() ? timeWidth + dp(17) : timeWidth) + dp(31)); } else { int diff = maxChildWidth - getExtraTextX() - lastLineWidth; if (diff >= 0 && diff <= timeMore) { backgroundWidth = maxChildWidth + timeMore - diff + dp(31); } else { backgroundWidth = Math.max(maxChildWidth, lastLineWidth + timeMore) + dp(31); } } } public boolean setHighlightedText(String text) { return setHighlightedText(text, false, -1, false); } public boolean setHighlightedText(String text, boolean quote, int quote_offset, boolean byClick) { if (highlightedQuote && !quote && TextUtils.isEmpty(text)) { return false; } MessageObject messageObject = messageObjectToSet != null ? messageObjectToSet : currentMessageObject; highlightedQuote = quote; if (messageObject == null || TextUtils.isEmpty(text)) { if (!urlPathSelection.isEmpty()) { linkSelectionBlockNum = -1; highlightedQuote = false; resetUrlPaths(); invalidate(); } return false; } if (!quote) { quoteHighlight = null; } String message; if (currentCaption != null) { message = currentCaption.toString(); } else { message = messageObject.messageOwner.message; } if (message == null || TextUtils.isEmpty(message)) { if (!urlPathSelection.isEmpty()) { linkSelectionBlockNum = -1; highlightedQuote = false; resetUrlPaths(); invalidate(); } return false; } if (!quote) { text = text.toLowerCase(); message = message.toLowerCase(); } int start = -1, length = -1; String punctuationsChars = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n"; if (quote) { start = MessageObject.findQuoteStart(message, text, quote_offset); length = text.length(); } else { for (int a = 0, N1 = message.length(); a < N1; a++) { int currentLen = 0; for (int b = 0, N2 = Math.min(text.length(), N1 - a); b < N2; b++) { boolean match = message.charAt(a + b) == text.charAt(b); if (match) { if (currentLen != 0 || a == 0 || punctuationsChars.indexOf(message.charAt(a - 1)) >= 0) { currentLen++; } else { match = false; } } if (!match || b == N2 - 1) { if (currentLen > 0 && currentLen > length) { length = currentLen; start = a; } break; } } } } if (start == -1) { if (!urlPathSelection.isEmpty()) { linkSelectionBlockNum = -1; highlightedQuote = false; resetUrlPaths(); invalidate(); } return false; } if (!quote) { for (int a = start + length, N = message.length(); a < N; a++) { if (punctuationsChars.indexOf(message.charAt(a)) < 0) { length++; } else { break; } } } highlightedQuote = quote; int end = start + length; if (quote && currentMessagesGroup == null && groupedMessagesToSet == null) { final boolean hadQuoteHighlight = quoteHighlight == null || !quoteHighlight.done(); if (quoteHighlight == null || quoteHighlight.todo || quoteHighlight.poll || quoteHighlight.id != messageObject.getId() || quoteHighlight.start != start || quoteHighlight.end != end) { if (captionLayout != null) { quoteHighlight = new QuoteHighlight(this, getParent(), messageObject.getId(), captionLayout.textLayoutBlocks, start, end, captionLayout.textXOffset); } else { quoteHighlight = new QuoteHighlight(this, getParent(), messageObject.getId(), messageObject.textLayoutBlocks, start, end, messageObject.textXOffset); } } if (quoteHighlight != null && !quoteHighlight.quotesToExpand.isEmpty()) { if (byClick) { MessageObject msg = getPrimaryMessageObject(); if (msg == null) msg = messageObject; if (msg != null) { msg.expandedQuotes = msg.expandedQuotes == null ? new HashSet<>() : new HashSet<>(msg.expandedQuotes); msg.expandedQuotes.addAll(quoteHighlight.quotesToExpand); if (delegate != null) { delegate.forceUpdate(this, false); } } } else if (!hadQuoteHighlight) { quoteHighlight = null; } } } else if (!TextUtils.isEmpty(currentCaption)) { if (captionLayout == null) { highlightCaptionToSetStart = start; highlightCaptionToSetEnd = end; } else { highlight(start, end, captionLayout.textLayoutBlocks); } } else if (messageObject.textLayoutBlocks != null) { highlight(start, end, messageObject.textLayoutBlocks); } return true; } public boolean setHighlightedTask(int taskId) { final MessageObject messageObject = messageObjectToSet != null ? messageObjectToSet : currentMessageObject; if (messageObject == null) { quoteHighlight = null; return false; } if (quoteHighlight == null || !quoteHighlight.todo || quoteHighlight.start != -taskId) { quoteHighlight = new QuoteHighlight(this, messageObject.getId(), taskId); } highlightedQuote = true; return true; } public boolean setHighlightedPoll(byte[] pollOptionId) { final MessageObject messageObject = messageObjectToSet != null ? messageObjectToSet : currentMessageObject; if (messageObject == null) { quoteHighlight = null; return false; } if (quoteHighlight == null || !quoteHighlight.poll || !Arrays.equals(quoteHighlight.pollOptionId, pollOptionId)) { quoteHighlight = new QuoteHighlight(this, messageObject.getId(), pollOptionId); } highlightedQuote = true; return true; } private void highlight(int start, int end, ArrayList textLayoutBlocks) { if (textLayoutBlocks == null) { return; } int length = end - start; for (int c = 0; c < textLayoutBlocks.size(); c++) { MessageObject.TextLayoutBlock block = textLayoutBlocks.get(c); if (start >= block.charactersOffset && start < block.charactersEnd) { linkSelectionBlockNum = c; resetUrlPaths(); try { LinkPath path = obtainNewUrlPath(); path.setUseCornerPathImplementation(true); path.setCurrentLayout(block.textLayout, start, 0); block.textLayout.getSelectionPath(start, end, path); path.closeRects(); float y = block.height + block.padBottom; if (end >= block.charactersOffset + length) { for (int a = c + 1; a < textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = textLayoutBlocks.get(a); length = nextBlock.charactersEnd - nextBlock.charactersOffset; path = obtainNewUrlPath(); path.setUseCornerPathImplementation(true); y += nextBlock.padTop; path.setCurrentLayout(nextBlock.textLayout, 0, y); y += nextBlock.height + nextBlock.padBottom; nextBlock.textLayout.getSelectionPath(0, end - nextBlock.charactersOffset, path); path.closeRects(); if (end < block.charactersOffset + length - 1) { break; } } } if (highlightedQuote) { isHighlightedAnimated = true; highlightProgress = 2500; } } catch (Exception e) { FileLog.e(e); } invalidate(); break; } } highlightCaptionToSetStart = -1; highlightCaptionToSetEnd = -1; } public boolean setHighlightedSpan(CharacterStyle span) { MessageObject messageObject = messageObjectToSet != null ? messageObjectToSet : currentMessageObject; highlightedQuote = false; if (messageObject == null || messageObject.messageOwner.message == null || span == null) { if (!urlPathSelection.isEmpty()) { linkSelectionBlockNum = -1; highlightedQuote = false; resetUrlPaths(); invalidate(); } return false; } if (captionLayout != null && !TextUtils.isEmpty(messageObject.caption) && messageObject.caption instanceof Spannable) { Spanned spanned = (Spanned) messageObject.caption; int start = -1, end = -1; CharacterStyle[] spans = spanned.getSpans(0, spanned.length(), CharacterStyle.class); if (spans != null && spans.length > 0) { for (int i = 0; i < spans.length; ++i) { if (spans[i] == span) { start = spanned.getSpanStart(span); end = spanned.getSpanEnd(span); break; } } } if (start >= 0 && end >= 0) { int length = (end - start); for (int c = 0; c < captionLayout.textLayoutBlocks.size(); c++) { MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(c); if (start >= block.charactersOffset && start < block.charactersEnd) { linkSelectionBlockNum = c; highlightedQuote = false; resetUrlPaths(); try { LinkPath path = obtainNewUrlPath(); path.setCurrentLayout(block.textLayout, start, 0); block.textLayout.getSelectionPath(start, end, path); if (end >= block.charactersOffset + length) { for (int a = c + 1; a < captionLayout.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = captionLayout.textLayoutBlocks.get(a); length = nextBlock.charactersEnd - nextBlock.charactersOffset; path = obtainNewUrlPath(); path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.height); nextBlock.textLayout.getSelectionPath(0, end - nextBlock.charactersOffset, path); if (end < block.charactersOffset + length - 1) { break; } } } } catch (Exception e) { FileLog.e(e); } invalidate(); return true; } } } } if (messageObject.messageText instanceof Spanned && messageObject.textLayoutBlocks != null) { Spanned spanned = (Spanned) messageObject.messageText; int start = -1, end = -1; CharacterStyle[] spans = spanned.getSpans(0, spanned.length(), CharacterStyle.class); if (spans != null && spans.length > 0) { for (int i = 0; i < spans.length; ++i) { if (spans[i] == span) { start = spanned.getSpanStart(span); end = spanned.getSpanEnd(span); break; } } } if (start >= 0 && end >= 0) { int length = (end - start); for (int c = 0; c < messageObject.textLayoutBlocks.size(); c++) { MessageObject.TextLayoutBlock block = messageObject.textLayoutBlocks.get(c); if (start >= block.charactersOffset && start < block.charactersEnd) { linkSelectionBlockNum = c; highlightedQuote = false; resetUrlPaths(); try { LinkPath path = obtainNewUrlPath(); path.setCurrentLayout(block.textLayout, start, 0); block.textLayout.getSelectionPath(start, end, path); if (end >= block.charactersOffset + length) { for (int a = c + 1; a < messageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = messageObject.textLayoutBlocks.get(a); length = nextBlock.charactersEnd - nextBlock.charactersOffset; path = obtainNewUrlPath(); path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.height); nextBlock.textLayout.getSelectionPath(0, end - nextBlock.charactersOffset, path); if (end < block.charactersOffset + length - 1) { break; } } } } catch (Exception e) { FileLog.e(e); } invalidate(); return true; } } } } if (!urlPathSelection.isEmpty()) { linkSelectionBlockNum = -1; highlightedQuote = false; resetUrlPaths(); invalidate(); } return false; } @Override protected boolean verifyDrawable(@NonNull Drawable who) { if (super.verifyDrawable(who) || who == selectorDrawable[0] || who == animatedInfoLayout || who == selectorDrawable[1] || who == linkPreviewSelector || who == nameLayoutSelector || who == replySelector || reactionsLayoutInBubble != null && reactionsLayoutInBubble.verifyDrawable(who) || who instanceof LoadingDrawable) { return true; } if (pollAddButtonDrawable != null && pollAddButtonDrawable.verifyDrawable(who)) { return true; } for (PollButton button : pollButtons) { if (button.selectorDrawable == who || button.pollButtonDrawable != null && button.pollButtonDrawable.verifyDrawable(who)) { return true; } } return false; } @Override public void invalidateDrawable(Drawable drawable) { super.invalidateDrawable(drawable); if (currentMessagesGroup != null) { invalidateWithParent(); } } private boolean isCurrentLocationTimeExpired(MessageObject messageObject) { final int period = MessageObject.getMedia(currentMessageObject.messageOwner).period; final int currentTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); if (period == 0x7fffffff) { return false; } else if (period % 60 == 0) { return Math.abs(currentTime - messageObject.messageOwner.date) > period; } else { return Math.abs(currentTime - messageObject.messageOwner.date) > period - 5; } } private void checkLocationExpired() { if (currentMessageObject == null) { return; } boolean newExpired = isCurrentLocationTimeExpired(currentMessageObject); if (newExpired != locationExpired) { locationExpired = newExpired; if (!locationExpired) { AndroidUtilities.runOnUIThread(invalidateRunnable, 1000); scheduledInvalidate = true; int maxWidth = backgroundWidth - dp(37 + 54); docTitleLayout = new StaticLayout(TextUtils.ellipsize(getString(R.string.AttachLiveLocation), Theme.chat_locationTitlePaint, maxWidth, TextUtils.TruncateAt.END), Theme.chat_locationTitlePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else { MessageObject messageObject = currentMessageObject; currentMessageObject = null; setMessageObject(messageObject, currentMessagesGroup, pinnedBottom, pinnedTop, firstInChat); } } } public void setIsUpdating(boolean value) { isUpdating = true; } public void setMessageObject(MessageObject messageObject, MessageObject.GroupedMessages groupedMessages, boolean bottomNear, boolean topNear, boolean firstInChat ) { setMessageObject(messageObject, groupedMessages, bottomNear, topNear, firstInChat, false); } public void setMessageObject(MessageObject messageObject, MessageObject.GroupedMessages groupedMessages, boolean bottomNear, boolean topNear, boolean firstInChat, boolean lastInChatList) { if (attachedToWindow && !frozen) { setMessageContent(messageObject, groupedMessages, bottomNear, topNear, firstInChat, lastInChatList); } else { messageObjectToSet = messageObject; groupedMessagesToSet = groupedMessages; bottomNearToSet = bottomNear; topNearToSet = topNear; firstInChatToSet = firstInChat; lastInChatListToSet = lastInChatList; } } private boolean frozen; public void freezeCell(boolean freeze) { this.frozen = freeze; if (!frozen && messageObjectToSet != null && attachedToWindow) { messageObjectToSet.animateComments = false; setMessageContent(messageObjectToSet, groupedMessagesToSet, bottomNearToSet, topNearToSet, firstInChatToSet, lastInChatListToSet); messageObjectToSet = null; groupedMessagesToSet = null; } } private int getAdditionalWidthForPosition(MessageObject.GroupedMessagePosition position) { int w = 0; if (position != null) { if ((position.flags & MessageObject.POSITION_FLAG_RIGHT) == 0) { w += dp(4); } if ((position.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { w += dp(4); } } return w; } public void createSelectorDrawable(int num) { int color; if (currentMessageObject.isUnsupported()) { color = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewInstantText : Theme.key_chat_inPreviewInstantText); } else if (num == 0 && psaHintPressed) { color = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outViews : Theme.key_chat_inViews); } else if (num == 0 && linkLine != null) { color = linkLine.getColor(); } else if (num == 0 && contactLine != null) { color = contactLine.getColor(); } else { color = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewInstantText : Theme.key_chat_inPreviewInstantText); } if (selectorDrawable[num] == null) { selectorMaskDrawable[num] = new MaskDrawable() { @Override public void updatePath() { android.graphics.Rect bounds = getBounds(); rect.set(pathX = bounds.left, pathY = bounds.top, bounds.right, bounds.bottom); path.rewind(); if (selectorDrawableMaskType[num] == 3 || selectorDrawableMaskType[num] == 4) { path.addCircle(rect.centerX(), rect.centerY(), dp(selectorDrawableMaskType[num] == 3 ? 16 : 20), Path.Direction.CW); } else if (selectorDrawableMaskType[num] == 2) { boolean out = currentMessageObject != null && currentMessageObject.isOutOwner(); for (int a = 0; a < 4; a++) { if (!instantTextNewLine) { if (a == (out ? 3 : 2)) { radii[a * 2] = radii[a * 2 + 1] = dp(SharedConfig.bubbleRadius); continue; } if ((mediaBackground && currentPosition == null || pinnedBottom) && (a == 2 || a == 3)) { radii[a * 2] = radii[a * 2 + 1] = dp(pinnedBottom ? Math.min(5, SharedConfig.bubbleRadius) : SharedConfig.bubbleRadius); continue; } } radii[a * 2] = radii[a * 2 + 1] = 0; } if (!out && !drawPinnedBottom && currentPosition == null && (currentPosition == null || pollInstantViewTouchesBottom)) { path.moveTo(rect.left + dp(6), rect.top); path.lineTo(rect.left + dp(6), rect.bottom - dp(6) - dp(2 + 3)); AndroidUtilities.rectTmp.set( rect.left + dp(7 - 12 - 2), rect.bottom - dp(12 + 2 + 9), rect.left + dp(8 - 2), rect.bottom ); path.arcTo(AndroidUtilities.rectTmp, 0, 83, false); AndroidUtilities.rectTmp.set(rect.right - radii[4] * 2, rect.bottom - radii[5] * 2, rect.right, rect.bottom); path.arcTo(AndroidUtilities.rectTmp, 90, -90, false); path.lineTo(rect.right, rect.top); path.close(); } else { path.addRoundRect(rect, radii, Path.Direction.CW); } path.close(); } else { final float r = selectorDrawableMaskType[num] == 0 ? dp(6) : 0; path.addRoundRect(rect, r, r, Path.Direction.CW); } } }; ColorStateList colorStateList = new ColorStateList( new int[][]{StateSet.WILD_CARD}, new int[]{getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewInstantText : Theme.key_chat_inPreviewInstantText) & 0x19ffffff} ); selectorDrawable[num] = new BaseCell.RippleDrawableSafe(colorStateList, null, selectorMaskDrawable[num]); selectorDrawable[num].setCallback(this); } else { Theme.setSelectorDrawableColor(selectorDrawable[num], color & 0x19ffffff, true); } selectorDrawable[num].setVisible(true, false); } private static class MaskDrawable extends Drawable { protected final Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); { maskPaint.setColor(0xffffffff); } public final RectF rect = new RectF(); public int pathX, pathY; public final Path path = new Path(); public void updatePath() {} @Override public void draw(@NonNull Canvas canvas) { updatePath(); canvas.drawPath(path, maskPaint); } @Override public void setAlpha(int alpha) {} @Override public void setColorFilter(ColorFilter colorFilter) {} @Override public int getOpacity() { return PixelFormat.TRANSPARENT; } } private void createInstantViewButton() { if (drawInstantView) { createSelectorDrawable(0); } if (drawInstantView && instantViewLayout == null) { CharSequence str; instantWidth = dp(12 + 9 + 12); if (instantViewButtonText != null) { str = instantViewButtonText; } else if (drawInstantViewType == 12) { str = getString(R.string.OpenChannelPost); } else if (drawInstantViewType == 1) { str = getString(R.string.OpenChannel); } else if (drawInstantViewType == 29) { str = getString(R.string.OpenChannelDirect); } else if (drawInstantViewType == 13) { str = getString(R.string.SendMessage).toUpperCase(); } else if (drawInstantViewType == INSTANT_BUTTON_TYPE_PROFILE) { str = getString(R.string.OpenProfile).toUpperCase(); } else if (drawInstantViewType == INSTANT_BUTTON_TYPE_AI_STYLE) { str = getString(R.string.OpenAIStyle); } else if (drawInstantViewType == 10) { str = getString(R.string.OpenBot); } else if (drawInstantViewType == 2) { str = getString(R.string.OpenGroup); } else if (drawInstantViewType == 3) { str = getString(R.string.OpenMessage); } else if (drawInstantViewType == 5) { str = getString(R.string.ViewContact); } else if (drawInstantViewType == 6) { str = getString(R.string.OpenBackground); } else if (drawInstantViewType == 7) { str = getString(R.string.OpenTheme); } else if (drawInstantViewType == 9 || drawInstantViewType == 11) { TLRPC.TL_webPage webPage = (TLRPC.TL_webPage) MessageObject.getMedia(currentMessageObject.messageOwner).webpage; if (webPage != null && webPage.url.contains("voicechat=")) { str = getString(R.string.VoipGroupJoinAsSpeaker); } else { str = getString(R.string.VoipGroupJoinAsLinstener); } } else if (drawInstantViewType == 25) { str = getString(R.string.VoipGroupJoinAsLinstener); } else if (drawInstantViewType == 14) { str = getString(R.string.ViewChatList).toUpperCase(); } else if (drawInstantViewType == 15) { str = getString(R.string.BotWebAppInstantViewOpen).toUpperCase(); } else if (drawInstantViewType == 16) { str = getString(R.string.OpenLink).toUpperCase(); } else if (drawInstantViewType == 17) { str = getString(R.string.ViewStory).toUpperCase(); } else if (drawInstantViewType == 18 || drawInstantViewType == 22) { str = getString(R.string.BoostLinkButton); } else if (drawInstantViewType == 19) { str = getString(R.string.BoostingHowItWork); } else if (drawInstantViewType == 20) { str = getString(R.string.OpenGift); } else if (drawInstantViewType == 21) { str = getString(R.string.AppUpdate); } else if (drawInstantViewType == 23) { str = getString(R.string.OpenStickerSet); } else if (drawInstantViewType == 24) { str = getString(R.string.OpenEmojiSet); } else if (drawInstantViewType == 26) { if (instantViewTypeIsGiftAuction != null) { final boolean needIcon; if (instantViewTypeIsGiftAuction.auction_start_date > ConnectionsManager.getInstance(currentAccount).getCurrentTime()) { str = getString(R.string.OpenGiftAuctionView); needIcon = false; } else if (instantViewTypeIsGiftAuction.sold_out) { str = getString(R.string.OpenGiftAuctionResults); needIcon = true; } else { str = getString(R.string.OpenGiftAuctionActive); needIcon = true; } if (needIcon) { SpannableString ok = new SpannableString("*"); ok.setSpan(new ColoredImageSpan(R.drawable.filled_gift_sell_24), 0, ok.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); str = TextUtils.concat(ok, " ", str); } } else { str = getString(R.string.OpenUniqueGift); } } else if (drawInstantViewType == 27) { str = getString(R.string.JoinCall).toUpperCase(); } else if (drawInstantViewType == 28) { str = getString(R.string.ViewCollection); } else { str = getString(R.string.InstantView); } if (currentMessageObject.isSponsored()) { int buttonWidth = (int) (Theme.chat_instantViewPaint.measureText(str, 0, str.length()) + dp(10 + 24 + 10 + 31)); if (backgroundWidth < buttonWidth) { backgroundWidth = buttonWidth; } } int mWidth = backgroundWidth - dp(10 + 24 + 10 + 31); instantViewLayout = new StaticLayout(TextUtils.ellipsize(str, Theme.chat_instantViewPaint, mWidth, TextUtils.TruncateAt.END), Theme.chat_instantViewPaint, mWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); instantViewLayoutWidth = instantViewLayout.getLineCount() > 0 ? instantViewLayout.getLineWidth(0) : 0; instantViewLayoutLeft = instantViewLayout.getLineCount() > 0 ? instantViewLayout.getLineLeft(0) : 0; instantWidth = backgroundWidth - dp(drawInstantViewType == INSTANT_BUTTON_TYPE_BACK_TO_VOTE || drawInstantViewType == INSTANT_BUTTON_TYPE_VIEW_VOTES_AS_AUTHOR_LIST || drawInstantViewType == INSTANT_BUTTON_TYPE_VIEW_VOTES_PUBLIC_LIST || drawInstantViewType == INSTANT_BUTTON_TYPE_ADD_OPTION || drawInstantViewType == INSTANT_BUTTON_TYPE_VOTE_MULTISELECT ? 13 : 34); totalHeight += dp(46); if (currentMessageObject.type == MessageObject.TYPE_CONTACT) { totalHeight += dp(14); } if (currentMessageObject.isSponsored()) { totalHeight += dp(2); } if (instantViewLayout != null && instantViewLayout.getLineCount() > 0) { instantTextX = (int) (instantWidth - Math.ceil(instantViewLayout.getLineWidth(0))) / 2 + (drawInstantViewType == 0 ? dp(8) : 0); instantTextLeftX = (int) instantViewLayout.getLineLeft(0); instantTextX += -instantTextLeftX; } } } private void createContactButtons() { createSelectorDrawable(0); if (drawContact) { int needDrawFlag = 0; int buttonsCount = 0; if (drawContactView) { needDrawFlag |= 1; buttonsCount++; } if (drawContactSendMessage) { needDrawFlag |= 2; buttonsCount++; } if (drawContactAdd) { needDrawFlag |= 4; buttonsCount++; } if (buttonsCount == 0) { contactButtons = null; drawnContactButtonsFlag = 0; return; } totalHeight += dp(60); boolean needRecreate = needDrawFlag != drawnContactButtonsFlag; if (needRecreate) { drawnContactButtonsFlag = 0; int mWidth = (backgroundWidth - dp(10 + 24 + 10 + 31)) / buttonsCount; float parentWidth = (backgroundWidth - AndroidUtilities.dpf2(37)) / buttonsCount; if (contactButtons == null) { contactButtons = new ArrayList<>(buttonsCount); } else { contactButtons.clear(); } if (drawContactView) { drawnContactButtonsFlag |= 1; String str = getString("ViewContact", R.string.ViewContact); InstantViewButton instantViewButton = createInstantViewButton(INSTANT_BUTTON_TYPE_CONTACT_VIEW, str, mWidth, parentWidth); contactButtons.add(instantViewButton); } if (drawContactSendMessage) { drawnContactButtonsFlag |= 2; String str = getString("SharedContactMessage", R.string.SharedContactMessage); InstantViewButton instantViewButton = createInstantViewButton(INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE, str, mWidth, parentWidth); contactButtons.add(instantViewButton); } if (drawContactAdd) { drawnContactButtonsFlag |= 4; String str = getString("SharedContactAdd", R.string.SharedContactAdd); InstantViewButton instantViewButton = createInstantViewButton(INSTANT_BUTTON_TYPE_CONTACT_ADD, str, mWidth, parentWidth); contactButtons.add(instantViewButton); } } } } private InstantViewButton createInstantViewButton(int type, String str, int availableWidth, float parentWidth) { InstantViewButton instantViewButton = new InstantViewButton(); instantViewButton.type = type; instantViewButton.layout = new StaticLayout(TextUtils.ellipsize(str, Theme.chat_instantViewPaint, availableWidth, TextUtils.TruncateAt.END), Theme.chat_instantViewPaint, availableWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); instantViewButton.buttonWidth = parentWidth; if (instantViewButton.layout.getLineCount() > 0) { instantViewButton.textX = (float) (instantViewButton.buttonWidth - Math.ceil(instantViewButton.layout.getLineWidth(0))) / 2; int instantTextLeftX = (int) instantViewButton.layout.getLineLeft(0); instantViewButton.textX -= instantTextLeftX; } return instantViewButton; } @Override public void requestLayout() { if (inLayout) { return; } super.requestLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (currentMessageObject != null && (currentMessageObject.checkLayout() || lastHeight != AndroidUtilities.displaySize.y)) { inLayout = true; MessageObject messageObject = currentMessageObject; currentMessageObject = null; setMessageObject(messageObject, currentMessagesGroup, pinnedBottom, pinnedTop, firstInChat); inLayout = false; } updateSelectionTextPosition(); final int normHeight = starsPriceTopPadding + topicSeparatorTopPadding + suggestionOfferTopPadding + totalHeight + keyboardHeight + askBotForumBottomPadding + bottomActionPadding; int resultHeight = normHeight; ChatActivityDraftMessageMeasureController botDraftHeightController = getDraftMessageMeasureController(); if (botDraftHeightController != null) { resultHeight = botDraftHeightController.getOverrideMeasureHeight(currentMessageObject, normHeight); } additionalPaddingHeight = Math.max(0, resultHeight - normHeight); setMeasuredDimension( isWidthAdaptive() ? getBoundsRight() - getBoundsLeft() : MeasureSpec.getSize(widthMeasureSpec), resultHeight ); } private int additionalPaddingHeight; public int getAdditionalPaddingHeight() { return additionalPaddingHeight; } public void forceResetMessageObject() { MessageObject messageObject = messageObjectToSet != null ? messageObjectToSet : currentMessageObject; currentMessageObject = null; setMessageObject(messageObject, currentMessagesGroup, pinnedBottom, pinnedTop, firstInChat); } private int getGroupPhotosWidth() { int width = getParentWidth(); if (currentMessageObject != null && currentMessageObject.preview) { width = parentWidth; } if (!AndroidUtilities.isInMultiwindow && AndroidUtilities.isTablet() && (!AndroidUtilities.isSmallTablet() || getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)) { final int leftWidth = AndroidUtilities.getTabletLeftFragmentSize(width, 0, 0); return width - leftWidth; } else { return width; } } public boolean isUpdating() { return isUpdating; } int getExtraTextX() { int pad = 0; // if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_ARTICLE) { // pad += dp(4); // } if (SharedConfig.bubbleRadius >= 15) { pad += dp(2); } else if (SharedConfig.bubbleRadius >= 11) { pad += dp(1); } return pad; } private int getExtraTimeX() { if (!currentMessageObject.isOutOwner() && (!mediaBackground || captionLayout != null) && SharedConfig.bubbleRadius > 11) { return dp((SharedConfig.bubbleRadius - 11) / 1.5f); } if (!currentMessageObject.isOutOwner() && isPlayingRound && isAvatarVisible && currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { return (int) ((AndroidUtilities.roundPlayingMessageSize(isSideMenued) - AndroidUtilities.roundMessageSize) * 0.7f); } return 0; } public void relayout() { forcedLayout = true; forceLayout(); } int lastSize; @SuppressLint("DrawAllocation") @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (currentMessageObject == null) { return; } int currentSize = getMeasuredHeight() + (getMeasuredWidth() << 16); if (lastSize != currentSize || !wasLayout || forcedLayout) { layoutWidth = getMeasuredWidth(); layoutHeight = getMeasuredHeight() - substractBackgroundHeight - getPaddingTop() - getPaddingBottom() - additionalPaddingHeight; if (timeTextWidth < 0) { timeTextWidth = dp(10); } if (currentTimeString != null) { timeLayout = new StaticLayout(currentTimeString, Theme.chat_timePaint, timeTextWidth + dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else { timeLayout = null; } if (mediaBackground) { if (currentMessageObject.isOutOwner()) { timeX = layoutWidth - timeWidth - dp(42.0f); } else { timeX = backgroundWidth - dp(4) - timeWidth; if (currentMessageObject.isAnyKindOfSticker()) { timeX = Math.max(dp(26), timeX); } if (isSideMenuLeftMargin()) { timeX += dp(ChatActivity.SIDE_MENU_WIDTH); } else if (isAvatarVisible && !isWidthAdaptive()) { timeX += dp(48); } if (currentPosition != null && currentPosition.leftSpanOffset != 0) { timeX += (int) Math.ceil(currentPosition.leftSpanOffset / 1000.0f * getGroupPhotosWidth()); } if (captionLayout != null && currentPosition != null) { timeX += dp(4); } } if (SharedConfig.bubbleRadius >= 10 && captionLayout == null && documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER) { timeX -= dp(2); } } else { if (currentMessageObject.isOutOwner()) { timeX = layoutWidth - timeWidth - dp(38.5f); } else { timeX = backgroundWidth - dp(9) - timeWidth; if (currentMessageObject.isAnyKindOfSticker()) { timeX = Math.max(0, timeX); } if (isSideMenuLeftMargin()) { timeX += dp(ChatActivity.SIDE_MENU_WIDTH); } else if (isAvatarVisible && !isWidthAdaptive()) { timeX += dp(48); } if (shouldDrawTimeOnMedia()) { timeX -= dp(7); } } } timeX -= getExtraTimeX(); if (effectId != 0) { timeX += dp(14 + 4); } final boolean isInWelcomeMessages = delegate != null && delegate.getChatMode() == ChatActivity.MODE_WELCOME_MESSAGES; if ((currentMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0 && !isInWelcomeMessages) { viewsLayout = new StaticLayout(currentViewsString == null ? "" : currentViewsString, Theme.chat_timePaint, viewsTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else { viewsLayout = null; } if (currentRepliesString != null && !currentMessageObject.scheduled) { repliesLayout = new StaticLayout(currentRepliesString, Theme.chat_timePaint, repliesTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else { repliesLayout = null; } if (isAvatarVisible) { avatarImage.setImageCoords(dp(currentMessageObject.isRepostPreview ? 15 : 6), avatarImage.getImageY(), dp(currentMessageObject.isRepostPreview ? 36 : 42), dp(currentMessageObject.isRepostPreview ? 36 : 42)); } if (currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW && currentUnlockString != null) { unlockLayout = new StaticLayout(currentUnlockString, Theme.chat_unlockExtendedMediaTextPaint, unlockTextWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); TLRPC.TL_messageExtendedMediaPreview preview = (TLRPC.TL_messageExtendedMediaPreview) currentMessageObject.messageOwner.media.extended_media.get(0); if (preview.video_duration != 0) { String str = AndroidUtilities.formatDuration(preview.video_duration, false); durationWidth = (int) Math.ceil(Theme.chat_durationPaint.measureText(str)); videoInfoLayout = new StaticLayout(str, Theme.chat_durationPaint, durationWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } else { videoInfoLayout = null; } } else { unlockLayout = null; } wasLayout = true; forcedLayout = false; } lastSize = currentSize; if (currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_ARTICLE) { textY = dp(10) + namesOffset; if (currentMessageObject.isSponsored()) { linkPreviewY = textY + dp(14); } else if (linkPreviewAbove) { linkPreviewY = textY + dp(10); textY += linkPreviewHeight + dp(13); if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { textY += dp(44); } } else { linkPreviewY = textY + currentMessageObject.textHeight(transitionParams) + dp(10); } factCheckY = linkPreviewAbove ? textY + currentMessageObject.textHeight(transitionParams) + dp(10) : linkPreviewY + linkPreviewHeight + dp(drawInstantView ? 46 : 0) + dp(linkPreviewHeight > 0 ? 4 : -8); } if (groupMedia != null) { int x; if (currentMessageObject.isOutOwner()) { if (mediaBackground) { x = layoutWidth - backgroundWidth - dp(3); } else { x = layoutWidth - backgroundWidth + dp(6); } } else { x = dp(15); if (isSideMenuLeftMargin()) { x += dp(ChatActivity.SIDE_MENU_WIDTH); } else if ((isChat || currentMessageObject.isRepostPreview) && isAvatarVisible && !isPlayingRound) { x += dp(48); } } x -= dp(2); groupMedia.x = x; } if (isRoundVideo) { updatePlayingMessageProgress(); } if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { if (currentMessageObject.isOutOwner()) { seekBarX = layoutWidth - backgroundWidth + dp(57); buttonX = layoutWidth - backgroundWidth + dp(14); timeAudioX = layoutWidth - backgroundWidth + dp(67); } else { seekBarX = dp(66); buttonX = dp(23); timeAudioX = dp(76); if (isSideMenuLeftMargin()) { seekBarX += dp(ChatActivity.SIDE_MENU_WIDTH); buttonX += dp(ChatActivity.SIDE_MENU_WIDTH); timeAudioX += dp(ChatActivity.SIDE_MENU_WIDTH); } else if (needDrawAvatar()) { seekBarX += dp(48); buttonX += dp(48); timeAudioX += dp(48); } } if (hasLinkPreview) { seekBarX += dp(10); buttonX += dp(10); timeAudioX += dp(10); } updateSeekBarWaveformWidth(null); seekBarY = dp(13) + namesOffset + mediaOffsetY + (captionAbove && captionLayout != null ? captionLayout.textHeight(transitionParams) : 0); buttonY = dp(13) + namesOffset + mediaOffsetY + (captionAbove && captionLayout != null ? captionLayout.textHeight(transitionParams) : 0); radialProgress.setProgressRect(buttonX, buttonY, buttonX + dp(44), buttonY + dp(44)); updatePlayingMessageProgress(); if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { int x; if (currentMessageObject.type == MessageObject.TYPE_TEXT && (hasLinkPreview || hasGamePreview || hasInvoicePreview)) { int linkX; if (hasGamePreview) { linkX = unmovedTextX - dp(10); } else if (hasInvoicePreview) { linkX = unmovedTextX + dp(1); } else { linkX = unmovedTextX + dp(1); } if (isSmallImage) { x = linkX + backgroundWidth - dp(81); } else { x = linkX + (hasInvoicePreview ? -dp(6.3f) : dp(10)); } } else { if (currentMessageObject.isOutOwner()) { if (mediaBackground) { x = layoutWidth - backgroundWidth - dp(3); } else { x = layoutWidth - backgroundWidth + dp(6); } } else { x = dp(15); if (isSideMenuLeftMargin()) { x += dp(ChatActivity.SIDE_MENU_WIDTH); } else if ((isChat || currentMessageObject != null && (currentMessageObject.forceAvatar || currentMessageObject.messageOwner.guestchat_via_from != null) || currentMessageObject.getDialogId() == UserObject.VERIFY) && isAvatarVisible && (!isPlayingRound || currentMessageObject.isVoiceTranscriptionOpen())) { x += dp(48); } if (currentPosition != null && !currentPosition.edge) { x -= dp(10); } } } if (currentPosition != null) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { x -= dp(2); } if (currentPosition.leftSpanOffset != 0) { x += (int) Math.ceil(currentPosition.leftSpanOffset / 1000.0f * getGroupPhotosWidth()); } } if (currentMessageObject.type != MessageObject.TYPE_TEXT) { x -= dp(2); } if (currentMessageObject.isVoiceTranscriptionOpen()) { x += dp(10); } if (!transitionParams.imageChangeBoundsTransition || transitionParams.updatePhotoImageX) { transitionParams.updatePhotoImageX = false; photoImage.setImageCoords(x, currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO ? linkPreviewY : photoImage.getImageY(), photoImage.getImageWidth(), photoImage.getImageHeight()); } } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { if (currentMessageObject.isOutOwner()) { seekBarX = layoutWidth - backgroundWidth + dp(56); buttonX = layoutWidth - backgroundWidth + dp(14); timeAudioX = layoutWidth - backgroundWidth + dp(67); } else { seekBarX = dp(65); buttonX = dp(23); timeAudioX = dp(76); if (isSideMenuLeftMargin()) { seekBarX += dp(ChatActivity.SIDE_MENU_WIDTH); buttonX += dp(ChatActivity.SIDE_MENU_WIDTH); timeAudioX += dp(ChatActivity.SIDE_MENU_WIDTH); } else if (needDrawAvatar()) { seekBarX += dp(48); buttonX += dp(48); timeAudioX += dp(48); } } if (hasLinkPreview) { seekBarX += dp(10); buttonX += dp(10); timeAudioX += dp(10); } updateSeekBarWaveformWidth(null); seekBarY = dp(29) + namesOffset + mediaOffsetY + (captionAbove && captionLayout != null ? captionLayout.textHeight(transitionParams) : 0); buttonY = dp(13) + namesOffset + mediaOffsetY + (captionAbove && captionLayout != null ? captionLayout.textHeight(transitionParams) : 0); radialProgress.setProgressRect(buttonX, buttonY, buttonX + dp(44), buttonY + dp(44)); updatePlayingMessageProgress(); } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT && !drawPhotoImage) { if (currentMessageObject.isOutOwner()) { buttonX = layoutWidth - backgroundWidth + dp(14); } else { if (isSideMenuLeftMargin()) { buttonX = dp(23 + ChatActivity.SIDE_MENU_WIDTH); } else if (needDrawAvatar()) { buttonX = dp(23 + 48); } else { buttonX = dp(23); } } if (hasLinkPreview) { buttonX += dp(10); } buttonY = dp(13) + namesOffset + mediaOffsetY + (captionAbove && captionLayout != null ? captionLayout.textHeight(transitionParams) : 0); radialProgress.setProgressRect(buttonX, buttonY, buttonX + dp(44), buttonY + dp(44)); photoImage.setImageCoords(buttonX - dp(10), buttonY - dp(10), photoImage.getImageWidth(), photoImage.getImageHeight()); } else if (currentMessageObject.type == MessageObject.TYPE_CONTACT) { int x; if (currentMessageObject.isOutOwner()) { x = layoutWidth - backgroundWidth + dp(26); } else { x = dp(35); if (isSideMenuLeftMargin()) { x += dp(ChatActivity.SIDE_MENU_WIDTH); } else if (needDrawAvatar()) { x += dp(48); } } photoImage.setImageCoords(x, dp(24) + namesOffset, dp(46), dp(46)); } else { int x; if (currentMessageObject.type == MessageObject.TYPE_TEXT && (hasLinkPreview || hasGamePreview || hasInvoicePreview)) { int linkX; if (hasGamePreview) { linkX = unmovedTextX - dp(10); } else if (hasInvoicePreview) { linkX = unmovedTextX + dp(1); } else { linkX = unmovedTextX + dp(1); } if (isSmallImage) { x = linkX + backgroundWidth - dp(81); } else { x = linkX + (hasInvoicePreview ? -dp(6.3f) : dp(10)); } } else { if (currentMessageObject.isOutOwner()) { if (mediaBackground) { x = layoutWidth - backgroundWidth - dp(3); } else { x = layoutWidth - backgroundWidth + dp(6); } } else { x = dp(15); if (isSideMenuLeftMargin()) { x += dp(ChatActivity.SIDE_MENU_WIDTH); } else if ((isChat || currentMessageObject.isRepostPreview || currentMessageObject.messageOwner.guestchat_via_from != null) && isAvatarVisible && !isPlayingRound) { x += dp(48); } if (currentPosition != null && !currentPosition.edge) { x -= dp(10); } } } if (currentPosition != null) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { x -= dp(2); } if (currentPosition.leftSpanOffset != 0) { x += (int) Math.ceil(currentPosition.leftSpanOffset / 1000.0f * getGroupPhotosWidth()); } } if (currentMessageObject.type != MessageObject.TYPE_TEXT) { x -= dp(2); } if (drawInstantViewType == 17) { x += dp(10) + (instantWidth - photoImage.getImageWidth()) / 2; } if (!transitionParams.imageChangeBoundsTransition || transitionParams.updatePhotoImageX) { transitionParams.updatePhotoImageX = false; photoImage.setImageCoords((float) x, photoImage.getImageY(), photoImage.getImageWidth(), photoImage.getImageHeight()); } buttonX = (int) (x + (photoImage.getImageWidth() - dp(48)) / 2.0f); buttonY = (int) (photoImage.getImageY() + (photoImage.getImageHeight() - dp(48)) / 2); radialProgress.setProgressRect(buttonX, buttonY, buttonX + dp(48), buttonY + dp(48)); deleteProgressRect.set(buttonX + dp(5), buttonY + dp(5), buttonX + dp(43), buttonY + dp(43)); if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { videoButtonX = (int) (photoImage.getImageX() + dp(8)); videoButtonY = (int) (photoImage.getImageY() + dp(8)); videoRadialProgress.setProgressRect(videoButtonX, videoButtonY, videoButtonX + dp(24), videoButtonY + dp(24)); } } } public boolean needDelayRoundProgressDraw() { return (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) && currentMessageObject != null && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO && MediaController.getInstance().isPlayingMessage(currentMessageObject); } public void drawRoundProgress(Canvas canvas) { float inset = isPlayingRound ? dp(4) : 0; boolean drawPause = MediaController.getInstance().isPlayingMessage(currentMessageObject) && MediaController.getInstance().isMessagePaused(); boolean drawTouchedSeekbar = drawPause && roundSeekbarTouched == 1; if (drawPause && roundToPauseProgress != 1f) { roundToPauseProgress += 16 / 220f; if (roundToPauseProgress > 1f) { roundToPauseProgress = 1f; } else { invalidate(); } } else if (!drawPause && roundToPauseProgress != 0f) { roundToPauseProgress -= 16 / 150f; if (roundToPauseProgress < 0) { roundToPauseProgress = 0f; } else { invalidate(); } } if (drawTouchedSeekbar && roundToPauseProgress2 != 1f) { roundToPauseProgress2 += 16 / 150f; if (roundToPauseProgress2 > 1f) { roundToPauseProgress2 = 1f; } else { invalidate(); } } else if (!drawTouchedSeekbar && roundToPauseProgress2 != 0f) { roundToPauseProgress2 -= 16 / 150f; if (roundToPauseProgress2 < 0) { roundToPauseProgress2 = 0f; } else { invalidate(); } } float pauseProgress = drawPause ? AndroidUtilities.overshootInterpolator.getInterpolation(roundToPauseProgress) : roundToPauseProgress; if (transitionParams.animatePlayingRound) { inset = (isPlayingRound ? transitionParams.animateChangeProgress : (1f - transitionParams.animateChangeProgress)) * dp(4); } inset += dp(16) * pauseProgress; if (roundToPauseProgress > 0) { float r = photoImage.getImageWidth() / 2f; Theme.getRadialSeekbarShadowDrawable().draw(canvas, photoImage.getCenterX(), photoImage.getCenterY(), r, roundToPauseProgress); } rect.set(photoImage.getImageX() + AndroidUtilities.dpf2(1.5f) + inset, photoImage.getImageY() + AndroidUtilities.dpf2(1.5f) + inset, photoImage.getImageX2() - AndroidUtilities.dpf2(1.5f) - inset, photoImage.getImageY2() - AndroidUtilities.dpf2(1.5f) - inset); int oldAplha = -1; if (roundProgressAlpha != 1f || !hasLinkPreview && getVideoTranscriptionProgress() > 0) { oldAplha = Theme.chat_radialProgressPaint.getAlpha(); Theme.chat_radialProgressPaint.setAlpha((int) (roundProgressAlpha * (!hasLinkPreview ? 1f - getVideoTranscriptionProgress() : 1f) * oldAplha)); } if (videoForwardDrawable != null && videoForwardDrawable.isAnimating()) { videoForwardDrawable.setBounds((int) photoImage.getImageX(), (int) photoImage.getImageY(), (int) (photoImage.getImageX() + photoImage.getImageWidth()), (int) (photoImage.getImageY() + photoImage.getImageHeight())); videoForwardDrawable.draw(canvas); } int paintAlpha = Theme.chat_radialProgressPaint.getAlpha(); float paintWidth = Theme.chat_radialProgressPaint.getStrokeWidth(); float audioProgress = roundProgressAlpha == 1f ? currentMessageObject.audioProgress : lastDrawingAudioProgress; if (pauseProgress > 0) { float radius = rect.width() / 2f; Theme.chat_radialProgressPaint.setStrokeWidth(paintWidth + paintWidth * 0.5f * roundToPauseProgress); Theme.chat_radialProgressPaint.setAlpha((int) (paintAlpha * roundToPauseProgress * 0.3f)); canvas.drawCircle(rect.centerX(), rect.centerY(), radius, Theme.chat_radialProgressPaint); Theme.chat_radialProgressPaint.setAlpha(paintAlpha); seekbarRoundX = (float) (rect.centerX() + Math.sin(Math.toRadians(-360 * audioProgress + 180)) * radius); seekbarRoundY = (float) (rect.centerY() + Math.cos(Math.toRadians(-360 * audioProgress + 180)) * radius); Theme.chat_radialProgressPausedSeekbarPaint.setColor(Color.WHITE); Theme.chat_radialProgressPausedSeekbarPaint.setAlpha((int) (255 * Math.min(1f, pauseProgress) * (!hasLinkPreview ? 1f - getVideoTranscriptionProgress() : 1))); canvas.drawCircle(seekbarRoundX, seekbarRoundY, dp(3) + dp(5) * pauseProgress + dp(3) * roundToPauseProgress2, Theme.chat_radialProgressPausedSeekbarPaint); } if (roundSeekbarOutAlpha != 0f) { roundSeekbarOutAlpha -= 16f / 150f; if (roundSeekbarOutAlpha < 0) { roundSeekbarOutAlpha = 0f; } else { invalidate(); } } if (roundSeekbarOutAlpha != 0f) { if (oldAplha == -1) { oldAplha = Theme.chat_radialProgressPaint.getAlpha(); } Theme.chat_radialProgressPaint.setAlpha((int) (paintAlpha * (1f - roundSeekbarOutAlpha))); canvas.drawArc(rect, -90, 360 * audioProgress, false, Theme.chat_radialProgressPaint); Theme.chat_radialProgressPaint.setAlpha((int) (paintAlpha * roundSeekbarOutAlpha)); canvas.drawArc(rect, -90, 360 * roundSeekbarOutProgress, false, Theme.chat_radialProgressPaint); } else { canvas.drawArc(rect, -90, 360 * audioProgress, false, Theme.chat_radialProgressPaint); } if (oldAplha != -1) { Theme.chat_radialProgressPaint.setAlpha(oldAplha); } Theme.chat_radialProgressPaint.setStrokeWidth(paintWidth); } private void updatePollAnimations(long dt) { if (pollVoteInProgress) { voteRadOffset += 360 * dt / 2000.0f; int count = (int) (voteRadOffset / 360); voteRadOffset -= count * 360; voteCurrentProgressTime += dt; if (voteCurrentProgressTime >= 500.0f) { voteCurrentProgressTime = 500.0f; } if (voteRisingCircleLength) { voteCurrentCircleLength = 4 + 266 * AndroidUtilities.accelerateInterpolator.getInterpolation(voteCurrentProgressTime / 500.0f); } else { voteCurrentCircleLength = 4 - (firstCircleLength ? 360 : 270) * (1.0f - AndroidUtilities.decelerateInterpolator.getInterpolation(voteCurrentProgressTime / 500.0f)); } if (voteCurrentProgressTime == 500.0f) { if (voteRisingCircleLength) { voteRadOffset += 270; voteCurrentCircleLength = -266; } voteRisingCircleLength = !voteRisingCircleLength; if (firstCircleLength) { firstCircleLength = false; } voteCurrentProgressTime = 0; } invalidate(); } final boolean showHintButton = hintButtonVisible && (currentMessageObject == null || !currentMessageObject.expandedExplanation); if (showHintButton && hintButtonProgress < 1.0f) { hintButtonProgress += dt / 180.0f; if (hintButtonProgress > 1.0f) { hintButtonProgress = 1.0f; } invalidate(); } else if (!showHintButton && hintButtonProgress > 0.0f) { hintButtonProgress -= dt / 180.0f; if (hintButtonProgress < 0.0f) { hintButtonProgress = 0.0f; } invalidate(); } if (animatePollAnswer) { pollAnimationProgressTime += dt; if (pollAnimationProgressTime >= 300.0f) { pollAnimationProgressTime = 300.0f; } pollAnimationProgress = AndroidUtilities.decelerateInterpolator.getInterpolation(pollAnimationProgressTime / 300.0f); if (pollAnimationProgress >= 1.0f) { pollAnimationProgress = 1.0f; animatePollAnswer = false; animatePollAnswerAlpha = false; pollVoteInProgress = false; if (pollUnvoteInProgress && animatePollAvatars) { if (pollRecentVotersDrawable != null) { pollRecentVotersDrawable.set(null, false); } } pollUnvoteInProgress = false; for (int a = 0, N = pollButtons.size(); a < N; a++) { PollButton button = pollButtons.get(a); button.prevChosen = false; } } invalidate(); } } public void drawContent(Canvas canvas, boolean preview) { if (preview != (currentMessageObject != null && currentMessageObject.preview)) { return; } boolean newPart = needNewVisiblePart && currentMessageObject.type == MessageObject.TYPE_TEXT, hasSpoilers = hasSpoilers(); if (newPart || hasSpoilers) { getLocalVisibleRect(scrollRect); if (hasSpoilers) { updateSpoilersVisiblePart(scrollRect.top, scrollRect.bottom); } if (newPart) { setVisiblePart(scrollRect.top, scrollRect.bottom - scrollRect.top, parentHeight, parentViewTopOffset, viewTop, parentWidth, backgroundHeight, blurredViewTopOffset, blurredViewBottomOffset, 0); needNewVisiblePart = false; } } float buttonX = this.buttonX; float buttonY = this.buttonY; if (transitionParams.animateButton) { buttonX = AndroidUtilities.lerp(transitionParams.animateFromButtonX, this.buttonX, transitionParams.animateChangeProgress); buttonY = AndroidUtilities.lerp(transitionParams.animateFromButtonY, this.buttonY, transitionParams.animateChangeProgress); radialProgress.setProgressRect((int) buttonX, (int) buttonY, (int) buttonX + dp(44), (int) buttonY + dp(44)); } updateSeekBarWaveformWidth(canvas); forceNotDrawTime = currentMessagesGroup != null || delegate != null && delegate.getChatMode() == ChatActivity.MODE_WELCOME_MESSAGES; photoImage.setPressed((isHighlightedAnimated || isHighlighted) && currentPosition != null ? 2 : 0); photoImage.setVisible(!PhotoViewer.isShowingImage(currentMessageObject) && !SecretMediaViewer.getInstance().isShowingImage(currentMessageObject) && !StoryViewer.isShowingImage(currentMessageObject), false); blurredPhotoImage.setVisible(fitPhotoImage || !PhotoViewer.isShowingImage(currentMessageObject) && !SecretMediaViewer.getInstance().isShowingImage(currentMessageObject) && !StoryViewer.isShowingImage(currentMessageObject), false); if (groupMedia != null ? !groupMedia.allVisible() : !photoImage.getVisible()) { mediaWasInvisible = true; timeWasInvisible = true; if (animatingNoSound == 1) { animatingNoSoundProgress = 0.0f; animatingNoSound = 0; } else if (animatingNoSound == 2) { animatingNoSoundProgress = 1.0f; animatingNoSound = 0; } } else if (groupPhotoInvisible) { timeWasInvisible = true; } else if (mediaWasInvisible || timeWasInvisible) { if (mediaWasInvisible) { controlsAlpha = 0.0f; mediaWasInvisible = false; } if (timeWasInvisible) { timeAlpha = 0.0f; timeWasInvisible = false; } lastControlsAlphaChangeTime = System.currentTimeMillis(); totalChangeTime = 0; } radialProgress.setProgressColor(getThemedColor(Theme.key_chat_mediaProgress)); videoRadialProgress.setProgressColor(getThemedColor(Theme.key_chat_mediaProgress)); imageDrawn = false; radialProgress.setCircleCrossfadeColor(-1, 0.0f, 1.0f); if (groupMedia != null) { drawTime = groupMedia.allVisible(); groupMedia.draw(canvas); } else if (currentMessageObject.type == MessageObject.TYPE_ARTICLE) { layoutTextXY(false); final int left = getCurrentBackgroundLeft() + dp(!currentMessageObject.isOutOwner() && !drawPinnedBottom ? 8 : 2); final int right = getCurrentBackgroundRight() + dp(currentMessageObject.isOutOwner() && !drawPinnedBottom ? -7 : -2); float alpha = 1.0f; if (transitionParams.animateRichLayout && transitionParams.animateOutRichLayout != null) { transitionParams.updateCrossfadeProgress(); final RichMessageLayout layout = transitionParams.animateOutRichLayout; layout.attach(this); layout.checkQuoteLine(currentUser, currentChat); final int padLeft = Math.max(0, textX - left); final int padRight = Math.max(0, right - (textX + layout.getMinWidth())); canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * transitionParams.oldProgress), Canvas.ALL_SAVE_FLAG); canvas.translate(textX, textY); layout.draw(canvas, padLeft, padRight, null); canvas.restore(); alpha = transitionParams.newProgress; } if (currentMessageObject.richLayout != null) { final RichMessageLayout layout = currentMessageObject.richLayout; layout.attach(this); layout.checkQuoteLine(currentUser, currentChat); layout.setChatMessageCellDelegate(this, this.delegate); final int padLeft = Math.max(0, textX - left); final int padRight = Math.max(0, right - (textX + layout.getMinWidth())); if (alpha < 1) { canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); } else { canvas.save(); } canvas.translate(textX, textY); if (delegate != null && delegate.getTextSelectionHelper() != null) { delegate.getTextSelectionHelper().drawRich(currentMessageObject, layout, canvas); } layout.draw(canvas, padLeft, padRight, transitionParams); canvas.restore(); if (botDraftTypingAnimator != null && botDraftTypingAnimator.isRunning()) { invalidate(); invalidateOutbounds(); } if (currentMessageObject.isBotPendingDraft) { invalidate(); } } } else if (currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_STORY_MENTION || currentMessageObject.type == MessageObject.TYPE_EMOJIS || currentMessageObject.isGiveawayOrGiveawayResults()) { layoutTextXY(false); if (!enterTransitionInProgress && currentMessageObject != null && !currentMessageObject.preview) { if (!transitionParams.animateExpandedQuotes || delegate == null || delegate.canDrawOutboundsContent()) { if (!drawForBlur && !(canvas instanceof SizeNotifierFrameLayout.SimplerCanvas) && animatedEmojiStack != null && ((currentMessageObject.textLayoutBlocks != null && !currentMessageObject.textLayoutBlocks.isEmpty()) || (transitionParams.animateOutTextBlocks != null && !transitionParams.animateOutTextBlocks.isEmpty()))) { animatedEmojiStack.clearPositions(); } drawMessageText(canvas); } } if (!(enterTransitionInProgress && !currentMessageObject.isVoice())) { drawLinkPreview(canvas, 1f); getIconForCurrentState(); // sets colors } drawTime = true; } else if (drawPhotoImage) { float pipFloat = roundVideoPlayPipFloat.get(); if (pipFloat > 0) { if (drillHolePaint == null) { drillHolePaint = new Paint(Paint.ANTI_ALIAS_FLAG); } drillHolePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLoader : Theme.key_chat_inLoader)); drillHolePaint.setAlpha((int) (drillHolePaint.getAlpha() * getVideoTranscriptionProgress())); canvas.drawCircle(photoImage.getCenterX(), photoImage.getCenterY(), photoImage.getImageWidth() / 2f, drillHolePaint); } if (isRoundVideo && ( MediaController.getInstance().isPlayingMessage(currentMessageObject) && MediaController.getInstance().isVideoDrawingReady() && canvas.isHardwareAccelerated() && (currentMessageObject == null || !currentMessageObject.isVoiceTranscriptionOpen() || pipFloat >= 1) )) { imageDrawn = true; drawTime = true; } else { if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO && Theme.chat_roundVideoShadow != null) { float x = photoImage.getImageX() - dp(3); float y = photoImage.getImageY() - dp(2); int wasAlpha = 255; // Theme.chat_roundVideoShadow.getAlpha(); Theme.chat_roundVideoShadow.setAlpha((int) (255 * (1f - getVideoTranscriptionProgress()))); Theme.chat_roundVideoShadow.setBounds((int) x, (int) y, (int) (x + photoImage.getImageWidth() + dp(6)), (int) (y + photoImage.getImageHeight() + dp(6))); Theme.chat_roundVideoShadow.draw(canvas); Theme.chat_roundVideoShadow.setAlpha(wasAlpha); if (!photoImage.hasBitmapImage() || photoImage.getCurrentAlpha() != 1) { Theme.chat_docBackPaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outBubble : Theme.key_chat_inBubble)); canvas.drawCircle(photoImage.getCenterX(), photoImage.getCenterY(), photoImage.getImageWidth() / 2, Theme.chat_docBackPaint); } } drawMediaCheckBox = mediaCheckBox != null && (checkBoxVisible || mediaCheckBox.getProgress() != 0 || checkBoxAnimationInProgress) && currentMessagesGroup != null; if (drawMediaCheckBox && (mediaCheckBox.isChecked() || mediaCheckBox.getProgress() != 0 || checkBoxAnimationInProgress) && (!textIsSelectionMode())) { if (!currentMessagesGroup.isDocuments) { Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outBubbleSelected : Theme.key_chat_inBubbleSelected)); rect.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); int[] rad = photoImage.getRoundRadius(); rectPath.reset(); for (int a = 0; a < rad.length; a++) { radii[a * 2] = radii[a * 2 + 1] = rad[a]; } rectPath.addRoundRect(rect, radii, Path.Direction.CW); rectPath.close(); canvas.drawPath(rectPath, Theme.chat_replyLinePaint); } photoImage.setSideClip(dp(14) * mediaCheckBox.getProgress()); if (checkBoxAnimationInProgress) { mediaCheckBox.setBackgroundAlpha(checkBoxAnimationProgress); } else { mediaCheckBox.setBackgroundAlpha(checkBoxVisible ? 1.0f : mediaCheckBox.getProgress()); } } else { photoImage.setSideClip(0); } if (isRoundVideo && currentMessageObject.isVoiceTranscriptionOpen() && pipFloat > 0) { canvas.save(); if (drillHolePath == null) { drillHolePath = new Path(); } else { drillHolePath.rewind(); } drillHolePath.addCircle(photoImage.getCenterX(), photoImage.getCenterY(), photoImage.getImageWidth() / 2f * (1f - pipFloat), Path.Direction.CW); canvas.clipPath(drillHolePath); } final boolean pinchToZoomDrawing = delegate != null && delegate.getPinchToZoomHelper() != null && delegate.getPinchToZoomHelper().isInOverlayModeFor(this); if (!pinchToZoomDrawing || fitPhotoImage) { float top = getY() + getPaddingTop() + photoImage.getImageY(); float bottom = top + photoImage.getImageHeight(); photoImageOutOfBounds = false; // if (!SizeNotifierFrameLayout.drawingBlur && (parentBoundsTop != 0 || parentBoundsBottom != 0) && (bottom < parentBoundsTop || top > parentBoundsBottom)) { // photoImageOutOfBounds = true; // } if (!photoImageOutOfBounds || drawForBlur) { photoImage.setSkipUpdateFrame(drawForBlur || skipFrameUpdate); if (flipImage) { canvas.save(); canvas.scale(-1f, 1, photoImage.getCenterX(), photoImage.getCenterY()); if (blurredPhotoImage != null && fitPhotoImage) { blurredPhotoImage.setImageCoords(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageWidth(), photoImage.getImageHeight()); blurredPhotoImage.setRoundRadius(photoImage.getRoundRadius()); blurredPhotoImage.draw(canvas); } if (!pinchToZoomDrawing) { if (allowDrawPhotoImage()) { imageDrawn = drawPhotoImage(canvas); } else { imageDrawn = true; } if (currentMessageObject.hasMediaSpoilers()) { drawBlurredPhoto(canvas); } } canvas.restore(); } else { if (blurredPhotoImage != null && fitPhotoImage) { blurredPhotoImage.setImageCoords(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageWidth(), photoImage.getImageHeight()); blurredPhotoImage.setRoundRadius(photoImage.getRoundRadius()); blurredPhotoImage.draw(canvas); } if (!pinchToZoomDrawing) { if (allowDrawPhotoImage()) { boolean needRestore = false; if (contactBounce != null) { float contactScale = contactBounce.getScale(0.0125f); if (contactScale != 1f) { needRestore = true; canvas.save(); canvas.scale(contactScale, contactScale, contactRect.centerX(), contactRect.centerY()); } } imageDrawn = drawPhotoImage(canvas); if (needRestore) { canvas.restore(); } } else { imageDrawn = true; } if (currentMessageObject.hasMediaSpoilers()) { drawBlurredPhoto(canvas); } } } photoImage.setSkipUpdateFrame(skipFrameUpdate); } } if (isRoundVideo && currentMessageObject.isVoiceTranscriptionOpen() && pipFloat > 0) { canvas.restore(); } if (!isRoundVideo) { drawVideoTimestamps(canvas, getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outReplyLine : Theme.key_chat_inReplyLine)); } boolean drawTimeOld = drawTime; boolean groupPhotoVisible = photoImage.getVisible(); drawTime = groupPhotoVisible || currentMessageObject.shouldDrawReactionsInLayout() && currentMessageObject.hasReactions(); if (currentPosition != null && drawTimeOld != drawTime) { ViewGroup viewGroup = (ViewGroup) getParent(); if (viewGroup != null) { if (!currentPosition.last) { int count = viewGroup.getChildCount(); for (int a = 0; a < count; a++) { View child = viewGroup.getChildAt(a); if (child == this || !(child instanceof ChatMessageCell)) { continue; } ChatMessageCell cell = (ChatMessageCell) child; if (cell.getCurrentMessagesGroup() == currentMessagesGroup) { MessageObject.GroupedMessagePosition position = cell.getCurrentPosition(); if (position.last && position.maxY == currentPosition.maxY && cell.timeX - dp(4) + cell.getLeft() < getRight()) { cell.groupPhotoInvisible = !groupPhotoVisible; cell.invalidate(); viewGroup.invalidate(); } } } } else { viewGroup.invalidate(); } } } } } else { if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { drawMediaCheckBox = mediaCheckBox != null && (checkBoxVisible || mediaCheckBox.getProgress() != 0 || checkBoxAnimationInProgress) && currentMessagesGroup != null; if (drawMediaCheckBox) { radialProgress.setCircleCrossfadeColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeText : Theme.key_chat_inTimeText, checkBoxAnimationProgress, 1.0f - mediaCheckBox.getProgress()); } if (drawMediaCheckBox && !textIsSelectionMode() && (mediaCheckBox.isChecked() || mediaCheckBox.getProgress() != 0 || checkBoxAnimationInProgress)) { if (checkBoxAnimationInProgress) { mediaCheckBox.setBackgroundAlpha(checkBoxAnimationProgress); if (radialProgress.getMiniIcon() == MediaActionDrawable.ICON_NONE) { radialProgress.setMiniIconScale(checkBoxAnimationProgress); } } else { mediaCheckBox.setBackgroundAlpha(checkBoxVisible ? 1.0f : mediaCheckBox.getProgress()); } } else if (mediaCheckBox != null) { mediaCheckBox.setBackgroundAlpha(1.0f); } } } if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { if (drawPhotoImage && !currentMessageObject.isRepostPreview && !currentMessageObject.isSponsored() && photoImage.getVisible() && !hasGamePreview && !currentMessageObject.needDrawBluredPreview() && !currentMessageObject.preview && !isSmallImage && !currentMessageObject.isSponsored()) { int oldAlpha = ((BitmapDrawable) Theme.chat_msgMediaMenuDrawable).getPaint().getAlpha(); Theme.chat_msgMediaMenuDrawable.setAlpha((int) (oldAlpha * controlsAlpha)); setDrawableBounds(Theme.chat_msgMediaMenuDrawable, otherX = (int) (photoImage.getImageX() + photoImage.getImageWidth() - dp(14)), otherY = (int) (photoImage.getImageY() + dp(8.1f))); Theme.chat_msgMediaMenuDrawable.draw(canvas); Theme.chat_msgMediaMenuDrawable.setAlpha(oldAlpha); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { if (currentMessageObject.isOutOwner()) { Theme.chat_audioTitlePaint.setColor(getThemedColor(Theme.key_chat_outAudioTitleText)); Theme.chat_audioPerformerPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outAudioPerformerSelectedText : Theme.key_chat_outAudioPerformerText)); Theme.chat_audioTimePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outAudioDurationSelectedText : Theme.key_chat_outAudioDurationText)); radialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() || buttonPressed != 0 ? Theme.key_chat_outAudioSelectedProgress : Theme.key_chat_outAudioProgress)); } else if (linkLine != null && hasLinkPreview) { Theme.chat_audioTitlePaint.setColor(linkLine.getColor()); Theme.chat_audioPerformerPaint.setColor(Theme.adaptHue(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inAudioPerformerSelectedText : Theme.key_chat_inAudioPerformerText), linkLine.getColor())); Theme.chat_audioTimePaint.setColor(Theme.adaptHue(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inAudioDurationSelectedText : Theme.key_chat_inAudioDurationText), linkLine.getColor())); radialProgress.setProgressColor(Theme.adaptHue(getThemedColor(isDrawSelectionBackground() || buttonPressed != 0 ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress), linkLine.getColor())); seekBar.setColors(Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbar), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioCacheSeekbar), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarFill), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarFill), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarSelected), linkLine.getColor())); } else { Theme.chat_audioTitlePaint.setColor(getThemedColor(Theme.key_chat_inAudioTitleText)); Theme.chat_audioPerformerPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inAudioPerformerSelectedText : Theme.key_chat_inAudioPerformerText)); Theme.chat_audioTimePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inAudioDurationSelectedText : Theme.key_chat_inAudioDurationText)); radialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() || buttonPressed != 0 ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress)); } float tx = 0; if (transitionParams.animateBackgroundBoundsInner) { tx = transitionParams.deltaLeft; } radialProgress.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); radialProgress.iconScale = 1f; if (drawPhotoImage && currentMessageObject != null && currentMessageObject.hasMediaSpoilers() && currentMessageObject.isSensitive() && (!currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0 && mediaSpoilerRevealProgress < 1)) { radialProgress.iconScale *= mediaSpoilerRevealProgress; } radialProgress.draw(canvas); canvas.save(); canvas.translate(tx + timeAudioX + songX, dp(13) + namesOffset + getMediaOffsetY()); songLayout.draw(canvas); canvas.restore(); boolean showSeekbar = MediaController.getInstance().isPlayingMessage(currentMessageObject); if (showSeekbar && toSeekBarProgress != 1f) { toSeekBarProgress += 16f / 100f; if (toSeekBarProgress > 1f) { toSeekBarProgress = 1f; } invalidate(); } else if (!showSeekbar && toSeekBarProgress != 0) { toSeekBarProgress -= 16f / 100f; if (toSeekBarProgress < 0) { toSeekBarProgress = 0; } invalidate(); } if (toSeekBarProgress > 0) { float y = seekBarY; if (transitionParams.animateBackgroundBoundsInner) { y += transitionParams.deltaTop; } if (toSeekBarProgress != 1f) { canvas.saveLayerAlpha(tx + seekBarX, y, tx + seekBarX + seekBar.getWidth() + dp(24), y + dp(24), (int) (255 * (toSeekBarProgress)), Canvas.ALL_SAVE_FLAG); } else { canvas.save(); } canvas.translate(tx + seekBarX, y); seekBar.draw(canvas); canvas.restore(); } if (toSeekBarProgress < 1f) { float x = tx + timeAudioX + performerX; float y = dp(35) + namesOffset + getMediaOffsetY(); if (toSeekBarProgress != 0) { canvas.saveLayerAlpha(x, y, x + performerLayout.getWidth(), y + performerLayout.getHeight(), (int) (255 * (1f - toSeekBarProgress)), Canvas.ALL_SAVE_FLAG); } else { canvas.save(); } if (toSeekBarProgress != 0) { float s = 0.7f + 0.3f * (1f - toSeekBarProgress); canvas.scale(s, s, x, y + performerLayout.getHeight() / 2f); } canvas.translate(x, y); performerLayout.draw(canvas); canvas.restore(); } canvas.save(); canvas.translate(tx + timeAudioX, dp(57) + namesOffset + getMediaOffsetY()); durationLayout.draw(canvas); canvas.restore(); if (shouldDrawMenuDrawable()) { Drawable menuDrawable; if (currentMessageObject.isOutOwner()) { menuDrawable = getThemedDrawable(isDrawSelectionBackground() ? Theme.key_drawable_msgOutMenuSelected : Theme.key_drawable_msgOutMenu); } else { menuDrawable = isDrawSelectionBackground() ? Theme.chat_msgInMenuSelectedDrawable : Theme.chat_msgInMenuDrawable; } setDrawableBounds(menuDrawable, otherX = (int) buttonX + backgroundWidth - dp(currentMessageObject.type == MessageObject.TYPE_TEXT ? 58 : 48) - dp(hasLinkPreview ? 18 : 0), otherY = (int) buttonY - dp(2)); if (transitionParams.animateChangeProgress != 1f && transitionParams.animateShouldDrawMenuDrawable) { menuDrawable.setAlpha((int) (255 * transitionParams.animateChangeProgress)); } menuDrawable.draw(canvas); if (transitionParams.animateChangeProgress != 1f && transitionParams.animateShouldDrawMenuDrawable) { menuDrawable.setAlpha(255); } } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { if (currentMessageObject.isOutOwner()) { Theme.chat_audioTimePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outAudioDurationSelectedText : Theme.key_chat_outAudioDurationText)); radialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() || buttonPressed != 0 ? Theme.key_chat_outAudioSelectedProgress : Theme.key_chat_outAudioProgress)); } else if (hasLinkPreview && linkLine != null) { Theme.chat_audioTimePaint.setColor(Theme.adaptHue(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inAudioDurationSelectedText : Theme.key_chat_inAudioDurationText), linkLine.getColor())); radialProgress.setProgressColor(Theme.adaptHue(getThemedColor(isDrawSelectionBackground() || buttonPressed != 0 ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress), linkLine.getColor())); seekBar.setColors(Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbar), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioCacheSeekbar), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarFill), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarFill), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarSelected), linkLine.getColor())); } else { Theme.chat_audioTimePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inAudioDurationSelectedText : Theme.key_chat_inAudioDurationText)); radialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() || buttonPressed != 0 ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress)); } AudioVisualizerDrawable audioVisualizerDrawable; if (overridenAudioVisualizer != null) { audioVisualizerDrawable = overridenAudioVisualizer; } else if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { audioVisualizerDrawable = Theme.getCurrentAudiVisualizerDrawable(); } else { audioVisualizerDrawable = Theme.getAnimatedOutAudioVisualizerDrawable(currentMessageObject); } if (audioVisualizerDrawable != null && !(documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && hasLinkPreview)) { audioVisualizerDrawable.setParentView(this); if (linkLine != null) { audioVisualizerDrawable.draw(canvas, buttonX + dp(22), buttonY + dp(22), linkLine.getColor(), documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND ? getVideoTranscriptionProgress() : 1, resourcesProvider); } else { audioVisualizerDrawable.draw(canvas, buttonX + dp(22), buttonY + dp(22), currentMessageObject.isOutOwner(), documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND ? getVideoTranscriptionProgress() : 1, resourcesProvider); } } if (!enterTransitionInProgress && documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { radialProgress.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); radialProgress.iconScale = 1f; if (drawPhotoImage && currentMessageObject != null && currentMessageObject.hasMediaSpoilers() && currentMessageObject.isSensitive() && (!currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0 && mediaSpoilerRevealProgress < 1)) { radialProgress.iconScale *= mediaSpoilerRevealProgress; } drawVoiceOnce(canvas, seekBarWaveform == null ? 1f : 1f - seekBarWaveform.explosionRate, () -> radialProgress.draw(canvas)); } int seekBarX = this.seekBarX; int timeAudioX = this.timeAudioX; float yoffset = 0; if (transitionParams.animateButton) { int offset = this.buttonX - (int) (transitionParams.animateFromButtonX * (1f - transitionParams.animateChangeProgress) + this.buttonX * (transitionParams.animateChangeProgress)); seekBarX -= offset; timeAudioX -= offset; } if (transitionParams.animateBackgroundBoundsInner) { yoffset += transitionParams.deltaTop; } if (isRoundVideo && currentMessageObject.isOutOwner()) { seekBarX = getCurrentBackgroundLeft() + dp(57); timeAudioX = getCurrentBackgroundLeft() + dp(67); } if (isRoundVideo) { yoffset += (1f - getVideoTranscriptionProgress()) * AndroidUtilities.roundMessageSize; } canvas.save(); if (!(documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && hasLinkPreview)) { if (useSeekBarWaveform) { canvas.translate(seekBarX + dp(13) - seekBarWaveformTranslateX, seekBarY + yoffset); seekBarWaveform.setAlpha(isRoundVideo ? CubicBezierInterpolator.EASE_IN.getInterpolation(getVideoTranscriptionProgress()) : 1f); seekBarWaveform.draw(canvas, this); } else { canvas.translate(seekBarX, seekBarY + yoffset); seekBar.setAlpha(isRoundVideo ? CubicBezierInterpolator.EASE_IN.getInterpolation(getVideoTranscriptionProgress()) : 1f); seekBar.draw(canvas); } } canvas.restore(); float transcribeAlpha = getUseTranscribeButtonProgress(); float playingRoundAlpha = 0; if (transitionParams.animatePlayingRound) { if (isPlayingRound) { playingRoundAlpha = transitionParams.animateChangeProgress; } else { playingRoundAlpha = 1f - transitionParams.animateChangeProgress; } } else if (isPlayingRound) { playingRoundAlpha = 1f; } if (!wasTranscriptionOpen) { transcribeAlpha = AndroidUtilities.lerp(transcribeAlpha * (1f - playingRoundAlpha), transcribeAlpha, getVideoTranscriptionProgress()); } if (transcribeAlpha > 0 && !(documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && hasLinkPreview)) { canvas.save(); int backgroundWidth = getCurrentBackgroundRight() - getCurrentBackgroundLeft() + dp(pinnedBottom ? 6 : 0); int seekBarWidth = backgroundWidth - dp(92 + (hasLinkPreview ? 10 : 0) + 36); if (transcribeButton == null) { transcribeButton = new TranscribeButton(this, seekBarWaveform) { @Override public void drawGradientBackground(Canvas canvas, Rect bounds, float alpha) { Paint paint; if (currentMessageObject.shouldDrawWithoutBackground()) { paint = getThemedPaint(Theme.key_paint_chatActionBackground); } else { paint = getThemedPaint(Theme.key_paint_chatTimeBackground); } int oldAlpha = paint.getAlpha(); paint.setAlpha((int) (oldAlpha * alpha)); applyServiceShaderMatrix(); canvas.drawRect(bounds, paint); if (paint == getThemedPaint(Theme.key_paint_chatActionBackground) && hasGradientService()) { int oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * alpha)); canvas.drawRect(bounds, Theme.chat_actionBackgroundGradientDarkenPaint); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); } paint.setAlpha(oldAlpha); } @Override protected void onOpen() { wasTranscriptionOpen = true; } }; transcribeButton.setOpen(currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionOpen && currentMessageObject.messageOwner.voiceTranscriptionFinal && TranscribeButton.isVideoTranscriptionOpen(currentMessageObject), false); transcribeButton.setLoading(TranscribeButton.isTranscribing(currentMessageObject), false); transcribeButton.setLock(TranscribeButton.showTranscribeLock(currentMessageObject), false); } if (drawSideButton != 0) { transcribeX = AndroidUtilities.lerp( seekBarX + dp(13 + 8) + seekBarWidth, sideStartX, 1f - getVideoTranscriptionProgress() ); transcribeY = AndroidUtilities.lerp( seekBarY + dp(3), sideStartY - dp(32 + 8), 1f - getVideoTranscriptionProgress() ); } else { transcribeX = AndroidUtilities.lerp( seekBarX + dp(13 + 8) + seekBarWidth, currentMessageObject != null && currentMessageObject.isOutOwner() ? getCurrentBackgroundLeft() - dp(32 + 8) + dp(28) * playingRoundAlpha : getCurrentBackgroundRight() + dp(8) - dp(40) * playingRoundAlpha, 1f - getVideoTranscriptionProgress() ); float y = layoutHeight + transitionParams.deltaBottom - dp(28 - (drawPinnedBottom ? 2 : 0)); if (!reactionsLayoutInBubble.isEmpty) { y -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress); } y = AndroidUtilities.lerp(y, dp(44) + namesOffset + getMediaOffsetY() - dp(1.7f), getVideoTranscriptionProgress()); y += dp(1.7f); transcribeY = AndroidUtilities.lerp( seekBarY + dp(3), y - dp(12) - (currentMessageObject.isOutOwner() ? 0 : dp(28) * playingRoundAlpha), 1f - getVideoTranscriptionProgress() ); } transcribeButton.setBounds( (int) transcribeX, (int) transcribeY, AndroidUtilities.lerp(dp(30), dp(32), 1f - getVideoTranscriptionProgress()), AndroidUtilities.lerp(dp(24), dp(32), 1f - getVideoTranscriptionProgress()), AndroidUtilities.lerp(dp(8), dp(16), 1f - getVideoTranscriptionProgress()) ); transcribeButton.setColor( ColorUtils.blendARGB( getThemedColor(Theme.key_chat_serviceText), getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground), documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO ? 1 : getVideoTranscriptionProgress() ), getThemedColor(Theme.key_windowBackgroundWhiteGrayText), currentMessageObject.isOut(), documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO ? 0 : 1f - getVideoTranscriptionProgress() ); transcribeButton.draw(canvas, transcribeAlpha); canvas.restore(); } if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { canvas.save(); canvas.translate(timeAudioX, dp(44) + namesOffset + getMediaOffsetY() + yoffset); durationLayout.draw(canvas); canvas.restore(); if (currentMessageObject.type != MessageObject.TYPE_TEXT && currentMessageObject.isContentUnread()) { Theme.chat_docBackPaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outVoiceSeekbarFill : Theme.key_chat_inVoiceSeekbarFill)); canvas.drawCircle(timeAudioX + timeWidthAudio + dp(6), dp(51) + namesOffset + getMediaOffsetY(), dp(3), Theme.chat_docBackPaint); } } if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { if (durationLayout != null) { boolean playing = MediaController.getInstance().isPlayingMessage(currentMessageObject); if (playing || roundProgressAlpha != 0) { if (playing) { roundProgressAlpha = 1f; } else { roundProgressAlpha -= 16 / 150f; if (roundProgressAlpha < 0) { roundProgressAlpha = 0; } else { invalidate(); } } drawRoundProgress(canvas); } } } } if (currentMessageObject != null && !currentMessageObject.isOutOwner() && (isForum || isMonoForum && isAllChats) && (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO || currentMessageObject.type == MessageObject.TYPE_STICKER || currentMessageObject.type == MessageObject.TYPE_ANIMATED_STICKER) && isSideMenued) { float avatarAlpha; if (transitionParams.animateDrawingSideMenuEnabled) { avatarAlpha = lerp(!isSideMenuEnabled, isSideMenuEnabled, transitionParams.animateChangeProgress); } else { avatarAlpha = isSideMenuEnabled ? 1.0f : 0.0f; } if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { avatarAlpha *= (1.0f - getVideoTranscriptionProgress()); } if (avatarAlpha > 0.0f) { final float wasX = avatarImage.getImageX(); final float wasY = avatarImage.getImageY(); final float wasWidth = avatarImage.getImageWidth(); final float wasHeight = avatarImage.getImageHeight(); final float wasAlpha = avatarImage.getAlpha(); final float scale = lerp(.1f, 1.0f, avatarAlpha); final boolean wasVisible = avatarImage.getVisible(); avatarImage.setVisible(true, false); avatarImage.setImageCoords(photoImage.getImageX() + dp(7), photoImage.getImageY() + dp(7), dp(26) * scale, dp(26) * scale); avatarImage.setAlpha(avatarAlpha); avatarImage.draw(canvas); avatarImage.setImageCoords(wasX, wasY, wasWidth, wasHeight); avatarImage.setAlpha(wasAlpha); avatarImage.setVisible(wasVisible, false); } } if (captionLayout != null || hasFactCheck || transitionParams.animateFactCheck) { updateCaptionLayout(); } updateReactionLayoutPosition(); if (shouldDrawCaptionLayout() && !currentMessageObject.preview) { drawCaptionLayout(canvas, false, 1f); // drawCommentLayout(canvas, 1f); // not needed because it is already called by drawCaptionLayout drawReactionsLayout(canvas, 1f, null); } if (currentMessagesGroup == null) { drawFactCheck(canvas, 1f); } if (hasOldCaptionPreview) { int linkX; if ( currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || currentMessageObject.type == MessageObject.TYPE_GIF ) { linkX = (int) (photoImage.getImageX() + dp(5)); } else { linkX = backgroundDrawableLeft + dp(currentMessageObject.isOutOwner() ? 11 : 17); } float startY = totalHeight - dp(drawPinnedTop ? 9 : 10) - linkPreviewHeight - dp(8 + 3); float linkPreviewY = startY; Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewLine : Theme.key_chat_inPreviewLine)); AndroidUtilities.rectTmp.set(linkX, linkPreviewY - dp(3), linkX + dp(6), linkPreviewY + linkPreviewHeight); if (replyRoundRectPath == null) { replyRoundRectPath = new Path(); } else { replyRoundRectPath.rewind(); } canvas.save(); canvas.clipRect(AndroidUtilities.rectTmp.left, AndroidUtilities.rectTmp.top, AndroidUtilities.rectTmp.left + dp(3), AndroidUtilities.rectTmp.bottom); replyRoundRectPath.addRoundRect(AndroidUtilities.rectTmp, dp(4), dp(4), Path.Direction.CW); canvas.drawPath(replyRoundRectPath, Theme.chat_replyLinePaint); canvas.restore(); if (siteNameLayout != null) { Theme.chat_replyNamePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outSiteNameText : Theme.key_chat_inSiteNameText)); canvas.save(); float x = -siteNameLeft + (hasInvoicePreview ? 0 : dp(10)); canvas.translate(linkX + x, linkPreviewY - dp(3)); SpoilerEffect.layoutDrawMaybe(siteNameLayout, canvas); canvas.restore(); linkPreviewY += siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1); } if (currentMessageObject.isOutOwner()) { Theme.chat_replyTextPaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); } else { Theme.chat_replyTextPaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); } if (descriptionLayout != null) { if (linkPreviewY != startY) { linkPreviewY += dp(2); } descriptionY = (int) linkPreviewY - dp(3); canvas.save(); canvas.translate(linkX + dp(10) + descriptionX, descriptionY); SpoilerEffect.layoutDrawMaybe(descriptionLayout, canvas); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(1, descriptionLayout.getPaint().getColor())); canvas.restore(); } drawTime = true; } if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { Drawable menuDrawable; if (currentMessageObject.isOutOwner()) { Theme.chat_docNamePaint.setColor(getThemedColor(Theme.key_chat_outFileNameText)); Theme.chat_infoPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outFileInfoSelectedText : Theme.key_chat_outFileInfoText)); Theme.chat_docBackPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outFileBackgroundSelected : Theme.key_chat_outFileBackground)); menuDrawable = getThemedDrawable(isDrawSelectionBackground() ? Theme.key_drawable_msgOutMenuSelected : Theme.key_drawable_msgOutMenu); } else if (linkLine != null && hasLinkPreview) { Theme.chat_docNamePaint.setColor(Theme.adaptHue(getThemedColor(Theme.key_chat_inFileNameText), linkLine.getColor())); Theme.chat_infoPaint.setColor(Theme.adaptHue(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inFileInfoSelectedText : Theme.key_chat_inFileInfoText), linkLine.getColor())); Theme.chat_docBackPaint.setColor(Theme.adaptHue(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inFileBackgroundSelected : Theme.key_chat_inFileBackground), linkLine.getColor())); menuDrawable = isDrawSelectionBackground() ? Theme.chat_msgInMenuSelectedDrawable : Theme.chat_msgInMenuDrawable; } else { Theme.chat_docNamePaint.setColor(getThemedColor(Theme.key_chat_inFileNameText)); Theme.chat_infoPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inFileInfoSelectedText : Theme.key_chat_inFileInfoText)); Theme.chat_docBackPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inFileBackgroundSelected : Theme.key_chat_inFileBackground)); menuDrawable = isDrawSelectionBackground() ? Theme.chat_msgInMenuSelectedDrawable : Theme.chat_msgInMenuDrawable; } float x; int titleY; int subtitleY; if (drawPhotoImage) { if (currentMessageObject.type == MessageObject.TYPE_TEXT) { setDrawableBounds(menuDrawable, otherX = (int) (photoImage.getImageX() + backgroundWidth - dp(56 + (hasLinkPreview ? 12 : 0))), otherY = (int) (photoImage.getImageY() + dp(4))); } else { setDrawableBounds(menuDrawable, otherX = (int) (photoImage.getImageX() + backgroundWidth - dp(40 + (hasLinkPreview ? 12 : 0))), otherY = (int) (photoImage.getImageY() + dp(4))); } x = (int) (photoImage.getImageX() + photoImage.getImageWidth() + dp(10)); titleY = (int) (photoImage.getImageY() + dp(8)); subtitleY = (int) (photoImage.getImageY() + (docTitleLayout != null ? docTitleLayout.getLineBottom(docTitleLayout.getLineCount() - 1) + dp(13) : dp(8))); if (!imageDrawn) { if (currentMessageObject.isOutOwner()) { radialProgress.setColorKeys(Theme.key_chat_outLoader, Theme.key_chat_outLoaderSelected, Theme.key_chat_outMediaIcon, Theme.key_chat_outMediaIconSelected); radialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outFileProgressSelected : Theme.key_chat_outFileProgress)); videoRadialProgress.setColorKeys(Theme.key_chat_outLoader, Theme.key_chat_outLoaderSelected, Theme.key_chat_outMediaIcon, Theme.key_chat_outMediaIconSelected); videoRadialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outFileProgressSelected : Theme.key_chat_outFileProgress)); } else if (linkLine != null && hasLinkPreview) { radialProgress.setColors(linkLine.getColor(), linkLine.getColor(), Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .01f)), Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .05f))); radialProgress.setProgressColor(Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .01f))); videoRadialProgress.setColors(linkLine.getColor(), linkLine.getColor(), Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .01f)), Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .05f))); videoRadialProgress.setProgressColor(Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .01f))); } else { radialProgress.setColorKeys(Theme.key_chat_inLoader, Theme.key_chat_inLoaderSelected, Theme.key_chat_inMediaIcon, Theme.key_chat_inMediaIconSelected); radialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inFileProgressSelected : Theme.key_chat_inFileProgress)); videoRadialProgress.setColorKeys(Theme.key_chat_inLoader, Theme.key_chat_inLoaderSelected, Theme.key_chat_inMediaIcon, Theme.key_chat_inMediaIconSelected); videoRadialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inFileProgressSelected : Theme.key_chat_inFileProgress)); } rect.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX() + photoImage.getImageWidth(), photoImage.getImageY() + photoImage.getImageHeight()); int[] rad = photoImage.getRoundRadius(); rectPath.reset(); for (int a = 0; a < rad.length; a++) { radii[a * 2] = rad[a]; radii[a * 2 + 1] = rad[a]; } rectPath.addRoundRect(rect, radii, Path.Direction.CW); rectPath.close(); canvas.drawPath(rectPath, Theme.chat_docBackPaint); } else { radialProgress.setColorKeys(Theme.key_chat_mediaLoaderPhoto, Theme.key_chat_mediaLoaderPhotoSelected, Theme.key_chat_mediaLoaderPhotoIcon, Theme.key_chat_mediaLoaderPhotoIconSelected); radialProgress.setProgressColor(getThemedColor(Theme.key_chat_mediaProgress)); videoRadialProgress.setColorKeys(Theme.key_chat_mediaLoaderPhoto, Theme.key_chat_mediaLoaderPhotoSelected, Theme.key_chat_mediaLoaderPhotoIcon, Theme.key_chat_mediaLoaderPhotoIconSelected); videoRadialProgress.setProgressColor(getThemedColor(Theme.key_chat_mediaProgress)); if (buttonState == -1 && radialProgress.getIcon() != MediaActionDrawable.ICON_NONE) { radialProgress.setIcon(MediaActionDrawable.ICON_NONE, true, true); } } } else { setDrawableBounds(menuDrawable, otherX = (int) buttonX + backgroundWidth - dp(currentMessageObject.type == MessageObject.TYPE_TEXT ? 58 : 48) - dp(hasLinkPreview ? 18 + 6 : 0), otherY = (int) buttonY - dp(2)); x = buttonX + dp(53); titleY = (int) buttonY + dp(4); subtitleY = (int) buttonY + dp(27); if (docTitleLayout != null && docTitleLayout.getLineCount() > 1) { subtitleY += (docTitleLayout.getLineCount() - 1) * dp(16) + dp(2); } if (currentMessageObject.isOutOwner()) { radialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() || buttonPressed != 0 ? Theme.key_chat_outAudioSelectedProgress : Theme.key_chat_outAudioProgress)); videoRadialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() || videoButtonPressed != 0 ? Theme.key_chat_outAudioSelectedProgress : Theme.key_chat_outAudioProgress)); } else { radialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() || buttonPressed != 0 ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress)); videoRadialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() || videoButtonPressed != 0 ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress)); } } if (shouldDrawMenuDrawable()) { if (transitionParams.animateChangeProgress != 1f && transitionParams.animateShouldDrawMenuDrawable) { menuDrawable.setAlpha((int) (255 * transitionParams.animateChangeProgress)); } menuDrawable.draw(canvas); if (transitionParams.animateChangeProgress != 1f && transitionParams.animateShouldDrawMenuDrawable) { menuDrawable.setAlpha(255); } } try { if (docTitleLayout != null) { canvas.save(); canvas.translate(x + docTitleOffsetX, titleY); docTitleLayout.draw(canvas); canvas.restore(); } } catch (Exception e) { FileLog.e(e); } try { if (infoLayout != null) { canvas.save(); canvas.translate(x, subtitleY); if (buttonState == 1 && loadingProgressLayout != null) { loadingProgressLayout.draw(canvas); } else { infoLayout.draw(canvas); } canvas.restore(); } } catch (Exception e) { FileLog.e(e); } } if (currentMessageObject.type == MessageObject.TYPE_GEO && !(MessageObject.getMedia(currentMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGeoLive) && currentMapProvider == 2 && photoImage.hasNotThumb()) { Drawable redLocationIcon = sharedResources.getRedLocationIcon(); int w = (int) (redLocationIcon.getIntrinsicWidth() * 0.8f); int h = (int) (redLocationIcon.getIntrinsicHeight() * 0.8f); int x = (int) (photoImage.getImageX() + (photoImage.getImageWidth() - w) / 2); int y = (int) (photoImage.getImageY() + (photoImage.getImageHeight() / 2 - h) - dp(16) * (1f - CubicBezierInterpolator.EASE_OUT_BACK.getInterpolation(photoImage.getCurrentAlpha()))); redLocationIcon.setAlpha((int) (255 * Math.min(1, photoImage.getCurrentAlpha() * 5))); redLocationIcon.setBounds(x, y, x + w, y + h); redLocationIcon.draw(canvas); if (photoImage.getCurrentAlpha() < 1) { invalidate(); } } transitionParams.recordDrawingState(); checkStakedDice(); } private void checkStakedDice() { if (currentMessageObject == null || !currentMessageObject.isStakedDice()) return; if (playedDice) return; final Drawable drawable = photoImage.getDrawable(); if (!(drawable instanceof RLottieDiceDrawable)) return; final RLottieDiceDrawable lottieDrawable = (RLottieDiceDrawable) drawable; if (!lottieDrawable.hasBaseDice()) return; if (!playedDice && lottieDrawable.isDiceRevealed()) { playedDice = true; if (delegate != null) { delegate.forceUpdate(this, false); } } } public void startRevealMedia() { startRevealMedia( photoImage.getImageX() + photoImage.getImageWidth() / 2f, photoImage.getImageY() + photoImage.getImageHeight() / 2f ); } public void startRevealMedia(float x, float y) { mediaSpoilerRevealMaxRadius = (float) Math.sqrt(Math.pow(photoImage.getImageWidth(), 2) + Math.pow(photoImage.getImageHeight(), 2)); startRevealMedia(x, y, mediaSpoilerRevealMaxRadius); } private void startRevealMedia(float x, float y, float maxRadius) { if (currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0f) { return; } if (currentMessageObject.type == MessageObject.TYPE_VIDEO) { currentMessageObject.forceUpdate = true; currentMessageObject.revealingMediaSpoilers = true; setMessageContent(currentMessageObject, currentMessagesGroup, pinnedBottom, pinnedTop, firstInChat, lastInChatList); currentMessageObject.revealingMediaSpoilers = false; currentMessageObject.forceUpdate = false; if (currentMessagesGroup != null) { radialProgress.setProgress(0f, false); } } mediaSpoilerRevealX = x; mediaSpoilerRevealY = y; ValueAnimator animator = ValueAnimator.ofFloat(0, 1).setDuration((long) MathUtils.clamp(mediaSpoilerRevealMaxRadius * 0.3f, 250, 550)); animator.setInterpolator(CubicBezierInterpolator.EASE_BOTH); animator.addUpdateListener(animation -> { mediaSpoilerRevealProgress = (float) animation.getAnimatedValue(); invalidate(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { currentMessageObject.isMediaSpoilersRevealed = true; invalidate(); } }); animator.start(); } public boolean drawingToBitmap; public void drawBlurredPhoto(Canvas canvas) { if (currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress == 1f) { return; } int[] rad = photoImage.getRoundRadius(); mediaSpoilerRadii[0] = mediaSpoilerRadii[1] = rad[0]; mediaSpoilerRadii[2] = mediaSpoilerRadii[3] = rad[1]; mediaSpoilerRadii[4] = mediaSpoilerRadii[5] = rad[2]; mediaSpoilerRadii[6] = mediaSpoilerRadii[7] = rad[3]; mediaSpoilerPath.rewind(); AndroidUtilities.rectTmp.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); mediaSpoilerPath.addRoundRect(AndroidUtilities.rectTmp, mediaSpoilerRadii, Path.Direction.CW); canvas.save(); canvas.clipPath(mediaSpoilerPath); if (mediaSpoilerRevealProgress != 0f) { mediaSpoilerPath.rewind(); mediaSpoilerPath.addCircle(mediaSpoilerRevealX, mediaSpoilerRevealY, mediaSpoilerRevealMaxRadius * mediaSpoilerRevealProgress, Path.Direction.CW); canvas.clipPath(mediaSpoilerPath, Region.Op.DIFFERENCE); } if (currentMessageObject.needDrawBluredPreview()) { photoImage.draw(canvas); } else { blurredPhotoImage.setImageCoords(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageWidth(), photoImage.getImageHeight()); blurredPhotoImage.setRoundRadius(photoImage.getRoundRadius()); blurredPhotoImage.draw(canvas); } drawBlurredPhotoParticles(canvas); canvas.restore(); } public void drawBlurredPhotoParticles(Canvas canvas) { if (mediaSpoilerEffect2 == null) { return; } canvas.save(); canvas.translate(photoImage.getImageX(), photoImage.getImageY()); mediaSpoilerEffect2.draw(canvas, this, (int) photoImage.getImageWidth(), (int) photoImage.getImageHeight(), photoImage.getAlpha(), drawingToBitmap); canvas.restore(); invalidate(); } private float getUseTranscribeButtonProgress() { if (transitionParams.animateUseTranscribeButton) { if (useTranscribeButton) { return transitionParams.animateChangeProgress; } else { return 1f - transitionParams.animateChangeProgress; } } else { return useTranscribeButton ? 1 : 0; } } private void updateReactionLayoutPosition() { if (!currentMessageObject.shouldDrawReactions()) { return; } if (!reactionsLayoutInBubble.isEmpty && (currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) && !reactionsLayoutInBubble.isSmall) { if (currentMessageObject.type == MessageObject.TYPE_EMOJIS || currentMessageObject.isAnimatedEmoji() || currentMessageObject.isAnyKindOfSticker()) { if (currentMessageObject.isOutOwner()) { reactionsLayoutInBubble.x = getMeasuredWidth() - reactionsLayoutInBubble.width - dp(16);//AndroidUtilities.displaySize.x - maxWidth - dp(17); } else { reactionsLayoutInBubble.x = getCurrentBackgroundLeft(); } } else { if (currentMessageObject.isOutOwner()) { reactionsLayoutInBubble.x = getCurrentBackgroundLeft() + dp(11); } else { if (isRoundVideo) { reactionsLayoutInBubble.x = getCurrentBackgroundLeft() + dp(11) + (int) dp(AndroidUtilities.lerp(0, !drawPinnedBottom ? 6 : 0, getVideoTranscriptionProgress())); reactionsLayoutInBubble.x -= (int) ((1f - getVideoTranscriptionProgress()) * dp(9)); } else { reactionsLayoutInBubble.x = getCurrentBackgroundLeft() + dp(!mediaBackground && drawPinnedBottom ? 11 : 17); if (mediaBackground) { reactionsLayoutInBubble.x -= dp(9); } } } } if (!currentMessageObject.isOutOwner() && currentPosition != null) { reactionsLayoutInBubble.x -= dp(64 - (needDrawAvatar() ? 48 : 0)) * sideMenuAlpha; } reactionsLayoutInBubble.y = getBackgroundDrawableBottom() - dp(10) - reactionsLayoutInBubble.height; reactionsLayoutInBubble.y -= (drawCommentButton ? dp(currentMessageObject.type == MessageObject.TYPE_PAID_MEDIA && hasCaptionLayout() ? 28 : 43) : 0); if (hasNewLineForTime && !(drawForwardedName && hasLinkPreview && documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO)) { reactionsLayoutInBubble.y -= dp(16); } if (currentMessageObject.type != MessageObject.TYPE_FILE && (captionLayout != null && ((currentMessageObject.type != MessageObject.TYPE_VOICE && currentMessageObject.type != MessageObject.TYPE_POLL && !(currentMessageObject.isOut() && drawForwardedName && !drawPhotoImage)) || (currentPosition != null && currentMessagesGroup != null) || currentMessageObject.type == MessageObject.TYPE_PAID_MEDIA))) { reactionsLayoutInBubble.y -= dp(14); } reactionsLayoutInBubble.y += reactionsLayoutInBubble.positionOffsetY; } if (reactionsLayoutInBubble.isSmall && !reactionsLayoutInBubble.isEmpty) { int timeYOffset; if (shouldDrawTimeOnMedia()) { timeYOffset = -(drawCommentButton ? dp(41.3f) : 0); } else { if (currentMessageObject.isSponsored()) { timeYOffset = -dp(48); if (hasNewLineForTime) { timeYOffset -= dp(16); } } else { timeYOffset = -(drawCommentButton ? dp(43) : 0); } } reactionsLayoutInBubble.y = (int) (shouldDrawTimeOnMedia() ? getPhotoBottom() + additionalTimeOffsetY - dp(7.3f) - timeLayout.getHeight() : layoutHeight - dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); reactionsLayoutInBubble.y += timeLayout.getHeight() / 2f - dp(7); reactionsLayoutInBubble.x = (int) timeX; } } public float getPhotoBottom() { if (groupMedia != null) { return groupMedia.y + groupMedia.height; } else { return photoImage.getImageY2(); } } public void drawVoiceOnce(Canvas canvas, float progress, Runnable drawRadialProgress) { if (currentMessageObject != null && currentMessageObject.isVoiceOnce()) { final float scale = progress; final float rcx = radialProgress.progressRect.centerX() + (float) Math.cos(AndroidUtilities.lerp(190, 45, scale) / 180f * Math.PI) * dp(22.6274f); final float rcy = radialProgress.progressRect.centerY() + (float) Math.sin(AndroidUtilities.lerp(190, 45, scale) / 180f * Math.PI) * dp(22.6274f); AndroidUtilities.rectTmp.set(radialProgress.progressRect); AndroidUtilities.rectTmp.inset(-dp(1), -dp(1)); canvas.saveLayerAlpha(AndroidUtilities.rectTmp, 0xFF, Canvas.ALL_SAVE_FLAG); radialProgress.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); radialProgress.iconScale = scale; drawRadialProgress.run(); if (onceClearPaint == null) { onceClearPaint = new Paint(Paint.ANTI_ALIAS_FLAG); onceClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); } if (scale < 1f) { canvas.save(); final float s = (1f - scale) * .7f; canvas.scale(s, s, radialProgress.progressRect.centerX(), AndroidUtilities.lerp(radialProgress.progressRect.top, radialProgress.progressRect.bottom, .5f)); if (onceFire == null) { onceFire = new RLottieDrawable(R.raw.fire_once, dp(32), dp(32), true, null); onceFire.setMasterParent(this); onceFire.setAllowDecodeSingleFrame(true); onceFire.setAutoRepeat(1); onceFire.start(); } onceFire.setBounds( (int) radialProgress.progressRect.left, (int) radialProgress.progressRect.top, (int) radialProgress.progressRect.right, (int) radialProgress.progressRect.bottom ); if (onceRadialPaint == null) { onceRadialPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } if (onceRadialCutPaint == null) { onceRadialCutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); onceRadialCutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); } if (onceRadialStrokePaint == null) { onceRadialStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); onceRadialStrokePaint.setStyle(Paint.Style.STROKE); } int iconColor = radialProgress.iconColorKey >= 0 ? getThemedColor(radialProgress.iconColorKey) : radialProgress.iconColor; onceRadialPaint.setColor(iconColor); onceRadialStrokePaint.setColor(iconColor); radialProgress.mediaActionDrawable.applyShaderMatrix(false); onceRadialPaint.setShader(radialProgress.mediaActionDrawable.paint2.getShader()); onceRadialStrokePaint.setShader(radialProgress.mediaActionDrawable.paint2.getShader()); AndroidUtilities.rectTmp.set(onceFire.getBounds()); canvas.saveLayerAlpha(AndroidUtilities.rectTmp, 0xFF, Canvas.ALL_SAVE_FLAG); AndroidUtilities.rectTmp.inset(1, 1); canvas.drawRect(AndroidUtilities.rectTmp, onceRadialPaint); onceFire.draw(canvas, onceRadialCutPaint); canvas.restore(); canvas.restore(); onceRadialStrokePaint.setAlpha((int) (0xFF * (1f - scale))); onceRadialStrokePaint.setStrokeWidth(dp(1.66f)); rect.set(radialProgress.progressRect); rect.inset(dp(3), dp(3)); canvas.drawArc(rect, -90, -360 * (1f - seekBarWaveform.explodeProgress), false, onceRadialStrokePaint); if (timerParticles == null) { timerParticles = new TimerParticles(); } timerParticles.draw(canvas, onceRadialStrokePaint, rect, -360 * (1f - seekBarWaveform.explodeProgress), 1f - scale); } else if (onceFire != null) { onceFire.recycle(true); onceFire = null; if (timerParticles != null) { timerParticles = null; } } canvas.drawCircle(rcx, rcy, dp(10 + scale * 1.5f) * scale, onceClearPaint); canvas.restore(); if (oncePeriod == null) { oncePeriod = new CaptionContainerView.PeriodDrawable(3); oncePeriod.updateColors(0xffffffff, 0, 0); oncePeriod.diameterDp = 14; oncePeriod.setTextSize(10); oncePeriod.strokePaint.setStrokeWidth(dpf2(1.5f)); oncePeriod.setValue(1, false, false); oncePeriod.textOffsetX = -dpf2(.33f); oncePeriod.textOffsetY = dpf2(.33f); } oncePeriod.diameterDp = 14 * scale; oncePeriod.setTextSize(10 * scale); canvas.saveLayerAlpha(rcx - dp(10), rcy - dp(10), rcx + dp(10), rcy + dp(10), 0xFF, Canvas.ALL_SAVE_FLAG); canvas.drawCircle(rcx, rcy, dp(10) * scale, radialProgress.circlePaint); oncePeriod.setClear(AndroidUtilities.computePerceivedBrightness(radialProgress.circlePaint.getColor()) > .8f); oncePeriod.setCenterXY(rcx, rcy); oncePeriod.draw(canvas, scale); canvas.restore(); } else { drawRadialProgress.run(); } } public void drawLinkPreview(Canvas canvas, float alpha) { if (!currentMessageObject.isSponsored() && !currentMessageObject.isUnsupported() && !hasLinkPreview && !hasGamePreview && !hasInvoicePreview) { return; } int restoreCount = canvas.getSaveCount(); final int backgroundWidth = (int) (this.backgroundWidth + (transitionParams != null ? - transitionParams.deltaLeft + transitionParams.deltaRight : 0)); final float right = getBackgroundDrawableRight() + (transitionParams != null ? transitionParams.deltaRight : 0) - dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) - getExtraTextX(); int startY; int linkPreviewYDiff = 0; int linkX; if (hasGamePreview) { startY = dp(14) + namesOffset; linkX = unmovedTextX - dp(10); } else if (hasInvoicePreview) { startY = dp(14) + namesOffset; linkX = unmovedTextX + dp(1); } else if (currentMessageObject.isSponsored()) { startY = this.linkPreviewY - dp(2); linkX = unmovedTextX + dp(1); } else { if (currentMessageObject.isOutOwner()) { linkX = backgroundDrawableLeft + dp(12) + getExtraTextX(); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { linkX -= Math.max(0, linkX + Math.max(replyNameWidth, replyTextWidth) + dp(14) - AndroidUtilities.displaySize.x); } } else { if (mediaBackground) { linkX = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { linkX = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } linkX += transitionParams.deltaLeft; linkX -= dp(1.33f); startY = this.linkPreviewY; if (transitionParams.animateLinkPreviewY) { final int animatedStartY = AndroidUtilities.lerp(transitionParams.animateFromLinkPreviewY, startY, transitionParams.animateChangeProgress); linkPreviewYDiff = animatedStartY - startY; startY = animatedStartY; } } final int width = (int) (right - linkX); int linkPreviewY = startY; int smallImageStartY = 0; int linkPreviewHeight = this.linkPreviewHeight; if (transitionParams != null && transitionParams.animateLinkPreviewHeight) { linkPreviewHeight = AndroidUtilities.lerp(transitionParams.animateFromLinkPreviewHeight, linkPreviewHeight, transitionParams.animateChangeProgress); } if (linkLine == null) { linkLine = new ReplyMessageLine(this); } Theme.chat_replyNamePaint.setColor(linkLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_LINK)); linkLine.setEmojiAlpha(drawInstantViewType == 23 || drawInstantViewType == 24 || drawInstantViewType == 28 ? 0.5f : 1f); final boolean drawPhotoImageBeforeBefore = currentMessageObject.isSponsored() && !isSmallImage; final boolean drawPhotoImageBefore = !drawPhotoImageBeforeBefore && drawInstantView && (drawInstantViewType != 26 && drawInstantViewType != 9 && drawInstantViewType != 2 && drawInstantViewType != 13 && drawInstantViewType != 11 && drawInstantViewType != 25 && drawInstantViewType != 1 && drawInstantViewType != 29 && drawInstantViewType != 18 && drawInstantViewType != 22) || drawInstantViewType == 6 && imageBackgroundColor != 0; final boolean drawPhotoImageAfter = !drawPhotoImageBeforeBefore && (!drawInstantView || drawInstantViewType == 9 || drawInstantViewType == 2 || drawInstantViewType == 11 || drawInstantViewType == 25 || drawInstantViewType == 13 || drawInstantViewType == 1 || drawInstantViewType == 29 || drawInstantViewType == 18 || drawInstantViewType == 22 || drawInstantViewType == INSTANT_BUTTON_TYPE_PROFILE || isSmallImage || drawInstantViewType == 26); boolean restore = false; boolean drawInstantButtonInside = false; boolean loading = delegate != null && delegate.isProgressLoading(this, ChatActivity.PROGRESS_INSTANT); if (!hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults() && !currentMessageObject.isUnsupported()) { drawInstantButtonInside = true; if (linkPreviewBounce == null) { linkPreviewBounce = new ButtonBounce(this, 2.0f, 2.0f); } canvas.save(); final float s = linkPreviewBounce.getScale(0.01f); canvas.scale(s, s, linkX + width / 2f, linkPreviewY + (linkPreviewHeight + (drawInstantButtonInside && drawInstantView ? dp(42) : 0)) / 2f); restore = true; AndroidUtilities.rectTmp.set(linkX, linkPreviewY - dp(6), linkX + width, linkPreviewY + linkPreviewHeight + (drawInstantButtonInside && drawInstantView ? dp(42) : 0)); linkLine.setLoading(loading); float rad = (float) Math.floor(SharedConfig.bubbleRadius / (currentMessageObject.isSponsored() ? 2f : 3f)); linkLine .offsetEmoji(0, drawPhotoImageBefore ? (1f - isSmallImage()) * (dp(18) + photoImage.getImageHeight() + (siteNameLayout != null ? siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1) : 0)) : 0) .drawBackground(canvas, AndroidUtilities.rectTmp, rad, rad, rad, alpha); int rippleColor = linkLine.getBackgroundColor(); if (linkPreviewSelector == null) { linkPreviewSelector = Theme.createRadSelectorDrawable(linkPreviewSelectorColor = rippleColor, 0, 0); linkPreviewSelector.setCallback(this); Theme.setMaskDrawableRad(linkPreviewSelector, 3, 6, 6, 3); linkPreviewSelector.setCallback(this); } else if (linkPreviewSelectorColor != rippleColor) { Theme.setSelectorDrawableColor(linkPreviewSelector, linkPreviewSelectorColor = rippleColor, true); } linkPreviewSelector.setBounds((int) AndroidUtilities.rectTmp.left, (int) AndroidUtilities.rectTmp.top, (int) AndroidUtilities.rectTmp.right, (int) AndroidUtilities.rectTmp.bottom); linkPreviewSelector.draw(canvas); linkLine.drawLine(canvas, AndroidUtilities.rectTmp, alpha); linkLine.drawLoadingBackground(canvas, AndroidUtilities.rectTmp, rad, rad, rad, alpha); } if (drawPhotoImage && drawPhotoImageBeforeBefore) { if (linkPreviewY != startY) { linkPreviewY += dp(2); } final int photoWidth = width - dp(17); if (isSmallImage) { photoImage.setImageX(linkX + width - photoImage.getImageWidth() - dp(6)); photoImage.setImageY(smallImageStartY); } else { photoImage.setImageX(linkX + (hasInvoicePreview ? -dp(6.3f) : dp(10))); photoImage.setImageY(linkPreviewY); } if (transitionParams != null && transitionParams.animateSmallImage) { if (!isSmallImage && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { photoImage.setImageWidth((int) AndroidUtilities.lerp(transitionParams.photoImageFromWidth, photoWidth, transitionParams.animateChangeProgress)); } photoImage.setImageX(AndroidUtilities.lerp(transitionParams.photoImageFromCenterX, photoImage.getCenterX(), transitionParams.animateChangeProgress) - photoImage.getImageWidth() / 2f); photoImage.setImageY(AndroidUtilities.lerp(transitionParams.photoImageFromCenterY, photoImage.getCenterY(), transitionParams.animateChangeProgress) - photoImage.getImageHeight() / 2f); } else if (!isSmallImage && documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { photoImage.setImageWidth(photoWidth); } if (!isSmallImage && drawImageButton) { int size = dp(48); buttonX = this.buttonX = (int) (photoImage.getImageX() + (photoImage.getImageWidth() - size) / 2.0f); buttonY = this.buttonY = (int) (photoImage.getImageY() + (photoImage.getImageHeight() - size) / 2.0f); radialProgress.setProgressRect((int) buttonX, (int) buttonY, (int) buttonX + size, (int) buttonY + size); } if (isRoundVideo && MediaController.getInstance().isPlayingMessage(currentMessageObject) && MediaController.getInstance().isVideoDrawingReady() && canvas.isHardwareAccelerated()) { imageDrawn = true; drawTime = true; } else { if (delegate == null || delegate.getPinchToZoomHelper() == null || !delegate.getPinchToZoomHelper().isInOverlayModeFor(this)) { if (alpha != 1f) { photoImage.setAlpha(alpha); if (allowDrawPhotoImage()) { imageDrawn = photoImage.draw(canvas); } else { imageDrawn = true; } if (currentMessageObject.hasMediaSpoilers()) { blurredPhotoImage.setAlpha(alpha); drawBlurredPhoto(canvas); blurredPhotoImage.setAlpha(1f); } photoImage.setAlpha(1f); } else { if (allowDrawPhotoImage()) { imageDrawn = photoImage.draw(canvas); } else { imageDrawn = true; } if (currentMessageObject.hasMediaSpoilers()) { drawBlurredPhoto(canvas); } } } } linkPreviewY += photoImage.getImageHeight() + dp(6); } if (siteNameLayout != null) { if (titleLabelLayout != null) { linkPreviewY += dp(1); } smallImageStartY = linkPreviewY - dp(1); int wasAlpha = Theme.chat_replyNamePaint.getAlpha(); if (alpha != 1f) { Theme.chat_replyNamePaint.setAlpha((int) (alpha * wasAlpha)); } canvas.save(); float x = (Math.abs(siteNameLeft) > 1 ? width - dp(hasInvoicePreview ? 0 : 20) - siteNameWidth - siteNameLeft : 0) + (hasInvoicePreview ? 0 : dp(10)); canvas.translate(linkX + x, linkPreviewY - dp(1)); SpoilerEffect.layoutDrawMaybe(siteNameLayout, canvas); canvas.restore(); if (titleLabelLayout != null) { titleLabelX = linkX + x + siteNameLayoutWidth + dp(12); titleLabelY = linkPreviewY; rect.set(titleLabelX - dp(6), titleLabelY - dp(2), titleLabelX + titleLabelLayoutWidth + dp(6), titleLabelY + titleLabelLayoutHeight + dp(2)); if (titleLabelBounce == null) { titleLabelBounce = new ButtonBounce(this); } float scale = titleLabelBounce.getScale(0.1f); boolean scaleRestore = scale != 1; if (scaleRestore) { canvas.save(); canvas.scale(scale, scale, rect.centerX(), rect.centerY()); } Theme.chat_instantViewPaint.setColor(Theme.chat_replyNamePaint.getColor()); int wasInstantViewAlpha = Theme.chat_instantViewPaint.getAlpha(); Theme.chat_instantViewPaint.setAlpha((int) (wasAlpha * .11f)); canvas.drawRoundRect(rect, rect.height(), rect.height(), Theme.chat_instantViewPaint); Theme.chat_instantViewPaint.setAlpha(wasInstantViewAlpha); Theme.chat_titleLabelTextPaint.setColor(Theme.chat_replyNamePaint.getColor()); Theme.chat_titleLabelTextPaint.setAlpha(Theme.chat_replyNamePaint.getAlpha()); canvas.save(); canvas.translate(titleLabelX, titleLabelY); titleLabelLayout.draw(canvas); canvas.restore(); if (scaleRestore) { canvas.restore(); } } linkPreviewY += siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1); Theme.chat_replyNamePaint.setAlpha(wasAlpha); } if ((hasGamePreview || hasInvoicePreview) && currentMessageObject.textHeight(transitionParams) != 0) { startY += currentMessageObject.textHeight(transitionParams) + dp(4); linkPreviewY += currentMessageObject.textHeight(transitionParams) + dp(4); } if (drawPhotoImage && drawPhotoImageBefore) { if (isSmallImage) { if (transitionParams != null && transitionParams.animateSmallImage) { float diff = (linkPreviewY != startY ? dp(2) : 0) + transitionParams.photoImageFromHeight + dp(6); linkPreviewY += diff * (1f - transitionParams.animateChangeProgress); } } else { float yProgress = 1f; if (transitionParams != null && transitionParams.animateSmallImage) { yProgress = transitionParams.animateChangeProgress; } if (linkPreviewY != startY) { linkPreviewY += yProgress * dp(2); } int photoWidth = width - dp(17); float tx = 0; if (!isSmallImage && drawInstantViewType == 17) { AndroidUtilities.rectTmp2.set(linkX + dp(10), linkPreviewY, linkX + dp(10) + photoWidth, linkPreviewY + (int) photoImage.getImageHeight()); AndroidUtilities.rectTmp.set(AndroidUtilities.rectTmp2); if (gradientDrawable == null) { if (currentPhotoObject != null && currentPhotoObject.gradientTopColor != 0 && currentPhotoObject.gradientBottomColor != 0) { gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{currentPhotoObject.gradientTopColor, currentPhotoObject.gradientBottomColor}); } else if (photoImage.getBitmap() != null) { int[] colors = DominantColors.getColorsSync(false, photoImage.getBitmap(), Theme.isCurrentThemeDark()); gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors); if (currentPhotoObject != null) { currentPhotoObject.gradientTopColor = colors[0]; currentPhotoObject.gradientBottomColor = colors[1]; } } } if (gradientDrawable != null) { canvas.save(); if (drillHolePath != null) { drillHolePath.rewind(); } else { drillHolePath = new Path(); } drillHolePath.addRoundRect(AndroidUtilities.rectTmp, dp(4), dp(4), Path.Direction.CW); canvas.clipPath(drillHolePath); gradientDrawable.setBounds(AndroidUtilities.rectTmp2); gradientDrawable.draw(canvas); canvas.restore(); } tx = (instantWidth - photoImage.getImageWidth() - dp(10) - (transitionParams == null ? 0 : (currentMessageObject.isOutOwner() ? transitionParams.deltaLeft : -transitionParams.deltaRight))) / 2f; } if (imageBackgroundSideColor != 0) { int x = linkX + dp(10); photoImage.setImageX(tx + x + (imageBackgroundSideWidth - photoImage.getImageWidth()) / 2); photoImage.setImageY(linkPreviewY); rect.set(x, photoImage.getImageY(), x + imageBackgroundSideWidth, photoImage.getImageY2()); Theme.chat_instantViewPaint.setColor(ColorUtils.setAlphaComponent(imageBackgroundSideColor, (int) (255 * alpha))); canvas.drawRoundRect(rect, dp(4), dp(4), Theme.chat_instantViewPaint); } else { photoImage.setImageX(tx + linkX + dp(10)); photoImage.setImageY(linkPreviewY); } if (drawInstantViewType != 17) { if (transitionParams != null && transitionParams.animateSmallImage) { if (!isSmallImage && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { photoImage.setImageWidth((int) AndroidUtilities.lerp(transitionParams.photoImageFromWidth, photoWidth, transitionParams.animateChangeProgress)); } photoImage.setImageX(AndroidUtilities.lerp(transitionParams.photoImageFromCenterX, photoImage.getCenterX(), transitionParams.animateChangeProgress) - photoImage.getImageWidth() / 2f); photoImage.setImageY(AndroidUtilities.lerp(transitionParams.photoImageFromCenterY, photoImage.getCenterY(), transitionParams.animateChangeProgress) - photoImage.getImageHeight() / 2f); } else if (!isSmallImage && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { photoImage.setImageWidth(photoWidth); } } if (imageBackgroundColor != 0) { rect.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); if (imageBackgroundGradientColor1 != 0) { if (imageBackgroundGradientColor2 != 0) { if (motionBackgroundDrawable == null) { motionBackgroundDrawable = new MotionBackgroundDrawable(imageBackgroundColor, imageBackgroundGradientColor1, imageBackgroundGradientColor2, imageBackgroundGradientColor3, true); if (imageBackgroundIntensity < 0) { photoImage.setGradientBitmap(motionBackgroundDrawable.getBitmap()); } if (!photoImage.hasImageSet()) { motionBackgroundDrawable.setRoundRadius(dp(4)); } } } else { if (gradientShader == null) { Rect r = BackgroundGradientDrawable.getGradientPoints(AndroidUtilities.getWallpaperRotation(imageBackgroundGradientRotation, false), (int) rect.width(), (int) rect.height()); gradientShader = new LinearGradient(r.left, r.top, r.right, r.bottom, new int[]{imageBackgroundColor, imageBackgroundGradientColor1}, null, Shader.TileMode.CLAMP); } Theme.chat_instantViewPaint.setShader(gradientShader); if (alpha != 1f) { Theme.chat_instantViewPaint.setAlpha((int) (255 * alpha)); } } } else { Theme.chat_instantViewPaint.setShader(null); Theme.chat_instantViewPaint.setColor(imageBackgroundColor); if (alpha != 1f) { Theme.chat_instantViewPaint.setAlpha((int) (255 * alpha)); } } if (motionBackgroundDrawable != null) { motionBackgroundDrawable.setBounds((int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom); motionBackgroundDrawable.draw(canvas); } else if (imageBackgroundSideColor != 0) { canvas.drawRect(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2(), Theme.chat_instantViewPaint); } else { canvas.drawRoundRect(rect, dp(4), dp(4), Theme.chat_instantViewPaint); } Theme.chat_instantViewPaint.setShader(null); Theme.chat_instantViewPaint.setAlpha(255); } if (drawPhotoImage && drawInstantView && drawInstantViewType != 9) { if (drawImageButton) { int size = dp(48); buttonX = this.buttonX = (int) (photoImage.getImageX() + (photoImage.getImageWidth() - size) / 2.0f); buttonY = this.buttonY = (int) (photoImage.getImageY() + (photoImage.getImageHeight() - size) / 2.0f); radialProgress.setProgressRect((int) buttonX, (int) buttonY, (int) buttonX + size, (int) buttonY + size); } if (delegate == null || delegate.getPinchToZoomHelper() == null || !delegate.getPinchToZoomHelper().isInOverlayModeFor(this)) { if (alpha != 1f) { photoImage.setAlpha(alpha); if (allowDrawPhotoImage()) { imageDrawn = photoImage.draw(canvas); } else { imageDrawn = true; } if (currentMessageObject.hasMediaSpoilers()) { blurredPhotoImage.setAlpha(alpha); drawBlurredPhoto(canvas); blurredPhotoImage.setAlpha(1f); } photoImage.setAlpha(1f); } else { if (allowDrawPhotoImage()) { imageDrawn = photoImage.draw(canvas); } else { imageDrawn = true; } if (currentMessageObject.hasMediaSpoilers()) { drawBlurredPhoto(canvas); } } } } if (transitionParams != null && transitionParams.animateChange) { linkPreviewY += yProgress * (transitionParams.animateToImageH + dp(6)); } else { linkPreviewY += yProgress * (photoImage.getImageHeight() + dp(6)); } } } if (currentMessageObject.isOutOwner()) { Theme.chat_replyNamePaint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_messageTextOut), (int) (255 * alpha))); Theme.chat_replyTextPaint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_messageTextOut), (int) (255 * alpha))); } else { Theme.chat_replyNamePaint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_messageTextIn), (int) (255 * alpha))); Theme.chat_replyTextPaint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_messageTextIn), (int) (255 * alpha))); } if (titleLayout != null) { float oy = 0; if (linkPreviewY != startY) { linkPreviewY += dp(4); oy = dp(1); } if (smallImageStartY == 0) { smallImageStartY = linkPreviewY - dp(1); } canvas.save(); canvas.translate(linkX + dp(10) + (Math.abs(titleLayoutLeft) > 1 ? width - dp(20) - titleLayoutWidth - titleLayoutLeft : 0), linkPreviewY - dp(3) + (!transitionParams.animateLinkPreviewY ? -transitionParams.deltaTop + transitionParams.deltaBottom : 0)); TextPaint paint = titleLayout.getPaint(); int wasAlpha = paint.getAlpha(); paint.setAlpha((int) (wasAlpha * alpha)); SpoilerEffect.layoutDrawMaybe(titleLayout, canvas); paint.setAlpha(wasAlpha); canvas.restore(); linkPreviewY += titleLayout.getLineBottom(titleLayout.getLineCount() - 1); } if (authorLayout != null) { if (linkPreviewY != startY) { linkPreviewY += dp(2); } if (smallImageStartY == 0) { smallImageStartY = linkPreviewY - dp(1); } canvas.save(); canvas.translate(linkX + dp(10) + (Math.abs(authorLayoutLeft) > 1 ? width - dp(20) - authorLayoutWidth - authorLayoutLeft : 0), linkPreviewY - dp(3) + (!transitionParams.animateLinkPreviewY ? -transitionParams.deltaTop + transitionParams.deltaBottom : 0)); TextPaint paint = authorLayout.getPaint(); int wasAlpha = paint.getAlpha(); paint.setAlpha((int) (wasAlpha * alpha)); SpoilerEffect.layoutDrawMaybe(authorLayout, canvas); paint.setAlpha(wasAlpha); canvas.restore(); linkPreviewY += authorLayout.getLineBottom(authorLayout.getLineCount() - 1); } if (descriptionLayout != null) { if (linkPreviewY != startY) { linkPreviewY += dp(2); } if (smallImageStartY == 0) { smallImageStartY = linkPreviewY - dp(1); } descriptionY = linkPreviewY - dp(3); canvas.save(); canvas.translate(linkX + dp(10) + (Math.abs(descriptionLayoutLeft) > 1 ? width - dp(20) - descriptionLayoutWidth - descriptionLayoutLeft : 0), descriptionY + (!transitionParams.animateLinkPreviewY ? -transitionParams.deltaTop + transitionParams.deltaBottom : 0)); if (linkBlockNum == -10) { if (links.draw(canvas)) { invalidate(); } } drawProgressLoadingLink(canvas, -2); if (delegate != null && delegate.getTextSelectionHelper() != null && getDelegate().getTextSelectionHelper().isSelected(currentMessageObject)) { delegate.getTextSelectionHelper().drawDescription(currentMessageObject.isOutOwner(), descriptionLayout, canvas); } TextPaint paint = descriptionLayout.getPaint(); if (drawInstantButtonInside && currentMessageObject != null && !currentMessageObject.isOutOwner() && linkLine != null) { paint.linkColor = linkLine.getColor(); } int wasAlpha = paint.getAlpha(); paint.setAlpha((int) (wasAlpha * alpha)); SpoilerEffect.layoutDrawMaybe(descriptionLayout, canvas); paint.setAlpha(wasAlpha); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(1, descriptionLayout.getPaint().getColor())); canvas.restore(); paint.linkColor = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_messageLinkOut : Theme.key_chat_messageLinkIn); linkPreviewY += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); } if (drawPhotoImage && drawPhotoImageAfter) { if (linkPreviewY != startY) { linkPreviewY += dp(2); } final int photoWidth = width - dp(17); if (isSmallImage) { photoImage.setImageX(linkX + width - photoImage.getImageWidth() - dp(6)); photoImage.setImageY(smallImageStartY); } else { photoImage.setImageX(linkX + (hasInvoicePreview ? -dp(6.3f) : dp(10))); photoImage.setImageY(linkPreviewY); } if (transitionParams != null && transitionParams.animateSmallImage) { if (!isSmallImage && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { photoImage.setImageWidth((int) AndroidUtilities.lerp(transitionParams.photoImageFromWidth, photoWidth, transitionParams.animateChangeProgress)); } photoImage.setImageX(AndroidUtilities.lerp(transitionParams.photoImageFromCenterX, photoImage.getCenterX(), transitionParams.animateChangeProgress) - photoImage.getImageWidth() / 2f); photoImage.setImageY(AndroidUtilities.lerp(transitionParams.photoImageFromCenterY, photoImage.getCenterY(), transitionParams.animateChangeProgress) - photoImage.getImageHeight() / 2f); } else if (!isSmallImage && documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { photoImage.setImageWidth(photoWidth); } if (!isSmallImage && drawImageButton) { int size = dp(48); buttonX = this.buttonX = (int) (photoImage.getImageX() + (photoImage.getImageWidth() - size) / 2.0f); buttonY = this.buttonY = (int) (photoImage.getImageY() + (photoImage.getImageHeight() - size) / 2.0f); radialProgress.setProgressRect((int) buttonX, (int) buttonY, (int) buttonX + size, (int) buttonY + size); } if (isRoundVideo && MediaController.getInstance().isPlayingMessage(currentMessageObject) && MediaController.getInstance().isVideoDrawingReady() && canvas.isHardwareAccelerated()) { imageDrawn = true; drawTime = true; } else { if (delegate == null || delegate.getPinchToZoomHelper() == null || !delegate.getPinchToZoomHelper().isInOverlayModeFor(this)) { if (alpha != 1f) { photoImage.setAlpha(alpha); if (allowDrawPhotoImage()) { imageDrawn = photoImage.draw(canvas); } else { imageDrawn = true; } if (currentMessageObject.hasMediaSpoilers()) { blurredPhotoImage.setAlpha(alpha); drawBlurredPhoto(canvas); blurredPhotoImage.setAlpha(1f); } photoImage.setAlpha(1f); } else { if (allowDrawPhotoImage()) { imageDrawn = photoImage.draw(canvas); } else { imageDrawn = true; } if (currentMessageObject.hasMediaSpoilers()) { drawBlurredPhoto(canvas); } } } } } if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { videoButtonX = (int) (photoImage.getImageX() + dp(8)); videoButtonY = (int) (photoImage.getImageY() + dp(8)); videoRadialProgress.setProgressRect(videoButtonX, videoButtonY, videoButtonX + dp(24), videoButtonY + dp(24)); } Paint timeBackgroundPaint = getThemedPaint(Theme.key_paint_chatTimeBackground); if (photosCountLayout != null && photoImage.getVisible()) { int x = (int) (photoImage.getImageX() + photoImage.getImageWidth() - dp(8) - photosCountWidth); int y = (int) (photoImage.getImageY() + photoImage.getImageHeight() - dp(19)); rect.set(x - dp(4), y - dp(1.5f), x + photosCountWidth + dp(4), y + dp(14.5f)); int oldAlpha = timeBackgroundPaint.getAlpha(); timeBackgroundPaint.setAlpha((int) (oldAlpha * controlsAlpha)); Theme.chat_durationPaint.setAlpha((int) (255 * controlsAlpha)); canvas.drawRoundRect(rect, dp(4), dp(4), timeBackgroundPaint); timeBackgroundPaint.setAlpha(oldAlpha); canvas.save(); canvas.translate(x, y); photosCountLayout.draw(canvas); canvas.restore(); Theme.chat_durationPaint.setAlpha(255); } if (videoInfoLayout != null && (!drawPhotoImage || photoImage.getVisible()) && imageBackgroundSideColor == 0) { int x; int y; if (hasGamePreview || hasInvoicePreview || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER) { if (drawPhotoImage) { x = (int) (photoImage.getImageX() + dp(8.5f)); y = (int) (photoImage.getImageY() + dp(6)); int height = dp(documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER ? 14.5f : 16.5f); rect.set(x - dp(4), y - dp(1.5f), x + durationWidth + dp(4), y + height); canvas.drawRoundRect(rect, dp(4), dp(4), timeBackgroundPaint); } else { x = linkX; y = linkPreviewY; } } else { x = (int) (photoImage.getImageX() + photoImage.getImageWidth() - dp(8) - durationWidth); y = (int) (photoImage.getImageY() + photoImage.getImageHeight() - dp(19)); rect.set(x - dp(4), y - dp(1.5f), x + durationWidth + dp(4), y + dp(14.5f)); canvas.drawRoundRect(rect, dp(4), dp(4), getThemedPaint(Theme.key_paint_chatTimeBackground)); } canvas.save(); canvas.translate(x, y); if (hasInvoicePreview) { if (drawPhotoImage) { Theme.chat_shipmentPaint.setColor(getThemedColor(Theme.key_chat_previewGameText)); } else { if (currentMessageObject.isOutOwner()) { Theme.chat_shipmentPaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); } else { Theme.chat_shipmentPaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); } } } videoInfoLayout.draw(canvas); canvas.restore(); } drawVideoTimestamps(canvas, linkLine.getColor()); giveawayMessageCell.draw(canvas, namesOffset, linkX, resourcesProvider); giveawayResultsMessageCell.draw(canvas, namesOffset, linkX, resourcesProvider); if (drawInstantView) { Drawable instantDrawable; if (currentMessageObject.isOutOwner()) { final int color = getThemedColor(Theme.key_chat_outPreviewInstantText); if (this.instantDrawable == null) { if (drawInstantViewType == 27) { this.instantDrawable = getContext().getResources().getDrawable(R.drawable.mini_call_join).mutate(); } else { this.instantDrawable = getThemedDrawable(Theme.key_drawable_msgOutInstant); } this.instantDrawable.setColorFilter(new PorterDuffColorFilter(this.instantDrawableColor = color, PorterDuff.Mode.SRC_IN)); } if (this.instantDrawableColor != color) { this.instantDrawable.setColorFilter(new PorterDuffColorFilter(this.instantDrawableColor = color, PorterDuff.Mode.SRC_IN)); } instantDrawable = this.instantDrawable; Theme.chat_instantViewPaint.setColor(color); Theme.chat_instantViewButtonPaint.setColor(Theme.multAlpha(color, .10f)); if (instantButtonLoading != null) { instantButtonLoading.setColors( Theme.multAlpha(color, .1f), Theme.multAlpha(color, .3f), Theme.multAlpha(color, .3f), Theme.multAlpha(color, 1.2f) ); } } else { int color = getThemedColor(Theme.key_chat_inPreviewInstantText); if (linkLine != null && !currentMessageObject.isUnsupported()) { color = linkLine.getColor(); } if (this.instantDrawable == null) { if (drawInstantViewType == 16) { this.instantDrawable = getContext().getResources().getDrawable(R.drawable.mini_external_link).mutate(); } else if (drawInstantViewType == 27) { this.instantDrawable = getContext().getResources().getDrawable(R.drawable.mini_call_join).mutate(); } else { this.instantDrawable = getContext().getResources().getDrawable(R.drawable.msg_instant).mutate(); } this.instantDrawable.setColorFilter(new PorterDuffColorFilter(this.instantDrawableColor = color, PorterDuff.Mode.SRC_IN)); } if (this.instantDrawableColor != color) { this.instantDrawable.setColorFilter(new PorterDuffColorFilter(this.instantDrawableColor = color, PorterDuff.Mode.SRC_IN)); } instantDrawable = this.instantDrawable; Theme.chat_instantViewPaint.setColor(color); Theme.chat_instantViewButtonPaint.setColor(Theme.multAlpha(color, .10f)); if (instantButtonLoading != null) { instantButtonLoading.setColors( Theme.multAlpha(color, .1f), Theme.multAlpha(color, .3f), Theme.multAlpha(color, .3f), Theme.multAlpha(color, 1.2f) ); } } if (drawInstantButtonInside) { int instantY = startY + linkPreviewHeight + dp(14); int wasAlpha = Theme.chat_instantViewPaint.getAlpha(); Theme.chat_instantViewPaint.setAlpha((int) (wasAlpha * .18f)); canvas.drawRect(linkX + dp(3 + 7), startY + linkPreviewHeight + dp(2), linkX + width - dp(7), startY + linkPreviewHeight + dp(2) + Math.max(1, dp(0.66f)), Theme.chat_instantViewPaint); Theme.chat_instantViewPaint.setAlpha(wasAlpha); final float textWidth = dp(drawInstantViewType == 27 ? 20 : drawInstantViewType == 0 ? 15 : 0) + instantViewLayoutWidth; float l = linkX + (width - textWidth) / 2f; if (drawInstantViewType == 0) { setDrawableBounds(instantDrawable, l, instantY + dp(1), dp(9), dp(13)); instantDrawable.setAlpha((int) (0xFF * alpha)); instantDrawable.draw(canvas); l += dp(15); } else if (drawInstantViewType == 27) { setDrawableBounds(instantDrawable, l, instantY, instantDrawable.getIntrinsicWidth(), instantDrawable.getIntrinsicHeight()); instantDrawable.setAlpha((int) (0xFF * alpha)); instantDrawable.draw(canvas); l += dp(20); } else if (drawInstantViewType == 16) { l -= dp(11f); setDrawableBounds(instantDrawable, l + textWidth + dp(4f), instantY - dp(2f), dp(18), dp(18)); instantDrawable.setAlpha((int) (0xFF * alpha)); instantDrawable.draw(canvas); } if (instantViewLayout != null) { canvas.save(); canvas.translate(l - instantViewLayoutLeft, instantY); SpoilerEffect.layoutDrawMaybe(instantViewLayout, canvas); canvas.restore(); } } else { int instantY = startY + linkPreviewHeight + dp(currentMessageObject.isUnsupported() ? -5 : 10); if (instantButtonLoading != null && !loading && !instantButtonLoading.isDisappeared() && !instantButtonLoading.isDisappearing()) { instantButtonLoading.disappear(); } if (instantButtonLoading == null && loading) { instantButtonLoading = new LoadingDrawable(); instantButtonLoading.strokePaint.setStrokeWidth(dp(1.25f)); instantButtonLoading.setAppearByGradient(true); } else if (instantButtonLoading != null && loading && (instantButtonLoading.isDisappeared() || instantButtonLoading.isDisappearing())) { instantButtonLoading.reset(); instantButtonLoading.resetDisappear(); } instantButtonRect.set(linkX, instantY, linkX + instantWidth, instantY + dp(36)); float scale = instantButtonBounce.getScale(.02f); boolean scaleRestore = scale != 1; if (scaleRestore) { canvas.save(); canvas.scale(scale, scale, instantButtonRect.centerX(), instantButtonRect.centerY()); } selectorDrawableMaskType[0] = 0; createSelectorDrawable(0); selectorDrawable[0].setBounds(linkX, instantY, linkX + instantWidth, instantY + dp(36)); selectorDrawable[0].draw(canvas); if (instantButtonLoading != null && !instantButtonLoading.isDisappeared()) { instantButtonLoading.setBounds(instantButtonRect); instantButtonLoading.setRadiiDp(6); instantButtonLoading.draw(canvas); invalidate(); } canvas.drawRoundRect(instantButtonRect, dp(6), dp(6), Theme.chat_instantViewButtonPaint); if (drawInstantViewType == 0) { setDrawableBounds(instantDrawable, instantTextLeftX + instantTextX + linkX - dp(15), instantY + dp(11.5f), dp(9), dp(13)); instantDrawable.setAlpha((int) (0xFF * alpha)); instantDrawable.draw(canvas); } else if (drawInstantViewType == 16) { if (instantLinkArrowPaint == null) { instantLinkArrowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); instantLinkArrowPaint.setStyle(Paint.Style.STROKE); instantLinkArrowPaint.setStrokeCap(Paint.Cap.ROUND); instantLinkArrowPaint.setStrokeJoin(Paint.Join.ROUND); } instantLinkArrowPaint.setColor(Theme.chat_instantViewPaint.getColor()); instantLinkArrowPaint.setStrokeWidth(AndroidUtilities.dpf2(1.333f)); if (instantLinkArrowPath == null) { instantLinkArrowPath = new Path(); } else { instantLinkArrowPath.rewind(); } instantLinkArrowPath.moveTo(instantButtonRect.right - dp(6 + 5), instantButtonRect.top + dp(6)); instantLinkArrowPath.lineTo(instantButtonRect.right - dp(6), instantButtonRect.top + dp(6)); instantLinkArrowPath.lineTo(instantButtonRect.right - dp(6), instantButtonRect.top + dp(6 + 5)); instantLinkArrowPath.moveTo(instantButtonRect.right - AndroidUtilities.dpf2(6 + 5.66f), instantButtonRect.top + dp(6 + 5.66f)); instantLinkArrowPath.lineTo(instantButtonRect.right - dp(6), instantButtonRect.top + dp(6)); canvas.drawPath(instantLinkArrowPath, instantLinkArrowPaint); } if (instantViewLayout != null) { canvas.save(); canvas.translate(linkX + instantTextX, instantY + dp(10.5f)); SpoilerEffect.layoutDrawMaybe(instantViewLayout, canvas); canvas.restore(); } if (scaleRestore) { canvas.restore(); } } } canvas.restoreToCount(restoreCount); } public void drawFactCheck(Canvas canvas, float alpha) { if (currentPosition != null && !currentPosition.last) { return; } float factCheckAlpha = hasFactCheck ? 1f : 0f; if (transitionParams.animateFactCheck) { factCheckAlpha = AndroidUtilities.lerp(1f - factCheckAlpha, factCheckAlpha, transitionParams.animateChangeProgress); } alpha *= factCheckAlpha; if (alpha <= 0) return; final float right = getBackgroundDrawableRight() + (transitionParams != null ? transitionParams.deltaRight : 0) - dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) - getExtraTextX(); int x, y; if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { x = (int) captionX; } else if (currentMessageObject.isOutOwner()) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { x -= Math.max(0, x + Math.max(replyNameWidth, replyTextWidth) + dp(14) - AndroidUtilities.displaySize.x); } } else { if (mediaBackground) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { x = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } x += transitionParams.deltaLeft; x -= dp(1.33f); y = this.factCheckY; // if (transitionParams.animateLinkPreviewY) { // final int animatedStartY = AndroidUtilities.lerp(transitionParams.animateFromLinkPreviewY, startY, transitionParams.animateChangeProgress); // linkPreviewYDiff = animatedStartY - startY; // y = animatedStartY; // } final int width = (int) (right - x); int smallImageStartY = 0; int height = factCheckHeight; if (transitionParams.animateFactCheckHeight) { height = AndroidUtilities.lerp(transitionParams.animateFactCheckHeightFrom, factCheckHeight, transitionParams.animateChangeProgress); } float expanded = !factCheckLarge || getPrimaryMessageObject() != null && getPrimaryMessageObject().factCheckExpanded ? 1f : 0f; if (transitionParams.animateFactCheckExpanded) { expanded = AndroidUtilities.lerp(1f - expanded, expanded, transitionParams.animateChangeProgress); } if (factCheckLine == null) { factCheckLine = new ReplyMessageLine(this); } int textColor = factCheckLine.setFactCheck(resourcesProvider); canvas.save(); canvas.translate(x, y); AndroidUtilities.rectTmp.set(0, 0, width, height); final float s = factCheckBounce != null ? factCheckBounce.getScale(0.01f) : 1f; canvas.scale(s, s, AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY()); factCheckLine.drawBackground(canvas, AndroidUtilities.rectTmp, 5, 5, 5, alpha, false, false); factCheckLine.drawLine(canvas, AndroidUtilities.rectTmp, alpha); if (factCheckTitle != null) { factCheckTitle.draw(canvas, dp(10), dp(12), textColor, alpha); if (factCheckWhat != null) { final int bx = (int) (dp(10) + factCheckTitle.getCurrentWidth() + dp(4)); AndroidUtilities.rectTmp.set(bx, dp(4.33f), bx + dp(10) + factCheckWhat.getCurrentWidth(), dp(4.33f + 17.33f)); final float s2 = factCheckWhatBounce != null ? factCheckWhatBounce.getScale(0.1f) : 1f; canvas.save(); canvas.scale(s2, s2, AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY()); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(17), dp(17), factCheckLine.backgroundPaint); factCheckWhat.draw(canvas, bx + dp(5), dp(12), textColor, alpha); canvas.restore(); } } canvas.restore(); } public void drawFactCheckText(Canvas canvas, float alpha) { if (currentPosition != null && !currentPosition.last) { return; } float factCheckAlpha = hasFactCheck ? 1f : 0f; if (transitionParams.animateFactCheck) { factCheckAlpha = AndroidUtilities.lerp(1f - factCheckAlpha, factCheckAlpha, transitionParams.animateChangeProgress); } alpha *= factCheckAlpha; if (alpha <= 0) return; final float right = getBackgroundDrawableRight() + (transitionParams != null ? transitionParams.deltaRight : 0) - dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) - getExtraTextX(); int x, y; if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { x = (int) captionX; } else if (currentMessageObject.isOutOwner()) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { x -= Math.max(0, x + Math.max(replyNameWidth, replyTextWidth) + dp(14) - AndroidUtilities.displaySize.x); } } else { if (mediaBackground) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { x = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } x += transitionParams.deltaLeft; x -= dp(1.33f); y = this.factCheckY; final int width = (int) (right - x); int smallImageStartY = 0; int height = factCheckHeight; if (transitionParams.animateFactCheckHeight) { height = AndroidUtilities.lerp(transitionParams.animateFactCheckHeightFrom, factCheckHeight, transitionParams.animateChangeProgress); } float expanded = !factCheckLarge || getPrimaryMessageObject() != null && getPrimaryMessageObject().factCheckExpanded ? 1f : 0f; if (transitionParams.animateFactCheckExpanded) { expanded = AndroidUtilities.lerp(1f - expanded, expanded, transitionParams.animateChangeProgress); } if (factCheckLine == null) { factCheckLine = new ReplyMessageLine(this); } int textColor = factCheckLine.setFactCheck(resourcesProvider); canvas.save(); canvas.translate(x, y); AndroidUtilities.rectTmp.set(0, 0, width, height); final float s = factCheckBounce != null ? factCheckBounce.getScale(0.01f) : 1f; canvas.scale(s, s, AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY()); if (factCheckTextLayout != null) { if (factCheckLarge) { canvas.saveLayerAlpha(0, 0, width, height - 1, 0xFF, Canvas.ALL_SAVE_FLAG); } canvas.save(); canvas.translate(dp(10) - factCheckTextLayoutLeft, dp(22)); Theme.chat_replyTextPaint.linkColor = textColor; if (factCheckLinks != null && factCheckLinks.draw(canvas)) { invalidateOutbounds(); } if (currentMessageObject.isOutOwner()) { Theme.chat_replyTextPaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); } else { Theme.chat_replyTextPaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); } int oldAlpha = Theme.chat_replyTextPaint.getAlpha(); Theme.chat_replyTextPaint.setAlpha((int) (oldAlpha * alpha)); if (delegate != null && delegate.getTextSelectionHelper() != null && getDelegate().getTextSelectionHelper().isSelected(currentMessageObject)) { delegate.getTextSelectionHelper().drawFactCheck(currentMessageObject.isOutOwner(), factCheckTextLayout, canvas); } factCheckTextLayout.draw(canvas); canvas.restore(); Theme.chat_replyTextPaint.setAlpha(oldAlpha); AndroidUtilities.rectTmp.set(dp(10), dp(22) + factCheckTextLayoutHeight + dp(6.33f), width - dp(10), dp(22) + factCheckTextLayoutHeight + dp(6.33f) + 1); Theme.chat_titleLabelTextPaint.setColor(textColor); Theme.chat_titleLabelTextPaint.setAlpha((int) (Theme.chat_titleLabelTextPaint.getAlpha() * .5f * alpha)); canvas.drawRect(AndroidUtilities.rectTmp, Theme.chat_titleLabelTextPaint); canvas.save(); canvas.translate(dp(10) - factCheckText2LayoutLeft, dp(22) + factCheckTextLayoutHeight + dp(12.66f)); Theme.chat_titleLabelTextPaint.setColor(textColor); Theme.chat_titleLabelTextPaint.setAlpha((int) (Theme.chat_titleLabelTextPaint.getAlpha() * alpha)); factCheckText2Layout.draw(canvas); canvas.restore(); if (clip == null) { clip = new GradientClip(); } if (factCheckLarge) { canvas.save(); final int sz = dp(22) + factCheckTextLayoutHeight + dp(12.66f) < height ? dp(20) : dp(24); AndroidUtilities.rectTmp.set(0, height - dp(6.66f) - sz, width, height); clip.draw(canvas, AndroidUtilities.rectTmp, GradientClip.BOTTOM, (1f - expanded) * alpha); AndroidUtilities.rectTmp.set(width - dp(60), height - sz, width - dp(32), height); clip.draw(canvas, AndroidUtilities.rectTmp, GradientClip.RIGHT, (1f - expanded) * alpha); AndroidUtilities.rectTmp.set(width - dp(32), height - sz, width, height); canvas.drawRect(AndroidUtilities.rectTmp, clip.getPaint(GradientClip.RIGHT, (1f - expanded) * alpha)); canvas.restore(); canvas.restore(); } } if (factCheckLarge) { if (factCheckArrow == null) { factCheckArrow = getContext().getResources().getDrawable(R.drawable.arrow_more).mutate(); factCheckArrow.setColorFilter(new PorterDuffColorFilter(factCheckArrowColor = textColor, PorterDuff.Mode.SRC_IN)); } if (textColor != factCheckArrowColor) { factCheckArrow.setColorFilter(new PorterDuffColorFilter(factCheckArrowColor = textColor, PorterDuff.Mode.SRC_IN)); } canvas.save(); final int sz = dp(16); factCheckArrow.setBounds( width - sz - dp(4 + 3), height - sz - dp(2 + 3), width - dp(4 + 3), height - dp(2 + 3) ); canvas.rotate(AndroidUtilities.lerp(0, 180, expanded), factCheckArrow.getBounds().centerX(), factCheckArrow.getBounds().centerY()); factCheckArrow.setAlpha((int) (0xFF * alpha)); factCheckArrow.draw(canvas); canvas.restore(); } canvas.restore(); } private float isSmallImage() { if (transitionParams.animateSmallImage) { return isSmallImage ? transitionParams.animateChangeProgress : 1f - transitionParams.animateChangeProgress; } return isSmallImage ? 1f : 0f; } private boolean shouldDrawMenuDrawable() { return (currentMessagesGroup == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0) && !hasLinkPreview && (currentMessageObject == null || !currentMessageObject.isRepostPreview && !currentMessageObject.isSponsored()); } private void drawContact(Canvas canvas) { if (contactLine == null) { contactLine = new ReplyMessageLine(this); } int nameColor = contactLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_CONTACT); if (contactBounce == null) { contactBounce = new ButtonBounce(this, 2.0f, 2.0f); } int textX = (int) (photoImage.getImageX() - dp(13)); int instantY = layoutHeight - dp(62); if (!reactionsLayoutInBubble.isEmpty && !reactionsLayoutInBubble.isSmall) { instantY -= reactionsLayoutInBubble.totalHeight; } if (drawCommentButton) { instantY -= dp(shouldDrawTimeOnMedia() ? 39.3f : 41); } if (contactRect == null) { contactRect = new RectF(); } float width = getBackgroundDrawableRight() - (dp(10) + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? dp(6) : 0)) - getExtraTextX(); if (transitionParams.animateBackgroundBoundsInner) { width += transitionParams.deltaRight; } contactRect.set(textX, photoImage.getImageY() - dp(9), width, instantY + dp(38f)); final float scale = contactBounce.getScale(0.0125f); boolean needContactViewScale = scale != 1f; if (needContactViewScale) { canvas.save(); canvas.scale(scale, scale, contactRect.centerX(), contactRect.centerY()); } if (selectorDrawable[0] != null) { selectorDrawableMaskType[0] = 0; selectorDrawable[0].setBounds(textX, (int) (photoImage.getImageY() - dp(9)), (int) width, instantY + dp(38f)); if (selectorDrawableColor != Theme.multAlpha(contactLine.getColor(), .1f)) { Theme.setSelectorDrawableColor(selectorDrawable[0], selectorDrawableColor = Theme.multAlpha(contactLine.getColor(), .1f), true); } selectorDrawable[0].draw(canvas); } float radF = (float) Math.floor(SharedConfig.bubbleRadius / 3f); int rad = (int) radF; contactLine.drawBackground(canvas, contactRect, radF, radF, radF, 1f); contactLine.drawLine(canvas, contactRect, 1f); Theme.chat_contactNamePaint.setColor(nameColor); Theme.chat_contactPhonePaint.setColor(getThemedColor(Theme.key_chat_inContactPhoneSelectedText)); if (currentMessageObject.isOutOwner()) { Theme.chat_contactPhonePaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); } else { Theme.chat_contactPhonePaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); } if (titleLayout != null) { canvas.save(); canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + dp(9), dp(27) + namesOffset); SpoilerEffect.layoutDrawMaybe(titleLayout, canvas); canvas.restore(); } if (docTitleLayout != null) { canvas.save(); canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + dp(9), dp(50) + namesOffset); SpoilerEffect.layoutDrawMaybe(docTitleLayout, canvas); canvas.restore(); } if (contactButtons != null && contactButtons.size() > 0) { Theme.chat_instantViewPaint.setColor(nameColor); Theme.chat_instantViewButtonPaint.setColor(Theme.multAlpha(nameColor, .10f)); int wasAlpha = Theme.chat_instantViewPaint.getAlpha(); Theme.chat_instantViewPaint.setAlpha((int) (wasAlpha * .18f)); canvas.drawRect(contactRect.left + dp(3 + 7), instantY + dp(2), contactRect.right - dp(7), instantY + dp(2) + Math.max(1, dp(0.66f)), Theme.chat_instantViewPaint); Theme.chat_instantViewPaint.setAlpha(wasAlpha); instantY += dp(2); float instantButtonLeft = textX + dp(3); boolean needCreateSelectorDrawable = contactButtons != null && contactButtons.size() > 1; int rippleColor = contactLine.getBackgroundColor(); for (int i = 0; i < contactButtons.size(); i++) { InstantViewButton instantViewButton = contactButtons.get(i); float right = Math.min(instantButtonLeft + instantViewButton.buttonWidth, contactRect.right); instantViewButton.rect.set(instantButtonLeft, instantY, right, instantY + dp(36)); if (needCreateSelectorDrawable && instantViewButton.selectorDrawable == null) { instantViewButton.selectorDrawable = Theme.createRadSelectorDrawable(linkPreviewSelectorColor = rippleColor, 0, 0, i == (contactButtons.size() - 1) ? rad : 0, 0); instantViewButton.selectorDrawable.setCallback(this); } if (instantViewButton.selectorDrawable != null) { instantViewButton.selectorDrawable.setBounds((int) instantButtonLeft, instantY, (int) right, instantY + dp(36)); instantViewButton.selectorDrawable.draw(canvas); } float buttonScale = 1f; boolean needButtonScale = false; if (!needContactViewScale) { if (instantViewButton.buttonBounce != null) { buttonScale = instantViewButton.buttonBounce.getScale(0.02f); needButtonScale = buttonScale != 1; } } if (needButtonScale) { canvas.save(); canvas.scale(buttonScale, buttonScale, instantViewButton.rect.centerX(), instantViewButton.rect.centerY()); } if (instantViewButton.layout != null) { canvas.save(); canvas.translate(instantButtonLeft + instantViewButton.textX, instantY + dp(10.5f)); instantViewButton.layout.draw(canvas); canvas.restore(); } if (needButtonScale) { canvas.restore(); } instantButtonLeft += instantViewButton.buttonWidth; } } if (needContactViewScale) { canvas.restore(); } } private Paint botButtonPaint; private void drawBotButtons(Canvas canvas, ArrayList botButtons, int alpha) { if (SizeNotifierFrameLayout.drawingBlur) { return; } final int widthForButtons = getWidthForButtons(); int addX; if (currentMessageObject != null && currentMessageObject.isOutOwner()) { addX = getMeasuredWidth() - widthForButtons - dp(10); } else { addX = backgroundDrawableLeft + dp(mediaBackground || drawPinnedBottom ? 1 : 7); } if (transitionParams.animateBackgroundBoundsInner) { addX += transitionParams.deltaLeft; } float top = layoutHeight - dp(2) + transitionParams.deltaBottom; float height = 0; for (int a = 0; a < botButtons.size(); a++) { BotButton button = botButtons.get(a); int bottom = button.y + button.height; if (bottom > height) { height = bottom; } } rect.set(0, top, getMeasuredWidth(), top + height); if (alpha != 0xFF) { canvas.saveLayerAlpha(rect, alpha, Canvas.ALL_SAVE_FLAG); } else { canvas.save(); } boolean invalidate = false; for (int a = 0; a < botButtons.size(); a++) { BotButton button = botButtons.get(a); float y = button.y + layoutHeight - dp(2) + transitionParams.deltaBottom; float s = button.getPressScale(); if (button.isSeparator) { final float x1 = button.x * widthForButtons + addX; final float x2 = button.x * widthForButtons + addX + button.width * widthForButtons; final float totalWidth = x2 - x1; final int blockWidth = dp(3.66f); final int separatorsCount = Math.round((totalWidth - blockWidth) / dp(8.66f)); final float partWidth = (totalWidth - blockWidth) / separatorsCount; applyServiceShaderMatrix(); final float br = dp(1); for (int n = 0; n < separatorsCount + 1; n++) { rect.set(x1 + partWidth * n, y, x1 + partWidth * n + blockWidth, y + button.height); canvas.drawRoundRect(rect, br, br, getThemedPaint(Theme.key_paint_chatActionBackground)); if (hasGradientService()) { canvas.drawRoundRect(rect, br, br, Theme.chat_actionBackgroundGradientDarkenPaint); } } continue; } rect.set( button.x * widthForButtons + addX, y, button.x * widthForButtons + addX + button.width * widthForButtons, y + button.height ); applyServiceShaderMatrix(); final TL_keyboard.TL_inlineButtonTypeUrl buttonTypeUrl = TLKeyboardHelper.getType(button.button, TL_keyboard.TL_inlineButtonTypeUrl.class); boolean drawProgress = drawButtonProgress(button.button); if (button.buttonCustom != null && currentMessageObject != null) { if (button.buttonCustom.id == BotInlineKeyboard.ButtonCustom.SUGGESTION_ACCEPT) { drawProgress |= MessagesController.getInstance(currentAccount).isSendingSuggestedMessageApproval(currentMessageObject.getDialogId(), currentMessageObject.getId(), true); } else if (button.buttonCustom.id == BotInlineKeyboard.ButtonCustom.SUGGESTION_DECLINE) { drawProgress |= MessagesController.getInstance(currentAccount).isSendingSuggestedMessageApproval(currentMessageObject.getDialogId(), currentMessageObject.getId(), false); } } if (button.draw(canvas, rect, drawProgress, hasInvoicePreview && hasInvoicePrice, resourcesProvider)) { invalidate = true; } } canvas.restore(); if (invalidate) { invalidateOutbounds(); } } public final boolean drawButtonProgress(TL_keyboard.KeyboardButtonProto button) { if (TLKeyboardHelper.isType(button, TL_keyboard.TL_inlineButtonTypeCallback.class) || TLKeyboardHelper.isType(button, TL_keyboard.TL_inlineButtonTypeGame.class) || TLKeyboardHelper.isType(button, TL_keyboard.TL_inlineButtonTypeBuy.class) || TLKeyboardHelper.isType(button, TL_keyboard.TL_inlineButtonTypeUrlAuth.class)) { return SendMessagesHelper.getInstance(currentAccount).isSendingCallback(currentMessageObject, button); } if (TLKeyboardHelper.isType(button, TL_keyboard.TL_buttonTypeRequestGeoLocation.class)) { return SendMessagesHelper.getInstance(currentAccount).isSendingCurrentLocation(currentMessageObject, button); } final TL_keyboard.TL_inlineButtonTypeUrl url = TLKeyboardHelper.getType(button, TL_keyboard.TL_inlineButtonTypeUrl.class); if (url != null && delegate != null) { return delegate.isProgressLoading(this, ChatActivity.PROGRESS_BOT_BUTTON) && TextUtils.equals(delegate.getProgressLoadingBotButtonUrl(this), url.url); } return false; } private boolean allowDrawPhotoImage() { return !currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0f || blurredPhotoImage.getBitmap() == null; } public void layoutTextXY(boolean parent) { if (currentMessageObject.isOutOwner()) { textX = (parent ? (int) (backgroundDrawableLeft + transitionParams.deltaLeft) : getCurrentBackgroundLeft()) + dp(11) + getExtraTextX(); } else { textX = (parent ? (int) (backgroundDrawableLeft + transitionParams.deltaLeft) : getCurrentBackgroundLeft()) + (currentMessageObject.type == MessageObject.TYPE_EMOJIS ? 0 : dp(!mediaBackground && drawPinnedBottom ? 11 : 17)) + getExtraTextX(); } if (hasGamePreview) { textX += dp(11); textY = dp(14) + namesOffset; if (siteNameLayout != null) { textY += siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1); } } else if (hasInvoicePreview) { textY = dp(14) + namesOffset; if (siteNameLayout != null) { textY += siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1); } } else if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { textY = dp(6) + namesOffset; if (!currentMessageObject.isOut()) { textX = getCurrentBackgroundLeft(); } else { textX -= dp(4); } } else { textY = dp(8) + namesOffset; if (currentMessageObject.type == MessageObject.TYPE_ARTICLE) { if (currentMessageObject.richLayout != null && currentMessageObject.richLayout.startsWithMedia()) { textY += dp(namesOffset <= 0 ? -3 : 2); } } else { if (currentMessageObject.hasCodeAtTop && SharedConfig.bubbleRadius > 10) { textY += dp(SharedConfig.bubbleRadius < 15 ? 1 : 2); } if (currentMessageObject.hasCodeAtTop && namesOffset > 0) { textY += dp(5); } } } if (currentMessageObject.isSponsored()) { linkPreviewY = textY + dp(14); } else if (linkPreviewAbove) { linkPreviewY = textY + dp(10); textY += linkPreviewHeight + dp(13); if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { textY += dp(44); } } else { linkPreviewY = textY + currentMessageObject.textHeight(transitionParams) + dp(10); } factCheckY = linkPreviewAbove ? textY + currentMessageObject.textHeight(transitionParams) + dp(10) : linkPreviewY + linkPreviewHeight + dp(drawInstantView ? 46 : 0) + dp(linkPreviewHeight > 0 ? 4 : -8); unmovedTextX = textX; if (currentMessageObject.textXOffset != 0 && replyNameLayout != null) { int diff = backgroundWidth - dp(31) - currentMessageObject.textWidth; if (!hasNewLineForTime) { diff -= timeWidth + dp(4 + (currentMessageObject.isOutOwner() ? 20 : 0)); } if (diff > 0) { textX += diff - getExtraTimeX(); } } } public void drawMessageText(Canvas canvas) { if (currentMessageObject == null || currentMessageObject.isSponsored()) { return; } float textY = this.textY; if (transitionParams.animateTextY) { textY = transitionParams.animateFromTextY * (1f - transitionParams.animateChangeProgress) + this.textY * transitionParams.animateChangeProgress; } if (transitionParams.animateChangeProgress != 1.0f && transitionParams.animateMessageText) { canvas.save(); if (currentBackgroundDrawable != null) { Rect r = currentBackgroundDrawable.getBounds(); if (currentMessageObject.isOutOwner() && !mediaBackground && !pinnedBottom) { canvas.clipRect( r.left + dp(4), r.top + dp(4), r.right - dp(10), r.bottom - dp(4) ); } else { canvas.clipRect( r.left + dp(4), r.top + dp(4), r.right - dp(4), r.bottom - dp(4) ); } } if (botDraftTypingAnimator != null && botDraftTypingAnimator.isRunning()) { drawMessageText(textX, textY, canvas, currentMessageObject.textLayoutBlocks, currentMessageObject.textXOffset, true, 1, true, false, false); } else { drawMessageText(textX, textY, canvas, transitionParams.animateOutTextBlocks, transitionParams.animateOutTextXOffset, false, (1.0f - transitionParams.animateChangeProgress), true, false, false); drawMessageText(textX, textY, canvas, currentMessageObject.textLayoutBlocks, currentMessageObject.textXOffset, true, transitionParams.animateChangeProgress, true, false, false); } canvas.restore(); } else if (transitionParams.animateLinkAbove && currentBackgroundDrawable != null) { float oldTextY = textY; if (transitionParams.animateLinkAbove) { textY = this.textY + (linkPreviewAbove ? 1 : -1) * currentMessageObject.textHeight(transitionParams) * (1f - transitionParams.animateChangeProgress); oldTextY = transitionParams.animateFromTextY - (linkPreviewAbove ? 1 : -1) * currentMessageObject.textHeight(transitionParams) * transitionParams.animateChangeProgress; } canvas.save(); AndroidUtilities.rectTmp.set(currentBackgroundDrawable.getBounds()); if (currentMessageObject.isOutOwner() && !mediaBackground && !pinnedBottom) { AndroidUtilities.rectTmp.left += dp(4); AndroidUtilities.rectTmp.right -= dp(10); } else { AndroidUtilities.rectTmp.left += dp(4); AndroidUtilities.rectTmp.right -= dp(4); } canvas.clipRect(AndroidUtilities.rectTmp.left, transitionParams.animateFromTextY, AndroidUtilities.rectTmp.right, transitionParams.animateFromTextY + currentMessageObject.textHeight(transitionParams) + dp(4)); drawMessageText(textX, oldTextY, canvas, currentMessageObject.textLayoutBlocks, currentMessageObject.textXOffset, false, (1.0f - transitionParams.animateChangeProgress), true, false, false); canvas.restore(); canvas.save(); AndroidUtilities.rectTmp.set(currentBackgroundDrawable.getBounds()); if (currentMessageObject.isOutOwner() && !mediaBackground && !pinnedBottom) { AndroidUtilities.rectTmp.left += dp(4); AndroidUtilities.rectTmp.right -= dp(10); } else { AndroidUtilities.rectTmp.left += dp(4); AndroidUtilities.rectTmp.right -= dp(4); } canvas.clipRect(AndroidUtilities.rectTmp.left, this.textY, AndroidUtilities.rectTmp.right, this.textY + currentMessageObject.textHeight(transitionParams) + dp(4)); drawMessageText(textX, textY, canvas, currentMessageObject.textLayoutBlocks, currentMessageObject.textXOffset, true, 1.0f, true, false, false); canvas.restore(); } else { drawMessageText(textX, textY, canvas, currentMessageObject.textLayoutBlocks, currentMessageObject.textXOffset, true, 1.0f, true, false, false); } } public void drawMessageText(Canvas canvas, ArrayList textLayoutBlocks, boolean origin, float alpha, boolean drawOnlyText) { float textY = this.textY; if (transitionParams.animateTextY) { textY = transitionParams.animateFromTextY * (1f - transitionParams.animateChangeProgress) + this.textY * transitionParams.animateChangeProgress; } drawMessageText(textX, textY, canvas, textLayoutBlocks, currentMessageObject == null ? 0 : currentMessageObject.textXOffset, origin, alpha, false, drawOnlyText, false); } @SuppressLint("Range") public void drawMessageText(float textX, float textY, Canvas canvas, ArrayList textLayoutBlocks, float rtlOffset, boolean origin, float alpha, boolean drawAllBlocks, boolean drawOnlyText, boolean caption) { drawMessageText(textX, textY, canvas, textLayoutBlocks, rtlOffset, origin, alpha, drawAllBlocks, drawOnlyText, caption, false); } public void drawMessageText(float textX, float textY, Canvas canvas, ArrayList textLayoutBlocks, float rtlOffset, boolean origin, float alpha, boolean drawAllBlocks, boolean drawOnlyText, boolean caption, boolean explanation) { if (textLayoutBlocks == null || textLayoutBlocks.isEmpty() || alpha == 0) { return; } int firstVisibleBlockNum; int lastVisibleBlockNum; if (origin && !drawAllBlocks) { if (fullyDraw) { this.firstVisibleBlockNum = 0; this.lastVisibleBlockNum = textLayoutBlocks.size(); } firstVisibleBlockNum = this.firstVisibleBlockNum; lastVisibleBlockNum = this.lastVisibleBlockNum; } else { firstVisibleBlockNum = 0; lastVisibleBlockNum = textLayoutBlocks.size(); } final TranslateController translateController = MessagesController.getInstance(currentAccount).getTranslateController(); final boolean translating = translateController.isTranslating(currentMessageObject); final boolean shouldTranslate = currentMessageObject != null && TranslateController.isTranslatable(currentMessageObject) && translateController.isTranslatingDialog(currentMessageObject.getDialogId()); final boolean shouldSummarize = currentMessageObject != null && currentMessageObject.messageOwner.summarizedOpen; final boolean isFinal = shouldTranslate == (currentMessageObject != null && currentMessageObject.translated) && shouldSummarize == (currentMessageObject != null && currentMessageObject.summarized); if (origin == !isFinal) { if (translationLoadingFloat == null) { translationLoadingFloat = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); } float translationLoading = translationLoadingFloat.set(translating ? 1 : 0); if (translationLoading > 0) { if (translationLoadingDrawable == null) { translationLoadingDrawable = new LoadingDrawable(); translationLoadingDrawable.setAppearByGradient(true); if (translationLoadingPath == null) { translationLoadingPath = new LinkPath(true); translationLoadingPath.setUseCornerPathImplementation(true); } translationLoadingDrawable.usePath(translationLoadingPath); translationLoadingDrawable.setRadiiDp(5); translationLoadingDrawable.reset(); } if (translationLoadingDrawableText != textLayoutBlocks) { translationLoadingDrawableText = textLayoutBlocks; translationLoadingPath.reset(); for (int i = 0; i < textLayoutBlocks.size(); ++i) { MessageObject.TextLayoutBlock block = textLayoutBlocks.get(i); if (block != null && block.textLayout != null) { translationLoadingPath.setCurrentLayout(block.textLayout, 0, block.isRtl() ? rtlOffset : 0, block.textYOffset(textLayoutBlocks, transitionParams) + block.padTop); translationLoadingPath.setAllowReset(false); block.textLayout.getSelectionPath(0, block.textLayout.getText().length(), translationLoadingPath); translationLoadingPath.setAllowReset(true); } } translationLoadingPath.closeRects(); translationLoadingDrawable.updateBounds(); } if (translating && (translationLoadingDrawable.isDisappearing() || translationLoadingDrawable.isDisappeared())) { translationLoadingDrawable.reset(); translationLoadingDrawable.resetDisappear(); } else if (!translating && !translationLoadingDrawable.isDisappearing() && !translationLoadingDrawable.isDisappeared()) { translationLoadingDrawable.disappear(); } int color = getThemedColor(currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.key_chat_messageLinkOut : Theme.key_chat_messageLinkIn); translationLoadingDrawable.setColors( Theme.multAlpha(color, .05f), Theme.multAlpha(color, .15f), Theme.multAlpha(color, .1f), Theme.multAlpha(color, .3f) ); canvas.save(); canvas.translate(textX, textY + transitionYOffsetForDrawables); translationLoadingDrawable.setAlpha((int) (0xFF * alpha * translationLoading)); translationLoadingDrawable.draw(canvas); canvas.restore(); invalidate(); } } if (firstVisibleBlockNum >= 0) { float right; if (currentMessagesGroup == null || currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0) { right = getBackgroundDrawableRight() + transitionParams.deltaRight; } else { int end, dWidth; if (AndroidUtilities.isTablet()) { dWidth = AndroidUtilities.getMinTabletSide(); } else { dWidth = getParentWidth(); } int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } if (!mediaBackground && currentMessageObject.isOutOwner()) { end = backgroundDrawableLeft + firstLineWidth - dp(6); } else { end = backgroundDrawableLeft + firstLineWidth; } end -= getExtraTextX() + dp(8 + (isAvatarVisible ? 48 : 0)); right = end; } right -= dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) + getExtraTextX(); final float maxWidth = right - textX; int restore = Integer.MIN_VALUE; int oldAlpha = 0; int oldLinkAlpha = 0; boolean needRestoreColor = false; if (alpha != 1.0f) { if (drawOnlyText || caption) { needRestoreColor = true; oldAlpha = Theme.chat_msgTextPaint.getAlpha(); oldLinkAlpha = Color.alpha(Theme.chat_msgTextPaint.linkColor); Theme.chat_msgTextPaint.setAlpha((int) (oldAlpha * alpha)); Theme.chat_msgTextPaint.linkColor = ColorUtils.setAlphaComponent(Theme.chat_msgTextPaint.linkColor, (int) (oldLinkAlpha * alpha)); } else { if (currentBackgroundDrawable != null) { int top = currentBackgroundDrawable.getBounds().top; int bottom = currentBackgroundDrawable.getBounds().bottom; if (caption) { rect.set(getCurrentBackgroundLeft() - dp(10), top, currentBackgroundDrawable.getBounds().right + dp(10), bottom); } else { if (getY() < 0) { top = (int) -getY(); } if (getY() + getMeasuredHeight() > parentHeight) { bottom = (int) (parentHeight - getY()); } rect.set(getCurrentBackgroundLeft(), top, currentBackgroundDrawable.getBounds().right, bottom); } } else { rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); } restore = canvas.saveLayerAlpha(rect, (int) (alpha * 255), Canvas.ALL_SAVE_FLAG); } } int spoilersColor = currentMessageObject.isOutOwner() && !ChatObject.isChannelAndNotMegaGroup(currentMessageObject.getChatId(), currentAccount) ? getThemedColor(Theme.key_chat_outTimeText) : Theme.chat_msgTextPaint.getColor(); if (quoteHighlight != null && !quoteHighlight.todo && !quoteHighlight.poll && currentMessagesGroup == null) { MessageDrawable backgroundDrawable = currentBackgroundDrawable; if (backgroundDrawable != null) { canvas.save(); canvas.clipPath(backgroundDrawable.makePath()); quoteHighlight.paint.setColor(Theme.multAlpha(getThemedColor(currentMessageObject != null && currentMessageObject.isOutOwner() && !currentMessageObject.preview ? Theme.key_chat_outReplyLine : Theme.key_chat_inReplyLine), Theme.isCurrentThemeDark() ? .2f : .2f)); quoteHighlight.draw(canvas, textX, textY, backgroundDrawable.getBounds(), getHighlightAlpha(true)); canvas.restore(); } } for (int a = firstVisibleBlockNum; a <= lastVisibleBlockNum; a++) { if (a >= textLayoutBlocks.size()) { break; } MessageObject.TextLayoutBlock block = textLayoutBlocks.get(a); int saveCount = canvas.getSaveCount(); canvas.save(); final float blockRtl = (block.isRtl() ? rtlOffset - (block.quote ? dp(10) : 0) : 0); canvas.translate(textX - blockRtl, textY + block.textYOffset(textLayoutBlocks, transitionParams) + transitionYOffsetForDrawables + block.padTop); if (a == linkBlockNum && !explanation || a == linkExplanationBlockNum && explanation) { if (!drawOnlyText && links.draw(canvas)) { invalidate(); } drawProgressLoadingLink(canvas, a); } float collapsed = 1f; int blockSpoilersColor = spoilersColor; final int width = (int) (block.maxRight + dp(24) > maxWidth * .7f ? maxWidth : block.maxRight + dp(24)); if (block.quote) { if (quoteLine == null) { quoteLine = new ReplyMessageLine(this); } quoteLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_QUOTE); AndroidUtilities.rectTmp.set(0, -block.padTop + dp(block.first ? 3 + 1.66f : 3), width, block.height(transitionParams) + dp(4)); AndroidUtilities.rectTmp.offset(blockRtl, 0); if (block.quoteCollapse && block.collapsedBounce != null) { final float s = block.collapsedBounce.getScale(0.01f); canvas.scale(s, s, AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY()); } quoteLine.drawBackground(canvas, AndroidUtilities.rectTmp, 5, 5, 5, alpha); quoteLine.drawLine(canvas, AndroidUtilities.rectTmp, alpha); if (quoteDrawable == null) { quoteDrawable = new Drawable[2]; } if (quoteDrawableColor == null) { quoteDrawableColor = new int[2]; } final int q = block.quoteCollapse ? 1 : 0; if (quoteDrawable[q] == null) { quoteDrawable[q] = getContext().getResources().getDrawable(R.drawable.mini_quote).mutate(); } if (quoteLine.getColor() != quoteDrawableColor[q]) { quoteDrawable[q].setColorFilter(new PorterDuffColorFilter(quoteDrawableColor[q] = quoteLine.getColor(), PorterDuff.Mode.SRC_IN)); } quoteDrawable[q].setBounds( (int) (AndroidUtilities.rectTmp.right - dp(2 + (!drawPinnedTop ? 1 : 0)) - quoteDrawable[q].getIntrinsicWidth()), (int) (AndroidUtilities.rectTmp.top + dp(2 + (!drawPinnedTop ? 1 : 0))), (int) (AndroidUtilities.rectTmp.right - dp(2 + (!drawPinnedTop ? 1 : 0))), (int) (AndroidUtilities.rectTmp.top + dp(2 + (!drawPinnedTop ? 1 : 0)) + quoteDrawable[q].getIntrinsicHeight()) ); quoteDrawable[q].setAlpha((int) (0xFF * alpha)); quoteDrawable[q].draw(canvas); blockSpoilersColor = quoteLine.getColor(); Theme.chat_msgGameTextPaint.linkColor = Theme.chat_replyTextPaint.linkColor = Theme.chat_quoteTextPaint.linkColor = Theme.chat_msgTextPaint.linkColor = currentMessageObject.isOutOwner() ? Theme.getColor(Theme.key_chat_messageLinkOut, resourcesProvider) : quoteLine.getColor(); if (block.quoteCollapse && block.height > block.collapsedHeight) { collapsed = block.collapsed(transitionParams); if (quoteArrow == null) { quoteArrow = getContext().getResources().getDrawable(R.drawable.arrow_more).mutate(); quoteArrow.setColorFilter(new PorterDuffColorFilter(quoteArrowColor = quoteLine.getColor(), PorterDuff.Mode.SRC_IN)); } if (quoteLine.getColor() != quoteArrowColor) { quoteArrow.setColorFilter(new PorterDuffColorFilter(quoteArrowColor = quoteLine.getColor(), PorterDuff.Mode.SRC_IN)); } canvas.save(); final int sz = dp(16); quoteArrow.setBounds( width + (int) blockRtl - sz - dp(4 + 3), block.height(transitionParams) - sz - dp(2), width + (int) blockRtl - dp(4 + 3), block.height(transitionParams) - dp(2) ); canvas.rotate(AndroidUtilities.lerp(180, 0, collapsed), quoteArrow.getBounds().centerX(), quoteArrow.getBounds().centerY()); quoteArrow.setAlpha((int) (0xFF * alpha)); quoteArrow.draw(canvas); canvas.restore(); canvas.saveLayerAlpha(blockRtl, 0, width + blockRtl, block.height(transitionParams) - 1, 0xFF, Canvas.ALL_SAVE_FLAG); } } else { Theme.chat_msgGameTextPaint.linkColor = Theme.chat_replyTextPaint.linkColor = Theme.chat_quoteTextPaint.linkColor = Theme.chat_msgTextPaint.linkColor = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_messageLinkOut : Theme.key_chat_messageLinkIn); if (block.code) { if (quoteLine == null) { quoteLine = new ReplyMessageLine(this); } quoteLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_CODE); if (currentMessageObject.isOutOwner() && (Theme.isCurrentThemeDark() || Theme.isCustomTheme())) { quoteLine.setBackgroundColor(getThemedColor(Theme.key_chat_outCodeBackground)); } AndroidUtilities.rectTmp.set(0, -dp(2 + 4) - block.languageHeight, namesOffset <= 0 ? maxWidth + dp(4) : maxWidth, block.height + dp(2 + 4)); AndroidUtilities.rectTmp.offset((block.isRtl() ? rtlOffset : 0), 0); if (block.hasCodeCopyButton) { AndroidUtilities.rectTmp.bottom += dp(38); } final float rightRad = block.first && namesOffset <= 0 && !caption ? ((!currentMessageObject.isOutOwner() || !pinnedTop) ? SharedConfig.bubbleRadius / 3f * 2f : Math.min(6, SharedConfig.bubbleRadius)) : Math.min(5, SharedConfig.bubbleRadius);; quoteLine.drawBackground(canvas, AndroidUtilities.rectTmp, 5, rightRad, Math.min(5, SharedConfig.bubbleRadius), alpha); if (block.languageHeight > 0) { float wasBottom = AndroidUtilities.rectTmp.bottom; AndroidUtilities.rectTmp.bottom = AndroidUtilities.rectTmp.top + block.languageHeight; quoteLine.drawBackground(canvas, AndroidUtilities.rectTmp, 5, rightRad, 0, (Theme.isCurrentThemeDark() ? .60f : .80f) * alpha); AndroidUtilities.rectTmp.bottom = wasBottom; } quoteLine.drawLine(canvas, AndroidUtilities.rectTmp, alpha); if (block.hasCodeCopyButton) { block.drawCopyCodeButton(canvas, AndroidUtilities.rectTmp, quoteLine.getColor(), quoteLine.getBackgroundColor(), alpha); } canvas.translate(dp(10), 0); if (block.languageLayout != null) { block.languageLayout.ellipsize((int) (maxWidth - dp(8 + 4))).draw(canvas, 0, -dp(6) - block.languageHeight / 2f, quoteLine.color3, alpha); } } } if (a == linkSelectionBlockNum && quoteHighlight == null && !urlPathSelection.isEmpty() && !drawOnlyText) { final Paint paint = currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.chat_outUrlPaint : Theme.chat_urlPaint; paint.setColor(getThemedColor(currentMessageObject != null && currentMessageObject.isOutOwner() && !currentMessageObject.preview ? Theme.key_chat_outReplyLine : Theme.key_chat_inReplyLine)); int wasAlpha = (int) (paint.getAlpha() * (Theme.isCurrentThemeDark() ? .2f : .3f)); paint.setAlpha((int) (wasAlpha * (highlightedQuote ? getHighlightAlpha() : 1))); for (int b = 0; b < urlPathSelection.size(); b++) { canvas.drawPath(urlPathSelection.get(b), paint); } paint.setAlpha(wasAlpha); } if (delegate != null && delegate.getTextSelectionHelper() != null && transitionParams.animateChangeProgress == 1f && !drawOnlyText) { if (caption) { delegate.getTextSelectionHelper().drawCaption(currentMessageObject, block, canvas); } else { delegate.getTextSelectionHelper().draw(currentMessageObject, block, canvas); } } try { Emoji.emojiDrawingYOffset = -transitionYOffsetForDrawables; boolean needDrawTextDefault = true; if (botDraftTypingAnimator != null && botDraftTypingAnimator.isRunning()) { needDrawTextDefault = false; if (botDraftTypingAnimator.needDraw(block)) { if (botDraftTypingAnimator.isFadeBlock(block)) { final int lineIndex = botDraftTypingAnimator.getFadeLineIndex(block); final float xPos = botDraftTypingAnimator.getFadeXPosition(block); MultiLayoutTypingAnimator.drawLayoutWithLastLineFade(canvas, block.textLayout, lineIndex, xPos); } else { needDrawTextDefault = true; } } invalidate(); } if (currentMessageObject != null && currentMessageObject.isBotPendingDraft) { invalidate(); } if (needDrawTextDefault) { SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, blockSpoilersColor, 0, block.spoilersPatchedTextLayout, 0, block.textLayout, block.spoilers, canvas, currentPosition != null); } Emoji.emojiDrawingYOffset = 0; } catch (Exception e) { FileLog.e(e); } if (block.quoteCollapse && block.height > block.collapsedHeight) { if (clip == null) { clip = new GradientClip(); } canvas.save(); AndroidUtilities.rectTmp.set(0, block.height(transitionParams) - dp(24), width, block.height(transitionParams)); clip.draw(canvas, AndroidUtilities.rectTmp, GradientClip.BOTTOM, collapsed); canvas.restore(); } canvas.restoreToCount(saveCount); } if (needRestoreColor) { Theme.chat_msgTextPaint.setAlpha(oldAlpha); Theme.chat_msgTextPaint.linkColor = ColorUtils.setAlphaComponent(Theme.chat_msgTextPaint.linkColor, oldLinkAlpha); } if (restore != Integer.MIN_VALUE) { canvas.restoreToCount(restore); } } } public AnimatedEmojiSpan[] getAnimatedEmojiSpans() { AnimatedEmojiSpan[] messageTextSpans = currentMessageObject != null && currentMessageObject.messageText instanceof Spanned ? ((Spanned) currentMessageObject.messageText).getSpans(0, currentMessageObject.messageText.length(), AnimatedEmojiSpan.class) : null; AnimatedEmojiSpan[] captionTextSpans = currentMessageObject != null && currentMessageObject.caption instanceof Spanned ? ((Spanned) currentMessageObject.caption).getSpans(0, currentMessageObject.caption.length(), AnimatedEmojiSpan.class) : null; if ((messageTextSpans == null || messageTextSpans.length == 0) && (captionTextSpans == null || captionTextSpans.length == 0)) { return null; } AnimatedEmojiSpan[] array = new AnimatedEmojiSpan[(messageTextSpans == null ? 0 : messageTextSpans.length) + (captionTextSpans == null ? 0 : captionTextSpans.length)]; int j = 0; if (messageTextSpans != null) { for (int i = 0; i < messageTextSpans.length; ++i, ++j) { array[j] = messageTextSpans[i]; } } if (captionTextSpans != null) { for (int i = 0; i < captionTextSpans.length; ++i, ++j) { array[j] = captionTextSpans[i]; } } return array; } public void updateCaptionLayout() { float captionYBelow; boolean asBottom = false; if ( currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || currentMessageObject.type == MessageObject.TYPE_GIF || currentMessageObject.type == MessageObject.TYPE_STORY ) { float x, y, h; if (transitionParams.imageChangeBoundsTransition) { x = transitionParams.animateToImageX; y = transitionParams.animateToImageY; h = transitionParams.animateToImageH; } else { x = photoImage.getImageX(); y = photoImage.getImageY(); h = photoImage.getImageHeight(); } captionX = x + dp(5) + captionOffsetX; captionYBelow = y + h + dp(6); captionY = y + AndroidUtilities.lerp(h + dp(6), (captionLayout == null ? 0 : -captionLayout.textHeight()) - dp(4), mediaAbove()); } else if (hasOldCaptionPreview) { captionX = backgroundDrawableLeft + dp(currentMessageObject.isOutOwner() ? 11 : 17) + captionOffsetX; captionYBelow = totalHeight - captionHeight - dp(drawPinnedTop ? 9 : 10) - linkPreviewHeight - dp(17) - dp(drawCommentButton && drawSideButton != 3 ? (shouldDrawTimeOnMedia() ? 41.3f : 43) : 0); captionY = AndroidUtilities.lerp( captionYBelow, dp(9) + namesOffset, mediaAbove() ); asBottom = true; } else { if (isRoundVideo) { captionX = getBackgroundDrawableLeft() + dp(11 + (currentMessageObject.isOutOwner() ? 0 : 6)); } else { captionX = backgroundDrawableLeft + dp(currentMessageObject.isOutOwner() || mediaBackground || drawPinnedBottom ? 11 : 17) + captionOffsetX; } captionYBelow = totalHeight - captionHeight - dp(drawPinnedTop ? 9 : 10) - dp(drawCommentButton && drawSideButton != 3 ? (shouldDrawTimeOnMedia() ? 41.3f : 43) : 0) - (!reactionsLayoutInBubble.isEmpty && !reactionsLayoutInBubble.isSmall ? dp(currentMessageObject.type == MessageObject.TYPE_FILE && currentPosition == null ? 10 : 0) + reactionsLayoutInBubble.totalHeight : 0); captionY = AndroidUtilities.lerp( captionYBelow, dp(9) + namesOffset, mediaAbove() ); asBottom = true; } captionX += getExtraTextX(); if (currentMessageObject != null && !(currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_STORY_MENTION || currentMessageObject.isGiveawayOrGiveawayResults() || currentMessageObject.isSponsored())) { if (asBottom && hasFactCheck) { captionY -= (factCheckHeight + dp(16)) * (1f - mediaAbove()); } factCheckY = (int) (captionYBelow - (asBottom ? factCheckHeight + dp(14) : 0) + AndroidUtilities.lerp(captionLayout != null ? captionLayout.textHeight(transitionParams) + dp(4) : 0, dp(6), mediaAbove()) - transitionParams.deltaTop); } if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_POLL) { captionY += pollContentHeightWithOffset; } } private float mediaAbove() { if (transitionParams.animateMediaAbove) { return AndroidUtilities.lerp(captionAbove ? 0f : 1f, captionAbove ? 1f : 0f, transitionParams.animateChangeProgress); } return captionAbove ? 1f : 0f; } private float factCheckAlpha() { if (transitionParams.animateFactCheck) { return AndroidUtilities.lerp(hasFactCheck ? 0f : 1f, hasFactCheck ? 1f : 0f, transitionParams.animateChangeProgress); } return hasFactCheck ? 1f : 0f; } public int captionFlag() { return captionAbove ? MessageObject.POSITION_FLAG_TOP : MessageObject.POSITION_FLAG_BOTTOM; } private boolean textIsSelectionMode() { if (getCurrentMessagesGroup() != null || delegate == null) { return false; } return delegate.getTextSelectionHelper() != null && delegate.getTextSelectionHelper().isSelected(currentMessageObject); } public float getViewTop() { return viewTop; } public int getBackgroundHeight() { return backgroundHeight; } private int getMiniIconForCurrentState() { if (miniButtonState < 0) { return MediaActionDrawable.ICON_NONE; } if (miniButtonState == 0) { return MediaActionDrawable.ICON_DOWNLOAD; } else { return MediaActionDrawable.ICON_CANCEL; } } private int getIconForCurrentState() { if (currentMessageObject == null || currentMessageObject.hasExtendedMedia()) { return MediaActionDrawable.ICON_NONE; } if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject.isVoiceTranscriptionOpen() && canStreamVideo) { if (buttonState == 1 || buttonState == 4) { return MediaActionDrawable.ICON_PAUSE; } return MediaActionDrawable.ICON_PLAY; } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { if (currentMessageObject.isOutOwner()) { radialProgress.setColorKeys(Theme.key_chat_outLoader, Theme.key_chat_outLoaderSelected, Theme.key_chat_outMediaIcon, Theme.key_chat_outMediaIconSelected); } else if (linkLine != null && hasLinkPreview) { radialProgress.setColors(linkLine.getColor(), linkLine.getColor(), Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .01f)), Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .05f))); } else { radialProgress.setColorKeys(Theme.key_chat_inLoader, Theme.key_chat_inLoaderSelected, Theme.key_chat_inMediaIcon, Theme.key_chat_inMediaIconSelected); } if (buttonState == 1) { return MediaActionDrawable.ICON_PAUSE; } else if (buttonState == 2) { return MediaActionDrawable.ICON_DOWNLOAD; } else if (buttonState == 4) { return MediaActionDrawable.ICON_CANCEL; } return MediaActionDrawable.ICON_PLAY; } else { if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT && !drawPhotoImage) { if (currentMessageObject.isOutOwner()) { radialProgress.setColorKeys(Theme.key_chat_outLoader, Theme.key_chat_outLoaderSelected, Theme.key_chat_outMediaIcon, Theme.key_chat_outMediaIconSelected); } else if (linkLine != null && hasLinkPreview) { radialProgress.setColors(linkLine.getColor(), linkLine.getColor(), Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .01f)), Theme.blendOver(0xffffffff, Theme.multAlpha(linkLine.getColor(), .05f))); } else { radialProgress.setColorKeys(Theme.key_chat_inLoader, Theme.key_chat_inLoaderSelected, Theme.key_chat_inMediaIcon, Theme.key_chat_inMediaIconSelected); } if (buttonState == -1) { return MediaActionDrawable.ICON_FILE; } else if (buttonState == 0) { return MediaActionDrawable.ICON_DOWNLOAD; } else if (buttonState == 1) { return MediaActionDrawable.ICON_CANCEL; } } else { radialProgress.setColorKeys(Theme.key_chat_mediaLoaderPhoto, Theme.key_chat_mediaLoaderPhotoSelected, Theme.key_chat_mediaLoaderPhotoIcon, Theme.key_chat_mediaLoaderPhotoIconSelected); videoRadialProgress.setColorKeys(Theme.key_chat_mediaLoaderPhoto, Theme.key_chat_mediaLoaderPhotoSelected, Theme.key_chat_mediaLoaderPhotoIcon, Theme.key_chat_mediaLoaderPhotoIconSelected); if (buttonState >= 0 && buttonState < 4) { if (buttonState == 0) { return MediaActionDrawable.ICON_DOWNLOAD; } else if (buttonState == 1) { return MediaActionDrawable.ICON_CANCEL; } else if (buttonState == 2) { return MediaActionDrawable.ICON_PLAY; } else { return autoPlayingMedia ? MediaActionDrawable.ICON_NONE : MediaActionDrawable.ICON_PLAY; } } else if (buttonState == -1) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { return (drawPhotoImage && (currentPhotoObject != null || currentPhotoObjectThumb != null) && (photoImage.hasBitmapImage() || currentMessageObject.mediaExists() || currentMessageObject.attachPathExists)) ? MediaActionDrawable.ICON_NONE : MediaActionDrawable.ICON_FILE; } else if (currentMessageObject.needDrawBluredPreview()) { return MediaActionDrawable.ICON_FIRE; } else if (hasEmbed) { return MediaActionDrawable.ICON_PLAY; } } } } if (currentMessageObject != null && isRoundVideo && currentMessageObject.isVoiceTranscriptionOpen()) { return MediaActionDrawable.ICON_PLAY; } return MediaActionDrawable.ICON_NONE; } public int getMaxNameWidth() { if (documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { int maxWidth; if (AndroidUtilities.isTablet()) { maxWidth = AndroidUtilities.getMinTabletSide() - dp(isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : needDrawAvatar() ? 42 : 0); } else { maxWidth = Math.min(getParentWidth(), AndroidUtilities.displaySize.y) - dp(isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : needDrawAvatar() ? 42 : 0); } if (currentMessageObject != null && currentMessageObject.isSaved && currentMessageObject.isOutOwner() && checkNeedDrawShareButton(currentMessageObject)) { maxWidth -= dp(25); } if (isPlayingRound && (currentMessageObject == null || !currentMessageObject.isVoiceTranscriptionOpen())) { int backgroundWidthLocal = backgroundWidth - (AndroidUtilities.roundPlayingMessageSize(isSideMenued) - AndroidUtilities.roundMessageSize); return maxWidth - backgroundWidthLocal - dp(57); } if (isSideMenued && (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER)) { return backgroundWidth - dp(57); } return maxWidth - backgroundWidth - dp(57); } if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { int dWidth; if (AndroidUtilities.isTablet()) { dWidth = AndroidUtilities.getMinTabletSide(); } else { dWidth = getParentWidth(); } int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } return firstLineWidth - dp(31 + (isSideMenued ? ChatActivity.SIDE_MENU_WIDTH : needDrawAvatar() ? 48 : 0)); } else if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { return Math.max(currentMessageObject.textWidth, (int) ((AndroidUtilities.displaySize.x - dp(52) - (isAvatarVisible ? dp(48) : 0)) * .5f)); } else { int width = backgroundWidth; if (currentMessageObject != null && currentMessageObject.isSaved && currentMessageObject.isOutOwner() && checkNeedDrawShareButton(currentMessageObject)) { width -= dp(25); } width -= dp(mediaBackground ? 22 : 31); return width; } } public void updatePollContentButtonState(boolean ifSame, boolean animated, boolean fromSet) { if (pollContentDrawable != null) { pollContentDrawable.updatePlayingMessageProgress(); } if (pollExplanationDrawable != null) { pollExplanationDrawable.updatePlayingMessageProgress(); } invalidate(); } public void updateButtonState(boolean ifSame, boolean animated, boolean fromSet) { if (currentMessageObject == null) { return; } if (currentMessageObject.type == MessageObject.TYPE_STORY && currentMessageObject.isVideoStory()) { buttonState = 2; getIconForCurrentState(); return; } if (animated && (PhotoViewer.isShowingImage(currentMessageObject) || !attachedToWindow)) { animated = false; } drawRadialCheckBackground = false; String fileName = null; boolean fileExists = false; if (currentMessageObject.type == MessageObject.TYPE_PHOTO) { if (currentPhotoObject == null) { radialProgress.setIcon(MediaActionDrawable.ICON_NONE, ifSame, animated); return; } fileName = FileLoader.getAttachFileName(currentPhotoObject); fileExists = currentMessageObject.mediaExists(); } else if ( currentMessageObject.type == MessageObject.TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || currentMessageObject.type == MessageObject.TYPE_FILE || documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC ) { if (currentMessageObject.useCustomPhoto) { buttonState = 1; radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); return; } if (currentMessageObject.attachPathExists && !TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath)) { fileName = currentMessageObject.messageOwner.attachPath; fileExists = true; } else if (!currentMessageObject.isSendError() || documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { fileName = currentMessageObject.getFileName(); // currentMessageObject.updateQualitiesCached(true); fileExists = currentMessageObject.mediaExists(); } } else if (documentAttachType != DOCUMENT_ATTACH_TYPE_NONE) { fileName = FileLoader.getAttachFileName(documentAttach); fileExists = currentMessageObject.mediaExists(); } else if (currentPhotoObject != null) { fileName = FileLoader.getAttachFileName(currentPhotoObject); fileExists = currentMessageObject.mediaExists(); } boolean autoDownload; if (documentAttach != null && documentAttach.dc_id == Integer.MIN_VALUE) { autoDownload = false; } else { autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject); } if (currentMessageObject.isHiddenSensitive()) { autoDownload = false; } canStreamVideo = ( (currentMessageObject.isSent() || currentMessageObject.isForwarded()) && (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && autoDownload ) && currentMessageObject.canStreamVideo() && !currentMessageObject.needDrawBluredPreview() ); if ( SharedConfig.streamMedia && (int) currentMessageObject.getDialogId() != 0 && !currentMessageObject.isSecretMedia() && ( documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || canStreamVideo && currentPosition != null && ( (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0 || (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) == 0 ) ) ) { hasMiniProgress = fileExists ? 1 : 2; fileExists = true; } if (currentMessageObject.isSendError() || TextUtils.isEmpty(fileName) && (currentMessageObject.isAnyKindOfSticker() || !currentMessageObject.isSending() && !currentMessageObject.isEditing())) { radialProgress.setIcon(MediaActionDrawable.ICON_NONE, ifSame, false); radialProgress.setMiniIcon(MediaActionDrawable.ICON_NONE, ifSame, false); videoRadialProgress.setIcon(MediaActionDrawable.ICON_NONE, ifSame, false); videoRadialProgress.setMiniIcon(MediaActionDrawable.ICON_NONE, ifSame, false); return; } boolean fromBot = currentMessageObject.messageOwner.params != null && currentMessageObject.messageOwner.params.containsKey("query_id"); if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen() && canStreamVideo) { if (currentMessageObject.isOut() && (currentMessageObject.isSending() && !currentMessageObject.isForwarded() || currentMessageObject.isEditing() && currentMessageObject.isEditingMedia()) || currentMessageObject.isSendError() && fromBot) { if (!TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath)) { DownloadController.getInstance(currentAccount).addLoadingFileObserver(currentMessageObject.messageOwner.attachPath, currentMessageObject, this); wasSending = true; buttonState = 4; boolean sending = SendMessagesHelper.getInstance(currentAccount).isSendingMessage(currentMessageObject.getId()); if ((currentPosition != null || currentMessageObject.isPaid()) && sending && buttonState == 4) { drawRadialCheckBackground = true; getIconForCurrentState(); radialProgress.setIcon(MediaActionDrawable.ICON_CHECK, ifSame, animated); } else { radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); } radialProgress.setMiniIcon(MediaActionDrawable.ICON_NONE, ifSame, animated); if (!fromBot) { long[] progress = ImageLoader.getInstance().getFileProgressSizes(currentMessageObject.messageOwner.attachPath); float loadingProgress = 0; if (progress == null && sending) { loadingProgress = 1.0f; } else if (progress != null) { loadingProgress = DownloadController.getProgress(progress); } radialProgress.setProgress(loadingProgress, false); } else { radialProgress.setProgress(0, false); } } else { buttonState = -1; getIconForCurrentState(); radialProgress.setIcon(MediaActionDrawable.ICON_CANCEL_NOPROFRESS, ifSame, false); radialProgress.setProgress(0, false); radialProgress.setMiniIcon(MediaActionDrawable.ICON_NONE, ifSame, false); } } else { if (hasMiniProgress != 0) { radialProgress.setMiniProgressBackgroundColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLoader : Theme.key_chat_inLoader)); boolean playing = MediaController.getInstance().isPlayingMessage(currentMessageObject); if (!playing || MediaController.getInstance().isMessagePaused()) { buttonState = 0; } else { buttonState = 1; } radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); if (hasMiniProgress == 1) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); miniButtonState = -1; } else { DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); if (!FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { createLoadingProgressLayout(documentAttach); miniButtonState = 0; } else { miniButtonState = 1; long[] progress = ImageLoader.getInstance().getFileProgressSizes(fileName); if (progress != null) { radialProgress.setProgress(DownloadController.getProgress(progress), animated); createLoadingProgressLayout(progress[0], progress[1]); } else { radialProgress.setProgress(0, animated); createLoadingProgressLayout(0, currentMessageObject.getSize()); } } } radialProgress.setMiniIcon(getMiniIconForCurrentState(), ifSame, animated); } else if (fileExists) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); boolean playing = MediaController.getInstance().isPlayingMessage(currentMessageObject); if (!playing || MediaController.getInstance().isMessagePaused()) { buttonState = 0; } else { buttonState = 1; } radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); } else { DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); if (!FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { buttonState = 2; } else { buttonState = 4; long[] progress = ImageLoader.getInstance().getFileProgressSizes(fileName); if (progress != null) { radialProgress.setProgress(DownloadController.getProgress(progress), animated); createLoadingProgressLayout(progress[0], progress[1]); } else { createLoadingProgressLayout(documentAttach); radialProgress.setProgress(0, animated); } } radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); } } updatePlayingMessageProgress(); } else if ( currentMessageObject.type == MessageObject.TYPE_TEXT && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT && documentAttachType != DOCUMENT_ATTACH_TYPE_STORY && documentAttachType != DOCUMENT_ATTACH_TYPE_GIF && documentAttachType != DOCUMENT_ATTACH_TYPE_VIDEO && documentAttachType != DOCUMENT_ATTACH_TYPE_WALLPAPER && documentAttachType != DOCUMENT_ATTACH_TYPE_THEME ) { if (currentPhotoObject == null || !drawImageButton) { return; } if (!fileExists) { DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); float setProgress = 0; if (!FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { if ( !currentMessageObject.loadingCancelled && autoDownload && ( documentAttachType == 0 || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && MessageObject.isGifDocument(documentAttach, currentMessageObject.hasValidGroupId()) ) ) { buttonState = 1; } else { buttonState = 0; } } else { buttonState = 1; long[] progress = ImageLoader.getInstance().getFileProgressSizes(fileName); setProgress = progress != null ? DownloadController.getProgress(progress) : 0; if (progress != null && progress[0] == progress[1]) { createLoadingProgressLayout(progress[0], progress[1]); } else { if (currentMessageObject.getDocument() != null) { createLoadingProgressLayout(currentMessageObject.loadedFileSize, currentMessageObject.getSize()); } } } radialProgress.setProgress(setProgress, false); } else { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && !photoImage.isAllowStartAnimation()) { buttonState = 2; } else { buttonState = -1; } } radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); invalidate(); } else { if (currentMessageObject.isOut() && (currentMessageObject.isSending() && !currentMessageObject.isForwarded() || currentMessageObject.isEditing() && currentMessageObject.isEditingMedia())) { if (!TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath)) { DownloadController.getInstance(currentAccount).addLoadingFileObserver(currentMessageObject.messageOwner.attachPath, currentMessageObject, this); wasSending = true; boolean needProgress = currentMessageObject.messageOwner.attachPath == null || !currentMessageObject.messageOwner.attachPath.startsWith("http"); HashMap params = currentMessageObject.messageOwner.params; if (currentMessageObject.messageOwner.message != null && params != null && (params.containsKey("url") || params.containsKey("bot"))) { needProgress = false; buttonState = -1; } else { buttonState = 1; } boolean sending = SendMessagesHelper.getInstance(currentAccount).isSendingMessage(currentMessageObject.getId()); if ((currentPosition != null || currentMessageObject.isPaid()) && sending && buttonState == 1) { drawRadialCheckBackground = true; getIconForCurrentState(); radialProgress.setIcon(MediaActionDrawable.ICON_CHECK, ifSame, animated); } else { radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); } if (needProgress) { long[] progress = ImageLoader.getInstance().getFileProgressSizes(currentMessageObject.messageOwner.attachPath); float loadingProgress = 0; if (progress == null && sending) { loadingProgress = 1.0f; } else if (progress != null) { loadingProgress = DownloadController.getProgress(progress); createLoadingProgressLayout(progress[0], progress[1]); } radialProgress.setProgress(loadingProgress, false); } else { radialProgress.setProgress(0, false); } invalidate(); } else { getIconForCurrentState(); if (currentMessageObject.isSticker() || currentMessageObject.isAnimatedSticker() || currentMessageObject.isLocation() || currentMessageObject.isGif() || documentAttachType == DOCUMENT_ATTACH_TYPE_STORY) { buttonState = -1; radialProgress.setIcon(MediaActionDrawable.ICON_NONE, ifSame, false); } else { buttonState = 1; radialProgress.setIcon(MediaActionDrawable.ICON_CANCEL_NOPROFRESS, ifSame, false); } radialProgress.setProgress(0, false); } videoRadialProgress.setIcon(MediaActionDrawable.ICON_NONE, ifSame, false); } else { if (wasSending && !TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath)) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); } boolean isLoadingVideo = false; if ((documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) && autoPlayingMedia) { isLoadingVideo = FileLoader.getInstance(currentAccount).isLoadingVideo(documentAttach, MediaController.getInstance().isPlayingMessage(currentMessageObject)); AnimatedFileDrawable animation = photoImage.getAnimation(); if (animation != null) { if (currentMessageObject.hadAnimationNotReadyLoading) { if (animation.hasBitmap()) { currentMessageObject.hadAnimationNotReadyLoading = false; } } else { currentMessageObject.hadAnimationNotReadyLoading = isLoadingVideo && !animation.hasBitmap(); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && !fileExists) { currentMessageObject.hadAnimationNotReadyLoading = true; } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO && !isLoadingVideo) { String key = ImageLocation.getForDocument(documentAttach).getKey(null, null, false); if (key != null) { isLoadingVideo = ImageLoader.getInstance().imageLoadingKeys.contains(key); } } } if (hasMiniProgress != 0) { radialProgress.setMiniProgressBackgroundColor(getThemedColor(Theme.key_chat_inLoaderPhoto)); buttonState = 3; radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); if (hasMiniProgress == 1 || currentMessageObject.sendPreview) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); miniButtonState = -1; } else { DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); if (!FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { miniButtonState = 0; } else { miniButtonState = 1; long[] progress = ImageLoader.getInstance().getFileProgressSizes(fileName); if (progress != null) { createLoadingProgressLayout(progress[0], progress[1]); radialProgress.setProgress(DownloadController.getProgress(progress), animated); } else { createLoadingProgressLayout(documentAttach); radialProgress.setProgress(0, animated); } } } radialProgress.setMiniIcon(getMiniIconForCurrentState(), ifSame, animated); } else if (fileExists || (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) && autoPlayingMedia && !currentMessageObject.hadAnimationNotReadyLoading && !isLoadingVideo) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); if (drawVideoImageButton && animated) { if (animatingDrawVideoImageButton != 1 && animatingDrawVideoImageButtonProgress > 0) { if (animatingDrawVideoImageButton == 0) { animatingDrawVideoImageButtonProgress = 1.0f; } animatingDrawVideoImageButton = 1; } } else if (animatingDrawVideoImageButton == 0) { animatingDrawVideoImageButton = 1; } drawVideoImageButton = false; drawVideoSize = false; if (currentMessageObject.needDrawBluredPreview()) { buttonState = -1; } else { if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && currentMessageObject.gifState == 1) { if (photoImage.isAnimationRunning()) { currentMessageObject.gifState = 0; buttonState = -1; } else { buttonState = 2; } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO && !hasEmbed) { buttonState = 3; } else { buttonState = -1; } } videoRadialProgress.setIcon(MediaActionDrawable.ICON_NONE, ifSame, animatingDrawVideoImageButton != 0); radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); if (!fromSet && photoNotSet) { setMessageObject(currentMessageObject, currentMessagesGroup, pinnedBottom, pinnedTop, firstInChat); } invalidate(); } else { drawVideoSize = documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF; if ((documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) && canStreamVideo && !drawVideoImageButton && animated) { if (animatingDrawVideoImageButton != 2 && animatingDrawVideoImageButtonProgress < 1.0f) { if (animatingDrawVideoImageButton == 0) { animatingDrawVideoImageButtonProgress = 0.0f; } animatingDrawVideoImageButton = 2; } } else if (animatingDrawVideoImageButton == 0) { animatingDrawVideoImageButtonProgress = 1.0f; } DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); boolean progressVisible = false; if (!FileLoader.getInstance(currentAccount).isLoadingFile(fileName) && !currentMessageObject.hadAnimationNotReadyLoading) { if (!currentMessageObject.loadingCancelled && autoDownload) { buttonState = 1; } else if (currentMessageObject.type == MessageObject.TYPE_GEO) { buttonState = -1; } else { buttonState = 0; } boolean hasDocLayout = currentMessageObject.type == MessageObject.TYPE_VIDEO || currentMessageObject.type == MessageObject.TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO; boolean fullWidth = true; if (currentPosition != null) { int mask = MessageObject.POSITION_FLAG_LEFT | MessageObject.POSITION_FLAG_RIGHT; fullWidth = (currentPosition.flags & mask) == mask; } if ((documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && autoDownload) && canStreamVideo && hasDocLayout && fullWidth) { drawVideoImageButton = true; getIconForCurrentState(); radialProgress.setIcon(autoPlayingMedia ? MediaActionDrawable.ICON_NONE : MediaActionDrawable.ICON_PLAY, ifSame, animated); videoRadialProgress.setIcon(MediaActionDrawable.ICON_DOWNLOAD, ifSame, animated); } else { drawVideoImageButton = false; radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); videoRadialProgress.setIcon(MediaActionDrawable.ICON_NONE, ifSame, false); if (!drawVideoSize && animatingDrawVideoImageButton == 0) { animatingDrawVideoImageButtonProgress = 0.0f; } } } else { buttonState = 1; long[] progress = ImageLoader.getInstance().getFileProgressSizes(fileName); if (progress != null) { createLoadingProgressLayout(progress[0], progress[1]); } else { createLoadingProgressLayout(documentAttach); } boolean hasDocLayout = currentMessageObject.type == MessageObject.TYPE_VIDEO || currentMessageObject.type == MessageObject.TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO; boolean fullWidth = true; if (currentPosition != null) { int mask = MessageObject.POSITION_FLAG_LEFT | MessageObject.POSITION_FLAG_RIGHT; fullWidth = (currentPosition.flags & mask) == mask; } if ((documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || MessageObject.isGifDocument(documentAttach, currentMessageObject.hasValidGroupId()) && autoDownload) && canStreamVideo && hasDocLayout && fullWidth) { drawVideoImageButton = true; getIconForCurrentState(); radialProgress.setIcon(autoPlayingMedia || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF ? MediaActionDrawable.ICON_NONE : MediaActionDrawable.ICON_PLAY, ifSame, animated); videoRadialProgress.setProgress(progress != null ? DownloadController.getProgress(progress) : 0, animated); videoRadialProgress.setIcon(MediaActionDrawable.ICON_CANCEL_FILL, ifSame, animated); } else { drawVideoImageButton = false; radialProgress.setProgress(progress != null ? DownloadController.getProgress(progress) : 0, animated); radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); videoRadialProgress.setIcon(MediaActionDrawable.ICON_NONE, ifSame, false); if (!drawVideoSize && animatingDrawVideoImageButton == 0) { animatingDrawVideoImageButtonProgress = 0.0f; } } } invalidate(); } } } if (hasMiniProgress == 0) { radialProgress.setMiniIcon(MediaActionDrawable.ICON_NONE, false, animated); } } private void didPressMiniButton(boolean animated) { if (miniButtonState == 0) { miniButtonState = 1; radialProgress.setProgress(0, false); if (currentMessageObject != null && !currentMessageObject.isAnyKindOfSticker()) { currentMessageObject.putInDownloadsStore = true; } if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); currentMessageObject.loadingCancelled = false; } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { createLoadingProgressLayout(documentAttach); FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); currentMessageObject.loadingCancelled = false; } radialProgress.setMiniIcon(getMiniIconForCurrentState(), false, true); invalidate(); } else if (miniButtonState == 1) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { MediaController.getInstance().cleanupPlayer(true, true); } } miniButtonState = 0; currentMessageObject.loadingCancelled = true; FileLoader.getInstance(currentAccount).cancelLoadFile(documentAttach); radialProgress.setMiniIcon(getMiniIconForCurrentState(), false, true); invalidate(); } } private void didPressButton(boolean animated, boolean video) { if (delegate != null && currentMessageObject.isSensitive() && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.needDrawBluredPreview() && !currentMessageObject.isMediaSpoilersRevealed) { delegate.didPressRevealSensitiveContent(this); return; } if (currentMessageObject != null && !currentMessageObject.isAnyKindOfSticker()) { currentMessageObject.putInDownloadsStore = true; } if (buttonState == 0 && (!drawVideoImageButton || video)) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen() && currentMessageObject.mediaExists) { if (miniButtonState == 0) { FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); currentMessageObject.loadingCancelled = false; } if (delegate.needPlayMessage(this, currentMessageObject, false)) { if (hasMiniProgress == 2 && miniButtonState != 1) { miniButtonState = 1; radialProgress.setProgress(0, false); radialProgress.setMiniIcon(getMiniIconForCurrentState(), false, true); } updatePlayingMessageProgress(); buttonState = 1; radialProgress.setIcon(getIconForCurrentState(), false, true); invalidate(); } } else { if (video) { videoRadialProgress.setProgress(0, false); } else { radialProgress.setProgress(0, false); } TLRPC.PhotoSize thumb; String thumbFilter; if (currentPhotoObject != null && (photoImage.hasNotThumb() || currentPhotoObjectThumb == null)) { thumb = currentPhotoObject; thumbFilter = thumb instanceof TLRPC.TL_photoStrippedSize || "s".equals(thumb.type) ? currentPhotoFilterThumb : currentPhotoFilter; } else { thumb = currentPhotoObjectThumb; thumbFilter = currentPhotoFilterThumb; } final int cacheType = currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0; if (currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW) { photoImage.setForceLoading(true); photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, currentPhotoObject.size, null, currentMessageObject, cacheType); } else if (currentMessageObject.type == MessageObject.TYPE_GIF) { FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); if (currentMessageObject.loadedFileSize > 0) { createLoadingProgressLayout(documentAttach); } } else if (isRoundVideo) { if (currentMessageObject.isSecretMedia()) { FileLoader.getInstance(currentAccount).loadFile(currentMessageObject.getDocument(), currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); } else { currentMessageObject.gifState = 2; TLRPC.Document document = currentMessageObject.getDocument(); photoImage.setForceLoading(true); photoImage.setImage(ImageLocation.getForDocument(document), null, ImageLocation.getForObject(thumb, document), thumbFilter, document.size, null, currentMessageObject, 0); } wouldBeInPip = true; ChatMessageCell.this.invalidate(); } else if (currentMessageObject.type == MessageObject.TYPE_FILE) { FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); if (currentMessageObject.loadedFileSize > 0) { createLoadingProgressLayout(documentAttach); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL, cacheType); if (currentMessageObject.loadedFileSize > 0) { createLoadingProgressLayout(currentMessageObject.getDocument()); } } else if (currentMessageObject.type == MessageObject.TYPE_TEXT && documentAttachType != DOCUMENT_ATTACH_TYPE_NONE) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { photoImage.setForceLoading(true); photoImage.setImage(ImageLocation.getForDocument(documentAttach), null, ImageLocation.getForDocument(currentPhotoObject, documentAttach), currentPhotoFilterThumb, documentAttach.size, null, currentMessageObject, cacheType); currentMessageObject.gifState = 2; if (currentMessageObject.loadedFileSize > 0) { createLoadingProgressLayout(currentMessageObject.getDocument()); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER) { photoImage.setImage(ImageLocation.getForDocument(documentAttach), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObject, documentAttach), "b1", 0, "jpg", currentMessageObject, 1); } } else { photoImage.setForceLoading(true); photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, currentMessageObject, 0); } currentMessageObject.loadingCancelled = false; buttonState = 1; if (video) { videoRadialProgress.setIcon(MediaActionDrawable.ICON_CANCEL_FILL, false, animated); } else { radialProgress.setIcon(getIconForCurrentState(), false, animated); } invalidate(); } } else if (buttonState == 1 && (!drawVideoImageButton || video)) { photoImage.setForceLoading(false); if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen()) { boolean result = MediaController.getInstance().pauseMessage(currentMessageObject); if (result) { buttonState = 0; radialProgress.setIcon(getIconForCurrentState(), false, animated); invalidate(); } } else { if (currentMessageObject.isOut() && !drawVideoImageButton && (currentMessageObject.isSending() || currentMessageObject.isEditing())) { if (radialProgress.getIcon() != MediaActionDrawable.ICON_CHECK) { delegate.didPressCancelSendButton(this); } } else { currentMessageObject.loadingCancelled = true; if ( documentAttachType == DOCUMENT_ATTACH_TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER ) { FileLoader.getInstance(currentAccount).cancelLoadFile(documentAttach); } else if ( currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW || currentMessageObject.type == MessageObject.TYPE_GIF || currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO ) { ImageLoader.getInstance().cancelForceLoadingForImageReceiver(photoImage); photoImage.cancelLoadImage(); } else if (currentMessageObject.type == MessageObject.TYPE_FILE) { FileLoader.getInstance(currentAccount).cancelLoadFile(currentMessageObject.getDocument()); } buttonState = 0; if (video) { videoRadialProgress.setIcon(MediaActionDrawable.ICON_DOWNLOAD, false, animated); } else { radialProgress.setIcon(getIconForCurrentState(), false, animated); } invalidate(); } } } else if (buttonState == 2) { if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_STORY) { delegate.didPressImage(this, 0, 0, false); } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen()) { if (miniButtonState == 0) { FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); currentMessageObject.loadingCancelled = false; } if (delegate.needPlayMessage(this, currentMessageObject, false)) { if (hasMiniProgress == 2 && miniButtonState != 1) { miniButtonState = 1; radialProgress.setProgress(0, false); radialProgress.setMiniIcon(getMiniIconForCurrentState(), false, true); } updatePlayingMessageProgress(); buttonState = 1; radialProgress.setIcon(getIconForCurrentState(), false, true); invalidate(); } if (isRoundVideo) { wouldBeInPip = true; ChatMessageCell.this.invalidate(); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { radialProgress.setProgress(0, false); FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); currentMessageObject.loadingCancelled = false; buttonState = 4; radialProgress.setIcon(getIconForCurrentState(), true, animated); invalidate(); } else { if (isRoundVideo) { MessageObject playingMessage = MediaController.getInstance().getPlayingMessageObject(); if (playingMessage == null || !playingMessage.isRoundVideo()) { photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); } } else { photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); } currentMessageObject.gifState = 0; buttonState = -1; radialProgress.setIcon(getIconForCurrentState(), false, animated); } } else if (buttonState == 3 || buttonState == 0) { if (hasMiniProgress == 2 && miniButtonState != 1) { miniButtonState = 1; radialProgress.setProgress(0, false); radialProgress.setMiniIcon(getMiniIconForCurrentState(), false, animated); } if (delegate != null) { delegate.didPressImage(this, 0, 0, false); } } else if (buttonState == 4) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen()) { if (currentMessageObject.isOut() && (currentMessageObject.isSending() || currentMessageObject.isEditing()) || currentMessageObject.isSendError()) { if (delegate != null && radialProgress.getIcon() != MediaActionDrawable.ICON_CHECK) { delegate.didPressCancelSendButton(this); } } else { currentMessageObject.loadingCancelled = true; FileLoader.getInstance(currentAccount).cancelLoadFile(documentAttach); buttonState = 2; radialProgress.setIcon(getIconForCurrentState(), false, animated); invalidate(); } } } } @Override public void onFailedDownload(String fileName, boolean canceled) { updateButtonState(true, documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC, false); } @Override public void onSuccessDownload(String fileName) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER && currentMessageObject.isDice()) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); setCurrentDiceValue(true); } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { updateButtonState(false, true, false); updateWaveform(); } else { currentMessageObject.updateQualitiesCached(true); if (drawVideoImageButton) { videoRadialProgress.setProgress(1, true); } else { radialProgress.setProgress(1, true); } if (!currentMessageObject.needDrawBluredPreview() && !autoPlayingMedia && documentAttach != null) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { photoImage.setImage(ImageLocation.getForDocument(documentAttach), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || currentPhotoObject != null && "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, documentAttach.size, null, currentMessageObject, 0); photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); autoPlayingMedia = true; } else if (!isSmallImage && !currentMessageObject.isHiddenSensitive() && (!currentMessageObject.hasVideoCover() || currentMessageObject.isLivePhoto()) && SharedConfig.isAutoplayVideo() && !currentMessageObject.isRepostPreview && documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0)) { animatingNoSound = 2; if (currentMessageObject.cachedQuality != null) { photoImage.setImage(ImageLocation.getForVideoPath(currentMessageObject.cachedQuality.uri.getPath()), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || currentPhotoObject != null && "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, documentAttach.size, null, currentMessageObject, 0); } else { photoImage.setImage(ImageLocation.getForDocument(documentAttach), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || currentPhotoObject != null && "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, documentAttach.size, null, currentMessageObject, 0); } if (!PhotoViewer.isPlayingMessage(currentMessageObject)) { photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); } else { photoImage.setAllowStartAnimation(false); } autoPlayingMedia = true; } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { if (currentMessageObject.cachedQuality != null) { photoImage.setImage(ImageLocation.getForVideoPath(currentMessageObject.cachedQuality.uri.getPath()), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || currentPhotoObject != null && "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, documentAttach.size, null, currentMessageObject, 0); } else { photoImage.setImage(ImageLocation.getForDocument(documentAttach), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || currentPhotoObject != null && "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, documentAttach.size, null, currentMessageObject, 0); } if (!currentMessageObject.isHiddenSensitive() && SharedConfig.isAutoplayGifs() && !currentMessageObject.isRepostPreview) { photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); } else { photoImage.setAllowStartAnimation(false); photoImage.stopAnimation(); } autoPlayingMedia = true; } } if (currentMessageObject.type == MessageObject.TYPE_TEXT) { if (!autoPlayingMedia && documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && currentMessageObject.gifState != 1) { buttonState = 2; didPressButton(true, false); } else if (!photoNotSet) { updateButtonState(false, true, false); } else { setMessageObject(currentMessageObject, currentMessagesGroup, pinnedBottom, pinnedTop, firstInChat); } } else { if (!photoNotSet) { updateButtonState(false, true, false); } if (photoNotSet) { setMessageObject(currentMessageObject, currentMessagesGroup, pinnedBottom, pinnedTop, firstInChat); } } } } @Override public void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb, boolean memCache) { if (currentMessageObject != null && set) { if (setCurrentDiceValue(!memCache && !currentMessageObject.wasUnread)) { return; } if ( thumb && currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW && !currentMessageObject.mediaExists || !thumb && !currentMessageObject.mediaExists && !currentMessageObject.attachPathExists && ( currentMessageObject.type == MessageObject.TYPE_TEXT && ( documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || documentAttachType == DOCUMENT_ATTACH_TYPE_NONE || documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER ) || currentMessageObject.type == MessageObject.TYPE_PHOTO ) ) { currentMessageObject.mediaExists = true; updateButtonState(false, true, false); } } if (set && currentMessageObject != null) { clearBlurredImage(blurredPhotoImage); if ((currentMessageObject.hasMediaSpoilers() || fitPhotoImage) && imageReceiver.getBitmap() != null && !imageReceiver.getBitmap().isRecycled()) { blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(imageReceiver.getBitmap(), currentMessageObject.isRoundVideo())); blurredPhotoImage.setColorFilter(getFancyBlurFilter()); } } } public boolean setCurrentDiceValue(boolean instant) { if (!currentMessageObject.isDice()) { return false; } Drawable drawable = photoImage.getDrawable(); if (!(drawable instanceof RLottieDiceDrawable)) { return false; } RLottieDiceDrawable lottieDrawable = (RLottieDiceDrawable) drawable; String emoji = currentMessageObject.getDiceEmoji(); TLRPC.TL_messages_stickerSet stickerSet = MediaDataController.getInstance(currentAccount).getStickerSetByEmojiOrName(emoji); if (stickerSet == null) { MediaDataController.getInstance(currentAccount).loadStickersByEmojiOrName(emoji, true, true); return false; } int value = currentMessageObject.getDiceValue(); if ("\uD83C\uDFB0".equals(currentMessageObject.getDiceEmoji())) { if (value >= 0 && value <= 64) { ((SlotsDrawable) lottieDrawable).setDiceNumber(this, value, stickerSet, instant); if (currentMessageObject.isOut()) { lottieDrawable.setOnFinishCallback(diceFinishCallback, Integer.MAX_VALUE); } currentMessageObject.wasUnread = false; } if (!lottieDrawable.hasBaseDice() && stickerSet.documents.size() > 0) { ((SlotsDrawable) lottieDrawable).setBaseDice(this, stickerSet); } } else { if (!lottieDrawable.hasBaseDice() && stickerSet.documents.size() > 0) { TLRPC.Document document = stickerSet.documents.get(0); File path = FileLoader.getInstance(currentAccount).getPathToAttach(document, true); if (lottieDrawable.setBaseDice(path)) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); } else { String fileName = FileLoader.getAttachFileName(document); DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); FileLoader.getInstance(currentAccount).loadFile(document, stickerSet, FileLoader.PRIORITY_NORMAL, 1); } } if (value >= 0 && value < stickerSet.documents.size()) { if (!instant && currentMessageObject.isOut()) { MessagesController.DiceFrameSuccess frameSuccess = MessagesController.getInstance(currentAccount).diceSuccess.get(emoji); if (frameSuccess != null && frameSuccess.num == value) { lottieDrawable.setOnFinishCallback(diceFinishCallback, frameSuccess.frame); } } TLRPC.Document document = stickerSet.documents.get(Math.max(value, 0)); File path = FileLoader.getInstance(currentAccount).getPathToAttach(document, true); if (lottieDrawable.setDiceNumber(path, instant)) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); } else { String fileName = FileLoader.getAttachFileName(document); DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); FileLoader.getInstance(currentAccount).loadFile(document, stickerSet, FileLoader.PRIORITY_NORMAL, 1); } currentMessageObject.wasUnread = false; } } return true; } @Override public void onAnimationReady(ImageReceiver imageReceiver) { if (currentMessageObject != null && imageReceiver == photoImage && currentMessageObject.isAnimatedSticker()) { delegate.setShouldNotRepeatSticker(currentMessageObject); } } @Override public void onProgressDownload(String fileName, long downloadedSize, long totalSize) { float progress = totalSize == 0 ? 0 : Math.min(1f, downloadedSize / (float) totalSize); currentMessageObject.loadedFileSize = downloadedSize; createLoadingProgressLayout(downloadedSize, totalSize); if (drawVideoImageButton) { videoRadialProgress.setProgress(progress, true); } else { radialProgress.setProgress(progress, true); } if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { if (hasMiniProgress != 0) { if (miniButtonState != 1) { updateButtonState(false, false, false); } } else { if (buttonState != 4) { updateButtonState(false, false, false); } } } else { if (hasMiniProgress != 0) { if (miniButtonState != 1) { updateButtonState(false, false, false); } } else { if (buttonState != 1) { updateButtonState(false, false, false); } } } } @Override public void onProgressUpload(String fileName, long uploadedSize, long totalSize, boolean isEncrypted) { float progress = totalSize == 0 ? 0 : Math.min(1f, uploadedSize / (float) totalSize); currentMessageObject.loadedFileSize = uploadedSize; radialProgress.setProgress(progress, true); if (uploadedSize == totalSize && (currentPosition != null || currentMessageObject.isPaid())) { boolean sending = SendMessagesHelper.getInstance(currentAccount).isSendingMessage(currentMessageObject.getId()); if (sending && (buttonState == 1 || buttonState == 4 && documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC)) { drawRadialCheckBackground = true; getIconForCurrentState(); radialProgress.setIcon(MediaActionDrawable.ICON_CHECK, false, true); } } if (lastLoadingSizeTotal > 0 && Math.abs(lastLoadingSizeTotal - totalSize) > UPLOADING_ALLOWABLE_ERROR) { lastLoadingSizeTotal = totalSize; } createLoadingProgressLayout(uploadedSize, totalSize); } private void createLoadingProgressLayout(TLRPC.Document document) { if (document == null) { return; } long[] progresses = ImageLoader.getInstance().getFileProgressSizes(FileLoader.getDocumentFileName(document)); if (progresses != null) { createLoadingProgressLayout(progresses[0], progresses[1]); } else { createLoadingProgressLayout(currentMessageObject.loadedFileSize, document.size); } } private void createLoadingProgressLayout(long loadedSize, long totalSize) { if (totalSize <= 0 || documentAttach == null) { loadingProgressLayout = null; return; } long hash = (loadedSize << 16) + totalSize; if (loadingProgressLayout != null && loadingProgressLayoutHash == hash) { return; } loadingProgressLayoutHash = hash; if (lastLoadingSizeTotal == 0) { lastLoadingSizeTotal = totalSize; } else { totalSize = lastLoadingSizeTotal; if (loadedSize > lastLoadingSizeTotal) { loadedSize = lastLoadingSizeTotal; } } String totalStr = AndroidUtilities.formatFileSize(totalSize); String maxAvailableString = String.format("000.0 mm / %s", totalStr); String str; int w; w = (int) Math.ceil(Theme.chat_infoPaint.measureText(maxAvailableString)); boolean fullWidth = true; if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { int max = Math.max(this.infoWidth, docTitleWidth); if (w <= max) { str = String.format("%s / %s", AndroidUtilities.formatFileSize(loadedSize), totalStr); } else { str = AndroidUtilities.formatFileSize(loadedSize); } } else { if (currentPosition != null) { int mask = MessageObject.POSITION_FLAG_LEFT | MessageObject.POSITION_FLAG_RIGHT; fullWidth = (currentPosition.flags & mask) == mask; } if (!fullWidth) { int percent = (int) (Math.min(1f, loadedSize / (float) totalSize) * 100); if (percent >= 100) { str = "100%"; } else { str = String.format(Locale.US, "%2d%%", percent); } } else { str = String.format("%s / %s", AndroidUtilities.formatFileSize(loadedSize), totalStr); } } w = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); if (fullWidth && w > backgroundWidth - dp(48)) { int percent = (int) (Math.min(1f, loadedSize / (float) totalSize) * 100); if (percent >= 100) { str = "100%"; } else { str = String.format(Locale.US, "%2d%%", percent); } w = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); } loadingProgressLayout = new StaticLayout(str, Theme.chat_infoPaint, w, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } @Override public void onProvideStructure(ViewStructure structure) { super.onProvideStructure(structure); if (allowAssistant && Build.VERSION.SDK_INT >= 23) { if (currentMessageObject != null && currentMessageObject.messageText != null && currentMessageObject.messageText.length() > 0) { structure.setText(currentMessageObject.messageText); } else if (currentMessageObject != null && currentMessageObject.caption != null && currentMessageObject.caption.length() > 0) { structure.setText(currentMessageObject.caption); } } } public void setDelegate(ChatMessageCellDelegate chatMessageCellDelegate) { delegate = chatMessageCellDelegate; } public ChatMessageCellDelegate getDelegate() { return delegate; } public void setAllowAssistant(boolean value) { allowAssistant = value; } private void measureTime(MessageObject messageObject) { CharSequence signString; MessageObject primaryMessageObject = getPrimaryMessageObject(); long fromId = messageObject.getFromChatId(); if (messageObject.scheduled) { signString = null; } else if (primaryMessageObject.messageOwner.via_business_bot_id != 0) { TLRPC.User botUser = MessagesController.getInstance(messageObject.currentAccount).getUser(primaryMessageObject.messageOwner.via_business_bot_id); if (botUser == null) { signString = null; } else { signString = UserObject.getUserName(botUser); } } else if (messageObject.messageOwner.post_author != null) { if (isMegagroup && messageObject.getFromChatId() == messageObject.getDialogId()) { signString = null; } else { signString = messageObject.messageOwner.post_author.replace("\n", ""); } } else if (messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.post_author != null) { signString = messageObject.messageOwner.fwd_from.post_author.replace("\n", ""); } else if (messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.imported) { if (messageObject.messageOwner.fwd_from.date == messageObject.messageOwner.date) { signString = getString("ImportedMessage", R.string.ImportedMessage); } else { signString = LocaleController.formatImportedDate(messageObject.messageOwner.fwd_from.date) + " " + getString("ImportedMessage", R.string.ImportedMessage); } } else if (!messageObject.isOutOwner() && fromId > 0 && messageObject.messageOwner.post) { TLRPC.User signUser = MessagesController.getInstance(currentAccount).getUser(fromId); if (signUser != null) { signString = ContactsController.formatName(signUser.first_name, signUser.last_name).replace('\n', ' '); } else { signString = null; } } else { signString = null; } if (messageObject.getDialogId() < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-messageObject.getDialogId()); if (chat != null && chat.signature_profiles && (messageObject.messageOwner.flags & 256) != 0) { signString = null; } } String timeString; TLRPC.User author = null; if (currentMessageObject.isFromUser()) { author = MessagesController.getInstance(currentAccount).getUser(fromId); } boolean hasReplies = messageObject.hasReplies(); if (messageObject.scheduled || messageObject.messageOwner.edit_hide) { edited = false; } else if (currentPosition == null || currentMessagesGroup == null || currentMessagesGroup.messages.isEmpty()) { edited = (messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_EDITED) != 0 || messageObject.isEditing(); } else { edited = false; hasReplies = currentMessagesGroup.messages.get(0).hasReplies(); if (!currentMessagesGroup.messages.get(0).messageOwner.edit_hide) { for (int a = 0, size = currentMessagesGroup.messages.size(); a < size; a++) { MessageObject object = currentMessagesGroup.messages.get(a); if ((object.messageOwner.flags & TLRPC.MESSAGE_FLAG_EDITED) != 0 || object.isEditing()) { edited = true; break; } } } } if (currentMessageObject.isWelcomeMessage()) { timeString = ""; // Long.toString(currentMessageObject.getId()); } else if (currentMessageObject.notime || currentMessageObject.isSponsored() || currentMessageObject.isQuickReply() || currentMessageObject.isWelcomeMessage()) { timeString = ""; } else if (currentMessageObject.scheduled && currentMessageObject.messageOwner.date == 0x7FFFFFFE) { timeString = ""; } else if (currentMessageObject.realDate != 0) { timeString = LocaleController.formatSmallDateChat(currentMessageObject.realDate) + ", " + LocaleController.getInstance().getFormatterDay().format((long) (currentMessageObject.realDate) * 1000); } else if (currentMessageObject.isRepostPreview) { timeString = LocaleController.formatSmallDateChat(messageObject.messageOwner.date) + ", " + LocaleController.getInstance().getFormatterDay().format((long) (messageObject.messageOwner.date) * 1000); } else if (edited) { if (AppGlobalConfig.getInstance(currentAccount).messagePrimaryEditedDate.get()) { int editDate = currentMessagesGroup != null ? currentMessagesGroup.getMaxEditDate() : messageObject.messageOwner.edit_date; if (editDate == 0 && currentMessageObject.isEditing()) { editDate = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); } timeString = LocaleController.formatPmEditedDate(editDate); } else { timeString = (getString(R.string.EditedMessage) + " " + LocaleController.getInstance().getFormatterDay().format((long) (messageObject.messageOwner.date) * 1000)); } } else if (currentMessageObject.isSaved && currentMessageObject.messageOwner.fwd_from != null && (currentMessageObject.messageOwner.fwd_from.date != 0 || currentMessageObject.messageOwner.fwd_from.saved_date != 0)) { int date = currentMessageObject.messageOwner.fwd_from.saved_date; if (date == 0) { date = currentMessageObject.messageOwner.fwd_from.date; } timeString = LocaleController.formatSeenDate(date); } else { timeString = LocaleController.getInstance().getFormatterDay().format((long) (messageObject.messageOwner.date) * 1000); } if (currentMessageObject.messageOwner.video_processing_pending) { timeString = formatString(R.string.ScheduledTimeApprox, timeString); } if (signString != null) { if (messageObject.messageOwner.via_business_bot_id != 0) { currentTimeString = timeString + ", "; } else if (messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.imported) { currentTimeString = " " + timeString; } else { currentTimeString = ", " + timeString; } } else { currentTimeString = timeString; } if (currentMessageObject.isStakedDice()) { currentTimeString = TextUtils.concat("💎", StarsIntroActivity.formatTON(currentMessageObject.getStakedDiceAmount()), " ", currentTimeString); currentTimeString = StarsIntroActivity.replaceDiamond(currentTimeString, 0.55f, null, 0, dp(-.33f), 1.05f); } final long starsPrice = currentMessageObject.getDialogId() < 0 ? getStarsPrice() : 0; if (starsPrice > 0) { currentTimeString = TextUtils.concat("⭐️", AndroidUtilities.formatWholeNumber((int) starsPrice, 0), " ", currentTimeString); currentTimeString = StarsIntroActivity.replaceStars(currentTimeString, 0.8f, null, 0, dp(-.33f), 0.94f); } if (currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.schedule_repeat_period != 0) { final int period = currentMessageObject.messageOwner.schedule_repeat_period; if (period == 365 * 86400) { currentTimeString = TextUtils.concat(getString(R.string.MessageScheduledRepeatYearly), ", ", currentTimeString); } else if (period == 182 * 86400) { currentTimeString = TextUtils.concat(formatPluralString("MessageScheduledRepeatMonthlyMany", 6), ", ", currentTimeString); } else if (period == 91 * 86400) { currentTimeString = TextUtils.concat(formatPluralString("MessageScheduledRepeatMonthlyMany", 3), ", ", currentTimeString); } else if (period == 30 * 86400) { currentTimeString = TextUtils.concat(getString(R.string.MessageScheduledRepeatMonthly), ", ", currentTimeString); } else if (period == 14 * 86400) { currentTimeString = TextUtils.concat(getString(R.string.MessageScheduledRepeatBiweekly), ", ", currentTimeString); } else if (period == 7 * 86400) { currentTimeString = TextUtils.concat(getString(R.string.MessageScheduledRepeatWeekly), ", ", currentTimeString); } else if (period == 86400) { currentTimeString = TextUtils.concat(getString(R.string.MessageScheduledRepeatDaily), ", ", currentTimeString); } else { currentTimeString = TextUtils.concat(formatString(R.string.MessageScheduledRepeatSeconds, period), ", ", currentTimeString); } } timeTextWidth = timeWidth = (int) Math.ceil(Theme.chat_timePaint.measureText(currentTimeString, 0, currentTimeString == null ? 0 : currentTimeString.length())); if (currentMessageObject.scheduled && currentMessageObject.messageOwner.date == 0x7FFFFFFE || currentMessageObject.notime) { timeWidth -= dp(8); } final boolean isInWelcomeMessages = delegate != null && delegate.getChatMode() == ChatActivity.MODE_WELCOME_MESSAGES; if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0 && !isInWelcomeMessages) { currentViewsString = String.format("%s", LocaleController.formatShortNumber(Math.max(1, messageObject.messageOwner.views), null)); viewsTextWidth = (int) Math.ceil(Theme.chat_timePaint.measureText(currentViewsString)); float drawableWidth = Theme.chat_msgInViewsDrawable.getIntrinsicWidth() * (Theme.chat_timePaint.getTextSize() - dp(2)) / Theme.chat_msgInViewsDrawable.getIntrinsicHeight(); timeWidth += viewsTextWidth + drawableWidth + dp(10); } if (messageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW) { String str = formatString(R.string.PaymentCheckoutPay, LocaleController.getInstance().formatCurrencyString(messageObject.messageOwner.media.total_amount, messageObject.messageOwner.media.currency).toUpperCase(Locale.ROOT)); currentUnlockString = str.length() >= 2 ? str.substring(0, 1).toUpperCase(Locale.ROOT) + str.substring(1).toLowerCase(Locale.ROOT) : str; unlockTextWidth = (int) Math.ceil(Theme.chat_unlockExtendedMediaTextPaint.measureText(currentUnlockString)); } if (isChat && isMegagroup && (!isThreadChat || isMonoForum) && hasReplies) { currentRepliesString = String.format("%s", LocaleController.formatShortNumber(getRepliesCount(), null)); repliesTextWidth = (int) Math.ceil(Theme.chat_timePaint.measureText(currentRepliesString)); float drawableWidth = Theme.chat_msgInRepliesDrawable.getIntrinsicWidth() * (Theme.chat_timePaint.getTextSize() - dp(2)) / Theme.chat_msgInRepliesDrawable.getIntrinsicHeight(); timeWidth += repliesTextWidth + drawableWidth + dp(10); } else { currentRepliesString = null; } if (isPinned) { timeWidth += Theme.chat_msgInPinnedDrawable.getIntrinsicWidth() + dp(3); } if (messageObject.scheduled) { if (messageObject.isSendError()) { timeWidth += dp(18); } else if (messageObject.isSending() && messageObject.messageOwner.peer_id.channel_id != 0 && !messageObject.isSupergroup()) { timeWidth += dp(18); } } if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(Integer.MAX_VALUE, Gravity.LEFT); timeWidth += reactionsLayoutInBubble.width; } TLRPC.TL_availableEffect effect = getEffect(); if (effectId != (effect != null ? effect.id : 0)) { if (effectDrawable == null) { effectDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, !(delegate != null && delegate.canDrawOutboundsContent()), dp(14), AnimatedEmojiDrawable.CACHE_TYPE_MESSAGE_EFFECT_MINI); } final boolean animated = effectMessageId == currentMessageObject.getId(); if (effect != null) { if (!TextUtils.isEmpty(effect.emoticon)) { effectDrawable.set(Emoji.getEmojiDrawable(effect.emoticon), animated); } else if ((effect.flags & 1) != 0) { effectDrawable.set(effect.static_icon_id, animated); } } else { effectDrawable.set((Drawable) null, animated); } effectId = effect != null ? effect.id : 0; effectMessageId = currentMessageObject.getId(); } if (effectId != 0 && !currentMessageObject.notime) { timeWidth += dp(14 + 4); } if (signString != null) { if (availableTimeWidth == 0) { availableTimeWidth = dp(1000); } int widthForSign = availableTimeWidth - timeWidth; if (messageObject.isOutOwner()) { if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { widthForSign -= dp(20); } else { widthForSign -= dp(96); } } signString = Emoji.replaceEmoji(signString, Theme.chat_timePaint.getFontMetricsInt(), false); int width = (int) Math.ceil(Theme.chat_timePaint.measureText(signString, 0, signString.length())); signWidth = Math.min(width, widthForSign); if (width > widthForSign) { if (widthForSign <= 0) { signString = ""; width = 0; } else { signString = TextUtils.ellipsize(signString, Theme.chat_timePaint, widthForSign, TextUtils.TruncateAt.END); width = widthForSign; } } SpannableStringBuilder currentTimeStringBuilder = new SpannableStringBuilder(); if (messageObject.messageOwner.via_business_bot_id != 0) { currentTimeStringBuilder.append(currentTimeString); currentTimeStringBuilder.append(signString); } else { currentTimeStringBuilder.append(signString); currentTimeStringBuilder.append(currentTimeString); } currentTimeString = currentTimeStringBuilder; timeTextWidth += width; timeWidth += width; } else { signWidth = 0; } } protected boolean shouldDrawSelectionOverlay() { return hasSelectionOverlay() && (isPressed() && isCheckPressed || !isCheckPressed && isPressed || isHighlighted || isHighlightedAnimated) && !textIsSelectionMode() && (currentMessagesGroup == null || drawSelectionBackground) && currentBackgroundDrawable != null; } private int getSelectionOverlayColor() { if (resourcesProvider == null) { return 0; } return resourcesProvider.getColor(currentMessageObject != null && currentMessageObject.isOut() ? Theme.key_chat_outBubbleSelectedOverlay : Theme.key_chat_inBubbleSelectedOverlay); } private boolean hasSelectionOverlay() { int selectionOverlayColor = getSelectionOverlayColor(); return selectionOverlayColor != 0 && selectionOverlayColor != 0xffff0000; } public boolean isDrawSelectionBackground() { return (isPressed() && isCheckPressed || !isCheckPressed && isPressed || isHighlighted) && !textIsSelectionMode() && !hasSelectionOverlay() && (currentMessageObject == null || !currentMessageObject.preview); } private boolean isOpenChatByShare(MessageObject messageObject) { return messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.saved_from_peer != null && (delegate == null || delegate.isReplyOrSelf()); } protected boolean checkNeedDrawShareButton(MessageObject messageObject) { if (isReportChat) return false; if (currentMessageObject.deleted && !currentMessageObject.deletedByThanos) return false; if (currentMessageObject.isSponsored()) return false; if (currentMessageObject.isEphemeral()) return false; if (currentMessagesGroup != null && currentPosition != null) { final boolean last = (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & (messageObject.isOutOwner() ? MessageObject.POSITION_FLAG_LEFT : MessageObject.POSITION_FLAG_RIGHT)) != 0; if (!currentMessagesGroup.isDocuments && !last) { return false; } } return messageObject.needDrawShareButton(); } public boolean isInsideBackground(float x, float y) { return currentBackgroundDrawable != null && x >= backgroundDrawableLeft && x <= backgroundDrawableLeft + backgroundDrawableRight; } private void updateCurrentUserAndChat() { if (currentMessageObject == null) { return; } MessagesController messagesController = MessagesController.getInstance(currentAccount); TLRPC.MessageFwdHeader fwd_from = currentMessageObject.messageOwner.fwd_from; long currentUserId = UserConfig.getInstance(currentAccount).getClientUserId(); if (fwd_from != null && fwd_from.from_id instanceof TLRPC.TL_peerChannel && (currentMessageObject.getDialogId() == currentUserId || currentMessageObject.getDialogId() == UserObject.REPLY_BOT)) { currentChat = MessagesController.getInstance(currentAccount).getChat(fwd_from.from_id.channel_id); } else if (fwd_from != null && currentMessageObject.getDialogId() == UserObject.VERIFY) { long did = DialogObject.getPeerDialogId(fwd_from.from_id); if (did >= 0) { currentUser = messagesController.getUser(did); } else { currentChat = messagesController.getChat(-did); } } else if (fwd_from != null && fwd_from.saved_from_peer != null) { if (fwd_from.saved_from_peer.user_id != 0) { if (!isSavedChat && fwd_from.from_id instanceof TLRPC.TL_peerUser) { currentUser = messagesController.getUser(fwd_from.from_id.user_id); } else { currentUser = messagesController.getUser(fwd_from.saved_from_peer.user_id); } } else if (fwd_from.saved_from_peer.channel_id != 0) { if (currentMessageObject.isSavedFromMegagroup() && fwd_from.from_id instanceof TLRPC.TL_peerUser) { currentUser = messagesController.getUser(fwd_from.from_id.user_id); } else { currentChat = messagesController.getChat(fwd_from.saved_from_peer.channel_id); } } else if (fwd_from.saved_from_peer.chat_id != 0) { if (fwd_from.from_id instanceof TLRPC.TL_peerUser) { currentUser = messagesController.getUser(fwd_from.from_id.user_id); } else { currentChat = messagesController.getChat(fwd_from.saved_from_peer.chat_id); } } } else if (fwd_from != null && fwd_from.from_id instanceof TLRPC.TL_peerUser && (fwd_from.imported || currentMessageObject.getDialogId() == currentUserId)) { currentUser = messagesController.getUser(fwd_from.from_id.user_id); } else if (fwd_from != null && !TextUtils.isEmpty(fwd_from.saved_from_name) && (fwd_from.imported || currentMessageObject.getDialogId() == currentUserId)) { currentUser = new TLRPC.TL_user(); currentUser.first_name = fwd_from.saved_from_name; } else if (fwd_from != null && !TextUtils.isEmpty(fwd_from.from_name) && (fwd_from.imported || currentMessageObject.getDialogId() == currentUserId)) { currentUser = new TLRPC.TL_user(); currentUser.first_name = fwd_from.from_name; } /*else if (currentMessageObject.isWelcomeAnchored()) { final long did = currentMessageObject.getDialogId(); if (did > 0) { currentUser = messagesController.getUser(did); } else { currentChat = messagesController.getChat(-did); } } */else { long did = currentMessageObject.getDialogId(); long fromId = currentMessageObject.getFromChatId(); TLRPC.Chat fromChat = null; if (DialogObject.isChatDialog(fromId)) { fromChat = messagesController.getChat(-fromId); } TLRPC.Chat chat = null; if (DialogObject.isChatDialog(did)) { chat = messagesController.getChat(-did); } if (DialogObject.isEncryptedDialog(currentMessageObject.getDialogId())) { if (currentMessageObject.isOutOwner()) { currentUser = UserConfig.getInstance(currentAccount).getCurrentUser(); } else { TLRPC.EncryptedChat echat = messagesController.getEncryptedChat(DialogObject.getEncryptedChatId(currentMessageObject.getDialogId())); if (echat != null) { currentUser = messagesController.getUser(echat.user_id); } } } else if (DialogObject.isUserDialog(fromId) && (!currentMessageObject.messageOwner.post || fromChat != null && fromChat.signature_profiles)) { currentUser = messagesController.getUser(fromId); } else if (currentMessageObject.messageOwner.post && chat != null && !chat.signature_profiles) { currentChat = chat; } else if (DialogObject.isChatDialog(fromId)) { currentChat = fromChat; } else if (currentMessageObject.messageOwner.post) { currentChat = messagesController.getChat(currentMessageObject.messageOwner.peer_id.channel_id); } } } private void setMessageObjectInternal(MessageObject messageObject) { if (((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0 || messageObject.messageOwner.replies != null) && !currentMessageObject.scheduled && !currentMessageObject.isSponsored()) { if (!currentMessageObject.viewsReloaded) { MessagesController.getInstance(currentAccount).addToViewsQueue(currentMessageObject); currentMessageObject.viewsReloaded = true; } } updateCurrentUserAndChat(); setAvatar(messageObject); measureTime(messageObject); namesOffset = 0; final boolean isEphemeral = (messageObject.isEphemeralAndNotWelcome() || messageObject.messageOwner.ephemeralAnchorMsgId != 0 || messageObject.isWelcomeMessage() && messageObject.messageOwner.welcomeTemplateFirst ) && !messageObject.isWelcomeAnchored(); if (isEphemeral) { final ColoredImageSpan coloredImageSpan = new ColoredImageSpan(R.drawable.mini_ephemeral_hidden_14); coloredImageSpan.setColorKey(messageObject.shouldDrawWithoutBackground() ? getThemedColor(Theme.key_chat_stickerReplyNameText) : messageObject.isOut() && (resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark()) ? Theme.key_chat_messageLinkOut : Theme.key_chat_tagAdmin); // coloredImageSpan.setTopOffset(1); SpannableStringBuilder ssb = new SpannableStringBuilder("* "); if (delegate != null && delegate.getChatMode() == ChatActivity.MODE_WELCOME_MESSAGES) { ssb.append(getString(R.string.EphemeralMessageVisibleToYou)); } else if (messageObject.isOut()) { final long botId = messageObject.getEphemeralReceiverBotId(); String username = botId != 0 ? UserObject.getPublicUsername(MessagesController.getInstance(currentAccount).getUser(botId)) : ""; if (username == null) { username = ""; } ssb.append(formatString(R.string.EphemeralMessageVisibleToOther, username)); } else { ssb.append(getString(R.string.EphemeralMessageVisibleToYou)); } ssb.setSpan(coloredImageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); totalHeight += dp(EPHEMERAL_HINT_HEIGHT - (messageObject.isReply() ? 4 : 0)); namesOffset += dp(EPHEMERAL_HINT_HEIGHT - (messageObject.isReply() ? 4 : 0)); ephemeralLayout = new StaticLayout(ssb, Theme.chat_ephemeralPaint, dp(300), Layout.Alignment.ALIGN_NORMAL, 0f, 0f, false); ephemeralWidth = ephemeralLayout.getLineCount() > 0 ? ((int) ephemeralLayout.getLineWidth(0) + dp(10)) : 0; } String viaUsername = null; CharSequence viaString = null; if (messageObject.isWelcomeMessage() && !messageObject.isWelcomeAnchored() && delegate != null && delegate.getChatMode() == ChatActivity.MODE_DEFAULT && messageObject.messageOwner.from_id != null && messageObject.messageOwner.from_id.user_id != 0) { final TLRPC.User botUser = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.from_id.user_id); final String botUsername = UserObject.getPublicUsername(botUser); if (botUser != null && !TextUtils.isEmpty(botUsername)) { viaUsername = "@" + botUsername; viaString = AndroidUtilities.replaceTags(String.format(" %s %s", getString("ViaBot", R.string.ViaBot), viaUsername)); viaWidth = (int) Math.ceil(Theme.chat_replyNamePaint.measureText(viaString, 0, viaString.length())); currentViaBotUser = botUser; } } else if (messageObject.messageOwner.via_bot_id != 0) { final TLRPC.User botUser = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.via_bot_id); final String botUsername = UserObject.getPublicUsername(botUser); if (botUser != null && !TextUtils.isEmpty(botUsername)) { viaUsername = "@" + botUsername; viaString = AndroidUtilities.replaceTags(String.format(" %s %s", getString("ViaBot", R.string.ViaBot), viaUsername)); viaWidth = (int) Math.ceil(Theme.chat_replyNamePaint.measureText(viaString, 0, viaString.length())); currentViaBotUser = botUser; } } else if (!TextUtils.isEmpty(messageObject.messageOwner.via_bot_name)) { viaUsername = "@" + messageObject.messageOwner.via_bot_name; viaString = AndroidUtilities.replaceTags(String.format(" %s %s", getString("ViaBot", R.string.ViaBot), viaUsername)); viaWidth = (int) Math.ceil(Theme.chat_replyNamePaint.measureText(viaString, 0, viaString.length())); } boolean needAuthorName = isNeedAuthorName(); boolean viaBot = (messageObject.messageOwner.fwd_from == null || messageObject.type == MessageObject.TYPE_MUSIC) && viaUsername != null; boolean viaGuestBot = messageObject.messageOwner.guestchat_via_from != null; if (!hasPsaHint && (needAuthorName || viaBot || viaGuestBot)) { drawNameLayout = true; drawNameAvatar = !messageObject.isOutOwner() && (isForum || isMonoForum) && isSideMenuEnabled && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0) && !(messageObject.type == MessageObject.TYPE_ROUND_VIDEO || messageObject.type == MessageObject.TYPE_STICKER || messageObject.type == MessageObject.TYPE_ANIMATED_STICKER); nameWidth = getMaxNameWidth(); if (nameWidth < 0) { nameWidth = dp(100); } if (drawNameAvatar) { nameWidth -= dp(32.33f); } if (drawTopic && topicButton != null) { nameWidth -= topicButton.width + dp(8); } int adminWidth = 0; boolean isAdmin = false, isOwner = false, isTag = false; SpannableStringBuilder adminString = null; String adminLabel; if (messageObject.isWelcomeMessage()) { adminString = null; } else if (isMegagroup && currentChat != null && messageObject.messageOwner.post_author != null && currentChat.id == -currentMessageObject.getFromChatId()) { adminString = new SpannableStringBuilder(messageObject.messageOwner.post_author.replace("\n", "")); } else if (isMegagroup && currentChat != null && currentMessageObject.isForwardedChannelPost()) { adminString = new SpannableStringBuilder(getString(R.string.DiscussChannel)); } else if ((currentUser != null || currentChat != null) && !currentMessageObject.isOutOwner() && !currentMessageObject.isAnyKindOfSticker() && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO && delegate != null) { adminLabel = delegate.getAdminRank(currentUser != null ? currentUser.id : currentChat.id); if (messageObject.messageOwner.from_rank != null) { adminLabel = messageObject.messageOwner.from_rank; } if (adminLabel != null) { isTag = true; isOwner = delegate.isOwner(currentUser != null ? currentUser.id : currentChat.id); isAdmin = delegate.isAdmin(currentUser != null ? currentUser.id : currentChat.id); if (adminLabel.isEmpty()) { adminLabel = getString(isOwner ? R.string.ChatTagOwner : R.string.ChatTagAdmin); } adminString = new SpannableStringBuilder(adminLabel); } } int boosts = currentMessageObject.messageOwner.from_boosts_applied; if (boosts > 0) { if (adminString == null) { adminString = new SpannableStringBuilder(); } Pair pair = BoostCounterSpan.create(this, Theme.chat_namePaint, boosts); boostCounterSpan = pair.second; boostCounterSpan.isRtl = AndroidUtilities.isRTL(adminString); boostCounterSpan.margin = isAdmin || isOwner; if (boostCounterSpan.isRtl) { adminString.insert(0, pair.first); } else { adminString.append(pair.first); } } if (adminString != null) { StaticLayout staticLayout = new StaticLayout(adminString, Theme.chat_adminPaint, dp(300), Layout.Alignment.ALIGN_NORMAL, 0f, 0f, false); adminWidth = (int) staticLayout.getLineWidth(0); if (isAdmin || isOwner) adminWidth += dp(12); nameWidth -= adminWidth; } currentNameStatus = null; nameStatusSlug = null; currentNameBotVerificationId = 0; if (messageObject.customName != null) { currentNameString = messageObject.customName; } else if (needAuthorName) { currentNameString = getAuthorName(); currentNameStatus = getAuthorStatus(); currentNameBotVerificationId = getAuthorBotVerificationId(); } else { currentNameString = ""; } int additionalWidth = dp(currentMessageObject.isSponsored() ? -24 : 0); CharSequence nameStringFinal = AndroidUtilities.removeDiacritics(currentNameString.replace('\n', ' ').replace('\u200F', ' ')); try { nameStringFinal = Emoji.replaceEmoji(nameStringFinal, Theme.chat_namePaint.getFontMetricsInt(), false); } catch (Exception ignore) {} if (currentNameStatus != null && !viaBot) { nameWidth -= dp(4 + 12 + 4); } if (currentNameBotVerificationId != 0) { nameWidth -= dp(4 + 12 + 4); } if (adminString != null) { nameWidth -= dp(8); } nameStringFinal = TextUtils.ellipsize(nameStringFinal, Theme.chat_namePaint, nameWidth + additionalWidth - (viaBot ? viaWidth : 0), TextUtils.TruncateAt.END); if (viaGuestBot) { int colorKey; if (currentMessageObject.shouldDrawWithoutBackground()) { colorKey = Theme.key_chat_stickerViaBotNameText; } else { colorKey = currentMessageObject.isOutOwner() ? Theme.key_chat_outViaBotNameText : Theme.key_chat_inViaBotNameText; } final SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); stringBuilder.append(DialogObject.getShortName(DialogObject.getPeerDialogId(messageObject.messageOwner.from_id))); int start = stringBuilder.length(); stringBuilder.append(" "); stringBuilder.append(getString(R.string.GuestBotFor)); stringBuilder.append(" "); stringBuilder.append(DialogObject.getShortName(DialogObject.getPeerDialogId(messageObject.messageOwner.guestchat_via_from))); stringBuilder.setSpan(new TypefaceSpan(Typeface.DEFAULT, 0), start, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); stringBuilder.setSpan(new ForegroundColorSpanThemable(colorKey), 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); nameStringFinal = stringBuilder; nameStringFinal = TextUtils.ellipsize(nameStringFinal, Theme.chat_namePaint, nameWidth + additionalWidth, TextUtils.TruncateAt.END); } else if (viaBot) { viaNameWidth = (int) Math.ceil(Theme.chat_namePaint.measureText(nameStringFinal, 0, nameStringFinal.length())); if (viaNameWidth != 0) { viaNameWidth += dp(4); } int color; if (currentMessageObject.shouldDrawWithoutBackground()) { color = getThemedColor(Theme.key_chat_stickerViaBotNameText); } else { color = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outViaBotNameText : Theme.key_chat_inViaBotNameText); } String viaBotString = getString(R.string.ViaBot); if (currentNameString.length() > 0) { SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); stringBuilder.append(nameStringFinal).append(" ").append(viaBotString).append(" ").append(viaUsername); stringBuilder.setSpan(viaSpan1 = new TypefaceSpan(Typeface.DEFAULT, 0, color), nameStringFinal.length() + 1, nameStringFinal.length() + 1 + viaBotString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); if (currentNameStatus != null) { viaNameWidth += dp(4 + 20 + 4); stringBuilder.setSpan(new DialogCell.FixedWidthSpan(dp(4 + 20 + 4)), nameStringFinal.length(), nameStringFinal.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } stringBuilder.setSpan(viaSpan2 = new TypefaceSpan(AndroidUtilities.bold(), 0, color), nameStringFinal.length() + 2 + viaBotString.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); nameStringFinal = stringBuilder; } else { viaOnly = true; SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); stringBuilder.append(viaBotString).append(" ").append(viaUsername); stringBuilder.setSpan(viaSpan1 = new TypefaceSpan(Typeface.DEFAULT, 0, color), 0, viaBotString.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); stringBuilder.setSpan(viaSpan2 = new TypefaceSpan(AndroidUtilities.bold(), 0, color), 1 + viaBotString.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); nameStringFinal = stringBuilder; } nameStringFinal = TextUtils.ellipsize(nameStringFinal, Theme.chat_namePaint, nameWidth + additionalWidth, TextUtils.TruncateAt.END); } try { nameLayout = new StaticLayout(nameStringFinal, Theme.chat_namePaint, nameWidth + additionalWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (nameLayout.getLineCount() > 0) { nameWidth = nameLayoutWidth = (int) Math.ceil(nameLayout.getLineWidth(0)); if (!messageObject.isAnyKindOfSticker()) { namesOffset += getNameHeight(); } nameOffsetX = nameLayout.getLineLeft(0); } else { nameWidth = nameLayoutWidth = 0; nameOffsetX = 0; } if (drawNameAvatar) { nameWidth += dp(32.33f + 4); } if (drawTopic && topicButton != null) { nameWidth += topicButton.width + dp(8); } if (currentNameStatus != null && !viaBot) { nameWidth += dp(4 + 12 + 4); } if (currentNameBotVerificationId != 0) { nameWidth += dp(4 + 12 + 4); } nameWidth -= additionalWidth; if (adminString != null) { adminLayout = new StaticLayout(adminString, Theme.chat_adminPaint, adminWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); adminLayoutIsAdmin = isAdmin || isOwner; adminLayoutIsOwner = isOwner; adminLayoutIsTag = isTag; if (!drawNameAvatar) { nameWidth += adminLayout.getLineWidth(0) + (adminLayoutIsAdmin ? dp(12) : 0) + dp(8); } else { nameWidth = (int) Math.max(nameWidth, dp(32.33f) + adminLayout.getLineWidth(0) + (isAdmin ? dp(12) : 0) + dp(8)); } boostCounterBounds = new RectF(); } else { adminLayout = null; adminLayoutIsAdmin = false; adminLayoutIsOwner = false; adminLayoutIsTag = false; boostCounterBounds = null; } } catch (Exception e) { FileLog.e(e); } if (currentNameStatusDrawable == null && currentNameStatus != null) { currentNameStatusDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, true, dp(20)); if (attachedToWindow) { currentNameStatusDrawable.attach(); } } if (currentNameStatusDrawable != null) { if (currentNameStatus == null) { currentNameStatusDrawable.set((Drawable) null, false); } else if (currentNameStatus instanceof Long) { currentNameStatusDrawable.set((long) currentNameStatus, false); } else if (currentNameStatus instanceof Drawable) { currentNameStatusDrawable.set((Drawable) currentNameStatus, false); } } if (currentNameEmojiStatusDrawable == null && currentNameBotVerificationId != 0) { currentNameEmojiStatusDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, true, dp(18)); if (attachedToWindow) { currentNameEmojiStatusDrawable.attach(); } } if (currentNameEmojiStatusDrawable != null) { if (currentNameBotVerificationId == 0) { currentNameEmojiStatusDrawable.set((Drawable) null, false); } else { currentNameEmojiStatusDrawable.set(currentNameBotVerificationId, false); } } if (currentNameString.length() == 0) { currentNameString = null; } } else { currentNameString = null; nameLayout = null; nameWidth = 0; nameOffsetX = 0; } currentForwardUser = null; currentForwardNameString = null; currentForwardChannel = null; currentForwardName = null; forwardedNameLayout[0] = null; forwardedNameLayout[1] = null; replyPanelIsForward = false; forwardedNameWidth = 0; if (messageObject.isForwarded()) { if (messageObject.messageOwner.fwd_from.from_id instanceof TLRPC.TL_peerChannel) { currentForwardChannel = MessagesController.getInstance(currentAccount).getChat(messageObject.messageOwner.fwd_from.from_id.channel_id); } else if (messageObject.messageOwner.fwd_from.from_id instanceof TLRPC.TL_peerChat) { currentForwardChannel = MessagesController.getInstance(currentAccount).getChat(messageObject.messageOwner.fwd_from.from_id.chat_id); } else if (messageObject.messageOwner.fwd_from.from_id instanceof TLRPC.TL_peerUser) { currentForwardUser = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.fwd_from.from_id.user_id); } } if (messageObject.type == MessageObject.TYPE_STORY || (drawForwardedName && messageObject.needDrawForwarded() && (currentPosition == null || currentPosition.minY == 0))) { if (messageObject.type != MessageObject.TYPE_STORY && messageObject.messageOwner.fwd_from.from_name != null) { currentForwardName = messageObject.messageOwner.fwd_from.from_name; } if (messageObject.type == MessageObject.TYPE_STORY || currentForwardUser != null || currentForwardChannel != null || currentForwardName != null) { String forwardedString; CharSequence lastLine; if (forwardAvatar == null) { forwardAvatar = new AvatarSpan(this, currentAccount); forwardAvatar.translate(0, dp(-.33f)); } forwardAvatar.setSize((1.23f * ((int) Theme.chat_forwardNamePaint.getTextSize())) / AndroidUtilities.density); if (messageObject.type == MessageObject.TYPE_STORY) { currentForwardNameString = forwardedString = getString(R.string.ForwardedStory); long storyDialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.media.peer); if (storyDialogId > 0) { forwardAvatar.setUser(currentForwardUser = MessagesController.getInstance(currentAccount).getUser(storyDialogId)); } else { forwardAvatar.setChat(currentForwardChannel = MessagesController.getInstance(currentAccount).getChat(-storyDialogId)); } boolean includeAvatar = true; String name = AndroidUtilities.removeDiacritics(getNameFromDialogId(storyDialogId)); if (storyDialogId < 0 && currentForwardChannel == null) { name = getString("ChannelPrivate", R.string.ChannelPrivate); includeAvatar = false; } lastLine = new SpannableStringBuilder((includeAvatar ? "A " : "") + name); ((SpannableStringBuilder) lastLine).setSpan(new TypefaceSpan(AndroidUtilities.bold()), 0, lastLine.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); if (includeAvatar) { ((SpannableStringBuilder) lastLine).setSpan(forwardAvatar, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } forwardedNameWidth = getMaxNameWidth(); } else { boolean includeAvatar = true; if (currentForwardChannel != null) { if (currentForwardUser != null) { currentForwardNameString = String.format("%s (%s)", currentForwardChannel.title, UserObject.getUserName(currentForwardUser)); forwardAvatar.setUser(currentForwardUser); } else if (!TextUtils.isEmpty(messageObject.messageOwner.fwd_from.post_author)) { currentForwardNameString = String.format("%s (%s)", currentForwardChannel.title, messageObject.messageOwner.fwd_from.post_author); forwardAvatar.setChat(currentForwardChannel); } else { currentForwardNameString = currentForwardChannel.title; forwardAvatar.setChat(currentForwardChannel); } } else if (currentForwardUser != null) { currentForwardNameString = UserObject.getUserName(currentForwardUser); forwardAvatar.setUser(currentForwardUser); } else { currentForwardNameString = currentForwardName; includeAvatar = false; } forwardedNameWidth = getMaxNameWidth(); forwardedString = getForwardedMessageText(messageObject); if (hasPsaHint) { forwardedNameWidth -= dp(36); } CharSequence name = TextUtils.ellipsize((includeAvatar ? "A " : "") + currentForwardNameString.replace('\n', ' '), Theme.chat_replyNamePaint, forwardedNameWidth - viaWidth - dp(includeAvatar ? 17.33f : 0), TextUtils.TruncateAt.END); String fromString = AndroidUtilities.removeDiacritics(name.toString()); SpannableStringBuilder stringBuilder; if (viaString != null) { stringBuilder = new SpannableStringBuilder(String.format("%s %s %s", fromString, getString("ViaBot", R.string.ViaBot), viaUsername)); viaNameWidth = (int) Math.ceil(Theme.chat_forwardNamePaint.measureText(fromString)); stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.bold()), stringBuilder.length() - viaUsername.length() - 1, stringBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else { stringBuilder = new SpannableStringBuilder(fromString); } if (includeAvatar && stringBuilder.length() > 1) { stringBuilder.setSpan(forwardAvatar, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } forwardNameCenterX = (int) Math.ceil(Theme.chat_forwardNamePaint.measureText(name, 0, name.length())) / 2; if (currentForwardName == null || messageObject.messageOwner.fwd_from.from_id != null) { stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.bold()), 0, stringBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } lastLine = stringBuilder; } try { lastLine = Emoji.replaceEmoji(lastLine, Theme.chat_forwardNamePaint.getFontMetricsInt(), false); } catch (Exception ignore) { } lastLine = TextUtils.ellipsize(lastLine, Theme.chat_forwardNamePaint, forwardedNameWidth, TextUtils.TruncateAt.END); try { forwardedNameLayout[1] = new StaticLayout(lastLine, Theme.chat_forwardNamePaint, forwardedNameWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); lastLine = TextUtils.ellipsize(AndroidUtilities.replaceTags(forwardedString), Theme.chat_forwardNamePaint, forwardedNameWidth, TextUtils.TruncateAt.END); forwardedNameLayout[0] = new StaticLayout(lastLine, Theme.chat_forwardNamePaint, forwardedNameWidth + dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (forwardBg == null) { forwardBg = new ForwardBackground(this); } forwardBg.set(forwardedNameLayout, !currentMessageObject.isOutOwner() && !(drawNameLayout && nameLayout != null) && pinnedTop); forwardedNameWidth = Math.max((int) Math.ceil(forwardedNameLayout[0].getLineWidth(0)), (int) Math.ceil(forwardedNameLayout[1].getLineWidth(0))); if (hasPsaHint) { forwardedNameWidth += dp(36); } forwardNameOffsetX[0] = forwardedNameLayout[0].getLineLeft(0); forwardNameOffsetX[1] = forwardedNameLayout[1].getLineLeft(0); if (isSideMenued && !drawBackground || messageObject.type != MessageObject.TYPE_ROUND_VIDEO && !messageObject.isAnyKindOfSticker() || messageObject.type == MessageObject.TYPE_EMOJIS) { namesOffset += dp(8) + Theme.chat_forwardNamePaint.getTextSize() * 2; if (messageObject.type == MessageObject.TYPE_EMOJIS) { namesOffset += dp(8); } } } catch (Exception e) { FileLog.e(e); } } } if ((!messageObject.isGiveawayResults() && (!isThreadChat || messageObject.isQuickReply() || isSavedChat || messageObject.getReplyTopMsgId(isForum) != 0 || isForumGeneral || isMonoForum) && messageObject.hasValidReplyMessageObject() || messageObject.messageOwner.fwd_from != null && messageObject.isDice() || (messageObject.messageOwner.reply_to != null && (messageObject.messageOwner.reply_to.story_id != 0 || !TextUtils.isEmpty(messageObject.messageOwner.reply_to.quote_text) || messageObject.messageOwner.reply_to.reply_from != null))) && !messageObject.isRepostPreview) { if (currentPosition == null || currentPosition.minY == 0) { if (isSideMenued && !drawBackground || !messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO || messageObject.type == MessageObject.TYPE_EMOJIS) { namesOffset += dp(20) + (Theme.chat_replyTextPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); if (messageObject.type == MessageObject.TYPE_EMOJIS && !drawForwardedName) { namesOffset += dp(12); } else if (messageObject.type != MessageObject.TYPE_TEXT) { namesOffset += dp(5); } } if (drawForwardedName && forwardedNameLayout[0] != null) { namesOffset += dp(2); } int maxWidth = getMaxNameWidth(); if (!messageObject.shouldDrawWithoutBackground()) { maxWidth -= dp(messageObject.isOutOwner() ? 20 : 10); if (messageObject.type != MessageObject.TYPE_TEXT || messageObject.needDrawShareButton()) { maxWidth -= dp(messageObject.isSaved && messageObject.isOutOwner() ? 35 : 10); } } else if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { maxWidth += dp(13); } CharSequence stringFinalText = null; CharSequence name = null; hasReplyQuote = messageObject.messageOwner.reply_to != null && (messageObject.messageOwner.reply_to.flags & 64) != 0 && messageObject.messageOwner.reply_to.quote_text != null; isReplyQuote = hasReplyQuote && messageObject.messageOwner.reply_to.quote; final boolean showQuote = isReplyQuote && messageObject.messageOwner.reply_to.quote; if (isReplyQuote && showQuote && replyQuoteDrawable == null) { replyQuoteDrawable = getContext().getResources().getDrawable(R.drawable.mini_quote).mutate(); replyQuoteDrawableColor = Color.WHITE; } final TextPaint textPaint = isReplyQuote && messageObject.shouldDrawWithoutBackground() ? Theme.chat_quoteTextPaint : Theme.chat_replyTextPaint; if (messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.story_id != 0) { name = AndroidUtilities.removeDiacritics(getNameFromDialogId(DialogObject.getPeerDialogId(messageObject.messageOwner.reply_to.peer))); if (messageObject.messageOwner.replyStory == null || messageObject.messageOwner.replyStory instanceof TL_stories.TL_storyItemDeleted) { if (messageObject.messageOwner.replyStory == null) { stringFinalText = getString("Loading", R.string.Loading); } else { stringFinalText = StoriesUtilities.createExpiredStoryString(); } needReplyImage = false; } else { needReplyImage = true; StoriesUtilities.setStoryMiniImage(replyImageReceiver, messageObject.messageOwner.replyStory); stringFinalText = StoriesUtilities.createReplyStoryString(); maxWidth -= dp(16) + (textPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); } } else if ((!isThreadChat || isMonoForum || messageObject.isQuickReply() || isSavedChat || messageObject.getReplyTopMsgId(isForum) != 0 || isForumGeneral) && messageObject.hasValidReplyMessageObject() || hasReplyQuote || messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.reply_from != null) { lastReplyMessage = messageObject.replyMessageObject == null ? null : messageObject.replyMessageObject.messageOwner; int cacheType = 1; int size = 0; boolean hasReplySpoiler = false; TLObject photoObject = null; TLRPC.PhotoSize photoSize = null; TLRPC.PhotoSize thumbPhotoSize = null; ImageLocation photoImageLocation = null; Drawable photoImageThumb = null; if (messageObject.replyMessageObject != null) { hasReplySpoiler = messageObject.replyMessageObject.hasMediaSpoilers(); photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.replyMessageObject.photoThumbs2, 320); thumbPhotoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.replyMessageObject.photoThumbs2, 40); photoObject = messageObject.replyMessageObject.photoThumbsObject2; if (photoSize == null) { if (messageObject.replyMessageObject.mediaExists) { photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.replyMessageObject.photoThumbs, AndroidUtilities.getPhotoSize()); if (photoSize != null) { size = photoSize.size; } cacheType = 0; } else { photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.replyMessageObject.photoThumbs, 320); } thumbPhotoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.replyMessageObject.photoThumbs, 40); photoObject = messageObject.replyMessageObject.photoThumbsObject; } if (photoSize == null) { TLRPC.MessageMedia m = MessageObject.getMedia(messageObject.replyMessageObject); if (m instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll mediaPoll = (TLRPC.TL_messageMediaPoll) m; TLRPC.MessageMedia replyMedia = mediaPoll.attached_media; if (messageObject.messageOwner.reply_to.poll_option != null) { TLRPC.PollAnswer option = MessageObject.findPollItem(messageObject.replyMessageObject, messageObject.messageOwner.reply_to.poll_option); if (option != null) { replyMedia = option.media; } } if (replyMedia != null) { if (replyMedia.document != null) { final boolean isWebpSticker = MessageObject.isStickerDocument(replyMedia.document) || MessageObject.isVideoSticker(replyMedia.document); final boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(replyMedia.document, true); if (isWebpSticker || isAnimatedSticker) { final Drawable thumb = DocumentObject.getSvgThumb(replyMedia.document, Theme.key_chat_serviceBackground, 1.0f); photoImageLocation = ImageLocation.getForDocument(replyMedia.document); photoImageThumb = thumb; } else { thumbPhotoSize = FileLoader.getClosestPhotoSizeWithSize(replyMedia.document.thumbs, 40); photoSize = FileLoader.getClosestPhotoSizeWithSize(replyMedia.document.thumbs, 320, false, null, true); } photoObject = messageObject.replyMessageObject.messageOwner; } else if (replyMedia.photo != null) { thumbPhotoSize = FileLoader.getClosestPhotoSizeWithSize(replyMedia.photo.sizes, 40); photoSize = FileLoader.getClosestPhotoSizeWithSize(replyMedia.photo.sizes, 320, false, null, true); photoObject = messageObject.replyMessageObject.messageOwner; } } } } if (thumbPhotoSize == photoSize) { thumbPhotoSize = null; } } if (messageObject.messageOwner != null && messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.reply_media != null) { if (messageObject.messageOwner.reply_to.reply_media.document != null) { photoObject = messageObject.messageOwner.reply_to.reply_media.document; photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.messageOwner.reply_to.reply_media.document.thumbs, 320); } else if (messageObject.messageOwner.reply_to.reply_media.photo != null) { photoObject = messageObject.messageOwner.reply_to.reply_media.photo; photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.messageOwner.reply_to.reply_media.photo.sizes, 320); } if (photoSize == null) { replyImageReceiver.setImageBitmap((Drawable) null); needReplyImage = false; } else { currentReplyPhoto = photoSize; replyImageReceiver.setImage(ImageLocation.getForObject(photoSize, photoObject), hasReplySpoiler ? "5_5_b" : "50_50", ImageLocation.getForObject(thumbPhotoSize, photoObject), hasReplySpoiler ? "50_50_b4" : "50_50_b", size, null, messageObject, cacheType); needReplyImage = true; maxWidth -= dp(isReplyQuote ? 3 : 7) + Theme.chat_replyNamePaint.getTextSize() + Theme.chat_replyTextPaint.getTextSize(); } } else if (photoSize == null && photoImageLocation == null || messageObject.replyMessageObject == null || messageObject.replyMessageObject.isAnyKindOfSticker() || messageObject.isAnyKindOfSticker() && !AndroidUtilities.isTablet() || messageObject.replyMessageObject.isSecretMedia() || messageObject.replyMessageObject.isWebpageDocument()) { replyImageReceiver.setImageBitmap((Drawable) null); needReplyImage = false; } else { if (messageObject.replyMessageObject.isRoundVideo()) { replyImageReceiver.setRoundRadius(dp(32)); } else { replyImageReceiver.setRoundRadius(dp(4)); } currentReplyPhoto = photoSize; if (photoImageLocation != null) { replyImageReceiver.setImage(photoImageLocation, "50_50", photoImageThumb, 0, null, messageObject.replyMessageObject, cacheType); } else { replyImageReceiver.setImage(ImageLocation.getForObject(photoSize, photoObject), hasReplySpoiler ? "5_5_b" : "50_50", ImageLocation.getForObject(thumbPhotoSize, photoObject), hasReplySpoiler ? "50_50_b4" : "50_50_b", size, null, messageObject.replyMessageObject, cacheType); } needReplyImage = true; maxWidth -= dp(isReplyQuote ? 3 : 7) + Theme.chat_replyNamePaint.getTextSize() + Theme.chat_replyTextPaint.getTextSize(); } if (DialogObject.isEncryptedDialog(messageObject.getDialogId())) { if (messageObject.replyMessageObject != null && messageObject.replyMessageObject.isOutOwner()) { name = AndroidUtilities.removeDiacritics(UserObject.getUserName(UserConfig.getInstance(currentAccount).getCurrentUser())); } else { TLRPC.EncryptedChat echat = MessagesController.getInstance(currentAccount).getEncryptedChat(DialogObject.getEncryptedChatId(currentMessageObject.getDialogId())); if (echat != null) { name = AndroidUtilities.removeDiacritics(UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(echat.user_id))); } } } else if (hasReplyQuote && !DialogObject.isEncryptedDialog(messageObject.getDialogId())) { name = messageObject.getReplyQuoteNameWithIcon(); } else if (messageObject.hideSendersName) { if (messageObject.sendAsPeer != null) { if (messageObject.sendAsPeer.channel_id != 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(messageObject.sendAsPeer.channel_id); if (chat != null) { name = AndroidUtilities.removeDiacritics(chat.title); } } else { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(messageObject.sendAsPeer.user_id); name = AndroidUtilities.removeDiacritics(UserObject.getUserName(user)); } } else { name = AndroidUtilities.removeDiacritics(UserObject.getUserName(AccountInstance.getInstance(currentAccount).getUserConfig().getCurrentUser())); } } else if (messageObject.customReplyName != null) { name = AndroidUtilities.removeDiacritics(messageObject.customReplyName); } else if (messageObject.replyMessageObject == null && messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.reply_from != null) { name = messageObject.getReplyQuoteNameWithIcon(); } else if (messageObject.replyMessageObject != null) { if (drawForwardedName) { name = AndroidUtilities.removeDiacritics(messageObject.replyMessageObject.getForwardedName()); } if (name == null) { long fromId = messageObject.replyMessageObject.getFromChatId(); if (fromId > 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(fromId); if (user != null) { name = AndroidUtilities.removeDiacritics(UserObject.getUserName(user)); } } else if (fromId < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId); if (chat != null) { name = AndroidUtilities.removeDiacritics(chat.title); } } else if (messageObject.replyMessageObject.messageOwner != null && messageObject.replyMessageObject.messageOwner.peer_id != null) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(messageObject.replyMessageObject.messageOwner.peer_id.channel_id); if (chat != null) { name = AndroidUtilities.removeDiacritics(chat.title); } } } } if (name == null) { name = getString("Loading", R.string.Loading); } if (messageObject.messageOwner.reply_to != null && (messageObject.messageOwner.reply_to.flags & 2048) != 0 && messageObject.replyMessageObject != null && MessageObject.getMedia(messageObject.replyMessageObject) instanceof TLRPC.TL_messageMediaToDo) { TLRPC.TodoItem task = MessageObject.findTodoItem(messageObject.replyMessageObject, messageObject.messageOwner.reply_to.todo_item_id); if (task != null) { isReplyTaskOrPollOption = true; stringFinalText = MessageObject.formatTextWithEntities(task.title, messageObject.isOutOwner(), textPaint); if (replyTaskCheckbox == null) { replyTaskCheckbox = new CheckBoxBase(this, 12, resourcesProvider); replyTaskCheckbox.checkScale = 0.5f; replyTaskCheckbox.setDrawUnchecked(false); replyTaskCheckbox.setBackgroundType(9); if (attachedToWindow) { replyTaskCheckbox.onAttachedToWindow(); } } replyTaskCheckbox.setCuttingCheck(Theme.isCurrentThemeDark()); replyTaskCheckbox.setChecked(MessageObject.isCompleted(messageObject.replyMessageObject, task.id), true); } else { TLRPC.TL_messageMediaToDo mediaTodo = (TLRPC.TL_messageMediaToDo) MessageObject.getMedia(messageObject.replyMessageObject); if (mediaTodo.todo != null && mediaTodo.todo.title != null) { stringFinalText = MessageObject.formatTextWithEntities(mediaTodo.todo.title, messageObject.isOutOwner(), textPaint); } } } else if (messageObject.messageOwner.reply_to != null && (messageObject.messageOwner.reply_to.poll_option != null) && messageObject.replyMessageObject != null && MessageObject.getMedia(messageObject.replyMessageObject) instanceof TLRPC.TL_messageMediaPoll) { TLRPC.PollAnswer task = MessageObject.findPollItem(messageObject.replyMessageObject, messageObject.messageOwner.reply_to.poll_option); if (task != null) { isReplyTaskOrPollOption = true; stringFinalText = MessageObject.formatTextWithEntities(task.text, messageObject.isOutOwner(), textPaint); if (replyTaskCheckbox == null) { replyTaskCheckbox = new CheckBoxBase(this, 12, resourcesProvider); replyTaskCheckbox.checkScale = 0.5f; replyTaskCheckbox.setDrawUnchecked(false); replyTaskCheckbox.setBackgroundType(9); if (attachedToWindow) { replyTaskCheckbox.onAttachedToWindow(); } } replyTaskCheckbox.setCuttingCheck(Theme.isCurrentThemeDark()); replyTaskCheckbox.setChecked(true, true); } else { TLRPC.TL_messageMediaPoll mediaTodo = (TLRPC.TL_messageMediaPoll) MessageObject.getMedia(messageObject.replyMessageObject); if (mediaTodo.poll != null && mediaTodo.poll.question != null) { stringFinalText = MessageObject.formatTextWithEntities(mediaTodo.poll.question, messageObject.isOutOwner(), textPaint); } } } else if (hasReplyQuote || messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.quote_text != null && messageObject.messageOwner.reply_to.reply_from != null) { String mess = messageObject.messageOwner.reply_to.quote_text; mess = mess.replace('\n', ' '); stringFinalText = new SpannableStringBuilder(mess); stringFinalText = Emoji.replaceEmoji(stringFinalText, textPaint.getFontMetricsInt(), false); if (messageObject.messageOwner.reply_to.quote_entities != null) { stringFinalText = MessageObject.replaceAnimatedEmoji(stringFinalText, messageObject.messageOwner.reply_to.quote_entities, textPaint.getFontMetricsInt(), true); MessageObject.addEntitiesToText(stringFinalText, messageObject.messageOwner.reply_to.quote_entities, currentMessageObject.isOutOwner(), false, false, false); } } else if (messageObject.messageOwner.reply_to != null && messageObject.replyMessageObject != null && MessageObject.getMedia(messageObject.replyMessageObject) instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll poll = (TLRPC.TL_messageMediaPoll) MessageObject.getMedia(messageObject.replyMessageObject); SpannableStringBuilder ssb = new SpannableStringBuilder(); ssb.append("* "); ssb.setSpan(new ColoredImageSpan(R.drawable.mini_reply_poll_16), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append(getString(poll.poll.quiz ? R.string.QuizPoll : R.string.Poll)); stringFinalText = ssb; } else if (messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.reply_from != null && messageObject.messageOwner.reply_to.reply_media != null) { stringFinalText = messageObject.getMediaTitle(messageObject.messageOwner.reply_to.reply_media); } else if (messageObject.replyMessageObject != null && messageObject.replyMessageObject.messageTextForReply != null) { stringFinalText = messageObject.replyMessageObject.messageTextForReply; } else if (MessageObject.getMedia(messageObject.replyMessageObject) instanceof TLRPC.TL_messageMediaGame) { stringFinalText = Emoji.replaceEmoji(MessageObject.getMedia(messageObject.replyMessageObject).game.title, textPaint.getFontMetricsInt(), false); stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); } else if (MessageObject.getMedia(messageObject.replyMessageObject) instanceof TLRPC.TL_messageMediaInvoice) { stringFinalText = Emoji.replaceEmoji(MessageObject.getMedia(messageObject.replyMessageObject).title, textPaint.getFontMetricsInt(), false); stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); } else if (messageObject.replyMessageObject != null && !TextUtils.isEmpty(messageObject.replyMessageObject.caption)) { String mess = messageObject.replyMessageObject.caption.toString(); if (mess.length() > 150) { mess = mess.substring(0, 150); } mess = mess.replace('\n', ' '); stringFinalText = Emoji.replaceEmoji(mess, textPaint.getFontMetricsInt(), true); if (messageObject.replyMessageObject.messageOwner != null) { stringFinalText = MessageObject.replaceAnimatedEmoji(stringFinalText, messageObject.replyMessageObject.messageOwner.entities, textPaint.getFontMetricsInt(), true); } stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); if (stringFinalText instanceof Spannable && messageObject.replyMessageObject.messageOwner != null) { MediaDataController.addTextStyleRuns(messageObject.replyMessageObject.messageOwner.entities, messageObject.replyMessageObject.caption, (Spannable) stringFinalText); stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); } } else if (messageObject.replyMessageObject != null && messageObject.replyMessageObject.messageText != null && messageObject.replyMessageObject.messageText.length() > 0) { CharSequence mess = messageObject.replyMessageObject.messageText; if (mess.length() > 150) { mess = mess.subSequence(0, 150); } if (!(mess instanceof SpannableStringBuilder)) { mess = new SpannableStringBuilder(mess); } mess = AndroidUtilities.removeSpans(mess, QuoteSpan.class); mess = AndroidUtilities.removeSpans(mess, QuoteSpan.QuoteStyleSpan.class); mess = AndroidUtilities.replaceNewLines(mess); stringFinalText = Emoji.replaceEmoji(mess, textPaint.getFontMetricsInt(), true); if (messageObject.replyMessageObject.messageOwner != null) { stringFinalText = MessageObject.replaceAnimatedEmoji(stringFinalText, messageObject.replyMessageObject.messageOwner.entities, textPaint.getFontMetricsInt(), true); } stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); if (stringFinalText instanceof Spannable) { MediaDataController.addTextStyleRuns(messageObject.replyMessageObject, (Spannable) stringFinalText); stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); } } } else { replyImageReceiver.setImageBitmap((Drawable) null); needReplyImage = false; replyPanelIsForward = true; if (messageObject.messageOwner.fwd_from != null) { if (messageObject.messageOwner.fwd_from.from_id instanceof TLRPC.TL_peerChannel) { currentForwardChannel = MessagesController.getInstance(currentAccount).getChat(messageObject.messageOwner.fwd_from.from_id.channel_id); } else if (messageObject.messageOwner.fwd_from.from_id instanceof TLRPC.TL_peerChat) { currentForwardChannel = MessagesController.getInstance(currentAccount).getChat(messageObject.messageOwner.fwd_from.from_id.chat_id); } else if (messageObject.messageOwner.fwd_from.from_id instanceof TLRPC.TL_peerUser) { currentForwardUser = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.fwd_from.from_id.user_id); } if (messageObject.messageOwner.fwd_from.from_name != null) { currentForwardName = messageObject.messageOwner.fwd_from.from_name; } } if (currentForwardUser != null || currentForwardChannel != null || currentForwardName != null) { if (forwardAvatar == null) { forwardAvatar = new AvatarSpan(this, currentAccount); forwardAvatar.translate(0, dp(-.33f)); } forwardAvatar.setSize((1.23f * ((int) Theme.chat_forwardNamePaint.getTextSize())) / AndroidUtilities.density); boolean includeAvatar = true; if (currentForwardChannel != null) { if (currentForwardUser != null) { currentForwardNameString = String.format("%s (%s)", currentForwardChannel.title, UserObject.getUserName(currentForwardUser)); forwardAvatar.setUser(currentForwardUser); } else { currentForwardNameString = currentForwardChannel.title; forwardAvatar.setChat(currentForwardChannel); } } else if (currentForwardUser != null) { currentForwardNameString = UserObject.getUserName(currentForwardUser); forwardAvatar.setUser(currentForwardUser); } else { currentForwardNameString = currentForwardName; includeAvatar = false; } name = getForwardedMessageText(messageObject); CharSequence text = currentForwardNameString == null ? "" : currentForwardNameString.replace('\n', ' '); CharSequence ellipsizedText = TextUtils.ellipsize((includeAvatar ? "A " : "") + text, Theme.chat_replyNamePaint, maxWidth - dp(includeAvatar ? 17.33f : 0), TextUtils.TruncateAt.END); SpannableStringBuilder stringBuilder = new SpannableStringBuilder(ellipsizedText); if (includeAvatar && stringBuilder.length() > 1) { stringBuilder.setSpan(forwardAvatar, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } if (currentForwardName == null || messageObject.messageOwner.fwd_from.from_id != null) { stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.bold()), 0, ellipsizedText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } stringFinalText = TextUtils.ellipsize(stringBuilder, textPaint, maxWidth, TextUtils.TruncateAt.END); forwardNameCenterX = (int) Math.ceil(Theme.chat_replyNamePaint.measureText(ellipsizedText, 0, ellipsizedText.length())) / 2; } } CharSequence stringFinalName = name; try { stringFinalName = Emoji.replaceEmoji(stringFinalName, Theme.chat_replyNamePaint.getFontMetricsInt(), false); } catch (Exception ignore) {} if (isReplyQuote) { maxWidth -= dp(24); } stringFinalName = stringFinalName == null ? "" : TextUtils.ellipsize(AndroidUtilities.replaceCharSequence("\n", stringFinalName, " "), Theme.chat_replyNamePaint, maxWidth, TextUtils.TruncateAt.END); try { if (replyLine == null) { replyLine = new ReplyMessageLine(this); } replyLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_REPLY); if (replyLine.hasSticker()) { maxWidth -= dp(38); } replyNameWidth = dp(4) + (needReplyImage ? dp(16) + (int) (textPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()) : 0); if (stringFinalName != null) { replyNameLayout = new StaticLayout(stringFinalName, Theme.chat_replyNamePaint, maxWidth + dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (replyNameLayout.getLineCount() > 0) { replyNameWidth += (int) Math.ceil(replyNameLayout.getLineWidth(0)) + dp(4); replyNameOffset = (int) replyNameLayout.getLineLeft(0); } } if (isReplyQuote && showQuote && replyQuoteDrawable != null) { replyNameWidth += dp(2 + 4 + (!drawPinnedTop ? 2 : 0)) + replyQuoteDrawable.getIntrinsicWidth(); } else { replyNameWidth += dp(3); } if (replyLine.hasSticker()) { replyNameWidth += dp(38); } } catch (Exception e) { FileLog.e(e); } try { replyTextWidth = dp(4) + (needReplyImage ? dp(33) : 0); if (stringFinalText != null) { SpannableStringBuilder sb = new SpannableStringBuilder(stringFinalText); boolean changed = false; for (TextStyleSpan span : sb.getSpans(0, sb.length(), TextStyleSpan.class)) { if ((span.getTextStyleRun().flags & TextStyleSpan.FLAG_STYLE_MONO) != 0) { changed = true; sb.removeSpan(span); } } replyTextRTL = AndroidUtilities.isRTL(sb); if (isReplyQuote && !currentMessageObject.shouldDrawWithoutBackground()) { maxWidth += dp(24 + 12); // replyTextWidth += dp(24); } if (isReplyQuote && needReplyImage && !replyTextRTL) { final float sz = dp(isReplyQuote ? 3 : 7) + Theme.chat_replyNamePaint.getTextSize() + Theme.chat_replyTextPaint.getTextSize(); sb.setSpan(new LeadingMarginSpan.Standard((int) sz + dp(4), 0), 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); replyTextWidth -= sz; maxWidth += sz; } if (changed || !isReplyQuote) { stringFinalText = TextUtils.ellipsize(sb, textPaint, maxWidth, TextUtils.TruncateAt.END); } else { stringFinalText = sb; } replyTextOffset = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { StaticLayout.Builder slb = StaticLayout.Builder.obtain(stringFinalText, 0, stringFinalText.length(), textPaint, maxWidth) .setAlignment(Layout.Alignment.ALIGN_NORMAL) .setIncludePad(false); slb.setBreakStrategy(LineBreaker.BREAK_STRATEGY_SIMPLE); if (isReplyQuote && !currentMessageObject.replyTextRevealed) { slb .setMaxLines(5) .setEllipsize(TextUtils.TruncateAt.END); } replyTextLayout = slb.build(); if (!currentMessageObject.replyTextRevealed) { currentMessageObject.replyTextEllipsized = replyTextLayout.getLineCount() > 0 && replyTextLayout.getEllipsisCount(replyTextLayout.getLineCount() - 1) > 0; } } else { replyTextLayout = new StaticLayout(stringFinalText, 0, stringFinalText.length(), textPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth); } replyTextHeight = replyTextLayout.getHeight(); if (isSideMenued && !drawBackground || (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO || messageObject.type == MessageObject.TYPE_EMOJIS)) { namesOffset += Math.max(0, replyTextHeight - dp(3.66f) - Theme.chat_replyTextPaint.getTextSize()); } if (replyTextLayout.getLineCount() > 0) { int width = 0; replyTextOffset = replyTextLayout.getWidth(); for (int i = 0; i < replyTextLayout.getLineCount(); ++i) { width = Math.max(width, (int) Math.ceil(replyTextLayout.getLineWidth(i))); int left = (int) Math.ceil(replyTextLayout.getLineLeft(i)); if (i > 0 && (replyTextOffset == 0) != (left == 0)) { width = replyTextLayout.getWidth(); } replyTextOffset = Math.min(replyTextOffset, left); } replyTextWidth += width + dp(18); } if (isReplyTaskOrPollOption) { replyTextWidth += dp(16); } replySpoilers.clear(); if (hasReplyQuote || getMessageObject().replyMessageObject != null && !getMessageObject().replyMessageObject.isSpoilersRevealed) { SpoilerEffect.addSpoilers(this, replyTextLayout, replyTextOffset, replyTextOffset + replyTextWidth, replySpoilersPool, replySpoilers); } animatedEmojiReplyStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiReplyStack, replyTextLayout); } if (replyNameWidth > replyTextWidth) { replyNameWidth += dp(Math.max(2, SharedConfig.bubbleRadius / 4f)); } } catch (Exception e) { FileLog.e(e); } } } else if ((!isThreadChat || messageObject.isQuickReply() || isMonoForum) && messageObject.getReplyMsgId() != 0 && !messageObject.isGiveawayResults() && !messageObject.isRepostPreview) { if (!(messageObject.replyMessageObject != null && (messageObject.replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty || messageObject.replyMessageObject.messageOwner != null && messageObject.replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate)) && (delegate == null || delegate.doNotShowLoadingReply(messageObject))) { if (isSideMenued && !drawBackground || !messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { namesOffset += dp(14 + 4) + (Theme.chat_replyTextPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); if (messageObject.type != MessageObject.TYPE_TEXT) { namesOffset += dp(5); } } needReplyImage = false; int maxWidth = getMaxNameWidth(); if (!messageObject.shouldDrawWithoutBackground()) { maxWidth -= dp(10); } else if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { maxWidth += dp(13); } replyNameLayout = new StaticLayout(getString("Loading", R.string.Loading), Theme.chat_replyNamePaint, maxWidth + dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (replyNameLayout.getLineCount() > 0) { replyNameWidth += (int) Math.ceil(replyNameLayout.getLineWidth(0)) + dp(8); replyNameOffset = (int) replyNameLayout.getLineLeft(0); } } } if (messageObject.summarized && (currentPosition == null || currentPosition.minY == 0)) { drawSummaryReply = true; if (summaryTitle == null) { summaryTitle = new Text(getString(R.string.SummaryTitle), 14, AndroidUtilities.bold()); summarySubtitle = new Text(getString(R.string.SummarySubtitle), 14); } summaryTitle.multiline(3).setMaxWidth(getMaxNameWidth() - dp(25)); summarySubtitle.multiline(3).setMaxWidth(getMaxNameWidth() - dp(25)); namesOffset += dp(8) + summaryTitle.getHeight() + summarySubtitle.getHeight() + dp(6); } else { drawSummaryReply = false; } requestLayout(); } private String getNameFromDialogId(long fromId) { String name = null; if (fromId > 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(fromId); if (user != null) { name = UserObject.getUserName(user); } } else if (fromId < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId); if (chat != null) { name = chat.title; } } return name; } protected boolean isNeedAuthorName() { if (currentMessageObject.forceAvatar || currentMessageObject.getDialogId() == UserObject.VERIFY && currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.fwd_from != null) { return true; } if (currentMessageObject.isSponsored()) { return false; } if (currentMessageObject.isGiveawayOrGiveawayResults()) { return false; } if (isBotForum && !isPinnedChat) { return false; } final boolean forwardedFromSelfViaBot = currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.fwd_from != null && currentMessageObject.messageOwner.fwd_from.from_id != null && currentMessageObject.messageOwner.via_bot_id != 0 && DialogObject.getPeerDialogId(currentMessageObject.messageOwner.fwd_from.from_id) == DialogObject.getPeerDialogId(currentMessageObject.messageOwner.peer_id); if (forwardedFromSelfViaBot) { return false; } return ( isPinnedChat && currentMessageObject.type == MessageObject.TYPE_TEXT || !pinnedTop && drawName && isChat && (!currentMessageObject.isOutOwner() || currentMessageObject.isSupergroup() && currentMessageObject.isFromGroup() || currentMessageObject.isRepostPreview) || currentMessageObject.isImportedForward() && currentMessageObject.messageOwner.fwd_from.from_id == null ); } private String getAuthorName() { if (currentUser != null) { return UserObject.getUserName(currentUser); } else if (currentChat != null) { if (currentMessageObject != null && (currentMessageObject.getDialogId() != UserObject.REPLY_BOT) && currentChat.signature_profiles) { long did = DialogObject.getPeerDialogId(currentMessageObject.messageOwner.from_id); if (did >= 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); if (user != null) return UserObject.getUserName(user); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); if (chat != null) return chat.title; } } return currentChat.title; } else if (currentMessageObject != null && currentMessageObject.isSponsored()) { return currentMessageObject.sponsoredTitle; } return "DELETED"; } private Object getAuthorStatus() { if (currentUser != null) { Long emojiStatusId = UserObject.getEmojiStatusDocumentId(currentUser); if (emojiStatusId != null) { if (currentUser.emoji_status instanceof TLRPC.TL_emojiStatusCollectible) { nameStatusSlug = ((TLRPC.TL_emojiStatusCollectible) currentUser.emoji_status).slug; } return emojiStatusId; } else if (currentUser.premium) { return ContextCompat.getDrawable(ApplicationLoader.applicationContext, R.drawable.msg_premium_liststar).mutate(); } } else if (currentChat != null) { if (currentMessageObject != null && (currentMessageObject.getDialogId() != UserObject.REPLY_BOT) && currentChat.signature_profiles) { long did = DialogObject.getPeerDialogId(currentMessageObject.messageOwner.from_id); if (did >= 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); if (user != null && user.emoji_status instanceof TLRPC.TL_emojiStatusCollectible) { nameStatusSlug = ((TLRPC.TL_emojiStatusCollectible) user.emoji_status).slug; } return UserObject.getEmojiStatusDocumentId(user); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); if (chat != null) { if (chat.emoji_status instanceof TLRPC.TL_emojiStatusCollectible) { nameStatusSlug = ((TLRPC.TL_emojiStatusCollectible) chat.emoji_status).slug; } return DialogObject.getEmojiStatusDocumentId(chat.emoji_status); } } } } return null; } private long getAuthorBotVerificationId() { if (currentUser != null) { return DialogObject.getBotVerificationIcon(currentUser); } else if (currentChat != null) { if (currentMessageObject != null && (currentMessageObject.getDialogId() != UserObject.REPLY_BOT) && currentChat.signature_profiles) { long did = DialogObject.getPeerDialogId(currentMessageObject.messageOwner.from_id); if (did >= 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); if (user != null) return DialogObject.getBotVerificationIcon(user); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); if (chat != null) return DialogObject.getBotVerificationIcon(chat); } } } return 0; } private String getForwardedMessageText(MessageObject messageObject) { if (hasPsaHint) { String forwardedString = getString("PsaMessage_" + messageObject.messageOwner.fwd_from.psa_type); if (forwardedString == null) { forwardedString = getString("PsaMessageDefault", R.string.PsaMessageDefault); } return forwardedString; } else { return getString(R.string.ForwardedFrom); } } public int getExtraInsetHeight() { int h = addedCaptionHeight; if (hasFactCheck) { h += dp(2 + (reactionsLayoutInBubble.isEmpty ? 18 : 0)) + factCheckHeight; } if (drawCommentButton) { h += dp(shouldDrawTimeOnMedia() ? 41.3f : 43); } if (!reactionsLayoutInBubble.isEmpty && currentMessageObject.shouldDrawReactionsInLayout()) { h += reactionsLayoutInBubble.totalHeight; } return h; } public ImageReceiver getAvatarImage() { return isAvatarVisible ? avatarImage : null; } public float getCheckBoxTranslation() { return checkBoxTranslation; } public boolean shouldDrawAlphaLayer() { return (currentMessagesGroup == null || !currentMessagesGroup.transitionParams.backgroundChangeBounds) && getAlpha() != 1f; } public float getCaptionX() { float captionY = this.captionY; if (transitionParams.animateBackgroundBoundsInner) { if (transitionParams.transformGroupToSingleMessage) { captionX += transitionParams.deltaLeft; } else if (transitionParams.moveCaption) { captionX = this.captionX * transitionParams.animateChangeProgress + transitionParams.captionFromX * (1f - transitionParams.animateChangeProgress); } else if (!currentMessageObject.isVoice() || !TextUtils.isEmpty(currentMessageObject.caption)) { captionX += transitionParams.deltaLeft; } } return captionX; } public float getCaptionY() { float captionY = this.captionY; if (transitionParams.animateBackgroundBoundsInner) { if (transitionParams.transformGroupToSingleMessage) { captionY -= getTranslationY(); } else if (transitionParams.moveCaption) { captionY = this.captionY * transitionParams.animateChangeProgress + transitionParams.captionFromY * (1f - transitionParams.animateChangeProgress); } } return captionY; } public boolean isDrawPinnedBottom() { boolean forceMediaByGroup = currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0 && currentMessagesGroup.isDocuments; return mediaBackground || drawPinnedBottom || forceMediaByGroup; } public void drawCheckBox(Canvas canvas) { if (currentMessageObject != null && currentMessageObject.isSponsored()) { return; } if (currentMessageObject != null && !currentMessageObject.isSending() && currentMessageObject.type != MessageObject.TYPE_JOINED_CHANNEL && !currentMessageObject.isSendError() && checkBox != null && (checkBoxVisible || checkBoxAnimationInProgress) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { canvas.save(); float y = getY() + getPaddingTop(); if (currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) { y = getTop() + currentMessagesGroup.transitionParams.offsetTop - getTranslationY(); } else { y += transitionParams.deltaTop; } canvas.translate(sideMenuWidth, y + transitionYOffsetForDrawables); checkBox.draw(canvas); canvas.restore(); } } public void setBackgroundTopY(boolean fromParent) { for (int a = 0; a < 2; a++) { if (a == 1 && !fromParent) { return; } MessageDrawable drawable = a == 0 ? currentBackgroundDrawable : currentBackgroundSelectedDrawable; if (drawable == null) { continue; } int w = parentWidth; int h = parentHeight; if (h == 0) { w = getParentWidth(); h = AndroidUtilities.displaySize.y; if (getParent() instanceof View) { View view = (View) getParent(); w = view.getMeasuredWidth(); h = view.getMeasuredHeight(); } } drawable.setTop((int) ((fromParent ? getY() : getTop()) + parentViewTopOffset), w, h, (int) parentViewTopOffset, blurredViewTopOffset, blurredViewBottomOffset, pinnedTop, pinnedBottom || transitionParams.changePinnedBottomProgress != 1); drawable.setBotButtonsBottom(hasInlineBotButtons()); } } public void setBackgroundTopY(int offset) { MessageDrawable drawable = currentBackgroundDrawable; int w = parentWidth; int h = parentHeight; if (h == 0) { w = getParentWidth(); h = AndroidUtilities.displaySize.y; if (getParent() instanceof View) { View view = (View) getParent(); w = view.getMeasuredWidth(); h = view.getMeasuredHeight(); } } drawable.setTop((int) (parentViewTopOffset + offset), w, h, (int) parentViewTopOffset, blurredViewTopOffset, blurredViewBottomOffset, pinnedTop, pinnedBottom || transitionParams.changePinnedBottomProgress != 1); drawable.setBotButtonsBottom(hasInlineBotButtons()); } public float transitionYOffsetForDrawables; public void setDrawableBoundsInner(Drawable drawable, int x, int y, int w, int h) { if (drawable != null) { if (botDraftTypingAnimator != null && botDraftTypingAnimator.isRunning()) { transitionYOffsetForDrawables = 0; } else { transitionYOffsetForDrawables = (y + h + transitionParams.deltaBottom) - ((int) (y + h + transitionParams.deltaBottom)); } drawable.setBounds((int) (x + transitionParams.deltaLeft), (int) (y + transitionParams.deltaTop), (int) (x + w + transitionParams.deltaRight), (int) (y + h + transitionParams.deltaBottom)); } } private Paint selectionOverlayPaint; public void setupTextColors() { if (currentMessageObject.isOutOwner()) { Theme.chat_msgTextPaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); Theme.chat_msgGameTextPaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); Theme.chat_msgTextCodePaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); Theme.chat_msgTextCode2Paint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); Theme.chat_msgTextCode3Paint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); Theme.chat_msgGameTextPaint.linkColor = Theme.chat_replyTextPaint.linkColor = Theme.chat_quoteTextPaint.linkColor = Theme.chat_msgTextPaint.linkColor = Theme.chat_msgTextCodePaint.linkColor = Theme.chat_msgTextCode2Paint.linkColor = Theme.chat_msgTextCode3Paint.linkColor = getThemedColor(Theme.key_chat_messageLinkOut); } else { Theme.chat_msgTextPaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); Theme.chat_msgGameTextPaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); Theme.chat_msgTextCodePaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); Theme.chat_msgTextCode2Paint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); Theme.chat_msgTextCode3Paint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); Theme.chat_msgGameTextPaint.linkColor = Theme.chat_replyTextPaint.linkColor = Theme.chat_quoteTextPaint.linkColor = Theme.chat_msgTextPaint.linkColor = Theme.chat_msgTextCodePaint.linkColor = Theme.chat_msgTextCode2Paint.linkColor = Theme.chat_msgTextCode3Paint.linkColor = getThemedColor(Theme.key_chat_messageLinkIn); } if (documentAttach != null) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { if (currentMessageObject.isOutOwner()) { seekBarWaveform.setColors(getThemedColor(Theme.key_chat_outVoiceSeekbar), getThemedColor(Theme.key_chat_outVoiceSeekbarFill), getThemedColor(Theme.key_chat_outVoiceSeekbarSelected)); seekBar.setColors(getThemedColor(Theme.key_chat_outAudioSeekbar), getThemedColor(Theme.key_chat_outAudioCacheSeekbar), getThemedColor(Theme.key_chat_outAudioSeekbarFill), getThemedColor(Theme.key_chat_outAudioSeekbarFill), getThemedColor(Theme.key_chat_outAudioSeekbarSelected)); } else if (hasLinkPreview && linkLine != null) { seekBarWaveform.setColors(Theme.adaptHue(getThemedColor(Theme.key_chat_inVoiceSeekbar), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inVoiceSeekbarFill), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inVoiceSeekbarSelected), linkLine.getColor())); seekBar.setColors(Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbar), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioCacheSeekbar), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarFill), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarFill), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarSelected), linkLine.getColor())); } else { seekBarWaveform.setColors(getThemedColor(Theme.key_chat_inVoiceSeekbar), getThemedColor(Theme.key_chat_inVoiceSeekbarFill), getThemedColor(Theme.key_chat_inVoiceSeekbarSelected)); seekBar.setColors(getThemedColor(Theme.key_chat_inAudioSeekbar), getThemedColor(Theme.key_chat_inAudioCacheSeekbar), getThemedColor(Theme.key_chat_inAudioSeekbarFill), getThemedColor(Theme.key_chat_inAudioSeekbarFill), getThemedColor(Theme.key_chat_inAudioSeekbarSelected)); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { if (currentMessageObject.isOutOwner()) { seekBar.setColors(getThemedColor(Theme.key_chat_outAudioSeekbar), getThemedColor(Theme.key_chat_outAudioCacheSeekbar), getThemedColor(Theme.key_chat_outAudioSeekbarFill), getThemedColor(Theme.key_chat_outAudioSeekbarFill), getThemedColor(Theme.key_chat_outAudioSeekbarSelected)); } else if (hasLinkPreview && linkLine != null) { seekBar.setColors(Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbar), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioCacheSeekbar), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarFill), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarFill), linkLine.getColor()), Theme.adaptHue(getThemedColor(Theme.key_chat_inAudioSeekbarSelected), linkLine.getColor())); } else { seekBar.setColors(getThemedColor(Theme.key_chat_inAudioSeekbar), getThemedColor(Theme.key_chat_inAudioCacheSeekbar), getThemedColor(Theme.key_chat_inAudioSeekbarFill), getThemedColor(Theme.key_chat_inAudioSeekbarFill), getThemedColor(Theme.key_chat_inAudioSeekbarSelected)); } } } if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { Theme.chat_timePaint.setColor( ColorUtils.blendARGB( getThemedColor(Theme.key_chat_serviceText), getThemedColor(isDrawSelectionBackground() ? (currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeSelectedText : Theme.key_chat_inTimeSelectedText) : (currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeText : Theme.key_chat_inTimeText) ), getVideoTranscriptionProgress() ) ); } else { if (mediaBackground) { if (currentMessageObject.shouldDrawWithoutBackground()) { Theme.chat_timePaint.setColor(getThemedColor(Theme.key_chat_serviceText)); } else { Theme.chat_timePaint.setColor(getThemedColor(Theme.key_chat_mediaTimeText)); } } else { if (currentMessageObject.isOutOwner()) { Theme.chat_timePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outTimeSelectedText : Theme.key_chat_outTimeText)); } else { Theme.chat_timePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inTimeSelectedText : Theme.key_chat_inTimeText)); } } } } protected boolean isWidthAdaptive() { return false; } @Override public int getBoundsLeft() { boolean isOut = currentMessageObject != null && currentMessageObject.isOutOwner(); int avatarWidth = needDrawAvatar() ? dp(currentPosition != null ? 73 : (currentMessageObject != null && currentMessageObject.isRepostPreview ? 42 : 63)) : 0; int shareButtonWidth = (isOut && (checkNeedDrawShareButton(currentMessageObject) || useTranscribeButton) ? dp(48) : 0); int left = getBackgroundDrawableLeft() - avatarWidth - shareButtonWidth; if (botButtons != null) { int buttonMostLeft = Integer.MAX_VALUE; int addX; final int widthForButtons = getWidthForButtons(); if (currentMessageObject != null && currentMessageObject.isOutOwner()) { addX = getMeasuredWidth() - widthForButtons - dp(10); } else { addX = backgroundDrawableLeft + dp(mediaBackground || drawPinnedBottom ? 1 : 7); } for (int i = 0; i < botButtons.size(); ++i) { BotButton btn = botButtons.get(i); buttonMostLeft = Math.max(buttonMostLeft, addX + (int) (btn.x * widthForButtons)); } left = Math.min(left, buttonMostLeft); } if (starsPriceText != null) { left = Math.min(left, (int) (getParentWidth() - starsPriceText.getWidth() - dp(18)) / 2); } if (topicSeparator != null) { left = Math.min(sideMenuWidth, left); } return Math.max(0, left); } @Override public int getBoundsRight() { boolean isIn = currentMessageObject != null && !currentMessageObject.isOutOwner(); int shareButtonWidth = (isIn && (checkNeedDrawShareButton(currentMessageObject) || useTranscribeButton) ? dp(48) : 0); int right = getBackgroundDrawableRight() + shareButtonWidth; if (botButtons != null) { int buttonMostRight = 0; int addX; final int widthForButtons = getWidthForButtons(); if (currentMessageObject != null && currentMessageObject.isOutOwner()) { addX = getMeasuredWidth() - getWidthForButtons() - dp(10); } else { addX = backgroundDrawableLeft + dp(mediaBackground || drawPinnedBottom ? 1 : 7); } for (int i = 0; i < botButtons.size(); ++i) { BotButton btn = botButtons.get(i); buttonMostRight = Math.max(buttonMostRight, addX + (int) (btn.x * widthForButtons) + (int) (btn.width * widthForButtons)); } right = Math.max(right, buttonMostRight); } if (starsPriceText != null) { right = Math.max(right, (int) (getParentWidth() + starsPriceText.getWidth() + dp(18)) / 2); } if (topicSeparator != null) { right = Math.max(right, getWidth()); } return right; } @SuppressLint("WrongCall") @Override protected void onDraw(Canvas canvas) { drawInternal(canvas); } public void drawInternal(Canvas canvas) { if (currentMessageObject == null) { return; } if (!wasLayout) { onLayout(false, getLeft(), getTop(), getRight(), getBottom()); } if (enterTransitionInProgress && currentMessageObject.isAnimatedEmojiStickers()) { return; } if (channelRecommendationsCell != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { if (delegate == null || delegate.canDrawOutboundsContent()) { channelRecommendationsCell.draw(canvas); } transitionParams.recordDrawingState(); return; } final int sponosoredAlpha = (int) (255 * (1f - isSponsoredMessageHidden.getFloatValue())); if (sponosoredAlpha == 0) { return; } final int restore = canvas.getSaveCount(); int restoreToSponosoredAlpha = -1; if (sponosoredAlpha != 255) { restoreToSponosoredAlpha = canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), sponosoredAlpha); } setupTextColors(); if (getStarsPriceTopPadding() + suggestionOfferTopPadding + getTopicSeparatorTopPadding() > 0) { canvas.save(); canvas.translate(0, getStarsPriceTopPadding() + suggestionOfferTopPadding + getTopicSeparatorTopPadding()); } if (isWidthAdaptive()) { canvas.save(); canvas.translate(-getBoundsLeft(), 0); } drawBackgroundInternal(canvas, false); if (isHighlightedAnimated) { long newTime = System.currentTimeMillis(); long dt = Math.abs(newTime - lastHighlightProgressTime); if (dt > 17) { dt = 17; } highlightProgress -= dt; lastHighlightProgressTime = newTime; if (highlightProgress <= 0) { highlightProgress = 0; isHighlightedAnimated = false; if (highlightedQuote) { resetUrlPaths(); } highlightedQuote = false; } invalidate(); if (getParent() != null) { ((View) getParent()).invalidate(); } } if (alphaInternal != 1.0f) { int top = 0; int left = 0; int bottom = getMeasuredHeight(); int right = getMeasuredWidth(); if (currentBackgroundDrawable != null) { top = currentBackgroundDrawable.getBounds().top; bottom = currentBackgroundDrawable.getBounds().bottom; left = currentBackgroundDrawable.getBounds().left; right = currentBackgroundDrawable.getBounds().right; } if (drawSideButton != 0) { if (currentMessageObject.isOutOwner()) { left -= dp(8 + 32); } else { right += dp(8 + 32); } } if (getY() < 0) { top = (int) -getY(); } if (getY() + getMeasuredHeight() > parentHeight) { bottom = (int) (parentHeight - getY()); } rect.set(left, top, right, bottom); canvas.saveLayerAlpha(rect, (int) (255 * alphaInternal), Canvas.ALL_SAVE_FLAG); } boolean clipContent = false; if (transitionParams.animateBackgroundBoundsInner && currentBackgroundDrawable != null && !isRoundVideo && (currentMessageObject == null || !currentMessageObject.sendPreview)) { Rect r = currentBackgroundDrawable.getBounds(); canvas.save(); canvas.clipRect( r.left + dp(4), r.top + dp(4), r.right - dp(4), r.bottom - dp(4) ); clipContent = true; } drawContent(canvas, false); if (expiredStoryView != null && expiredStoryView.visible) { expiredStoryView.draw(canvas, this); } if (clipContent) { canvas.restore(); } if (replyNameLayout != null) { float replyTextHeight = this.replyTextHeight; if (transitionParams != null && transitionParams.animateReplyTextLayout != null) { replyTextHeight = AndroidUtilities.lerp(transitionParams.animateFromReplyTextHeight, replyTextHeight, transitionParams.animateChangeProgress); } replyHeight = dp(9) + Theme.chat_replyNamePaint.getTextSize() + Math.max(replyTextHeight - dp(3.66f), Theme.chat_replyTextPaint.getTextSize()); if (currentMessageObject.shouldDrawWithoutBackground() && currentMessageObject.type != MessageObject.TYPE_EMOJIS && !isSideMenued) { if (currentMessageObject.isOutOwner()) { replyStartX = dp(23); if (isPlayingRound) { replyStartX -= AndroidUtilities.roundPlayingMessageSize(isSideMenued) - AndroidUtilities.roundMessageSize; } } else if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { replyStartX = backgroundDrawableLeft + backgroundDrawableRight + dp(4); } else { replyStartX = backgroundDrawableLeft + backgroundDrawableRight + dp(17); } if (drawForwardedName) { forwardHeight = dp(4) + (int) Theme.chat_forwardNamePaint.getTextSize() * 2; replyStartY = forwardNameY + forwardHeight + dp(6); } else { replyStartY = dp(12); } } else { if (currentMessageObject.isOutOwner()) { replyStartX = backgroundDrawableLeft + dp(12) + getExtraTextX(); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { replyStartX -= Math.max(0, replyStartX + Math.max(replyNameWidth, replyTextWidth) + dp(14) - AndroidUtilities.displaySize.x); } } else { if (mediaBackground) { replyStartX = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { replyStartX = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { replyStartX -= dp(7); } forwardHeight = dp(4) + (int) Theme.chat_forwardNamePaint.getTextSize() * 2; replyStartY = dp(12) + (int) (drawNameLayout && nameLayout != null ? getNameHeightAnimated() + dp(1) : 0) + (drawForwardedName && forwardedNameLayout[0] != null ? dp(4) + forwardHeight : 0); } replyStartY += dp(.66f); if (ephemeralLayout != null) { replyStartY += dp(EPHEMERAL_HINT_HEIGHT - 4); } } if (drawSummaryReply) { if (currentMessageObject.isOutOwner()) { summaryStartX = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { if (mediaBackground) { summaryStartX = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { summaryStartX = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } summaryStartY = dp(12) + (int) (drawNameLayout && nameLayout != null ? getNameHeightAnimated() + dp(1) : 0) + (drawForwardedName && forwardedNameLayout[0] != null ? dp(4) + forwardHeight : 0) + (int) (replyNameLayout != null ? replyHeight + dp(12) : 0); } if (currentPosition == null && !transitionParams.animateBackgroundBoundsInner && !(enterTransitionInProgress && !currentMessageObject.isVoice())) { drawNamesLayout(canvas, 1f); } if ((!autoPlayingMedia || !MediaController.getInstance().isPlayingMessageAndReadyToDraw(currentMessageObject) || isRoundVideo) && !transitionParams.animateBackgroundBoundsInner && !(currentMessageObject != null && currentMessageObject.preview)) { drawOverlays(canvas); } if ((drawTime || !mediaBackground) && !forceNotDrawTime && !transitionParams.animateBackgroundBoundsInner && !(enterTransitionInProgress && !currentMessageObject.isVoice()) && (!currentMessageObject.isQuickReply() || currentMessageObject.isSendError())) { drawTime(canvas, 1f, false); } if ((controlsAlpha != 1.0f || timeAlpha != 1.0f) && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO) { long newTime = System.currentTimeMillis(); long dt = Math.abs(lastControlsAlphaChangeTime - newTime); if (dt > 17) { dt = 17; } totalChangeTime += dt; if (totalChangeTime > TIME_APPEAR_MS) { totalChangeTime = TIME_APPEAR_MS; } lastControlsAlphaChangeTime = newTime; if (controlsAlpha != 1.0f) { controlsAlpha = AndroidUtilities.decelerateInterpolator.getInterpolation(totalChangeTime / (float) TIME_APPEAR_MS); } if (timeAlpha != 1.0f) { timeAlpha = AndroidUtilities.decelerateInterpolator.getInterpolation(totalChangeTime / (float) TIME_APPEAR_MS); } invalidate(); if (forceNotDrawTime && currentPosition != null && currentPosition.last && getParent() != null) { View parent = (View) getParent(); parent.invalidate(); } } if ((drawBackground || transitionParams.animateDrawBackground) && shouldDrawSelectionOverlay() && currentMessagesGroup == null && hasSelectionOverlay()) { if (selectionOverlayPaint == null) { selectionOverlayPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } selectionOverlayPaint.setColor(getSelectionOverlayColor()); int wasAlpha = selectionOverlayPaint.getAlpha(); selectionOverlayPaint.setAlpha((int) (wasAlpha * getHighlightAlpha() * getAlpha())); if (selectionOverlayPaint.getAlpha() > 0) { canvas.save(); canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); currentBackgroundDrawable.drawCached(canvas, backgroundCacheParams, selectionOverlayPaint); canvas.restore(); } selectionOverlayPaint.setAlpha(wasAlpha); } if (delegate == null || delegate.canDrawOutboundsContent() || transitionParams.messageEntering || getAlpha() != 1f) { drawOutboundsContent(canvas); } updateSelectionTextPosition(); if (restoreToSponosoredAlpha != -1) { canvas.restoreToCount(restoreToSponosoredAlpha); } canvas.restoreToCount(restore); } public void drawBackgroundInternal(Canvas canvas, boolean fromParent) { drawBackgroundInternal(canvas, fromParent, false); } @SuppressLint("WrongCall") private boolean drawBackgroundInternal(Canvas canvas, boolean fromParent, boolean internal) { if (currentMessageObject == null) { return false; } if (!wasLayout && !animationRunning) { forceLayout(); return false; } if (!wasLayout || forcedLayout) { onLayout(false, getLeft(), getTop(), getRight(), getBottom()); } final boolean hasUnsupportedBlocks = currentMessageObject.richLayout != null && currentMessageObject.richLayout.hasUnsupportedBlocks(); final boolean hasRootUnsupportedBlocks = currentMessageObject.richLayout != null && currentMessageObject.richLayout.hasRootUnsupportedBlocks(); ArrayList holes = null; ArrayList holesRoot = null; if (!internal && hasUnsupportedBlocks) { holes = currentMessageObject.richLayout.getUnsupportedHoles(); holesRoot = currentMessageObject.richLayout.getUnsupportedHolesRoot(); } if (!internal && hasRootUnsupportedBlocks && holes != null && !holes.isEmpty()) { //if (transitionParams != null && transitionParams.animateChange || currentMessageObject.richLayout.blockquoteAnimating || currentMessageObject.richLayout.detailsAnimating) { layoutTextXY(false); //} final int textY = this.textY; boolean result = false; int bY = 0; for (int a = 0, N = holesRoot.size(); a <= N; a++) { RichMessageLayout.RichUnsupportedBlock hole = a < N ? holesRoot.get(a) : null; canvas.save(); if (hole != null) { canvas.clipRect(0, a == 0 ? Integer.MIN_VALUE : textY + bY, getWidth(), textY + (int) hole.getY(transitionParams)); result |= drawBackgroundInternal(canvas, fromParent, true); bY = (int) (hole.getY(transitionParams) + hole.getHeight(transitionParams)); } else { canvas.clipRect(0, textY + bY, getWidth(), Integer.MAX_VALUE); result |= drawBackgroundInternal(canvas, fromParent, true); } canvas.restore(); } if (!result) { return false; } float backgroundX; if (currentMessageObject.isOutOwner()) { backgroundX = layoutWidth - backgroundWidth + dp(11); } else { if (isSideMenuEnabled) { backgroundX = dp(20 + ChatActivity.SIDE_MENU_WIDTH); } else if (needDrawAvatar()) { backgroundX = dp(20 + 48); } else { backgroundX = dp(20); } } if (transitionParams.animateBackgroundBoundsInner) { backgroundX += transitionParams.deltaLeft; } float bwidth = backgroundWidth; if (transitionParams.animateBackgroundBoundsInner) { bwidth += transitionParams.deltaRight - transitionParams.deltaLeft; } final int backgroundLeft = (int) (backgroundX - dp(9)); final int backgroundRight = (int) (backgroundX + bwidth - dp(22)); final Paint paint; if (isDrawSelectionBackground()) { if (currentBackgroundSelectedDrawable != null) { paint = currentBackgroundSelectedDrawable.getPaint(); } else { return result; } } else { if (currentBackgroundDrawable != null) { paint = currentBackgroundDrawable.getPaint(); } else { return result; } } if (drawBackground) { for (int a = 0, N = holes.size(); a < N; a++) { final RichMessageLayout.RichUnsupportedBlock hole = holes.get(a); final float t = textY + hole.getY(transitionParams); final float b = t + hole.getHeight(transitionParams); if (hole.level == 0) { final int tornWidth = backgroundRight - backgroundLeft; if (hole.tornBitmap == null || hole.tornBitmap.getWidth() < tornWidth) { hole.tornParams = new TornEdge.Params(); hole.tornBitmap = TornEdge.createTearBitmap(hole.tornParams, tornWidth, currentMessageObject.getId() * 100 + hole.index); } canvas.save(); canvas.clipRect(backgroundLeft, 0, backgroundRight, getHeight()); TornEdge.drawTopEdge(canvas, hole.tornBitmap, hole.tornParams, tornWidth, backgroundLeft, t, paint); TornEdge.drawBottomEdge(canvas, hole.tornBitmap, hole.tornParams, tornWidth, backgroundLeft, b, paint); canvas.restore(); } AndroidUtilities.rectTmp.set( backgroundLeft + (hole.padding.left + dp(7)) + dp(3.33f), t + hole.padding.top, backgroundRight - (hole.padding.right + dp(7)) - dp(3.33f), b - hole.padding.bottom); drawServiceBackground(canvas, AndroidUtilities.rectTmp, dp(18), 1f); } } return result; } Drawable currentBackgroundShadowDrawable; int additionalTop = 0; int additionalBottom = 0; boolean forceMediaByGroup = currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0 && currentMessagesGroup.isDocuments && !drawPinnedBottom; if (currentMessageObject.isOutOwner()) { if (transitionParams.changePinnedBottomProgress >= 1 && !mediaBackground && !drawPinnedBottom && !forceMediaByGroup) { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgOut); currentBackgroundSelectedDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgOutSelected); transitionParams.drawPinnedBottomBackground = false; } else { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgOutMedia); currentBackgroundSelectedDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgOutMediaSelected); transitionParams.drawPinnedBottomBackground = true; } setBackgroundTopY(true); if (isDrawSelectionBackground() && (currentPosition == null || getBackground() != null)) { currentBackgroundShadowDrawable = currentBackgroundSelectedDrawable.getShadowDrawable(); } else { currentBackgroundShadowDrawable = currentBackgroundDrawable.getShadowDrawable(); } backgroundDrawableLeft = layoutWidth - backgroundWidth - (!mediaBackground ? 0 : dp(9)); backgroundDrawableRight = backgroundWidth - (mediaBackground ? 0 : dp(3)); if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { if (!currentPosition.edge) { backgroundDrawableRight += dp(10); } } int backgroundLeft = backgroundDrawableLeft; if (!forceMediaByGroup && transitionParams.changePinnedBottomProgress != 1) { if (!mediaBackground) { backgroundDrawableRight -= dp(6); } } else if (!mediaBackground && drawPinnedBottom) { backgroundDrawableRight -= dp(6); } if (currentPosition != null) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) == 0) { backgroundDrawableRight += dp(SharedConfig.bubbleRadius + 2); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { backgroundLeft -= dp(SharedConfig.bubbleRadius + 2); backgroundDrawableRight += dp(SharedConfig.bubbleRadius + 2); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { additionalTop -= dp(SharedConfig.bubbleRadius + 3); additionalBottom += dp(SharedConfig.bubbleRadius + 3); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { additionalBottom += dp(SharedConfig.bubbleRadius + 3); } } int offsetBottom; if (drawPinnedBottom && drawPinnedTop) { offsetBottom = 0; } else if (drawPinnedBottom) { offsetBottom = dp(1); } else { offsetBottom = dp(2); } backgroundDrawableTop = additionalTop + (drawPinnedTop ? 0 : dp(1)); int backgroundHeight = layoutHeight - offsetBottom + additionalBottom; backgroundDrawableBottom = backgroundDrawableTop + backgroundHeight; if (!mediaBackground) { if (drawPinnedTop) { backgroundDrawableTop -= dp(1); backgroundHeight += dp(1); } if (drawPinnedBottom) { backgroundDrawableBottom += dp(1); backgroundHeight += dp(1); } } if (forceMediaByGroup) { setDrawableBoundsInner(currentBackgroundDrawable, backgroundLeft, backgroundDrawableTop - additionalTop, backgroundDrawableRight, backgroundHeight - additionalBottom + 10); setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundDrawableLeft, backgroundDrawableTop, backgroundDrawableRight - dp(6), backgroundHeight); } else { setDrawableBoundsInner(currentBackgroundDrawable, backgroundLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); } setDrawableBoundsInner(currentBackgroundShadowDrawable, backgroundLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); } else { if (transitionParams.changePinnedBottomProgress >= 1 && !mediaBackground && !drawPinnedBottom && !forceMediaByGroup) { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgIn); currentBackgroundSelectedDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgInSelected); transitionParams.drawPinnedBottomBackground = false; } else { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgInMedia); currentBackgroundSelectedDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgInMediaSelected); transitionParams.drawPinnedBottomBackground = true; } setBackgroundTopY(true); if (isDrawSelectionBackground() && (currentPosition == null || getBackground() != null)) { currentBackgroundShadowDrawable = currentBackgroundSelectedDrawable.getShadowDrawable(); } else { currentBackgroundShadowDrawable = currentBackgroundDrawable.getShadowDrawable(); } backgroundDrawableLeft = dp(isSideMenuEnabled ? ChatActivity.SIDE_MENU_WIDTH : (isChat || currentMessageObject != null && (currentMessageObject.isRepostPreview || currentMessageObject.forceAvatar || currentMessageObject.messageOwner.guestchat_via_from != null) || currentMessageObject.getDialogId() == UserObject.VERIFY) && isAvatarVisible ? 48 : 0) + dp(!mediaBackground ? 3 : 9); backgroundDrawableRight = backgroundWidth - (mediaBackground ? 0 : dp(3)); if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { if (!currentPosition.edge) { backgroundDrawableLeft -= dp(10); backgroundDrawableRight += dp(10); } if (currentPosition.leftSpanOffset != 0) { backgroundDrawableLeft += (int) Math.ceil(currentPosition.leftSpanOffset / 1000.0f * getGroupPhotosWidth()); } } if ((!mediaBackground && drawPinnedBottom) || !forceMediaByGroup && transitionParams.changePinnedBottomProgress != 1) { if (!(!drawPinnedBottom && mediaBackground)) { backgroundDrawableRight -= dp(6); } if (!mediaBackground) { backgroundDrawableLeft += dp(6); } } if (currentPosition != null) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) == 0) { backgroundDrawableRight += dp(SharedConfig.bubbleRadius + 2); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { backgroundDrawableLeft -= dp(SharedConfig.bubbleRadius + 2); backgroundDrawableRight += dp(SharedConfig.bubbleRadius + 2); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { additionalTop -= dp(SharedConfig.bubbleRadius + 3); additionalBottom += dp(SharedConfig.bubbleRadius + 3); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { additionalBottom += dp(SharedConfig.bubbleRadius + 4); } } int offsetBottom; if (drawPinnedBottom && drawPinnedTop) { offsetBottom = 0; } else if (drawPinnedBottom) { offsetBottom = dp(1); } else { offsetBottom = dp(2); } backgroundDrawableTop = additionalTop + (drawPinnedTop ? 0 : dp(1)); int backgroundHeight = layoutHeight - offsetBottom + additionalBottom; backgroundDrawableBottom = backgroundDrawableTop + backgroundHeight; if (!mediaBackground) { if (drawPinnedTop) { backgroundDrawableTop -= dp(1); backgroundHeight += dp(1); } if (drawPinnedBottom) { backgroundDrawableBottom += dp(1); backgroundHeight += dp(1); } } setDrawableBoundsInner(currentBackgroundDrawable, backgroundDrawableLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); if (forceMediaByGroup) { setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundDrawableLeft + dp(6), backgroundDrawableTop, backgroundDrawableRight - dp(6), backgroundHeight); } else { setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundDrawableLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); } setDrawableBoundsInner(currentBackgroundShadowDrawable, backgroundDrawableLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); } if (!currentMessageObject.isOutOwner() && transitionParams.changePinnedBottomProgress != 1 && !mediaBackground && !drawPinnedBottom) { backgroundDrawableLeft -= dp(6); backgroundDrawableRight += dp(6); } if (hasPsaHint) { int x; if (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0) { x = currentBackgroundDrawable.getBounds().right; } else { x = 0; int dWidth = getGroupPhotosWidth(); for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { x += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } } Drawable drawable = Theme.chat_psaHelpDrawable[currentMessageObject.isOutOwner() ? 1 : 0]; int y; if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { y = dp(12); } else { y = dp(10 + (drawNameLayout ? 19 : 0)); } psaHelpX = x - drawable.getIntrinsicWidth() - dp(currentMessageObject.isOutOwner() ? 20 : 14); psaHelpY = y + dp(4); } if (checkBoxVisible || checkBoxAnimationInProgress) { animateCheckboxTranslation(); int size = dp(21); checkBox.setBounds(dp(8 - 35) + checkBoxTranslation, currentBackgroundDrawable.getBounds().bottom - dp(8) - size, size, size); } if (!fromParent && drawBackgroundInParent()) { return false; } int restoreCount = canvas.getSaveCount(); if (transitionYOffsetForDrawables != 0) { canvas.save(); canvas.translate(0, transitionYOffsetForDrawables); } float pinnedBottomOffset = 0; if (currentMessageObject != null && currentMessageObject.isRoundVideo()) { float progress = getVideoTranscriptionProgress(); // if (transitionParams.animateDrawBackground) { // Rect bounds = currentBackgroundDrawable.getBounds(); // bounds.bottom = AndroidUtilities.lerp(bounds.top + bounds.width(), bounds.bottom, progress); // } currentBackgroundDrawable.setRoundingRadius(1f - progress); pinnedBottomOffset = AndroidUtilities.lerp(backgroundWidth / 2, 0, progress); canvas.saveLayerAlpha(0, 0, getWidth(), Math.max(currentBackgroundDrawable.getBounds().bottom, getHeight()), (int) (255 * progress), Canvas.ALL_SAVE_FLAG); roundVideoPlayPipFloat.set((MediaController.getInstance().isPiPShown() && MediaController.getInstance().isPlayingMessageAndReadyToDraw(currentMessageObject) || wouldBeInPip) && canvas.isHardwareAccelerated() ? 1f : 0f); if (MediaController.getInstance().isPiPShown()) { wouldBeInPip = false; } } else { roundVideoPlayPipFloat.set(0, true); } if ((drawBackground || transitionParams.animateDrawBackground) && currentBackgroundDrawable != null && (currentPosition == null || isDrawSelectionBackground() && (currentMessageObject.isMusic() || currentMessageObject.isDocument())) && !(enterTransitionInProgress && !currentMessageObject.isVoice())) { float alphaInternal = this.alphaInternal; if (fromParent) { alphaInternal *= getAlpha(); } if (hasSelectionOverlay()) { // if ((isPressed() && isCheckPressed || !isCheckPressed && isPressed) && !textIsSelectionMode()) { // currentSelectedBackgroundAlpha = 1f; // currentBackgroundSelectedDrawable.setAlpha((int) (255 * alphaInternal)); // currentBackgroundSelectedDrawable.drawCached(canvas, backgroundCacheParams); // } else { currentSelectedBackgroundAlpha = 0; currentBackgroundDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundDrawable.drawCached(canvas, backgroundCacheParams); // } if (currentBackgroundShadowDrawable != null && currentPosition == null) { currentBackgroundShadowDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundShadowDrawable.draw(canvas); } } else { if (isHighlightedAnimated) { currentBackgroundDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundDrawable.drawCached(canvas, backgroundCacheParams); currentSelectedBackgroundAlpha = getHighlightAlpha(); if (currentPosition == null) { currentBackgroundSelectedDrawable.setAlpha((int) (alphaInternal * currentSelectedBackgroundAlpha * 255)); currentBackgroundSelectedDrawable.drawCached(canvas, backgroundCacheParams); } } else if (selectedBackgroundProgress != 0 && (currentMessageObject == null || !currentMessageObject.preview) && !(currentMessagesGroup != null && currentMessagesGroup.isDocuments)) { currentBackgroundDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundDrawable.drawCached(canvas, backgroundCacheParams); currentSelectedBackgroundAlpha = selectedBackgroundProgress; currentBackgroundSelectedDrawable.setAlpha((int) (currentSelectedBackgroundAlpha * alphaInternal * 255)); currentBackgroundSelectedDrawable.drawCached(canvas, backgroundCacheParams); if (currentBackgroundDrawable.getGradientShader() == null) { currentBackgroundShadowDrawable = null; } } else { if (isDrawSelectionBackground() && quoteHighlight == null && (currentPosition == null || currentMessageObject.isMusic() || currentMessageObject.isDocument() || getBackground() != null)) { if (currentPosition != null) { canvas.save(); // canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); } currentSelectedBackgroundAlpha = 1f; currentBackgroundSelectedDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundSelectedDrawable.drawCached(canvas, backgroundCacheParams); if (currentPosition != null) { canvas.restore(); } } else { currentSelectedBackgroundAlpha = 0; currentBackgroundDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundDrawable.drawCached(canvas, backgroundCacheParams); } } if (currentBackgroundShadowDrawable != null && currentPosition == null) { currentBackgroundShadowDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundShadowDrawable.draw(canvas); } if (transitionParams.changePinnedBottomProgress != 1f && currentPosition == null) { if (currentMessageObject.isOutOwner()) { MessageDrawable drawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgOut); Rect rect = currentBackgroundDrawable.getBounds(); drawable.setBounds(rect.left, rect.top, rect.right + dp(6), rect.bottom); canvas.save(); canvas.translate(-pinnedBottomOffset, 0); canvas.clipRect(rect.right - dp(16), rect.bottom - dp(16), rect.right + dp(16), rect.bottom); int w = parentWidth; int h = parentHeight; if (h == 0) { w = getParentWidth(); h = AndroidUtilities.displaySize.y; if (getParent() instanceof View) { View view = (View) getParent(); w = view.getMeasuredWidth(); h = view.getMeasuredHeight(); } } drawable.setTop((int) (getY() + parentViewTopOffset), w, h, (int) parentViewTopOffset, blurredViewTopOffset, blurredViewBottomOffset, pinnedTop, pinnedBottom); drawable.setBotButtonsBottom(hasInlineBotButtons()); float alpha = !mediaBackground && !pinnedBottom ? transitionParams.changePinnedBottomProgress : (1f - transitionParams.changePinnedBottomProgress); drawable.setAlpha((int) (255 * alpha)); drawable.draw(canvas); drawable.setAlpha(255); canvas.restore(); } else { MessageDrawable drawable; if (transitionParams.drawPinnedBottomBackground) { drawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgIn); } else { drawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgInMedia); } float alpha = !mediaBackground && !pinnedBottom ? transitionParams.changePinnedBottomProgress : (1f - transitionParams.changePinnedBottomProgress); drawable.setAlpha((int) (255 * alpha)); Rect rect = currentBackgroundDrawable.getBounds(); drawable.setBounds(rect.left - dp(6), rect.top, rect.right, rect.bottom); canvas.save(); canvas.translate(pinnedBottomOffset, 0); canvas.clipRect(rect.left - dp(6), rect.bottom - dp(16), rect.left + dp(6 + 12), rect.bottom); drawable.draw(canvas); drawable.setAlpha(255); canvas.restore(); } } } } if (currentMessageObject != null && currentMessageObject.isRoundVideo()) { currentBackgroundDrawable.setRoundingRadius(0); } canvas.restoreToCount(restoreCount); return true; } private void animateCheckboxTranslation() { if (checkBoxVisible || checkBoxAnimationInProgress) { if (checkBoxVisible && checkBoxAnimationProgress == 1.0f || !checkBoxVisible && checkBoxAnimationProgress == 0.0f) { checkBoxAnimationInProgress = false; } Interpolator interpolator = checkBoxVisible ? CubicBezierInterpolator.EASE_OUT : CubicBezierInterpolator.EASE_IN; checkBoxTranslation = (int) Math.ceil(interpolator.getInterpolation(checkBoxAnimationProgress) * dp(35)); if (currentMessageObject.type == MessageObject.TYPE_ARTICLE && getCurrentBackgroundRight() + dp(35) > getWidth()) checkBoxTranslation = 0; if (!currentMessageObject.isOutOwner() || currentMessageObject.hasWideCode) { updateTranslation(); } if (checkBoxAnimationInProgress) { long newTime = SystemClock.elapsedRealtime(); long dt = newTime - lastCheckBoxAnimationTime; lastCheckBoxAnimationTime = newTime; if (checkBoxVisible) { checkBoxAnimationProgress += dt / 200.0f; if (checkBoxAnimationProgress > 1.0f) { checkBoxAnimationProgress = 1.0f; } } else { checkBoxAnimationProgress -= dt / 200.0f; if (checkBoxAnimationProgress <= 0.0f) { checkBoxAnimationProgress = 0.0f; } } invalidate(); ((View) getParent()).invalidate(); } } } public boolean drawBackgroundInParent() { if (canDrawBackgroundInParent && currentMessageObject != null && currentMessageObject.isOutOwner()) { return getThemedColor(Theme.key_chat_outBubbleGradient1) != 0; } return false; } public void drawServiceBackground(Canvas canvas, RectF rect, float radius, float alpha) { applyServiceShaderMatrix(); if (alpha != 1f) { int oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (alpha * oldAlpha)); canvas.drawRoundRect(rect, radius, radius, getThemedPaint(Theme.key_paint_chatActionBackground)); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); } else { canvas.drawRoundRect(rect, radius, radius, getThemedPaint(sideButtonPressed ? Theme.key_paint_chatActionBackgroundSelected : Theme.key_paint_chatActionBackground)); } if (hasGradientService()) { if (alpha != 1f) { int oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (alpha * oldAlpha)); canvas.drawRoundRect(rect, radius, radius, Theme.chat_actionBackgroundGradientDarkenPaint); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); } else { canvas.drawRoundRect(rect, radius, radius, Theme.chat_actionBackgroundGradientDarkenPaint); } } } public void drawServiceBackground(Canvas canvas, Path path, float alpha) { applyServiceShaderMatrix(); if (alpha != 1f) { int oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (alpha * oldAlpha)); canvas.drawPath(path, getThemedPaint(Theme.key_paint_chatActionBackground)); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); } else { canvas.drawPath(path, getThemedPaint(sideButtonPressed ? Theme.key_paint_chatActionBackgroundSelected : Theme.key_paint_chatActionBackground)); } if (hasGradientService()) { if (alpha != 1f) { int oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (alpha * oldAlpha)); canvas.drawPath(path, Theme.chat_actionBackgroundGradientDarkenPaint); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); } else { canvas.drawPath(path, Theme.chat_actionBackgroundGradientDarkenPaint); } } } public void drawCommentButton(Canvas canvas, float alpha) { if (drawSideButton != 3) { return; } int height = dp(32); if (commentLayout != null) { sideStartY -= dp(18); height += dp(18); } rect.set(sideStartX, sideStartY, sideStartX + dp(32), sideStartY + height); applyServiceShaderMatrix(); if (alpha != 1f) { int oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (alpha * oldAlpha)); canvas.drawRoundRect(rect, dp(16), dp(16), getThemedPaint(Theme.key_paint_chatActionBackground)); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); } else { canvas.drawRoundRect(rect, dp(16), dp(16), getThemedPaint(sideButtonPressed ? Theme.key_paint_chatActionBackgroundSelected : Theme.key_paint_chatActionBackground)); } if (hasGradientService()) { if (alpha != 1f) { int oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (alpha * oldAlpha)); canvas.drawRoundRect(rect, dp(16), dp(16), Theme.chat_actionBackgroundGradientDarkenPaint); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); } else { canvas.drawRoundRect(rect, dp(16), dp(16), Theme.chat_actionBackgroundGradientDarkenPaint); } } Drawable commentStickerDrawable = Theme.getThemeDrawable(Theme.key_drawable_commentSticker); setDrawableBounds(commentStickerDrawable, sideStartX + dp(4), sideStartY + dp(4)); if (alpha != 1f) { commentStickerDrawable.setAlpha((int) (255 * alpha)); commentStickerDrawable.draw(canvas); commentStickerDrawable.setAlpha(255); } else { commentStickerDrawable.draw(canvas); } if (commentLayout != null) { Theme.chat_stickerCommentCountPaint.setColor(getThemedColor(Theme.key_chat_stickerReplyNameText)); Theme.chat_stickerCommentCountPaint.setAlpha((int) (255 * alpha)); if (transitionParams.animateComments) { if (transitionParams.animateCommentsLayout != null) { canvas.save(); Theme.chat_stickerCommentCountPaint.setAlpha((int) (255 * (1.0 - transitionParams.animateChangeProgress) * alpha)); canvas.translate(sideStartX + (dp(32) - transitionParams.animateTotalCommentWidth) / 2, sideStartY + dp(30)); transitionParams.animateCommentsLayout.draw(canvas); canvas.restore(); } Theme.chat_stickerCommentCountPaint.setAlpha((int) (255 * transitionParams.animateChangeProgress)); } canvas.save(); canvas.translate(sideStartX + (dp(32) - totalCommentWidth) / 2, sideStartY + dp(30)); commentLayout.draw(canvas); canvas.restore(); } } public void applyServiceShaderMatrix() { applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, getX(), viewTop); } public void applyServiceShaderMatrix(int measuredWidth, int backgroundHeight, float x, float viewTop) { if (resourcesProvider != null) { resourcesProvider.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop + starsPriceTopPadding + topicSeparatorTopPadding + suggestionOfferTopPadding); } else { Theme.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop + starsPriceTopPadding + topicSeparatorTopPadding + suggestionOfferTopPadding); } } public boolean hasOutboundsContent() { if (effectDrawable != null && effectDrawable.isNotEmpty() > 0) { return true; } if (hasFactCheck) { return true; } if (transitionParams.animateExpandedQuotes && (currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_STORY_MENTION || currentMessageObject.type == MessageObject.TYPE_EMOJIS || currentMessageObject.isGiveawayOrGiveawayResults())) { return true; } if (channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { return true; } if ((drawTopic || transitionParams.animateDrawTopic) && topicButton != null) { return true; } if (starsPriceText != null && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { return true; } if (bottomActionText != null && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { return true; } if (topicSeparator != null && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { return true; } if (suggestionOffer != null && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { return true; } if (drawStartBotTopic && (currentPosition == null || BitwiseUtils.hasFlag(currentPosition.flags, MessageObject.POSITION_FLAG_BOTTOM) && BitwiseUtils.hasFlag(currentPosition.flags, MessageObject.POSITION_FLAG_LEFT))) { return true; } if (getAlpha() != 1f) { return false; } return ( reactionsLayoutInBubble.hasOverlay() || (!transitionParams.transitionBotButtons.isEmpty() && transitionParams.animateBotButtonsChanged) || !botButtons.isEmpty() || drawSideButton != 0 || drawNameLayout && nameLayout != null && currentNameEmojiStatusDrawable != null && !currentNameEmojiStatusDrawable.isEmpty() || animatedEmojiStack != null && !animatedEmojiStack.holders.isEmpty() || currentNameStatusDrawable != null && !currentNameStatusDrawable.isEmpty() || currentMessagesGroup == null && (transitionParams.animateReplaceCaptionLayout && transitionParams.animateChangeProgress != 1f || transitionParams.animateChangeProgress != 1.0f && transitionParams.animateMessageText) && transitionParams.animateOutAnimateEmoji != null && !transitionParams.animateOutAnimateEmoji.holders.isEmpty() || drawSummaryReply || transitionParams.animateSummaryReply || currentMessageObject != null && currentMessageObject.richLayout != null && currentMessageObject.richLayout.hasOverlay() || transitionParams.animateRichLayout && transitionParams.animateOutRichLayout != null && transitionParams.animateOutRichLayout.hasOverlay() ); } public boolean showTopicSeparator = true; public void setShowTopic(boolean show) { if (showTopicSeparator != show) { showTopicSeparator = show; invalidateOutbounds(); invalidate(); } } public int getTopicSeparatorTopPadding() { if (transitionParams.animateMonoforumPadding) { return lerp(transitionParams.animateMonoforumPaddingFrom, topicSeparatorTopPadding, transitionParams.animateChangeProgress); } return topicSeparatorTopPadding; } public int getStarsPriceTopPadding() { if (transitionParams.animateStarsPriceTopPadding) { return lerp(transitionParams.animateStarsPriceTopPaddingFrom, starsPriceTopPadding, transitionParams.animateChangeProgress); } return starsPriceTopPadding; } public int getBottomActionPadding() { if (transitionParams.animateBottomActionPadding) { return lerp(transitionParams.animateBottomActionPaddingFrom, bottomActionPadding, transitionParams.animateChangeProgress); } return bottomActionPadding; } public void drawOutboundsContent(Canvas canvas) { if (channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { channelRecommendationsCell.draw(canvas); return; } if (currentMessageObject == null) { return; } if (currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_STORY_MENTION || currentMessageObject.type == MessageObject.TYPE_EMOJIS || currentMessageObject.isGiveawayOrGiveawayResults()) { if (transitionParams.animateExpandedQuotes) { layoutTextXY(false); drawMessageText(canvas); } } if (starsPriceText != null && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { final float appear = transitionParams.animateStarsPriceText ? transitionParams.animateChangeProgress : 1.0f; final float alpha = transitionParams.ignoreAlpha ? timeAlpha : getAlpha() * appear; final float scale = lerp(0.6f, 1.0f, appear); canvas.save(); canvas.translate((getParentWidth() - starsPriceText.getWidth()) / 2.0f, -getStarsPriceTopPadding() + dp(4.5f) + dp(3.33f)); canvas.scale(scale, scale, getParentWidth() / 2.0f, dp(6.83f) - dp(4.5f) - dp(3.33f)); applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, getX(), viewTop - getStarsPriceTopPadding() + dp(4.5f) + dp(3.33f)); final Paint backgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackground); int oldAlpha = backgroundPaint.getAlpha(); backgroundPaint.setPathEffect(starsPriceTextPathEffect); backgroundPaint.setAlpha((int) (oldAlpha * alpha)); canvas.drawPath(starsPriceTextPath, backgroundPaint); backgroundPaint.setPathEffect(null); backgroundPaint.setAlpha(oldAlpha); if (hasGradientService()) { final Paint darkenPaint = getThemedPaint(Theme.key_paint_chatActionBackgroundDarken); oldAlpha = darkenPaint.getAlpha(); darkenPaint.setPathEffect(starsPriceTextPathEffect); darkenPaint.setAlpha((int) (oldAlpha * alpha)); canvas.drawPath(starsPriceTextPath, darkenPaint); darkenPaint.setPathEffect(null); darkenPaint.setAlpha(oldAlpha); } canvas.restore(); canvas.save(); canvas.scale(scale, scale, getParentWidth() / 2.0f, -getStarsPriceTopPadding() + dp(6.83f)); starsPriceText.draw(canvas, (getParentWidth() - starsPriceText.getWidth()) / 2.0f, -getStarsPriceTopPadding() + dp(6.83f), getThemedColor(Theme.key_chat_serviceText), alpha); canvas.restore(); } if (bottomActionText != null && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { final float y = getHeight() - getPaddingTop() - transitionParams.deltaTop + transitionParams.deltaBottom - getBottomActionPadding() - dp(9); final float appear = transitionParams.animateBottomActionText ? transitionParams.animateChangeProgress : 1.0f; final float alpha = transitionParams.ignoreAlpha ? timeAlpha : getAlpha() * appear; final float scale = lerp(0.6f, 1.0f, appear); canvas.save(); canvas.translate((getParentWidth() - bottomActionText.getWidth()) / 2.0f, y + dp(4.5f) + dp(3.33f)); canvas.scale(scale, scale, getParentWidth() / 2.0f, dp(6.83f) - dp(4.5f) - dp(3.33f)); applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, getX(), viewTop + y + dp(4.5f) + dp(3.33f)); final Paint backgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackground); int oldAlpha = backgroundPaint.getAlpha(); backgroundPaint.setPathEffect(bottomActionTextPathEffect); backgroundPaint.setAlpha((int) (oldAlpha * alpha)); canvas.drawPath(bottomActionTextPath, backgroundPaint); backgroundPaint.setPathEffect(null); backgroundPaint.setAlpha(oldAlpha); if (hasGradientService()) { final Paint darkenPaint = getThemedPaint(Theme.key_paint_chatActionBackgroundDarken); oldAlpha = darkenPaint.getAlpha(); darkenPaint.setPathEffect(bottomActionTextPathEffect); darkenPaint.setAlpha((int) (oldAlpha * alpha)); canvas.drawPath(bottomActionTextPath, darkenPaint); darkenPaint.setPathEffect(null); darkenPaint.setAlpha(oldAlpha); } canvas.restore(); canvas.save(); canvas.scale(scale, scale, getParentWidth() / 2.0f, y + dp(6.83f)); bottomActionText.draw(canvas, (getParentWidth() - bottomActionText.getWidth()) / 2.0f, y + dp(6.83f), getThemedColor(Theme.key_chat_serviceText), alpha); canvas.restore(); } if (topicSeparator != null && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { float alpha = transitionParams.ignoreAlpha ? timeAlpha : getAlpha(); if (transitionParams.animateMonoforumPadding) { alpha *= showTopicSeparator ? transitionParams.animateChangeProgress : (1.0f - transitionParams.animateChangeProgress); } final float top = -starsPriceTopPadding - topicSeparatorTopPadding - suggestionOfferTopPadding; applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, sideMenuWidth / 2f + getX(), viewTop + top); topicSeparator.draw(canvas, getParentWidth(), sideMenuWidth, top, 1.0f, alpha, showTopicSeparator); } if (suggestionOffer != null && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { float alpha = transitionParams.ignoreAlpha ? timeAlpha : getAlpha(); final float top = -starsPriceTopPadding - suggestionOfferTopPadding + dp(4); applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, sideMenuWidth / 2f + getX(), viewTop + top); final int x = (getParentWidth() - suggestionOffer.getWidth()) / 2; suggestionOffer.draw(canvas, getParentWidth(), sideMenuWidth, top , 1.0f, alpha, showTopicSeparator); } if (summaryTitle != null && summaryLine != null && summaryBounce != null) { final float summaryAlpha = transitionParams.animateSummaryReply ? (drawSummaryReply ? transitionParams.animateChangeProgress : 1.0f - transitionParams.animateChangeProgress) : (drawSummaryReply ? 1.0f : 0.0f); if (summaryAlpha > 0) { final float s = summaryBounce.getScale(0.025f) * lerp(0.8f, 1.0f, summaryAlpha); canvas.save(); canvas.scale(s, s, summarySelectorRect.centerX(), summarySelectorRect.centerY()); final int textColor = summaryLine.getColor(); if (summaryParticles == null) { summaryParticles = new StarsReactionsSheet.Particles(StarsReactionsSheet.Particles.TYPE_RADIAL_INSIDE, 30); } summaryParticles.setBounds(summarySelectorRect); summaryParticles.process(); summaryParticles.draw(canvas, Theme.multAlpha(textColor, 0.66f), summaryAlpha); invalidateOutbounds(); canvas.restore(); } } if (currentMessagesGroup != null) { updateCaptionLayout(); drawFactCheck(canvas, 1f); } drawFactCheckText(canvas, 1f); if (!enterTransitionInProgress) { drawAnimatedEmojis(canvas, 1f); } if (currentMessageObject.type == MessageObject.TYPE_ARTICLE) { final RichMessageLayout currentLayout = currentMessageObject.richLayout; final RichMessageLayout outgoingLayout = transitionParams.animateRichLayout ? transitionParams.animateOutRichLayout : null; final int textColorKey = currentMessageObject.isOutOwner() ? Theme.key_chat_messageTextOut : Theme.key_chat_messageTextIn; final ColorFilter emojiColorFilter = getAdaptiveEmojiColorFilter(0, getThemedColor(textColorKey)); if (outgoingLayout != null) { transitionParams.updateCrossfadeProgress(); drawRichLayoutOverlay(canvas, outgoingLayout, transitionParams.oldProgress, emojiColorFilter); drawRichLayoutOverlay(canvas, currentLayout, transitionParams.newProgress, emojiColorFilter); } else { drawRichLayoutOverlay(canvas, currentLayout, 1f, emojiColorFilter); } } if (reactionsLayoutInBubble.hasOverlay() && drawReactionsLayoutOverlay(canvas, 1f)) { Choreographer60FpsContent.getInstance().addFrameCallback(invalidateOutboundsRunnable, 15); } else { Choreographer60FpsContent.getInstance().removeFrameCallback(invalidateOutboundsRunnable); } if ((currentNameStatusDrawable != null || currentNameEmojiStatusDrawable != null || topicButton != null && (drawTopic || transitionParams.animateDrawTopic)) && drawNameLayout && nameLayout != null && (currentPosition == null || currentPosition.minX == 0 && currentPosition.minY == 0) && !(currentMessageObject.deleted && !drawingToBitmap && currentMessagesGroup != null && currentMessagesGroup.messages.size() >= 1)) { int color; float nameX, nameY; if (currentMessageObject.shouldDrawWithoutBackground()) { color = getThemedColor(Theme.key_chat_stickerNameText); if (currentMessageObject.isOutOwner()) { nameX = dp(28); } else { nameX = backgroundDrawableLeft + transitionParams.deltaLeft + backgroundDrawableRight + dp(22); } if (currentNameBotVerificationId != 0) { nameX += dp(20); } nameY = layoutHeight - dp(38); nameX -= nameOffsetX; } else { if (mediaBackground || currentMessageObject.isOutOwner()) { nameX = backgroundDrawableLeft + transitionParams.deltaLeft + dp(isSideMenuEnabled && currentPosition != null && !currentMessageObject.isOutOwner() && currentMessagesGroup != null && !currentMessagesGroup.isDocuments ? -4 : 11) + getExtraTextX(); } else { nameX = backgroundDrawableLeft + transitionParams.deltaLeft + dp(!mediaBackground && drawPinnedBottom ? 11 : 17) + getExtraTextX(); } if (currentNameBotVerificationId != 0) { nameX += dp(20); } if (currentMessageObject.isOutOwner() && ChatObject.isChannel(currentChat)) { if (currentBackgroundDrawable != null && currentBackgroundDrawable.hasGradient()) { color = getThemedColor(Theme.key_chat_messageTextOut); } else { color = getThemedColor(Theme.key_chat_outForwardedNameText); } } else if (currentMessageObject.isOutOwner()) { color = getThemedColor(Theme.key_chat_outForwardedNameText); } else if ( currentMessageObject.overrideLinkColor >= 0 || currentMessageObject.isFromUser() && currentUser != null || currentMessageObject.isFromChannel() && currentChat != null || currentMessageObject.sponsoredColor != null && currentMessageObject.sponsoredColor.color != -1 ) { int colorId; if (currentMessageObject.overrideLinkColor >= 0) { colorId = currentMessageObject.overrideLinkColor; } else if (currentMessageObject.sponsoredColor != null) { colorId = currentMessageObject.sponsoredColor.color; } else if (currentMessageObject.isFromUser() && currentUser != null) { colorId = UserObject.getColorId(currentUser); } else { colorId = ChatObject.getColorId(currentChat); } if (colorId < 7) { color = getThemedColor(Theme.keys_avatar_nameInMessage[colorId]); } else { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { color = peerColor.getColor(0, resourcesProvider); } else { color = getThemedColor(Theme.key_chat_inForwardedNameText); } } } else { color = getThemedColor(Theme.key_chat_inForwardedNameText); } nameY = dp(drawPinnedTop ? 9 : 10); } if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { nameX += currentMessagesGroup.transitionParams.offsetLeft; nameY += currentMessagesGroup.transitionParams.offsetTop - getTranslationY(); } nameX += animationOffsetX; nameY += transitionParams.deltaTop; float nx; if (transitionParams.animateSign) { nx = transitionParams.animateNameX + (nameX - transitionParams.animateNameX) * transitionParams.animateChangeProgress; } else { nx = nameX; } float ny = nameY; final float avatarAlpha; if (transitionParams.animateDrawAvatar) { avatarAlpha = lerp(!drawNameAvatar, drawNameAvatar, transitionParams.animateChangeProgress); } else { avatarAlpha = drawNameAvatar ? 1.0f : 0.0f; } nx += dp(32.33f) * avatarAlpha; final float avatarY = ny; if (adminLayout == null) { ny += dp(5) * avatarAlpha; } else { ny -= dp(2.33f) * avatarAlpha; } if (currentNameEmojiStatusDrawable != null) { currentNameEmojiStatusDrawable.setBounds( (int) (Math.abs(nx) - dp(20)), (int) (ny + nameLayout.getHeight() / 2 - dp(9)), (int) (Math.abs(nx) - dp(2)), (int) (ny + nameLayout.getHeight() / 2 + dp(9)) ); currentNameEmojiStatusDrawable.setColor(ColorUtils.setAlphaComponent(color, 115)); currentNameEmojiStatusDrawable.draw(canvas); } if (currentNameStatusDrawable != null) { currentNameStatusDrawable.setBounds( (int) (Math.abs(nx) + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(2)), (int) (ny + nameLayout.getHeight() / 2 - dp(10)), (int) (Math.abs(nx) + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(22)), (int) (ny + nameLayout.getHeight() / 2 + dp(10)) ); currentNameStatusDrawable.setColor(ColorUtils.setAlphaComponent(color, 115)); currentNameStatusDrawable.draw(canvas); } float end; if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { int dWidth = getGroupPhotosWidth(); int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } if (!mediaBackground && currentMessageObject.isOutOwner()) { end = backgroundDrawableLeft + firstLineWidth - dp(6); } else { end = backgroundDrawableLeft + firstLineWidth; } end -= getExtraTextX() + dp(8); if (!currentMessageObject.isOutOwner()) { end -= dp(48); } } else { if (currentMessageObject.shouldDrawWithoutBackground()) { if (currentMessageObject.isOutOwner()) { end = dp(28 + 11) + nameWidth; } else { end = backgroundDrawableLeft + transitionParams.deltaLeft + backgroundDrawableRight + dp(33) + nameWidth; } } else if (!mediaBackground && currentMessageObject.isOutOwner()) { end = backgroundDrawableLeft + backgroundDrawableRight - dp(6); } else { end = backgroundDrawableLeft + backgroundDrawableRight; } } end += transitionParams.deltaRight; final float topicAlpha; if (transitionParams.animateDrawTopic) { topicAlpha = lerp(!drawTopic, drawTopic, transitionParams.animateChangeProgress); } else { topicAlpha = drawTopic ? 1.0f : 0.0f; } if (topicAlpha > 0.0f && topicButton != null) { topicButton.draw(canvas, end - dp(11) - topicButton.width, avatarY, topicAlpha); } } if (!transitionParams.transitionBotButtons.isEmpty() && transitionParams.animateBotButtonsChanged) { float t = transitionParams.animateChangeProgress; t = MathUtils.clamp(1f - (float) Math.pow(t, 2f), 0f, 1f); drawBotButtons(canvas, transitionParams.transitionBotButtons, (int) (0xFF * t)); } if (!botButtons.isEmpty()) { float alpha = 1f; if (transitionParams.animateBotButtonsChanged) { alpha = 1f - MathUtils.clamp(1f - (float) Math.pow(transitionParams.animateChangeProgress, 2f), 0f, 1f); } drawBotButtons(canvas, botButtons, (int) (alpha * 0xFF)); } if (askBotForumSeparator != null && (currentPosition == null /*|| (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0*/)) { float top = layoutHeight - dp(12) + transitionParams.deltaBottom + keyboardHeight; float alpha = 1f; if (transitionParams.animateBotButtonsChanged) { alpha = 1f - MathUtils.clamp(1f - (float) Math.pow(transitionParams.animateChangeProgress, 2f), 0f, 1f); } applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, sideMenuWidth / 2f + getX(), viewTop + top); askBotForumSeparator.draw(canvas, getParentWidth(), sideMenuWidth, top, 1.0f, alpha, false); if (askBotForumBubble != null) { applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, 0 + getX(), viewTop); int bx = (getMeasuredWidth() - askBotForumBubble.getBubbleWidth() + sideMenuWidth) / 2; int by = (int) top + dp(34); askBotForumBubble.setBounds(bx, by, bx + askBotForumBubble.getBubbleWidth(), by + askBotForumBubble.getBubbleHeight()); askBotForumBubble.draw(canvas); } } drawSideButton(canvas); drawSummarizeButton(canvas); } public void drawAnimatedEmojis(Canvas canvas, float alpha) { drawAnimatedEmojiMessageText(canvas, alpha); if (shouldDrawCaptionLayout()) { drawAnimatedEmojiCaption(canvas, alpha); } } private void drawAnimatedEmojiMessageText(Canvas canvas, float alpha) { if (currentMessageObject == null || currentMessageObject.isSponsored()) { return; } float textY = this.textY; if (transitionParams.animateTextY) { textY = transitionParams.animateFromTextY * (1f - transitionParams.animateChangeProgress) + this.textY * transitionParams.animateChangeProgress; } if (transitionParams.animateChangeProgress != 1.0f && transitionParams.animateMessageText && !(botDraftTypingAnimator != null && botDraftTypingAnimator.isRunning())) { canvas.save(); if (currentBackgroundDrawable != null) { Rect r = currentBackgroundDrawable.getBounds(); if (currentMessageObject.isOutOwner() && !mediaBackground && !pinnedBottom) { canvas.clipRect( r.left + dp(4), r.top + dp(4), r.right - dp(10), r.bottom - dp(4) ); } else { canvas.clipRect( r.left + dp(4), r.top + dp(4), r.right - dp(4), r.bottom - dp(4) ); } } drawAnimatedEmojiMessageText(textX, textY, canvas, transitionParams.animateOutTextBlocks, transitionParams.animateOutAnimateEmoji, false, alpha * (1.0f - transitionParams.animateChangeProgress), currentMessageObject.textXOffset, false); drawAnimatedEmojiMessageText(textX, textY, canvas, currentMessageObject.textLayoutBlocks, animatedEmojiStack, true, alpha * transitionParams.animateChangeProgress, currentMessageObject.textXOffset, false); canvas.restore(); } else { drawAnimatedEmojiMessageText(textX, textY, canvas, currentMessageObject.textLayoutBlocks, animatedEmojiStack, true, alpha, currentMessageObject.textXOffset, false); } } private void drawAnimatedEmojiMessageText(float textX, float textY, Canvas canvas, ArrayList textLayoutBlocks, AnimatedEmojiSpan.EmojiGroupedSpans stack, boolean origin, float alpha, float rtlOffset, boolean drawAllBlocks) { if (currentMessageObject == null || textLayoutBlocks == null || textLayoutBlocks.isEmpty() || alpha == 0) { return; } int firstVisibleBlockNum; int lastVisibleBlockNum; if (origin && !drawAllBlocks) { if (fullyDraw) { this.firstVisibleBlockNum = 0; this.lastVisibleBlockNum = textLayoutBlocks.size(); } firstVisibleBlockNum = this.firstVisibleBlockNum; lastVisibleBlockNum = this.lastVisibleBlockNum; } else { firstVisibleBlockNum = 0; lastVisibleBlockNum = textLayoutBlocks.size(); } float right; if (currentMessagesGroup == null || currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0) { right = getBackgroundDrawableRight() + transitionParams.deltaRight; } else { int end, dWidth; if (AndroidUtilities.isTablet()) { dWidth = AndroidUtilities.getMinTabletSide(); } else { dWidth = getParentWidth(); } int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } if (!mediaBackground && currentMessageObject.isOutOwner()) { end = backgroundDrawableLeft + firstLineWidth - dp(6); } else { end = backgroundDrawableLeft + firstLineWidth; } end -= getExtraTextX() + dp(8 + (isAvatarVisible ? 48 : 0)); right = end; } right -= dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) + getExtraTextX(); final float maxWidth = right - textX; for (int a = firstVisibleBlockNum; a <= lastVisibleBlockNum; a++) { if (a >= textLayoutBlocks.size()) { break; } if (a < 0) { continue; } MessageObject.TextLayoutBlock block = textLayoutBlocks.get(a); int saveCount = canvas.getSaveCount(); canvas.save(); canvas.translate(textX - (block.isRtl() ? (int) Math.ceil(rtlOffset) : 0), textY + block.padTop + block.textYOffset(textLayoutBlocks, transitionParams) + transitionYOffsetForDrawables); float drawingYOffset = textY + block.textYOffset(textLayoutBlocks, transitionParams) + transitionYOffsetForDrawables; float top = 0; // parentBoundsTop - getY() - drawingYOffset + dp(20); float bottom = 0; // parentBoundsBottom - getY() - drawingYOffset - dp(20); if (transitionParams.messageEntering) { top = bottom = 0; } int textColorKey = currentMessageObject.isOutOwner() ? Theme.key_chat_messageTextOut : Theme.key_chat_messageTextIn; if (currentMessageObject.shouldDrawWithoutBackground()) { textColorKey = Theme.key_windowBackgroundWhiteBlackText; } float collapsed = 1f; final int width = (int) (block.maxRight + dp(24) > maxWidth * .7f ? maxWidth : block.maxRight + dp(24)); if (block.quoteCollapse) { AndroidUtilities.rectTmp.set(0, -block.padTop + dp(block.first ? 3 + 1.66f : 3), width, block.height(transitionParams) + dp(4)); AndroidUtilities.rectTmp.offset((block.isRtl() ? rtlOffset - dp(10) : 0), 0); if (block.collapsedBounce != null) { final float s = block.collapsedBounce.getScale(0.01f); canvas.scale(s, s, AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY()); } } if (block.quoteCollapse && block.height > block.collapsedHeight) { collapsed = block.collapsed(transitionParams); canvas.saveLayerAlpha(0, 0, width, block.height(transitionParams) - 1, 0xFF, Canvas.ALL_SAVE_FLAG); } AnimatedEmojiSpan.drawAnimatedEmojis(canvas, block.textLayout, stack, 0, block.spoilers, top, bottom, drawingYOffset, alpha, getAdaptiveEmojiColorFilter(0, getThemedColor(textColorKey))); if (block.quoteCollapse && block.height > block.collapsedHeight) { if (clip == null) { clip = new GradientClip(); } canvas.save(); AndroidUtilities.rectTmp.set(0, block.height(transitionParams) - dp(24), width, block.height(transitionParams)); clip.draw(canvas, AndroidUtilities.rectTmp, GradientClip.BOTTOM, collapsed); canvas.restore(); } canvas.restoreToCount(saveCount); } } public void drawAnimatedEmojiCaption(Canvas canvas, float alpha) { if (captionLayout == null) { return; } float captionY = this.captionY; float captionX = this.captionX; if (transitionParams.animateBackgroundBoundsInner) { if (transitionParams.transformGroupToSingleMessage) { captionY -= getTranslationY(); captionX += transitionParams.deltaLeft; } else if (transitionParams.moveCaption) { captionX = this.captionX * transitionParams.animateChangeProgress + transitionParams.captionFromX * (1f - transitionParams.animateChangeProgress); captionY = this.captionY * transitionParams.animateChangeProgress + transitionParams.captionFromY * (1f - transitionParams.animateChangeProgress); } else if (!currentMessageObject.isVoice() || !TextUtils.isEmpty(currentMessageObject.caption)) { captionX += transitionParams.deltaLeft; } } if (transitionParams.animateReplaceCaptionLayout && transitionParams.animateChangeProgress != 1f) { drawAnimatedEmojiMessageText(captionX, captionY, canvas, transitionParams.animateOutCaptionLayout != null ? transitionParams.animateOutCaptionLayout.textLayoutBlocks : null, transitionParams.animateOutAnimateEmoji, false, alpha * (1f - transitionParams.animateChangeProgress), transitionParams.animateOutCaptionLayout != null ? transitionParams.animateOutCaptionLayout.textXOffset : 0, true); drawAnimatedEmojiMessageText(captionX, captionY, canvas, captionLayout != null ? captionLayout.textLayoutBlocks : null, animatedEmojiStack, true, alpha * transitionParams.animateChangeProgress, captionLayout != null ? captionLayout.textXOffset : 0, true); } else { drawAnimatedEmojiMessageText(captionX, captionY, canvas, captionLayout != null ? captionLayout.textLayoutBlocks : null, animatedEmojiStack, true, alpha, captionLayout != null ? captionLayout.textXOffset : 0, true); } } public void setHideSideButtonByQuickShare (boolean hide) { if (hideSideButtonByQuickShare != hide) { hideSideButtonByQuickShare = hide; boolean b = invalidatesParent; invalidatesParent = true; invalidate(); invalidatesParent = b; } } public void drawSideButton(Canvas canvas) { drawSideButton(canvas, false); } public void drawSideButton(Canvas canvas, boolean fromQuickShare) { if (hideSideButtonByQuickShare && !fromQuickShare || drawSideButton == 0) { return; } if (currentPosition != null && currentMessagesGroup != null && currentMessagesGroup.isDocuments && !currentPosition.last) { return; } if (currentMessageObject.isOutOwner()) { sideStartX = transitionParams.lastBackgroundLeft - dp(8 + 32); if (currentMessagesGroup != null) { sideStartX += currentMessagesGroup.transitionParams.offsetLeft - animationOffsetX; } } else { sideStartX = transitionParams.lastBackgroundRight + dp(8); if (currentMessagesGroup != null) { sideStartX += currentMessagesGroup.transitionParams.offsetRight - animationOffsetX; } } if (drawSideButton == SIDE_BUTTON_SPONSORED_CLOSE) { sideStartY = dp(6); } else { sideStartY = layoutHeight + transitionParams.deltaBottom - dp(41); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS && currentMessageObject.textWidth < timeTextWidth) { sideStartY -= dp(22); } if (currentMessagesGroup != null) { sideStartY += currentMessagesGroup.transitionParams.offsetBottom; if (currentMessagesGroup.transitionParams.backgroundChangeBounds) { sideStartY -= getTranslationY(); } } if (currentMessageObject.shouldDrawReactions() && !reactionsLayoutInBubble.isSmall) { if (isRoundVideo) { sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress) * (1f - getVideoTranscriptionProgress()); } else if (reactionsLayoutInBubble.drawServiceShaderBackground > 0) { sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress); } } } if (drawSideButton != SIDE_BUTTON_SPONSORED_CLOSE) { float sideMin = (layoutHeight + transitionParams.deltaBottom - dp(32)) / 2f; if (sideStartY < sideMin) { sideStartY = sideMin; } } if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { if (drawSideButton == 3 && commentLayout != null) { sideStartY = dp(18); } else { sideStartY = 0; } } if (!currentMessageObject.isOutOwner() && isRoundVideo && !hasLinkPreview) { float offsetSize = isAvatarVisible ? ((AndroidUtilities.roundPlayingMessageSize(isSideMenued) - AndroidUtilities.roundMessageSize) * 0.7f) : dp(50); float offsetX = isPlayingRound ? offsetSize * (1f - getVideoTranscriptionProgress()) : 0; float offsetY = isPlayingRound ? dp(28) * (1f - getVideoTranscriptionProgress()) : 0; if (transitionParams.animatePlayingRound) { offsetX = (isPlayingRound ? transitionParams.animateChangeProgress : (1f - transitionParams.animateChangeProgress)) * (1f - getVideoTranscriptionProgress()) * offsetSize; offsetY = (isPlayingRound ? transitionParams.animateChangeProgress : (1f - transitionParams.animateChangeProgress)) * (1f - getVideoTranscriptionProgress()) * dp(28); } sideStartX -= offsetX; sideStartY -= offsetY; } sideButtonVisible = true; if (drawSideButton == 3) { if (!(enterTransitionInProgress && !currentMessageObject.isVoice())) { drawCommentButton(canvas, 1f); } } else { if (SizeNotifierFrameLayout.drawingBlur) { return; } rect.set(sideStartX, sideStartY, sideStartX + dp(32), sideStartY + dp(drawSideButton2 == SIDE_BUTTON_SPONSORED_MORE ? 64 : 32)); if (rect.right >= getMeasuredWidth()) { sideButtonVisible = false; return; } final int sponosoredAlpha = (int) (255 * (1f - isSponsoredMessageHidden.getFloatValue())); int restoreToSponosoredAlpha = -1; if (sponosoredAlpha != 255) { restoreToSponosoredAlpha = canvas.saveLayerAlpha(sideStartX, sideStartY, sideStartX + dp(32), sideStartY + dp(64), sponosoredAlpha); } applyServiceShaderMatrix(); if (drawSideButton == SIDE_BUTTON_SPONSORED_CLOSE && drawSideButton2 == SIDE_BUTTON_SPONSORED_MORE && sideButtonPressed) { if (sideButtonPath1 == null) { sideButtonPath1 = new Path(); } else { sideButtonPath1.rewind(); } if (sideButtonPath2 == null) { sideButtonPath2 = new Path(); } else { sideButtonPath2.rewind(); } if (sideButtonPathCorners1 == null) { sideButtonPathCorners1 = new float[8]; sideButtonPathCorners1[0] = sideButtonPathCorners1[1] = sideButtonPathCorners1[2] = sideButtonPathCorners1[3] = dp(16); } if (sideButtonPathCorners2 == null) { sideButtonPathCorners2 = new float[8]; sideButtonPathCorners2[4] = sideButtonPathCorners2[5] = sideButtonPathCorners2[6] = sideButtonPathCorners2[7] = dp(16); } AndroidUtilities.rectTmp.set(sideStartX, sideStartY, sideStartX + dp(32), sideStartY + dp(32)); sideButtonPath1.addRoundRect(AndroidUtilities.rectTmp, sideButtonPathCorners1, Path.Direction.CW); AndroidUtilities.rectTmp.set(sideStartX, sideStartY + dp(32), sideStartX + dp(32), sideStartY + dp(64)); sideButtonPath2.addRoundRect(AndroidUtilities.rectTmp, sideButtonPathCorners2, Path.Direction.CW); if (pressedSideButton == SIDE_BUTTON_SPONSORED_CLOSE) { canvas.drawPath(sideButtonPath1, getThemedPaint(Theme.key_paint_chatActionBackgroundSelected)); canvas.drawPath(sideButtonPath2, getThemedPaint(Theme.key_paint_chatActionBackground)); } else { canvas.drawPath(sideButtonPath1, getThemedPaint(Theme.key_paint_chatActionBackground)); canvas.drawPath(sideButtonPath2, getThemedPaint(Theme.key_paint_chatActionBackgroundSelected)); } } else { canvas.drawRoundRect(rect, dp(16), dp(16), getThemedPaint(sideButtonPressed ? Theme.key_paint_chatActionBackgroundSelected : Theme.key_paint_chatActionBackground)); } if (hasGradientService()) { canvas.drawRoundRect(rect, dp(16), dp(16), Theme.chat_actionBackgroundGradientDarkenPaint); } if (drawSideButton == 2) { Drawable goIconDrawable = getThemedDrawable(Theme.key_drawable_goIcon); setDrawableBounds(goIconDrawable, sideStartX + dp(16) - goIconDrawable.getIntrinsicWidth() / 2f, sideStartY + dp(16) - goIconDrawable.getIntrinsicHeight() / 2f); goIconDrawable.draw(canvas); } else if (drawSideButton == SIDE_BUTTON_SPONSORED_CLOSE) { final int scx = (int) (sideStartX + dp(16)), scy = (int) (sideStartY + dp(16)); Drawable drawable = getThemedDrawable(Theme.key_drawable_closeIcon); int shw = drawable.getIntrinsicWidth() / 2, shh = drawable.getIntrinsicHeight() / 2; drawable.setBounds(scx - shw, scy - shh, scx + shw, scy + shh); setDrawableBounds(drawable, sideStartX + dp(4), sideStartY + dp(4)); canvas.save(); canvas.scale(.65f, .65f, drawable.getBounds().centerX(), drawable.getBounds().centerY()); drawable.draw(canvas); canvas.restore(); if (drawSideButton2 == SIDE_BUTTON_SPONSORED_MORE) { drawable = getThemedDrawable(Theme.key_drawable_moreIcon); shw = drawable.getIntrinsicWidth() / 2; shh = drawable.getIntrinsicHeight() / 2; drawable.setBounds(scx - shw, scy - shh, scx + shw, scy + shh); setDrawableBounds(drawable, sideStartX + dp(4), sideStartY + dp(34)); drawable.draw(canvas); } } else { final int scx = (int) (sideStartX + dp(16)), scy = (int) (sideStartY + dp(16)); Drawable drawable = getThemedDrawable(Theme.key_drawable_shareIcon); final int shw = drawable.getIntrinsicWidth() / 2, shh = drawable.getIntrinsicHeight() / 2; drawable.setBounds(scx - shw, scy - shh, scx + shw, scy + shh); setDrawableBounds(drawable, sideStartX + dp(4), sideStartY + dp(4)); drawable.draw(canvas); } if (restoreToSponosoredAlpha != -1) { canvas.restoreToCount(restoreToSponosoredAlpha); } } } private SummaryIcon summarizeIcon; public void drawSummarizeButton(Canvas canvas) { summarizeButtonX = sideStartX; summarizeButtonY = getPaddingTop() + dp(8); summarizeButtonY = Math.max(Math.min(-childPosition2 + dp(4), sideStartY - dp(42)), summarizeButtonY); if (drawSummarizeButton && sideButtonVisible) { rect.set(summarizeButtonX, summarizeButtonY, summarizeButtonX + dp(32), summarizeButtonY + dp(32)); applyServiceShaderMatrix(); canvas.drawRoundRect(rect, dp(16), dp(16), getThemedPaint(sideButtonPressed ? Theme.key_paint_chatActionBackgroundSelected : Theme.key_paint_chatActionBackground)); if (hasGradientService()) { canvas.drawRoundRect(rect, dp(16), dp(16), Theme.chat_actionBackgroundGradientDarkenPaint); } if (summarizeIcon == null) { summarizeIcon = new SummaryIcon(this); } final MessageObject msg = getMessageObject(); final boolean open = msg != null && msg.messageOwner != null && msg.messageOwner.summarizedOpen; summarizeIcon.set(open); setDrawableBounds(summarizeIcon, summarizeButtonX + dp(16) - summarizeIcon.getIntrinsicWidth() / 2f, summarizeButtonY + dp(16) - summarizeIcon.getIntrinsicHeight() / 2f); summarizeIcon.draw(canvas); } } public float getSideButtonStartX() { return sideStartX; } public float getSideButtonStartY() { return sideStartY; } public void setTimeAlpha(float value) { timeAlpha = value; } public float getTimeAlpha() { return timeAlpha; } private boolean isSideMenuPossibleLeftMargin() { return isSideMenued && (currentMessageObject != null && !currentMessageObject.isOutOwner()) && (currentPosition == null); } private boolean isSideMenuLeftMargin() { return isSideMenuEnabled && (currentMessageObject != null && !currentMessageObject.isOutOwner()) && (currentPosition == null); } public int getBackgroundDrawableLeft() { MessageObject messageObject = getMessageObject(); if (messageObject != null && messageObject.isOutOwner()) { if (isRoundVideo) { return layoutWidth - backgroundWidth - (int) ((1f - getVideoTranscriptionProgress()) * dp(9)); } return layoutWidth - backgroundWidth - (!mediaBackground ? 0 : dp(9)); } else { int r; if (isRoundVideo) { r = dp(isSideMenuLeftMargin() ? ChatActivity.SIDE_MENU_WIDTH : ((isChat || messageObject != null && (messageObject.isRepostPreview || messageObject.forceAvatar || messageObject.messageOwner.guestchat_via_from != null) || messageObject.getDialogId() == UserObject.VERIFY) && isAvatarVisible ? 48 : 0) + 3); r += (int) (dp(6) * (1f - getVideoTranscriptionProgress())); } else { r = dp(isSideMenuLeftMargin() ? ChatActivity.SIDE_MENU_WIDTH : ((isChat || messageObject != null && (messageObject.isRepostPreview || messageObject.forceAvatar || messageObject.messageOwner.guestchat_via_from != null) || messageObject.getDialogId() == UserObject.VERIFY) && isAvatarVisible ? 48 : 0)) + dp(!mediaBackground ? 3 : 9); } if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { if (currentPosition.leftSpanOffset != 0) { r += (int) Math.ceil(currentPosition.leftSpanOffset / 1000.0f * getGroupPhotosWidth()); } } if (isRoundVideo) { if (drawPinnedBottom) { r += (int) (dp(6) * (1f - getVideoTranscriptionProgress())); } } else if (!mediaBackground && drawPinnedBottom) { r += dp(6); } return r; } } public int getBackgroundDrawableRight() { int right = backgroundWidth; if (isRoundVideo) { right -= (int) (getVideoTranscriptionProgress() * dp(3)); if (drawPinnedBottom && (currentMessageObject != null && currentMessageObject.isOutOwner())) { right -= dp(6) * (1f - getVideoTranscriptionProgress()); } if (drawPinnedBottom && !(currentMessageObject != null && currentMessageObject.isOutOwner())) { right -= dp(6) * (1f - getVideoTranscriptionProgress()); } return getBackgroundDrawableLeft() + right; } right -= (mediaBackground ? 0 : dp(3)); if (!mediaBackground && drawPinnedBottom) { right -= dp(6); } return getBackgroundDrawableLeft() + right; } public int getBackgroundDrawableTop() { int additionalTop = 0; if (currentPosition != null) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { additionalTop -= dp(3); } } int top = additionalTop + (drawPinnedTop ? 0 : dp(1)); if (!mediaBackground) { if (drawPinnedTop) { top -= dp(1); } } return top; } public int getBackgroundDrawableBottom() { int additionalBottom = 0; if (currentPosition != null) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { additionalBottom += dp(3); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { additionalBottom += dp((currentMessageObject != null && currentMessageObject.isOutOwner() ? 3 : 4)); } } int offsetBottom; if (drawPinnedBottom && drawPinnedTop) { offsetBottom = 0; } else if (drawPinnedBottom) { offsetBottom = dp(1); } else { offsetBottom = dp(2); } int top = getBackgroundDrawableTop(); int bottom = top + layoutHeight - offsetBottom + additionalBottom; if (!mediaBackground) { if (drawPinnedTop) { bottom += dp(1); } if (drawPinnedBottom) { bottom += dp(1); } } return bottom; } public void drawBackground(Canvas canvas, int left, int top, int right, int bottom, boolean pinnedTop, boolean pinnedBottom, boolean selected, int keyboardHeight) { if (currentMessageObject != null && currentMessageObject.isOutOwner()) { if (!mediaBackground && !pinnedBottom) { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(selected ? Theme.key_drawable_msgOutSelected : Theme.key_drawable_msgOut); } else { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(selected ? Theme.key_drawable_msgOutMediaSelected : Theme.key_drawable_msgOutMedia); } } else { if (!mediaBackground && !pinnedBottom) { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(selected ? Theme.key_drawable_msgInSelected : Theme.key_drawable_msgIn); } else { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(selected ? Theme.key_drawable_msgInMediaSelected : Theme.key_drawable_msgInMedia); } } int w = parentWidth; int h = parentHeight; if (h == 0) { w = getParentWidth(); h = AndroidUtilities.displaySize.y; if (getParent() instanceof View) { View view = (View) getParent(); w = view.getMeasuredWidth(); h = view.getMeasuredHeight(); } } if (currentBackgroundDrawable != null) { currentBackgroundDrawable.setTop(keyboardHeight, w, h, (int) parentViewTopOffset, blurredViewTopOffset, blurredViewBottomOffset, pinnedTop, pinnedBottom); currentBackgroundDrawable.setBotButtonsBottom(hasInlineBotButtons()); Drawable currentBackgroundShadowDrawable = currentBackgroundDrawable.getShadowDrawable(); if (currentBackgroundShadowDrawable != null) { currentBackgroundShadowDrawable.setAlpha((int) (getAlpha() * 255)); currentBackgroundShadowDrawable.setBounds(left, top, right, bottom); currentBackgroundShadowDrawable.draw(canvas); currentBackgroundShadowDrawable.setAlpha(255); } currentBackgroundDrawable.setAlpha((int) (getAlpha() * 255)); currentBackgroundDrawable.setBounds(left, top, right, bottom); currentBackgroundDrawable.drawCached(canvas, backgroundCacheParams); currentBackgroundDrawable.setAlpha(255); } animateCheckboxTranslation(); } private boolean hasInlineBotButtons() { return currentMessageObject != null && currentMessageObject.hasInlineBotButtons() || drawContinueBotTopic; } public boolean hasNameLayout() { return ( drawNameLayout && nameLayout != null || drawForwardedName && forwardedNameLayout[0] != null && forwardedNameLayout[1] != null && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0) || drawSummaryReply || transitionParams.animateSummaryReply || replyNameLayout != null ); } public boolean isDrawNameLayout() { return drawNameLayout && nameLayout != null; } public boolean isAdminLayoutChanged() { return !TextUtils.equals(lastPostAuthor, currentMessageObject.messageOwner.post_author); } public void drawNamesLayout(Canvas canvas, float alpha) { long newAnimationTime = SystemClock.elapsedRealtime(); long dt = newAnimationTime - lastNamesAnimationTime; if (dt > 17) { dt = 17; } lastNamesAnimationTime = newAnimationTime; if (currentMessageObject.deleted && !drawingToBitmap && currentMessagesGroup != null && currentMessagesGroup.messages.size() >= 1) { return; } int restore = Integer.MIN_VALUE; if (alpha != 1f) { rect.set(0, 0, getMaxNameWidth(), getMeasuredHeight()); restore = canvas.saveLayerAlpha(rect, (int) (255 * alpha), Canvas.ALL_SAVE_FLAG); } float replyForwardAlpha = 1f; if (isRoundVideo && !hasLinkPreview) { replyForwardAlpha *= 1f - getVideoTranscriptionProgress(); if (transitionParams.animatePlayingRound) { if (isPlayingRound) { replyForwardAlpha *= (1f - transitionParams.animateChangeProgress); } else { replyForwardAlpha *= transitionParams.animateChangeProgress; } } else if (isPlayingRound) { replyForwardAlpha = 0; } } if ((drawNameLayout || transitionParams.animateDrawNameLayout) && nameLayout != null) { float nameAlpha = !transitionParams.animateDrawNameLayout ? 1f : (drawNameLayout ? transitionParams.animateChangeProgress : 1f - transitionParams.animateChangeProgress); canvas.save(); int oldAlpha; if (currentMessageObject.shouldDrawWithoutBackground()) { Theme.chat_namePaint.setColor(getThemedColor(Theme.key_chat_stickerNameText)); if (currentMessageObject.isOutOwner()) { nameX = dp(28); } else { nameX = backgroundDrawableLeft + transitionParams.deltaLeft + backgroundDrawableRight + dp(22); } if (currentNameBotVerificationId != 0) { nameX += dp(20); } nameY = layoutHeight - dp(38); float alphaProgress = currentMessageObject.isOut() && (checkBoxVisible || checkBoxAnimationInProgress) ? (1.0f - checkBoxAnimationProgress) : 1.0f; rect.set((int) nameX - dp(12), (int) nameY - dp(5), (int) nameX + dp(12) + nameWidth, (int) nameY + dp(22)); applyServiceShaderMatrix(); oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (alphaProgress * oldAlpha * replyForwardAlpha)); canvas.drawRoundRect(rect, dp(6), dp(6), getThemedPaint(Theme.key_paint_chatActionBackground)); if (hasGradientService()) { int oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * timeAlpha * replyForwardAlpha)); canvas.drawRoundRect(rect, dp(6), dp(6), Theme.chat_actionBackgroundGradientDarkenPaint); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); } if (viaSpan1 != null || viaSpan2 != null) { int color = getThemedColor(Theme.key_chat_stickerViaBotNameText); color = (getThemedColor(Theme.key_chat_stickerViaBotNameText) & 0x00ffffff) | ((int) (Color.alpha(color) * alphaProgress) << 24); if (viaSpan1 != null) { viaSpan1.setColor(color); } if (viaSpan2 != null) { viaSpan2.setColor(color); } } nameX -= nameOffsetX; getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); } else { if (mediaBackground || currentMessageObject.isOutOwner()) { nameX = backgroundDrawableLeft + transitionParams.deltaLeft + dp(isSideMenuEnabled && currentPosition != null && !currentMessageObject.isOutOwner() && currentMessagesGroup != null && !currentMessagesGroup.isDocuments ? -4 : 11) - nameOffsetX + getExtraTextX(); } else { nameX = backgroundDrawableLeft + transitionParams.deltaLeft + dp(!mediaBackground && drawPinnedBottom ? 11 : 17) - nameOffsetX + getExtraTextX(); } if (currentNameBotVerificationId != 0) { nameX += dp(20); } if (currentMessageObject.isOutOwner() && ChatObject.isChannel(currentChat)) { if (currentBackgroundDrawable != null && currentBackgroundDrawable.hasGradient()) { Theme.chat_namePaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); } else { Theme.chat_namePaint.setColor(getThemedColor(Theme.key_chat_outForwardedNameText)); } } else if (currentMessageObject.isOutOwner()) { Theme.chat_namePaint.setColor(getThemedColor(Theme.key_chat_outForwardedNameText)); } else if ( currentMessageObject.overrideLinkColor >= 0 || currentMessageObject.isFromUser() && currentUser != null || currentMessageObject.isFromChannel() && currentChat != null ) { int colorId; if (currentMessageObject.overrideLinkColor >= 0) { colorId = currentMessageObject.overrideLinkColor; } else if (currentMessageObject.isFromUser() && currentUser != null) { colorId = UserObject.getColorId(currentUser); } else { colorId = ChatObject.getColorId(currentChat); } if (colorId < 7) { Theme.chat_namePaint.setColor(getThemedColor(Theme.keys_avatar_nameInMessage[colorId])); } else { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { Theme.chat_namePaint.setColor(peerColor.getColor(0, resourcesProvider)); } else { Theme.chat_namePaint.setColor(getThemedColor(Theme.key_chat_inForwardedNameText)); } } } else { Theme.chat_namePaint.setColor(getThemedColor(Theme.key_chat_inForwardedNameText)); } nameY = dp(drawPinnedTop ? 9 : 10); if (viaSpan1 != null || viaSpan2 != null) { int color = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outViaBotNameText : Theme.key_chat_inViaBotNameText); if (viaSpan1 != null) { viaSpan1.setColor(color); } if (viaSpan2 != null) { viaSpan2.setColor(color); } } } if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { nameX += currentMessagesGroup.transitionParams.offsetLeft; nameY += currentMessagesGroup.transitionParams.offsetTop - getTranslationY(); } nameX += animationOffsetX; nameY += transitionParams.deltaTop; float nx; if (transitionParams.animateSign) { nx = transitionParams.animateNameX + (nameX - transitionParams.animateNameX) * transitionParams.animateChangeProgress; } else { nx = nameX; } float ny = nameY; final float avatarAlpha; if (transitionParams.animateDrawAvatar) { avatarAlpha = lerp(!drawNameAvatar, drawNameAvatar, transitionParams.animateChangeProgress); } else { avatarAlpha = drawNameAvatar ? 1.0f : 0.0f; } if (avatarAlpha > 0.0f) { float avatarX = nx; if (currentNameBotVerificationId != 0) { avatarX -= dp(20); } final float wasX = avatarImage.getImageX(); final float wasY = avatarImage.getImageY(); final float wasWidth = avatarImage.getImageWidth(); final float wasHeight = avatarImage.getImageHeight(); final float wasAlpha = avatarImage.getAlpha(); final float scale = lerp(.1f, 1.0f, avatarAlpha); final boolean wasVisible = avatarImage.getVisible(); avatarImage.setVisible(true, false); avatarImage.setImageCoords(avatarX, ny + dp(13) * (1.0f - scale), dp(26) * scale, dp(26) * scale); avatarImage.setAlpha(avatarAlpha); avatarImage.draw(canvas); avatarImage.setImageCoords(wasX, wasY, wasWidth, wasHeight); avatarImage.setAlpha(wasAlpha); avatarImage.setVisible(wasVisible, false); } nx += dp(32.33f) * avatarAlpha; if (adminLayout == null) { ny += dp(5) * avatarAlpha; } else { ny -= dp(2.33f) * avatarAlpha; } if (!currentMessageObject.isSponsored()) { int selectorColor = Theme.multAlpha(Theme.chat_namePaint.getColor(), .12f); if (nameLayoutSelector == null) { nameLayoutSelector = Theme.createRadSelectorDrawable(nameLayoutSelectorColor = selectorColor, 6, 6); nameLayoutSelector.setCallback(this); } else if (nameLayoutSelectorColor != selectorColor) { Theme.setSelectorDrawableColor(nameLayoutSelector, nameLayoutSelectorColor = selectorColor, true); } nameLayoutSelector.setBounds( (int) (nx + nameOffsetX - dp(4)), (int) (ny - dp(1.33f)), (int) (nx + nameOffsetX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(4)), (int) (ny + nameLayout.getHeight() + dp(1.33f)) ); nameLayoutSelector.setAlpha((int) (0xFF * nameAlpha)); nameLayoutSelector.draw(canvas); if (currentNameStatus != null) { if (nameStatusSelector == null) { nameStatusSelector = Theme.createRadSelectorDrawable(nameStatusSelectorColor = selectorColor, 6, 6); nameStatusSelector.setCallback(this); } else if (nameStatusSelectorColor != selectorColor) { Theme.setSelectorDrawableColor(nameStatusSelector, nameStatusSelectorColor = selectorColor, true); } boolean isStarDrawable = currentNameStatus instanceof Drawable; //star has smaller size than other emoji float starVerticalOffset = isStarDrawable ? 1.5f : 0f; float starHorizontalOffset = isStarDrawable ? -5 : 0; nameStatusSelector.setBounds( (int) (nx + nameOffsetX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth)), (int) (ny - dp(1.33f + 2 - starVerticalOffset)), (int) (nx + nameOffsetX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(4 + 12 + 4 + 4 + starHorizontalOffset)), (int) (ny + nameLayout.getHeight() + dp(1.33f + 2 - starVerticalOffset)) ); nameStatusSelector.setAlpha((int) (0xFF * nameAlpha)); nameStatusSelector.draw(canvas); } } canvas.translate(nx, ny); oldAlpha = Theme.chat_namePaint.getAlpha(); Theme.chat_namePaint.setAlpha((int) (oldAlpha * nameAlpha)); nameLayout.draw(canvas); Theme.chat_namePaint.setAlpha(oldAlpha); canvas.restore(); float end; if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { int dWidth = getGroupPhotosWidth(); int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } if (!mediaBackground && currentMessageObject.isOutOwner()) { end = backgroundDrawableLeft + firstLineWidth - dp(6); } else { end = backgroundDrawableLeft + firstLineWidth; } end -= getExtraTextX() + dp(8); if (isSideMenuEnabled) { end -= dp(ChatActivity.SIDE_MENU_WIDTH); } else if (!currentMessageObject.isOutOwner()) { end -= dp(48); } } else { if (currentMessageObject.shouldDrawWithoutBackground()) { if (currentMessageObject.isOutOwner()) { end = dp(28 + 11) + nameWidth; } else { end = backgroundDrawableLeft + transitionParams.deltaLeft + backgroundDrawableRight + dp(33) + nameWidth; } } else if (!mediaBackground && currentMessageObject.isOutOwner()) { end = backgroundDrawableLeft + backgroundDrawableRight - dp(6); } else { end = backgroundDrawableLeft + backgroundDrawableRight; } } end += transitionParams.deltaRight; if (adminLayout != null) { int color; if (currentMessageObject.shouldDrawWithoutBackground()) { color = getThemedColor(Theme.key_chat_stickerReplyNameText); } else if (currentMessageObject.isOutOwner()) { color = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outAdminSelectedText : Theme.key_chat_outAdminText); } else { if (adminLayoutIsOwner) { color = getThemedColor(Theme.key_chat_tagCreator); } else if (adminLayoutIsAdmin) { color = getThemedColor(Theme.key_chat_tagAdmin); } else { color = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inAdminSelectedText : Theme.key_chat_inAdminText); } } Theme.chat_adminPaint.setColor(color); canvas.save(); final float lineWidth = adminLayout.getLineWidth(0); float ax = end - dp(11) - lineWidth - (adminLayoutIsAdmin ? dp(6) : 0); float ax2 = end - dp(11); float ay = nameY + dp(0.5f); ax = lerp(ax, nx, avatarAlpha); ax2 = lerp(ax2, nx + lineWidth + (adminLayoutIsAdmin ? dp(6) : 0), avatarAlpha); ay += dp(14) * avatarAlpha; if (currentNameBotVerificationId != 0) { ax -= dp(20) * avatarAlpha; } if (boostCounterSpan != null && boostCounterBounds != null) { final float bx = ax + lineWidth + dp(11) - dp(boostCounterSpan.isRtl ? 5f : 7.5f) - boostCounterSpan.getWidth(); boostCounterBounds.set(bx, ay, bx + boostCounterSpan.getWidth(), ay + adminLayout.getHeight()); if (boostCounterSpan.margin) { if (boostCounterSpan.isRtl) { boostCounterBounds.right -= dp(8); } else { boostCounterBounds.left += dp(8); } } int selectorColor = Theme.multAlpha(Theme.chat_namePaint.getColor(), .12f); if (boostCounterLayoutSelector == null) { boostCounterLayoutSelector = Theme.createRadSelectorDrawable(boostCounterSelectorColor = selectorColor, 6, 6); boostCounterLayoutSelector.setCallback(this); } else if (boostCounterSelectorColor != selectorColor) { Theme.setSelectorDrawableColor(boostCounterLayoutSelector, boostCounterSelectorColor = selectorColor, true); } boostCounterLayoutSelector.setBounds((int) boostCounterBounds.left - dp(4), (int) boostCounterBounds.top, (int) (int) boostCounterBounds.right, (int) boostCounterBounds.bottom); boostCounterLayoutSelector.setAlpha((int) (0xFF * nameAlpha)); boostCounterLayoutSelector.draw(canvas); } adminLayoutRect.set(ax - dp(6), ay - dp(1), ax2, ay + dp(15)); adminLayoutRect.inset(dp(-4), dp(-4)); final float scale = adminLayoutBounce == null ? 1.0f : adminLayoutBounce.getScale(.05f); canvas.scale(scale, scale, adminLayoutRect.centerX(), adminLayoutRect.centerY()); canvas.translate(ax, ay); if (transitionParams.animateSign) { Theme.chat_adminPaint.setAlpha((int) (Color.alpha(color) * transitionParams.animateChangeProgress)); } if (adminLayoutIsAdmin) { AndroidUtilities.rectTmp.set(-dp(6), -dp(1), ax2 - ax, dp(15)); if (boostCounterSpan != null) { if (boostCounterSpan.isRtl) { AndroidUtilities.rectTmp.left += boostCounterSpan.getWidth(); } else { AndroidUtilities.rectTmp.right -= boostCounterSpan.getWidth(); } } final int wasAlpha = Theme.chat_adminPaint.getAlpha(); Theme.chat_adminPaint.setAlpha((int) (wasAlpha * 0.12f)); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), Theme.chat_adminPaint); Theme.chat_adminPaint.setAlpha(wasAlpha); } adminLayout.draw(canvas); canvas.restore(); } } if (ephemeralLayout != null) { if (currentMessageObject.shouldDrawWithoutBackground() && currentMessageObject.isOutOwner()) { ephemeralX = dp(20); } else if (mediaBackground || currentMessageObject.isOutOwner()) { ephemeralX = backgroundDrawableLeft + transitionParams.deltaLeft + dp(isSideMenuEnabled && currentPosition != null && !currentMessageObject.isOutOwner() && currentMessagesGroup != null && !currentMessagesGroup.isDocuments ? -4 : 11) - nameOffsetX + getExtraTextX(); } else { ephemeralX = backgroundDrawableLeft + transitionParams.deltaLeft + dp(!mediaBackground && drawPinnedBottom ? 11 : 17) - nameOffsetX + getExtraTextX(); } ephemeralY = dp(drawPinnedTop ? 9 : 10); if ((drawNameLayout || transitionParams.animateDrawNameLayout) && nameLayout != null) { ephemeralY += dp(21.66f); } final float avatarAlpha; if (transitionParams != null && transitionParams.animateDrawAvatar) { avatarAlpha = lerp(!drawNameAvatar, drawNameAvatar, transitionParams.animateChangeProgress); } else { avatarAlpha = drawNameAvatar ? 1.0f : 0.0f; } if (avatarAlpha > 0) { ephemeralY += dp(12 * sideMenuAlpha); } final int ephemeralBaseColor = currentMessageObject.shouldDrawWithoutBackground() ? getThemedColor(Theme.key_chat_stickerReplyNameText) : getThemedColor( currentMessageObject.isOut() && (resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark()) ? Theme.key_chat_messageLinkOut : Theme.key_chat_tagAdmin); Theme.chat_ephemeralPaint.setColor(ephemeralBaseColor); float ax = ephemeralX; float ay = ephemeralY + dp(0.5f); AndroidUtilities.rectTmp.set(-dp(3.33f), -dp(1.66f), ephemeralLayout.getLineWidth(0) + dp(6), dp(15.66f)); AndroidUtilities.rectTmp.offset(ax, ay); if (currentMessageObject.shouldDrawWithoutBackground()) { applyServiceShaderMatrix(); int oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8.66f), dp(8.66f), getThemedPaint(Theme.key_paint_chatActionBackground)); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); if (hasGradientService()) { oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8.66f), dp(8.66f), Theme.chat_actionBackgroundGradientDarkenPaint); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); } } else { final int wasAlpha = Theme.chat_ephemeralPaint.getAlpha(); Theme.chat_ephemeralPaint.setAlpha((int) (wasAlpha * 0.12f)); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8.66f), dp(8.66f), Theme.chat_ephemeralPaint); Theme.chat_ephemeralPaint.setAlpha(wasAlpha); } canvas.save(); canvas.translate(ax, ay); ephemeralLayout.draw(canvas); canvas.restore(); } boolean drawForwardedNameLocal = drawForwardedName || currentMessageObject.type == MessageObject.TYPE_STORY; boolean hasReply = replyNameLayout != null; StaticLayout[] forwardedNameLayoutLocal = forwardedNameLayout; float animatingAlpha = 1f; int forwardedNameWidthLocal = forwardedNameWidth; if (transitionParams.animateForwardedLayout) { if (!currentMessageObject.needDrawForwarded()) { drawForwardedNameLocal = true; forwardedNameLayoutLocal = transitionParams.animatingForwardedNameLayout; animatingAlpha = 1f - transitionParams.animateChangeProgress; forwardedNameWidthLocal = transitionParams.animateForwardNameWidth; } else { animatingAlpha = transitionParams.animateChangeProgress; } } float forwardNameXLocal = 0; int forwardNameRight = -1; boolean needDrawReplyBackground = true; if (drawForwardedNameLocal && forwardedNameLayoutLocal[0] != null && forwardedNameLayoutLocal[1] != null && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0)) { if (!isSideMenued && (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO || currentMessageObject.isAnyKindOfSticker())) { Theme.chat_forwardNamePaint.setColor(getThemedColor(Theme.key_chat_stickerReplyNameText)); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { if (currentMessageObject.isOutOwner()) { if (currentMessageObject.needDrawForwarded()) { forwardNameXLocal = forwardNameX = backgroundDrawableLeft + dp(11) + getExtraTextX(); forwardNameXLocal += transitionParams.deltaLeft; } else { forwardNameXLocal = transitionParams.animateForwardNameX; } int width = Math.max(forwardedNameWidthLocal + dp(14), hasReply ? Math.max(replyNameWidth, replyTextWidth) + dp(14) : 0); forwardNameXLocal -= Math.max(0, forwardNameXLocal + width - AndroidUtilities.displaySize.x); } else { if (currentMessageObject.needDrawForwarded()) { forwardNameXLocal = forwardNameX = backgroundDrawableLeft + dp(mediaBackground || drawPinnedBottom ? 11 : 17) + getExtraTextX(); } else { forwardNameXLocal = transitionParams.animateForwardNameX; } } forwardNameXLocal -= dp(7); } else if (currentMessageObject.needDrawForwarded()) { if (currentMessageObject.isOutOwner()) { forwardNameXLocal = forwardNameX = dp(23); } else { forwardNameXLocal = forwardNameX = backgroundDrawableLeft + backgroundDrawableRight + dp(17); } } else { forwardNameXLocal = transitionParams.animateForwardNameX; } if (!currentMessageObject.isVoiceTranscriptionOpen() && (currentMessageObject.isOutOwner() && currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO && transitionParams.animatePlayingRound || isPlayingRound)) { forwardNameXLocal -= dp(78) * (isPlayingRound ? transitionParams.animateChangeProgress : (1f - transitionParams.animateChangeProgress)); } forwardNameY = dp(12); forwardHeight = dp(4) + (int) Theme.chat_forwardNamePaint.getTextSize() * 2; int backWidth = forwardedNameWidthLocal + dp(14); if (hasReply) { needDrawReplyBackground = false; int replyBackWidth = Math.max(replyNameWidth, replyTextWidth) - dp(4) + dp(7); rect.set((int) forwardNameXLocal - dp(7), forwardNameY - dp(6), forwardNameRight = ((int) forwardNameXLocal - dp(7) + Math.max(backWidth, replyBackWidth)), forwardNameY + forwardHeight + dp(6) + replyHeight + dp(3)); } else { rect.set((int) forwardNameXLocal - dp(7), forwardNameY - dp(6), (int) forwardNameXLocal - dp(7) + backWidth, forwardNameY + forwardHeight + dp(6)); } int oldAlpha1 = -1, oldAlpha2 = -1; if (hasReply || forwardBg == null) { applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, getX(), viewTop); if (animatingAlpha != 1f || replyForwardAlpha != 1f) { oldAlpha1 = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha1 * animatingAlpha * replyForwardAlpha)); } canvas.drawRoundRect(rect, dp(6), dp(6), getThemedPaint(Theme.key_paint_chatActionBackground)); if (hasGradientService()) { if (animatingAlpha != 1f || replyForwardAlpha != 1f) { oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * animatingAlpha * replyForwardAlpha)); } canvas.drawRoundRect(rect, dp(6), dp(6), Theme.chat_actionBackgroundGradientDarkenPaint); } } else { applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, getX() + forwardNameXLocal, viewTop + forwardNameY); canvas.save(); canvas.translate(forwardNameXLocal, forwardNameY); final float s = forwardBg.bounce.getScale(.02f); canvas.scale(s, s, forwardBg.bounds.centerX(), forwardBg.bounds.centerY()); if (animatingAlpha != 1f || replyForwardAlpha != 1f) { oldAlpha1 = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha1 * animatingAlpha * replyForwardAlpha)); } canvas.drawPath(forwardBg.path, getThemedPaint(Theme.key_paint_chatActionBackground)); if (hasGradientService()) { if (animatingAlpha != 1f || replyForwardAlpha != 1f) { oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * animatingAlpha * replyForwardAlpha)); } canvas.drawPath(forwardBg.path, Theme.chat_actionBackgroundGradientDarkenPaint); } canvas.restore(); } if (oldAlpha1 >= 0) { getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha1); } if (oldAlpha2 >= 0) { Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); } } else { forwardNameY = dp(7) + (int) (drawNameLayout ? getNameHeightAnimated() + dp(1) : 0); if (!drawNameLayout && (currentMessageObject.type == MessageObject.TYPE_GIF || currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.type == MessageObject.TYPE_VIDEO || currentMessageObject.type == MessageObject.TYPE_STORY || currentMessageObject.type == MessageObject.TYPE_PAID_MEDIA || currentMessageObject.type == MessageObject.TYPE_FILE)) { forwardNameY += dp(2); } if (!drawNameLayout && currentMessageObject.type == MessageObject.TYPE_TEXT && !drawPinnedTop) { forwardNameY += dp(2); } forwardHeight = dp(4) + (int) Theme.chat_forwardNamePaint.getTextSize() * 2; Theme.chat_forwardNamePaint.setColor(getThemedColor(hasPsaHint ? Theme.key_chat_inPsaNameText : Theme.key_chat_inForwardedNameText)); if (currentMessageObject.isOutOwner()) { Theme.chat_forwardNamePaint.setColor(getThemedColor(hasPsaHint ? Theme.key_chat_outPsaNameText : Theme.key_chat_outForwardedNameText)); } else if (!hasPsaHint && currentMessageObject.messageOwner != null && (currentMessageObject.isStoryMedia() || currentMessageObject.messageOwner.fwd_from != null && currentMessageObject.messageOwner.fwd_from.from_id != null)) { long dialogId; if (currentMessageObject.isStoryMedia()) { dialogId = DialogObject.getPeerDialogId(MessageObject.getMedia(currentMessageObject).peer); } else { dialogId = DialogObject.getPeerDialogId(currentMessageObject.messageOwner.fwd_from.from_id); } int colorId = 5; if (dialogId < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); if (chat != null) { colorId = ChatObject.getColorId(chat); } } else { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); if (user != null) { colorId = UserObject.getColorId(user); } } if (colorId < 7) { Theme.chat_forwardNamePaint.setColor(getThemedColor(Theme.keys_avatar_nameInMessage[colorId])); } else { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { Theme.chat_forwardNamePaint.setColor(peerColor.getColor(0, resourcesProvider)); } } } if (currentMessageObject.isOutOwner()) { if (currentMessageObject.needDrawForwarded()) { forwardNameXLocal = forwardNameX = backgroundDrawableLeft + dp(10) + getExtraTextX(); forwardNameXLocal += transitionParams.deltaLeft; } else { forwardNameXLocal = transitionParams.animateForwardNameX; } } else { if (currentMessageObject.needDrawForwarded()) { forwardNameXLocal = forwardNameX = backgroundDrawableLeft + dp(mediaBackground || drawPinnedBottom ? 10 : 16) + getExtraTextX(); forwardNameXLocal += transitionParams.deltaLeft; } else { forwardNameXLocal = transitionParams.animateForwardNameX; } } } boolean clipContent = false; if (transitionParams.animateForwardedLayout) { if (currentBackgroundDrawable != null && currentMessagesGroup == null && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO && !currentMessageObject.isAnyKindOfSticker()) { Rect r = currentBackgroundDrawable.getBounds(); canvas.save(); if (currentMessageObject.isOutOwner() && !mediaBackground && !pinnedBottom) { canvas.clipRect( r.left + dp(4), r.top + dp(4), r.right - dp(10), r.bottom - dp(4) ); } else { canvas.clipRect( r.left + dp(4), r.top + dp(4), r.right - dp(4), r.bottom - dp(4) ); } clipContent = true; } } canvas.save(); canvas.translate(forwardNameXLocal, forwardNameY); final boolean forwardLoading = delegate != null && delegate.isProgressLoading(this, ChatActivity.PROGRESS_FORWARD); if (forwardBg != null) { final float s = forwardBg.bounce.getScale(.02f); canvas.scale(s, s, forwardBg.bounds.centerX(), forwardBg.bounds.centerY()); if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO || currentMessageObject.isAnyKindOfSticker()) { forwardBg.setColor(Theme.multAlpha(Theme.getColor(Theme.key_listSelector, resourcesProvider), 1.35f)); } else { forwardBg.setColor(Theme.multAlpha(Theme.chat_forwardNamePaint.getColor(), .15f)); } forwardBg.draw(canvas, forwardLoading); } for (int a = 0; a < 2; a++) { canvas.save(); canvas.translate(-forwardNameOffsetX[a], (forwardHeight / 2f + dp(1.33f)) * a); if (animatingAlpha != 1f || replyForwardAlpha != 1f) { int oldAlpha = forwardedNameLayoutLocal[a].getPaint().getAlpha(); forwardedNameLayoutLocal[a].getPaint().setAlpha((int) (oldAlpha * animatingAlpha * replyForwardAlpha)); forwardedNameLayoutLocal[a].draw(canvas); forwardedNameLayoutLocal[a].getPaint().setAlpha(oldAlpha); } else { forwardedNameLayoutLocal[a].draw(canvas); } canvas.restore(); } canvas.restore(); if (clipContent) { canvas.restore(); } if (hasPsaHint) { if (psaButtonVisible || psaButtonProgress > 0) { Drawable drawable = Theme.chat_psaHelpDrawable[currentMessageObject.isOutOwner() ? 1 : 0]; int cx = psaHelpX + drawable.getIntrinsicWidth() / 2; int cy = psaHelpY + drawable.getIntrinsicHeight() / 2; float scale = psaButtonVisible && psaButtonProgress < 1 ? AnimationProperties.overshootInterpolator.getInterpolation(psaButtonProgress) : psaButtonProgress; int w = (int) (drawable.getIntrinsicWidth() * scale); int h = (int) (drawable.getIntrinsicHeight() * scale); drawable.setBounds(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2); drawable.draw(canvas); if (selectorDrawable[0] != null && selectorDrawableMaskType[0] == 3) { canvas.save(); canvas.scale(psaButtonProgress, psaButtonProgress, selectorDrawable[0].getBounds().centerX(), selectorDrawable[0].getBounds().centerY()); selectorDrawable[0].draw(canvas); canvas.restore(); } } if (psaButtonVisible && psaButtonProgress < 1.0f) { psaButtonProgress += dt / 180.0f; invalidate(); if (psaButtonProgress > 1.0f) { psaButtonProgress = 1.0f; setInvalidatesParent(false); } } else if (!psaButtonVisible && psaButtonProgress > 0.0f) { psaButtonProgress -= dt / 180.0f; invalidate(); if (psaButtonProgress < 0.0f) { psaButtonProgress = 0.0f; setInvalidatesParent(false); } } } } if (hasReply) { float replyStartX = this.replyStartX; float replyStartY = this.replyStartY; if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { replyStartX += currentMessagesGroup.transitionParams.offsetLeft; } if (transitionParams.animateBackgroundBoundsInner) { if (isRoundVideo) { replyStartX += (currentMessageObject.isOutOwner() ? 0 : transitionParams.deltaLeft) + transitionParams.deltaRight; } else { replyStartX += transitionParams.deltaLeft; } replyStartY = AndroidUtilities.lerp(transitionParams.animateFromReplyY, this.replyStartY, transitionParams.animateChangeProgress); } if (!needDrawReplyBackground) { replyStartX = forwardNameXLocal; } final boolean loading = currentMessageObject != null && delegate != null && delegate.isProgressLoading(this, ChatActivity.PROGRESS_REPLY); if (replyPressedFloat == null) { replyPressedFloat = new AnimatedFloat(this); } float replyPressedT = replyPressedFloat.set(replySelectorPressed || loading ? 1f : 0f); if (replyLine == null) { replyLine = new ReplyMessageLine(this); } Theme.chat_replyNamePaint.setColor(replyLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_REPLY)); int rippleColor = ColorUtils.setAlphaComponent(replyLine.getColor(), 0x1e); if (currentMessageObject.shouldDrawWithoutBackground()) { Theme.chat_replyLinePaint.setColor(getThemedColor(Theme.key_chat_stickerReplyLine)); int oldAlpha = Theme.chat_replyLinePaint.getAlpha(); Theme.chat_replyLinePaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); rippleColor = ColorUtils.setAlphaComponent(Theme.chat_replyLinePaint.getColor(), Color.alpha(rippleColor)); Theme.chat_replyNamePaint.setColor(getThemedColor(Theme.key_chat_stickerReplyNameText)); oldAlpha = Theme.chat_replyNamePaint.getAlpha(); Theme.chat_replyNamePaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); Theme.chat_replyTextPaint.setColor(getThemedColor(Theme.key_chat_stickerReplyMessageText)); Theme.chat_replyTextPaint.linkColor = getThemedColor(Theme.key_chat_stickerReplyMessageText); oldAlpha = Theme.chat_replyTextPaint.getAlpha(); Theme.chat_replyTextPaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); if (needDrawReplyBackground) { if (replyBounce == null) { replyBounce = new ButtonBounce(this, 2.0f, 2.0f); } canvas.save(); final float s = replyBounce.getScale(0.0125f); int backWidth = Math.max(replyNameWidth, replyTextWidth); rect.set((int) replyStartX - dp(7), replyStartY - dp(3), (int) replyStartX - dp(4) + backWidth, replyStartY + dp(3) + replyHeight); canvas.scale(s, s, Utilities.clamp(replyBounceX, rect.right, rect.left), Utilities.clamp(replyBounceY, rect.bottom, rect.top)); applyServiceShaderMatrix(); oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); canvas.drawRoundRect(rect, dp(4), dp(4), getThemedPaint(Theme.key_paint_chatActionBackground)); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); if (hasGradientService()) { oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); canvas.drawRoundRect(rect, dp(4), dp(4), Theme.chat_actionBackgroundGradientDarkenPaint); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); } canvas.restore(); } } else { if (currentMessageObject.isOutOwner()) { if (currentMessageObject.isReplyToStory()) { Theme.chat_replyTextPaint.setColor(Theme.chat_replyNamePaint.getColor()); Theme.chat_replyTextPaint.linkColor = Theme.chat_replyTextPaint.getColor(); } else { float blendPressed = replyPressedT; int color = getThemedColor(Theme.key_chat_outReplyMessageText); if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.contentType != 1 && currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaPoll) || hasReplyQuote)) { color = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outReplyMediaMessageSelectedText : Theme.key_chat_outReplyMediaMessageText); blendPressed = .6f + (blendPressed * .4f); } Theme.chat_replyTextPaint.setColor(ColorUtils.blendARGB(color, Theme.adaptHue(color, Theme.chat_replyNamePaint.getColor()), blendPressed)); Theme.chat_replyTextPaint.linkColor = ColorUtils.blendARGB(color, Theme.adaptHue(color, Theme.chat_replyNamePaint.getColor()), Utilities.clamp(blendPressed * 2, 1f, 0f)); } } else { if (currentMessageObject.isReplyToStory()) { Theme.chat_replyTextPaint.setColor(Theme.chat_replyNamePaint.getColor()); Theme.chat_replyTextPaint.linkColor = Theme.chat_replyTextPaint.getColor(); } else { float blendPressed = replyPressedT; int color = getThemedColor(Theme.key_chat_inReplyMessageText); if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.contentType != 1 && currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) || hasReplyQuote)) { color = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inReplyMediaMessageSelectedText : Theme.key_chat_inReplyMediaMessageText); blendPressed = .6f + (blendPressed * .4f); } Theme.chat_replyTextPaint.setColor(ColorUtils.blendARGB(color, Theme.adaptHue(color, Theme.chat_replyNamePaint.getColor()), blendPressed)); Theme.chat_replyTextPaint.linkColor = ColorUtils.blendARGB(color, Theme.adaptHue(color, Theme.chat_replyNamePaint.getColor()), Utilities.clamp(blendPressed * 2, 1f, 0f)); } } } Theme.chat_quoteTextPaint.setColor(Theme.chat_replyTextPaint.getColor()); Theme.chat_quoteTextPaint.linkColor = Theme.chat_replyTextPaint.linkColor; int offset = dp(10); forwardNameX = replyStartX - replyTextOffset + offset + (needReplyImage ? offset + dp(25) : 0); if ((currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0) && !(enterTransitionInProgress && !currentMessageObject.isVoice())) { int restoreToCount = -1; float _alpha = (transitionParams.ignoreAlpha ? 1f : getAlpha()) * replyForwardAlpha; if (_alpha != 1f) { AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); restoreToCount = canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (0xFF * _alpha), Canvas.ALL_SAVE_FLAG); } float leftRad, rightRad, bottomRad = Math.min(4f, SharedConfig.bubbleRadius); if (currentMessageObject.shouldDrawWithoutBackground()) { rightRad = bottomRad = needDrawReplyBackground ? 6 : 4; replySelectorRect.set( (replyStartX - dp(7)), (replyStartY - dp(3)), (replyStartX + Math.max(replyNameWidth, replyTextWidth) - dp(4)), (replyStartY + replyHeight + dp(3)) ); if (forwardNameRight > 0) { replySelectorRect.right = Math.max(replySelectorRect.right, forwardNameRight); } } else { if (drawTopic || drawNameLayout || (drawForwardedName && forwardedNameLayout[0] != null)) { rightRad = bottomRad; } else if (!currentMessageObject.isOutOwner() || !drawPinnedTop) { rightRad = SharedConfig.bubbleRadius * .6f; } else { rightRad = SharedConfig.bubbleRadius / 3f; } float right; if (currentMessagesGroup == null || currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0) { right = getBackgroundDrawableRight() + transitionParams.deltaRight; } else { int end, dWidth; if (AndroidUtilities.isTablet()) { dWidth = AndroidUtilities.getMinTabletSide(); } else { dWidth = getParentWidth(); } int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } if (!mediaBackground && currentMessageObject.isOutOwner()) { end = backgroundDrawableLeft + firstLineWidth - dp(6); } else { end = backgroundDrawableLeft + firstLineWidth; } end -= getExtraTextX() + dp(8) + lerp(dp(isAvatarVisible ? 48 : 0), dp(ChatActivity.SIDE_MENU_WIDTH), sideMenuAlpha); right = end; } right -= dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) + getExtraTextX(); replySelectorRect.set( (backgroundDrawableLeft + transitionParams.deltaLeft + dp(10 + (!currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) + getExtraTextX()), (replyStartY - dp((!mediaBackground && drawPinnedTop && !drawNameLayout ? 2 : 0)) - (drawForwardedName && forwardedNameLayout[0] != null && !drawNameLayout ? 2 : 0)), right, (replyStartY + replyHeight + dp(4)) ); } if (needDrawReplyBackground) { if (replyBounce == null) { replyBounce = new ButtonBounce(this, 2.0f, 2.0f); } if (restoreToCount == -1) { restoreToCount = canvas.getSaveCount(); } canvas.save(); final float s = replyBounce.getScale(0.0125f); canvas.scale(s, s, Utilities.clamp(replyBounceX, replySelectorRect.right, replySelectorRect.left), Utilities.clamp(replyBounceY, replySelectorRect.bottom, replySelectorRect.top)); } // draw reply background leftRad = bottomRad; // line redesign replyLine.setLoading(loading); replyLine.drawBackground(canvas, replySelectorRect, leftRad, rightRad, bottomRad, alpha, isReplyQuote, currentMessageObject.shouldDrawWithoutBackground()); if (replySelector == null) { replySelector = Theme.createRadSelectorDrawable(replySelectorColor = rippleColor, 0, 0); replySelector.setCallback(this); } replySelector.setBounds((int) replySelectorRect.left, (int) replySelectorRect.top, (int) replySelectorRect.right, (int) replySelectorRect.bottom); if (leftRad != replySelectorRadLeft || rightRad != replySelectorRadRight) { Theme.setMaskDrawableRad(replySelector, replySelectorRadLeft = leftRad, replySelectorRadRight = rightRad, bottomRad, bottomRad); } if (rippleColor != replySelectorColor) { Theme.setSelectorDrawableColor(replySelector, replySelectorColor = rippleColor, true); } replySelector.draw(canvas); if (replyRoundRectPath == null) { replyRoundRectPath = new Path(); } else { replyRoundRectPath.rewind(); } replyLine.drawLine(canvas, replySelectorRect); replyLine.drawLoadingBackground(canvas, replySelectorRect, leftRad, rightRad, bottomRad, alpha); float replyImageSz = 0; if (needReplyImage) { replyImageReceiver.setAlpha(replyForwardAlpha); replyImageSz = Math.min(replySelectorRect.height() - dp(10), dp(isReplyQuote ? 3 : 7) + Theme.chat_replyNamePaint.getTextSize() + Theme.chat_replyTextPaint.getTextSize()); replyImageReceiver.setImageCoords(replySelectorRect.left + dp(8), replySelectorRect.top + dp((isReplyQuote && replyTextLayout != null && replyTextLayout.getLineCount() <= 1 ? 2 : 0) + 5), replyImageSz, replyImageSz); replyImageReceiver.draw(canvas); if (currentMessageObject != null && currentMessageObject.hasValidReplyMessageObject() && currentMessageObject.replyMessageObject.hasMediaSpoilers()) { int[] rad = replyImageReceiver.getRoundRadius(); mediaSpoilerRadii[0] = mediaSpoilerRadii[1] = rad[0]; mediaSpoilerRadii[2] = mediaSpoilerRadii[3] = rad[1]; mediaSpoilerRadii[4] = mediaSpoilerRadii[5] = rad[2]; mediaSpoilerRadii[6] = mediaSpoilerRadii[7] = rad[3]; mediaSpoilerPath.rewind(); AndroidUtilities.rectTmp.set(replyImageReceiver.getImageX(), replyImageReceiver.getImageY(), replyImageReceiver.getImageX2(), replyImageReceiver.getImageY2()); mediaSpoilerPath.addRoundRect(AndroidUtilities.rectTmp, mediaSpoilerRadii, Path.Direction.CW); canvas.save(); canvas.clipPath(mediaSpoilerPath); int sColor = Color.WHITE; if (mediaSpoilerEffect == null) { mediaSpoilerEffect = new SpoilerEffect(); } mediaSpoilerEffect.setColor(ColorUtils.setAlphaComponent(sColor, (int) (Color.alpha(sColor) * 0.325f * replyImageReceiver.getAlpha()))); mediaSpoilerEffect.setBounds((int) replyImageReceiver.getImageX(), (int) replyImageReceiver.getImageY(), (int) replyImageReceiver.getImageX2(), (int) replyImageReceiver.getImageY2()); mediaSpoilerEffect.draw(canvas); canvas.restore(); invalidate(); } } final float offsetX = currentMessageObject != null && currentMessageObject.shouldDrawWithoutBackground() ? -dp(6) : -dp(1); final float offsetY = currentMessageObject != null && currentMessageObject.shouldDrawWithoutBackground() ? dp(1) : dp(3); final boolean showQuote = isReplyQuote && currentMessageObject != null && currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.reply_to.quote; if (isReplyQuote && showQuote && replyQuoteDrawable != null) { if (replyLine.getColor() != replyQuoteDrawableColor) { replyQuoteDrawable.setColorFilter(new PorterDuffColorFilter(replyQuoteDrawableColor = replyLine.getColor(), PorterDuff.Mode.SRC_IN)); } replyQuoteDrawable.setBounds( (int) (replySelectorRect.right - dp(2 + (!drawPinnedTop ? 1 : 0)) - replyQuoteDrawable.getIntrinsicWidth()), (int) (replySelectorRect.top + dp(2 + (!drawPinnedTop ? 1 : 0))), (int) (replySelectorRect.right - dp(2 + (!drawPinnedTop ? 1 : 0))), (int) (replySelectorRect.top + dp(2 + (!drawPinnedTop ? 1 : 0)) + replyQuoteDrawable.getIntrinsicHeight()) ); replyQuoteDrawable.draw(canvas); } if (replyNameLayout != null) { canvas.save(); canvas.translate(replyStartX + offsetX - replyNameOffset + offset + (needReplyImage ? replyImageSz + dp(3) : 0), replyStartY + offsetY); replyNameLayout.draw(canvas); canvas.restore(); } int spoilersColor; if (currentMessageObject != null && currentMessageObject.isOutOwner() && !ChatObject.isChannelAndNotMegaGroup(currentMessageObject.getChatId(), currentAccount)) { spoilersColor = getThemedColor(Theme.key_chat_outTimeText); } else { spoilersColor = Theme.chat_replyTextPaint.getColor(); } if (transitionParams.animateReplyTextLayout != null && transitionParams.animateChangeProgress < 1) { canvas.save(); canvas.clipRect(replySelectorRect); canvas.save(); float left = replyStartX + offset + offsetX; if (isReplyQuote && needReplyImage) { left -= dp(2); } if (needReplyImage && (!isReplyQuote || replyTextRTL)) { left += replyImageSz + dp(3); } if (replyTextRTL && transitionParams.animateReplyTextOffset > 0) { left = replySelectorRect.right - dp(8) - transitionParams.animateReplyTextLayout.getWidth(); } canvas.translate(left, replyStartY + offsetY - dp(1) + Theme.chat_replyNamePaint.getTextSize() + dp(5)); final TextPaint paint = transitionParams.animateReplyTextLayout.getPaint(); int wasAlpha2 = paint.getAlpha(); paint.setAlpha((int) (wasAlpha2 * (1f - transitionParams.animateChangeProgress))); SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -dp(2), spoilersPatchedReplyTextLayout, 0, transitionParams.animateReplyTextLayout, replySpoilers, canvas, false); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, transitionParams.animateReplyTextLayout, transitionParams.animateOutAnimateEmojiReply, 0, replySpoilers, 0, 0, 0, alpha, getAdaptiveEmojiColorFilter(2, paint.getColor())); paint.setAlpha(wasAlpha2); canvas.restore(); } if (replyTextLayout != null) { canvas.save(); float left = replyStartX + offset + offsetX; float top = replyStartY + offsetY - dp(1) + Theme.chat_replyNamePaint.getTextSize() + dp(5); if (isReplyQuote && needReplyImage) { left -= dp(2); } if (needReplyImage && (!isReplyQuote || replyTextRTL)) { left += replyImageSz + dp(3); } if (isReplyTaskOrPollOption && replyTaskCheckbox != null) { final int sz = 12; replyTaskCheckbox.setBounds((int) left, (int) top + dp(2), dp(sz), dp(sz)); Theme.chat_instantViewRectPaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outMenu : Theme.key_chat_inMenu)); canvas.drawCircle(left + dp(sz / 2), top + dp(2 + sz / 2), dp(sz / 2 - 1), Theme.chat_instantViewRectPaint); replyTaskCheckbox.setColor(-1, currentMessageObject.isOutOwner() ? Theme.key_chat_outAudioSeekbarFill : Theme.key_chat_inAudioSeekbarFill, Theme.key_checkboxCheck); replyTaskCheckbox.draw(canvas); } if (isReplyTaskOrPollOption) { left += dp(16); } if (replyTextRTL && replyTextOffset > 0) { left = replySelectorRect.right - dp(8) - replyTextLayout.getWidth(); } canvas.translate(left, top); final TextPaint paint = replyTextLayout.getPaint(); int wasAlpha2 = paint.getAlpha(); paint.setAlpha((int) (wasAlpha2 * (transitionParams.animateReplyTextLayout != null ? transitionParams.animateChangeProgress : 1))); SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -dp(2), spoilersPatchedReplyTextLayout, 0, replyTextLayout, replySpoilers, canvas, false); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, replyTextLayout, animatedEmojiReplyStack, 0, replySpoilers, 0, 0, 0, alpha, getAdaptiveEmojiColorFilter(2, paint.getColor())); paint.setAlpha(wasAlpha2); canvas.restore(); } if (transitionParams.animateReplyTextLayout != null && transitionParams.animateChangeProgress < 1) { canvas.restore(); } if (restoreToCount >= 0) { canvas.restoreToCount(restoreToCount); } } } if (summaryTitle != null && summarySubtitle != null) { final float summaryAlpha = transitionParams.animateSummaryReply ? (drawSummaryReply ? transitionParams.animateChangeProgress : 1.0f - transitionParams.animateChangeProgress) : (drawSummaryReply ? 1.0f : 0.0f); if (summaryAlpha > 0) { final float height = dp(4) + summaryTitle.getHeight() + summarySubtitle.getHeight(); float right; if (currentMessagesGroup == null || currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0) { right = getBackgroundDrawableRight() + transitionParams.deltaRight; } else { int end, dWidth; if (AndroidUtilities.isTablet()) { dWidth = AndroidUtilities.getMinTabletSide(); } else { dWidth = getParentWidth(); } int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } if (!mediaBackground && currentMessageObject.isOutOwner()) { end = backgroundDrawableLeft + firstLineWidth - dp(6); } else { end = backgroundDrawableLeft + firstLineWidth; } end -= getExtraTextX() + dp(8) + lerp(dp(isAvatarVisible ? 48 : 0), dp(ChatActivity.SIDE_MENU_WIDTH), sideMenuAlpha); right = end; } right -= dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) + getExtraTextX(); summarySelectorRect.set( (backgroundDrawableLeft + transitionParams.deltaLeft + dp(10 + (!currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) + getExtraTextX()), (summaryStartY - dp((!mediaBackground && drawPinnedTop && !drawNameLayout ? 2 : 0)) - (drawForwardedName && forwardedNameLayout[0] != null && !drawNameLayout ? 2 : 0)), right, (summaryStartY + height) ); if (summaryBounce == null) { summaryBounce = new ButtonBounce(this, 2.0f, 2.0f); } final float s = summaryBounce.getScale(0.025f) * lerp(0.8f, 1.0f, summaryAlpha); canvas.save(); canvas.scale(s, s, summarySelectorRect.centerX(), summarySelectorRect.centerY()); if (summaryLine == null) { summaryLine = new ReplyMessageLine(this); } final int textColor = summaryLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_REPLY); final int rippleColor = Theme.multAlpha(textColor, 0.15f); final float rad = Math.min(4f, SharedConfig.bubbleRadius); summaryLine.drawBackground(canvas, summarySelectorRect, rad, rad, rad, alpha * summaryAlpha, isReplyQuote, currentMessageObject.shouldDrawWithoutBackground()); if (summaryReplySelector == null) { summaryReplySelector = Theme.createRadSelectorDrawable(replySelectorColor = rippleColor, (int) rad, (int) rad); summaryReplySelector.setCallback(this); } summaryReplySelector.setBounds((int) summarySelectorRect.left, (int) summarySelectorRect.top, (int) summarySelectorRect.right, (int) summarySelectorRect.bottom); if (rippleColor != summarySelectorColor) { Theme.setSelectorDrawableColor(summaryReplySelector, summarySelectorColor = rippleColor, true); } summaryReplySelector.setAlpha((int) (0xFF * alpha * summaryAlpha)); summaryReplySelector.draw(canvas); summaryLine.drawLine(canvas, summarySelectorRect, alpha * summaryAlpha); summaryTitle.draw(canvas, summaryStartX + dp(10), summaryStartY + dp(2), textColor, summaryAlpha); if (summarySubtitle != null) { summarySubtitle.draw(canvas, summaryStartX + dp(10), summaryStartY + summaryTitle.getHeight(), textColor, summaryAlpha); } canvas.restore(); } } if (restore != Integer.MIN_VALUE) { canvas.restoreToCount(restore); } } public boolean hasCaptionLayout() { return captionLayout != null; } public boolean hasCommentLayout() { return drawCommentButton; } public MessageObject.TextLayoutBlocks getCaptionLayout() { return captionLayout; } public MessageObject.TextLayoutBlocks getExplanationLayout() { return explanationLayout; } public float getExplanationX() { return lastDrawExplanationX; } public float getExplanationY() { return lastDrawExplanationY; } public void setDrawSelectionBackground(boolean value) { if (drawSelectionBackground != value) { drawSelectionBackground = value; invalidate(); } } public boolean isDrawingSelectionBackground() { return drawSelectionBackground || isHighlightedAnimated || isHighlighted; } public float getHighlightAlpha() { return getHighlightAlpha(false); } public float getHighlightAlpha(boolean quote) { float t = 1.0f; if (!drawSelectionBackground && isHighlightedAnimated) { t *= highlightProgress >= 300 ? 1.0f : highlightProgress / 300.0f; } if (!quote && quoteHighlight != null) { t *= (1f - quoteHighlight.getT()); } return t; } public void setCheckBoxVisible(boolean visible, boolean animated) { if (animated && currentMessageObject != null && currentMessageObject.deletedByThanos) { return; } if (visible) { quoteHighlight = null; if (checkBox == null) { checkBox = new CheckBoxBase(this, 21, resourcesProvider); if (attachedToWindow) { checkBox.onAttachedToWindow(); } } else { checkBox.setResourcesProvider(resourcesProvider); } } if (visible && ((currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) || (groupedMessagesToSet != null && groupedMessagesToSet.messages.size() > 1))) { if (mediaCheckBox == null) { mediaCheckBox = new CheckBoxBase(this, 21, resourcesProvider); mediaCheckBox.setUseDefaultCheck(true); if (attachedToWindow) { mediaCheckBox.onAttachedToWindow(); } } else { mediaCheckBox.setResourcesProvider(resourcesProvider); } } if (checkBoxVisible == visible) { if (animated != checkBoxAnimationInProgress && !animated) { checkBoxAnimationProgress = visible ? 1.0f : 0.0f; invalidate(); } return; } checkBoxAnimationInProgress = animated; checkBoxVisible = visible; if (animated) { lastCheckBoxAnimationTime = SystemClock.elapsedRealtime(); } else { checkBoxAnimationProgress = visible ? 1.0f : 0.0f; } invalidate(); } public boolean isCheckBoxVisible() { return checkBoxVisible || checkBoxAnimationInProgress; } public void setChecked(boolean checked, boolean allChecked, boolean animated) { if (!checked && animated && currentMessageObject != null && currentMessageObject.deletedByThanos) { return; } if (checkBox != null) { checkBox.setChecked(allChecked, animated); } if (mediaCheckBox != null) { mediaCheckBox.setChecked(checked, animated); } backgroundDrawable.setSelected(allChecked, animated); } public void setLastTouchCoords(float x, float y) { lastTouchX = x; lastTouchY = y; backgroundDrawable.setTouchCoords(lastTouchX + getTranslationX(), lastTouchY); } public MessageBackgroundDrawable getBackgroundDrawable() { return backgroundDrawable; } public MessageDrawable getCurrentBackgroundDrawable(boolean update) { if (update) { boolean forceMediaByGroup = currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0 && currentMessagesGroup.isDocuments && !drawPinnedBottom; if (currentMessageObject.isOutOwner()) { if (!mediaBackground && !drawPinnedBottom && !forceMediaByGroup) { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgOut); } else { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgOutMedia); } } else { if (!mediaBackground && !drawPinnedBottom && !forceMediaByGroup) { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgIn); } else { currentBackgroundDrawable = (MessageDrawable) getThemedDrawable(Theme.key_drawable_msgInMedia); } } } currentBackgroundDrawable.getBackgroundDrawable(); return currentBackgroundDrawable; } private boolean shouldDrawCaptionLayout() { return currentMessageObject != null && !currentMessageObject.preview && !currentMessageObject.isSponsored() && (currentPosition == null || (currentMessagesGroup != null && currentMessagesGroup.isDocuments && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0)) && !transitionParams.animateBackgroundBoundsInner && !(enterTransitionInProgress && currentMessageObject.isVoice()); } public void drawCaptionLayout(Canvas canvas, boolean selectionOnly, float alpha) { if (animatedEmojiStack != null && !(canvas instanceof SizeNotifierFrameLayout.SimplerCanvas) && (captionLayout != null || transitionParams.animateOutCaptionLayout != null)) { animatedEmojiStack.clearPositions(); } if (transitionParams.animateReplaceCaptionLayout && transitionParams.animateChangeProgress != 1f) { drawCaptionLayout(canvas, transitionParams.animateOutCaptionLayout, false, selectionOnly, alpha * (1f - transitionParams.animateChangeProgress)); drawCaptionLayout(canvas, captionLayout, true, selectionOnly, alpha * transitionParams.animateChangeProgress); } else { drawCaptionLayout(canvas, captionLayout, true, selectionOnly, alpha); } if (!selectionOnly) { drawAnimatedEmojiCaption(canvas, alpha); } if (currentMessageObject != null && currentMessageObject.messageOwner != null && currentMessageObject.isVoiceTranscriptionOpen() && !currentMessageObject.messageOwner.voiceTranscriptionFinal && TranscribeButton.isTranscribing(currentMessageObject)) { invalidate(); } } public void drawCommentLayout(Canvas canvas, float alpha) { int x; if (mediaBackground) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { x = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } int endX = x - getExtraTextX(); if (currentMessagesGroup != null && !currentMessageObject.isMusic() && !currentMessageObject.isDocument()) { int dWidth = getGroupPhotosWidth(); if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { endX += Math.ceil(currentPosition.pw / 1000.0f * dWidth); } else { int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } endX += firstLineWidth - dp(9); } if (currentChat != null && currentChat.signature_profiles) { endX -= dp(48); } } else { endX += backgroundWidth - (mediaBackground ? 0 : dp(9)); } if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0 && !currentMessagesGroup.hasSibling) { endX += dp(14); } if (currentBackgroundDrawable != null && drawCommentButton && timeLayout != null) { float y = layoutHeight + transitionParams.deltaBottom - dp(18) - timeLayout.getHeight(); if (currentMessagesGroup != null) { y += currentMessagesGroup.transitionParams.offsetBottom; if (currentMessagesGroup.transitionParams.backgroundChangeBounds) { y -= getTranslationY(); } } int h; int h2; if (pinnedBottom) { h = 2; h2 = 3; } else if (pinnedTop) { h = 4; h2 = 1; } else { h = 3; h2 = 0; } int buttonX = getCurrentBackgroundLeft() + dp(currentMessageObject.isOutOwner() || mediaBackground || drawPinnedBottom ? 2 : 8); float buttonY = layoutHeight - dp(45.1f - h2); if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0 && !currentMessagesGroup.hasSibling) { buttonX -= dp(10); } commentButtonRect.set( buttonX - dp((currentMessageObject == null || !currentMessageObject.isOutOwner()) && !drawPinnedBottom && currentPosition == null && (currentMessageObject == null || currentMessageObject.type != MessageObject.TYPE_POLL || pollInstantViewTouchesBottom) ? 6 : 0), (int) buttonY, endX - dp(14), layoutHeight - dp(h) + 1 ); if (selectorDrawable[1] != null && selectorDrawableMaskType[1] == 2) { int count = canvas.getSaveCount(); selectorDrawable[1].setBounds(commentButtonRect); selectorDrawable[1].draw(canvas); canvas.restoreToCount(count); } if (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && currentPosition.minX == 0 && currentPosition.maxX == 0) { boolean drawProgress = delegate != null && delegate.shouldDrawThreadProgress(this, false); boolean drawProgressDelayed = delegate != null && delegate.shouldDrawThreadProgress(this, true); if (drawProgress) { if (commentLoading == null) { commentLoading = new LoadingDrawable(); commentLoading.setAppearByGradient(true); } else if (commentLoading.isDisappeared() || commentLoading.isDisappearing()) { commentLoading.reset(); commentLoading.resetDisappear(); } } else if (commentLoading != null && !commentLoading.isDisappearing() && !commentLoading.isDisappeared()) { commentLoading.disappear(); } if (commentLoading != null && !commentLoading.isDisappeared()) { int color = getThemedColor(Theme.key_chat_inInstant); commentLoading.setColors(Theme.multAlpha(color, .05f), Theme.multAlpha(color, .15f)); commentLoading.setBounds(commentButtonRect); canvas.save(); if (selectorMaskDrawable[1] != null) { selectorMaskDrawable[1].setBounds(commentButtonRect); selectorMaskDrawable[1].updatePath(); canvas.clipPath(selectorMaskDrawable[1].path); } commentLoading.draw(canvas); canvas.restore(); invalidate(); } if (getAlpha() != 1f) { AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (0xFF * getAlpha()), Canvas.ALL_SAVE_FLAG); } Theme.chat_instantViewPaint.setColor(getThemedColor(Theme.key_chat_inPreviewInstantText)); boolean drawnAvatars = false; int avatarsOffset = 2; if (commentAvatarImages != null) { int toAdd = dp(17); int ax = x + getExtraTextX(); for (int a = commentAvatarImages.length - 1; a >= 0; a--) { if (!commentAvatarImagesVisible[a] || !commentAvatarImages[a].hasImageSet()) { continue; } commentAvatarImages[a].setImageX(ax + toAdd * a); commentAvatarImages[a].setImageY(y - dp(4) + (pinnedBottom ? dp(2) : 0)); if (a != commentAvatarImages.length - 1) { canvas.drawCircle(commentAvatarImages[a].getCenterX(), commentAvatarImages[a].getCenterY(), dp(13), currentBackgroundDrawable.getPaint()); } commentAvatarImages[a].draw(canvas); drawnAvatars = true; if (a != 0) { avatarsOffset += 17; } } } if (getAlpha() != 1f) { canvas.restore(); } if (!mediaBackground || captionLayout != null || (!reactionsLayoutInBubble.isEmpty && !reactionsLayoutInBubble.isSmall)) { if (isDrawSelectionBackground()) { Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outVoiceSeekbarSelected : Theme.key_chat_inVoiceSeekbarSelected)); } else { Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outVoiceSeekbar : Theme.key_chat_inVoiceSeekbar)); } float ly = layoutHeight - dp(45.1f - h2); ly += transitionParams.deltaBottom; if (currentMessagesGroup != null) { ly += currentMessagesGroup.transitionParams.offsetBottom; if (currentMessagesGroup.transitionParams.backgroundChangeBounds) { ly -= getTranslationY(); } } else { int backgroundWidth = (int) (this.backgroundWidth - transitionParams.deltaLeft + transitionParams.deltaRight); endX = x + backgroundWidth - dp(12); } Theme.chat_replyLinePaint.setAlpha((int) (Theme.chat_replyLinePaint.getAlpha() * ChatMessageCell.this.getAlpha())); canvas.drawLine(x, ly, endX - dp(14), ly, Theme.chat_replyLinePaint); } if (commentLayout != null && drawSideButton != 3) { Theme.chat_commentTextPaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewInstantText : Theme.key_chat_inPreviewInstantText)); commentX = x + dp(33 + avatarsOffset); if (drawCommentNumber) { commentX += commentNumberWidth + dp(4); } int prevAlpha = Theme.chat_commentTextPaint.getAlpha(); if (transitionParams.animateComments) { if (transitionParams.animateCommentsLayout != null) { canvas.save(); Theme.chat_commentTextPaint.setAlpha((int) (prevAlpha * (1.0 - transitionParams.animateChangeProgress))); float cx = transitionParams.animateCommentX + (commentX - transitionParams.animateCommentX) * transitionParams.animateChangeProgress; canvas.translate(cx, y - dp(0.1f) + (pinnedBottom ? dp(2) : 0)); transitionParams.animateCommentsLayout.draw(canvas); canvas.restore(); } } canvas.save(); canvas.translate(x + dp(33 + avatarsOffset), y - dp(0.1f) + (pinnedBottom ? dp(2) : 0)); if (!currentMessageObject.isSent()) { Theme.chat_commentTextPaint.setAlpha(127); Theme.chat_commentArrowDrawable.setAlpha(127); Theme.chat_commentDrawable.setAlpha(127); } else { Theme.chat_commentArrowDrawable.setAlpha(255); Theme.chat_commentDrawable.setAlpha(255); } if (drawCommentNumber || transitionParams.animateComments && transitionParams.animateDrawCommentNumber) { if (drawCommentNumber && transitionParams.animateComments) { if (transitionParams.animateDrawCommentNumber) { Theme.chat_commentTextPaint.setAlpha(prevAlpha); } else { Theme.chat_commentTextPaint.setAlpha((int) (prevAlpha * transitionParams.animateChangeProgress)); } } Theme.chat_commentTextPaint.setAlpha((int) (Theme.chat_commentTextPaint.getAlpha() * ChatMessageCell.this.getAlpha())); commentNumberLayout.draw(canvas); if (drawCommentNumber) { canvas.translate(commentNumberWidth + dp(4), 0); } } if (transitionParams.animateComments && transitionParams.animateCommentsLayout != null) { Theme.chat_commentTextPaint.setAlpha((int) (prevAlpha * transitionParams.animateChangeProgress)); } else { Theme.chat_commentTextPaint.setAlpha((int) (prevAlpha * alpha)); } Theme.chat_commentTextPaint.setAlpha((int) (Theme.chat_commentTextPaint.getAlpha() * ChatMessageCell.this.getAlpha())); commentLayout.draw(canvas); canvas.restore(); commentUnreadX = x + commentWidth + dp(33 + avatarsOffset) + dp(9); if (drawCommentNumber) { commentUnreadX += commentNumberWidth + dp(4); } TLRPC.MessageReplies replies = null; if (currentMessagesGroup != null && !currentMessagesGroup.messages.isEmpty()) { MessageObject messageObject = currentMessagesGroup.messages.get(0); if (messageObject.hasReplies()) { replies = messageObject.messageOwner.replies; } } else { if (currentMessageObject.hasReplies()) { replies = currentMessageObject.messageOwner.replies; } } if (commentDrawUnread = (replies != null && replies.read_max_id != 0 && replies.read_max_id < replies.max_id)) { int color = getThemedColor(Theme.key_chat_inInstant); Theme.chat_docBackPaint.setColor(color); int unreadX; if (transitionParams.animateComments) { if (!transitionParams.animateCommentDrawUnread) { Theme.chat_docBackPaint.setAlpha((int) (Color.alpha(color) * transitionParams.animateChangeProgress)); } unreadX = (int) (transitionParams.animateCommentUnreadX + (commentUnreadX - transitionParams.animateCommentUnreadX) * transitionParams.animateChangeProgress); } else { unreadX = commentUnreadX; } canvas.drawCircle(unreadX, y + dp(8) + (pinnedBottom ? dp(2) : 0), dp(2.5f), Theme.chat_docBackPaint); } } if (!drawnAvatars) { setDrawableBounds(Theme.chat_commentDrawable, x, y - dp(4) + (pinnedBottom ? dp(2) : 0)); if (alpha != 1f) { Theme.chat_commentDrawable.setAlpha((int) (255 * alpha)); Theme.chat_commentDrawable.draw(canvas); Theme.chat_commentDrawable.setAlpha(255); } else { Theme.chat_commentDrawable.draw(canvas); } } commentArrowX = endX - dp(44); int commentX; if (transitionParams.animateComments) { commentX = (int) (transitionParams.animateCommentArrowX + (commentArrowX - transitionParams.animateCommentArrowX) * transitionParams.animateChangeProgress); } else { commentX = commentArrowX; } float commentY = y - dp(4) + (pinnedBottom ? dp(2) : 0); long newTime = SystemClock.elapsedRealtime(); long dt = (newTime - commentProgressLastUpadteTime); commentProgressLastUpadteTime = newTime; if (dt > 17) { dt = 17; } if (drawProgressDelayed) { if (commentProgressAlpha < 1.0f) { commentProgressAlpha += dt / 180.0f; if (commentProgressAlpha > 1.0f) { commentProgressAlpha = 1.0f; } } } else { if (commentProgressAlpha > 0.0f) { commentProgressAlpha -= dt / 180.0f; if (commentProgressAlpha < 0.0f) { commentProgressAlpha = 0.0f; } } } if ((drawProgressDelayed || commentProgressAlpha > 0.0f) && commentProgress != null) { commentProgress.setColor(getThemedColor(Theme.key_chat_inInstant)); commentProgress.setAlpha(commentProgressAlpha); commentProgress.draw(canvas, commentX + dp(11), commentY + dp(12), commentProgressAlpha); invalidate(); } if (!drawProgressDelayed || commentProgressAlpha < 1.0f) { int aw = Theme.chat_commentArrowDrawable.getIntrinsicWidth(); int ah = Theme.chat_commentArrowDrawable.getIntrinsicHeight(); float acx = commentX + aw / 2; float acy = commentY + ah / 2; Theme.chat_commentArrowDrawable.setBounds((int) (acx - aw / 2 * (1.0f - commentProgressAlpha)), (int) (acy - ah / 2 * (1.0f - commentProgressAlpha)), (int) (acx + aw / 2 * (1.0f - commentProgressAlpha)), (int) (acy + ah / 2 * (1.0f - commentProgressAlpha))); Theme.chat_commentArrowDrawable.setAlpha((int) (255 * (1.0f - commentProgressAlpha) * alpha)); Theme.chat_commentArrowDrawable.draw(canvas); } } } } public boolean hasReactionsToDraw() { return currentMessageObject != null && currentMessageObject.shouldDrawReactions() && (currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) && !reactionsLayoutInBubble.isSmall; } public void drawReactionsLayout(Canvas canvas, float alpha, Integer only) { if (isRoundVideo) { reactionsLayoutInBubble.drawServiceShaderBackground = 1f - getVideoTranscriptionProgress(); } if (reactionsVisible && hasReactionsToDraw()) { if (reactionsLayoutInBubble.drawServiceShaderBackground > 0) { applyServiceShaderMatrix(); } boolean restore = false; if (alpha * getAlpha() != 1f) { AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (0xFF * alpha * getAlpha()), Canvas.ALL_SAVE_FLAG); restore = true; } if (reactionsLayoutInBubble.drawServiceShaderBackground > 0 || !transitionParams.animateBackgroundBoundsInner || currentPosition != null || isRoundVideo) { reactionsLayoutInBubble.setScrimProgress(0, false); reactionsLayoutInBubble.draw(canvas, (transitionParams.animateChange ? transitionParams.animateChangeProgress : 1f), only); } else { canvas.save(); canvas.clipRect(0, 0, getMeasuredWidth(), getBackgroundDrawableBottom() + transitionParams.deltaBottom); reactionsLayoutInBubble.setScrimProgress(0, false); reactionsLayoutInBubble.draw(canvas, (transitionParams.animateChange ? transitionParams.animateChangeProgress : 1f), only); canvas.restore(); } if (restore) { canvas.restore(); } } } private void drawRichLayoutOverlay(Canvas canvas, RichMessageLayout layout, float alpha, ColorFilter colorFilter) { if (layout == null || alpha <= 0f || !layout.hasOverlay()) { return; } final int saveCount; if (alpha < 1f) { saveCount = canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); } else { saveCount = canvas.save(); } canvas.translate(textX, textY); layout.drawOverlay(canvas, colorFilter); canvas.restoreToCount(saveCount); } public boolean drawReactionsLayoutOverlay(Canvas canvas, float alpha) { if (isRoundVideo) { reactionsLayoutInBubble.drawServiceShaderBackground = 1f - getVideoTranscriptionProgress(); } if (!reactionsVisible) { return false; } if (hasReactionsToDraw()) { if (reactionsLayoutInBubble.drawServiceShaderBackground > 0) { applyServiceShaderMatrix(); } boolean restore = false; if (alpha * getAlpha() != 1f) { AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (0xFF * alpha * getAlpha()), Canvas.ALL_SAVE_FLAG); restore = true; } final boolean needsInvalidate; if (reactionsLayoutInBubble.drawServiceShaderBackground > 0 || !transitionParams.animateBackgroundBoundsInner || currentPosition != null || isRoundVideo) { needsInvalidate = reactionsLayoutInBubble.drawOverlay(canvas, transitionParams.animateChange ? transitionParams.animateChangeProgress : 1f); } else { canvas.save(); canvas.clipRect(0, 0, getMeasuredWidth(), getBackgroundDrawableBottom() + transitionParams.deltaBottom); needsInvalidate = reactionsLayoutInBubble.drawOverlay(canvas, transitionParams.animateChange ? transitionParams.animateChangeProgress : 1f); canvas.restore(); } if (restore) { canvas.restore(); } return true; } return false; } private void drawCaptionLayout(Canvas canvas, MessageObject.TextLayoutBlocks captionLayout, boolean origin, boolean selectionOnly, float alpha) { int x; if (mediaBackground) { x = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { x = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } int endX = x - getExtraTextX(); if (currentMessagesGroup != null && !currentMessageObject.isMusic() && !currentMessageObject.isDocument()) { int dWidth = getGroupPhotosWidth(); if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { endX += Math.ceil(currentPosition.pw / 1000.0f * dWidth); } else { int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a); if (position.minY == 0) { firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth); } else { break; } } endX += firstLineWidth - dp(9); } } else { endX += backgroundWidth - (mediaBackground ? 0 : dp(9)); } if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0 && !currentMessagesGroup.hasSibling) { endX += dp(14); } drawCommentLayout(canvas, alpha); if (captionLayout == null || selectionOnly && links.isEmpty() || (currentMessageObject.deleted && !drawingToBitmap && currentPosition != null) || alpha == 0) { return; } setupTextColors(); canvas.save(); float renderingAlpha = alpha; if (currentMessagesGroup != null) { renderingAlpha = currentMessagesGroup.transitionParams.captionEnterProgress * alpha; } if (renderingAlpha == 0) { return; } float captionY = this.captionY; float captionX = this.captionX; if (transitionParams.animateBackgroundBoundsInner) { if (transitionParams.transformGroupToSingleMessage) { captionY -= getTranslationY(); captionX += transitionParams.deltaLeft; } else if (transitionParams.moveCaption) { captionX = this.captionX * transitionParams.animateChangeProgress + transitionParams.captionFromX * (1f - transitionParams.animateChangeProgress); captionY = this.captionY * transitionParams.animateChangeProgress + transitionParams.captionFromY * (1f - transitionParams.animateChangeProgress); } else if ((!currentMessageObject.isVoice() && !currentMessageObject.isRoundVideo()) || !TextUtils.isEmpty(currentMessageObject.caption)) { captionX += transitionParams.deltaLeft; } } if (isRoundVideo && transitionParams.animateDrawBackground) { captionY += (1f - getVideoTranscriptionProgress()) * AndroidUtilities.roundMessageSize; } int restore = Integer.MIN_VALUE; if (renderingAlpha != 1.0f) { rect.set(captionX, captionY, captionX + captionLayout.textWidth, captionY + captionLayout.textHeight(transitionParams)); restore = canvas.saveLayerAlpha(rect, (int) (255 * renderingAlpha), Canvas.ALL_SAVE_FLAG); } if (isRoundVideo && transitionParams.animateDrawBackground) { if (backgroundCacheParams != null) { Path path = backgroundCacheParams.getPath(); if (path != null && !path.isEmpty()) { canvas.translate(0, transitionYOffsetForDrawables); canvas.clipPath(path); canvas.translate(0, -transitionYOffsetForDrawables); } } } else if (transitionParams.animateBackgroundBoundsInner && currentBackgroundDrawable != null && currentMessagesGroup == null || transitionParams.animateMediaAbove && currentMessagesGroup == null) { int bottomoffset = (drawCommentButton && commentButtonRect != null ? commentButtonRect.height() : 0) + (reactionsLayoutInBubble != null && !reactionsLayoutInBubble.isSmall ? reactionsLayoutInBubble.height : 0); if (currentMessageObject.isOutOwner() && !mediaBackground && !pinnedBottom) { canvas.clipRect( getBackgroundDrawableLeft() + transitionParams.deltaLeft + dp(4), getBackgroundDrawableTop() + transitionParams.deltaTop + dp(4), getBackgroundDrawableRight() + transitionParams.deltaRight - dp(10), getBackgroundDrawableBottom() + transitionParams.deltaBottom - dp(4) - bottomoffset ); } else { canvas.clipRect( getBackgroundDrawableLeft() + transitionParams.deltaLeft + dp(4), getBackgroundDrawableTop() + transitionParams.deltaTop + dp(4), getBackgroundDrawableRight() + transitionParams.deltaRight - dp(4), getBackgroundDrawableBottom() + transitionParams.deltaBottom - dp(4) - bottomoffset ); } } canvas.save(); canvas.translate(captionX, captionY); // if (links.draw(canvas)) { // invalidate(); // } // drawProgressLoadingLink(canvas, -1); if (highlightPath != null) { float t = (System.currentTimeMillis() - highlightPathStart) / 850f; if (t > 1) { highlightPath = null; } else { int wasAlpha = Theme.chat_textSearchSelectionPaint.getAlpha(); Theme.chat_textSearchSelectionPaint.setAlpha((int) (wasAlpha * .8f * (4 * t * (1 - t)))); canvas.save(); float s = .4f + .6f * AndroidUtilities.overshootInterpolator.getInterpolation(Math.min(1, t * 4f)); canvas.scale(s, s, highlightPath.centerX, highlightPath.centerY); canvas.drawPath(highlightPath, Theme.chat_textSearchSelectionPaint); canvas.restore(); Theme.chat_textSearchSelectionPaint.setAlpha(wasAlpha); } invalidate(); } canvas.restore(); if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { Theme.chat_timePaint.setColor( ColorUtils.blendARGB( getThemedColor(Theme.key_chat_serviceText), getThemedColor(isDrawSelectionBackground() ? (currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeSelectedText : Theme.key_chat_inTimeSelectedText) : (currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeText : Theme.key_chat_inTimeText) ), getVideoTranscriptionProgress() ) ); } if (!selectionOnly) { if (transitionParams.animateMediaAbove && transitionParams.animateChangeProgress != 1f) { final float captionYTop, captionYBottom; if ( currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || currentMessageObject.type == MessageObject.TYPE_GIF || currentMessageObject.type == MessageObject.TYPE_STORY ) { float y, h; y = photoImage.getImageY(); h = photoImage.getImageHeight(); captionYBottom = y + h + dp(6); captionYTop = y + (captionLayout == null ? 0 : -captionLayout.textHeight(transitionParams)) - dp(4); } else if (hasOldCaptionPreview) { captionYBottom = totalHeight - dp(drawPinnedTop ? 9 : 10) - linkPreviewHeight - dp(17) - dp(drawCommentButton && drawSideButton != 3 ? (shouldDrawTimeOnMedia() ? 41.3f : 43) : 0) - captionHeight; captionYTop = dp(9); } else { captionYBottom = totalHeight - captionHeight - dp(drawPinnedTop ? 9 : 10) - dp(drawCommentButton && drawSideButton != 3 ? (shouldDrawTimeOnMedia() ? 41.3f : 43) : 0) - (!reactionsLayoutInBubble.isEmpty && !reactionsLayoutInBubble.isSmall ? reactionsLayoutInBubble.totalHeight : 0); captionYTop = dp(9); } drawMessageText(captionX, captionAbove ? captionYBottom : captionYTop, canvas, captionLayout.textLayoutBlocks, captionLayout.textXOffset, origin, alpha * (1f - transitionParams.animateChangeProgress), true, false, true); drawMessageText(captionX, captionAbove ? captionYTop : captionYBottom, canvas, captionLayout.textLayoutBlocks, captionLayout.textXOffset, origin, alpha * transitionParams.animateChangeProgress, true, false, true); } else { drawMessageText(captionX, captionY, canvas, captionLayout.textLayoutBlocks, captionLayout.textXOffset, origin, alpha, true, false, true); } } if (restore != Integer.MIN_VALUE) { canvas.restoreToCount(restore); } canvas.restore(); } public void drawProgressLoadingLink(Canvas canvas, int blockNum) { updateProgressLoadingLink(); if (progressLoadingLinkDrawables == null || progressLoadingLinkDrawables.isEmpty()) { return; } int color = getThemedColor(currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground); for (int i = 0; i < progressLoadingLinkDrawables.size(); ++i) { LoadingDrawableLocation location = progressLoadingLinkDrawables.get(i); if (location.blockNum == blockNum) { LoadingDrawable drawable = location.drawable; drawable.setColors( Theme.multAlpha(color, .85f), Theme.multAlpha(color, 2f), Theme.multAlpha(color, 3.5f), Theme.multAlpha(color, 6f) ); drawable.draw(canvas); invalidate(); if (drawable.isDisappeared()) { progressLoadingLinkDrawables.remove(i); i--; } } } } public void updateProgressLoadingLink() { if (delegate == null) { return; } if (!delegate.isProgressLoading(this, ChatActivity.PROGRESS_LINK)) { progressLoadingLink = null; if (progressLoadingLinkDrawables != null && !progressLoadingLinkDrawables.isEmpty()) { for (int i = 0; i < progressLoadingLinkDrawables.size(); ++i) { LoadingDrawableLocation location = progressLoadingLinkDrawables.get(i); if (!location.drawable.isDisappearing()) { location.drawable.disappear(); } } } return; } CharacterStyle link = delegate.getProgressLoadingLink(this); if (link == progressLoadingLink) { return; } progressLoadingLink = link; if (progressLoadingLinkCurrentDrawable != null) { progressLoadingLinkCurrentDrawable.disappear(); progressLoadingLinkCurrentDrawable = null; } progressLoadingLinkCurrentDrawable = new LoadingDrawable(); progressLoadingLinkCurrentDrawable.setAppearByGradient(true); LinkPath path = new LinkPath(true); progressLoadingLinkCurrentDrawable.usePath(path); progressLoadingLinkCurrentDrawable.setRadiiDp(5); LoadingDrawableLocation location = new LoadingDrawableLocation(); location.drawable = progressLoadingLinkCurrentDrawable; location.blockNum = -3; if (progressLoadingLinkDrawables == null) { progressLoadingLinkDrawables = new ArrayList<>(); } progressLoadingLinkDrawables.add(location); if (progressLoadingLink != null) { boolean b = findProgressLoadingLink(location, path, descriptionLayout, 0, -2) || (captionLayout != null && findProgressLoadingLink(location, path, captionLayout.textLayoutBlocks)) || (currentMessageObject != null && findProgressLoadingLink(location, path, currentMessageObject.textLayoutBlocks)); } } private boolean findProgressLoadingLink(LoadingDrawableLocation location, LinkPath path, ArrayList textLayoutBlocks) { if (textLayoutBlocks == null) { return false; } for (int i = 0; i < textLayoutBlocks.size(); ++i) { if (findProgressLoadingLink(location, path, textLayoutBlocks.get(i).textLayout, 0, i)) { return true; } } return false; } private boolean findProgressLoadingLink(LoadingDrawableLocation location, LinkPath path, Layout layout, float yOffset, int blockNum) { if (layout != null && layout.getText() instanceof Spanned) { Spanned spanned = (Spanned) layout.getText(); CharacterStyle[] spans = spanned.getSpans(0, spanned.length(), CharacterStyle.class); if (spans != null) { for (int j = 0; j < spans.length; ++j) { if (spans[j] == progressLoadingLink) { location.blockNum = blockNum; break; } } } if (location.blockNum == blockNum) { path.rewind(); int start = spanned.getSpanStart(progressLoadingLink); int end = spanned.getSpanEnd(progressLoadingLink); path.setUseCornerPathImplementation(true); path.setCurrentLayout(layout, start, yOffset); layout.getSelectionPath(start, end, path); path.closeRects(); progressLoadingLinkCurrentDrawable.updateBounds(); return true; } } return false; } public boolean needDrawTime() { return !forceNotDrawTime && (currentMessageObject == null || currentMessageObject.type != MessageObject.TYPE_JOINED_CHANNEL); } public boolean shouldDrawTimeOnMedia() { if (overideShouldDrawTimeOnMedia != 0) { return overideShouldDrawTimeOnMedia == 1; } return mediaBackground && (captionLayout == null || captionAbove) && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall || currentMessageObject != null && (currentMessageObject.isAnyKindOfSticker() || currentMessageObject.isRoundVideo())) || currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_PAID_MEDIA/* || isMedia && drawCommentButton && !isRepliesChat*/; } public void drawTime(Canvas canvas, float alpha, boolean fromParent) { if (!drawFromPinchToZoom && delegate != null && delegate.getPinchToZoomHelper() != null && delegate.getPinchToZoomHelper().isInOverlayModeFor(this) && shouldDrawTimeOnMedia()) { return; } if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { return; } for (int i = 0; i < 2; i++) { float currentAlpha = alpha; if (i == 0 && isDrawSelectionBackground() && currentSelectedBackgroundAlpha == 1f && !shouldDrawTimeOnMedia()) { continue; } else if (i == 1 && ((!isDrawSelectionBackground() && currentSelectedBackgroundAlpha == 0) || shouldDrawTimeOnMedia())) { break; } boolean drawSelectionBackground = i == 1; if (i == 1) { currentAlpha *= currentSelectedBackgroundAlpha; } else if (!shouldDrawTimeOnMedia()) { currentAlpha *= (1f - currentSelectedBackgroundAlpha); } if (transitionParams.animateShouldDrawTimeOnMedia && transitionParams.animateChangeProgress != 1f) { if (shouldDrawTimeOnMedia()) { overideShouldDrawTimeOnMedia = 1; drawTimeInternal(canvas, currentAlpha * transitionParams.animateChangeProgress, fromParent, this.timeX, timeLayout, timeWidth, drawSelectionBackground); overideShouldDrawTimeOnMedia = 2; drawTimeInternal(canvas, currentAlpha * (1f - transitionParams.animateChangeProgress), fromParent, transitionParams.animateFromTimeX, transitionParams.animateTimeLayout, transitionParams.animateTimeWidth, drawSelectionBackground); } else { overideShouldDrawTimeOnMedia = 2; drawTimeInternal(canvas, currentAlpha * transitionParams.animateChangeProgress, fromParent, this.timeX, timeLayout, timeWidth, drawSelectionBackground); overideShouldDrawTimeOnMedia = 1; drawTimeInternal(canvas, currentAlpha * (1f - transitionParams.animateChangeProgress), fromParent, transitionParams.animateFromTimeX, transitionParams.animateTimeLayout, transitionParams.animateTimeWidth, drawSelectionBackground); } overideShouldDrawTimeOnMedia = 0; } else { float timeX; float timeWidth; if (transitionParams.shouldAnimateTimeX) { timeX = lerp(transitionParams.animateFromTimeX, this.timeX, transitionParams.animateChangeProgress); timeWidth = lerp(transitionParams.animateTimeWidth, this.timeWidth, transitionParams.animateChangeProgress); } else { timeX = this.timeX + transitionParams.deltaRight; timeWidth = this.timeWidth; } drawTimeInternal(canvas, currentAlpha, fromParent, timeX, timeLayout, timeWidth, drawSelectionBackground); } } if (transitionParams.animateBackgroundBoundsInner && !(currentMessageObject != null && currentMessageObject.preview)) { drawOverlays(canvas); } if (effectDrawable != null) { if (effectDrawableBounce == null) { effectDrawableBounce = new ButtonBounce(this); } final float s = effectDrawableBounce.getScale(.2f); int x = (int) (getTimeX() - dp(effectId == 0 ? 0 : 14 + 4) + timeWidth * (currentMessageObject.sendPreview ? 1f - timeAlpha : 0f)); int y = (int) getTimeY(); if (currentMessageObject != null && !currentMessageObject.notime && pinnedBottom && !shouldDrawTimeOnMedia()) { y += dp(2); } if (shouldDrawTimeOnMedia() && currentMessageObject.sendPreview) { x -= dp(1); } if (currentMessageObject != null && (currentMessageObject.type == MessageObject.TYPE_ANIMATED_STICKER || currentMessageObject.isAnyKindOfSticker())) { x -= dp(6); } int sz = dp(14); int cx = x + sz / 2, cy = y + sz / 2; effectDrawable.setBounds((int) (cx - sz / 2 * s), (int) (cy - sz / 2 * s), (int) (cx + sz / 2 * s), (int) (cy + sz / 2 * s)); if (!currentMessageObject.sendPreview) { effectDrawable.setAlpha((int) (0xFF * timeAlpha)); } effectDrawable.draw(canvas); } } private void drawTimeInternal(Canvas canvas, float alpha, boolean fromParent, float timeX, StaticLayout timeLayout, float timeWidth, boolean drawSelectionBackground) { if ((!drawTime || groupPhotoInvisible) && shouldDrawTimeOnMedia() || timeLayout == null || (currentMessageObject.deleted && currentPosition != null) || currentMessageObject.type == MessageObject.TYPE_PHONE_CALL) { return; } if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { Theme.chat_timePaint.setColor( ColorUtils.blendARGB( getThemedColor(Theme.key_chat_serviceText), getThemedColor(isDrawSelectionBackground() ? (currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeSelectedText : Theme.key_chat_inTimeSelectedText) : (currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeText : Theme.key_chat_inTimeText) ), getVideoTranscriptionProgress() ) ); } else { if (shouldDrawTimeOnMedia()) { if (currentMessageObject.shouldDrawWithoutBackground()) { Theme.chat_timePaint.setColor(getThemedColor(Theme.key_chat_serviceText)); } else { Theme.chat_timePaint.setColor(getThemedColor(Theme.key_chat_mediaTimeText)); } } else { if (currentMessageObject.isOutOwner()) { Theme.chat_timePaint.setColor(getThemedColor(drawSelectionBackground ? Theme.key_chat_outTimeSelectedText : Theme.key_chat_outTimeText)); } else { Theme.chat_timePaint.setColor(getThemedColor(drawSelectionBackground ? Theme.key_chat_inTimeSelectedText : Theme.key_chat_inTimeText)); } } } if (getTransitionParams().animateDrawingTimeAlpha) { alpha *= getTransitionParams().animateChangeProgress; } if (alpha != 1f) { Theme.chat_timePaint.setAlpha((int) (Theme.chat_timePaint.getAlpha() * alpha)); } canvas.save(); if (drawPinnedBottom && !shouldDrawTimeOnMedia()) { canvas.translate(0, dp(2)); } boolean bigRadius = false; float layoutHeight = this.layoutHeight; if (transitionParams.animateBackgroundBoundsInner) { layoutHeight += transitionParams.deltaBottom; } float timeTitleTimeX = timeX; if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { layoutHeight -= getTranslationY(); timeX += currentMessagesGroup.transitionParams.offsetRight; timeTitleTimeX += currentMessagesGroup.transitionParams.offsetRight; } if (drawPinnedBottom && shouldDrawTimeOnMedia()) { layoutHeight += dp(1); } if (transitionParams.animateBackgroundBoundsInner) { timeX += animationOffsetX; timeTitleTimeX += animationOffsetX; } if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { if (transitionParams.animateBackgroundBoundsInner && transitionParams.deltaRight != 0) { timeTitleTimeX += reactionsLayoutInBubble.getCurrentWidth(1f); } else { timeTitleTimeX += reactionsLayoutInBubble.getCurrentWidth(transitionParams.animateChangeProgress); } } if (transitionParams.animateEditedEnter) { timeTitleTimeX -= transitionParams.animateEditedWidthDiff * (1f - transitionParams.animateChangeProgress); } int timeYOffset; if (shouldDrawTimeOnMedia()) { timeYOffset = -(drawCommentButton ? dp(41.3f) : 0); Paint paint; if (currentMessageObject.shouldDrawWithoutBackground()) { paint = getThemedPaint(Theme.key_paint_chatActionBackground); } else { paint = getThemedPaint(Theme.key_paint_chatTimeBackground); } int oldAlpha = paint.getAlpha(); float oldAlpha3 = alpha; Theme.chat_timePaint.setAlpha((int) (255 * timeAlpha * alpha)); if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_GEO) { float progress = photoImage.isCrossfadingWithOldImage() ? 1 : photoImage.getCurrentAlpha(); if (!photoImage.hasNotThumb()) { progress = 0; } alpha = AndroidUtilities.lerp(0.35f, 1f, progress); } if (currentMessageObject != null && currentMessageObject.sendPreview) { alpha *= effectDrawable == null ? 0f : effectDrawable.isNotEmpty(); } paint.setAlpha((int) (oldAlpha * timeAlpha * alpha * .6f)); int r; if (documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER && currentMessageObject.type != MessageObject.TYPE_EMOJIS) { int[] rad = photoImage.getRoundRadius(); r = Math.min(dp(8), Math.max(rad[2], rad[3])); bigRadius = SharedConfig.bubbleRadius >= 10; } else { r = dp(4) + (currentMessageObject != null && currentMessageObject.isAnyKindOfSticker() ? dp(8) : 0); } timeX += (currentMessageObject != null && currentMessageObject.isAnyKindOfSticker() ? dp(-STICKER_STATUS_OFFSET) : 0); if (effectId != 0) { timeX -= dp(14 + 4); } float x1 = timeX - dp(bigRadius ? 6 : 4); float offsetX = (currentMessageObject != null && currentMessageObject.isAnyKindOfSticker()) ? dp(2) : 0; float timeY; if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && (currentMessageObject == null || !currentMessageObject.isRoundOnce())) { timeY = layoutHeight - (dp(drawPinnedBottom ? 4 : 5) + reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress)) * (1f - getVideoTranscriptionProgress()); } else { timeY = getPhotoBottom() + additionalTimeOffsetY; } float y1 = timeY - dp(23); float timeHeight = Math.max(dp(17), Theme.chat_timePaint.getTextSize() + dp(5)); rect.set(x1 - offsetX, y1, offsetX + x1 + timeWidth + dp((bigRadius ? 12 : 8) + (currentMessageObject.isOutOwner() ? 20 + (currentMessageObject.type == MessageObject.TYPE_EMOJIS ? 4 : 0) : 0)), y1 + timeHeight); if (groupMedia != null) { groupMedia.drawBlurRect(canvas, rect, r, .5f * timeAlpha * alpha); } else if (!currentMessageObject.isQuickReply()) { if (currentMessageObject.hasMediaSpoilers() && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO) { rectPath.rewind(); rectPath.addRoundRect(rect, r, r, Path.Direction.CW); canvas.save(); canvas.clipPath(rectPath); ImageReceiver imageReceiver = currentMessageObject.needDrawBluredPreview() ? photoImage : blurredPhotoImage; float wasAlpha = imageReceiver.getAlpha(); imageReceiver.setAlpha(.5f * wasAlpha); imageReceiver.draw(canvas); imageReceiver.setAlpha(wasAlpha); canvas.restore(); Paint dimPaint = getThemedPaint(Theme.key_paint_chatTimeBackground); int oldAlpha2 = dimPaint.getAlpha(); dimPaint.setAlpha((int) (oldAlpha2 * controlsAlpha * .4f)); canvas.drawRoundRect(rect, r, r, dimPaint); dimPaint.setAlpha(oldAlpha2); } else { applyServiceShaderMatrix(); canvas.drawRoundRect(rect, r, r, paint); if (paint == getThemedPaint(Theme.key_paint_chatActionBackground) && hasGradientService()) { int oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * timeAlpha * alpha)); canvas.drawRoundRect(rect, r, r, Theme.chat_actionBackgroundGradientDarkenPaint); Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); } } } paint.setAlpha(oldAlpha); alpha = oldAlpha3; float additionalX = -timeLayout.getLineLeft(0) + (currentMessageObject != null && currentMessageObject.isAnyKindOfSticker() ? dp(-STICKER_STATUS_OFFSET) : 0); if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { updateReactionLayoutPosition(); reactionsLayoutInBubble.setScrimProgress(0, false); reactionsLayoutInBubble.draw(canvas, transitionParams.animateChangeProgress, null); } if (ChatObject.isChannel(currentChat) && !currentChat.megagroup || (currentMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0 || repliesLayout != null || isPinned) { additionalX += this.timeWidth - timeLayout.getLineWidth(0); if (reactionsLayoutInBubble.isSmall && !reactionsLayoutInBubble.isEmpty) { additionalX -= reactionsLayoutInBubble.width; } int currentStatus = transitionParams.createStatusDrawableParams(); if (transitionParams.lastStatusDrawableParams >= 0 && transitionParams.lastStatusDrawableParams != currentStatus && !statusDrawableAnimationInProgress) { createStatusDrawableAnimator(transitionParams.lastStatusDrawableParams, currentStatus, fromParent); } if (statusDrawableAnimationInProgress) { currentStatus = animateToStatusDrawableParams; } boolean drawClock = (currentStatus & 4) != 0; boolean drawError = (currentStatus & 8) != 0; if (statusDrawableAnimationInProgress) { boolean outDrawClock = (animateFromStatusDrawableParams & 4) != 0; boolean outDrawError = (animateFromStatusDrawableParams & 8) != 0; drawClockOrErrorLayout(canvas, outDrawClock, outDrawError, layoutHeight, alpha, timeYOffset, timeX, 1f - statusDrawableProgress, drawSelectionBackground); drawClockOrErrorLayout(canvas, drawClock, drawError, layoutHeight, alpha, timeYOffset, timeX, statusDrawableProgress, drawSelectionBackground); if (!currentMessageObject.isOutOwner()) { if (!outDrawClock && !outDrawError) { drawViewsAndRepliesLayout(canvas, layoutHeight, alpha, timeYOffset, timeX, 1f - statusDrawableProgress, drawSelectionBackground); } if (!drawClock && !drawError) { drawViewsAndRepliesLayout(canvas, layoutHeight, alpha, timeYOffset, timeX, statusDrawableProgress, drawSelectionBackground); } } } else { if (!currentMessageObject.isOutOwner()) { if (!drawClock && !drawError) { drawViewsAndRepliesLayout(canvas, layoutHeight, alpha, timeYOffset, timeX, 1f, drawSelectionBackground); } } drawClockOrErrorLayout(canvas, drawClock, drawError, layoutHeight, alpha, timeYOffset, timeX, 1f, drawSelectionBackground); } if (currentMessageObject.isOutOwner()) { drawViewsAndRepliesLayout(canvas, layoutHeight, alpha, timeYOffset, timeX, 1f, drawSelectionBackground); } transitionParams.lastStatusDrawableParams = transitionParams.createStatusDrawableParams(); if (drawClock && fromParent && getParent() != null) { ((View) getParent()).invalidate(); } } canvas.save(); canvas.translate(drawTimeX = timeTitleTimeX + additionalX, drawTimeY = timeY - dp(7.3f) - timeLayout.getHeight()); SpoilerEffect.layoutDrawMaybe(timeLayout, canvas); canvas.restore(); Theme.chat_timePaint.setAlpha(255); } else { if (currentMessageObject.isSponsored()) { timeYOffset = -dp(48); if (hasNewLineForTime) { timeYOffset -= dp(4); } } else { timeYOffset = -(drawCommentButton ? dp(43) : 0); } float additionalX = -timeLayout.getLineLeft(0); if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { updateReactionLayoutPosition(); reactionsLayoutInBubble.setScrimProgress(0, false); reactionsLayoutInBubble.draw(canvas, transitionParams.animateChangeProgress, null); } if (ChatObject.isChannel(currentChat) && !currentChat.megagroup || (currentMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0 || (repliesLayout != null || transitionParams.animateReplies) || (isPinned || transitionParams.animatePinned)) { additionalX += timeWidth - timeLayout.getLineWidth(0); if (reactionsLayoutInBubble.isSmall && !reactionsLayoutInBubble.isEmpty) { additionalX -= reactionsLayoutInBubble.width; } int currentStatus = transitionParams.createStatusDrawableParams(); if (transitionParams.lastStatusDrawableParams >= 0 && transitionParams.lastStatusDrawableParams != currentStatus && !statusDrawableAnimationInProgress) { createStatusDrawableAnimator(transitionParams.lastStatusDrawableParams, currentStatus, fromParent); } if (statusDrawableAnimationInProgress) { currentStatus = animateToStatusDrawableParams; } boolean drawClock = (currentStatus & 4) != 0; boolean drawError = (currentStatus & 8) != 0; if (statusDrawableAnimationInProgress) { boolean outDrawClock = (animateFromStatusDrawableParams & 4) != 0; boolean outDrawError = (animateFromStatusDrawableParams & 8) != 0; drawClockOrErrorLayout(canvas, outDrawClock, outDrawError, layoutHeight, alpha, timeYOffset, timeX, 1f - statusDrawableProgress, drawSelectionBackground); drawClockOrErrorLayout(canvas, drawClock, drawError, layoutHeight, alpha, timeYOffset, timeX, statusDrawableProgress, drawSelectionBackground); if (!currentMessageObject.isOutOwner()) { if (!outDrawClock && !outDrawError) { drawViewsAndRepliesLayout(canvas, layoutHeight, alpha, timeYOffset, timeX, 1f - statusDrawableProgress, drawSelectionBackground); } if (!drawClock && !drawError) { drawViewsAndRepliesLayout(canvas, layoutHeight, alpha, timeYOffset, timeX, statusDrawableProgress, drawSelectionBackground); } } } else { if (!currentMessageObject.isOutOwner()) { if (!drawClock && !drawError) { drawViewsAndRepliesLayout(canvas, layoutHeight, alpha, timeYOffset, timeX, 1f, drawSelectionBackground); } } drawClockOrErrorLayout(canvas, drawClock, drawError, layoutHeight, alpha, timeYOffset, timeX, 1f, drawSelectionBackground); } if (currentMessageObject.isOutOwner()) { drawViewsAndRepliesLayout(canvas, layoutHeight, alpha, timeYOffset, timeX, 1f, drawSelectionBackground); } transitionParams.lastStatusDrawableParams = transitionParams.createStatusDrawableParams(); if (drawClock && fromParent && getParent() != null) { ((View) getParent()).invalidate(); } } canvas.save(); if (transitionParams.animateEditedEnter && transitionParams.animateChangeProgress != 1f) { if (transitionParams.animateEditedLayout != null) { canvas.translate(timeTitleTimeX + additionalX, layoutHeight - dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); int oldAlpha = Theme.chat_timePaint.getAlpha(); Theme.chat_timePaint.setAlpha((int) (oldAlpha * transitionParams.animateChangeProgress)); transitionParams.animateEditedLayout.draw(canvas); Theme.chat_timePaint.setAlpha(oldAlpha); SpoilerEffect.layoutDrawMaybe(transitionParams.animateTimeLayout, canvas); } else { int oldAlpha = Theme.chat_timePaint.getAlpha(); canvas.save(); canvas.translate(transitionParams.animateFromTimeX + additionalX, layoutHeight - dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); Theme.chat_timePaint.setAlpha((int) (oldAlpha * (1f - transitionParams.animateChangeProgress))); SpoilerEffect.layoutDrawMaybe(transitionParams.animateTimeLayout, canvas); canvas.restore(); canvas.translate(timeTitleTimeX + additionalX, layoutHeight - dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); Theme.chat_timePaint.setAlpha((int) (oldAlpha * (transitionParams.animateChangeProgress))); SpoilerEffect.layoutDrawMaybe(timeLayout, canvas); Theme.chat_timePaint.setAlpha(oldAlpha); } } else { canvas.translate(drawTimeX = timeTitleTimeX + additionalX, drawTimeY = layoutHeight - dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); SpoilerEffect.layoutDrawMaybe(timeLayout, canvas); } canvas.restore(); } if (currentMessageObject.isOutOwner()) { int currentStatus = transitionParams.createStatusDrawableParams(); if (transitionParams.lastStatusDrawableParams >= 0 && transitionParams.lastStatusDrawableParams != currentStatus && !statusDrawableAnimationInProgress) { createStatusDrawableAnimator(transitionParams.lastStatusDrawableParams, currentStatus, fromParent); } if (statusDrawableAnimationInProgress) { currentStatus = animateToStatusDrawableParams; } boolean drawCheck1 = (currentStatus & 1) != 0; boolean drawCheck2 = (currentStatus & 2) != 0; boolean drawClock = (currentStatus & 4) != 0; boolean drawError = (currentStatus & 8) != 0; boolean needRestore = false; if (transitionYOffsetForDrawables != 0) { needRestore = true; canvas.save(); canvas.translate(0, transitionYOffsetForDrawables); } if (statusDrawableAnimationInProgress) { boolean outDrawCheck1 = (animateFromStatusDrawableParams & 1) != 0; boolean outDrawCheck2 = (animateFromStatusDrawableParams & 2) != 0; boolean outDrawClock = (animateFromStatusDrawableParams & 4) != 0; boolean outDrawError = (animateFromStatusDrawableParams & 8) != 0; if (!outDrawClock && outDrawCheck2 && drawCheck2 && !outDrawCheck1 && drawCheck1) { drawStatusDrawable(canvas, drawCheck1, drawCheck2, drawClock, drawError, alpha, bigRadius, timeYOffset, layoutHeight, statusDrawableProgress, true, drawSelectionBackground); } else { drawStatusDrawable(canvas, outDrawCheck1, outDrawCheck2, outDrawClock, outDrawError, alpha, bigRadius, timeYOffset, layoutHeight, 1f - statusDrawableProgress, false, drawSelectionBackground); drawStatusDrawable(canvas, drawCheck1, drawCheck2, drawClock, drawError, alpha, bigRadius, timeYOffset, layoutHeight, statusDrawableProgress, false, drawSelectionBackground); } } else { drawStatusDrawable(canvas, drawCheck1, drawCheck2, drawClock, drawError, alpha, bigRadius, timeYOffset, layoutHeight, 1, false, drawSelectionBackground); } if (needRestore) { canvas.restore(); } transitionParams.lastStatusDrawableParams = transitionParams.createStatusDrawableParams(); if (fromParent && drawClock && getParent() != null) { ((View) getParent()).invalidate(); } } canvas.restore(); if (unlockLayout != null) { if (unlockX == 0 || unlockY == 0) { calculateUnlockXY(); } unlockSpoilerPath.rewind(); AndroidUtilities.rectTmp.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); int[] photoRadius = photoImage.getRoundRadius(); unlockSpoilerRadii[0] = unlockSpoilerRadii[1] = photoRadius[0]; unlockSpoilerRadii[2] = unlockSpoilerRadii[3] = photoRadius[1]; unlockSpoilerRadii[4] = unlockSpoilerRadii[5] = photoRadius[2]; unlockSpoilerRadii[6] = unlockSpoilerRadii[7] = photoRadius[3]; unlockSpoilerPath.addRoundRect(AndroidUtilities.rectTmp, unlockSpoilerRadii, Path.Direction.CW); canvas.save(); canvas.clipPath(unlockSpoilerPath); unlockSpoilerPath.rewind(); AndroidUtilities.rectTmp.set(unlockX - dp(12), unlockY - dp(8), unlockX + Theme.chat_msgUnlockDrawable.getIntrinsicWidth() + dp(14) + unlockLayout.getWidth() + dp(12), unlockY + unlockLayout.getHeight() + dp(8)); unlockSpoilerPath.addRoundRect(AndroidUtilities.rectTmp, dp(32), dp(32), Path.Direction.CW); canvas.clipPath(unlockSpoilerPath, Region.Op.DIFFERENCE); int sColor = Color.WHITE; if (mediaSpoilerEffect2 == null) { if (unlockSpoilerEffect == null) { unlockSpoilerEffect = new SpoilerEffect(); } unlockSpoilerEffect.setColor(ColorUtils.setAlphaComponent(sColor, (int) (Color.alpha(sColor) * 0.325f))); unlockSpoilerEffect.setBounds((int) photoImage.getImageX(), (int) photoImage.getImageY(), (int) photoImage.getImageX2(), (int) photoImage.getImageY2()); unlockSpoilerEffect.draw(canvas); } invalidate(); canvas.restore(); canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int)(unlockAlpha * 0xFF), Canvas.ALL_SAVE_FLAG); int wasAlpha = Theme.chat_timeBackgroundPaint.getAlpha(); Theme.chat_timeBackgroundPaint.setAlpha((int) (wasAlpha * 0.7f)); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(32), dp(32), Theme.chat_timeBackgroundPaint); Theme.chat_timeBackgroundPaint.setAlpha(wasAlpha); canvas.translate(unlockX + dp(4), unlockY); Theme.chat_msgUnlockDrawable.setBounds(0, 0, Theme.chat_msgUnlockDrawable.getIntrinsicWidth(), Theme.chat_msgUnlockDrawable.getIntrinsicHeight()); Theme.chat_msgUnlockDrawable.draw(canvas); canvas.translate(dp(6) + Theme.chat_msgUnlockDrawable.getIntrinsicWidth(), 0); SpoilerEffect.layoutDrawMaybe(unlockLayout, canvas); canvas.restore(); if (videoInfoLayout != null && photoImage.getVisible() && imageBackgroundSideColor == 0) { float rad; if (SharedConfig.bubbleRadius > 2) { rad = dp(SharedConfig.bubbleRadius - 2); bigRadius = SharedConfig.bubbleRadius >= 10; } else { rad = dp(SharedConfig.bubbleRadius); } int x = (int) (photoImage.getImageX() + dp(9)); int y = (int) (photoImage.getImageY() + dp(6)); rect.set(x - dp(4), y - dp(1.5f), x + durationWidth + dp(4) + dp(bigRadius ? 2 : 0), y + videoInfoLayout.getHeight() + dp(1.5f)); canvas.drawRoundRect(rect, rad, rad, getThemedPaint(Theme.key_paint_chatTimeBackground)); canvas.save(); canvas.translate(x + (bigRadius ? 2 : 0), y); SpoilerEffect.layoutDrawMaybe(videoInfoLayout, canvas); canvas.restore(); } } } private void createStatusDrawableAnimator(int lastStatusDrawableParams, int currentStatus, boolean fromParent) { boolean drawCheck1 = (currentStatus & 1) != 0; boolean drawCheck2 = (currentStatus & 2) != 0; boolean outDrawCheck1 = (lastStatusDrawableParams & 1) != 0; boolean outDrawCheck2 = (lastStatusDrawableParams & 2) != 0; boolean outDrawClock = (lastStatusDrawableParams & 4) != 0; boolean moveCheckTransition = !outDrawClock && outDrawCheck2 && drawCheck2 && !outDrawCheck1 && drawCheck1; if (transitionParams.messageEntering && !moveCheckTransition) { return; } statusDrawableProgress = 0f; statusDrawableAnimator = ValueAnimator.ofFloat(0, 1f); if (moveCheckTransition) { statusDrawableAnimator.setDuration(220); } else { statusDrawableAnimator.setDuration(150); } statusDrawableAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); animateFromStatusDrawableParams = lastStatusDrawableParams; animateToStatusDrawableParams = currentStatus; statusDrawableAnimator.addUpdateListener(valueAnimator -> { statusDrawableProgress = (float) valueAnimator.getAnimatedValue(); invalidate(); if (fromParent && getParent() != null) { ((View) getParent()).invalidate(); } }); statusDrawableAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { int currentStatus = transitionParams.createStatusDrawableParams(); if (animateToStatusDrawableParams != currentStatus) { createStatusDrawableAnimator(animateToStatusDrawableParams, currentStatus, fromParent); } else { statusDrawableAnimationInProgress = false; transitionParams.lastStatusDrawableParams = animateToStatusDrawableParams; } } }); statusDrawableAnimationInProgress = true; statusDrawableAnimator.start(); } private void drawClockOrErrorLayout(Canvas canvas, boolean drawTime, boolean drawError, float layoutHeight, float alpha, float timeYOffset, float timeX, float progress, boolean drawSelectionBackground) { boolean useScale = progress != 1f; float scale = 0.5f + 0.5f * progress; alpha *= progress; if (drawTime) { if (!currentMessageObject.isOutOwner()) { MsgClockDrawable clockDrawable = Theme.chat_msgClockDrawable; int clockColor; if (shouldDrawTimeOnMedia()) { clockColor = getThemedColor(Theme.key_chat_mediaSentClock); } else { clockColor = getThemedColor(drawSelectionBackground ? Theme.key_chat_outSentClockSelected : Theme.key_chat_mediaSentClock); } clockDrawable.setColor(clockColor); float timeY; if (shouldDrawTimeOnMedia()) { timeY = getPhotoBottom() + additionalTimeOffsetY - dp(9.0f); } else { timeY = layoutHeight - dp(pinnedBottom || pinnedTop ? 9.5f : 8.5f) + timeYOffset; if (isRoundVideo) { timeY -= (dp(drawPinnedBottom ? 4 : 5) + reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress)) * (1f - getVideoTranscriptionProgress()); } } setDrawableBounds(clockDrawable, timeX + (currentMessageObject.scheduled ? 0 : dp(11)), timeY - clockDrawable.getIntrinsicHeight()); clockDrawable.setAlpha((int) (255 * alpha)); if (useScale) { canvas.save(); canvas.scale(scale, scale, clockDrawable.getBounds().centerX(), clockDrawable.getBounds().centerY()); } clockDrawable.draw(canvas); clockDrawable.setAlpha(255); invalidate(); if (useScale) { canvas.restore(); } } } else if (drawError) { if (!currentMessageObject.isOutOwner()) { float x = timeX + (currentMessageObject.scheduled ? 0 : dp(11)); float y; if (shouldDrawTimeOnMedia()) { y = getPhotoBottom() + additionalTimeOffsetY - dp(21.5f); } else { y = layoutHeight - dp(pinnedBottom || pinnedTop ? 21.5f : 20.5f) + timeYOffset; if (isRoundVideo) { y -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress) * (1f - getVideoTranscriptionProgress()); } } rect.set(x, y, x + dp(14), y + dp(14)); int oldAlpha = Theme.chat_msgErrorPaint.getAlpha(); Theme.chat_msgErrorPaint.setAlpha((int) (255 * alpha)); if (useScale) { canvas.save(); canvas.scale(scale, scale, rect.centerX(), rect.centerY()); } canvas.drawRoundRect(rect, dp(1), dp(1), Theme.chat_msgErrorPaint); Theme.chat_msgErrorPaint.setAlpha(oldAlpha); Drawable errorDrawable = getThemedDrawable(Theme.key_drawable_msgError); setDrawableBounds(errorDrawable, x + dp(6), y + dp(2)); errorDrawable.setAlpha((int) (255 * alpha)); errorDrawable.draw(canvas); errorDrawable.setAlpha(255); if (useScale) { canvas.restore(); } } } } public float getTimeX() { return transitionParams.shouldAnimateTimeX ? AndroidUtilities.lerp(transitionParams.animateFromTimeX, timeX, transitionParams.animateChangeProgress) : timeX; } public float getTimeY() { int timeYOffset; if (shouldDrawTimeOnMedia()) { timeYOffset = -(drawCommentButton ? dp(41.3f) : 0); } else { if (currentMessageObject.isSponsored()) { timeYOffset = -dp(48); if (hasNewLineForTime) { timeYOffset -= dp(4); } } else { timeYOffset = -(drawCommentButton ? dp(43) : 0); } } return getTimeY(timeYOffset); } public float getTimeY(float timeYOffset) { if (shouldDrawTimeOnMedia() && documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND) { return getPhotoBottom() + additionalTimeOffsetY - dp(7.3f) - timeLayout.getHeight(); } float timeY = layoutHeight - dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset; if (isRoundVideo) { timeY -= (dp(drawPinnedBottom ? 4 : 5) + reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress)) * (1f - getVideoTranscriptionProgress()); } if (currentMessagesGroup != null) { timeY += currentMessagesGroup.transitionParams.offsetBottom; if (currentMessagesGroup.transitionParams.backgroundChangeBounds) { timeY -= getTranslationY(); } } else { timeY += transitionParams.deltaBottom - transitionParams.deltaTop; } return timeY; } private void drawViewsAndRepliesLayout(Canvas canvas, float layoutHeight, float alpha, float timeYOffset, float timeX, float progress, boolean drawSelectionBackground) { boolean useScale = progress != 1f; float scale = 0.5f + 0.5f * progress; alpha *= progress; float offsetX = reactionsLayoutInBubble.isSmall ? reactionsLayoutInBubble.getCurrentWidth(1f) : 0; int timeAlpha = Theme.chat_timePaint.getAlpha(); float timeY = getTimeY(timeYOffset); if (repliesLayout != null || transitionParams.animateReplies) { float repliesX = (transitionParams.shouldAnimateTimeX ? this.timeX : timeX) + offsetX; boolean inAnimation = transitionParams.animateReplies && transitionParams.animateRepliesLayout == null && repliesLayout != null; boolean outAnimation = transitionParams.animateReplies && transitionParams.animateRepliesLayout != null && repliesLayout == null; boolean replaceAnimation = transitionParams.animateReplies && transitionParams.animateRepliesLayout != null && repliesLayout != null; if (!(isRoundVideo && transitionParams.animateDrawBackground)) { if (transitionParams.shouldAnimateTimeX && !inAnimation) { if (outAnimation) { repliesX = transitionParams.animateFromTimeXReplies; } else { repliesX = transitionParams.animateFromTimeXReplies * (1f - transitionParams.animateChangeProgress) + repliesX * transitionParams.animateChangeProgress; } } else { // repliesX += transitionParams.deltaRight; } } if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { repliesX += currentMessagesGroup.transitionParams.offsetRight; } if (transitionParams.animateBackgroundBoundsInner) { repliesX += animationOffsetX; } Drawable repliesDrawable; float w; if (shouldDrawTimeOnMedia()) { if (currentMessageObject.shouldDrawWithoutBackground()) { repliesDrawable = getThemedDrawable(Theme.key_drawable_msgStickerReplies); } else { repliesDrawable = Theme.chat_msgMediaRepliesDrawable; } } else { if (!currentMessageObject.isOutOwner()) { repliesDrawable = drawSelectionBackground ? Theme.chat_msgInRepliesSelectedDrawable : Theme.chat_msgInRepliesDrawable; } else { repliesDrawable = getThemedDrawable(drawSelectionBackground ? Theme.key_drawable_msgOutRepliesSelected : Theme.key_drawable_msgOutReplies); } } w = setDrawableBounds(repliesDrawable, repliesX, timeY, Theme.chat_timePaint.getTextSize()); float repliesAlpha = alpha; if (inAnimation) { repliesAlpha *= transitionParams.animateChangeProgress; } else if (outAnimation) { repliesAlpha *= (1f - transitionParams.animateChangeProgress); } repliesDrawable.setAlpha((int) (255 * repliesAlpha)); if (useScale) { canvas.save(); float cx = repliesX + (w + dp(3) + repliesTextWidth) / 2f; canvas.scale(scale, scale, cx, repliesDrawable.getBounds().centerY()); } repliesDrawable.draw(canvas); repliesDrawable.setAlpha(255); if (transitionParams.animateReplies) { if (replaceAnimation) { canvas.save(); Theme.chat_timePaint.setAlpha((int) (timeAlpha * (1.0 - transitionParams.animateChangeProgress))); canvas.translate(repliesX + w + dp(3), timeY); transitionParams.animateRepliesLayout.draw(canvas); canvas.restore(); } Theme.chat_timePaint.setAlpha((int) (timeAlpha * repliesAlpha)); } canvas.save(); canvas.translate(repliesX + w + dp(3), timeY); if (repliesLayout != null) { repliesLayout.draw(canvas); } else if (transitionParams.animateRepliesLayout != null) { transitionParams.animateRepliesLayout.draw(canvas); } canvas.restore(); if (repliesLayout != null) { offsetX += w + repliesTextWidth + dp(10); } if (useScale) { canvas.restore(); } if (transitionParams.animateReplies) { Theme.chat_timePaint.setAlpha(timeAlpha); } transitionParams.lastTimeXReplies = repliesX; } if (viewsLayout != null) { float viewsX = (transitionParams.shouldAnimateTimeX ? this.timeX : timeX) + offsetX; if (!(isRoundVideo && transitionParams.animateDrawBackground)) { if (transitionParams.shouldAnimateTimeX) { viewsX = transitionParams.animateFromTimeXViews * (1f - transitionParams.animateChangeProgress) + viewsX * transitionParams.animateChangeProgress; } else { // viewsX += transitionParams.deltaRight; } } if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { viewsX += currentMessagesGroup.transitionParams.offsetRight; } if (transitionParams.animateBackgroundBoundsInner) { viewsX += animationOffsetX; } Drawable viewsDrawable; if (shouldDrawTimeOnMedia()) { if (currentMessageObject.shouldDrawWithoutBackground()) { viewsDrawable = getThemedDrawable(Theme.key_drawable_msgStickerViews); } else { viewsDrawable = Theme.chat_msgMediaViewsDrawable; } } else { if (!currentMessageObject.isOutOwner()) { viewsDrawable = drawSelectionBackground ? Theme.chat_msgInViewsSelectedDrawable : Theme.chat_msgInViewsDrawable; } else { viewsDrawable = getThemedDrawable(drawSelectionBackground ? Theme.key_drawable_msgOutViewsSelected : Theme.key_drawable_msgOutViews); } } float y = timeY; float w = setDrawableBounds(viewsDrawable, viewsX, y + dp(1.5f), Theme.chat_timePaint.getTextSize() - dp(2)); if (useScale) { canvas.save(); float cx = viewsX + (viewsDrawable.getIntrinsicWidth() + dp(3) + viewsTextWidth) / 2f; canvas.scale(scale, scale, cx, viewsDrawable.getBounds().centerY()); } viewsDrawable.setAlpha((int) (255 * alpha)); viewsDrawable.draw(canvas); viewsDrawable.setAlpha(255); if (transitionParams.animateViewsLayout != null) { canvas.save(); Theme.chat_timePaint.setAlpha((int) (timeAlpha * (1.0 - transitionParams.animateChangeProgress))); canvas.translate(viewsX + w + dp(3), y); SpoilerEffect.layoutDrawMaybe(transitionParams.animateViewsLayout, canvas); canvas.restore(); Theme.chat_timePaint.setAlpha((int) (timeAlpha * transitionParams.animateChangeProgress)); } canvas.save(); canvas.translate(viewsX + w + dp(3), y); SpoilerEffect.layoutDrawMaybe(viewsLayout, canvas); canvas.restore(); if (useScale) { canvas.restore(); } offsetX += viewsTextWidth + w + dp(10); if (transitionParams.animateViewsLayout != null) { Theme.chat_timePaint.setAlpha(timeAlpha); } transitionParams.lastTimeXViews = viewsX; } if (isPinned || transitionParams.animatePinned) { float pinnedX = (transitionParams.shouldAnimateTimeX ? this.timeX : timeX) + offsetX; boolean inAnimation = transitionParams.animatePinned && isPinned; boolean outAnimation = transitionParams.animatePinned && !isPinned; if (!isRoundVideo) { if (transitionParams.shouldAnimateTimeX && !inAnimation) { if (outAnimation) { pinnedX = transitionParams.animateFromTimeXPinned; } else { pinnedX = transitionParams.animateFromTimeXPinned * (1f - transitionParams.animateChangeProgress) + pinnedX * transitionParams.animateChangeProgress; } } else { // pinnedX += transitionParams.deltaRight; } } if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { pinnedX += currentMessagesGroup.transitionParams.offsetRight; } if (transitionParams.animateBackgroundBoundsInner) { pinnedX += animationOffsetX; } Drawable pinnedDrawable; if (shouldDrawTimeOnMedia()) { if (currentMessageObject.shouldDrawWithoutBackground()) { pinnedDrawable = getThemedDrawable(Theme.key_drawable_msgStickerPinned); } else { pinnedDrawable = Theme.chat_msgMediaPinnedDrawable; } } else { if (!currentMessageObject.isOutOwner()) { pinnedDrawable = drawSelectionBackground ? Theme.chat_msgInPinnedSelectedDrawable : Theme.chat_msgInPinnedDrawable; } else { pinnedDrawable = getThemedDrawable(drawSelectionBackground ? Theme.key_drawable_msgOutPinnedSelected : Theme.key_drawable_msgOutPinned); } } float w; if (transitionParams.animatePinned) { if (isPinned) { pinnedDrawable.setAlpha((int) (255 * alpha * transitionParams.animateChangeProgress)); w = setDrawableBounds(pinnedDrawable, pinnedX, timeY, Theme.chat_timePaint.getTextSize() + dp(1)); } else { pinnedDrawable.setAlpha((int) (255 * alpha * (1.0f - transitionParams.animateChangeProgress))); w = setDrawableBounds(pinnedDrawable, pinnedX, timeY, Theme.chat_timePaint.getTextSize() + dp(1)); } } else { pinnedDrawable.setAlpha((int) (255 * alpha)); w = setDrawableBounds(pinnedDrawable, pinnedX, timeY, Theme.chat_timePaint.getTextSize() + dp(1)); } if (useScale) { canvas.save(); float cx = pinnedX + w / 2f; canvas.scale(scale, scale, cx, pinnedDrawable.getBounds().centerY()); } pinnedDrawable.draw(canvas); pinnedDrawable.setAlpha(255); if (useScale) { canvas.restore(); } transitionParams.lastTimeXPinned = pinnedX; } } private void drawStatusDrawable(Canvas canvas, boolean drawCheck1, boolean drawCheck2, boolean drawClock, boolean drawError, float alpha, boolean bigRadius, float timeYOffset, float layoutHeight, float progress, boolean moveCheck, boolean drawSelectionBackground) { final boolean useScale = progress != 1f && !moveCheck; float scale = 0.5f + 0.5f * progress; if (useScale) { alpha = alpha * progress; } float timeY; if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && (currentMessageObject == null || !currentMessageObject.isRoundOnce())) { timeY = layoutHeight - (dp(drawPinnedBottom ? 4 : 5) + reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress)) * (1f - getVideoTranscriptionProgress()); } else { timeY = getPhotoBottom() + additionalTimeOffsetY; } timeY -= dp(8.5f); float offsetX = currentMessageObject != null && currentMessageObject.isAnyKindOfSticker() ? dp(-STICKER_STATUS_OFFSET) : 0; if (drawClock) { MsgClockDrawable drawable = Theme.chat_msgClockDrawable; int color; if (shouldDrawTimeOnMedia()) { if (currentMessageObject.shouldDrawWithoutBackground()) { color = getThemedColor(Theme.key_chat_serviceText); setDrawableBounds(drawable, layoutWidth - dp(bigRadius ? 24 : 22) - drawable.getIntrinsicWidth() + offsetX, timeY - drawable.getIntrinsicHeight() + timeYOffset); drawable.setAlpha((int) (255 * timeAlpha * alpha)); } else { color = getThemedColor(Theme.key_chat_mediaSentClock); setDrawableBounds(drawable, layoutWidth - dp(bigRadius ? 24 : 22) - drawable.getIntrinsicWidth() + offsetX, timeY - drawable.getIntrinsicHeight() + timeYOffset); drawable.setAlpha((int) (255 * alpha)); } } else { color = getThemedColor(Theme.key_chat_outSentClock); setDrawableBounds(drawable, layoutWidth - dp(18.5f) - drawable.getIntrinsicWidth(), layoutHeight - dp(8.5f) - drawable.getIntrinsicHeight() + timeYOffset); drawable.setAlpha((int) (255 * alpha)); } drawable.setColor(color); if (useScale) { canvas.save(); canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); } drawable.draw(canvas); drawable.setAlpha(255); if (useScale) { canvas.restore(); } invalidate(); } if (drawCheck2) { if (shouldDrawTimeOnMedia()) { Drawable drawable; if (moveCheck) { canvas.save(); } if (currentMessageObject.shouldDrawWithoutBackground()) { drawable = getThemedDrawable(Theme.key_drawable_msgStickerCheck); if (drawCheck1) { if (moveCheck) { canvas.translate(dp(4.8f) * (1f - progress), 0); } setDrawableBounds(drawable, layoutWidth - dp(bigRadius ? 28.3f : 26.3f) - drawable.getIntrinsicWidth() + offsetX, timeY - drawable.getIntrinsicHeight() + timeYOffset); } else { setDrawableBounds(drawable, layoutWidth - dp(bigRadius ? 23.5f : 21.5f) - drawable.getIntrinsicWidth() + offsetX, timeY - drawable.getIntrinsicHeight() + timeYOffset); } drawable.setAlpha((int) (255 * timeAlpha * alpha)); } else { if (drawCheck1) { if (moveCheck) { canvas.translate(dp(4.8f) * (1f - progress), 0); } setDrawableBounds(Theme.chat_msgMediaCheckDrawable, layoutWidth - dp(bigRadius ? 28.3f : 26.3f) - Theme.chat_msgMediaCheckDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgMediaCheckDrawable.getIntrinsicHeight() + timeYOffset); } else { setDrawableBounds(Theme.chat_msgMediaCheckDrawable, layoutWidth - dp(bigRadius ? 23.5f : 21.5f) - Theme.chat_msgMediaCheckDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgMediaCheckDrawable.getIntrinsicHeight() + timeYOffset); } Theme.chat_msgMediaCheckDrawable.setAlpha((int) (255 * timeAlpha * alpha)); drawable = Theme.chat_msgMediaCheckDrawable; } if (useScale) { canvas.save(); canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); } drawable.draw(canvas); if (useScale) { canvas.restore(); } if (moveCheck) { canvas.restore(); } drawable.setAlpha(255); } else { Drawable drawable; if (moveCheck) { canvas.save(); } if (drawCheck1) { if (moveCheck) { canvas.translate(dp(4) * (1f - progress), 0); } drawable = getThemedDrawable(drawSelectionBackground ? Theme.key_drawable_msgOutCheckReadSelected : Theme.key_drawable_msgOutCheckRead); setDrawableBounds(drawable, layoutWidth - dp(22.5f) - drawable.getIntrinsicWidth() + offsetX, layoutHeight - dp(pinnedBottom || pinnedTop ? 9 : 8) - drawable.getIntrinsicHeight() + timeYOffset); } else { drawable = getThemedDrawable(drawSelectionBackground ? Theme.key_drawable_msgOutCheckSelected : Theme.key_drawable_msgOutCheck); setDrawableBounds(drawable, layoutWidth - dp(18.5f) - drawable.getIntrinsicWidth() + offsetX, layoutHeight - dp(pinnedBottom || pinnedTop ? 9 : 8) - drawable.getIntrinsicHeight() + timeYOffset); } drawable.setAlpha((int) (255 * alpha)); if (useScale) { canvas.save(); canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); } drawable.draw(canvas); if (useScale) { canvas.restore(); } if (moveCheck) { canvas.restore(); } drawable.setAlpha(255); } } if (drawCheck1) { if (shouldDrawTimeOnMedia()) { Drawable drawable = currentMessageObject.shouldDrawWithoutBackground() ? getThemedDrawable(Theme.key_drawable_msgStickerHalfCheck) : Theme.chat_msgMediaHalfCheckDrawable; setDrawableBounds(drawable, layoutWidth - dp(bigRadius ? 23.5f : 21.5f) - drawable.getIntrinsicWidth() + offsetX, timeY - drawable.getIntrinsicHeight() + timeYOffset); drawable.setAlpha((int) (255 * timeAlpha * alpha)); if (useScale || moveCheck) { canvas.save(); canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); } drawable.draw(canvas); if (useScale || moveCheck) { canvas.restore(); } drawable.setAlpha(255); } else { Drawable drawable = getThemedDrawable(drawSelectionBackground ? Theme.key_drawable_msgOutHalfCheckSelected : Theme.key_drawable_msgOutHalfCheck); setDrawableBounds(drawable, layoutWidth - dp(18) - drawable.getIntrinsicWidth(), layoutHeight - dp(pinnedBottom || pinnedTop ? 9 : 8) - drawable.getIntrinsicHeight() + timeYOffset); drawable.setAlpha((int) (255 * alpha)); if (useScale || moveCheck) { canvas.save(); canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); } drawable.draw(canvas); if (useScale || moveCheck) { canvas.restore(); } drawable.setAlpha(255); } } if (drawError) { int x; float y; if (shouldDrawTimeOnMedia()) { x = layoutWidth - dp(34.5f); y = layoutHeight - dp(26.5f) + timeYOffset; } else { x = layoutWidth - dp(32); y = layoutHeight - dp(pinnedBottom || pinnedTop ? 22 : 21) + timeYOffset; } x += offsetX; rect.set(x, y, x + dp(14), y + dp(14)); int oldAlpha = Theme.chat_msgErrorPaint.getAlpha(); Theme.chat_msgErrorPaint.setAlpha((int) (oldAlpha * alpha)); canvas.drawRoundRect(rect, dp(1), dp(1), Theme.chat_msgErrorPaint); Theme.chat_msgErrorPaint.setAlpha(oldAlpha); setDrawableBounds(Theme.chat_msgErrorDrawable, x + dp(6), y + dp(2)); Theme.chat_msgErrorDrawable.setAlpha((int) (255 * alpha)); if (useScale) { canvas.save(); canvas.scale(scale, scale, Theme.chat_msgErrorDrawable.getBounds().centerX(), Theme.chat_msgErrorDrawable.getBounds().centerY()); } Theme.chat_msgErrorDrawable.draw(canvas); Theme.chat_msgErrorDrawable.setAlpha(255); if (useScale) { canvas.restore(); } } } private Paint srcOutPaint; public void drawOverlays(Canvas canvas) { if (!drawFromPinchToZoom && delegate != null && delegate.getPinchToZoomHelper() != null && delegate.getPinchToZoomHelper().isInOverlayModeFor(this)) { return; } long newAnimationTime = SystemClock.elapsedRealtime(); long animationDt = newAnimationTime - lastAnimationTime; if (animationDt > 17) { animationDt = 17; } lastAnimationTime = newAnimationTime; closeExplanationX = -1; closeExplanationY = -1; if (currentMessageObject.hadAnimationNotReadyLoading && photoImage.getVisible() && !currentMessageObject.needDrawBluredPreview() && (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF)) { AnimatedFileDrawable animation = photoImage.getAnimation(); if (animation != null && animation.hasBitmap()) { currentMessageObject.hadAnimationNotReadyLoading = false; updateButtonState(false, true, false); } } if (hasGamePreview) { } else if (currentMessageObject.isLivePhoto()) { float iconAlpha = 1.0f; if (videoRadialProgress != null && (drawVideoImageButton || animatingDrawVideoImageButton != 0) && !currentMessageObject.isRepostPreview && !currentMessageObject.sendPreview && photoImage.getVisible() && !isSmallImage && !currentMessageObject.isHiddenSensitive()) { iconAlpha = 1.0f - videoRadialProgress.getWholeAlpha(); } Theme.chat_livePhoto.setBounds( (int) (photoImage.getImageX() + dp(10)), (int) (photoImage.getImageY() + dp(10)), (int) (photoImage.getImageX() + dp(10) + Theme.chat_livePhoto.getIntrinsicWidth() * 0.75f), (int) (photoImage.getImageY() + dp(10) + Theme.chat_livePhoto.getIntrinsicHeight() * 0.75f) ); Theme.chat_livePhoto.setAlpha((int) (0xFF * iconAlpha)); Theme.chat_livePhoto.draw(canvas); } else if (currentMessageObject.type == MessageObject.TYPE_VIDEO || currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { if (photoImage.getVisible() && !currentMessageObject.isRepostPreview) { if (!currentMessageObject.needDrawBluredPreview() && !currentMessageObject.isSponsored() && !currentMessageObject.isRepostPreview && !currentMessageObject.preview && !isSmallImage) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { int oldAlpha = ((BitmapDrawable) Theme.chat_msgMediaMenuDrawable).getPaint().getAlpha(); if (drawMediaCheckBox) { Theme.chat_msgMediaMenuDrawable.setAlpha((int) (oldAlpha * controlsAlpha * (1.0f - checkBoxAnimationProgress))); } else { Theme.chat_msgMediaMenuDrawable.setAlpha((int) (oldAlpha * controlsAlpha)); } setDrawableBounds(Theme.chat_msgMediaMenuDrawable, otherX = (int) (photoImage.getImageX() + photoImage.getImageWidth() - dp(14)), otherY = (int) (photoImage.getImageY() + dp(8.1f))); Theme.chat_msgMediaMenuDrawable.draw(canvas); Theme.chat_msgMediaMenuDrawable.setAlpha(oldAlpha); } } boolean playing = MediaController.getInstance().isPlayingMessage(currentMessageObject); if (animatingNoSoundPlaying != playing) { animatingNoSoundPlaying = playing; animatingNoSound = playing ? 1 : 2; animatingNoSoundProgress = playing ? 1.0f : 0.0f; } boolean fullWidth = true; if (currentPosition != null) { int mask = MessageObject.POSITION_FLAG_LEFT | MessageObject.POSITION_FLAG_RIGHT; fullWidth = (currentPosition.flags & mask) == mask; } if (((documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) && (buttonState == 1 || buttonState == 2 || buttonState == 0 || buttonState == 3 || buttonState == -1) || currentMessageObject.needDrawBluredPreview()) && !currentMessageObject.isRepostVideoPreview) { if (autoPlayingMedia) { updatePlayingMessageProgress(); } if ((infoLayout != null || loadingProgressLayout != null) && (!forceNotDrawTime || autoPlayingMedia || drawVideoImageButton || animatingLoadingProgressProgress != 0 || (fullWidth && docTitleLayout != null) || (loadingProgressLayout != null && currentPosition != null && (buttonState == 1 || (buttonState == 3 && miniButtonState == 1)))) && (currentMessageObject != null && !currentMessageObject.sendPreview)) { boolean drawLoadingProgress; float alpha = 0; boolean drawDocTitleLayout; float loadingProgressAlpha = 1f; if (!fullWidth) { drawLoadingProgress = true; drawDocTitleLayout = false; loadingProgressAlpha = animatingLoadingProgressProgress; } else { drawLoadingProgress = (buttonState == 1 || miniButtonState == 1 || animatingLoadingProgressProgress != 0) && !currentMessageObject.isSecretMedia() && (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT); if (currentMessageObject.type == MessageObject.TYPE_VIDEO || currentMessageObject.type == MessageObject.TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { alpha = currentMessageObject.needDrawBluredPreview() && docTitleLayout == null ? 0 : animatingDrawVideoImageButtonProgress; } drawDocTitleLayout = alpha > 0 && docTitleLayout != null; if (!drawDocTitleLayout && (drawLoadingProgress || infoLayout == null)) { loadingProgressAlpha = animatingLoadingProgressProgress; } } loadingProgressAlpha *= (1f - isSmallImage()); if (drawPhotoImage && currentMessageObject != null && currentMessageObject.hasMediaSpoilers() && currentMessageObject.isSensitive() && (!currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0 && mediaSpoilerRevealProgress < 1)) { loadingProgressAlpha *= mediaSpoilerRevealProgress; } if (loadingProgressAlpha > 0) { boolean bigRadius = false; if (documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER && currentMessageObject.type != MessageObject.TYPE_EMOJIS) { bigRadius = SharedConfig.bubbleRadius >= 10; } Theme.chat_infoPaint.setColor(getThemedColor(Theme.key_chat_mediaInfoText)); int x1 = (int) (photoImage.getImageX() + dp(4)); int y1 = (int) (photoImage.getImageY() + dp(4)); int imageW; int infoW; if (autoPlayingMedia && (!playing || animatingNoSound != 0)) { imageW = (int) ((Theme.chat_msgNoSoundDrawable.getIntrinsicWidth() + dp(4)) * animatingNoSoundProgress); } else { imageW = 0; } if (drawLoadingProgress && loadingProgressLayout != null) { imageW = 0; infoW = (int) loadingProgressLayout.getLineWidth(0); // infoW = loadingProgressLayout.getCurrentWidth(); } else { infoW = infoWidth; } int w = (int) Math.ceil(infoW + dp(bigRadius ? 12 : 8) + imageW + (Math.max(infoW + (infoWidth == infoW ? imageW : 0), docTitleWidth) + (canStreamVideo ? dp(32) : 0) - infoW - imageW) * alpha); if (alpha != 0 && docTitleLayout == null) { alpha = 0; } canvas.save(); int oldAlpha = getThemedPaint(Theme.key_paint_chatTimeBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatTimeBackground).setAlpha((int) (oldAlpha * controlsAlpha * loadingProgressAlpha * (currentMessageObject.needDrawBluredPreview() ? .4f : 1f))); rect.set(x1, y1, x1 + w, y1 + dp(16.5f + 15.5f * alpha)); int[] rad = photoImage.getRoundRadius(); int r = Math.min(dp(8), Math.max(rad[0], rad[1])); if (currentMessageObject.needDrawBluredPreview()) { rectPath.reset(); rectPath.addRoundRect(rect, r, r, Path.Direction.CW); canvas.save(); canvas.clipPath(rectPath); float wasAlpha = photoImage.getAlpha(); photoImage.setAlpha(.5f * wasAlpha); photoImage.draw(canvas); photoImage.setAlpha(wasAlpha); canvas.restore(); canvas.drawRoundRect(rect, r, r, getThemedPaint(Theme.key_paint_chatTimeBackground)); } else if (drawDocTitleLayout || (drawLoadingProgress && loadingProgressLayout != null) || (!drawLoadingProgress && infoLayout != null)) { canvas.scale(loadingProgressAlpha, loadingProgressAlpha, x1, y1); canvas.drawRoundRect(rect, r, r, getThemedPaint(Theme.key_paint_chatTimeBackground)); } else { canvas.scale(loadingProgressAlpha, loadingProgressAlpha, x1, y1); } Theme.chat_infoPaint.setAlpha((int) (255 * controlsAlpha * loadingProgressAlpha)); Theme.chat_infoBoldPaint.setColor(Theme.chat_infoPaint.getColor()); canvas.translate(noSoundCenterX = (int) (photoImage.getImageX() + dp((bigRadius ? 10 : 8) + (canStreamVideo ? 30 * alpha : 0))), photoImage.getImageY() + dp(5.5f + 0.2f * alpha)); if (infoLayout != null && (!drawLoadingProgress || drawDocTitleLayout)) { infoLayout.draw(canvas); } if (imageW != 0 && (!drawLoadingProgress || drawDocTitleLayout)) { canvas.save(); Theme.chat_msgNoSoundDrawable.setAlpha((int) (255 * animatingNoSoundProgress * animatingNoSoundProgress * controlsAlpha)); int size = dp(14 * animatingNoSoundProgress); int y = (dp(14) - size) / 2; int offset = infoWidth + dp(4); canvas.translate(offset, 0); Theme.chat_msgNoSoundDrawable.setBounds(0, y, size, y + size); Theme.chat_msgNoSoundDrawable.draw(canvas); noSoundCenterX += offset + size / 2; canvas.restore(); } if (drawLoadingProgress && loadingProgressLayout != null) { canvas.save(); if (drawDocTitleLayout) { Theme.chat_infoPaint.setAlpha((int) (255 * controlsAlpha * alpha)); canvas.translate(0, dp(14.3f * alpha)); } // loadingProgressLayout.copyStylesFrom(Theme.chat_infoPaint); loadingProgressLayout.draw(canvas); canvas.restore(); } else if (drawDocTitleLayout) { Theme.chat_infoPaint.setAlpha((int) (255 * controlsAlpha * alpha)); canvas.translate(0, dp(14.3f * alpha)); docTitleLayout.draw(canvas); } canvas.restore(); Theme.chat_infoPaint.setAlpha(255); getThemedPaint(Theme.key_paint_chatTimeBackground).setAlpha(oldAlpha); } } } if (animatingDrawVideoImageButton == 1) { animatingDrawVideoImageButtonProgress -= animationDt / 160.0f; if (animatingDrawVideoImageButtonProgress <= 0) { animatingDrawVideoImageButtonProgress = 0; animatingDrawVideoImageButton = 0; } invalidate(); } else if (animatingDrawVideoImageButton == 2) { animatingDrawVideoImageButtonProgress += animationDt / 160.0f; if (animatingDrawVideoImageButtonProgress >= 1) { animatingDrawVideoImageButtonProgress = 1; animatingDrawVideoImageButton = 0; } invalidate(); } if (animatingNoSound == 1) { animatingNoSoundProgress -= animationDt / 180.0f; if (animatingNoSoundProgress <= 0.0f) { animatingNoSoundProgress = 0.0f; animatingNoSound = 0; } invalidate(); } else if (animatingNoSound == 2) { animatingNoSoundProgress += animationDt / 180.0f; if (animatingNoSoundProgress >= 1.0f) { animatingNoSoundProgress = 1.0f; animatingNoSound = 0; } invalidate(); } float animatingToLoadingProgress = (buttonState == 1 || miniButtonState == 1) && loadingProgressLayout != null ? 1f : 0f; if (animatingToLoadingProgress == 0f && infoLayout != null && fullWidth) { animatingLoadingProgressProgress = 0f; } if (animatingLoadingProgressProgress < animatingToLoadingProgress) { animatingLoadingProgressProgress += animationDt / 160.0f; if (animatingLoadingProgressProgress > animatingToLoadingProgress) { animatingLoadingProgressProgress = animatingToLoadingProgress; } invalidate(); } else if (animatingLoadingProgressProgress != animatingToLoadingProgress) { animatingLoadingProgressProgress -= animationDt / 160.0f; if (animatingLoadingProgressProgress < animatingToLoadingProgress) { animatingLoadingProgressProgress = animatingToLoadingProgress; } invalidate(); } } } else if (currentMessageObject.type == MessageObject.TYPE_GEO) { if (docTitleLayout != null) { if (currentMessageObject.isOutOwner()) { Theme.chat_locationTitlePaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); Theme.chat_locationAddressPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outVenueInfoSelectedText : Theme.key_chat_outVenueInfoText)); } else { Theme.chat_locationTitlePaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); Theme.chat_locationAddressPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inVenueInfoSelectedText : Theme.key_chat_inVenueInfoText)); } if (MessageObject.getMedia(currentMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGeoLive) { int cy = (int) (photoImage.getImageY2() + dp(30)); if (!locationExpired || transitionParams.animateLocationIsExpired) { forceNotDrawTime = true; float progress; String text; StaticLayout docTitleLayout = this.docTitleLayout; StaticLayout infoLayout = this.infoLayout; float alpha = 1f; boolean forever = false; if (transitionParams.animateLocationIsExpired) { progress = transitionParams.lastDrawLocationExpireProgress; text = transitionParams.lastDrawLocationExpireText; docTitleLayout = transitionParams.lastDrawDocTitleLayout; infoLayout = transitionParams.lastDrawInfoLayout; alpha = 1f - transitionParams.animateChangeProgress; } else if (MessageObject.getMedia(currentMessageObject.messageOwner).period == 0x7fffffff) { forever = true; progress = 1.0f; text = ""; } else { progress = 1.0f - Math.abs(ConnectionsManager.getInstance(currentAccount).getCurrentTime() - currentMessageObject.messageOwner.date) / (float) MessageObject.getMedia(currentMessageObject.messageOwner).period; text = LocaleController.formatLocationLeftTime(Math.abs(MessageObject.getMedia(currentMessageObject.messageOwner).period - (ConnectionsManager.getInstance(currentAccount).getCurrentTime() - currentMessageObject.messageOwner.date))); } rect.set(photoImage.getImageX2() - dp(43), cy - dp(15), photoImage.getImageX2() - dp(13), cy + dp(15)); if (currentMessageObject.isOutOwner()) { Theme.chat_radialProgress2Paint.setColor(getThemedColor(Theme.key_chat_outInstant)); Theme.chat_livePaint.setColor(getThemedColor(Theme.key_chat_outInstant)); } else { Theme.chat_radialProgress2Paint.setColor(getThemedColor(Theme.key_chat_inInstant)); Theme.chat_livePaint.setColor(getThemedColor(Theme.key_chat_inInstant)); } int docTitleAlpha = Theme.chat_locationTitlePaint.getAlpha(); int infoAlpha = Theme.chat_locationAddressPaint.getAlpha(); int liveAplha = Theme.chat_livePaint.getAlpha(); if (alpha != 1f) { Theme.chat_locationTitlePaint.setAlpha((int) (docTitleAlpha * alpha)); Theme.chat_locationAddressPaint.setAlpha((int) (infoAlpha * alpha)); Theme.chat_livePaint.setAlpha((int) (liveAplha * alpha)); canvas.save(); canvas.translate(0, -dp(50) * transitionParams.animateChangeProgress); } Theme.chat_radialProgress2Paint.setAlpha((int) (50 * alpha)); canvas.drawCircle(rect.centerX(), rect.centerY(), dp(15), Theme.chat_radialProgress2Paint); Theme.chat_radialProgress2Paint.setAlpha((int) (255 * alpha)); canvas.drawArc(rect, -90, -360 * progress, false, Theme.chat_radialProgress2Paint); if (forever) { if (foreverDrawable == null) { foreverDrawable = getContext().getResources().getDrawable(R.drawable.filled_location_forever).mutate(); } if (Theme.chat_livePaint.getColor() != foreverDrawableColor) { foreverDrawable.setColorFilter(new PorterDuffColorFilter(foreverDrawableColor = Theme.chat_livePaint.getColor(), PorterDuff.Mode.SRC_IN)); } foreverDrawable.setBounds( (int) rect.centerX() - foreverDrawable.getIntrinsicWidth() / 2, (int) rect.centerY() - foreverDrawable.getIntrinsicHeight() / 2, (int) rect.centerX() + foreverDrawable.getIntrinsicWidth() / 2, (int) rect.centerY() + foreverDrawable.getIntrinsicHeight() / 2 ); foreverDrawable.draw(canvas); } else { float w = Theme.chat_livePaint.measureText(text); int len = text.length(); final float s2 = (len > 4 ? .75f : (len > 3 ? .85f : 1f)); canvas.save(); canvas.scale(s2, s2, rect.centerX(), rect.centerY()); canvas.drawText(text, rect.centerX() - w / 2, cy + dp(4), Theme.chat_livePaint); canvas.restore(); } if (docTitleLayout != null && infoLayout != null) { canvas.save(); canvas.translate(photoImage.getImageX() + dp(10), photoImage.getImageY2() + dp(10)); docTitleLayout.draw(canvas); canvas.translate(0, dp(23)); infoLayout.draw(canvas); canvas.restore(); } if (alpha != 1f) { Theme.chat_locationTitlePaint.setAlpha(docTitleAlpha); Theme.chat_locationAddressPaint.setAlpha(infoAlpha); Theme.chat_livePaint.setAlpha(liveAplha); canvas.restore(); } transitionParams.lastDrawLocationExpireProgress = progress; transitionParams.lastDrawLocationExpireText = text; transitionParams.lastDrawDocTitleLayout = docTitleLayout; transitionParams.lastDrawInfoLayout = infoLayout; } else { transitionParams.lastDrawLocationExpireText = null; transitionParams.lastDrawDocTitleLayout = null; transitionParams.lastDrawInfoLayout = null; } float progress = photoImage.isCrossfadingWithOldImage() ? 1 : photoImage.getCurrentAlpha(); if (progress > 0 && (photoImage.hasNotThumb() || photoImage.isCrossfadingWithOldImage())) { int cx = (int) (photoImage.getImageX() + photoImage.getImageWidth() / 2 - dp(31)); cy = (int) (photoImage.getImageY() + photoImage.getImageHeight() / 2 - dp(38) - dp(16) * (1f - CubicBezierInterpolator.EASE_OUT_BACK.getInterpolation(progress))); Drawable msgAvatarLiveLocation = sharedResources.getAvatarLiveLocation(); setDrawableBounds(msgAvatarLiveLocation, cx, cy); msgAvatarLiveLocation.setAlpha((int) (255 * Math.min(1, progress * 5))); msgAvatarLiveLocation.draw(canvas); locationImageReceiver.setImageCoords(cx + dp(5.0f), cy + dp(5.0f), dp(52), dp(52)); locationImageReceiver.setAlpha(Math.min(1, progress * 5)); locationImageReceiver.draw(canvas); } } else { canvas.save(); canvas.translate(photoImage.getImageX() + dp(6), photoImage.getImageY2() + dp(8)); docTitleLayout.draw(canvas); if (infoLayout != null) { canvas.translate(0, dp(21)); infoLayout.draw(canvas); } canvas.restore(); } } } else if (currentMessageObject.type == MessageObject.TYPE_PHONE_CALL) { Drawable icon; Drawable phone; int idx = currentMessageObject.isVideoCall() ? 1 : 0; if (currentMessageObject.isConferenceCall()) { if (currentMessageObject.isOutOwner()) { icon = Theme.chat_msgCallUpGreenDrawable; } else { icon = Theme.chat_msgCallDownRedDrawable; } if (groupCallDrawable == null) { groupCallDrawable = getContext().getResources().getDrawable(currentMessageObject.isVideoCall() ? R.drawable.filled_video_group : R.drawable.filled_calls_users).mutate(); } final int color = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outInstant : Theme.key_chat_inInstant); if (groupCallDrawableColor != color) { groupCallDrawable.setColorFilter(new PorterDuffColorFilter(groupCallDrawableColor = color, PorterDuff.Mode.SRC_IN)); } phone = groupCallDrawable; } else if (currentMessageObject.isOutOwner()) { icon = Theme.chat_msgCallUpGreenDrawable; if (currentMessageObject.isVideoCall()) { phone = getThemedDrawable(isDrawSelectionBackground() ? Theme.key_drawable_msgOutCallVideoSelected : Theme.key_drawable_msgOutCallVideo); } else { phone = getThemedDrawable(isDrawSelectionBackground() ? Theme.key_drawable_msgOutCallAudioSelected : Theme.key_drawable_msgOutCallAudio); } } else { TLRPC.PhoneCallDiscardReason reason = currentMessageObject.messageOwner.action.reason; if (reason instanceof TLRPC.TL_phoneCallDiscardReasonMissed || reason instanceof TLRPC.TL_phoneCallDiscardReasonBusy) { icon = Theme.chat_msgCallDownRedDrawable; } else { icon = Theme.chat_msgCallDownGreenDrawable; } phone = isDrawSelectionBackground() ? Theme.chat_msgInCallSelectedDrawable[idx] : Theme.chat_msgInCallDrawable[idx]; } if (currentMessageObject.isOutOwner()) { Theme.chat_audioTitlePaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); Theme.chat_contactPhonePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outTimeSelectedText : Theme.key_chat_outTimeText)); } else { Theme.chat_audioTitlePaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); Theme.chat_contactPhonePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inTimeSelectedText : Theme.key_chat_inTimeText)); } forceNotDrawTime = true; int x; if (currentMessageObject.isOutOwner()) { x = layoutWidth - backgroundWidth + dp(16); } else { if (needDrawAvatar()) { x = dp(74); } else { x = dp(25); } } otherX = x; if (LocaleController.isRTL) { x += phone.getIntrinsicWidth() + dp(12); } if (titleLayout != null) { canvas.save(); canvas.translate(x, dp(12) + namesOffset); titleLayout.draw(canvas); canvas.restore(); } if (docTitleLayout != null) { canvas.save(); canvas.translate(x + dp(LocaleController.isRTL ? -19 : 19), dp(37) + namesOffset); docTitleLayout.draw(canvas); canvas.restore(); } if (groupCallParticipantsText != null && groupCallParticipantsAvatars != null) { canvas.save(); canvas.translate(x + dp(LocaleController.isRTL ? -19 : 19) + docTitleWidth + dp(6), dp(36) + namesOffset); groupCallParticipantsAvatars.onDraw(canvas); canvas.translate(groupCallParticipantsAvatars.getMaxX() + dp(5), dp(8)); groupCallParticipantsText.draw(canvas, 0, 0, Theme.chat_contactPhonePaint.getColor(), 1.0f); canvas.restore(); } setDrawableBounds(icon, x + (LocaleController.isRTL && docTitleLayout != null ? docTitleLayout.getWidth() - icon.getIntrinsicWidth() : 0) - dp(1), dp(37) + namesOffset); icon.draw(canvas); if (selectorDrawable[0] != null && selectorDrawableMaskType[0] == 4) { selectorDrawable[0].draw(canvas); } if (!pinnedBottom && !pinnedTop) { otherY = dp(18.5f); } else if (pinnedBottom && pinnedTop) { otherY = dp(18); } else if (!pinnedBottom) { otherY = dp(17); } else { otherY = dp(19); } setDrawableBounds(phone, otherX + (LocaleController.isRTL ? 0 : backgroundWidth - dp(70)) + dp((idx == 0 ? 1 : 0)), otherY); phone.draw(canvas); } else if (currentMessageObject.type == MessageObject.TYPE_POLL) { long newTime = System.currentTimeMillis(); long dt = newTime - voteLastUpdateTime; if (dt > 17) { dt = 17; } voteLastUpdateTime = newTime; int color1; int color2; int linkColor; if (currentMessageObject.isOutOwner()) { color1 = getThemedColor(Theme.key_chat_messageTextOut); color2 = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outTimeSelectedText : Theme.key_chat_outTimeText); linkColor = getThemedColor(Theme.key_chat_messageLinkOut); } else { color1 = getThemedColor(Theme.key_chat_messageTextIn); color2 = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inTimeSelectedText : Theme.key_chat_inTimeText); linkColor = getThemedColor(Theme.key_chat_messageLinkIn); } Theme.chat_audioTitlePaint.setColor(color1); Theme.chat_audioPerformerPaint.linkColor = linkColor; Theme.chat_audioPerformerPaint.setColor(color1); Theme.chat_instantViewPaint.setColor(color1); Theme.chat_timePaint.setColor(color2); Theme.chat_livePaint.setColor(color2); Theme.chat_locationAddressPaint.setColor(color2); canvas.save(); final int targetExplanationHeight = currentMessageObject.expandedExplanation ? explanationHeight : 0; final float visualExplanationHeight; float animateExplanationOffset = 0; if (transitionParams.animateExpandedExplanation) { visualExplanationHeight = lerp( transitionParams.expandedExplanationFrom ? explanationHeight : 0f, targetExplanationHeight, transitionParams.animateChangeProgress); animateExplanationOffset = visualExplanationHeight - targetExplanationHeight; canvas.translate(0, animateExplanationOffset); } else { visualExplanationHeight = targetExplanationHeight; } if (transitionParams.animateNamesOffset) { canvas.translate(0, -namesOffset + lerp(transitionParams.animateNamesOffsetFrom, namesOffset, transitionParams.animateChangeProgress)); } else if (transitionParams.animateForwardedLayout) { float y = namesOffset * transitionParams.animateChangeProgress + transitionParams.animateForwardedNamesOffset * (1f - transitionParams.animateChangeProgress); if (currentMessageObject.needDrawForwarded()) { y -= namesOffset; } canvas.translate(0, y); } if (transitionParams.animateBackgroundBoundsInner) { canvas.translate(0, transitionParams.deltaTop); } float x; if (currentMessageObject.isOutOwner()) { x = layoutWidth - backgroundWidth + dp(11); } else { if (isSideMenuEnabled) { x = dp(20 + ChatActivity.SIDE_MENU_WIDTH); } else if (needDrawAvatar()) { x = dp(20 + 48); } else { x = dp(20); } } if (transitionParams.animateBackgroundBoundsInner) { x += transitionParams.deltaLeft; } float bwidth = backgroundWidth; if (transitionParams.animateBackgroundBoundsInner) { bwidth += transitionParams.deltaRight - transitionParams.deltaLeft; } final int pollButtonLeft = (int) (x - dp(9)); final int pollButtonRight = (int) (x + bwidth - dp(22)); if (visualExplanationHeight > dp(8)) { if (quoteLine == null) { quoteLine = new ReplyMessageLine(this); } AndroidUtilities.rectTmp.set(0, dp(5), bwidth - dp(23 + 10), visualExplanationHeight - dp(3)); AndroidUtilities.rectTmp.offset(x + dp(1), dp(10) + namesOffset + pollContentHeightWithOffset + captionHeight + targetExplanationHeight - visualExplanationHeight); quoteLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_LINK); quoteLine.drawBackground(canvas, AndroidUtilities.rectTmp, 5, 5, 5, 1, true, false); quoteLine.drawLine(canvas, AndroidUtilities.rectTmp, 1); if (explanationLayout != null) { final int c = Theme.chat_quoteTextPaint.getColor(); Theme.chat_quoteTextPaint.setColor(color1); canvas.save(); canvas.clipRect(AndroidUtilities.rectTmp); if (pollExplanationDrawable != null && pollExplanationDrawable.isHasMedia()) { final int dl = (int) AndroidUtilities.rectTmp.left + dp(10); final int dt2 = (int) (AndroidUtilities.rectTmp.top + (explanationHeight - dp(8))) - explanationContentHeight - dp(8); pollExplanationDrawable.setBounds(dl, dt2, dl + explanationContentWidth, dt2 + explanationContentHeight); pollExplanationDrawable.checkColors(currentMessageObject.isOut()); pollExplanationDrawable.setColors(color2, color1, color2, getThemedColor(currentMessageObject.isOut() ? Theme.key_chat_outLoader : Theme.key_chat_inLoader)); pollExplanationDrawable.draw(canvas); } if (explanationTitleLayout != null) { final int color = Theme.chat_replyNamePaint.getColor(); Theme.chat_replyNamePaint.setColor(quoteLine.getColor()); canvas.save(); canvas.translate(AndroidUtilities.rectTmp.left + dp(10), AndroidUtilities.rectTmp.top + dp(6)); explanationTitleLayout.draw(canvas); canvas.restore(); Theme.chat_replyNamePaint.setColor(color); if (closeExplanationDrawable != null) { if (closeExplanationDrawableColor != quoteLine.getColor()) { closeExplanationDrawableColor = quoteLine.getColor(); closeExplanationDrawable.setColorFilter(new PorterDuffColorFilter(closeExplanationDrawableColor, PorterDuff.Mode.SRC_IN)); } closeExplanationX = (int) AndroidUtilities.rectTmp.right - dp(16.33f); closeExplanationY = (int) AndroidUtilities.rectTmp.top + dp(16.33f); canvas.save(); canvas.scale(0.85f, 0.85f, closeExplanationX, closeExplanationY); final int xd = closeExplanationX - closeExplanationDrawable.getIntrinsicWidth() / 2; final int yd = closeExplanationY - closeExplanationDrawable.getIntrinsicHeight() / 2; closeExplanationDrawable.setBounds(xd, yd, xd + closeExplanationDrawable.getIntrinsicWidth(), yd + closeExplanationDrawable.getIntrinsicHeight() ); closeExplanationDrawable.draw(canvas); canvas.restore(); } } Theme.chat_explanationTextPaint.setColor(Theme.chat_quoteTextPaint.getColor()); Theme.chat_explanationTextPaint.linkColor = linkColor; drawMessageText(lastDrawExplanationX = (AndroidUtilities.rectTmp.left + dp(10)), lastDrawExplanationY = (AndroidUtilities.rectTmp.top + dp(25)), canvas, explanationLayout.textLayoutBlocks, explanationLayout.textXOffset, true, 1, true, false, false, true); drawAnimatedEmojiMessageText(AndroidUtilities.rectTmp.left + dp(10), AndroidUtilities.rectTmp.top + dp(25), canvas, explanationLayout.textLayoutBlocks, animatedEmojiPollExplanation, true, 1, explanationLayout.textXOffset, true); canvas.restore(); Theme.chat_quoteTextPaint.setColor(c); } } int titleLayoutHeight = 0; if (titleLayout != null) { canvas.save(); canvas.translate(x + getExtraTextX(), dp(15) + namesOffset + pollContentHeightWithOffset + captionHeight + targetExplanationHeight); int oldAlpha = Theme.chat_audioTitlePaint.getAlpha(); if (transitionParams.animateTitleLayout != null) { Theme.chat_audioTitlePaint.setAlpha((int) (transitionParams.animateChangeProgress * oldAlpha)); } titleLayout.draw(canvas); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, titleLayout, animatedEmojiPollQuestion, 0, null, 0, 0, 0, transitionParams.animateTitleLayout != null ? transitionParams.animateChangeProgress : 1.0f, getAdaptiveEmojiColorFilter(1, titleLayout.getPaint().getColor())); if (transitionParams.animateTitleLayout != null) { Theme.chat_audioTitlePaint.setAlpha(oldAlpha); } titleLayoutHeight = titleLayout.getHeight(); if (transitionParams.animateTitleLayout != null) { Theme.chat_audioTitlePaint.setAlpha((int) ((1.0f - transitionParams.animateChangeProgress) * oldAlpha)); transitionParams.animateTitleLayout.draw(canvas); Theme.chat_audioTitlePaint.setAlpha(oldAlpha); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, transitionParams.animateTitleLayout, transitionParams.animateTitleLayoutEmoji, 0, null, 0, 0, 0, 1.0f - transitionParams.animateChangeProgress, getAdaptiveEmojiColorFilter(1, transitionParams.animateTitleLayout.getPaint().getColor())); titleLayoutHeight = AndroidUtilities.lerp(transitionParams.animateTitleLayout.getHeight(), titleLayoutHeight, transitionParams.animateChangeProgress); } canvas.restore(); } if (pollContentDrawable != null && pollContentDrawable.isHasMedia()) { final int y = dp(namesOffset > 0 ? 11 : 5) + namesOffset - (int) animateExplanationOffset; final int x1 = (int) x - dp(9) + dp(2); pollContentDrawable.setBounds(x1, y, x1 + pollContentWidth, y + pollContentHeight); pollContentDrawable.checkColors(currentMessageObject.isOut()); pollContentDrawable.setColors(color2, color1, color2, getThemedColor(currentMessageObject.isOut() ? Theme.key_chat_outLoader : Theme.key_chat_inLoader)); pollContentDrawable.draw(canvas); } int y = titleLayoutHeight + dp(20) + namesOffset + pollContentHeightWithOffset + captionHeight + targetExplanationHeight; if (docTitleLayout != null) { canvas.save(); canvas.translate(x + docTitleOffsetX + getExtraTextX(), y); docTitleLayout.draw(canvas); canvas.restore(); TLRPC.MessageMedia m = MessageObject.getMedia(currentMessageObject.messageOwner); if (m instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll media = (TLRPC.TL_messageMediaPoll) m; if (media.poll.quiz && (pollVoted || pollClosed || pollResultsPreview || (pollHasVoteRestrictions && (!pollHideResults || pollHasResults))) && !TextUtils.isEmpty(media.results.solution)) { Drawable drawable = getThemedDrawable(currentMessageObject.isOutOwner() ? Theme.key_drawable_chat_pollHintDrawableOut : Theme.key_drawable_chat_pollHintDrawableIn); if (pollVoteInProgress) { drawable.setAlpha((int) (255 * pollAnimationProgress)); } else { drawable.setAlpha(255); } pollHintX = (int) (x + bwidth - dp(23) - drawable.getIntrinsicWidth() - dp(8)); pollHintY = y - dp(6); int cx = pollHintX + drawable.getIntrinsicWidth() / 2; int cy = pollHintY + drawable.getIntrinsicHeight() / 2; float scale = hintButtonVisible && hintButtonProgress < 1 ? AnimationProperties.overshootInterpolator.getInterpolation(hintButtonProgress) : hintButtonProgress; int w = (int) (drawable.getIntrinsicWidth() * scale); int h = (int) (drawable.getIntrinsicHeight() * scale); drawable.setBounds(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2); drawable.draw(canvas); } else { pollHintX = -1; } } else { pollHintX = -1; } if (pollRecentVotersDrawable != null && !isBot) { int toAdd; float ax; int lineLeft = (int) Math.ceil(docTitleLayout.getLineLeft(0)); if (docTitleOffsetX != 0 || lineLeft != 0) { toAdd = -dp(13); if (docTitleOffsetX != 0) { ax = x + docTitleOffsetX - dp(7 + 16) - getExtraTextX(); } else { ax = x + lineLeft - dp(7 + 16) - getExtraTextX(); } } else { toAdd = dp(13); ax = x + (int) Math.ceil(docTitleLayout.getLineWidth(0)) + dp(7) + getExtraTextX(); } if (animatePollAvatars && animatePollAnswerAlpha) { pollRecentVotersDrawable.setAlpha((int) (255 * MathUtils.clamp(pollUnvoteInProgress ? (1.0f - pollAnimationProgress) / 0.3f : pollAnimationProgress, 0f, 1.0f))); } else { pollRecentVotersDrawable.setAlpha(255); } pollRecentVotersDrawable.setBounds((int) ax, y - dp(1), (int) (ax + pollRecentVotersDrawable.getAnimatedWidth()), y - dp(1) + dp(16)); pollRecentVotersDrawable.draw(canvas, currentBackgroundDrawable.getPaint()); } } if ((!pollClosed && !pollVoted && !pollResultsPreview || pollVoteInProgress) && lastPoll != null && lastPoll.quiz && lastPoll.close_period != 0 && isBot) { long currentTime = ConnectionsManager.getInstance(currentAccount).getCurrentTimeMillis(); long time = Math.max(0, ((long) lastPoll.close_date) * 1000 - currentTime); if (closeTimeText == null || lastPollCloseTime != time) { closeTimeText = AndroidUtilities.formatDurationNoHours((int) Math.ceil(time / 1000.0f), false); closeTimeWidth = (int) Math.ceil(Theme.chat_timePaint.measureText(closeTimeText)); lastPollCloseTime = time; } if (time <= 0 && !pollClosed) { if (currentMessageObject.pollLastCheckTime + 1000 < SystemClock.elapsedRealtime()) { currentMessageObject.pollLastCheckTime = 0; } delegate.needReloadPolls(); } int tx = currentBackgroundDrawable.getBounds().right - closeTimeWidth - dp(currentMessageObject.isOutOwner() ? 40 : 34); if (time <= 5000) { Theme.chat_timePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPollWrongAnswer : Theme.key_chat_inPollWrongAnswer)); } if (animatePollAnswer) { Theme.chat_timePaint.setAlpha((int) (255 * (1.0f - pollAnimationProgress))); } canvas.drawText(closeTimeText, tx, y + dp(11), Theme.chat_timePaint); Theme.chat_pollTimerPaint.setColor(Theme.chat_timePaint.getColor()); tx += closeTimeWidth + dp(13); int rad = dp(5.1f); int ty = y + dp(6); if (time <= 60000) { rect.set(tx - rad, ty - rad, tx + rad, ty + rad); float radProgress = -360 * (time / (Math.min(60, lastPoll.close_period) * 1000.0f)); canvas.drawArc(rect, -90, radProgress, false, Theme.chat_pollTimerPaint); timerParticles.draw(canvas, Theme.chat_pollTimerPaint, rect, radProgress, pollVoteInProgress ? (1.0f - pollAnimationProgress) : 1.0f); } else { canvas.drawCircle(tx, ty, rad, Theme.chat_pollTimerPaint); } if (time > 60000 || timerTransitionProgress != 0.0f) { Theme.chat_pollTimerPaint.setAlpha((int) (255 * timerTransitionProgress)); canvas.drawLine(tx - dp(2.1f) * timerTransitionProgress, ty - dp(7.5f), tx + dp(2.1f) * timerTransitionProgress, ty - dp(7.5f), Theme.chat_pollTimerPaint); canvas.drawLine(tx, ty - dp(3) * timerTransitionProgress, tx, ty, Theme.chat_pollTimerPaint); if (time <= 60000) { timerTransitionProgress -= dt / 180.0f; if (timerTransitionProgress < 0) { timerTransitionProgress = 0; } } } invalidate(); } if (selectorDrawable[0] != null && (selectorDrawableMaskType[0] == 1 || selectorDrawableMaskType[0] == 3)) { if (selectorDrawableMaskType[0] == 3) { canvas.save(); canvas.scale(hintButtonProgress, hintButtonProgress, selectorDrawable[0].getBounds().centerX(), selectorDrawable[0].getBounds().centerY()); } selectorDrawable[0].draw(canvas); if (selectorDrawableMaskType[0] == 3) { canvas.restore(); } } final boolean todo = currentMessageObject.isTodo(); final boolean multipleChoice = lastPoll != null && lastPoll.multiple_choice; final boolean todoAllowed = todo && currentMessageObject.canCompleteTodo(); final boolean isVotedButHiddenResults = pollVoted && !pollHasResults && pollHideResults; final int buttonAlpha = (int) (animatePollAnswerAlpha && !isVotedButHiddenResults ? 255 * Math.min((pollUnvoteInProgress ? 1.0f - pollAnimationProgress : pollAnimationProgress) / 0.3f, 1.0f) : 255); for (int a = Math.max(firstVisiblePollButton, 0); a <= Math.min(lastVisiblePollButton == -1 ? Integer.MAX_VALUE : lastVisiblePollButton, pollButtons.size() - 1); a++) { PollButton button = pollButtons.get(a); button.x = (int) x; int by = button.y, bh = button.height; if (button.animateTitle != null) { by = AndroidUtilities.lerp(button.animateY, by, transitionParams.animateChangeProgress); bh = AndroidUtilities.lerp(button.animateHeight, bh, transitionParams.animateChangeProgress); } if (button.task != null && button.task.id == doNotDrawTaskId) { continue; } if (drawOnlyPollId != null && !Arrays.equals(button.answer.option, drawOnlyPollId)) { continue; } if (button.answer != null && button.answer.option != null && Arrays.equals(button.answer.option, doNotDrawPollId)) { continue; } canvas.save(); int selectorColor = Theme.multAlpha(color2, 0.12f); if (button.selectorDrawableColor != selectorColor) { Theme.setSelectorDrawableColor(button.selectorDrawable, button.selectorDrawableColor = selectorColor, false); } button.selectorDrawable.setBounds((int) (x - dp(8)), (int) (by + namesOffset - dp(13)), (int) (x + bwidth - dp(23)), (int) (by + namesOffset + bh + dp(13))); button.selectorDrawable.draw(canvas); canvas.restore(); if (button.pollButtonDrawable != null) { button.pollButtonDrawable.setBounds( pollButtonLeft, by + namesOffset - dp(13), pollButtonRight, by + namesOffset + bh + dp(13)); button.pollButtonDrawable.setVotersCountTextColor(color1); button.pollButtonDrawable.draw(canvas, currentBackgroundDrawable.getPaint()); } canvas.save(); button.titleX = x + dp(todoAllowed ? 48 : 35); button.titleY = by + namesOffset; canvas.translate(x + dp(todoAllowed ? 48 : 35), by + namesOffset); if (transitionParams.animateBackgroundBoundsInner) { canvas.translate(0, transitionParams.deltaTop); } int oldAlpha3 = Theme.chat_audioPerformerPaint.getAlpha(); if (button.animateTitle != null) { Theme.chat_audioPerformerPaint.setAlpha((int) (oldAlpha3 * transitionParams.animateChangeProgress)); } canvas.save(); if (todo && todoAllowed && button.author != null && pollCheckBox[a] != null) { final float progress = pollCheckBox[a].getProgress(); canvas.translate(0, -dp(7.66f) * progress); button.titleY += -dp(7.66f) * progress; } if (a == linkBlockNum && links.draw(canvas, 4)) { invalidate(); } if (button.moveTitleByCounter && button.pollButtonDrawable != null) { canvas.translate(-button.pollButtonDrawable.getVotersCountAnimatedWidth(dp(7)), 0); } button.title.draw(canvas); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, button.title, button.animatedEmoji, 0, null, 0, 0, 0, button.animateTitle != null ? transitionParams.animateChangeProgress : 1.0f, getAdaptiveEmojiColorFilter(1, button.title.getPaint().getColor())); if (button.animateTitle != null) { Theme.chat_audioPerformerPaint.setAlpha((int) (oldAlpha3 * (1.0f - transitionParams.animateChangeProgress))); button.animateTitle.draw(canvas); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, button.animateTitle, button.animateTitleEmoji, 0, null, 0, 0, 0, 1.0f - transitionParams.animateChangeProgress, getAdaptiveEmojiColorFilter(1, button.animateTitle.getPaint().getColor())); Theme.chat_audioPerformerPaint.setAlpha(oldAlpha3); } canvas.restore(); if (todo && todoAllowed && button.author != null && pollCheckBox[a] != null) { final float progress = pollCheckBox[a].getProgress(); if (progress > 0.0f) { button.author .ellipsize(bwidth - dp(8)) .draw(canvas, 0, button.title.getHeight() - dp(6) + button.author.getHeight() / 2f, color2, progress); } } Theme.chat_audioPerformerPaint.setAlpha(oldAlpha3); if (!todo && (pollVoted && (pollHasResults || !pollHideResults) || pollClosed || pollResultsPreview || (pollHasVoteRestrictions && (!pollHideResults || pollHasResults)) || animatePollAnswerAlpha && !isVotedButHiddenResults)) { if (lastPoll != null && lastPoll.quiz/* && pollVoted*/) { int key; if (button.correct) { key = currentMessageObject.isOutOwner() ? Theme.key_chat_outPollCorrectAnswer : Theme.key_chat_inPollCorrectAnswer; } else { key = currentMessageObject.isOutOwner() ? Theme.key_chat_outPollWrongAnswer : Theme.key_chat_inPollWrongAnswer; } if (!currentBackgroundDrawable.hasGradient() || Theme.hasThemeKey(key)) { Theme.chat_docBackPaint.setColor(getThemedColor(key)); } else { Theme.chat_docBackPaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outAudioSeekbarFill : Theme.key_chat_inAudioSeekbarFill)); } } else { Theme.chat_docBackPaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outAudioSeekbarFill : Theme.key_chat_inAudioSeekbarFill)); } if (animatePollAnswerAlpha && !isVotedButHiddenResults) { float oldAlpha = Theme.chat_instantViewPaint.getAlpha() / 255.0f; Theme.chat_instantViewPaint.setAlpha((int) (buttonAlpha * oldAlpha)); oldAlpha = Theme.chat_docBackPaint.getAlpha() / 255.0f; Theme.chat_docBackPaint.setAlpha((int) (buttonAlpha * oldAlpha)); } final boolean drawChosenCheckbox = button.chosen || button.prevChosen || lastPoll != null && lastPoll.quiz && button.correct && (pollVoted || pollClosed || pollResultsPreview || (pollHasVoteRestrictions && (!pollHideResults || pollHasResults))); int currentPercent = MathUtils.clamp((int) Math.ceil(button.prevPercent + (button.percent - button.prevPercent) * pollAnimationProgress), 0, 100); String text = String.format("%d%%", currentPercent); int width = (int) Math.ceil(Theme.chat_instantViewPaint.measureText(text)); canvas.drawText(text, -dp(6.5f) - width, dp(14) + (drawChosenCheckbox && button.title != null && button.title.getLineCount() < 2 ? resultsPollButtonOffset : 0), Theme.chat_instantViewPaint); width = backgroundWidth - dp(76); float currentPercentProgress = button.prevPercentProgress + (button.percentProgress - button.prevPercentProgress) * pollAnimationProgress; if (!isVotedButHiddenResults) { final int lineColor = Theme.chat_docBackPaint.getColor(); final int lineAlpha = Color.alpha(lineColor); final float lineWidth = width - (pollWithMediaInAnswers ? dp(37.33f) : 0); Theme.chat_docBackPaint.setColor(ColorUtils.setAlphaComponent(color1, 16 * lineAlpha / 255)); rect.set(Math.max(lineWidth * currentPercentProgress - dp(2), 0), bh + dp(6), lineWidth, bh + dp(11)); canvas.drawRoundRect(rect, dp(2), dp(2), Theme.chat_docBackPaint); Theme.chat_docBackPaint.setColor(lineColor); rect.set(0, bh + dp(6), lineWidth * currentPercentProgress, bh + dp(11)); canvas.drawRoundRect(rect, dp(2), dp(2), Theme.chat_docBackPaint); } if (drawChosenCheckbox) { float cx = rect.left - dp(15.5f); float cy = rect.centerY() + resultsPollButtonOffset; float s = dp(7); float r = dp(multipleChoice ? 4.5f : 7); canvas.saveLayerAlpha(cx - s, cy - s, cx + s, cy + s, buttonAlpha); Drawable drawable; if (lastPoll != null && lastPoll.quiz && !button.correct) { drawable = Theme.chat_pollCrossDrawable[currentMessageObject.isOutOwner() ? 1 : 0]; } else { drawable = Theme.chat_pollCheckDrawable[currentMessageObject.isOutOwner() ? 1 : 0]; } setDrawableBounds(drawable, cx - drawable.getIntrinsicWidth() / 2, cy - drawable.getIntrinsicHeight() / 2); drawable.draw(canvas); if (srcOutPaint == null) { srcOutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); srcOutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); } srcOutPaint.setColor(Theme.chat_docBackPaint.getColor()); canvas.drawRoundRect(cx - s, cy - s, cx + s, cy + s, r, r, srcOutPaint); canvas.restore(); } } if (todo || !pollVoted && !pollClosed && !pollResultsPreview && !(pollHasVoteRestrictions && (!pollHideResults || pollHasResults)) || isVotedButHiddenResults || animatePollAnswerAlpha) { if (isDrawSelectionBackground()) { Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outVoiceSeekbarSelected : Theme.key_chat_inVoiceSeekbarSelected)); } else { Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outVoiceSeekbar : Theme.key_chat_inVoiceSeekbar)); } if (animatePollAnswerAlpha && !isVotedButHiddenResults) { float oldAlpha = Theme.chat_replyLinePaint.getAlpha() / 255.0f; Theme.chat_replyLinePaint.setAlpha((int) ((255 - buttonAlpha) * oldAlpha)); } canvas.drawLine(-dp(2), bh + dp(13), bwidth - dp(todoAllowed ? 71 : 58), bh + dp(13), Theme.chat_replyLinePaint); if (todo && !todoAllowed) { if (button.chosen) { if (pollCheckPath == null) { pollCheckPath = new Path(); pollCheckPath.moveTo(-dp(3.66f), dp(.16f)); pollCheckPath.lineTo(dp(-1), dp(3)); pollCheckPath.lineTo(dp(3.66f), dp(-3)); } if (pollCheckPaint == null) { pollCheckPaint = new Paint(Paint.ANTI_ALIAS_FLAG); pollCheckPaint.setStyle(Paint.Style.STROKE); pollCheckPaint.setStrokeCap(Paint.Cap.ROUND); pollCheckPaint.setStrokeJoin(Paint.Join.ROUND); } pollCheckPaint.setStrokeWidth(dp(1.833f)); pollCheckPaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outAudioSeekbarFill : Theme.key_chat_inAudioSeekbarFill)); canvas.save(); canvas.translate(-dp(todoAllowed ? 35 : 22), dp(9)); canvas.drawPath(pollCheckPath, pollCheckPaint); canvas.restore(); } else { Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outAudioSeekbarFill : Theme.key_chat_inAudioSeekbarFill)); canvas.drawCircle(-dp(todoAllowed ? 35 : 22), dp(9), dp(2.5f), Theme.chat_replyLinePaint); } } else if (!todo && pollVoteInProgress && a == pollVoteInProgressNum && !isVotedButHiddenResults) { Theme.chat_instantViewRectPaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outAudioSeekbarFill : Theme.key_chat_inAudioSeekbarFill)); if (animatePollAnswerAlpha && !isVotedButHiddenResults) { float oldAlpha = Theme.chat_instantViewRectPaint.getAlpha() / 255.0f; Theme.chat_instantViewRectPaint.setAlpha((int) ((255 - buttonAlpha) * oldAlpha)); } rect.set(-dp(todoAllowed ? 35 : 22) - dp(8.5f), dp(9) - dp(8.5f), -dp(23) + dp(8.5f), dp(9) + dp(8.5f)); canvas.drawArc(rect, voteRadOffset, voteCurrentCircleLength, false, Theme.chat_instantViewRectPaint); } else if (!(pollHasVoteRestrictions && (!pollHideResults || pollHasResults))) { if (currentMessageObject.isOutOwner()) { Theme.chat_instantViewRectPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outMenuSelected : Theme.key_chat_outMenu)); } else { Theme.chat_instantViewRectPaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inMenuSelected : Theme.key_chat_inMenu)); } if (animatePollAnswerAlpha && !isVotedButHiddenResults) { float oldAlpha = Theme.chat_instantViewRectPaint.getAlpha() / 255.0f; Theme.chat_instantViewRectPaint.setAlpha((int) ((255 - buttonAlpha) * oldAlpha)); } { final float cx = -dp(todoAllowed ? 35 : 22); final float cy = dp(9); final float r = dp(multipleChoice ? 8f : 8.5f); if (multipleChoice) { canvas.drawRoundRect(cx - r, cy - r, cx + r, cy + r, dp(4), dp(4), Theme.chat_instantViewRectPaint); } else { canvas.drawCircle(cx, cy, r, Theme.chat_instantViewRectPaint); } } if (multipleChoice || isVotedButHiddenResults || todo) { int size = dp(multipleChoice ? 8f : 8.5f); int key = Theme.key_checkboxCheck; if (currentMessageObject.isOutOwner()) { if (getThemedColor(key) == 0xffffffff) { key = Theme.key_chat_outBubble; } } pollCheckBox[a].setColor(-1, currentMessageObject.isOutOwner() ? Theme.key_chat_outAudioSeekbarFill : Theme.key_chat_inAudioSeekbarFill, key); pollCheckBox[a].setBounds(-dp(todoAllowed ? 35 : 22) - size / 2, dp(9) - size / 2, size, size); pollCheckBox[a].setCustomRadius(multipleChoice ? dp(5) : 0); pollCheckBox[a].setSize(multipleChoice ? 19 : 20); pollCheckBox[a].draw(canvas); if (button.task != null && button.avatarImageReceiver != null) { if (pollCutAvatarPaint == null) { pollCutAvatarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); pollCutAvatarPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); } final float avatarAlpha = pollCheckBox[a].getProgress(); final float avatarScale = lerp(.5f, 1.f, avatarAlpha); button.avatarImageReceiver.setImageCoords(-dp(todoAllowed ? 35 : 22) - size / 2 + dp(8), dp(9) - dp(20) / 2, dp(20), dp(20)); canvas.saveLayerAlpha(button.avatarImageReceiver.getImageX(), button.avatarImageReceiver.getImageY(), button.avatarImageReceiver.getImageX2(), button.avatarImageReceiver.getImageY2(), 0xFF, Canvas.ALL_SAVE_FLAG); canvas.save(); canvas.scale(avatarScale, avatarScale, button.avatarImageReceiver.getImageX(), button.avatarImageReceiver.getCenterY()); button.avatarImageReceiver.setAlpha(avatarAlpha); button.avatarImageReceiver.draw(canvas); canvas.restore(); canvas.drawCircle(-dp(todoAllowed ? 35 : 22), dp(9), dp(11), pollCutAvatarPaint); canvas.restore(); } } } } canvas.restore(); } int lastVoteY = 0; if (!pollButtons.isEmpty()) { final PollButton btn = pollButtons.get(pollButtons.size() - 1); int by = btn.y, bh = btn.height; if (btn.animateTitle != null) { by = AndroidUtilities.lerp(btn.animateY, by, transitionParams.animateChangeProgress); bh = AndroidUtilities.lerp(btn.animateHeight, bh, transitionParams.animateChangeProgress); } lastVoteY = namesOffset + by + bh; } final int pollAddButtonAnimatedHeight; if (pollAllowAdding) { pollAddButtonAnimatedHeight = transitionParams.animatePollAddOptionHeight ? lerp(transitionParams.animatePollAddOptionHeightFrom, pollAddButtonHeight, transitionParams.animateChangeProgress) : pollAddButtonHeight; } else { pollAddButtonAnimatedHeight = 0; } if (pollAllowAdding && pollAddButtonDrawable != null) { int by = lastVoteY + dp(13); int bh = dp(44.33f); pollAddButtonDrawable.setTextColor((lastPoll != null && !lastPoll.public_voters && !lastPoll.multiple_choice ? Theme.chat_livePaint : Theme.chat_locationAddressPaint).getColor()); pollAddButtonDrawable.setBounds(pollButtonLeft, by, pollButtonRight, by + bh); pollAddButtonDrawable.draw(canvas); if (delegate != null) { canvas.save(); canvas.translate(pollButtonLeft, by); delegate.drawPollMode(canvas, this); canvas.restore(); } if (!pollVoted && !pollClosed && !pollResultsPreview || isVotedButHiddenResults || animatePollAnswerAlpha) { final int oldPaintColor = Theme.chat_replyLinePaint.getColor(); if (isDrawSelectionBackground()) { Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outVoiceSeekbarSelected : Theme.key_chat_inVoiceSeekbarSelected)); } else { Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outVoiceSeekbar : Theme.key_chat_inVoiceSeekbar)); } if (animatePollAnswerAlpha && !isVotedButHiddenResults) { float oldAlpha = Theme.chat_replyLinePaint.getAlpha() / 255.0f; Theme.chat_replyLinePaint.setAlpha((int) ((255 - buttonAlpha) * oldAlpha)); } canvas.drawLine(x + dp(35) - dp(2), by + pollAddButtonAnimatedHeight, x + dp(35) + bwidth - dp(58), by + pollAddButtonAnimatedHeight, Theme.chat_replyLinePaint); Theme.chat_replyLinePaint.setColor(oldPaintColor); } } if (pollAllowAdding) { lastVoteY += pollAddButtonAnimatedHeight; } final float progressVisibility = pollInstantButtonDrawable != null ? pollInstantButtonDrawable.getProgressFactor() : 0; final float timerVisibility = !todo && animatedInfoLayout2 != null && animatedInfoLayout2.isVisible() ? 1 : 0; final float instantViewVisibility = drawInstantView ? 1 : 0; if (drawInstantView) { int textX = getCurrentBackgroundLeft() + dp(currentMessageObject.isOutOwner() || mediaBackground || drawPinnedBottom ? 2 : 8); int instantY = lastVoteY + dp(13); if (currentMessageObject.isOutOwner()) { Theme.chat_instantViewPaint.setColor(getThemedColor(Theme.key_chat_outPreviewInstantText)); } else { Theme.chat_instantViewPaint.setColor(getThemedColor(Theme.key_chat_inPreviewInstantText)); } instantButtonRect.set(textX, instantY, textX + instantWidth, instantY + dp(44)); if (selectorDrawable[0] != null && selectorDrawableMaskType[0] == 2) { selectorDrawable[0].setBounds(textX - dp(pollInstantViewTouchesBottom ? 6 : 0), instantY, textX + instantWidth, instantY + dp(44)); selectorDrawable[0].draw(canvas); } if (currentMessageObject.isPoll() && pollInstantButtonDrawable != null) { pollInstantButtonDrawable.setButtonTextColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewInstantText : Theme.key_chat_inPreviewInstantText)); pollInstantButtonDrawable.setBounds(pollButtonLeft, instantY, pollButtonRight, instantY + dp(44)); pollInstantButtonDrawable.setTextOffsetY(-dp(7) * timerVisibility); pollInstantButtonDrawable.draw(canvas); } else if (instantViewLayout != null) { canvas.save(); canvas.translate(textX + instantTextX, instantY + dp(14.5f)); instantViewLayout.draw(canvas); canvas.restore(); } } else { if (animatedInfoLayout != null) { final float lvy = lastVoteY + dp(13 + 6 + 6) + dp(6) * (1f - timerVisibility); if (lastPoll != null && (lastPoll.public_voters || lastPoll.multiple_choice)) { // lastVoteY += dp(6); } canvas.save(); if (transitionParams.animateBackgroundBoundsInner) { canvas.translate(((getBackgroundDrawableLeft() + transitionParams.deltaLeft) + (getBackgroundDrawableRight() + transitionParams.deltaRight)) / 2.0f, lvy); } else { canvas.translate((getBackgroundDrawableLeft() + getBackgroundDrawableRight()) / 2.0f, lvy); } animatedInfoLayout.setBounds(-1, -1, 1, 1); animatedInfoLayout.setTextColor((lastPoll != null && !lastPoll.public_voters && !lastPoll.multiple_choice ? Theme.chat_livePaint : Theme.chat_locationAddressPaint).getColor()); animatedInfoLayout.draw(canvas); canvas.restore(); } } if (!todo && animatedInfoLayout2 != null) { final float lvy = lastVoteY + dp(13 + 6 + 6 + 16) + dp(6) * (1f - timerVisibility) + (dp(3) * instantViewVisibility); canvas.save(); if (transitionParams.animateBackgroundBoundsInner) { canvas.translate(((getBackgroundDrawableLeft() + transitionParams.deltaLeft) + (getBackgroundDrawableRight() + transitionParams.deltaRight)) / 2.0f, lvy); } else { canvas.translate((pollButtonLeft + pollButtonRight) / 2.0f, lvy); } animatedInfoLayout2.setBounds(-1, -1, 1, 1); animatedInfoLayout2.setTextColor((lastPoll != null && !lastPoll.public_voters && !lastPoll.multiple_choice ? Theme.chat_livePaint : Theme.chat_locationAddressPaint).getColor()); DrawableUtils.drawWithScale(canvas, animatedInfoLayout2, 1f - progressVisibility); canvas.restore(); } updatePollAnimations(dt); canvas.restore(); if (progressVisibility >= 1f) { checkPollVoteSendingStatus(true); } if (quoteHighlight != null && (quoteHighlight.todo || quoteHighlight.poll)) { MessageDrawable backgroundDrawable = currentBackgroundDrawable; if (backgroundDrawable != null) { canvas.save(); canvas.clipPath(backgroundDrawable.makePath()); quoteHighlight.paint.setColor(Theme.multAlpha(getThemedColor(currentMessageObject != null && currentMessageObject.isOutOwner() && !currentMessageObject.preview ? Theme.key_chat_outReplyLine : Theme.key_chat_inReplyLine), Theme.isCurrentThemeDark() ? .2f : .2f)); quoteHighlight.draw(canvas, textX, textY, backgroundDrawable.getBounds(), getHighlightAlpha(true)); canvas.restore(); } } } else if (currentMessageObject.type == MessageObject.TYPE_CONTACT) { drawContact(canvas); } if (drawImageButton && photoImage.getVisible() && !isSmallImage && !currentMessageObject.isRepostVideoPreview) { if (controlsAlpha != 1.0f) { radialProgress.setOverrideAlpha(controlsAlpha); } if (photoImage.hasImageSet()) { radialProgress.setBackgroundDrawable(null); } else { radialProgress.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); } boolean restore = false; boolean on = false; if (currentMessageObject != null && currentMessageObject.isRoundVideo() && (!currentMessageObject.mediaExists() || currentMessageObject.isRoundOnce())) { radialProgress.setProgressRect( photoImage.getImageX() + (photoImage.getImageWidth() / 2f - radialProgress.getRadius()), photoImage.getImageY() + (photoImage.getImageHeight() / 2f - radialProgress.getRadius()), photoImage.getImageX() + (photoImage.getImageWidth() / 2f + radialProgress.getRadius()), photoImage.getImageY() + (photoImage.getImageHeight() / 2f + radialProgress.getRadius()) ); } else if (currentMessageObject != null && currentMessageObject.isRoundVideo()) { radialProgress.setProgressRect( photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX() + photoImage.getImageWidth(), photoImage.getImageY() + photoImage.getImageHeight() ); canvas.saveLayerAlpha(radialProgress.getProgressRect(), (int) (255 * getVideoTranscriptionProgress()), Canvas.ALL_SAVE_FLAG); float scale = photoImage.getImageHeight() / (radialProgress.getRadius() * 2); canvas.scale(scale, scale, radialProgress.getProgressRect().centerX(), radialProgress.getProgressRect().centerY()); restore = true; } if ( (!isRoundVideo || !hasLinkPreview) && (!currentMessageObject.needDrawBluredPreview() || !MediaController.getInstance().isPlayingMessage(currentMessageObject)) && !(currentMessageObject.hasMediaSpoilers() && (!currentMessageObject.isMediaSpoilersRevealed || !currentMessageObject.revealingMediaSpoilers) && SharedConfig.isAutoplayVideo() && !currentMessageObject.isRepostPreview && currentMessagesGroup == null && (radialProgress.getIcon() == MediaActionDrawable.ICON_PLAY || radialProgress.getIcon() == MediaActionDrawable.ICON_NONE)) && !currentMessageObject.isHiddenSensitive() ) { if (currentMessageObject.needDrawBluredPreview()) { radialProgress.overrideCircleAlpha = 0f; } else if (isRoundVideo && !on) { radialProgress.overrideCircleAlpha = .25f + .75f * (1f - getVideoTranscriptionProgress()); } if (!currentMessageObject.isRoundOnce() && (!SharedConfig.isAutoplayVideo() || currentMessagesGroup != null) && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed && radialProgress.getIcon() == MediaActionDrawable.ICON_PLAY) { canvas.saveLayerAlpha(radialProgress.getProgressRect(), (int) (mediaSpoilerRevealProgress * 0xFF), Canvas.ALL_SAVE_FLAG); } drawRadialProgress(canvas); if (!currentMessageObject.isRoundOnce() && (!SharedConfig.isAutoplayVideo() || currentMessagesGroup != null) && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed && radialProgress.getIcon() == MediaActionDrawable.ICON_PLAY) { canvas.restore(); } if (currentMessageObject.needDrawBluredPreview() || isRoundVideo && !on) { radialProgress.overrideCircleAlpha = 1f; } } if (restore) { canvas.restore(); } } boolean drawCountdown = buttonState == -1 && currentMessageObject != null && currentMessageObject.needDrawBluredPreview() && !MediaController.getInstance().isPlayingMessage(currentMessageObject) && currentMessageObject.messageOwner.destroyTime != 0; if (drawCountdown && timerParticlesAlpha == null) { timerParticlesAlpha = new AnimatedFloat(0, this, 150, 120, CubicBezierInterpolator.EASE_OUT); } float countdownAlpha = timerParticlesAlpha == null ? 0 : timerParticlesAlpha.set(drawCountdown); if (countdownAlpha > 0 && photoImage.getVisible()) { final long msTime = System.currentTimeMillis() + ConnectionsManager.getInstance(currentAccount).getTimeDifference() * 1000; final float progress = Math.max(0, (long) currentMessageObject.messageOwner.destroyTime * 1000 - msTime) / (currentMessageObject.messageOwner.ttl * 1000.0f); Theme.chat_deleteProgressPaint.setColor(Color.WHITE); Theme.chat_deleteProgressPaint.setAlpha((int) (0xFF * countdownAlpha * controlsAlpha)); Theme.chat_deleteProgressPaint.setStrokeWidth(dp(2)); canvas.drawArc(deleteProgressRect, -90, -360 * progress, false, Theme.chat_deleteProgressPaint); if (timerParticles == null) { timerParticles = new TimerParticles(); } timerParticles.draw(canvas, Theme.chat_deleteProgressPaint, deleteProgressRect, progress * -360, controlsAlpha); invalidate(); updateSecretTimeText(currentMessageObject); } if ((drawVideoImageButton || animatingDrawVideoImageButton != 0) && !currentMessageObject.isRepostPreview && !currentMessageObject.sendPreview && photoImage.getVisible() && !isSmallImage && !currentMessageObject.isHiddenSensitive()) { float alpha = controlsAlpha; if (drawPhotoImage && currentMessageObject != null && currentMessageObject.hasMediaSpoilers() && currentMessageObject.isSensitive() && (!currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0 && mediaSpoilerRevealProgress < 1)) { alpha *= mediaSpoilerRevealProgress; } videoRadialProgress.setOverrideAlpha(alpha); videoRadialProgress.draw(canvas); } if (drawMediaCheckBox) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT && !drawPhotoImage) { int size = dp(20); mediaCheckBox.setBackgroundType(radialProgress.getMiniIcon() != MediaActionDrawable.ICON_NONE ? 12 : 13); mediaCheckBox.setBounds(buttonX + dp(28), buttonY + dp(28), size, size); mediaCheckBox.setColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeText : Theme.key_chat_inTimeText, currentMessageObject.isOutOwner() ? Theme.key_chat_outLoader : Theme.key_chat_inLoader, currentMessageObject.isOutOwner() ? Theme.key_chat_outBubble : Theme.key_chat_inBubble); mediaCheckBox.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); } else { int size = dp(21); mediaCheckBox.setBackgroundType(0); mediaCheckBox.setBounds((int) photoImage.getImageX2() - dp(21 + 4), (int) photoImage.getImageY() + dp(4), size, size); mediaCheckBox.setColor(-1, -1, currentMessageObject.isOutOwner() ? Theme.key_chat_outBubbleSelected : Theme.key_chat_inBubbleSelected); mediaCheckBox.setBackgroundDrawable(null); } mediaCheckBox.draw(canvas); } if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { float x1, y1; boolean playing = MediaController.getInstance().isPlayingMessage(currentMessageObject); if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { float offsetX = 0f; if (currentMessageObject.isOutOwner()) { float offsetSize = (AndroidUtilities.roundPlayingMessageSize(isSideMenued) - AndroidUtilities.roundMessageSize) * 0.2f; offsetX = isPlayingRound ? offsetSize : 0; if (transitionParams.animatePlayingRound) { offsetX = (isPlayingRound ? transitionParams.animateChangeProgress : (1f - transitionParams.animateChangeProgress)) * offsetSize; } } if (currentMessageObject != null && currentMessageObject.isRoundOnce()) { x1 = photoImage.getImageX(); y1 = photoImage.getImageY2() - (dp(drawPinnedBottom ? 4 : 5)/* + reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress)*/) * (1f - getVideoTranscriptionProgress()) - dp(17); } else { x1 = backgroundDrawableLeft + transitionParams.deltaLeft + (!currentMessageObject.isOutOwner() && !drawPinnedBottom && drawBackground ? dp(6) : 0) + dp(8) + roundPlayingDrawableProgress + offsetX; y1 = layoutHeight - dp(28 - (drawPinnedBottom ? 2 : 0)); } if (!reactionsLayoutInBubble.isEmpty && (currentMessageObject == null || !currentMessageObject.isRoundOnce())) { y1 -= reactionsLayoutInBubble.totalHeight; } transitionParams.lastDrawRoundVideoDotY = y1; if (transitionParams.animateRoundVideoDotY) { y1 = transitionParams.animateFromRoundVideoDotY * (1f - transitionParams.animateChangeProgress) + y1 * transitionParams.animateChangeProgress; } int timeAudioX = this.timeAudioX; if (!hasLinkPreview) { if (currentMessageObject.isOutOwner()) { timeAudioX = (getWidth() - ((transitionParams.animateBackgroundBoundsInner ? (int) (backgroundWidth - transitionParams.deltaLeft + transitionParams.deltaRight) : backgroundWidth)) - (!drawPinnedBottom && mediaBackground ? dp(8) : 0)) + dp(67); } x1 = AndroidUtilities.lerp(x1, timeAudioX - dp(4), getVideoTranscriptionProgress()); y1 = AndroidUtilities.lerp(y1, dp(44) + namesOffset + mediaOffsetY - dp(1.7f), getVideoTranscriptionProgress()); } rect.set(x1, y1, x1 + timeWidthAudio + dp(8 + 12 + 2), y1 + dp(17)); applyServiceShaderMatrix(); Paint bgPaint = getThemedPaint(Theme.key_paint_chatActionBackground); int oldAlpha = bgPaint.getAlpha(); bgPaint.setAlpha((int) (oldAlpha * timeAlpha * 0.5f * (1f - getVideoTranscriptionProgress()))); canvas.drawRoundRect(rect, dp(6), dp(6), bgPaint); if (hasGradientService()) { Paint darkenPaint = getThemedPaint(Theme.key_paint_chatActionBackgroundDarken); int oldAlpha2 = darkenPaint.getAlpha(); darkenPaint.setAlpha((int) (oldAlpha2 * timeAlpha * (1f - getVideoTranscriptionProgress()))); canvas.drawRoundRect(rect, dp(6), dp(6), darkenPaint); darkenPaint.setAlpha(oldAlpha2); } bgPaint.setAlpha(oldAlpha); boolean showPlayingDrawable = playing || !currentMessageObject.isContentUnread(); if (showPlayingDrawable && roundPlayingDrawableProgress != 1f) { roundPlayingDrawableProgress += 16f / 150f; if (roundPlayingDrawableProgress > 1f) { roundPlayingDrawableProgress = 1f; } else { invalidate(); } } else if (!showPlayingDrawable && roundPlayingDrawableProgress != 0) { roundPlayingDrawableProgress -= 16f / 150f; if (roundPlayingDrawableProgress < 0f) { roundPlayingDrawableProgress = 0f; } else { invalidate(); } } if (showPlayingDrawable) { if (playing && !MediaController.getInstance().isMessagePaused()) { roundVideoPlayingDrawable.start(); } else { roundVideoPlayingDrawable.stop(); } } if (roundPlayingDrawableProgress < 1f) { float cx = x1 + timeWidthAudio + dp(12); float cy = y1 + dp(8.3f); canvas.save(); canvas.scale((1f - roundPlayingDrawableProgress), (1f - roundPlayingDrawableProgress), cx, cy); Theme.chat_docBackPaint.setColor(Theme.chat_timePaint.getColor()); Theme.chat_docBackPaint.setAlpha((int) (255 * timeAlpha * (1f - roundPlayingDrawableProgress))); canvas.drawCircle(cx, cy, dp(3), Theme.chat_docBackPaint); canvas.restore(); } if (roundPlayingDrawableProgress > 0f) { setDrawableBounds(roundVideoPlayingDrawable, x1 + timeWidthAudio + dp(6), y1 + dp(2.3f)); canvas.save(); canvas.scale(roundPlayingDrawableProgress, roundPlayingDrawableProgress, roundVideoPlayingDrawable.getBounds().centerX(), roundVideoPlayingDrawable.getBounds().centerY()); if (!hasLinkPreview) { roundVideoPlayingDrawable.timeColor = Theme.chat_timePaint.getColor(); roundVideoPlayingDrawable.colorProgress = getVideoTranscriptionProgress(); } else { roundVideoPlayingDrawable.colorProgress = 0; } roundVideoPlayingDrawable.setAlpha((int) (255 * roundPlayingDrawableProgress * (1f - getVideoTranscriptionProgress()))); roundVideoPlayingDrawable.draw(canvas); canvas.restore(); } x1 += dp(4); y1 += dp(1.7f); } else { x1 = photoImage.getImageX(); y1 = photoImage.getImageY2() - (durationLayout != null ? durationLayout.getHeight() : 0); } if (durationLayout != null) { Theme.chat_timePaint.setAlpha((int) (255 * timeAlpha)); canvas.save(); canvas.translate(x1, y1); durationLayout.draw(canvas); canvas.restore(); Theme.chat_timePaint.setAlpha(255); } } if (drawPhotoImage && currentMessageObject != null && currentMessageObject.hasMediaSpoilers() && currentMessageObject.isSensitive() && (!currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0 && mediaSpoilerRevealProgress < 1)) { if (sensitiveText == null) { SpannableStringBuilder sensitiveTextString = new SpannableStringBuilder("x " + getString(R.string.MessageSensitiveContent)); ColoredImageSpan span = new ColoredImageSpan(R.drawable.filled_sensitive); sensitiveTextString.setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); sensitiveText = new Text(sensitiveTextString, 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); } int textPadding = 13, textHeight = 32; Text text = sensitiveText; if (photoImage.getImageWidth() < 2 * dp(textPadding) + text.getCurrentWidth()) { if (sensitiveTextShort == null) { SpannableStringBuilder sensitiveTextString = new SpannableStringBuilder("x " + getString(R.string.MessageSensitiveContentShort)); ColoredImageSpan span = new ColoredImageSpan(R.drawable.filled_sensitive); sensitiveTextString.setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); sensitiveTextShort = new Text(sensitiveTextString, 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); } text = sensitiveTextShort; } if (photoImage.getImageWidth() < 2 * dp(textPadding + textPadding) + text.getCurrentWidth()) { if (sensitiveTextShort2 == null) { SpannableStringBuilder sensitiveTextString = new SpannableStringBuilder(getString(R.string.MessageSensitiveContentShort)); sensitiveTextShort2 = new Text(sensitiveTextString, 13, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); } text = sensitiveTextShort2; textPadding = 10; textHeight = 28; } final float cx = photoImage.getImageX() + photoImage.getImageWidth() / 2f; final float cy = photoImage.getImageY() + photoImage.getImageHeight() / 2f; final float w = text.getCurrentWidth() + dp(2 * textPadding); final float h = dp(textHeight), r = h / 2f; float s = AndroidUtilities.lerp(.8f, 1f, 1f - mediaSpoilerRevealProgress); AndroidUtilities.rectTmp.set(cx - w / 2f * s, cy - h / 2f * s, cx + w / 2f * s, cy + h / 2f * s); rectPath.reset(); rectPath.addRoundRect(AndroidUtilities.rectTmp, r, r, Path.Direction.CW); canvas.save(); canvas.clipPath(rectPath); float wasAlpha = blurredPhotoImage.getAlpha(); blurredPhotoImage.setAlpha((1f - mediaSpoilerRevealProgress) * wasAlpha); blurredPhotoImage.draw(canvas); blurredPhotoImage.setAlpha(wasAlpha); canvas.restore(); int oldAlpha = getThemedPaint(Theme.key_paint_chatTimeBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatTimeBackground).setAlpha((int) (oldAlpha * controlsAlpha * (1f - mediaSpoilerRevealProgress) * .35f)); canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, getThemedPaint(Theme.key_paint_chatTimeBackground)); getThemedPaint(Theme.key_paint_chatTimeBackground).setAlpha(oldAlpha); canvas.save(); canvas.scale(s, s, cx, cy); text.draw(canvas, cx - w / 2f + dp(textPadding), cy, 0xFFFFFFFF, 1f - mediaSpoilerRevealProgress); canvas.restore(); } } public int getTodoIndex(int taskId) { for (int i = 0; i < pollButtons.size(); ++i) { final PollButton btn = pollButtons.get(i); if (btn.task != null && btn.task.id == taskId) { return i; } } return -1; } public int getPollIndex(byte[] taskId) { for (int i = 0; i < pollButtons.size(); ++i) { final PollButton btn = pollButtons.get(i); if (btn.answer != null && Arrays.equals(btn.answer.option, taskId)) { return i; } } return -1; } public float getPollButtonTop(int index) { if (index < 0 || index >= pollButtons.size()) return 0; final PollButton btn = pollButtons.get(index); float y = btn.y + namesOffset; if (transitionParams.animateForwardedLayout) { y += namesOffset * transitionParams.animateChangeProgress + transitionParams.animateForwardedNamesOffset * (1f - transitionParams.animateChangeProgress); if (currentMessageObject.needDrawForwarded()) { y -= namesOffset; } } if (transitionParams.animateBackgroundBoundsInner) { y += transitionParams.deltaTop; } return y - dp(13); } public float getPollButtonsLeft() { if (getMessageObject() != null && getMessageObject().isOutOwner()) { return dp(3) + this.layoutWidth - backgroundWidth; } else if (isSideMenuEnabled) { return dp(11 + ChatActivity.SIDE_MENU_WIDTH); } else if (needDrawAvatar()) { return dp(11 + 48); } else { return dp(11); } } public float getPollButtonsRight() { return getPollButtonsLeft() + backgroundWidth - dp(15); } public float getPollButtonBottom(int index) { if (index < 0 || index >= pollButtons.size()) return 0; final PollButton btn = pollButtons.get(index); float y = btn.y + namesOffset; if (transitionParams.animateForwardedLayout) { y += namesOffset * transitionParams.animateChangeProgress + transitionParams.animateForwardedNamesOffset * (1f - transitionParams.animateChangeProgress); if (currentMessageObject.needDrawForwarded()) { y -= namesOffset; } } if (transitionParams.animateBackgroundBoundsInner) { y += transitionParams.deltaTop; } return y + btn.height + dp(13); } private Paint clipPaint; protected float radialProgressAlpha = 1f; protected void drawRadialProgress(Canvas canvas) { final boolean withPeriod = currentMessageObject.isRoundOnce(); if (withPeriod) { AndroidUtilities.rectTmp.set(radialProgress.getProgressRect()); AndroidUtilities.rectTmp.inset(-dp(15), -dp(15)); canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (0xFF * radialProgressAlpha), Canvas.ALL_SAVE_FLAG); } else { canvas.save(); final int type = currentMessageObject.type; if (drawPhotoImage && (type == MessageObject.TYPE_VIDEO || type == MessageObject.TYPE_PHOTO || type == MessageObject.TYPE_GIF)) { canvas.clipRect(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); } } if (currentMessageObject.needDrawBluredPreview()) { drawPhotoBlurRect(canvas, radialProgress.getProgressRect()); } radialProgress.iconScale = 1f; if (drawPhotoImage && currentMessageObject != null && currentMessageObject.hasMediaSpoilers() && currentMessageObject.isSensitive() && (!currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0 && mediaSpoilerRevealProgress < 1)) { radialProgress.iconScale *= mediaSpoilerRevealProgress; } radialProgress.draw(canvas); if (withPeriod) { canvas.save(); drawPhotoBlurRect(canvas, getRadialProgress().getProgressRect()); getRadialProgress().draw(canvas); RectF pr = getRadialProgress().getProgressRect(); final float cx = pr.centerX() + dp(18); final float cy = pr.centerY() + dp(18); final float r = dp(10), cr = r + dp(1.33f); if (clipPaint == null) { clipPaint = new Paint(Paint.ANTI_ALIAS_FLAG); clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); } canvas.drawCircle(cx, cy, cr, clipPaint); AndroidUtilities.rectTmp.set(cx - r, cy - r, cx + r, cy + r); drawPhotoBlurRect(canvas, AndroidUtilities.rectTmp); if (oncePeriod == null) { oncePeriod = new CaptionContainerView.PeriodDrawable(3); oncePeriod.updateColors(0xffffffff, 0, 0); oncePeriod.diameterDp = 14; oncePeriod.setTextSize(10); oncePeriod.strokePaint.setStrokeWidth(dpf2(1.5f)); oncePeriod.setValue(1, false, false); oncePeriod.textOffsetX = -dpf2(.33f); oncePeriod.textOffsetY = dpf2(.33f); } oncePeriod.diameterDp = 14; oncePeriod.setTextSize(10); oncePeriod.setClear(false); oncePeriod.setCenterXY(cx, cy); oncePeriod.draw(canvas, 1f); canvas.restore(); } canvas.restore(); } protected void drawPhotoBlurRect(Canvas canvas, RectF rect) { rectPath.rewind(); rectPath.addRoundRect(rect, rect.width() / 2f, rect.height() / 2f, Path.Direction.CW); canvas.save(); canvas.clipPath(rectPath); float wasAlpha = photoImage.getAlpha(); photoImage.setAlpha((currentMessageObject.isRoundOnce() ? 1f : .5f) * wasAlpha); photoImage.draw(canvas); photoImage.setAlpha(wasAlpha); canvas.restore(); Paint dimPaint = getThemedPaint(Theme.key_paint_chatTimeBackground); int oldAlpha2 = dimPaint.getAlpha(); dimPaint.setAlpha((int) (oldAlpha2 * controlsAlpha * .4f)); canvas.drawRoundRect(rect, rect.width() / 2f, rect.height() / 2f, dimPaint); dimPaint.setAlpha(oldAlpha2); } @Override public int getObserverTag() { return TAG; } public MessageObject getMessageObject() { return messageObjectToSet != null ? messageObjectToSet : currentMessageObject; } @Override public ReactionsLayoutInBubble getReactionsLayout() { return reactionsLayoutInBubble; } @Override public void didPressReactionFromLayout(TLRPC.ReactionCount reaction, boolean longpress, float x, float y) { if (delegate != null) { delegate.didPressReaction(this, reaction, longpress, x, y); } } public TLRPC.Document getStreamingMedia() { return documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF ? documentAttach : null; } public boolean drawPinnedBottom() { if (currentMessagesGroup != null && currentMessagesGroup.isDocuments) { if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { return pinnedBottom; } return true; } return pinnedBottom; } public float getVideoTranscriptionProgress() { if (transitionParams == null || currentMessageObject == null || !currentMessageObject.isRoundVideo()) { return 1; } if (transitionParams.animateDrawBackground) { if (drawBackground) { return transitionParams.animateChangeProgress; } else { return 1f - transitionParams.animateChangeProgress; } } return drawBackground ? 1 : 0; } public boolean drawPinnedTop() { if (currentMessagesGroup != null && currentMessagesGroup.isDocuments) { if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0) { return pinnedTop; } return true; } return pinnedTop; } public boolean isPinnedBottom() { if (messageObjectToSet != null) { return bottomNearToSet; } return pinnedBottom; } public boolean isPinnedTop() { if (messageObjectToSet != null) { return topNearToSet; } return pinnedTop; } public boolean isFirstInChat() { if (messageObjectToSet != null) { return firstInChatToSet; } return firstInChat; } public boolean isLastInChatList() { if (messageObjectToSet != null) { return lastInChatListToSet; } return lastInChatList; } public MessageObject.GroupedMessages getCurrentMessagesGroup() { return currentMessagesGroup; } public MessageObject.GroupedMessagePosition getCurrentPosition() { return currentPosition; } public int getLayoutHeight() { return layoutHeight; } @Override public boolean performAccessibilityAction(int action, Bundle arguments) { if (delegate != null && delegate.onAccessibilityAction(action, arguments)) { return false; } if (action == AccessibilityNodeInfo.ACTION_CLICK) { int icon = getIconForCurrentState(); if (icon != MediaActionDrawable.ICON_NONE && icon != MediaActionDrawable.ICON_FILE) { didPressButton(true, false); } else if (currentMessageObject.type == MessageObject.TYPE_PHONE_CALL) { delegate.didPressOther(this, otherX, otherY); } else { didClickedImage(); } return true; } else if (action == R.id.acc_action_small_button) { didPressMiniButton(true); } else if (action == R.id.acc_action_msg_options) { if (delegate != null) { if (currentMessageObject.type == MessageObject.TYPE_PHONE_CALL) { delegate.didLongPress(this, 0, 0); } else { delegate.didPressOther(this, otherX, otherY); } } } else if (action == R.id.acc_action_open_forwarded_origin) { if (delegate != null) { if (currentForwardChannel != null) { delegate.didPressChannelAvatar(ChatMessageCell.this, currentForwardChannel, currentMessageObject.messageOwner.fwd_from.channel_post, lastTouchX, lastTouchY, false); } else if (currentForwardUser != null) { delegate.didPressUserAvatar(ChatMessageCell.this, currentForwardUser, lastTouchX, lastTouchY, false); } else if (currentForwardName != null) { delegate.didPressHiddenForward(ChatMessageCell.this); } } } else if (action == R.id.acc_action_summarize) { if (delegate != null) { delegate.didPressSummarize(this, drawSummaryReply); } } else if (action == R.id.acc_action_copy_code) { if (delegate != null && currentMessageObject.textLayoutBlocks != null) { for (MessageObject.TextLayoutBlock block : currentMessageObject.textLayoutBlocks) { if (block.hasCodeCopyButton) { delegate.didPressCodeCopy(this, block); break; } } } } if (currentMessageObject.isVoice() || currentMessageObject.isRoundVideo() || currentMessageObject.isMusic() && MediaController.getInstance().isPlayingMessage(currentMessageObject)) { if (seekBarAccessibilityDelegate.performAccessibilityActionInternal(action, arguments)) { return true; } } return super.performAccessibilityAction(action, arguments); } public void setAnimationRunning(boolean animationRunning, boolean willRemoved) { this.animationRunning = animationRunning; if (animationRunning) { this.willRemoved = willRemoved; } else { this.willRemoved = false; } } public float getEventX(MotionEvent event) { return event.getX(); } public float getEventY(MotionEvent event) { return event.getY() - starsPriceTopPadding - topicSeparatorTopPadding - suggestionOfferTopPadding; } @Override public boolean onHoverEvent(MotionEvent event) { int x = (int) getEventX(event); int y = (int) getEventY(event); if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER || event.getAction() == MotionEvent.ACTION_HOVER_MOVE) { for (int i = 0; i < accessibilityVirtualViewBounds.size(); i++) { Rect rect = accessibilityVirtualViewBounds.valueAt(i); if (rect.contains(x, y)) { int id = accessibilityVirtualViewBounds.keyAt(i); if (id != currentFocusedVirtualView) { currentFocusedVirtualView = id; sendAccessibilityEventForVirtualView(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); } return true; } } } else if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) { currentFocusedVirtualView = 0; } return super.onHoverEvent(event); } @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); } @Override public AccessibilityNodeProvider getAccessibilityNodeProvider() { return new MessageAccessibilityNodeProvider(); } private void sendAccessibilityEventForVirtualView(int viewId, int eventType) { sendAccessibilityEventForVirtualView(viewId, eventType, null); } private void sendAccessibilityEventForVirtualView(int viewId, int eventType, String text) { AccessibilityManager am = (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); if (am.isTouchExplorationEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain(eventType); event.setPackageName(getContext().getPackageName()); event.setSource(ChatMessageCell.this, viewId); if (text != null) { event.getText().add(text); } if (getParent() != null) { getParent().requestSendAccessibilityEvent(ChatMessageCell.this, event); } } } public static PointF getMessageSize(int imageW, int imageH) { return getMessageSize(imageW, imageH, 0, 0); } private static PointF getMessageSize(int imageW, int imageH, int photoWidth, int photoHeight) { if (photoHeight == 0 || photoWidth == 0) { if (AndroidUtilities.isTablet()) { photoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); } else { if (imageW >= imageH) { photoWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - dp(64); } else { photoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); } } photoHeight = photoWidth + dp(100); if (photoWidth > AndroidUtilities.getPhotoSize()) { photoWidth = AndroidUtilities.getPhotoSize(); } if (photoHeight > AndroidUtilities.getPhotoSize()) { photoHeight = AndroidUtilities.getPhotoSize(); } } float scale = (float) imageW / (float) photoWidth; int w = (int) (imageW / scale); int h = (int) (imageH / scale); if (w == 0) { w = dp(150); } if (h == 0) { h = dp(150); } if (h > photoHeight) { float scale2 = h; h = photoHeight; scale2 /= h; w = (int) (w / scale2); } else if (h < dp(120)) { h = dp(120); float hScale = (float) imageH / h; if (imageW / hScale < photoWidth) { w = (int) (imageW / hScale); } } float x = w; float y = h; return new PointF(x, y); } public StaticLayout getDescriptionlayout() { return descriptionLayout; } public float getDescriptionLayoutX() { float startY, linkX; if (hasGamePreview) { startY = dp(14) + namesOffset; linkX = unmovedTextX - dp(10); } else if (hasInvoicePreview) { startY = dp(14) + namesOffset; linkX = unmovedTextX + dp(1); } else if (currentMessageObject.isSponsored()) { startY = this.linkPreviewY - dp(2); linkX = unmovedTextX + dp(1); } else { if (currentMessageObject.isOutOwner()) { linkX = backgroundDrawableLeft + dp(12) + getExtraTextX(); if (currentMessageObject.type == MessageObject.TYPE_EMOJIS) { linkX -= Math.max(0, linkX + Math.max(replyNameWidth, replyTextWidth) + dp(14) - AndroidUtilities.displaySize.x); } } else { if (mediaBackground) { linkX = backgroundDrawableLeft + dp(12) + getExtraTextX(); } else { linkX = backgroundDrawableLeft + dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } linkX += transitionParams.deltaLeft; linkX -= dp(1.33f); startY = this.linkPreviewY; if (transitionParams.animateLinkPreviewY) { startY = AndroidUtilities.lerp(transitionParams.animateFromLinkPreviewY, startY, transitionParams.animateChangeProgress); } } final float right = getBackgroundDrawableRight() + (transitionParams != null ? transitionParams.deltaRight : 0) - dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) - getExtraTextX(); final int width = (int) (right - linkX); return linkX + dp(10) + (Math.abs(descriptionLayoutLeft) > 1 ? width - dp(20) - descriptionLayoutWidth - descriptionLayoutLeft : 0); } public float getDescriptionLayoutY() { return descriptionY + (!transitionParams.animateLinkPreviewY ? -transitionParams.deltaTop + transitionParams.deltaBottom : 0); } public StaticLayout getFactCheckLayout() { return factCheckTextLayout; } public void setSelectedBackgroundProgress(float value) { selectedBackgroundProgress = value; invalidate(); } public int computedGroupCaptionY; public MessageObject.TextLayoutBlocks computedCaptionLayout; public int computeHeight(MessageObject object, MessageObject.GroupedMessages groupedMessages, boolean withCaption) { photoImage.setIgnoreImageSet(true); avatarImage.setIgnoreImageSet(true); replyImageReceiver.setIgnoreImageSet(true); locationImageReceiver.setIgnoreImageSet(true); if (groupedMessages != null && groupedMessages.messages.size() != 1) { if (groupedMessages.messages.size() != groupedMessages.positions.size()) { groupedMessages.calculate(); } computedGroupCaptionY = 0; int h = 0; for (int i = 0; i < groupedMessages.messages.size(); i++) { MessageObject o = groupedMessages.messages.get(i); MessageObject.GroupedMessagePosition position = groupedMessages.getPosition(o); if (position != null && (position.flags & MessageObject.POSITION_FLAG_LEFT) != 0) { setMessageContent(o, groupedMessages, false, false, false, false); if (withCaption && !TextUtils.isEmpty(currentCaption)) { updateCaptionLayout(); computedGroupCaptionY = (int) (h + captionY); computedCaptionLayout = captionLayout; } h += totalHeight + keyboardHeight; } } return h; } setMessageContent(object, groupedMessages, false, false, false, false); photoImage.setIgnoreImageSet(false); avatarImage.setIgnoreImageSet(false); replyImageReceiver.setIgnoreImageSet(false); locationImageReceiver.setIgnoreImageSet(false); updateCaptionLayout(); return totalHeight + keyboardHeight; } public int computeWidth(MessageObject object, MessageObject.GroupedMessages groupedMessages) { photoImage.setIgnoreImageSet(true); avatarImage.setIgnoreImageSet(true); replyImageReceiver.setIgnoreImageSet(true); locationImageReceiver.setIgnoreImageSet(true); if (groupedMessages != null && groupedMessages.messages.size() != 1) { if (groupedMessages.messages.size() != groupedMessages.positions.size()) { groupedMessages.calculate(); } computedGroupCaptionY = 0; int h = 0; for (int i = 0; i < groupedMessages.messages.size(); i++) { MessageObject o = groupedMessages.messages.get(i); MessageObject.GroupedMessagePosition position = groupedMessages.getPosition(o); if (position != null && (position.flags & MessageObject.POSITION_FLAG_TOP) != 0) { setMessageContent(o, groupedMessages, false, false, false, false); h += backgroundWidth; } } return h; } setMessageContent(object, groupedMessages, false, false, false, false); photoImage.setIgnoreImageSet(false); avatarImage.setIgnoreImageSet(false); replyImageReceiver.setIgnoreImageSet(false); locationImageReceiver.setIgnoreImageSet(false); updateCaptionLayout(); return backgroundWidth; } public void shakeView() { Keyframe kf0 = Keyframe.ofFloat(0f, 0); Keyframe kf1 = Keyframe.ofFloat(0.2f, 3); Keyframe kf2 = Keyframe.ofFloat(0.4f, -3); Keyframe kf3 = Keyframe.ofFloat(0.6f, 3); Keyframe kf4 = Keyframe.ofFloat(0.8f, -3); Keyframe kf5 = Keyframe.ofFloat(1f, 0); PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe(View.ROTATION, kf0, kf1, kf2, kf3, kf4, kf5); Keyframe kfs0 = Keyframe.ofFloat(0f, 1.0f); Keyframe kfs1 = Keyframe.ofFloat(0.5f, 0.97f); Keyframe kfs2 = Keyframe.ofFloat(1.0f, 1.0f); PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofKeyframe(View.SCALE_X, kfs0, kfs1, kfs2); PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofKeyframe(View.SCALE_Y, kfs0, kfs1, kfs2); shakeAnimation = new AnimatorSet(); shakeAnimation.playTogether( ObjectAnimator.ofPropertyValuesHolder(this, pvhRotation), ObjectAnimator.ofPropertyValuesHolder(this, pvhScaleX), ObjectAnimator.ofPropertyValuesHolder(this, pvhScaleY)); shakeAnimation.setDuration(500); shakeAnimation.start(); } private void cancelShakeAnimation() { if (shakeAnimation != null) { shakeAnimation.cancel(); shakeAnimation = null; setScaleX(1.0f); setScaleY(1.0f); setRotation(0); } } private float slidingOffsetX; private float animationOffsetX; public Property ANIMATION_OFFSET_X = new Property(Float.class, "animationOffsetX") { @Override public Float get(ChatMessageCell object) { return object.animationOffsetX; } @Override public void set(ChatMessageCell object, Float value) { object.setAnimationOffsetX(value); } }; public void setSlidingOffset(float offsetX) { if (slidingOffsetX != offsetX) { slidingOffsetX = offsetX; updateTranslation(); } } public void setAnimationOffsetX(float offsetX) { if (animationOffsetX != offsetX) { animationOffsetX = offsetX; updateTranslation(); } } public void updateTranslation() { if (currentMessageObject == null) { return; } float tx = slidingOffsetX + animationOffsetX; if (!currentMessageObject.isOutOwner() || currentMessageObject.hasWideCode) { tx += checkBoxTranslation; } if (isSideMenued && !currentMessageObject.isOutOwner() && currentPosition != null) { tx += dp(ChatActivity.SIDE_MENU_WIDTH - (needDrawAvatar() ? 48 : 0)) * sideMenuAlpha; } setTranslationX(tx); } public float getNonAnimationTranslationX(boolean update) { float tx = slidingOffsetX; if (currentMessageObject != null && !currentMessageObject.isOutOwner()) { if (update && (checkBoxVisible || checkBoxAnimationInProgress)) { Interpolator interpolator = checkBoxVisible ? CubicBezierInterpolator.EASE_OUT : CubicBezierInterpolator.EASE_IN; checkBoxTranslation = (int) Math.ceil(interpolator.getInterpolation(checkBoxAnimationProgress) * dp(35)); if (currentMessageObject.type == MessageObject.TYPE_ARTICLE && getCurrentBackgroundRight() + dp(35) > getWidth()) checkBoxTranslation = 0; } tx += checkBoxTranslation; if (isSideMenued && currentPosition != null) { tx += dp(ChatActivity.SIDE_MENU_WIDTH - (needDrawAvatar() ? 48 : 0)) * sideMenuAlpha; } } return tx; } public float getSlidingOffsetX() { return slidingOffsetX; } public boolean willRemovedAfterAnimation() { return willRemoved; } public float getAnimationOffsetX() { return animationOffsetX; } @Override public void setTranslationX(float translationX) { super.setTranslationX(translationX); } public boolean isDraggingdAnyMusicSeekBar() { if (seekBar != null && seekBar.isDragging()) { return true; } if (currentMessageObject != null && currentMessageObject.isPoll()) { if (pollContentDrawable != null && pollContentDrawable.isDraggingSeekBar()) { return true; } if (pollExplanationDrawable != null && pollExplanationDrawable.isDraggingSeekBar()) { return true; } } return false; } public SeekBarWaveform getSeekBarWaveform() { return seekBarWaveform; } private class MessageAccessibilityNodeProvider extends AccessibilityNodeProvider { public static final int RICH_MEDIA_START = 6000; public static final int PROFILE = 5000; public static final int LINK_IDS_START = 2000; public static final int LINK_CAPTION_IDS_START = 3000; public static final int BOT_BUTTONS_START = 1000; public static final int POLL_BUTTONS_START = 500; public static final int INSTANT_VIEW = 499; public static final int SHARE = 498; public static final int REPLY = 497; public static final int COMMENT = 496; public static final int POLL_HINT = 495; public static final int FORWARD = 494; public static final int TRANSCRIBE = 493; public static final int CONTACT = 492; public static final int CONTACT_VIEW = 491; public static final int CONTACT_ADD = 490; public static final int CONTACT_MESSAGE = 489; private Path linkPath = new Path(); private RectF rectF = new RectF(); private Rect rect = new Rect(); private class ProfileSpan extends ClickableSpan { private TLRPC.User user; public ProfileSpan(TLRPC.User user) { this.user = user; } @Override public void onClick(@NonNull View view) { if (delegate != null) { delegate.didPressUserAvatar(ChatMessageCell.this, user, 0, 0, false); } } } private RichMessageLayout.RichBlock resolveRichElement(int virtualViewId, int[] outLocal) { if (currentMessageObject == null || currentMessageObject.richLayout == null) { return null; } final int globalIndex = virtualViewId - RICH_MEDIA_START; if (globalIndex < 0) { return null; } final RichMessageLayout richLayout = currentMessageObject.richLayout; int acc = 0; for (int b = 0; b < richLayout.blocks.size(); b++) { final RichMessageLayout.RichBlock block = richLayout.blocks.get(b); if (!block.isVisible()) { continue; } final int count = block.getAccessibilityElementCount(); if (globalIndex < acc + count) { outLocal[0] = globalIndex - acc; return block; } acc += count; } return null; } @Override public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { int[] pos = {0, 0}; getLocationOnScreen(pos); if (virtualViewId == HOST_VIEW_ID) { AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(ChatMessageCell.this); onInitializeAccessibilityNodeInfo(info); final boolean unread = currentMessageObject != null && currentMessageObject.isOut() && !currentMessageObject.scheduled && currentMessageObject.isUnread(); final boolean contentUnread = currentMessageObject != null && currentMessageObject.isContentUnread(); final long fileSize = currentMessageObject != null ? currentMessageObject.loadedFileSize : 0; if (accessibilityText == null || accessibilityTextUnread != unread || accessibilityTextContentUnread != contentUnread || accessibilityTextFileSize != fileSize) { SpannableStringBuilder sb = new SpannableStringBuilder(); if (isChat && currentUser != null && !currentMessageObject.isOut()) { sb.append(UserObject.getUserName(currentUser)); sb.setSpan(new ProfileSpan(currentUser), 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); final CharSequence adminText = getAdminAccessibilityText(); if (!TextUtils.isEmpty(adminText)) { if (adminLayoutIsTag) { sb.append(' ').append(formatString(adminLayoutIsAdmin ? R.string.AccDescrWithAdminTag : R.string.AccDescrWithMemberTag, adminText)); } else { sb.append(", ").append(adminText); } } sb.append('\n'); } if (drawForwardedName) { for (int a = 0; a < 2; a++) { if (forwardedNameLayout[a] != null && forwardedNameLayout[a].getText() != null) { sb.append(forwardedNameLayout[a].getText()); sb.append(a == 0 ? " " : "\n"); } } } if (documentAttach != null && documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { String fileName = FileLoader.getAttachFileName(documentAttach); if (fileName.indexOf('.') != -1) { sb.append(formatString(R.string.AccDescrDocumentType, fileName.substring(fileName.lastIndexOf('.') + 1).toUpperCase(Locale.ROOT))); } } if (currentMessageObject.richLayout != null && !currentMessageObject.richLayout.blocks.isEmpty()) { for (RichMessageLayout.RichBlock block : currentMessageObject.richLayout.blocks) { if (!block.isVisible()) { continue; } final int before = sb.length(); final SpannableStringBuilder blockText = new SpannableStringBuilder(); block.appendAccessibilityText(blockText); final CharSequence blockLabel = block.getAccessibilityLabel(); final CharSequence listMarker = block.getAccessibilityListMarker(); if (!TextUtils.isEmpty(listMarker)) { sb.append(listMarker); if (!TextUtils.isEmpty(blockLabel) || blockText.length() > 0) { sb.append(' '); } } if (!TextUtils.isEmpty(blockLabel)) { sb.append(blockLabel); if (blockText.length() > 0) { sb.append(", "); } } sb.append(blockText); if (sb.length() > before && sb.charAt(sb.length() - 1) != '\n') { sb.append('\n'); } } } else if (!TextUtils.isEmpty(currentMessageObject.messageText)) { CharSequence messageText = currentMessageObject.messageText; if (messageText instanceof Spanned) { final Spanned spanned = (Spanned) messageText; CodeHighlighting.Span[] codeSpans = spanned.getSpans(0, spanned.length(), CodeHighlighting.Span.class); if (codeSpans != null && codeSpans.length > 0) { SpannableStringBuilder ssb = new SpannableStringBuilder(messageText); Arrays.sort(codeSpans, (a, b) -> spanned.getSpanStart(b) - spanned.getSpanStart(a)); for (CodeHighlighting.Span span : codeSpans) { int start = spanned.getSpanStart(span); if (start < 0) { continue; } final CharSequence label = TextUtils.isEmpty(span.lng) ? getString(R.string.AccDescrCodeBlock) : formatString(R.string.AccDescrCodeBlockLanguage, MessageObject.TextLayoutBlock.capitalizeLanguage(span.lng)); ssb.insert(start, label + ". "); } messageText = ssb; } } sb.append(messageText); } if (documentAttach != null && (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO)) { if (buttonState == 1 && loadingProgressLayout != null) { sb.append("\n"); final boolean sending = currentMessageObject.isSending(); final String key = sending ? "AccDescrUploadProgress" : "AccDescrDownloadProgress"; final int resId = sending ? R.string.AccDescrUploadProgress : R.string.AccDescrDownloadProgress; sb.append(formatString(key, resId, AndroidUtilities.formatFileSize(currentMessageObject.loadedFileSize), AndroidUtilities.formatFileSize(lastLoadingSizeTotal))); } } if (currentMessageObject.isMusic()) { sb.append("\n"); sb.append(formatString("AccDescrMusicInfo", R.string.AccDescrMusicInfo, currentMessageObject.getMusicAuthor(), currentMessageObject.getMusicTitle())); sb.append(", "); sb.append(LocaleController.formatDuration((int) currentMessageObject.getDuration())); } else if (currentMessageObject.isVoice() || isRoundVideo) { sb.append(", "); sb.append(LocaleController.formatDuration((int) currentMessageObject.getDuration())); sb.append(", "); if (currentMessageObject.isContentUnread()) { sb.append(getString("AccDescrMsgNotPlayed", R.string.AccDescrMsgNotPlayed)); } else { sb.append(getString("AccDescrMsgPlayed", R.string.AccDescrMsgPlayed)); } } if (lastPoll != null) { sb.append(", "); sb.append(lastPoll.question.text); sb.append(", "); String title; if (pollClosed) { title = getString("FinalResults", R.string.FinalResults); } else { if (lastPoll.quiz) { if (lastPoll.public_voters) { title = getString("QuizPoll", R.string.QuizPoll); } else { title = getString("AnonymousQuizPoll", R.string.AnonymousQuizPoll); } } else if (lastPoll.public_voters) { title = getString("PublicPoll", R.string.PublicPoll); } else { title = getString("AnonymousPoll", R.string.AnonymousPoll); } } sb.append(title); } if (documentAttach != null) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { sb.append(", "); sb.append(LocaleController.formatDuration((int) currentMessageObject.getDuration())); } if (buttonState == 0 || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { sb.append(", "); sb.append(AndroidUtilities.formatFileSize(documentAttach.size)); } } if (currentMessageObject.isVoiceTranscriptionOpen()) { sb.append("\n"); sb.append(currentMessageObject.getVoiceTranscription()); } else { if (MessageObject.getMedia(currentMessageObject.messageOwner) != null && !TextUtils.isEmpty(currentMessageObject.caption)) { sb.append("\n"); sb.append(currentMessageObject.caption); } } if (currentMessageObject.isOut()) { if (currentMessageObject.isSent()) { sb.append("\n"); if (currentMessageObject.scheduled) { sb.append(formatString("AccDescrScheduledDate", R.string.AccDescrScheduledDate, currentTimeString)); } else { sb.append(formatString("AccDescrSentDate", R.string.AccDescrSentDate, getString("TodayAt", R.string.TodayAt) + " " + currentTimeString)); sb.append(", "); sb.append(currentMessageObject.isUnread() ? getString("AccDescrMsgUnread", R.string.AccDescrMsgUnread) : getString("AccDescrMsgRead", R.string.AccDescrMsgRead)); } } else if (currentMessageObject.isSending()) { sb.append("\n"); sb.append(getString("AccDescrMsgSending", R.string.AccDescrMsgSending)); final float sendingProgress = radialProgress.getProgress(); if (sendingProgress > 0f) { sb.append(Integer.toString(Math.round(sendingProgress * 100))).append("%"); } } else if (currentMessageObject.isSendError()) { sb.append("\n"); sb.append(getString("AccDescrMsgSendingError", R.string.AccDescrMsgSendingError)); } } else { sb.append("\n"); sb.append(formatString("AccDescrReceivedDate", R.string.AccDescrReceivedDate, getString("TodayAt", R.string.TodayAt) + " " + currentTimeString)); } if (getRepliesCount() > 0 && !hasCommentLayout()) { sb.append("\n"); sb.append(formatPluralString("AccDescrNumberOfReplies", getRepliesCount())); } if (currentMessageObject.messageOwner.reactions != null && currentMessageObject.messageOwner.reactions.results != null) { if (currentMessageObject.messageOwner.reactions.results.size() == 1) { TLRPC.ReactionCount reaction = currentMessageObject.messageOwner.reactions.results.get(0); String emoticon = reaction.reaction instanceof TLRPC.TL_reactionEmoji ? ((TLRPC.TL_reactionEmoji) reaction.reaction).emoticon : ""; if (reaction.count == 1) { sb.append("\n"); boolean isMe = false; String userName = ""; if (currentMessageObject.messageOwner.reactions.recent_reactions != null && currentMessageObject.messageOwner.reactions.recent_reactions.size() == 1) { TLRPC.MessagePeerReaction recentReaction = currentMessageObject.messageOwner.reactions.recent_reactions.get(0); if (recentReaction != null) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(MessageObject.getPeerId(recentReaction.peer_id)); isMe = UserObject.isUserSelf(user); if (user != null) { userName = UserObject.getFirstName(user); } } } if (isMe) { sb.append(formatString("AccDescrYouReactedWith", R.string.AccDescrYouReactedWith, emoticon)); } else { sb.append(formatString("AccDescrReactedWith", R.string.AccDescrReactedWith, userName, emoticon)); } } else if (reaction.count > 1) { sb.append("\n"); sb.append(formatPluralString("AccDescrNumberOfPeopleReactions", reaction.count, emoticon)); } } else { sb.append(getString("Reactions", R.string.Reactions)).append((": ")); final int count = currentMessageObject.messageOwner.reactions.results.size(); for (int i = 0; i < count; ++i) { TLRPC.ReactionCount reactionCount = currentMessageObject.messageOwner.reactions.results.get(i); String emoticon = reactionCount.reaction instanceof TLRPC.TL_reactionEmoji ? ((TLRPC.TL_reactionEmoji) reactionCount.reaction).emoticon : ""; if (reactionCount != null) { sb.append(emoticon).append(" ").append(reactionCount.count + ""); if (i + 1 < count) { sb.append(", "); } } } sb.append("\n"); } } if ((currentMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { sb.append("\n"); sb.append(formatPluralString("AccDescrNumberOfViews", currentMessageObject.messageOwner.views)); } sb.append("\n"); CharacterStyle[] links = sb.getSpans(0, sb.length(), ClickableSpan.class); for (CharacterStyle link : links) { int start = sb.getSpanStart(link); int end = sb.getSpanEnd(link); sb.removeSpan(link); ClickableSpan underlineSpan = new ClickableSpan() { @Override public void onClick(View view) { if (link instanceof ProfileSpan) { ((ProfileSpan) link).onClick(view); } else if (delegate != null) { delegate.didPressUrl(ChatMessageCell.this, link, false); } } }; sb.setSpan(underlineSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } accessibilityText = sb; accessibilityTextUnread = unread; accessibilityTextContentUnread = contentUnread; accessibilityTextFileSize = fileSize; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { info.setContentDescription(accessibilityText.toString()); } else { info.setText(accessibilityText); } info.setEnabled(true); AccessibilityNodeInfo.CollectionItemInfo itemInfo = info.getCollectionItemInfo(); if (itemInfo != null) { info.setCollectionItemInfo(AccessibilityNodeInfo.CollectionItemInfo.obtain(itemInfo.getRowIndex(), 1, 0, 1, false)); } info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.acc_action_msg_options, getString("AccActionMessageOptions", R.string.AccActionMessageOptions))); int icon = getIconForCurrentState(); CharSequence actionLabel = null; switch (icon) { case MediaActionDrawable.ICON_PLAY: actionLabel = getString("AccActionPlay", R.string.AccActionPlay); break; case MediaActionDrawable.ICON_PAUSE: actionLabel = getString("AccActionPause", R.string.AccActionPause); break; case MediaActionDrawable.ICON_FILE: actionLabel = getString("AccActionOpenFile", R.string.AccActionOpenFile); break; case MediaActionDrawable.ICON_DOWNLOAD: actionLabel = getString("AccActionDownload", R.string.AccActionDownload); break; case MediaActionDrawable.ICON_CANCEL: actionLabel = getString("AccActionCancelDownload", R.string.AccActionCancelDownload); break; default: if (currentMessageObject.type == MessageObject.TYPE_PHONE_CALL) { actionLabel = getString("CallAgain", R.string.CallAgain); } } info.addAction(new AccessibilityNodeInfo.AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, actionLabel)); info.addAction(new AccessibilityNodeInfo.AccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK, getString("AccActionEnterSelectionMode", R.string.AccActionEnterSelectionMode))); int smallIcon = getMiniIconForCurrentState(); if (smallIcon == MediaActionDrawable.ICON_DOWNLOAD) { info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.acc_action_small_button, getString("AccActionDownload", R.string.AccActionDownload))); } if (drawSummarizeButton || drawSummaryReply) { info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.acc_action_summarize, getString("SummaryTitle", R.string.SummaryTitle))); } if (currentMessageObject.textLayoutBlocks != null) { for (MessageObject.TextLayoutBlock block : currentMessageObject.textLayoutBlocks) { if (block.hasCodeCopyButton) { info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.acc_action_copy_code, getString("CopyCode", R.string.CopyCode))); break; } } } if ((currentMessageObject.isVoice() || currentMessageObject.isRoundVideo() || currentMessageObject.isMusic()) && MediaController.getInstance().isPlayingMessage(currentMessageObject)) { seekBarAccessibilityDelegate.onInitializeAccessibilityNodeInfoInternal(info); } if (useTranscribeButton && transcribeButton != null) { info.addChild(ChatMessageCell.this, TRANSCRIBE); } int i; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { if (isChat && currentUser != null && !currentMessageObject.isOut()) { info.addChild(ChatMessageCell.this, PROFILE); } if (currentMessageObject.messageText instanceof Spannable) { Spannable buffer = (Spannable) currentMessageObject.messageText; CharacterStyle[] links = buffer.getSpans(0, buffer.length(), ClickableSpan.class); i = 0; for (CharacterStyle link : links) { info.addChild(ChatMessageCell.this, LINK_IDS_START + i); i++; } } if (currentMessageObject.caption instanceof Spannable && captionLayout != null) { Spannable buffer = (Spannable) currentMessageObject.caption; CharacterStyle[] links = buffer.getSpans(0, buffer.length(), ClickableSpan.class); i = 0; for (CharacterStyle link : links) { info.addChild(ChatMessageCell.this, LINK_CAPTION_IDS_START + i); i++; } } } i = 0; for (BotButton button : botButtons) { info.addChild(ChatMessageCell.this, BOT_BUTTONS_START + i); i++; } if (hintButtonVisible && pollHintX != -1 && currentMessageObject.isPoll()) { info.addChild(ChatMessageCell.this, POLL_HINT); } i = 0; for (PollButton button : pollButtons) { info.addChild(ChatMessageCell.this, POLL_BUTTONS_START + i); i++; } if (drawInstantView && !instantButtonRect.isEmpty()) { info.addChild(ChatMessageCell.this, INSTANT_VIEW); } if (drawContact && contactRect != null && !contactRect.isEmpty()) { info.addChild(ChatMessageCell.this, CONTACT); if (contactButtons != null && contactButtons.size() > 1) { for (InstantViewButton instantViewButton : contactButtons) { if (drawContactView && instantViewButton.type == INSTANT_BUTTON_TYPE_CONTACT_VIEW && !instantViewButton.rect.isEmpty()) { info.addChild(ChatMessageCell.this, CONTACT_VIEW); } if (drawContactAdd && instantViewButton.type == INSTANT_BUTTON_TYPE_CONTACT_ADD && !instantViewButton.rect.isEmpty()) { info.addChild(ChatMessageCell.this, CONTACT_ADD); } if (drawContactSendMessage && instantViewButton.type == INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE && !instantViewButton.rect.isEmpty()) { info.addChild(ChatMessageCell.this, CONTACT_MESSAGE); } } } } if (commentLayout != null) { info.addChild(ChatMessageCell.this, COMMENT); } if (drawSideButton == 1 || drawSideButton == 2) { info.addChild(ChatMessageCell.this, SHARE); } if (replyNameLayout != null) { info.addChild(ChatMessageCell.this, REPLY); } if (currentMessageObject != null && currentMessageObject.richLayout != null) { final RichMessageLayout richLayout = currentMessageObject.richLayout; int acc = 0; for (int b = 0; b < richLayout.blocks.size(); b++) { final RichMessageLayout.RichBlock block = richLayout.blocks.get(b); if (!block.isVisible()) { continue; } final int count = block.getAccessibilityElementCount(); for (int e = 0; e < count; e++) { info.addChild(ChatMessageCell.this, RICH_MEDIA_START + acc + e); } acc += count; } } if (forwardedNameLayout[0] != null && forwardedNameLayout[1] != null) { info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.acc_action_open_forwarded_origin, getString("AccActionOpenForwardedOrigin", R.string.AccActionOpenForwardedOrigin))); } if (drawSelectionBackground || getBackground() != null) { info.setSelected(true); } return info; } else { AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); info.setSource(ChatMessageCell.this, virtualViewId); info.setParent(ChatMessageCell.this); info.setPackageName(getContext().getPackageName()); if (virtualViewId == PROFILE) { if (currentUser == null) { return null; } String content = UserObject.getUserName(currentUser); info.setText(content); rect.set((int) nameX, (int) nameY, (int) (nameX + nameWidth), (int) (nameY + (nameLayout != null ? nameLayout.getHeight() : 10))); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClassName("android.widget.TextView"); info.setEnabled(true); info.setClickable(true); info.setLongClickable(true); info.addAction(AccessibilityNodeInfo.ACTION_CLICK); info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); } else if (virtualViewId >= RICH_MEDIA_START) { final int[] localElement = {0}; final RichMessageLayout.RichBlock block = resolveRichElement(virtualViewId, localElement); if (block == null) { return null; } info.setText(block.getAccessibilityElementText(localElement[0])); block.getAccessibilityElementBounds(localElement[0], rect); rect.offset(textX, textY); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); final boolean checkbox = block.isAccessibilityElementCheckbox(localElement[0]); if (checkbox) { info.setClassName("android.widget.CheckBox"); } else if (block.isAccessibilityElementText(localElement[0])) { info.setClassName("android.widget.TextView"); } else { info.setClassName("android.widget.ImageView"); } info.setEnabled(true); if (checkbox) { info.setCheckable(true); info.setChecked(block.isAccessibilityElementChecked(localElement[0])); } final boolean clickable = block.isAccessibilityElementClickable(localElement[0]); info.setClickable(clickable); if (clickable) { info.addAction(AccessibilityNodeInfo.ACTION_CLICK); } } else if (virtualViewId >= LINK_CAPTION_IDS_START) { if (!(currentMessageObject.caption instanceof Spannable) || captionLayout == null) { return null; } Spannable buffer = (Spannable) currentMessageObject.caption; ClickableSpan link = getLinkById(virtualViewId, false); if (link == null) { return null; } int[] linkPos = getRealSpanStartAndEnd(buffer, link); String content = buffer.subSequence(linkPos[0], linkPos[1]).toString(); info.setText(content); for (MessageObject.TextLayoutBlock block : captionLayout.textLayoutBlocks) { int length = block.textLayout.getText().length(); if (block.charactersOffset <= linkPos[0] && block.charactersOffset + length >= linkPos[1]) { block.textLayout.getSelectionPath(linkPos[0] - block.charactersOffset, linkPos[1] - block.charactersOffset, linkPath); linkPath.computeBounds(rectF, true); rect.set((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom); rect.offset(0, (int) block.textYOffset(captionLayout.textLayoutBlocks, transitionParams)); rect.offset(textX, textY); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); break; } } info.setClassName("android.widget.TextView"); info.setEnabled(true); info.setClickable(true); info.setLongClickable(true); info.addAction(AccessibilityNodeInfo.ACTION_CLICK); info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); } else if (virtualViewId >= LINK_IDS_START) { if (!(currentMessageObject.messageText instanceof Spannable)) { return null; } Spannable buffer = (Spannable) currentMessageObject.messageText; ClickableSpan link = getLinkById(virtualViewId, false); if (link == null) { return null; } int[] linkPos = getRealSpanStartAndEnd(buffer, link); String content = buffer.subSequence(linkPos[0], linkPos[1]).toString(); info.setText(content); for (MessageObject.TextLayoutBlock block : currentMessageObject.textLayoutBlocks) { int length = block.textLayout.getText().length(); if (block.charactersOffset <= linkPos[0] && block.charactersOffset + length >= linkPos[1]) { block.textLayout.getSelectionPath(linkPos[0] - block.charactersOffset, linkPos[1] - block.charactersOffset, linkPath); linkPath.computeBounds(rectF, true); rect.set((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom); rect.offset(0, (int) block.textYOffset(currentMessageObject.textLayoutBlocks, transitionParams)); rect.offset(textX, textY); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); break; } } info.setClassName("android.widget.TextView"); info.setEnabled(true); info.setClickable(true); info.setLongClickable(true); info.addAction(AccessibilityNodeInfo.ACTION_CLICK); info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); } else if (virtualViewId >= BOT_BUTTONS_START) { int buttonIndex = virtualViewId - BOT_BUTTONS_START; if (buttonIndex >= botButtons.size()) { return null; } BotButton button = botButtons.get(buttonIndex); if (button.isSeparator) { return null; } info.setText(button.title.getText()); info.setClassName("android.widget.Button"); info.setEnabled(true); info.setClickable(true); info.addAction(AccessibilityNodeInfo.ACTION_CLICK); rect.set((int) (button.x * widthForButtons), button.y, (int) ((button.x + button.width) * widthForButtons), button.y + button.height); int addX; if (currentMessageObject.isOutOwner()) { addX = getMeasuredWidth() - getWidthForButtons() - dp(10); } else { addX = backgroundDrawableLeft + dp(mediaBackground ? 1 : 7); } rect.offset(addX, layoutHeight); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); } else if (virtualViewId >= POLL_BUTTONS_START) { int buttonIndex = virtualViewId - POLL_BUTTONS_START; if (buttonIndex >= pollButtons.size()) { return null; } PollButton button = pollButtons.get(buttonIndex); StringBuilder sb = new StringBuilder(button.title.getText()); if (!pollVoted) { info.setClassName("android.widget.Button"); } else { info.setSelected(button.chosen); sb.append(", ").append(button.percent).append("%"); if (lastPoll != null && lastPoll.quiz && (button.chosen || button.correct)) { sb.append(", ").append(button.correct ? getString("AccDescrQuizCorrectAnswer", R.string.AccDescrQuizCorrectAnswer) : getString("AccDescrQuizIncorrectAnswer", R.string.AccDescrQuizIncorrectAnswer)); } } info.setText(sb); info.setEnabled(true); info.addAction(AccessibilityNodeInfo.ACTION_CLICK); final int y = button.y + namesOffset; final int w = backgroundWidth - dp(76); rect.set(button.x, y, button.x + w, y + button.height); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); } else if (virtualViewId == POLL_HINT) { info.setClassName("android.widget.Button"); info.setEnabled(true); info.setText(getString(R.string.AccDescrQuizExplanation)); info.addAction(AccessibilityNodeInfo.ACTION_CLICK); rect.set(pollHintX - dp(8), pollHintY - dp(8), pollHintX + dp(32), pollHintY + dp(32)); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); } else if (virtualViewId == INSTANT_VIEW) { info.setClassName("android.widget.Button"); info.setEnabled(true); if (instantViewLayout != null) { info.setText(instantViewLayout.getText()); } info.addAction(AccessibilityNodeInfo.ACTION_CLICK); instantButtonRect.round(rect); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); } else if (virtualViewId == CONTACT) { info.setClassName("android.widget.Button"); info.setEnabled(true); if (titleLayout != null) { info.setText(titleLayout.getText()); } info.addAction(AccessibilityNodeInfo.ACTION_CLICK); contactRect.round(rect); if (contactButtons != null && contactButtons.size() > 1) { InstantViewButton instantViewButton = contactButtons.get(0); if (!instantViewButton.rect.isEmpty()) { rect.set(rect.left, rect.top, rect.right, (int) (rect.bottom - instantViewButton.rect.height())); } } info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); } else if (virtualViewId == CONTACT_VIEW || virtualViewId == CONTACT_ADD || virtualViewId == CONTACT_MESSAGE) { int requiredType; if (virtualViewId == CONTACT_VIEW) { requiredType = INSTANT_BUTTON_TYPE_CONTACT_VIEW; } else if (virtualViewId == CONTACT_ADD) { requiredType = INSTANT_BUTTON_TYPE_CONTACT_ADD; } else { requiredType = INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE; } for (int i = 0; i < contactButtons.size(); i++) { InstantViewButton instantViewButton = contactButtons.get(i); if (instantViewButton.type == requiredType) { info.setClassName("android.widget.Button"); info.setEnabled(true); if (instantViewButton.layout != null) { info.setText(instantViewButton.layout.getText()); } info.addAction(AccessibilityNodeInfo.ACTION_CLICK); instantViewButton.rect.round(rect); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); break; } } } else if (virtualViewId == SHARE) { info.setClassName("android.widget.ImageButton"); info.setEnabled(true); if (isOpenChatByShare(currentMessageObject)) { info.setContentDescription(getString("AccDescrOpenChat", R.string.AccDescrOpenChat)); } else { info.setContentDescription(getString("ShareFile", R.string.ShareFile)); } info.addAction(AccessibilityNodeInfo.ACTION_CLICK); rect.set((int) sideStartX, (int) sideStartY, (int) sideStartX + dp(40), (int) sideStartY + dp(32)); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); } else if (virtualViewId == REPLY) { info.setEnabled(true); StringBuilder sb = new StringBuilder(); sb.append(getString("Reply", R.string.Reply)); sb.append(", "); if (replyNameLayout != null) { sb.append(replyNameLayout.getText()); sb.append(", "); } if (replyTextLayout != null) { sb.append(replyTextLayout.getText()); } info.setContentDescription(sb.toString()); info.addAction(AccessibilityNodeInfo.ACTION_CLICK); rect.set(replyStartX, replyStartY, replyStartX + Math.max(replyNameWidth, replyTextWidth), replyStartY + (int) replyHeight); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); } else if (virtualViewId == FORWARD) { info.setEnabled(true); StringBuilder sb = new StringBuilder(); if (forwardedNameLayout[0] != null && forwardedNameLayout[1] != null) { for (int a = 0; a < 2; a++) { sb.append(forwardedNameLayout[a].getText()); sb.append(a == 0 ? " " : "\n"); } } info.setContentDescription(sb.toString()); info.addAction(AccessibilityNodeInfo.ACTION_CLICK); int x = (int) Math.min(forwardNameX - forwardNameOffsetX[0], forwardNameX - forwardNameOffsetX[1]); rect.set(x, forwardNameY, x + forwardedNameWidth, forwardNameY + forwardHeight); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); } else if (virtualViewId == COMMENT) { info.setClassName("android.widget.Button"); info.setEnabled(true); int commentCount = getRepliesCount(); String comment = null; if (currentMessageObject != null && !currentMessageObject.shouldDrawWithoutBackground() && !currentMessageObject.isAnimatedEmoji()) { if (isRepliesChat) { comment = getString("ViewInChat", R.string.ViewInChat); } else { comment = commentCount == 0 ? getString("LeaveAComment", R.string.LeaveAComment) : formatPluralString("CommentsCount", commentCount); } } else if (!isRepliesChat && commentCount > 0) { comment = LocaleController.formatShortNumber(commentCount, null); } if (comment != null) { info.setText(comment); } info.addAction(AccessibilityNodeInfo.ACTION_CLICK); rect.set(commentButtonRect); info.setBoundsInParent(rect); if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); } rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); } else if (virtualViewId == TRANSCRIBE) { info.setClassName("android.widget.Button"); info.setEnabled(true); info.setText(currentMessageObject.isVoiceTranscriptionOpen() ? getString("AccActionCloseTranscription", R.string.AccActionCloseTranscription) : getString("AccActionOpenTranscription", R.string.AccActionOpenTranscription)); info.addAction(AccessibilityNodeInfo.ACTION_CLICK); if (transcribeButton != null) { rect.set((int) transcribeX, (int) transcribeY, (int) (transcribeX + transcribeButton.width()), (int) (transcribeY + transcribeButton.height())); } info.setBoundsInParent(rect); rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); } info.setFocusable(true); info.setVisibleToUser(true); return info; } } @Override public boolean performAction(int virtualViewId, int action, Bundle arguments) { if (virtualViewId == HOST_VIEW_ID) { performAccessibilityAction(action, arguments); } else { if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) { sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); } else if (action == AccessibilityNodeInfo.ACTION_CLICK) { if (virtualViewId == PROFILE) { if (delegate != null) { delegate.didPressUserAvatar(ChatMessageCell.this, currentUser, 0, 0, false); } } else if (virtualViewId >= RICH_MEDIA_START) { final int[] localElement = {0}; final RichMessageLayout.RichBlock block = resolveRichElement(virtualViewId, localElement); if (block != null && block.onAccessibilityElementClick(localElement[0], ChatMessageCell.this)) { sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); AndroidUtilities.makeAccessibilityAnnouncement(block.getAccessibilityElementStateDescription(localElement[0])); } } else if (virtualViewId >= LINK_CAPTION_IDS_START) { ClickableSpan link = getLinkById(virtualViewId, true); if (link != null) { delegate.didPressUrl(ChatMessageCell.this, link, false); sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); } } else if (virtualViewId >= LINK_IDS_START) { ClickableSpan link = getLinkById(virtualViewId, false); if (link != null) { delegate.didPressUrl(ChatMessageCell.this, link, false); sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); } } else if (virtualViewId >= BOT_BUTTONS_START) { int buttonIndex = virtualViewId - BOT_BUTTONS_START; if (buttonIndex >= botButtons.size()) { return false; } BotButton button = botButtons.get(buttonIndex); if (delegate != null && !button.isLocked) { if (button.buttonCustom != null) { delegate.didPressCustomBotButton(ChatMessageCell.this, button.buttonCustom); } else if (button.button != null) { delegate.didPressBotButton(ChatMessageCell.this, button.button); } } sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); } else if (virtualViewId >= POLL_BUTTONS_START) { int buttonIndex = virtualViewId - POLL_BUTTONS_START; if (buttonIndex >= pollButtons.size()) { return false; } PollButton button = pollButtons.get(buttonIndex); if (delegate != null) { ArrayList answers = new ArrayList<>(); answers.add(button.answer); delegate.didPressVoteButtons(ChatMessageCell.this, answers, -1, 0, 0); } sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); } else if (virtualViewId == POLL_HINT) { didPressVoteHint(); } else if (virtualViewId == INSTANT_VIEW) { if (delegate != null) { delegate.didPressInstantButton(ChatMessageCell.this, drawInstantViewType); } } else if (virtualViewId == CONTACT) { if (delegate != null) { delegate.didPressInstantButton(ChatMessageCell.this, INSTANT_BUTTON_TYPE_CONTACT_VIEW); } } else if (virtualViewId == CONTACT_VIEW) { if (delegate != null) { delegate.didPressInstantButton(ChatMessageCell.this, INSTANT_BUTTON_TYPE_CONTACT_VIEW); } } else if (virtualViewId == CONTACT_ADD) { if (delegate != null) { delegate.didPressInstantButton(ChatMessageCell.this, INSTANT_BUTTON_TYPE_CONTACT_ADD); } } else if (virtualViewId == CONTACT_MESSAGE) { if (delegate != null) { delegate.didPressInstantButton(ChatMessageCell.this, INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE); } } else if (virtualViewId == SHARE) { if (delegate != null) { delegate.didPressSideButton(ChatMessageCell.this); } } else if (virtualViewId == REPLY) { if (delegate != null && (!isThreadChat || isMonoForum || currentMessageObject.getReplyTopMsgId() != 0) && (currentMessageObject.hasValidReplyMessageObject() || hasReplyQuote || currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.reply_to != null && currentMessageObject.messageOwner.reply_to.reply_from != null)) { delegate.didPressReplyMessage(ChatMessageCell.this, currentMessageObject.getReplyMsgId(), 0, 0, false); } } else if (virtualViewId == FORWARD) { if (delegate != null) { if (currentForwardChannel != null) { delegate.didPressChannelAvatar(ChatMessageCell.this, currentForwardChannel, currentMessageObject.messageOwner.fwd_from.channel_post, lastTouchX, lastTouchY, false); } else if (currentForwardUser != null) { delegate.didPressUserAvatar(ChatMessageCell.this, currentForwardUser, lastTouchX, lastTouchY, false); } else if (currentForwardName != null) { delegate.didPressHiddenForward(ChatMessageCell.this); } } } else if (virtualViewId == COMMENT) { if (delegate != null) { if (isRepliesChat) { delegate.didPressSideButton(ChatMessageCell.this); } else { delegate.didPressCommentButton(ChatMessageCell.this); } } } else if (virtualViewId == TRANSCRIBE && transcribeButton != null) { transcribeButton.onTap(); } } else if (action == AccessibilityNodeInfo.ACTION_LONG_CLICK) { ClickableSpan link = getLinkById(virtualViewId, virtualViewId >= LINK_CAPTION_IDS_START); if (link != null && delegate != null) { delegate.didPressUrl(ChatMessageCell.this, link, true); sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); } } } return true; } private ClickableSpan getLinkById(int id, boolean caption) { if (id == PROFILE) { return null; } if (caption) { id -= LINK_CAPTION_IDS_START; if (!(currentMessageObject.caption instanceof Spannable) || id < 0) { return null; } Spannable buffer = (Spannable) currentMessageObject.caption; ClickableSpan[] links = buffer.getSpans(0, buffer.length(), ClickableSpan.class); if (links.length <= id) { return null; } return links[id]; } else { id -= LINK_IDS_START; if (!(currentMessageObject.messageText instanceof Spannable) || id < 0) { return null; } Spannable buffer = (Spannable) currentMessageObject.messageText; ClickableSpan[] links = buffer.getSpans(0, buffer.length(), ClickableSpan.class); if (links.length <= id) { return null; } return links[id]; } } } public void setImageCoords(RectF rect) { setImageCoords(rect.left, rect.top, rect.width(), rect.height()); } public void setImageCoords(float x, float y, float w, float h) { photoImage.setImageCoords(x, y, w, h); if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { videoButtonX = (int) (photoImage.getImageX() + dp(8)); videoButtonY = (int) (photoImage.getImageY() + dp(8)); videoRadialProgress.setProgressRect(videoButtonX, videoButtonY, videoButtonX + dp(24), videoButtonY + dp(24)); buttonX = (int) (x + (photoImage.getImageWidth() - dp(48)) / 2.0f); buttonY = (int) (photoImage.getImageY() + (photoImage.getImageHeight() - dp(48)) / 2); radialProgress.setProgressRect(buttonX, buttonY, buttonX + dp(48), buttonY + dp(48)); } } @Override public float getAlpha() { if (ALPHA_PROPERTY_WORKAROUND) { return alphaInternal; } return super.getAlpha(); } @Override public void setAlpha(float alpha) { if ((alpha == 1f) != (getAlpha() == 1)) { invalidate(); } if (ALPHA_PROPERTY_WORKAROUND) { alphaInternal = alpha; invalidate(); } else { super.setAlpha(alpha); } if ((currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0) && !(enterTransitionInProgress && !currentMessageObject.isVoice()) && replyNameLayout != null && replyTextLayout != null || // Reply layout (currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) && !reactionsLayoutInBubble.isSmall) { // Reactions invalidate(); } } public int getCurrentBackgroundLeft() { if (currentBackgroundDrawable == null) { return 0; } int left = currentBackgroundDrawable.getBounds().left; if (!currentMessageObject.isOutOwner() && transitionParams.changePinnedBottomProgress != 1 && (isRoundVideo || !mediaBackground) && !drawPinnedBottom) { if (isRoundVideo) { left -= dp(6) * (getVideoTranscriptionProgress()); } else { left -= dp(6); } } return left; } public int getCurrentBackgroundRight() { if (currentBackgroundDrawable == null) { return getWidth(); } int right = currentBackgroundDrawable.getBounds().right; if (currentMessageObject.isOutOwner() && transitionParams.changePinnedBottomProgress != 1 && (isRoundVideo || !mediaBackground) && !drawPinnedBottom) { if (isRoundVideo) { right += dp(6) * (getVideoTranscriptionProgress()); } else { right += dp(6); } } return right; } public float getPaddingTopAnimated() { return getTopicSeparatorTopPadding() + starsPriceTopPadding + suggestionOfferTopPadding; } public TransitionParams getTransitionParams() { return transitionParams; } public float getDeltaTop() { return transitionParams.deltaTop; } public float getDeltaLeft() { return transitionParams.deltaLeft; } public float getDeltaRight() { return transitionParams.deltaRight; } public float getDeltaBottom() { return transitionParams.deltaBottom; } public int getTopMediaOffset() { if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_MUSIC) { return mediaOffsetY + namesOffset; } return 0; } public int getMediaOffsetY() { if (transitionParams.animateMediaOffsetY) { return AndroidUtilities.lerp(transitionParams.animateFromMediaOffsetY, mediaOffsetY, transitionParams.animateChangeProgress); } return mediaOffsetY; } public int getTextX() { return textX; } public int getTextY() { return textY; } public boolean isPlayingRound() { return isRoundVideo && isPlayingRound; } public int getParentWidth() { MessageObject object = currentMessageObject == null ? messageObjectToSet : currentMessageObject; if (object != null && object.preview && parentWidth > 0) { return parentWidth; } return AndroidUtilities.displaySize.x; } public class TransitionParams { public float lastDrawingImageX, lastDrawingImageY, lastDrawingImageW, lastDrawingImageH; public float lastDrawingCaptionX, lastDrawingCaptionY; public boolean animateChange; public int animateFromRepliesTextWidth; public boolean messageEntering; public boolean animateLocationIsExpired; public boolean lastLocatinIsExpired; public String lastDrawLocationExpireText; public float lastDrawLocationExpireProgress; public StaticLayout lastDrawDocTitleLayout; public StaticLayout lastDrawInfoLayout; public boolean updatePhotoImageX; public boolean animateRoundVideoDotY; public float lastDrawRoundVideoDotY; public float animateFromRoundVideoDotY; public boolean animateReplyY; public float lastDrawReplyY; public float animateFromReplyY; public boolean lastDrawingSmallImage; public int lastDrawnMonoforumPadding; public int lastDrawnStarsPriceTopPadding; public int lastDrawnBottomActionPadding; public boolean lastDrawnStarsPriceText; public boolean lastDrawnBottomActionText; public boolean lastIsPinned; private boolean animatePinned; public float lastTimeXPinned; public float animateFromTimeXPinned; public int lastRepliesCount; private boolean animateReplies; public StaticLayout lastRepliesLayout; private StaticLayout animateRepliesLayout; private float animateFromTimeXReplies; private float lastTimeXReplies; private float animateFromTimeXViews; private float lastTimeXViews; public int lastCommentsCount; public int lastTotalCommentWidth; public int lastCommentArrowX; public int lastCommentUnreadX; public boolean lastCommentDrawUnread; public float lastCommentX; public boolean lastDrawCommentNumber; public StaticLayout lastCommentLayout; private boolean animateComments; private StaticLayout animateCommentsLayout; private float animateCommentX; private int animateTotalCommentWidth; private int animateCommentArrowX; private int animateCommentUnreadX; private boolean animateCommentDrawUnread; private boolean animateDrawCommentNumber; private boolean animateSign; private float animateNameX; public String lastSignMessage; public boolean imageChangeBoundsTransition; public float deltaLeft; public float deltaRight; public float deltaBottom; public float deltaTop; // in animation, describe to what values deltaLeft and deltaRight moves to public float toDeltaLeft, toDeltaRight; public float animateToImageX, animateToImageY, animateToImageW, animateToImageH; public float captionFromX, captionFromY; private boolean moveCaption; public int[] imageRoundRadius = new int[4]; public float captionEnterProgress = 1f; public boolean wasDraw; public boolean animateBackgroundBoundsInner; public boolean animateBackgroundWidth; public boolean ignoreAlpha; public boolean drawPinnedBottomBackground; public float changePinnedBottomProgress = 1f; public int[] animateToRadius; public boolean animateRadius; public boolean transformGroupToSingleMessage; public Rect lastDrawingBackgroundRect = new Rect(); public boolean lastDrawingSideMenuEnabled; public boolean animateDrawingSideMenuEnabled; public boolean animateMessageText; private ArrayList animateOutTextBlocks; public ArrayList lastDrawingTextBlocks; private int lastDrawingTextWidth; public boolean animateRichLayout; private RichMessageLayout animateOutRichLayout; public RichMessageLayout lastDrawingRichLayout; private float animateOutTextXOffset; private AnimatedEmojiSpan.EmojiGroupedSpans animateOutAnimateEmoji; public float lastDrawingReplyTextHeight; private float animateFromReplyTextHeight; private StaticLayout animateReplyTextLayout; private AnimatedEmojiSpan.EmojiGroupedSpans animateOutAnimateEmojiReply; private boolean animateEditedEnter; private StaticLayout animateEditedLayout; private StaticLayout animateTimeLayout; private int animateTimeWidth; public int lastTimeWidth; private int animateEditedWidthDiff; public boolean lastDrawingEdited; boolean animateReplaceCaptionLayout; private MessageObject.TextLayoutBlocks animateOutCaptionLayout; public MessageObject.TextLayoutBlocks lastDrawingCaptionLayout; public boolean lastDrawingSummarized; public boolean lastDrawTime; public int lastTimeX; public int animateFromTimeX; public boolean shouldAnimateTimeX; public int lastBackgroundLeft, lastBackgroundRight; public boolean lastDrawBackground; public boolean animateDrawBackground; public boolean lastUseTranscribeButton; public boolean animateUseTranscribeButton; public float photoImageFromWidth, photoImageFromHeight; public float photoImageFromCenterX, photoImageFromCenterY; public boolean animateSmallImage; public int animateMonoforumPaddingFrom; public boolean animateMonoforumPadding; public boolean needsStopClipping; public boolean animateStarsPriceText; public int animateStarsPriceTopPaddingFrom; public boolean animateStarsPriceTopPadding; public boolean animateBottomActionText; public int animateBottomActionPaddingFrom; public boolean animateBottomActionPadding; public boolean lastDrawingLinkAbove; public boolean animateLinkAbove; public boolean lastDrawingMediaAbove; public boolean animateMediaAbove; public int lastDrawingLinkPreviewHeight; public int animateFromLinkPreviewHeight; public boolean animateLinkPreviewHeight; public boolean animateDrawingTimeAlpha; public float animateChangeProgress = 1f; private ArrayList lastDrawBotButtons = new ArrayList<>(); private ArrayList transitionBotButtons = new ArrayList<>(); public boolean animateWidthForButton; public int animateFromWidthForButton; public int lastDrawnWidthForButtons; public final float crossfadeProgressK = 0.5f; public float oldProgress = 0.0f, newProgress = 1.0f; private void updateCrossfadeProgress() { final float progress = Math.max(0.0f, Math.min(1.0f, animateChangeProgress)); oldProgress = (float) Math.pow(1.0f - progress, crossfadeProgressK); newProgress = (float) Math.pow(progress, crossfadeProgressK); } public float lastButtonX; public float lastButtonY; private float animateFromButtonX; private float animateFromButtonY; private boolean animateButton; public int lastMediaOffsetY; private int animateFromMediaOffsetY; private boolean animateMediaOffsetY; public int lastStatusDrawableParams = -1; public int lastViewsCount; public StaticLayout lastViewsLayout; private StaticLayout animateViewsLayout; public boolean lastShouldDrawTimeOnMedia; private boolean animateShouldDrawTimeOnMedia; public boolean lastShouldDrawMenuDrawable; private boolean animateShouldDrawMenuDrawable; public StaticLayout lastTimeLayout; public boolean lastIsPlayingRound; public boolean animatePlayingRound; public boolean animateTextY; public float lastDrawingTextY; public float lastDrawingTextX; public float animateFromTextY; public float lastTextXOffset; public int lastDrawingLinkPreviewY; public int animateFromLinkPreviewY; public boolean animateLinkPreviewY; public int lastTopOffset; public boolean animateForwardedLayout; public int animateForwardedNamesOffset; public int lastForwardedNamesOffset; public boolean lastDrawnForwardedName; public StaticLayout[] lastDrawnForwardedNameLayout = new StaticLayout[2]; public StaticLayout[] animatingForwardedNameLayout = new StaticLayout[2]; float animateForwardNameX; public float lastForwardNameX; int animateForwardNameWidth; public int lastForwardNameWidth; boolean animateBotButtonsChanged; public StaticLayout lastDrawnReplyTextLayout; public boolean animateNamesOffset; public int animateNamesOffsetFrom; public int lastNamesOffset; public int lastReplyTextXOffset; public float animateReplyTextOffset; public boolean lastDrawingRecommendationsExpanded; public boolean animateRecommendationsExpanded; public boolean animateFromRecommendationsExpanded; public boolean lastDrawNameLayout; public boolean lastDrawAvatar; public boolean lastDrawTopic; public boolean animateDrawNameLayout; public boolean animateDrawAvatar; public boolean animateDrawTopic; public boolean lastDrawingFactCheck; public boolean animateFactCheck; public int lastDrawingFactCheckHeight; public int animateFactCheckHeightFrom; public boolean animatePollAddOptionHeight; public int lastDrawingPollAddOptionHeight; public int animatePollAddOptionHeightFrom; public boolean animateFactCheckHeight; public boolean lastDrawingFactCheckExpanded; public boolean animateFactCheckExpanded; public boolean lastDrawingSummaryReply; public boolean animateSummaryReply; public HashSet lastDrawingExpandedQuotes; public HashSet animateExpandedQuotesFrom; public boolean animateExpandedQuotes; public boolean lastDrawingExpandedExplanation; public boolean expandedExplanationFrom; public boolean animateExpandedExplanation; public boolean lastDrawnTranslated; public StaticLayout lastDrawnTitleLayout; public StaticLayout animateTitleLayout; private AnimatedEmojiSpan.EmojiGroupedSpans animateTitleLayoutEmoji; public void recordDrawingState() { wasDraw = true; lastDrawingImageX = photoImage.getImageX(); lastDrawingImageY = photoImage.getImageY(); lastDrawingImageW = photoImage.getImageWidth(); lastDrawingImageH = photoImage.getImageHeight(); int[] r = photoImage.getRoundRadius(); System.arraycopy(r, 0, imageRoundRadius, 0, 4); if (currentBackgroundDrawable != null) { lastDrawingBackgroundRect.set(currentBackgroundDrawable.getBounds()); } lastDrawingSideMenuEnabled = isSideMenuEnabled; lastDrawingTextBlocks = currentMessageObject != null ? currentMessageObject.textLayoutBlocks : null; lastDrawingTextWidth = currentMessageObject != null ? currentMessageObject.textWidth : 0; lastDrawingEdited = edited; lastDrawingRichLayout = currentMessageObject != null ? currentMessageObject.richLayout : null; lastDrawingCaptionX = captionX; lastDrawingCaptionY = captionY; lastDrawingCaptionLayout = captionLayout; lastDrawingSummarized = currentMessageObject != null ? currentMessageObject.summarized : false; lastDrawBotButtons.clear(); if (!botButtons.isEmpty()) { lastDrawBotButtons.addAll(botButtons); } lastDrawingSmallImage = isSmallImage; lastDrawnMonoforumPadding = topicSeparatorTopPadding; lastDrawnStarsPriceTopPadding = starsPriceTopPadding; lastDrawnBottomActionPadding = bottomActionPadding; lastDrawnStarsPriceText = starsPriceText != null; lastDrawnBottomActionText = bottomActionText != null; lastDrawingLinkPreviewHeight = linkPreviewHeight; lastDrawingLinkAbove = linkPreviewAbove; lastDrawingMediaAbove = captionAbove; lastDrawingRecommendationsExpanded = currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL && channelRecommendationsCell != null && channelRecommendationsCell.isExpanded(); if (commentLayout != null) { lastCommentsCount = getRepliesCount(); lastTotalCommentWidth = totalCommentWidth; lastCommentLayout = commentLayout; lastCommentArrowX = commentArrowX; lastCommentUnreadX = commentUnreadX; lastCommentDrawUnread = commentDrawUnread; lastCommentX = commentX; lastDrawCommentNumber = drawCommentNumber; } lastRepliesCount = getRepliesCount(); this.lastViewsCount = getMessageObject().messageOwner.views; lastRepliesLayout = repliesLayout; lastViewsLayout = viewsLayout; lastIsPinned = isPinned; lastSignMessage = lastPostAuthor; lastDrawBackground = drawBackground; lastUseTranscribeButton = useTranscribeButton; lastButtonX = buttonX; lastButtonY = buttonY; lastMediaOffsetY = mediaOffsetY; lastDrawTime = !forceNotDrawTime; lastTimeX = timeX; lastTimeLayout = timeLayout; lastTimeWidth = timeWidth; lastShouldDrawTimeOnMedia = shouldDrawTimeOnMedia(); lastTopOffset = getTopMediaOffset(); lastShouldDrawMenuDrawable = shouldDrawMenuDrawable(); lastLocatinIsExpired = locationExpired; lastIsPlayingRound = isPlayingRound; lastDrawingTextY = textY; lastDrawingTextX = textX; lastDrawingLinkPreviewY = linkPreviewY; lastDrawnWidthForButtons = widthForButtons; lastDrawnForwardedNameLayout[0] = forwardedNameLayout[0]; lastDrawnForwardedNameLayout[1] = forwardedNameLayout[1]; lastDrawnForwardedName = currentMessageObject != null && currentMessageObject.needDrawForwarded(); lastForwardNameX = forwardNameX; lastNamesOffset = lastForwardedNamesOffset = namesOffset; lastForwardNameWidth = forwardedNameWidth; lastBackgroundLeft = getCurrentBackgroundLeft(); if (currentBackgroundDrawable != null) { lastBackgroundRight = currentBackgroundDrawable.getBounds().right; } lastTextXOffset = currentMessageObject != null ? currentMessageObject.textXOffset : 0; lastDrawingReplyTextHeight = replyTextHeight; lastDrawnReplyTextLayout = replyTextLayout; lastReplyTextXOffset = replyTextOffset; reactionsLayoutInBubble.recordDrawingState(); if (replyNameLayout != null) { lastDrawReplyY = replyStartY; } else { lastDrawReplyY = 0; } lastDrawNameLayout = drawNameLayout; lastDrawAvatar = drawNameAvatar; lastDrawTopic = drawTopic; lastDrawingFactCheckHeight = factCheckHeight; lastDrawingFactCheckExpanded = getPrimaryMessageObject() != null && getPrimaryMessageObject().factCheckExpanded; lastDrawingFactCheck = hasFactCheck; lastDrawingPollAddOptionHeight = pollAddButtonHeight; lastDrawingSummaryReply = drawSummaryReply; lastDrawingExpandedQuotes = getPrimaryMessageObject() != null ? getPrimaryMessageObject().expandedQuotes : null; lastDrawingExpandedExplanation = currentMessageObject != null && currentMessageObject.expandedExplanation; lastDrawnTranslated = currentMessageObject != null && currentMessageObject.translated; lastDrawnTitleLayout = titleLayout; } public void recordDrawingStatePreview() { lastDrawnForwardedNameLayout[0] = forwardedNameLayout[0]; lastDrawnForwardedNameLayout[1] = forwardedNameLayout[1]; lastDrawnForwardedName = currentMessageObject.needDrawForwarded(); lastForwardNameX = forwardNameX; lastNamesOffset = lastForwardedNamesOffset = namesOffset; lastForwardNameWidth = forwardedNameWidth; } public boolean animateChange() { if (!wasDraw) { return false; } boolean changed = false; needsStopClipping = false; animateDrawingSideMenuEnabled = false; if (lastDrawingSideMenuEnabled != isSideMenuEnabled) { animateDrawingSideMenuEnabled = true; changed = true; } animateMessageText = false; if (currentMessageObject.textLayoutBlocks != lastDrawingTextBlocks) { boolean sameText = true; if (currentMessageObject.textWidth != lastDrawingTextWidth && lastDrawingSideMenuEnabled != isSideMenuEnabled) { sameText = false; } if (currentMessageObject.textLayoutBlocks != null && lastDrawingTextBlocks != null && currentMessageObject.textLayoutBlocks.size() == lastDrawingTextBlocks.size()) { for (int i = 0; i < lastDrawingTextBlocks.size(); i++) { String newText = currentMessageObject.textLayoutBlocks.get(i).textLayout == null ? null : currentMessageObject.textLayoutBlocks.get(i).textLayout.getText().toString(); String oldText = lastDrawingTextBlocks.get(i).textLayout == null ? null : lastDrawingTextBlocks.get(i).textLayout.getText().toString(); if ((newText == null && oldText != null) || (newText != null && oldText == null) || !newText.equals(oldText)) { sameText = false; break; } else { if (animatedEmojiStack != null) { animatedEmojiStack.replaceLayout(currentMessageObject.textLayoutBlocks.get(i).textLayout, lastDrawingTextBlocks.get(i).textLayout); } } } } else { sameText = false; } if (!sameText) { animateMessageText = true; animateOutTextBlocks = lastDrawingTextBlocks; animateOutTextXOffset = lastTextXOffset; animateOutAnimateEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animateOutAnimateEmoji, lastDrawingTextBlocks, true); animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animatedEmojiStack, currentMessageObject.textLayoutBlocks); changed = true; } else { animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animatedEmojiStack, currentMessageObject.textLayoutBlocks); } } if (currentMessageObject.richLayout != null && (currentMessageObject.richLayout.detailsAnimating || currentMessageObject.richLayout.blockquoteAnimating)) { needsStopClipping = true; changed = true; } animateRichLayout = false; if (currentMessageObject.richLayout != lastDrawingRichLayout) { final boolean streaming = botDraftTypingAnimator != null && botDraftTypingAnimator.isRunning(); if (animateOutRichLayout != null) { animateOutRichLayout.detach(ChatMessageCell.this); animateOutRichLayout = null; } if (streaming) { if (currentMessageObject.richLayout != null && lastDrawingRichLayout != null) { currentMessageObject.richLayout.layout(lastDrawingRichLayout); } } else { animateRichLayout = true; animateOutRichLayout = lastDrawingRichLayout; if (animateOutRichLayout != null) { animateOutRichLayout.attach(ChatMessageCell.this); } } } animateDrawNameLayout = false; if (drawNameLayout != lastDrawNameLayout) { animateDrawNameLayout = true; changed = true; } animateDrawAvatar = false; if (drawNameAvatar != lastDrawAvatar) { animateDrawAvatar = true; changed = true; } animateDrawTopic = false; if (drawTopic != lastDrawTopic) { animateDrawTopic = true; changed = true; } if (replyTextLayout != lastDrawnReplyTextLayout) { CharSequence newText = replyTextLayout != null ? replyTextLayout.getText() : null; CharSequence oldText = lastDrawnReplyTextLayout != null ? lastDrawnReplyTextLayout.getText() : null; if (!TextUtils.equals(newText, oldText)) { animateFromReplyTextHeight = lastDrawingReplyTextHeight; animateReplyTextLayout = lastDrawnReplyTextLayout; animateReplyTextOffset = lastReplyTextXOffset; animateOutAnimateEmojiReply = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, false, animateOutAnimateEmojiReply, true, lastDrawnReplyTextLayout); changed = true; } } if (edited && !lastDrawingEdited && timeLayout != null) { String editedStr = getString("EditedMessage", R.string.EditedMessage); CharSequence text = timeLayout.getText(); int i = text.toString().indexOf(editedStr); if (i >= 0) { if (i == 0) { animateEditedLayout = new StaticLayout(editedStr, Theme.chat_timePaint, timeTextWidth + dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append(editedStr); spannableStringBuilder.append(text.subSequence(editedStr.length(), text.length())); spannableStringBuilder.setSpan(new EmptyStubSpan(), 0, editedStr.length(), 0); animateTimeLayout = new StaticLayout(spannableStringBuilder, Theme.chat_timePaint, timeTextWidth + dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); animateEditedWidthDiff = timeWidth - lastTimeWidth; } else { animateEditedWidthDiff = 0; animateEditedLayout = null; animateTimeLayout = lastTimeLayout; } animateEditedEnter = true; animateTimeWidth = lastTimeWidth; animateFromTimeX = lastTimeX; shouldAnimateTimeX = true; changed = true; } accessibilityText = null; } else if (!edited && lastDrawingEdited && timeLayout != null) { animateTimeLayout = lastTimeLayout; animateEditedWidthDiff = timeWidth - lastTimeWidth; animateEditedEnter = true; animateTimeWidth = lastTimeWidth; animateFromTimeX = lastTimeX; shouldAnimateTimeX = true; changed = true; } animateDrawBackground = false; if (drawBackground != lastDrawBackground) { animateDrawBackground = true; changed = true; } animateSmallImage = false; if (isSmallImage != lastDrawingSmallImage) { animateSmallImage = true; photoImageFromWidth = lastDrawingImageW; photoImageFromHeight = lastDrawingImageH; photoImageFromCenterX = lastDrawingImageX + lastDrawingImageW / 2f; photoImageFromCenterY = lastDrawingImageY + lastDrawingImageH / 2f; changed = true; } animateMonoforumPadding = false; if (topicSeparatorTopPadding != lastDrawnMonoforumPadding) { needsStopClipping = true; animateMonoforumPaddingFrom = lastDrawnMonoforumPadding; animateMonoforumPadding = true; changed = true; } animateStarsPriceTopPadding = false; if (starsPriceTopPadding != lastDrawnStarsPriceTopPadding) { animateStarsPriceTopPaddingFrom = lastDrawnStarsPriceTopPadding; animateStarsPriceTopPadding = true; changed = true; } animateStarsPriceText = false; if ((starsPriceText != null) != lastDrawnStarsPriceText) { animateStarsPriceText = true; changed = true; } animateBottomActionPadding = false; if (bottomActionPadding != lastDrawnBottomActionPadding) { animateBottomActionPaddingFrom = lastDrawnBottomActionPadding; animateBottomActionPadding = true; changed = true; } animateBottomActionText = false; if ((bottomActionText != null) != lastDrawnBottomActionText) { animateBottomActionText = true; changed = true; } animateRecommendationsExpanded = false; final boolean channelsExpanded = currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL && channelRecommendationsCell != null && channelRecommendationsCell.isExpanded(); if (channelsExpanded != lastDrawingRecommendationsExpanded) { animateRecommendationsExpanded = true; animateFromRecommendationsExpanded = lastDrawingRecommendationsExpanded; changed = true; } animateLinkAbove = false; if (linkPreviewAbove != lastDrawingLinkAbove) { animateLinkAbove = true; changed = true; } animateMediaAbove = false; if (captionAbove != lastDrawingMediaAbove) { animateMediaAbove = true; changed = true; } animateLinkPreviewHeight = false; if (hasLinkPreview && linkPreviewHeight != lastDrawingLinkPreviewHeight) { animateLinkPreviewHeight = true; animateFromLinkPreviewHeight = lastDrawingLinkPreviewHeight; changed = true; } animateUseTranscribeButton = false; if (useTranscribeButton != lastUseTranscribeButton) { animateUseTranscribeButton = true; changed = true; } boolean summarized = currentMessageObject != null ? currentMessageObject.summarized : false; if (captionLayout != lastDrawingCaptionLayout) { String oldCaption = lastDrawingCaptionLayout == null ? null : lastDrawingCaptionLayout.text.toString(); String currentCaption = captionLayout == null ? null : captionLayout.text.toString(); if ( (lastDrawingSideMenuEnabled != isSideMenuEnabled || lastDrawingSummarized != summarized) && (captionLayout == null ? 0 : captionLayout.textWidth) != (lastDrawingCaptionLayout == null ? 0 : lastDrawingCaptionLayout.textWidth) || (currentCaption == null) != (oldCaption == null) || (oldCaption != null && !oldCaption.equals(currentCaption)) ) { animateReplaceCaptionLayout = true; animateOutCaptionLayout = lastDrawingCaptionLayout; animateOutAnimateEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, null, animateOutCaptionLayout == null ? null : animateOutCaptionLayout.textLayoutBlocks); animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animatedEmojiStack, captionLayout == null ? null : captionLayout.textLayoutBlocks); if (lastDrawingSideMenuEnabled != isSideMenuEnabled || lastDrawingSummarized != summarized) { moveCaption = true; captionFromX = lastDrawingCaptionX; captionFromY = lastDrawingCaptionY; } changed = true; } else { updateCaptionLayout(); if (lastDrawingCaptionX != captionX || lastDrawingCaptionY != captionY) { moveCaption = true; captionFromX = lastDrawingCaptionX; captionFromY = lastDrawingCaptionY; changed = true; } } } else if (captionLayout != null && lastDrawingCaptionLayout != null) { updateCaptionLayout(); if (lastDrawingCaptionX != captionX || lastDrawingCaptionY != captionY) { moveCaption = true; captionFromX = lastDrawingCaptionX; captionFromY = lastDrawingCaptionY; changed = true; } } if (!lastDrawBotButtons.isEmpty() || !botButtons.isEmpty()) { if (lastDrawBotButtons.size() != botButtons.size()) { animateBotButtonsChanged = true; } if (!animateBotButtonsChanged) { for (int i = 0; i < botButtons.size(); i++) { BotButton button1 = botButtons.get(i); BotButton button2 = lastDrawBotButtons.get(i); if (button1.isSeparator || button2.isSeparator) { continue; } if (Math.abs(button1.x - button2.x) > 0.01f || Math.abs(button1.width - button2.width) > 0.01f || !TextUtils.equals(button1.title.getText(), button2.title.getText())) { animateBotButtonsChanged = true; break; } } } if (animateBotButtonsChanged) { transitionBotButtons.addAll(lastDrawBotButtons); } } if (lastDrawnWidthForButtons != widthForButtons) { animateFromWidthForButton = lastDrawnWidthForButtons; animateWidthForButton = true; } if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { if (buttonX != lastButtonX || buttonY != lastButtonY) { animateFromButtonX = lastButtonX; animateFromButtonY = lastButtonY; animateButton = true; changed = true; } } if (mediaOffsetY != lastMediaOffsetY) { animateFromMediaOffsetY = lastMediaOffsetY; animateMediaOffsetY = true; changed = true; } boolean timeDrawablesIsChanged = false; if (lastIsPinned != isPinned) { animatePinned = true; changed = true; timeDrawablesIsChanged = true; accessibilityText = null; } if ((lastRepliesLayout != null || repliesLayout != null) && lastRepliesCount != getRepliesCount()) { animateRepliesLayout = lastRepliesLayout; animateReplies = true; changed = true; timeDrawablesIsChanged = true; accessibilityText = null; } if (lastViewsLayout != null && this.lastViewsCount != getMessageObject().messageOwner.views) { animateViewsLayout = lastViewsLayout; changed = true; timeDrawablesIsChanged = true; accessibilityText = null; } if (commentLayout != null && lastCommentsCount != getRepliesCount()) { if (lastCommentLayout != null && !TextUtils.equals(lastCommentLayout.getText(), commentLayout.getText())) { animateCommentsLayout = lastCommentLayout; } else { animateCommentsLayout = null; } animateTotalCommentWidth = lastTotalCommentWidth; animateCommentX = lastCommentX; animateCommentArrowX = lastCommentArrowX; animateCommentUnreadX = lastCommentUnreadX; animateCommentDrawUnread = lastCommentDrawUnread; animateDrawCommentNumber = lastDrawCommentNumber; animateComments = true; changed = true; } if (!TextUtils.equals(lastSignMessage, lastPostAuthor)) { animateSign = true; animateNameX = nameX; changed = true; } if (lastDrawTime == forceNotDrawTime) { animateDrawingTimeAlpha = true; animateViewsLayout = null; changed = true; } else if (lastShouldDrawTimeOnMedia != shouldDrawTimeOnMedia()) { animateEditedEnter = false; animateShouldDrawTimeOnMedia = true; animateFromTimeX = lastTimeX; animateTimeLayout = lastTimeLayout; animateTimeWidth = lastTimeWidth; changed = true; } else if (timeDrawablesIsChanged || Math.abs(timeX - lastTimeX) > 1 && lastDrawingSideMenuEnabled == isSideMenuEnabled) { shouldAnimateTimeX = true; animateTimeWidth = lastTimeWidth; animateFromTimeX = lastTimeX; animateFromTimeXViews = lastTimeXViews; animateFromTimeXReplies = lastTimeXReplies; animateFromTimeXPinned = lastTimeXPinned; } if (lastShouldDrawMenuDrawable != shouldDrawMenuDrawable()) { animateShouldDrawMenuDrawable = true; } if (lastLocatinIsExpired != locationExpired) { animateLocationIsExpired = true; } if (lastIsPlayingRound != isPlayingRound) { animatePlayingRound = true; changed = true; } if (lastDrawingTextY != textY) { animateTextY = true; animateFromTextY = lastDrawingTextY; changed = true; } if (lastDrawingLinkPreviewY != linkPreviewY) { animateLinkPreviewY = true; animateFromLinkPreviewY = lastDrawingLinkPreviewY; changed = true; } if (lastDrawingPollAddOptionHeight != pollAddButtonHeight) { animatePollAddOptionHeight = true; animatePollAddOptionHeightFrom = lastDrawingPollAddOptionHeight; changed = true; } if (lastDrawingFactCheckHeight != factCheckHeight) { animateFactCheckHeight = true; animateFactCheckHeightFrom = lastDrawingFactCheckHeight; changed = true; } if (lastDrawingFactCheckExpanded != (getPrimaryMessageObject() != null && getPrimaryMessageObject().factCheckExpanded)) { animateFactCheckExpanded = true; changed = true; } if (lastDrawingFactCheck != hasFactCheck) { animateFactCheck = true; changed = true; } if (lastDrawingSummaryReply != drawSummaryReply) { animateSummaryReply = true; changed = true; } if (!MessageObject.expandedQuotesEquals(lastDrawingExpandedQuotes, currentMessageObject != null ? currentMessageObject.expandedQuotes : null)) { animateExpandedQuotes = true; animateExpandedQuotesFrom = lastDrawingExpandedQuotes; changed = true; } if (lastDrawingExpandedExplanation != (currentMessageObject != null && currentMessageObject.expandedExplanation)) { animateExpandedExplanation = true; expandedExplanationFrom = lastDrawingExpandedExplanation; changed = true; } if (currentMessageObject != null && lastDrawnForwardedName != currentMessageObject.needDrawForwarded()) { animateForwardedLayout = true; animatingForwardedNameLayout[0] = lastDrawnForwardedNameLayout[0]; animatingForwardedNameLayout[1] = lastDrawnForwardedNameLayout[1]; animateForwardNameX = lastForwardNameX; animateForwardedNamesOffset = lastForwardedNamesOffset; animateForwardNameWidth = lastForwardNameWidth; changed = true; } else if (lastNamesOffset != namesOffset) { animateNamesOffset = true; animateNamesOffsetFrom = lastNamesOffset; changed = true; } updateReactionLayoutPosition(); if (reactionsLayoutInBubble.animateChange()) { changed = true; } if (currentMessageObject.isRoundVideo()) { float y1 = layoutHeight - dp(28 - (drawPinnedBottom ? 2 : 0)); if (!reactionsLayoutInBubble.isEmpty) { y1 -= reactionsLayoutInBubble.totalHeight; } if (y1 != lastDrawRoundVideoDotY) { animateRoundVideoDotY = true; animateFromRoundVideoDotY = lastDrawRoundVideoDotY; changed = true; } } if (replyNameLayout != null && replyStartX != lastDrawReplyY && lastDrawReplyY != 0) { animateReplyY = true; animateFromReplyY = lastDrawReplyY; changed = true; } final boolean translated = currentMessageObject != null && currentMessageObject.translated; if (translated != lastDrawnTranslated) { if (titleLayout != null && lastDrawnTitleLayout != null) { animateTitleLayout = lastDrawnTitleLayout; animateTitleLayoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, false, animateTitleLayoutEmoji, animateTitleLayout); changed = true; } } return changed; } public void onDetach() { wasDraw = false; } public void resetAnimation() { animateChange = false; animatePinned = false; animateBackgroundBoundsInner = false; animateBackgroundWidth = false; deltaLeft = 0; deltaRight = 0; deltaBottom = 0; deltaTop = 0; toDeltaLeft = 0; toDeltaRight = 0; if (imageChangeBoundsTransition && animateToImageW != 0 && animateToImageH != 0) { photoImage.setImageCoords(animateToImageX, animateToImageY, animateToImageW, animateToImageH); } if (animateRadius) { photoImage.setRoundRadius(animateToRadius); } animateToImageX = 0; animateToImageY = 0; animateToImageW = 0; animateToImageH = 0; imageChangeBoundsTransition = false; changePinnedBottomProgress = 1f; captionEnterProgress = 1f; animateRadius = false; animateChangeProgress = 1f; oldProgress = 0f; newProgress = 1f; animateMessageText = false; animateRichLayout = false; animateDrawingSideMenuEnabled = false; animateDrawNameLayout = false; animateDrawAvatar = false; animateDrawTopic = false; animateOutTextBlocks = null; if (animateOutRichLayout != null) { animateOutRichLayout.detach(ChatMessageCell.this); } animateOutRichLayout = null; animateEditedLayout = null; animateTimeLayout = null; animateEditedEnter = false; animateReplaceCaptionLayout = false; transformGroupToSingleMessage = false; animateOutCaptionLayout = null; AnimatedEmojiSpan.release(ChatMessageCell.this, animateOutAnimateEmoji); animateOutAnimateEmoji = null; moveCaption = false; animateDrawingTimeAlpha = false; transitionBotButtons.clear(); animateButton = false; animateBotButtonsChanged = false; animateWidthForButton = false; animateMediaOffsetY = false; animateReplyTextLayout = null; animateReplies = false; animateRepliesLayout = null; animateComments = false; animateCommentsLayout = null; animateViewsLayout = null; animateShouldDrawTimeOnMedia = false; animateShouldDrawMenuDrawable = false; shouldAnimateTimeX = false; animateDrawBackground = false; animateSign = false; animateSmallImage = false; animateMonoforumPadding = false; animateStarsPriceTopPadding = false; animateStarsPriceText = false; animateBottomActionText = false; animateBottomActionPadding = false; needsStopClipping = false; animateLinkAbove = false; animateMediaAbove = false; animateRecommendationsExpanded = false; animateDrawingTimeAlpha = false; animateLocationIsExpired = false; animatePlayingRound = false; animateTextY = false; animateLinkPreviewY = false; animateFactCheckHeight = false; animateFactCheckExpanded = false; animateExpandedQuotes = false; animateExpandedExplanation = false; animateFactCheck = false; animateSummaryReply = false; animateForwardedLayout = false; animateNamesOffset = false; animatingForwardedNameLayout[0] = null; animatingForwardedNameLayout[1] = null; animateRoundVideoDotY = false; animateReplyY = false; reactionsLayoutInBubble.resetAnimation(); animateTitleLayout = null; AnimatedEmojiSpan.release(ChatMessageCell.this, animateTitleLayoutEmoji); } public boolean supportChangeAnimation() { return true; } public int createStatusDrawableParams() { if (currentMessageObject.isOutOwner()) { boolean drawCheck1 = false; boolean drawCheck2 = false; boolean drawClock = false; boolean drawError = false; if (currentMessageObject.isSending() || currentMessageObject.isEditing()) { drawCheck2 = false; drawClock = true; drawError = false; } else if (currentMessageObject.isSendError()) { drawCheck2 = false; drawClock = false; drawError = true; } else if (currentMessageObject.isSent()) { if (!currentMessageObject.scheduled && !currentMessageObject.isUnread()) { drawCheck1 = true; } else { drawCheck1 = false; } drawCheck2 = true; drawClock = false; drawError = false; } if (currentMessageObject.notime || currentMessageObject.isQuickReply()) { drawCheck1 = false; drawCheck2 = false; drawClock = false; } return (drawCheck1 ? 1 : 0) | (drawCheck2 ? 2 : 0) | (drawClock ? 4 : 0) | (drawError ? 8 : 0); } else { boolean drawClock = currentMessageObject.isSending() || currentMessageObject.isEditing(); boolean drawError = currentMessageObject.isSendError(); return (drawClock ? 4 : 0) | (drawError ? 8 : 0); } } } public int getThemedColor(int key) { return Theme.getColor(key, resourcesProvider); } private Drawable getThemedDrawable(String key) { Drawable drawable = resourcesProvider != null ? resourcesProvider.getDrawable(key) : null; return drawable != null ? drawable : Theme.getThemeDrawable(key); } public Paint getThemedPaint(String paintKey) { Paint paint = resourcesProvider != null ? resourcesProvider.getPaint(paintKey) : null; return paint != null ? paint : Theme.getThemePaint(paintKey); } public boolean hasGradientService() { return resourcesProvider != null ? resourcesProvider.hasGradientService() : Theme.hasGradientService(); } private ColorMatrixColorFilter getFancyBlurFilter() { if (fancyBlurFilter == null) { ColorMatrix colorMatrix = new ColorMatrix(); AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .9f); AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.6f); fancyBlurFilter = new ColorMatrixColorFilter(colorMatrix); } return fancyBlurFilter; } public int getNameStatusX() { return (int) (nameX + nameOffsetX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(2) + dp(4 + 12 + 4) / 2); } public int getNameStatusY() { return (int) (nameY + (nameLayout == null ? 0 : nameLayout.getHeight()) / 2); } @Override public void computeScroll() { super.computeScroll(); if (channelRecommendationsCell != null) { channelRecommendationsCell.computeScroll(); } } private ColorFilter[] adaptiveEmojiColorFilter; private int[] adaptiveEmojiColor; private ColorFilter getAdaptiveEmojiColorFilter(int n, int color) { if (adaptiveEmojiColorFilter == null) { adaptiveEmojiColor = new int[3]; adaptiveEmojiColorFilter = new ColorFilter[3]; } if (color != adaptiveEmojiColor[n] || adaptiveEmojiColorFilter[n] == null) { adaptiveEmojiColorFilter[n] = new PorterDuffColorFilter(adaptiveEmojiColor[n] = color, PorterDuff.Mode.SRC_IN); } return adaptiveEmojiColorFilter[n]; } private boolean isDark() { if (resourcesProvider != null) { return resourcesProvider.isDark(); } return Theme.isCurrentThemeDark(); } public boolean needDrawAvatar() { return ( isChat && !isSavedPreviewChat && (!isThreadPost || isForum) && ( currentMessageObject != null && !currentMessageObject.isOutOwner() && currentMessageObject.needDrawAvatar() ) || currentMessageObject != null && currentMessageObject.getDialogId() == UserObject.VERIFY || currentMessageObject != null && currentMessageObject.forceAvatar || currentMessageObject != null && currentMessageObject.messageOwner.guestchat_via_from != null ); } protected boolean drawPhotoImage(Canvas canvas) { if (currentMessageObject != null && currentMessageObject.isLivePhoto()) { final AnimatedFileDrawable animation = photoImage.getAnimation(); if (animation != null && animation.getDurationMs() > 0) { final float imageAlpha = 1.0f - Utilities.clamp01((animation.getDurationMs() - 90 - animation.getCurrentProgressMs()) / 500.0f); if (imageAlpha > 0) { boolean r = true; if (imageAlpha < 1) { r = photoImage.draw(canvas); } photoImage.setForceNotMedia(true); final float wasAlpha = photoImage.getAlpha(); photoImage.setAlpha(wasAlpha * imageAlpha); photoImage.draw(canvas); photoImage.setAlpha(wasAlpha); photoImage.setForceNotMedia(false); return r; } } } return photoImage.draw(canvas); } public boolean areTags() { MessageObject msg = getPrimaryMessageObject(); if (msg == null) return false; if (msg.messageOwner == null) return false; if (msg.messageOwner.reactions == null) return false; return msg.messageOwner.reactions.reactions_as_tags; } public String getFilename() { if (currentMessageObject == null) return null; if (currentMessageObject.type == MessageObject.TYPE_PHOTO) { if (currentPhotoObject == null) { return null; } return FileLoader.getAttachFileName(currentPhotoObject); } else if ( currentMessageObject.type == MessageObject.TYPE_GIF || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || currentMessageObject.type == MessageObject.TYPE_FILE || documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC ) { if (currentMessageObject.useCustomPhoto) { return null; } if (currentMessageObject.attachPathExists && !TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath)) { return currentMessageObject.messageOwner.attachPath; } else if (!currentMessageObject.isSendError() || documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { return currentMessageObject.getFileName(); } } else if (documentAttachType != DOCUMENT_ATTACH_TYPE_NONE) { return FileLoader.getAttachFileName(documentAttach); } else if (currentPhotoObject != null) { return FileLoader.getAttachFileName(currentPhotoObject); } return null; } public boolean checkLoadCaughtPremiumFloodWait() { return FileLoader.getInstance(currentAccount).checkLoadCaughtPremiumFloodWait(getFilename()); } public boolean checkUploadCaughtPremiumFloodWait() { return FileLoader.getInstance(currentAccount).checkUploadCaughtPremiumFloodWait(getFilename()); } public TLRPC.TL_availableEffect getEffect() { if (currentPosition != null && !currentPosition.last) { return null; } if (currentMessageObject != null) { return currentMessageObject.getEffect(); } return null; } private int layoutFactCheck(final int maxTextWidth) { MessageObject msg = getPrimaryMessageObject(); int addheight = 0; factCheckHeight = 0; factCheckWidth = 0; hasFactCheck = (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) && msg != null && msg.getFactCheck() != null && !msg.isRepostPreview; if (hasFactCheck) { TLRPC.TL_factCheck factCheck = msg.getFactCheck(); CharSequence text = msg.getFactCheckText(); if (factCheck.need_check || text == null) { hasFactCheck = false; } else { factCheckHeight += dp(4.66f); factCheckTitle = new Text(getString(R.string.FactCheck), 14, AndroidUtilities.bold()); factCheckWhat = new Text(getString(R.string.FactCheckWhat), 11); factCheckHeight += dp(17.33f); factCheckWidth = (int) (dp(20) + factCheckTitle.getCurrentWidth() + factCheckWhat.getCurrentWidth() + dp(18)); String country; try { country = new Locale("", factCheck.country).getDisplayCountry(LocaleController.getInstance().getCurrentLocale()); } catch (Exception e) { FileLog.e(e); country = factCheck.country; } factCheckTextLayout = StaticLayoutEx.createStaticLayout(text, Theme.chat_replyTextPaint, maxTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, dp(1), false, TextUtils.TruncateAt.END, maxTextWidth, 99999); factCheckText2Layout = StaticLayoutEx.createStaticLayout(formatString(R.string.FactCheckFooter, country), Theme.chat_titleLabelTextPaint, maxTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, dp(1), false, TextUtils.TruncateAt.END, maxTextWidth, 99999); factCheckTextLayoutLeft = factCheckTextLayout.getWidth(); int factCheckTextLayoutRight = 0; for (int a = 0; a < factCheckTextLayout.getLineCount(); a++) { factCheckTextLayoutLeft = (int) Math.min(factCheckTextLayoutLeft, factCheckTextLayout.getLineLeft(a)); factCheckTextLayoutRight = (int) Math.max(factCheckTextLayoutRight, factCheckTextLayout.getLineRight(a)); } int factCheckTextLayoutWidth = Math.abs(factCheckTextLayoutRight - factCheckTextLayoutLeft); // factCheckTextLayoutLastLineEnd = factCheckLarge && factCheckTextLayout.getLineRight(factCheckTextLayout.getLineCount() - 1) - factCheckTextLayoutLeft > factCheckTextLayoutWidth - dp(30); factCheckWidth = Math.max(factCheckWidth, factCheckTextLayoutWidth + dp(20)); factCheckText2LayoutLeft = factCheckText2Layout.getWidth(); int factCheckText2LayoutRight = 0; for (int a = 0; a < factCheckText2Layout.getLineCount(); a++) { factCheckText2LayoutLeft = (int) Math.min(factCheckText2LayoutLeft, factCheckText2Layout.getLineLeft(a)); factCheckText2LayoutRight = (int) Math.max(factCheckText2LayoutRight, factCheckText2Layout.getLineRight(a)); } int factCheckText2LayoutWidth = Math.abs(factCheckText2LayoutRight - factCheckText2LayoutLeft); factCheckWidth = Math.max(factCheckWidth, factCheckText2LayoutWidth + dp(20)); int height = (factCheckTextLayoutHeight = factCheckTextLayout.getLineBottom(factCheckTextLayout.getLineCount() - 1)) + dp(12.66f) + factCheckText2Layout.getLineBottom(factCheckText2Layout.getLineCount() - 1); int limit = (int) (3.5f * Theme.chat_replyTextPaint.getTextSize() * 1.4f); factCheckLarge = factCheckTextLayout.getLineCount() > 3 && height + dp(10) > limit; factCheckTextLayoutLastLineEnd = factCheckLarge && factCheckText2Layout.getLineRight(factCheckText2Layout.getLineCount() - 1) - factCheckText2LayoutLeft > factCheckWidth - dp(50); if (factCheckLarge && !msg.factCheckExpanded) { if (height < limit) { factCheckLarge = false; } height = Math.min(limit, height); } if (factCheckTextLayoutLastLineEnd) { height += Theme.chat_replyTextPaint.getTextSize() * 1.3f; } factCheckHeight += height; factCheckHeight += dp(6.66f); addheight += dp(2); } } return hasFactCheck ? factCheckHeight + addheight : 0; } public int getWidthForButtons() { if (transitionParams.animateWidthForButton) { return lerp(transitionParams.animateFromWidthForButton, widthForButtons, transitionParams.animateChangeProgress); } return widthForButtons; } public void drawVideoTimestamps(Canvas canvas, int color) { if (currentMessageObject == null || currentMessageObject.isLivePhoto() || controlsAlpha <= 0 || !photoImage.getVisible()) return; float progress; if (!currentMessageObject.openedInViewer && currentMessageObject.getVideoStartsTimestamp() != -1) { progress = currentMessageObject.getVideoStartsTimestamp() / (float) currentMessageObject.getDuration(); } else { progress = currentMessageObject.getVideoSavedProgress(); } progress = Utilities.clamp01(progress); // if (startsAtText != null && controlsAlpha > 0 && photoImage.getVisible()) { // final int w = dp(28) + (int) startsAtText.getCurrentWidth(), h = dp(17); // final float left = photoImage.getImageX() + dp(5), bottom = photoImage.getImageY2() - dp(5); // rect.set(left, bottom - h, left + w, bottom); // int oldAlpha = timeBackgroundPaint.getAlpha(); // timeBackgroundPaint.setAlpha((int) (oldAlpha * controlsAlpha)); // canvas.drawRoundRect(rect, dp(9), dp(9), timeBackgroundPaint); // timeBackgroundPaint.setAlpha(oldAlpha); // startsAtDrawable.setBounds((int) left + dp(6.33f), (int) bottom - h / 2 - startsAtDrawable.getIntrinsicHeight() / 2, (int) left + dp(6.33f) + startsAtDrawable.getIntrinsicWidth(), (int) bottom - h / 2 + startsAtDrawable.getIntrinsicHeight() / 2); // startsAtDrawable.setAlpha((int) (0xFF * controlsAlpha)); // startsAtDrawable.draw(canvas); // startsAtText.draw(canvas, left + dp(22.66f), bottom - h / 2, 0xFFFFFFFF, controlsAlpha); // } else if (progress > 0) { final int[] r = photoImage.getRoundRadius(); canvas.save(); if (r[0] <= 0 && r[1] <= 0 && r[2] <= 0 && r[3] <= 0) { canvas.clipRect(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); } else { if (photoImageClipPath == null) { photoImageClipPath = new Path(); photoImageClipPathRadii = new float[8]; } photoImageClipPathRadii[0] = photoImageClipPathRadii[1] = Math.max(0, r[0]); photoImageClipPathRadii[2] = photoImageClipPathRadii[3] = Math.max(0, r[1]); photoImageClipPathRadii[4] = photoImageClipPathRadii[5] = Math.max(0, r[2]); photoImageClipPathRadii[6] = photoImageClipPathRadii[7] = Math.max(0, r[3]); photoImageClipPath.rewind(); AndroidUtilities.rectTmp.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); photoImageClipPath.addRoundRect(AndroidUtilities.rectTmp, photoImageClipPathRadii, Path.Direction.CW); canvas.clipPath(photoImageClipPath); } Theme.chat_videoProgressPaint.setColor(Theme.multAlpha(Color.WHITE, .35f * controlsAlpha)); canvas.drawRect(photoImage.getImageX(), photoImage.getImageY2() - dp(3), photoImage.getImageX2(), photoImage.getImageY2(), Theme.chat_videoProgressPaint); Theme.chat_videoProgressPaint.setColor(Theme.multAlpha(color, controlsAlpha)); AndroidUtilities.rectTmp.set(photoImage.getImageX() - dp(2), photoImage.getImageY2() - dp(3), photoImage.getImageX() + photoImage.getImageWidth() * progress, photoImage.getImageY2()); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(2), dp(2), Theme.chat_videoProgressPaint); canvas.restore(); } } public long getStarsPrice() { if (currentMessagesGroup != null) { long totalPrice = 0; for (MessageObject msg : currentMessagesGroup.messages) { final long messagePrice = msg == null || msg.messageOwner == null ? 0 : msg.messageOwner.paid_message_stars; totalPrice += messagePrice; } return totalPrice; } else { return currentMessageObject == null || currentMessageObject.messageOwner == null ? 0 : currentMessageObject.messageOwner.paid_message_stars; } } private int getNameHeight() { if (drawNameAvatar) { if (adminLayout == null) { return dp(5 + 26); } else { return dp(5 + 26 + 6.66f); } } else { return (int) (dp(5) + Theme.chat_namePaint.getTextSize()); } } private float getNameHeightAnimated() { final float avatarAlpha; if (transitionParams.animateDrawAvatar) { avatarAlpha = lerp(!drawNameAvatar, drawNameAvatar, transitionParams.animateChangeProgress); } else { avatarAlpha = drawNameAvatar ? 1.0f : 0.0f; } return lerp( (dp(5) + Theme.chat_namePaint.getTextSize()), dp(adminLayout == null ? 5 + 26 : 5 + 26 + 4), avatarAlpha ); } private TL_stars.StarGift instantViewTypeIsGiftAuction; private static boolean isSmallImageLinkPreviewType(String type) { return "app".equals(type) || "profile".equals(type) || "article".equals(type) || "telegram_bot".equals(type) || "telegram_user".equals(type) || "telegram_channel".equals(type) || "telegram_channel_direct".equals(type) || "telegram_megagroup".equals(type) || "telegram_voicechat".equals(type) || "telegram_videochat".equals(type) || "telegram_livestream".equals(type) || "telegram_channel_boost".equals(type) || "telegram_group_boost".equals(type) || "telegram_aicomposetone".equals(type); } private static void normalizePollPercents(boolean hasDifferent, int restPercent, ArrayList sortedPollButtons) { if (!hasDifferent || restPercent == 0 || sortedPollButtons == null || sortedPollButtons.isEmpty()) { return; } Collections.sort(sortedPollButtons, (o1, o2) -> { if (o1.decimal > o2.decimal) { return -1; } else if (o1.decimal < o2.decimal) { return 1; } if (o1.percent > o2.percent) { return 1; } else if (o1.percent < o2.percent) { return -1; } return 0; }); for (int i = 0, n = sortedPollButtons.size(); i < n; i++) { if (restPercent <= 0) { break; } PollButton b = sortedPollButtons.get(i); if (b.percent > 0) { b.percent += 1; restPercent--; } } } public boolean getPollAddButtonBounds(Rect bounds) { if (pollAddButtonDrawable != null && pollAllowAdding) { bounds.set(pollAddButtonDrawable.getBounds()); return true; } return false; } private static void clearBlurredImage(ImageReceiver blurredPhotoImage) { if (blurredPhotoImage == null) { return; } Bitmap bitmap = blurredPhotoImage.getBitmap(); if (bitmap != null) { bitmap.recycle(); blurredPhotoImage.setImageBitmap((Bitmap) null); } } private static String getCallMessageText(MessageObject messageObject, boolean isMissed, boolean isBusy, boolean video) { String text; if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionConferenceCall) { if (messageObject.isOutOwner()) { text = getString(R.string.ConferenceCallOutgoing); } else if (isMissed) { text = getString(R.string.ConferenceCallMissed); } else { text = getString(R.string.ConferenceCallIncoming); } } else if (messageObject.isOutOwner()) { if (isMissed) { if (video) { text = getString(R.string.CallMessageVideoOutgoingMissed); } else { text = getString(R.string.CallMessageOutgoingMissed); } } else { if (video) { text = getString(R.string.CallMessageVideoOutgoing); } else { text = getString(R.string.CallMessageOutgoing); } } } else { if (isMissed) { if (video) { text = getString(R.string.CallMessageVideoIncomingMissed); } else { text = getString(R.string.CallMessageIncomingMissed); } } else if (isBusy) { if (video) { text = getString(R.string.CallMessageVideoIncomingDeclined); } else { text = getString(R.string.CallMessageIncomingDeclined); } } else { if (video) { text = getString(R.string.CallMessageVideoIncoming); } else { text = getString(R.string.CallMessageIncoming); } } } return text; } }