Skip to content

Commit

Permalink
fix: Update App Alert Dialog cannot show Emoji
Browse files Browse the repository at this point in the history
Co-authored-by: tehcneko <[email protected]>
  • Loading branch information
omg-xtao and tehcneko committed Feb 15, 2024
1 parent 08ae169 commit 8b14fd8
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import java.util.Locale;

import tw.nekomimi.nekogram.TextViewEffects;
import tw.nekomimi.nekogram.helpers.remote.UpdateHelper;

public class BlockingUpdateView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate {
Expand Down Expand Up @@ -97,7 +98,7 @@ public BlockingUpdateView(final Context context) {
titleTextView.setText(LocaleController.getString("UpdateTelegram", R.string.UpdateTelegram).replace("Telegram", LocaleController.getString("NekoX", R.string.NekoX)));
container.addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP));

textView = new TextView(context);
textView = new TextViewEffects(context);
textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
textView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Stories.recorder.ButtonWithCounterView;

import tw.nekomimi.nekogram.TextViewEffects;

public class UpdateAppAlertDialog extends BottomSheet {

private TLRPC.TL_help_appUpdate appUpdate;
Expand Down Expand Up @@ -266,7 +268,7 @@ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
messageTextView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
linearLayout.addView(messageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 23, 0, 23, 5));

TextView changelogTextView = new TextView(getContext());
TextView changelogTextView = new TextViewEffects(getContext());
changelogTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
changelogTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
changelogTextView.setLinkTextColor(Theme.getColor(Theme.key_dialogTextLink));
Expand Down
219 changes: 219 additions & 0 deletions TMessagesProj/src/main/java/tw/nekomimi/nekogram/TextViewEffects.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package tw.nekomimi.nekogram;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Region;
import android.text.Layout;
import android.text.Spanned;
import android.view.MotionEvent;

import org.telegram.messenger.AndroidUtilities;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.AnimatedEmojiDrawable;
import org.telegram.ui.Components.AnimatedEmojiSpan;
import org.telegram.ui.Components.LinkSpanDrawable;
import org.telegram.ui.Components.spoilers.SpoilerEffect;
import org.telegram.ui.Components.spoilers.SpoilersClickDetector;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class TextViewEffects extends LinkSpanDrawable.LinksTextView {

private final SpoilersClickDetector clickDetector;
private final List<SpoilerEffect> spoilers = new ArrayList<>();
private final Stack<SpoilerEffect> spoilersPool = new Stack<>();
private boolean isSpoilersRevealed;
private final Path path = new Path();
private Paint xRefPaint;

private int emojiOnlyCount;
private AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiDrawables;
private Layout lastLayout = null;
private int lastTextLength;

public TextViewEffects(Context context) {
this(context, null);
}

public TextViewEffects(Context context, Theme.ResourcesProvider resourcesProvider) {
super(context, resourcesProvider);

clickDetector = new SpoilersClickDetector(this, spoilers, (eff, x, y) -> {
if (isSpoilersRevealed) return;

eff.setOnRippleEndCallback(() -> post(() -> {
isSpoilersRevealed = true;
invalidateSpoilers();
}));

float rad = (float) Math.sqrt(Math.pow(getWidth(), 2) + Math.pow(getHeight(), 2));
for (SpoilerEffect ef : spoilers)
ef.startRipple(x, y, rad);
});
}

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (clickDetector.onTouchEvent(event))
return true;
return super.dispatchTouchEvent(event);
}

public void setText(CharSequence text, int emojiOnlyCount) {
this.emojiOnlyCount = emojiOnlyCount;
super.setText(text);
}

@Override
public void setText(CharSequence text, BufferType type) {
isSpoilersRevealed = false;
super.setText(text, type);
}

@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
invalidateSpoilers();
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
invalidateSpoilers();
}

@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();

AnimatedEmojiSpan.release(this, animatedEmojiDrawables);
}

@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
updateAnimatedEmoji(false);
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
updateAnimatedEmoji(false);
}

@Override
protected void onDraw(Canvas canvas) {
int pl = getPaddingLeft(), pt = getPaddingTop();

canvas.save();
path.rewind();
for (SpoilerEffect eff : spoilers) {
Rect bounds = eff.getBounds();
path.addRect(bounds.left + pl, bounds.top + pt, bounds.right + pl, bounds.bottom + pt, Path.Direction.CW);
}
canvas.clipPath(path, Region.Op.DIFFERENCE);
updateAnimatedEmoji(false);
super.onDraw(canvas);
if (animatedEmojiDrawables != null) {
AnimatedEmojiSpan.drawAnimatedEmojis(canvas, getLayout(), animatedEmojiDrawables, 0, spoilers, computeVerticalScrollOffset() - AndroidUtilities.dp(6), computeVerticalScrollOffset() + computeVerticalScrollExtent(), 0, 1f);
}
canvas.restore();

canvas.save();
canvas.clipPath(path);
path.rewind();
if (!spoilers.isEmpty()) {
spoilers.get(0).getRipplePath(path);
}
canvas.clipPath(path);
super.onDraw(canvas);
canvas.restore();

if (!spoilers.isEmpty()) {
boolean useAlphaLayer = spoilers.get(0).getRippleProgress() != -1;
if (useAlphaLayer) {
canvas.saveLayer(0, 0, getMeasuredWidth(), getMeasuredHeight(), null, Canvas.ALL_SAVE_FLAG);
} else {
canvas.save();
}
canvas.translate(getPaddingLeft(), getPaddingTop() + AndroidUtilities.dp(2));
for (SpoilerEffect eff : spoilers) {
eff.setColor(getPaint().getColor());
eff.draw(canvas);
}

if (useAlphaLayer) {
path.rewind();
spoilers.get(0).getRipplePath(path);
if (xRefPaint == null) {
xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
xRefPaint.setColor(0xff000000);
xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
canvas.drawPath(path, xRefPaint);
}
canvas.restore();
}
}

public void updateAnimatedEmoji(boolean force) {
int newTextLength = (getLayout() == null || getLayout().getText() == null) ? 0 : getLayout().getText().length();
if (force || lastLayout != getLayout() || lastTextLength != newTextLength) {
int cacheType = -1;
switch (emojiOnlyCount) {
case 0:
case 1:
case 2:
case 3:
case 4:
cacheType = AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES_LARGE;
break;
case 5:
case 6:
cacheType = AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD;
break;
case 7:
case 8:
case 9:
default:
if (emojiOnlyCount > 9) {
cacheType = AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES;
}
break;
}
animatedEmojiDrawables = AnimatedEmojiSpan.update(cacheType, this, animatedEmojiDrawables, getLayout());
lastLayout = getLayout();
lastTextLength = newTextLength;
}
}

private void invalidateSpoilers() {
if (spoilers == null) return;
spoilersPool.addAll(spoilers);
spoilers.clear();

if (isSpoilersRevealed) {
invalidate();
return;
}

Layout layout = getLayout();
if (layout != null && layout.getText() instanceof Spanned) {
if (animatedEmojiDrawables != null) {
animatedEmojiDrawables.recordPositions(false);
}
SpoilerEffect.addSpoilers(this, spoilersPool, spoilers);
if (animatedEmojiDrawables != null) {
animatedEmojiDrawables.recordPositions(true);
}
}
invalidate();
}
}

0 comments on commit 8b14fd8

Please sign in to comment.