Search in sources :

Example 1 with TextStyleSpan

use of org.telegram.ui.Components.TextStyleSpan in project Telegram-FOSS by Telegram-FOSS-Team.

the class ChatMessageCell method setMessageObjectInternal.

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();
    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(currentUser);
            avatarImage.setForUserOrChat(currentUser, avatarDrawable);
        } else if (currentChat != null) {
            if (currentChat.photo != null) {
                currentPhoto = currentChat.photo.photo_small;
            } else {
                currentPhoto = null;
            }
            avatarDrawable.setInfo(currentChat);
            avatarImage.setForUserOrChat(currentChat, avatarDrawable);
        } else if (messageObject != null && messageObject.isSponsored()) {
            if (messageObject.sponsoredChatInvite != null && messageObject.sponsoredChatInvite.chat != null) {
                avatarDrawable.setInfo(messageObject.sponsoredChatInvite.chat);
                avatarImage.setForUserOrChat(messageObject.sponsoredChatInvite.chat, avatarDrawable);
            } else {
                avatarDrawable.setInfo(messageObject.sponsoredChatInvite);
                TLRPC.Photo photo = messageObject.sponsoredChatInvite.photo;
                if (photo != null) {
                    avatarImage.setImage(ImageLocation.getForPhoto(photo.sizes.get(0), photo), "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;
    }
    measureTime(messageObject);
    namesOffset = 0;
    String viaUsername = null;
    CharSequence viaString = null;
    if (messageObject.messageOwner.via_bot_id != 0) {
        TLRPC.User botUser = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.via_bot_id);
        if (botUser != null && !TextUtils.isEmpty(botUser.username)) {
            viaUsername = "@" + botUser.username;
            viaString = AndroidUtilities.replaceTags(String.format(" %s <b>%s</b>", LocaleController.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 <b>%s</b>", LocaleController.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 == 14) && viaUsername != null;
    if (!hasPsaHint && (needAuthorName || viaBot)) {
        drawNameLayout = true;
        nameWidth = getMaxNameWidth();
        if (nameWidth < 0) {
            nameWidth = AndroidUtilities.dp(100);
        }
        int adminWidth;
        String adminString;
        String adminLabel;
        if (isMegagroup && currentChat != null && messageObject.messageOwner.post_author != null && currentChat.id == -currentMessageObject.getFromChatId()) {
            adminString = messageObject.messageOwner.post_author.replace("\n", "");
            adminWidth = (int) Math.ceil(Theme.chat_adminPaint.measureText(adminString));
            nameWidth -= adminWidth;
        } else if (isMegagroup && currentChat != null && currentMessageObject.isForwardedChannelPost()) {
            adminString = LocaleController.getString("DiscussChannel", R.string.DiscussChannel);
            adminWidth = (int) Math.ceil(Theme.chat_adminPaint.measureText(adminString));
            // TODO
            nameWidth -= adminWidth;
        } else if (currentUser != null && !currentMessageObject.isOutOwner() && !currentMessageObject.isAnyKindOfSticker() && currentMessageObject.type != 5 && delegate != null && (adminLabel = delegate.getAdminRank(currentUser.id)) != null) {
            if (adminLabel.length() == 0) {
                adminLabel = LocaleController.getString("ChatAdmin", R.string.ChatAdmin);
            }
            adminString = adminLabel;
            adminWidth = (int) Math.ceil(Theme.chat_adminPaint.measureText(adminString));
            nameWidth -= adminWidth;
        } else {
            adminString = null;
            adminWidth = 0;
        }
        if (messageObject.customName != null) {
            currentNameString = messageObject.customName;
        } else if (needAuthorName) {
            currentNameString = getAuthorName();
        } else {
            currentNameString = "";
        }
        CharSequence nameStringFinal = TextUtils.ellipsize(currentNameString.replace('\n', ' ').replace('\u200F', ' '), Theme.chat_namePaint, nameWidth - (viaBot ? viaWidth : 0), TextUtils.TruncateAt.END);
        if (viaBot) {
            viaNameWidth = (int) Math.ceil(Theme.chat_namePaint.measureText(nameStringFinal, 0, nameStringFinal.length()));
            if (viaNameWidth != 0) {
                viaNameWidth += AndroidUtilities.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 = LocaleController.getString("ViaBot", R.string.ViaBot);
            if (currentNameString.length() > 0) {
                SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("%s %s %s", nameStringFinal, viaBotString, viaUsername));
                stringBuilder.setSpan(viaSpan1 = new TypefaceSpan(Typeface.DEFAULT, 0, color), nameStringFinal.length() + 1, nameStringFinal.length() + 1 + viaBotString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                stringBuilder.setSpan(viaSpan2 = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, color), nameStringFinal.length() + 2 + viaBotString.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                nameStringFinal = stringBuilder;
            } else {
                SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("%s %s", viaBotString, viaUsername));
                stringBuilder.setSpan(viaSpan1 = new TypefaceSpan(Typeface.DEFAULT, 0, color), 0, viaBotString.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                stringBuilder.setSpan(viaSpan2 = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, color), 1 + viaBotString.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                nameStringFinal = stringBuilder;
            }
            nameStringFinal = TextUtils.ellipsize(nameStringFinal, Theme.chat_namePaint, nameWidth, TextUtils.TruncateAt.END);
        }
        try {
            nameLayout = new StaticLayout(nameStringFinal, Theme.chat_namePaint, nameWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
            if (nameLayout.getLineCount() > 0) {
                nameWidth = (int) Math.ceil(nameLayout.getLineWidth(0));
                if (!messageObject.isAnyKindOfSticker()) {
                    namesOffset += AndroidUtilities.dp(19);
                }
                nameOffsetX = nameLayout.getLineLeft(0);
            } else {
                nameWidth = 0;
            }
            if (adminString != null) {
                adminLayout = new StaticLayout(adminString, Theme.chat_adminPaint, adminWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
                nameWidth += adminLayout.getLineWidth(0) + AndroidUtilities.dp(8);
            } else {
                adminLayout = null;
            }
        } catch (Exception e) {
            FileLog.e(e);
        }
        if (currentNameString.length() == 0) {
            currentNameString = null;
        }
    } else {
        currentNameString = null;
        nameLayout = null;
        nameWidth = 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 (drawForwardedName && messageObject.needDrawForwarded() && (currentPosition == null || currentPosition.minY == 0)) {
        if (messageObject.messageOwner.fwd_from.from_name != null) {
            currentForwardName = messageObject.messageOwner.fwd_from.from_name;
        }
        if (currentForwardUser != null || currentForwardChannel != null || currentForwardName != null) {
            if (currentForwardChannel != null) {
                if (currentForwardUser != null) {
                    currentForwardNameString = String.format("%s (%s)", currentForwardChannel.title, UserObject.getUserName(currentForwardUser));
                } else if (!TextUtils.isEmpty(messageObject.messageOwner.fwd_from.post_author)) {
                    currentForwardNameString = String.format("%s (%s)", currentForwardChannel.title, messageObject.messageOwner.fwd_from.post_author);
                } else {
                    currentForwardNameString = currentForwardChannel.title;
                }
            } else if (currentForwardUser != null) {
                currentForwardNameString = UserObject.getUserName(currentForwardUser);
            } else {
                currentForwardNameString = currentForwardName;
            }
            forwardedNameWidth = getMaxNameWidth();
            String forwardedString = getForwardedMessageText(messageObject);
            if (hasPsaHint) {
                forwardedNameWidth -= AndroidUtilities.dp(36);
            }
            String from = LocaleController.getString("From", R.string.From);
            String fromFormattedString = LocaleController.getString("FromFormatted", R.string.FromFormatted);
            int idx = fromFormattedString.indexOf("%1$s");
            int fromWidth = (int) Math.ceil(Theme.chat_forwardNamePaint.measureText(from + " "));
            CharSequence name = TextUtils.ellipsize(currentForwardNameString.replace('\n', ' '), Theme.chat_replyNamePaint, forwardedNameWidth - fromWidth - viaWidth, TextUtils.TruncateAt.END);
            String fromString;
            try {
                fromString = String.format(fromFormattedString, name);
            } catch (Exception e) {
                fromString = name.toString();
            }
            CharSequence lastLine;
            SpannableStringBuilder stringBuilder;
            if (viaString != null) {
                stringBuilder = new SpannableStringBuilder(String.format("%s %s %s", fromString, LocaleController.getString("ViaBot", R.string.ViaBot), viaUsername));
                viaNameWidth = (int) Math.ceil(Theme.chat_forwardNamePaint.measureText(fromString));
                stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), stringBuilder.length() - viaUsername.length() - 1, stringBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            } else {
                stringBuilder = new SpannableStringBuilder(String.format(fromFormattedString, name));
            }
            forwardNameCenterX = fromWidth + (int) Math.ceil(Theme.chat_forwardNamePaint.measureText(name, 0, name.length())) / 2;
            if (idx >= 0 && (currentForwardName == null || messageObject.messageOwner.fwd_from.from_id != null)) {
                stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), idx, idx + name.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
            lastLine = stringBuilder;
            lastLine = TextUtils.ellipsize(lastLine, Theme.chat_forwardNamePaint, forwardedNameWidth, TextUtils.TruncateAt.END);
            try {
                forwardedNameLayout[1] = new StaticLayout(lastLine, Theme.chat_forwardNamePaint, forwardedNameWidth + AndroidUtilities.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 + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
                forwardedNameWidth = Math.max((int) Math.ceil(forwardedNameLayout[0].getLineWidth(0)), (int) Math.ceil(forwardedNameLayout[1].getLineWidth(0)));
                if (hasPsaHint) {
                    forwardedNameWidth += AndroidUtilities.dp(36);
                }
                forwardNameOffsetX[0] = forwardedNameLayout[0].getLineLeft(0);
                forwardNameOffsetX[1] = forwardedNameLayout[1].getLineLeft(0);
                if (messageObject.type != 5 && !messageObject.isAnyKindOfSticker()) {
                    namesOffset += AndroidUtilities.dp(36);
                }
            } catch (Exception e) {
                FileLog.e(e);
            }
        }
    }
    if ((!isThreadChat || messageObject.getReplyTopMsgId() != 0) && messageObject.hasValidReplyMessageObject() || messageObject.messageOwner.fwd_from != null && messageObject.isDice()) {
        if (currentPosition == null || currentPosition.minY == 0) {
            if (!messageObject.isAnyKindOfSticker() && messageObject.type != 5) {
                namesOffset += AndroidUtilities.dp(42);
                if (messageObject.type != 0) {
                    namesOffset += AndroidUtilities.dp(5);
                }
            }
            int maxWidth = getMaxNameWidth();
            if (!messageObject.shouldDrawWithoutBackground()) {
                maxWidth -= AndroidUtilities.dp(10);
            } else if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) {
                maxWidth += AndroidUtilities.dp(13);
            }
            CharSequence stringFinalText = null;
            String name = null;
            if ((!isThreadChat || messageObject.getReplyTopMsgId() != 0) && messageObject.hasValidReplyMessageObject()) {
                lastReplyMessage = messageObject.replyMessageObject.messageOwner;
                int cacheType = 1;
                int size = 0;
                TLObject photoObject;
                TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.replyMessageObject.photoThumbs2, 320);
                TLRPC.PhotoSize 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 (thumbPhotoSize == photoSize) {
                    thumbPhotoSize = null;
                }
                if (photoSize == 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(AndroidUtilities.dp(22));
                    } else {
                        replyImageReceiver.setRoundRadius(AndroidUtilities.dp(2));
                    }
                    currentReplyPhoto = photoSize;
                    replyImageReceiver.setImage(ImageLocation.getForObject(photoSize, photoObject), "50_50", ImageLocation.getForObject(thumbPhotoSize, photoObject), "50_50_b", size, null, messageObject.replyMessageObject, cacheType);
                    needReplyImage = true;
                    maxWidth -= AndroidUtilities.dp(44);
                }
                if (messageObject.customReplyName != null) {
                    name = messageObject.customReplyName;
                } else {
                    long fromId = messageObject.replyMessageObject.getFromChatId();
                    if (fromId > 0) {
                        TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(fromId);
                        if (user != null) {
                            name = UserObject.getUserName(user);
                        }
                    } else if (fromId < 0) {
                        TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId);
                        if (chat != null) {
                            name = chat.title;
                        }
                    } else {
                        TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(messageObject.replyMessageObject.messageOwner.peer_id.channel_id);
                        if (chat != null) {
                            name = chat.title;
                        }
                    }
                }
                if (name == null) {
                    name = LocaleController.getString("Loading", R.string.Loading);
                }
                if (messageObject.replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGame) {
                    stringFinalText = Emoji.replaceEmoji(messageObject.replyMessageObject.messageOwner.media.game.title, Theme.chat_replyTextPaint.getFontMetricsInt(), AndroidUtilities.dp(14), false);
                    stringFinalText = TextUtils.ellipsize(stringFinalText, Theme.chat_replyTextPaint, maxWidth, TextUtils.TruncateAt.END);
                } else if (messageObject.replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice) {
                    stringFinalText = Emoji.replaceEmoji(messageObject.replyMessageObject.messageOwner.media.title, Theme.chat_replyTextPaint.getFontMetricsInt(), AndroidUtilities.dp(14), false);
                    stringFinalText = TextUtils.ellipsize(stringFinalText, Theme.chat_replyTextPaint, maxWidth, TextUtils.TruncateAt.END);
                } else if (!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, Theme.chat_replyTextPaint.getFontMetricsInt(), AndroidUtilities.dp(14), false);
                    stringFinalText = TextUtils.ellipsize(stringFinalText, Theme.chat_replyTextPaint, maxWidth, TextUtils.TruncateAt.END);
                    if (stringFinalText instanceof Spannable) {
                        MediaDataController.addTextStyleRuns(messageObject.replyMessageObject.messageOwner.entities, messageObject.replyMessageObject.caption, (Spannable) stringFinalText);
                    }
                } else if (messageObject.replyMessageObject.messageText != null && messageObject.replyMessageObject.messageText.length() > 0) {
                    String mess = messageObject.replyMessageObject.messageText.toString();
                    if (mess.length() > 150) {
                        mess = mess.substring(0, 150);
                    }
                    mess = mess.replace('\n', ' ');
                    stringFinalText = Emoji.replaceEmoji(mess, Theme.chat_replyTextPaint.getFontMetricsInt(), AndroidUtilities.dp(14), false);
                    stringFinalText = TextUtils.ellipsize(stringFinalText, Theme.chat_replyTextPaint, maxWidth, TextUtils.TruncateAt.END);
                    if (stringFinalText instanceof Spannable) {
                        MediaDataController.addTextStyleRuns(messageObject.replyMessageObject, (Spannable) stringFinalText);
                    }
                }
            } else {
                replyImageReceiver.setImageBitmap((Drawable) null);
                needReplyImage = false;
                replyPanelIsForward = true;
                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 (currentForwardChannel != null) {
                        if (currentForwardUser != null) {
                            currentForwardNameString = String.format("%s (%s)", currentForwardChannel.title, UserObject.getUserName(currentForwardUser));
                        } else {
                            currentForwardNameString = currentForwardChannel.title;
                        }
                    } else if (currentForwardUser != null) {
                        currentForwardNameString = UserObject.getUserName(currentForwardUser);
                    } else {
                        currentForwardNameString = currentForwardName;
                    }
                    name = getForwardedMessageText(messageObject);
                    String from = LocaleController.getString("From", R.string.From);
                    String fromFormattedString = LocaleController.getString("FromFormatted", R.string.FromFormatted);
                    int idx = fromFormattedString.indexOf("%1$s");
                    int fromWidth = (int) Math.ceil(Theme.chat_replyNamePaint.measureText(from + " "));
                    CharSequence n = TextUtils.ellipsize(currentForwardNameString == null ? "" : currentForwardNameString.replace('\n', ' '), Theme.chat_replyNamePaint, maxWidth - fromWidth, TextUtils.TruncateAt.END);
                    SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format(fromFormattedString, n));
                    if (idx >= 0 && (currentForwardName == null || messageObject.messageOwner.fwd_from.from_id != null)) {
                        stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), idx, idx + n.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    }
                    stringFinalText = TextUtils.ellipsize(stringBuilder, Theme.chat_replyTextPaint, maxWidth, TextUtils.TruncateAt.END);
                    forwardNameCenterX = fromWidth + (int) Math.ceil(Theme.chat_replyNamePaint.measureText(n, 0, n.length())) / 2;
                }
            }
            CharSequence stringFinalName = name == null ? "" : TextUtils.ellipsize(name.replace('\n', ' '), Theme.chat_replyNamePaint, maxWidth, TextUtils.TruncateAt.END);
            try {
                replyNameWidth = AndroidUtilities.dp(4 + (needReplyImage ? 44 : 0));
                if (stringFinalName != null) {
                    replyNameLayout = new StaticLayout(stringFinalName, Theme.chat_replyNamePaint, maxWidth + AndroidUtilities.dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
                    if (replyNameLayout.getLineCount() > 0) {
                        replyNameWidth += (int) Math.ceil(replyNameLayout.getLineWidth(0)) + AndroidUtilities.dp(8);
                        replyNameOffset = (int) replyNameLayout.getLineLeft(0);
                    }
                }
            } catch (Exception e) {
                FileLog.e(e);
            }
            try {
                replyTextWidth = AndroidUtilities.dp(4 + (needReplyImage ? 44 : 0));
                if (stringFinalText != null) {
                    SpannableStringBuilder sb = new SpannableStringBuilder(stringFinalText);
                    for (TextStyleSpan span : sb.getSpans(0, sb.length(), TextStyleSpan.class)) {
                        if ((span.getTextStyleRun().flags & TextStyleSpan.FLAG_STYLE_MONO) != 0) {
                            sb.removeSpan(span);
                        }
                    }
                    replyTextLayout = new StaticLayout(sb, Theme.chat_replyTextPaint, maxWidth + AndroidUtilities.dp(10), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
                    if (replyTextLayout.getLineCount() > 0) {
                        replyTextWidth += (int) Math.ceil(replyTextLayout.getLineWidth(0)) + AndroidUtilities.dp(8);
                        replyTextOffset = (int) replyTextLayout.getLineLeft(0);
                    }
                    replySpoilers.clear();
                    if (getMessageObject().replyMessageObject != null && !getMessageObject().replyMessageObject.isSpoilersRevealed)
                        SpoilerEffect.addSpoilers(this, replyTextLayout, replySpoilersPool, replySpoilers);
                }
            } catch (Exception e) {
                FileLog.e(e);
            }
        }
    } else if (!isThreadChat && messageObject.getReplyMsgId() != 0) {
        if (!(messageObject.replyMessageObject != null && messageObject.replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty)) {
            if (!messageObject.isAnyKindOfSticker() && messageObject.type != 5) {
                namesOffset += AndroidUtilities.dp(42);
                if (messageObject.type != 0) {
                    namesOffset += AndroidUtilities.dp(5);
                }
            }
            needReplyImage = false;
            int maxWidth = getMaxNameWidth();
            if (!messageObject.shouldDrawWithoutBackground()) {
                maxWidth -= AndroidUtilities.dp(10);
            } else if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) {
                maxWidth += AndroidUtilities.dp(13);
            }
            replyNameLayout = new StaticLayout(LocaleController.getString("Loading", R.string.Loading), Theme.chat_replyNamePaint, maxWidth + AndroidUtilities.dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
            if (replyNameLayout.getLineCount() > 0) {
                replyNameWidth += (int) Math.ceil(replyNameLayout.getLineWidth(0)) + AndroidUtilities.dp(8);
                replyNameOffset = (int) replyNameLayout.getLineLeft(0);
            }
        }
    }
    requestLayout();
}
Also used : StaticLayout(android.text.StaticLayout) TLRPC(org.telegram.tgnet.TLRPC) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint) SuppressLint(android.annotation.SuppressLint) Point(org.telegram.ui.Components.Point) TextStyleSpan(org.telegram.ui.Components.TextStyleSpan) TLObject(org.telegram.tgnet.TLObject) SpannableStringBuilder(android.text.SpannableStringBuilder) Spannable(android.text.Spannable) TypefaceSpan(org.telegram.ui.Components.TypefaceSpan)

Example 2 with TextStyleSpan

use of org.telegram.ui.Components.TextStyleSpan in project Telegram-FOSS by Telegram-FOSS-Team.

the class MediaDataController method addStyleToText.

public static void addStyleToText(TextStyleSpan span, int start, int end, Spannable editable, boolean allowIntersection) {
    try {
        CharacterStyle[] spans = editable.getSpans(start, end, CharacterStyle.class);
        if (spans != null && spans.length > 0) {
            for (int a = 0; a < spans.length; a++) {
                CharacterStyle oldSpan = spans[a];
                TextStyleSpan.TextStyleRun textStyleRun;
                TextStyleSpan.TextStyleRun newStyleRun = span != null ? span.getTextStyleRun() : new TextStyleSpan.TextStyleRun();
                if (oldSpan instanceof TextStyleSpan) {
                    TextStyleSpan textStyleSpan = (TextStyleSpan) oldSpan;
                    textStyleRun = textStyleSpan.getTextStyleRun();
                } else if (oldSpan instanceof URLSpanReplacement) {
                    URLSpanReplacement urlSpanReplacement = (URLSpanReplacement) oldSpan;
                    textStyleRun = urlSpanReplacement.getTextStyleRun();
                    if (textStyleRun == null) {
                        textStyleRun = new TextStyleSpan.TextStyleRun();
                    }
                } else {
                    continue;
                }
                if (textStyleRun == null) {
                    continue;
                }
                int spanStart = editable.getSpanStart(oldSpan);
                int spanEnd = editable.getSpanEnd(oldSpan);
                editable.removeSpan(oldSpan);
                if (spanStart > start && end > spanEnd) {
                    editable.setSpan(createNewSpan(oldSpan, textStyleRun, newStyleRun, allowIntersection), spanStart, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                    if (span != null) {
                        editable.setSpan(new TextStyleSpan(new TextStyleSpan.TextStyleRun(newStyleRun)), spanEnd, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                    }
                    end = spanStart;
                } else {
                    int startTemp = start;
                    if (spanStart <= start) {
                        if (spanStart != start) {
                            editable.setSpan(createNewSpan(oldSpan, textStyleRun, null, allowIntersection), spanStart, start, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                        }
                        if (spanEnd > start) {
                            if (span != null) {
                                editable.setSpan(createNewSpan(oldSpan, textStyleRun, newStyleRun, allowIntersection), start, Math.min(spanEnd, end), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                            }
                            start = spanEnd;
                        }
                    }
                    if (spanEnd >= end) {
                        if (spanEnd != end) {
                            editable.setSpan(createNewSpan(oldSpan, textStyleRun, null, allowIntersection), end, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                        }
                        if (end > spanStart && spanEnd <= startTemp) {
                            if (span != null) {
                                editable.setSpan(createNewSpan(oldSpan, textStyleRun, newStyleRun, allowIntersection), spanStart, Math.min(spanEnd, end), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                            }
                            end = spanStart;
                        }
                    }
                }
            }
        }
        if (span != null && start < end && start < editable.length()) {
            editable.setSpan(span, start, Math.min(editable.length(), end), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    } catch (Exception e) {
        FileLog.e(e);
    }
}
Also used : TextStyleSpan(org.telegram.ui.Components.TextStyleSpan) CharacterStyle(android.text.style.CharacterStyle) Paint(android.graphics.Paint) SQLiteException(org.telegram.SQLite.SQLiteException) URLSpanReplacement(org.telegram.ui.Components.URLSpanReplacement)

Example 3 with TextStyleSpan

use of org.telegram.ui.Components.TextStyleSpan in project Telegram-FOSS by Telegram-FOSS-Team.

the class MessageObject method addEntitiesToText.

public static boolean addEntitiesToText(CharSequence text, ArrayList<TLRPC.MessageEntity> entities, boolean out, boolean usernames, boolean photoViewer, boolean useManualParse) {
    if (!(text instanceof Spannable)) {
        return false;
    }
    Spannable spannable = (Spannable) text;
    URLSpan[] spans = spannable.getSpans(0, text.length(), URLSpan.class);
    boolean hasUrls = spans != null && spans.length > 0;
    if (entities.isEmpty()) {
        return hasUrls;
    }
    byte t;
    if (photoViewer) {
        t = 2;
    } else if (out) {
        t = 1;
    } else {
        t = 0;
    }
    ArrayList<TextStyleSpan.TextStyleRun> runs = new ArrayList<>();
    ArrayList<TLRPC.MessageEntity> entitiesCopy = new ArrayList<>(entities);
    Collections.sort(entitiesCopy, (o1, o2) -> {
        if (o1.offset > o2.offset) {
            return 1;
        } else if (o1.offset < o2.offset) {
            return -1;
        }
        return 0;
    });
    for (int a = 0, N = entitiesCopy.size(); a < N; a++) {
        TLRPC.MessageEntity entity = entitiesCopy.get(a);
        if (entity.length <= 0 || entity.offset < 0 || entity.offset >= text.length()) {
            continue;
        } else if (entity.offset + entity.length > text.length()) {
            entity.length = text.length() - entity.offset;
        }
        if (!useManualParse || entity instanceof TLRPC.TL_messageEntityBold || entity instanceof TLRPC.TL_messageEntityItalic || entity instanceof TLRPC.TL_messageEntityStrike || entity instanceof TLRPC.TL_messageEntityUnderline || entity instanceof TLRPC.TL_messageEntityBlockquote || entity instanceof TLRPC.TL_messageEntityCode || entity instanceof TLRPC.TL_messageEntityPre || entity instanceof TLRPC.TL_messageEntityMentionName || entity instanceof TLRPC.TL_inputMessageEntityMentionName || entity instanceof TLRPC.TL_messageEntityTextUrl || entity instanceof TLRPC.TL_messageEntitySpoiler) {
            if (spans != null && spans.length > 0) {
                for (int b = 0; b < spans.length; b++) {
                    if (spans[b] == null) {
                        continue;
                    }
                    int start = spannable.getSpanStart(spans[b]);
                    int end = spannable.getSpanEnd(spans[b]);
                    if (entity.offset <= start && entity.offset + entity.length >= start || entity.offset <= end && entity.offset + entity.length >= end) {
                        spannable.removeSpan(spans[b]);
                        spans[b] = null;
                    }
                }
            }
        }
        TextStyleSpan.TextStyleRun newRun = new TextStyleSpan.TextStyleRun();
        newRun.start = entity.offset;
        newRun.end = newRun.start + entity.length;
        TLRPC.MessageEntity urlEntity = null;
        if (entity instanceof TLRPC.TL_messageEntitySpoiler) {
            newRun.flags = TextStyleSpan.FLAG_STYLE_SPOILER;
        } else if (entity instanceof TLRPC.TL_messageEntityStrike) {
            newRun.flags = TextStyleSpan.FLAG_STYLE_STRIKE;
        } else if (entity instanceof TLRPC.TL_messageEntityUnderline) {
            newRun.flags = TextStyleSpan.FLAG_STYLE_UNDERLINE;
        } else if (entity instanceof TLRPC.TL_messageEntityBlockquote) {
            newRun.flags = TextStyleSpan.FLAG_STYLE_QUOTE;
        } else if (entity instanceof TLRPC.TL_messageEntityBold) {
            newRun.flags = TextStyleSpan.FLAG_STYLE_BOLD;
        } else if (entity instanceof TLRPC.TL_messageEntityItalic) {
            newRun.flags = TextStyleSpan.FLAG_STYLE_ITALIC;
        } else if (entity instanceof TLRPC.TL_messageEntityCode || entity instanceof TLRPC.TL_messageEntityPre) {
            newRun.flags = TextStyleSpan.FLAG_STYLE_MONO;
        } else if (entity instanceof TLRPC.TL_messageEntityMentionName) {
            if (!usernames) {
                continue;
            }
            newRun.flags = TextStyleSpan.FLAG_STYLE_MENTION;
            newRun.urlEntity = entity;
        } else if (entity instanceof TLRPC.TL_inputMessageEntityMentionName) {
            if (!usernames) {
                continue;
            }
            newRun.flags = TextStyleSpan.FLAG_STYLE_MENTION;
            newRun.urlEntity = entity;
        } else {
            if (useManualParse && !(entity instanceof TLRPC.TL_messageEntityTextUrl)) {
                continue;
            }
            if ((entity instanceof TLRPC.TL_messageEntityUrl || entity instanceof TLRPC.TL_messageEntityTextUrl) && Browser.isPassportUrl(entity.url)) {
                continue;
            }
            if (entity instanceof TLRPC.TL_messageEntityMention && !usernames) {
                continue;
            }
            newRun.flags = TextStyleSpan.FLAG_STYLE_URL;
            newRun.urlEntity = entity;
        }
        for (int b = 0, N2 = runs.size(); b < N2; b++) {
            TextStyleSpan.TextStyleRun run = runs.get(b);
            if (newRun.start > run.start) {
                if (newRun.start >= run.end) {
                    continue;
                }
                if (newRun.end < run.end) {
                    TextStyleSpan.TextStyleRun r = new TextStyleSpan.TextStyleRun(newRun);
                    r.merge(run);
                    b++;
                    N2++;
                    runs.add(b, r);
                    r = new TextStyleSpan.TextStyleRun(run);
                    r.start = newRun.end;
                    b++;
                    N2++;
                    runs.add(b, r);
                } else {
                    TextStyleSpan.TextStyleRun r = new TextStyleSpan.TextStyleRun(newRun);
                    r.merge(run);
                    r.end = run.end;
                    b++;
                    N2++;
                    runs.add(b, r);
                }
                int temp = newRun.start;
                newRun.start = run.end;
                run.end = temp;
            } else {
                if (run.start >= newRun.end) {
                    continue;
                }
                int temp = run.start;
                if (newRun.end == run.end) {
                    run.merge(newRun);
                } else if (newRun.end < run.end) {
                    TextStyleSpan.TextStyleRun r = new TextStyleSpan.TextStyleRun(run);
                    r.merge(newRun);
                    r.end = newRun.end;
                    b++;
                    N2++;
                    runs.add(b, r);
                    run.start = newRun.end;
                } else {
                    TextStyleSpan.TextStyleRun r = new TextStyleSpan.TextStyleRun(newRun);
                    r.start = run.end;
                    b++;
                    N2++;
                    runs.add(b, r);
                    run.merge(newRun);
                }
                newRun.end = temp;
            }
        }
        if (newRun.start < newRun.end) {
            runs.add(newRun);
        }
    }
    int count = runs.size();
    for (int a = 0; a < count; a++) {
        TextStyleSpan.TextStyleRun run = runs.get(a);
        boolean setRun = false;
        String url = run.urlEntity != null ? TextUtils.substring(text, run.urlEntity.offset, run.urlEntity.offset + run.urlEntity.length) : null;
        if (run.urlEntity instanceof TLRPC.TL_messageEntityBotCommand) {
            spannable.setSpan(new URLSpanBotCommand(url, t, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else if (run.urlEntity instanceof TLRPC.TL_messageEntityHashtag || run.urlEntity instanceof TLRPC.TL_messageEntityMention || run.urlEntity instanceof TLRPC.TL_messageEntityCashtag) {
            spannable.setSpan(new URLSpanNoUnderline(url, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else if (run.urlEntity instanceof TLRPC.TL_messageEntityEmail) {
            spannable.setSpan(new URLSpanReplacement("mailto:" + url, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else if (run.urlEntity instanceof TLRPC.TL_messageEntityUrl) {
            hasUrls = true;
            String lowerCase = url.toLowerCase();
            if (!lowerCase.contains("://")) {
                spannable.setSpan(new URLSpanBrowser("http://" + url, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            } else {
                spannable.setSpan(new URLSpanBrowser(url, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        } else if (run.urlEntity instanceof TLRPC.TL_messageEntityBankCard) {
            hasUrls = true;
            spannable.setSpan(new URLSpanNoUnderline("card:" + url, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else if (run.urlEntity instanceof TLRPC.TL_messageEntityPhone) {
            hasUrls = true;
            String tel = PhoneFormat.stripExceptNumbers(url);
            if (url.startsWith("+")) {
                tel = "+" + tel;
            }
            spannable.setSpan(new URLSpanBrowser("tel:" + tel, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else if (run.urlEntity instanceof TLRPC.TL_messageEntityTextUrl) {
            spannable.setSpan(new URLSpanReplacement(run.urlEntity.url, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else if (run.urlEntity instanceof TLRPC.TL_messageEntityMentionName) {
            spannable.setSpan(new URLSpanUserMention("" + ((TLRPC.TL_messageEntityMentionName) run.urlEntity).user_id, t, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else if (run.urlEntity instanceof TLRPC.TL_inputMessageEntityMentionName) {
            spannable.setSpan(new URLSpanUserMention("" + ((TLRPC.TL_inputMessageEntityMentionName) run.urlEntity).user_id.user_id, t, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else if ((run.flags & TextStyleSpan.FLAG_STYLE_MONO) != 0) {
            spannable.setSpan(new URLSpanMono(spannable, run.start, run.end, t, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else {
            setRun = true;
            spannable.setSpan(new TextStyleSpan(run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        if (!setRun && (run.flags & TextStyleSpan.FLAG_STYLE_SPOILER) != 0) {
            spannable.setSpan(new TextStyleSpan(run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }
    return hasUrls;
}
Also used : URLSpanMono(org.telegram.ui.Components.URLSpanMono) ArrayList(java.util.ArrayList) URLSpanBotCommand(org.telegram.ui.Components.URLSpanBotCommand) SpannableString(android.text.SpannableString) URLSpan(android.text.style.URLSpan) TLRPC(org.telegram.tgnet.TLRPC) TextStyleSpan(org.telegram.ui.Components.TextStyleSpan) URLSpanNoUnderline(org.telegram.ui.Components.URLSpanNoUnderline) URLSpanBrowser(org.telegram.ui.Components.URLSpanBrowser) TextPaint(android.text.TextPaint) URLSpanUserMention(org.telegram.ui.Components.URLSpanUserMention) Spannable(android.text.Spannable) URLSpanReplacement(org.telegram.ui.Components.URLSpanReplacement)

Example 4 with TextStyleSpan

use of org.telegram.ui.Components.TextStyleSpan in project Telegram-FOSS by Telegram-FOSS-Team.

the class SpoilerEffect method addSpoilersInternal.

@SuppressLint("WrongConstant")
private static void addSpoilersInternal(View v, Spannable spannable, Layout textLayout, int lineStart, int lineEnd, float lineLeft, float lineTop, float lineRight, float lineBottom, int realStart, int realEnd, Stack<SpoilerEffect> spoilersPool, List<SpoilerEffect> spoilers) {
    SpannableStringBuilder vSpan = SpannableStringBuilder.valueOf(AndroidUtilities.replaceNewLines(new SpannableStringBuilder(spannable, realStart, realEnd)));
    for (TextStyleSpan styleSpan : vSpan.getSpans(0, vSpan.length(), TextStyleSpan.class)) vSpan.removeSpan(styleSpan);
    for (URLSpan urlSpan : vSpan.getSpans(0, vSpan.length(), URLSpan.class)) vSpan.removeSpan(urlSpan);
    int tLen = vSpan.toString().trim().length();
    if (tLen == 0)
        return;
    int width = textLayout.getEllipsizedWidth() > 0 ? textLayout.getEllipsizedWidth() : textLayout.getWidth();
    TextPaint measurePaint = new TextPaint(textLayout.getPaint());
    measurePaint.setColor(Color.BLACK);
    StaticLayout newLayout;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        newLayout = StaticLayout.Builder.obtain(vSpan, 0, vSpan.length(), measurePaint, width).setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY).setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE).setAlignment(Layout.Alignment.ALIGN_NORMAL).setLineSpacing(textLayout.getSpacingAdd(), textLayout.getSpacingMultiplier()).build();
    } else
        newLayout = new StaticLayout(vSpan, measurePaint, width, Layout.Alignment.ALIGN_NORMAL, textLayout.getSpacingMultiplier(), textLayout.getSpacingAdd(), false);
    boolean rtlInNonRTL = (LocaleController.isRTLCharacter(vSpan.charAt(0)) || LocaleController.isRTLCharacter(vSpan.charAt(vSpan.length() - 1))) && !LocaleController.isRTL;
    SpoilerEffect spoilerEffect = spoilersPool == null || spoilersPool.isEmpty() ? new SpoilerEffect() : spoilersPool.remove(0);
    spoilerEffect.setRippleProgress(-1);
    float ps = realStart == lineStart ? lineLeft : textLayout.getPrimaryHorizontal(realStart), pe = realEnd == lineEnd || rtlInNonRTL && realEnd == lineEnd - 1 && spannable.charAt(lineEnd - 1) == '\u2026' ? lineRight : textLayout.getPrimaryHorizontal(realEnd);
    spoilerEffect.setBounds((int) Math.min(ps, pe), (int) lineTop, (int) Math.max(ps, pe), (int) lineBottom);
    spoilerEffect.setColor(textLayout.getPaint().getColor());
    spoilerEffect.setRippleInterpolator(Easings.easeInQuad);
    if (!spoilerEffect.isLowDevice)
        spoilerEffect.setKeyPoints(SpoilerEffect.measureKeyPoints(newLayout));
    spoilerEffect.updateMaxParticles();
    if (v != null) {
        spoilerEffect.setParentView(v);
    }
    spoilerEffect.spaces.clear();
    for (int i = 0; i < vSpan.length(); i++) {
        if (vSpan.charAt(i) == ' ') {
            RectF r = new RectF();
            int off = realStart + i;
            int line = textLayout.getLineForOffset(off);
            r.top = textLayout.getLineTop(line);
            r.bottom = textLayout.getLineBottom(line);
            float lh = textLayout.getPrimaryHorizontal(off), rh = textLayout.getPrimaryHorizontal(off + 1);
            // RTL
            r.left = (int) Math.min(lh, rh);
            r.right = (int) Math.max(lh, rh);
            if (Math.abs(lh - rh) <= AndroidUtilities.dp(20)) {
                spoilerEffect.spaces.add(r);
            }
        }
    }
    spoilers.add(spoilerEffect);
}
Also used : RectF(android.graphics.RectF) TextStyleSpan(org.telegram.ui.Components.TextStyleSpan) StaticLayout(android.text.StaticLayout) URLSpan(android.text.style.URLSpan) SpannableStringBuilder(android.text.SpannableStringBuilder) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint) SuppressLint(android.annotation.SuppressLint) TextPaint(android.text.TextPaint) SuppressLint(android.annotation.SuppressLint)

Example 5 with TextStyleSpan

use of org.telegram.ui.Components.TextStyleSpan in project Telegram-FOSS by Telegram-FOSS-Team.

the class SpoilerEffect method renderWithRipple.

/**
 * Optimized version of text layout double-render
 *
 * @param v                        View to use as a parent view
 * @param invalidateSpoilersParent Set to invalidate parent or not
 * @param spoilersColor            Spoilers' color
 * @param verticalOffset           Additional vertical offset
 * @param patchedLayoutRef         Patched layout reference
 * @param textLayout               Layout to render
 * @param spoilers                 Spoilers list to render
 * @param canvas                   Canvas to render
 */
@SuppressLint("WrongConstant")
@MainThread
public static void renderWithRipple(View v, boolean invalidateSpoilersParent, int spoilersColor, int verticalOffset, AtomicReference<Layout> patchedLayoutRef, Layout textLayout, List<SpoilerEffect> spoilers, Canvas canvas) {
    if (spoilers.isEmpty()) {
        textLayout.draw(canvas);
        return;
    }
    Layout pl = patchedLayoutRef.get();
    if (pl == null || !textLayout.getText().toString().equals(pl.getText().toString()) || textLayout.getWidth() != pl.getWidth() || textLayout.getHeight() != pl.getHeight()) {
        SpannableStringBuilder sb = new SpannableStringBuilder(textLayout.getText());
        Spannable sp = (Spannable) textLayout.getText();
        for (TextStyleSpan ss : sp.getSpans(0, sp.length(), TextStyleSpan.class)) {
            if (ss.isSpoiler()) {
                int start = sp.getSpanStart(ss), end = sp.getSpanEnd(ss);
                for (Emoji.EmojiSpan e : sp.getSpans(start, end, Emoji.EmojiSpan.class)) {
                    sb.setSpan(new ReplacementSpan() {

                        @Override
                        public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) {
                            return e.getSize(paint, text, start, end, fm);
                        }

                        @Override
                        public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
                        }
                    }, start, end, sp.getSpanFlags(ss));
                    sb.removeSpan(e);
                }
                sb.setSpan(new ForegroundColorSpan(Color.TRANSPARENT), sp.getSpanStart(ss), sp.getSpanEnd(ss), sp.getSpanFlags(ss));
                sb.removeSpan(ss);
            }
        }
        Layout layout;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            layout = StaticLayout.Builder.obtain(sb, 0, sb.length(), textLayout.getPaint(), textLayout.getWidth()).setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY).setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE).setAlignment(Layout.Alignment.ALIGN_NORMAL).setLineSpacing(textLayout.getSpacingAdd(), textLayout.getSpacingMultiplier()).build();
        } else {
            layout = new StaticLayout(sb, textLayout.getPaint(), textLayout.getWidth(), textLayout.getAlignment(), textLayout.getSpacingMultiplier(), textLayout.getSpacingAdd(), false);
        }
        patchedLayoutRef.set(pl = layout);
    }
    if (!spoilers.isEmpty()) {
        canvas.save();
        canvas.translate(0, verticalOffset);
        pl.draw(canvas);
        canvas.restore();
    } else {
        textLayout.draw(canvas);
    }
    if (!spoilers.isEmpty()) {
        tempPath.rewind();
        for (SpoilerEffect eff : spoilers) {
            Rect b = eff.getBounds();
            tempPath.addRect(b.left, b.top, b.right, b.bottom, Path.Direction.CW);
        }
        if (!spoilers.isEmpty() && spoilers.get(0).rippleProgress != -1) {
            canvas.save();
            canvas.clipPath(tempPath);
            tempPath.rewind();
            if (!spoilers.isEmpty()) {
                spoilers.get(0).getRipplePath(tempPath);
            }
            canvas.clipPath(tempPath);
            canvas.translate(0, -v.getPaddingTop());
            textLayout.draw(canvas);
            canvas.restore();
        }
        boolean useAlphaLayer = spoilers.get(0).rippleProgress != -1;
        if (useAlphaLayer) {
            canvas.saveLayer(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight(), null, canvas.ALL_SAVE_FLAG);
        } else {
            canvas.save();
        }
        canvas.translate(0, -v.getPaddingTop());
        for (SpoilerEffect eff : spoilers) {
            eff.setInvalidateParent(invalidateSpoilersParent);
            if (eff.getParentView() != v)
                eff.setParentView(v);
            if (eff.shouldInvalidateColor()) {
                eff.setColor(ColorUtils.blendARGB(spoilersColor, Theme.chat_msgTextPaint.getColor(), Math.max(0, eff.getRippleProgress())));
            } else {
                eff.setColor(spoilersColor);
            }
            eff.draw(canvas);
        }
        if (useAlphaLayer) {
            tempPath.rewind();
            spoilers.get(0).getRipplePath(tempPath);
            if (xRefPaint == null) {
                xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
                xRefPaint.setColor(0xff000000);
                xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            }
            canvas.drawPath(tempPath, xRefPaint);
        }
        canvas.restore();
    }
}
Also used : Rect(android.graphics.Rect) ForegroundColorSpan(android.text.style.ForegroundColorSpan) Canvas(android.graphics.Canvas) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint) StaticLayout(android.text.StaticLayout) ReplacementSpan(android.text.style.ReplacementSpan) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint) SuppressLint(android.annotation.SuppressLint) Layout(android.text.Layout) StaticLayout(android.text.StaticLayout) TextStyleSpan(org.telegram.ui.Components.TextStyleSpan) PorterDuffXfermode(android.graphics.PorterDuffXfermode) Emoji(org.telegram.messenger.Emoji) SpannableStringBuilder(android.text.SpannableStringBuilder) Spannable(android.text.Spannable) MainThread(androidx.annotation.MainThread) SuppressLint(android.annotation.SuppressLint)

Aggregations

TextStyleSpan (org.telegram.ui.Components.TextStyleSpan)11 Paint (android.graphics.Paint)10 TextPaint (android.text.TextPaint)9 SuppressLint (android.annotation.SuppressLint)8 SpannableStringBuilder (android.text.SpannableStringBuilder)8 Spannable (android.text.Spannable)6 TLRPC (org.telegram.tgnet.TLRPC)6 StaticLayout (android.text.StaticLayout)5 URLSpanReplacement (org.telegram.ui.Components.URLSpanReplacement)5 ArrayList (java.util.ArrayList)4 URLSpanUserMention (org.telegram.ui.Components.URLSpanUserMention)4 Canvas (android.graphics.Canvas)3 PorterDuffXfermode (android.graphics.PorterDuffXfermode)3 RectF (android.graphics.RectF)3 SpannableString (android.text.SpannableString)3 CharacterStyle (android.text.style.CharacterStyle)3 URLSpan (android.text.style.URLSpan)3 Activity (android.app.Activity)2 Context (android.content.Context)2 Rect (android.graphics.Rect)2