NekoX/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java

744 lines
33 KiB
Java

/*
* 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 android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.StaticLayout;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.text.util.Linkify;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.Emoji;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessageObject;
import org.telegram.messenger.R;
import org.telegram.messenger.browser.Browser;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.BottomSheet;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.AlertsCreator;
import org.telegram.ui.Components.BulletinFactory;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.LinkPath;
import org.telegram.ui.Components.LinkSpanDrawable;
import org.telegram.ui.Components.StaticLayoutEx;
import org.telegram.ui.Components.URLSpanNoUnderline;
import java.util.concurrent.atomic.AtomicReference;
public class AboutLinkCell extends FrameLayout {
private StaticLayout textLayout;
private String oldText;
private int textX;
private int textY;
private SpannableStringBuilder stringBuilder;
private TextView valueTextView;
private TextView showMoreTextView;
private FrameLayout showMoreTextBackgroundView;
private FrameLayout bottomShadow;
private Drawable showMoreBackgroundDrawable;
private LinkSpanDrawable pressedLink;
private LinkSpanDrawable.LinkCollector links;
private Point urlPathOffset = new Point();
private LinkPath urlPath = new LinkPath(true);
private BaseFragment parentFragment;
private Theme.ResourcesProvider resourcesProvider;
private FrameLayout container;
private Drawable rippleBackground;
private StaticLayout firstThreeLinesLayout;
private StaticLayout[] nextLinesLayouts = null;
private int lastInlineLine = -1;
private Point[] nextLinesLayoutsPositions;
private boolean needSpace = false;
private boolean moreButtonDisabled;
public AboutLinkCell(Context context, BaseFragment fragment) {
this(context, fragment, null);
}
public AboutLinkCell(Context context, BaseFragment fragment, Theme.ResourcesProvider resourcesProvider) {
super(context);
this.resourcesProvider = resourcesProvider;
parentFragment = fragment;
container = new FrameLayout(context) {
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
boolean result = false;
if (textLayout != null || nextLinesLayouts != null) {
if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) {
if (x >= showMoreTextView.getLeft() && x <= showMoreTextView.getRight() &&
y >= showMoreTextView.getTop() && y <= showMoreTextView.getBottom()) {
return super.onTouchEvent(event);
}
if (getMeasuredWidth() > 0 && x > getMeasuredWidth() - AndroidUtilities.dp(23)) {
return super.onTouchEvent(event);
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (firstThreeLinesLayout != null && expandT < 1 && shouldExpand) {
if (checkTouchTextLayout(firstThreeLinesLayout, textX, textY, x, y)) {
result = true;
} else if (nextLinesLayouts != null) {
for (int i = 0; i < nextLinesLayouts.length; ++i) {
if (checkTouchTextLayout(nextLinesLayouts[i], nextLinesLayoutsPositions[i].x, nextLinesLayoutsPositions[i].y, x, y)) {
result = true;
break;
}
}
}
} else if (checkTouchTextLayout(textLayout, textX, textY, x, y)) {
result = true;
}
if (!result) {
resetPressedLink();
}
} else if (pressedLink != null) {
try {
onLinkClick((ClickableSpan) pressedLink.getSpan());
} catch (Exception e) {
FileLog.e(e);
}
resetPressedLink();
result = true;
}
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
resetPressedLink();
}
}
return result || super.onTouchEvent(event);
}
};
container.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
links = new LinkSpanDrawable.LinkCollector(container);
container.setClickable(true);
rippleBackground = Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), 0, 0);
valueTextView = new TextView(context);
valueTextView.setVisibility(GONE);
valueTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider));
valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13);
valueTextView.setLines(1);
valueTextView.setMaxLines(1);
valueTextView.setSingleLine(true);
valueTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
valueTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
valueTextView.setFocusable(false);
container.addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.BOTTOM, 23, 0, 23, 10));
bottomShadow = new FrameLayout(context);
Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.gradient_bottom).mutate();
shadowDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider), PorterDuff.Mode.SRC_ATOP));
bottomShadow.setBackground(shadowDrawable);
addView(bottomShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 12, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, 0));
addView(container, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.FILL_HORIZONTAL));
showMoreTextView = new TextView(context) {
private boolean pressed = false;
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean wasPressed = pressed;
if (event.getAction() == MotionEvent.ACTION_DOWN) {
pressed = true;
} else if (event.getAction() != MotionEvent.ACTION_MOVE) {
pressed = false;
}
if (wasPressed != pressed) {
invalidate();
}
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
if (pressed) {
AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight());
canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(4), AndroidUtilities.dp(4), Theme.chat_urlPaint);
}
super.onDraw(canvas);
}
};
showMoreTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourcesProvider));
showMoreTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
showMoreTextView.setLines(1);
showMoreTextView.setMaxLines(1);
showMoreTextView.setSingleLine(true);
showMoreTextView.setText(LocaleController.getString("DescriptionMore", R.string.DescriptionMore));
showMoreTextView.setOnClickListener(e -> {
updateCollapse(true, true);
});
showMoreTextView.setPadding(AndroidUtilities.dp(2), 0, AndroidUtilities.dp(2), 0);
showMoreTextBackgroundView = new FrameLayout(context);
showMoreBackgroundDrawable = context.getResources().getDrawable(R.drawable.gradient_left).mutate();
showMoreBackgroundDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider), PorterDuff.Mode.MULTIPLY));
showMoreTextBackgroundView.setBackground(showMoreBackgroundDrawable);
showMoreTextBackgroundView.setPadding(
showMoreTextBackgroundView.getPaddingLeft() + AndroidUtilities.dp(4),
AndroidUtilities.dp(1),
0,
AndroidUtilities.dp(3)
);
showMoreTextBackgroundView.addView(showMoreTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT));
addView(showMoreTextBackgroundView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT | Gravity.BOTTOM, 22 - showMoreTextBackgroundView.getPaddingLeft() / AndroidUtilities.density, 0, 22 - showMoreTextBackgroundView.getPaddingRight() / AndroidUtilities.density, 6));
backgroundPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider));
setWillNotDraw(false);
}
private void setShowMoreMarginBottom(int marginBottom) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) showMoreTextBackgroundView.getLayoutParams();
if (lp.bottomMargin != marginBottom) {
lp.bottomMargin = marginBottom;
showMoreTextBackgroundView.setLayoutParams(lp);
}
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
return false;
}
private Paint backgroundPaint = new Paint();
@Override
public void draw(Canvas canvas) {
View parent = (View) getParent();
float alpha = parent == null ? 1f : (float) Math.pow(parent.getAlpha(), 2f);
drawText(canvas);
float viewAlpha = showMoreTextBackgroundView.getAlpha();
if (viewAlpha > 0) {
canvas.save();
canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (viewAlpha * 255), Canvas.ALL_SAVE_FLAG);
showMoreBackgroundDrawable.setAlpha((int) (alpha * 255));
canvas.translate(showMoreTextBackgroundView.getLeft(), showMoreTextBackgroundView.getTop());
showMoreTextBackgroundView.draw(canvas);
canvas.restore();
}
viewAlpha = bottomShadow.getAlpha();
if (viewAlpha > 0) {
canvas.save();
canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (viewAlpha * 255), Canvas.ALL_SAVE_FLAG);
canvas.translate(bottomShadow.getLeft(), bottomShadow.getTop());
bottomShadow.draw(canvas);
canvas.restore();
}
container.draw(canvas);
super.draw(canvas);
}
final float SPACE = AndroidUtilities.dp(3f);
private void drawText(Canvas canvas) {
canvas.save();
canvas.clipRect(AndroidUtilities.dp(23 - 8), AndroidUtilities.dp(8), getWidth() - AndroidUtilities.dp(23), getHeight());
canvas.translate(textX = AndroidUtilities.dp(23), 0);
if (links != null && links.draw(canvas)) {
invalidate();
}
canvas.translate(0, textY = AndroidUtilities.dp(8));
try {
if (firstThreeLinesLayout == null || !shouldExpand) {
if (textLayout != null) {
textLayout.draw(canvas);
}
} else {
firstThreeLinesLayout.draw(canvas);
int lastLine = firstThreeLinesLayout.getLineCount() - 1;
float top = firstThreeLinesLayout.getLineTop(lastLine) + firstThreeLinesLayout.getTopPadding();
float x = firstThreeLinesLayout.getLineRight(lastLine) + (needSpace ? SPACE : 0),
y = firstThreeLinesLayout.getLineBottom(lastLine) - firstThreeLinesLayout.getLineTop(lastLine) - firstThreeLinesLayout.getBottomPadding();
float t = easeInOutCubic(1f - (float) Math.pow(expandT, 0.25f));
if (nextLinesLayouts != null) {
for (int line = 0; line < nextLinesLayouts.length; ++line) {
final StaticLayout layout = nextLinesLayouts[line];
if (layout != null) {
final int c = canvas.save();
if (nextLinesLayoutsPositions[line] != null) {
nextLinesLayoutsPositions[line].set((int) (textX + x * t), (int) (textY + top + y * (1f - t)));
}
if (lastInlineLine != -1 && lastInlineLine <= line) {
canvas.translate(0, top + y);
canvas.saveLayerAlpha(0, 0, layout.getWidth(), layout.getHeight(), (int) (255 * expandT), Canvas.ALL_SAVE_FLAG);
} else {
canvas.translate(x * t, top + y * (1f - t));
}
layout.draw(canvas);
canvas.restoreToCount(c);
x += layout.getLineRight(0) + SPACE;
y += layout.getLineBottom(0) + layout.getTopPadding();
}
}
}
}
} catch (Exception e) {
FileLog.e(e);
}
canvas.restore();
}
@Override
public void setOnClickListener(@Nullable OnClickListener l) {
container.setOnClickListener(l);
}
protected void didPressUrl(String url) {
}
protected void didResizeStart() {
}
protected void didResizeEnd() {
}
protected void didExtend() {}
private void resetPressedLink() {
links.clear();
pressedLink = null;
AndroidUtilities.cancelRunOnUIThread(longPressedRunnable);
invalidate();
}
public void setText(String text, boolean parseLinks) {
setTextAndValue(text, null, parseLinks);
}
public void setTextAndValue(String text, String value, boolean parseLinks) {
if (TextUtils.isEmpty(text) || TextUtils.equals(text, oldText)) {
return;
}
try {
oldText = AndroidUtilities.getSafeString(text);
} catch (Throwable e) {
oldText = text;
}
stringBuilder = new SpannableStringBuilder(oldText);
MessageObject.addLinks(false, stringBuilder, false, false, !parseLinks);
Emoji.replaceEmoji(stringBuilder, Theme.profile_aboutTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
if (lastMaxWidth <= 0) {
lastMaxWidth = AndroidUtilities.displaySize.x - AndroidUtilities.dp(23 + 23);
}
checkTextLayout(lastMaxWidth, true);
updateHeight();
int wasValueVisibility = valueTextView.getVisibility();
if (TextUtils.isEmpty(value)) {
valueTextView.setVisibility(GONE);
} else {
valueTextView.setText(value);
valueTextView.setVisibility(VISIBLE);
}
if (wasValueVisibility != valueTextView.getVisibility()) {
checkTextLayout(lastMaxWidth, true);
}
requestLayout();
}
Runnable longPressedRunnable = new Runnable() {
@Override
public void run() {
if (pressedLink != null) {
String url;
if (pressedLink.getSpan() instanceof URLSpanNoUnderline) {
url = ((URLSpanNoUnderline) pressedLink.getSpan()).getURL();
} else if (pressedLink.getSpan() instanceof URLSpan) {
url = ((URLSpan) pressedLink.getSpan()).getURL();
} else {
url = pressedLink.getSpan().toString();
}
try {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
} catch (Exception ignore) {}
ClickableSpan pressedLinkFinal = (ClickableSpan) pressedLink.getSpan();
BottomSheet.Builder builder = new BottomSheet.Builder(parentFragment.getParentActivity());
builder.setTitle(url);
builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> {
if (which == 0) {
onLinkClick(pressedLinkFinal);
} else if (which == 1) {
AndroidUtilities.addToClipboard(url);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
if (url.startsWith("@")) {
BulletinFactory.of(parentFragment).createSimpleBulletin(R.raw.copy, LocaleController.getString("UsernameCopied", R.string.UsernameCopied)).show();
} else if (url.startsWith("#") || url.startsWith("$")) {
BulletinFactory.of(parentFragment).createSimpleBulletin(R.raw.copy, LocaleController.getString("HashtagCopied", R.string.HashtagCopied)).show();
} else {
BulletinFactory.of(parentFragment).createSimpleBulletin(R.raw.copy, LocaleController.getString("LinkCopied", R.string.LinkCopied)).show();
}
}
}
});
builder.setOnPreDismissListener(di -> resetPressedLink());
builder.show();
pressedLink = null;
}
}
};
private boolean checkTouchTextLayout(StaticLayout textLayout, int textX, int textY, int ex, int ey) {
try {
int x = (int) (ex - textX);
int y = (int) (ey - textY);
final int line = textLayout.getLineForVertical(y);
final int off = textLayout.getOffsetForHorizontal(line, x);
final float left = textLayout.getLineLeft(line);
if (left <= x && left + textLayout.getLineWidth(line) >= x && y >= 0 && y <= textLayout.getHeight()) {
Spannable buffer = (Spannable) textLayout.getText();
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0 && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) {
resetPressedLink();
pressedLink = new LinkSpanDrawable(link[0], parentFragment.getResourceProvider(), ex, ey);
links.addLink(pressedLink);
int start = buffer.getSpanStart(pressedLink.getSpan());
int end = buffer.getSpanEnd(pressedLink.getSpan());
LinkPath path = pressedLink.obtainNewPath();
path.setCurrentLayout(textLayout, start, textY);
textLayout.getSelectionPath(start, end, path);
AndroidUtilities.runOnUIThread(longPressedRunnable, ViewConfiguration.getLongPressTimeout());
return true;
} else {
return false;
}
} else {
return false;
}
} catch (Exception e) {
FileLog.e(e);
return false;
}
}
private void onLinkClick(ClickableSpan pressedLink) {
if (pressedLink instanceof URLSpanNoUnderline) {
String url = ((URLSpanNoUnderline) pressedLink).getURL();
if (url.startsWith("@") || url.startsWith("#") || url.startsWith("/")) {
didPressUrl(url);
}
} else {
if (pressedLink instanceof URLSpan) {
String url = ((URLSpan) pressedLink).getURL();
if (AndroidUtilities.shouldShowUrlInAlert(url)) {
AlertsCreator.showOpenUrlAlert(parentFragment, url, true, true);
} else {
Browser.openUrl(getContext(), url);
}
} else {
pressedLink.onClick(this);
}
}
}
private static final int COLLAPSED_HEIGHT = AndroidUtilities.dp(8 + 20 * 3 + 8);
private static final int MAX_OPEN_HEIGHT = COLLAPSED_HEIGHT;// + AndroidUtilities.dp(20);
public class SpringInterpolator {
public float tension;
public float friction;
public SpringInterpolator(float tension, float friction) {
this.tension = tension;
this.friction = friction;
}
private final float mass = 1f;
private float position = 0, velocity = 0;
public float getValue(float deltaTime) {
deltaTime = Math.min(deltaTime, 250);
final float MAX_DELTA_TIME = 18;
while (deltaTime > 0) {
final float step = Math.min(deltaTime, MAX_DELTA_TIME);
step(step);
deltaTime -= step;
}
return position;
}
private void step(float delta) {
final float acceleration = (
-tension * 0.000001f * (position - 1f) + // spring force
-friction * 0.001f * velocity // damping force
) / mass; // pt/ms^2
velocity = velocity + acceleration * delta; // pt/ms
position = position + velocity * delta;
}
}
private float expandT = 0f;
private float rawCollapseT = 0f;
private ValueAnimator collapseAnimator;
private boolean expanded = false;
public void updateCollapse(boolean value, boolean animated) {
if (collapseAnimator != null) {
collapseAnimator.cancel();
collapseAnimator = null;
}
float fromValue = expandT,
toValue = value ? 1f : 0f;
if (animated) {
if (toValue > 0) {
didExtend();
}
float fullHeight = textHeight();
float collapsedHeight = Math.min(COLLAPSED_HEIGHT, fullHeight);
float fromHeight = AndroidUtilities.lerp(collapsedHeight, fullHeight, fromValue);
float toHeight = AndroidUtilities.lerp(collapsedHeight, fullHeight, toValue);
float dHeight = Math.abs(toHeight - fromHeight);
// float speedMultiplier = Math.min(Math.max(dHeight / AndroidUtilities.dp(76), 0.5f), 2f);
collapseAnimator = ValueAnimator.ofFloat(0, 1);
final float duration = Math.abs(fromValue - toValue) * 1250 * 2f;
final SpringInterpolator spring = new SpringInterpolator(380f, 20.17f);
final AtomicReference<Float> lastValue = new AtomicReference<>(fromValue);
collapseAnimator.addUpdateListener(a -> {
float now = (float) a.getAnimatedValue();
float deltaTime = (now - lastValue.getAndSet(now)) * 1000 * 8f;
rawCollapseT = AndroidUtilities.lerp(fromValue, toValue, (float) a.getAnimatedValue());
expandT = AndroidUtilities.lerp(fromValue, toValue, spring.getValue(deltaTime));
if (expandT > 0.8f && container.getBackground() == null) {
container.setBackground(rippleBackground);
}
showMoreTextBackgroundView.setAlpha(1f - expandT);
bottomShadow.setAlpha((float) Math.pow(1f - expandT, 2f));
updateHeight();
container.invalidate();
});
collapseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
didResizeEnd();
if (container.getBackground() == null) {
container.setBackground(rippleBackground);
}
expanded = true;
}
@Override
public void onAnimationStart(Animator animation) {
didResizeStart();
}
});
collapseAnimator.setDuration((long) duration);
collapseAnimator.start();
} else {
expandT = toValue;
forceLayout();
}
}
private int fromHeight() {
return Math.min(COLLAPSED_HEIGHT + (valueTextView.getVisibility() == View.VISIBLE ? AndroidUtilities.dp(20) : 0), textHeight());
}
private int updateHeight() {
int textHeight = textHeight();
float fromHeight = fromHeight();
int height = shouldExpand ? (int) AndroidUtilities.lerp(fromHeight, textHeight, expandT) : textHeight;
setHeight(height);
return height;
}
private void setHeight(int height) {
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) getLayoutParams();
int wasHeight;
boolean newHeight;
if (lp == null) {
newHeight = true;
wasHeight = (getMinimumHeight() == 0 ? getHeight() : getMinimumHeight());
lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
} else {
wasHeight = lp.height;
newHeight = wasHeight != height;
lp.height = height;
}
if (newHeight) {
setLayoutParams(lp);
}
}
private static final int MOST_SPEC = View.MeasureSpec.makeMeasureSpec(999999, View.MeasureSpec.AT_MOST);
private int lastMaxWidth = 0;
@SuppressLint("DrawAllocation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
checkTextLayout(MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(23 + 23), false);
int height = updateHeight();
super.onMeasure(
widthMeasureSpec,
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
);
}
private StaticLayout makeTextLayout(CharSequence string, int width) {
if (Build.VERSION.SDK_INT >= 24) {
return StaticLayout.Builder.obtain(string, 0, string.length(), Theme.profile_aboutTextPaint, width)
.setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY)
.setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE)
.setAlignment(LocaleController.isRTL ? StaticLayoutEx.ALIGN_RIGHT() : StaticLayoutEx.ALIGN_LEFT())
.build();
} else {
return new StaticLayout(string, Theme.profile_aboutTextPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
}
}
private void checkTextLayout(int maxWidth, boolean force) {
if (moreButtonDisabled) {
shouldExpand = false;
}
if (stringBuilder != null && (maxWidth != lastMaxWidth || force)) {
textLayout = makeTextLayout(stringBuilder, maxWidth);
shouldExpand = textLayout.getLineCount() >= 4; // && valueTextView.getVisibility() != View.VISIBLE;
if (textLayout.getLineCount() >= 3 && shouldExpand) {
int end = Math.max(textLayout.getLineStart(2), textLayout.getLineEnd(2));
if (stringBuilder.charAt(end - 1) == '\n')
end -= 1;
needSpace = stringBuilder.charAt(end - 1) != ' ' && stringBuilder.charAt(end - 1) != '\n';
firstThreeLinesLayout = makeTextLayout(stringBuilder.subSequence(0, end), maxWidth);
nextLinesLayouts = new StaticLayout[textLayout.getLineCount() - 3];
nextLinesLayoutsPositions = new Point[textLayout.getLineCount() - 3];
int lastLine = firstThreeLinesLayout.getLineCount() - 1;
float x = firstThreeLinesLayout.getLineRight(lastLine) + (needSpace ? SPACE : 0);
lastInlineLine = -1;
if (showMoreTextBackgroundView.getMeasuredWidth() <= 0) {
showMoreTextBackgroundView.measure(MOST_SPEC, MOST_SPEC);
}
for (int line = 3; line < textLayout.getLineCount(); ++line) {
int s = textLayout.getLineStart(line),
e = textLayout.getLineEnd(line);
final StaticLayout layout = makeTextLayout(stringBuilder.subSequence(Math.min(s, e), Math.max(s, e)), maxWidth);
nextLinesLayouts[line - 3] = layout;
nextLinesLayoutsPositions[line - 3] = new Point();
if (lastInlineLine == -1 && x > maxWidth - showMoreTextBackgroundView.getMeasuredWidth() + showMoreTextBackgroundView.getPaddingLeft()) {
lastInlineLine = line - 3;
}
x += layout.getLineRight(0) + SPACE;
}
if (x < maxWidth - showMoreTextBackgroundView.getMeasuredWidth() + showMoreTextBackgroundView.getPaddingLeft()) {
shouldExpand = false;
}
}
if (!shouldExpand) {
firstThreeLinesLayout = null;
nextLinesLayouts = null;
}
lastMaxWidth = maxWidth;
container.setMinimumHeight(textHeight());
if (shouldExpand && firstThreeLinesLayout != null) {
setShowMoreMarginBottom(
fromHeight()
-AndroidUtilities.dp(8)
-firstThreeLinesLayout.getLineBottom(firstThreeLinesLayout.getLineCount() - 1)
-showMoreTextBackgroundView.getPaddingBottom()
-showMoreTextView.getPaddingBottom()
-(showMoreTextView.getLayout() == null ? 0 : showMoreTextView.getLayout().getHeight() - showMoreTextView.getLayout().getLineBottom(showMoreTextView.getLineCount() - 1))
);
}
}
showMoreTextView.setVisibility(shouldExpand ? View.VISIBLE : View.GONE);
if (!shouldExpand && container.getBackground() == null) {
container.setBackground(rippleBackground);
}
if (shouldExpand && expandT < 1 && container.getBackground() != null) {
container.setBackground(null);
}
}
private int textHeight() {
int height = (textLayout != null ? textLayout.getHeight() : AndroidUtilities.dp(20)) + AndroidUtilities.dp(16);
if (valueTextView.getVisibility() == VISIBLE) {
height += AndroidUtilities.dp(23);
}
return height;
}
private boolean shouldExpand = false;
// private boolean shouldCollapse() {
// return textLayout != null && textLayout.getLineCount() > 4/* && valueTextView.getVisibility() != View.VISIBLE*/;
// }
public boolean onClick() {
if (shouldExpand && expandT <= 0) {
updateCollapse(true, true);
return true;
}
return false;
}
private float easeInOutCubic(float x) {
return x < 0.5 ? 4 * x * x * x : 1 - (float) Math.pow(-2 * x + 2, 3) / 2;
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
if (textLayout != null) {
final CharSequence text = stringBuilder;
final CharSequence valueText = valueTextView.getText();
info.setClassName("android.widget.TextView");
if (TextUtils.isEmpty(valueText)) {
info.setText(text);
} else {
info.setText(valueText + ": " + text);
}
}
}
public void setMoreButtonDisabled(boolean moreButtonDisabled) {
this.moreButtonDisabled = moreButtonDisabled;
}
}