/* * This is the source code of Telegram for Android v. 1.3.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. */ package org.telegram.ui.Cells; import android.content.Context; import android.graphics.Canvas; import android.text.Spannable; import android.text.style.ClickableSpan; import android.view.MotionEvent; import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.android.MessageObject; public class ChatMessageCell extends ChatBaseCell { private int textX, textY; private int totalHeight = 0; private ClickableSpan pressedLink; private int lastVisibleBlockNum = 0; private int firstVisibleBlockNum = 0; private int totalVisibleBlocksCount = 0; public ChatMessageCell(Context context) { super(context, false); drawForwardedName = true; } @Override public boolean onTouchEvent(MotionEvent event) { if (currentMessageObject != null && currentMessageObject.textLayoutBlocks != null && !currentMessageObject.textLayoutBlocks.isEmpty() && currentMessageObject.messageText instanceof Spannable && !isPressed) { if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) { int x = (int)event.getX(); int y = (int)event.getY(); if (x >= textX && y >= textY && x <= textX + currentMessageObject.textWidth && y <= textY + currentMessageObject.textHeight) { y -= textY; int blockNum = Math.max(0, y / currentMessageObject.blockHeight); if (blockNum < currentMessageObject.textLayoutBlocks.size()) { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum); x -= textX - (int)Math.ceil(block.textXOffset); y -= block.textYOffset; final int line = block.textLayout.getLineForVertical(y); final int off = block.textLayout.getOffsetForHorizontal(line, x) + block.charactersOffset; final float left = block.textLayout.getLineLeft(line); if (left <= x && left + block.textLayout.getLineWidth(line) >= x) { Spannable buffer = (Spannable)currentMessageObject.messageText; ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { if (event.getAction() == MotionEvent.ACTION_DOWN) { pressedLink = link[0]; return true; } else { if (link[0] == pressedLink) { try { pressedLink.onClick(this); } catch (Exception e) { FileLog.e("tmessages", e); } return true; } } } else { pressedLink = null; } } else { pressedLink = null; } } else { pressedLink = null; } } else { pressedLink = null; } } } else { pressedLink = null; } return super.onTouchEvent(event); } public void setVisiblePart(int position, int height) { if (currentMessageObject == null || currentMessageObject.textLayoutBlocks == null) { return; } int newFirst = -1, newLast = -1, newCount = 0; for (int a = Math.max(0, (position - textY) / currentMessageObject.blockHeight); a < currentMessageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); float y = textY + block.textYOffset; if (intersect(y, y + currentMessageObject.blockHeight, position, position + height)) { if (newFirst == -1) { newFirst = a; } newLast = a; newCount++; } else if (y > position) { break; } } if (lastVisibleBlockNum != newLast || firstVisibleBlockNum != newFirst || totalVisibleBlocksCount != newCount) { lastVisibleBlockNum = newLast; firstVisibleBlockNum = newFirst; totalVisibleBlocksCount = newCount; invalidate(); } } private boolean intersect(float left1, float right1, float left2, float right2) { if (left1 <= left2) { return right1 >= left2; } return left1 <= right2; } @Override public void setMessageObject(MessageObject messageObject) { if (currentMessageObject != messageObject || isUserDataChanged()) { if (currentMessageObject != messageObject) { firstVisibleBlockNum = 0; lastVisibleBlockNum = 0; } pressedLink = null; int maxWidth; if (isChat && !messageObject.isOut()) { maxWidth = AndroidUtilities.displaySize.x - AndroidUtilities.dp(122); drawName = true; } else { maxWidth = AndroidUtilities.displaySize.x - AndroidUtilities.dp(80); drawName = false; } backgroundWidth = maxWidth; super.setMessageObject(messageObject); backgroundWidth = messageObject.textWidth; totalHeight = messageObject.textHeight + AndroidUtilities.dpf(19.5f) + namesOffset; int maxChildWidth = Math.max(backgroundWidth, nameWidth); maxChildWidth = Math.max(maxChildWidth, forwardedNameWidth); int timeMore = timeWidth + AndroidUtilities.dp(6); if (messageObject.isOut()) { timeMore += AndroidUtilities.dpf(20.5f); } if (maxWidth - messageObject.lastLineWidth < timeMore) { totalHeight += AndroidUtilities.dp(14); backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth) + AndroidUtilities.dp(29); } else { int diff = maxChildWidth - messageObject.lastLineWidth; if (diff >= 0 && diff <= timeMore) { backgroundWidth = maxChildWidth + timeMore - diff + AndroidUtilities.dp(29); } else { backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth + timeMore) + AndroidUtilities.dp(29); } } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), totalHeight); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (currentMessageObject.isOut()) { textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10); textY = AndroidUtilities.dp(10) + namesOffset; } else { textX = AndroidUtilities.dp(19) + (isChat ? AndroidUtilities.dp(52) : 0); textY = AndroidUtilities.dp(10) + namesOffset; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (currentMessageObject == null || currentMessageObject.textLayoutBlocks == null || currentMessageObject.textLayoutBlocks.isEmpty() || firstVisibleBlockNum < 0) { return; } if (currentMessageObject.isOut()) { textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10); textY = AndroidUtilities.dp(10) + namesOffset; } else { textX = AndroidUtilities.dp(19) + (isChat ? AndroidUtilities.dp(52) : 0); textY = AndroidUtilities.dp(10) + namesOffset; } for (int a = firstVisibleBlockNum; a <= lastVisibleBlockNum; a++) { if (a >= currentMessageObject.textLayoutBlocks.size()) { break; } MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); canvas.save(); canvas.translate(textX - (int)Math.ceil(block.textXOffset), textY + block.textYOffset); try { block.textLayout.draw(canvas); } catch (Exception e) { FileLog.e("tmessages", e); } canvas.restore(); } } }