Sponsor heart: rainbow gradient + restore custom emoji status

- Make the shimmering heart a full rainbow spectrum (was single-hue)
- Move heart to rightDrawable2 so the custom emoji status / premium star
  returns to its normal slot next to the name
- Add clickable rightDrawable2 support to SimpleTextView so tapping the
  heart still opens the explanation bulletin
This commit is contained in:
instant992 2026-06-09 09:00:56 +04:00
parent 323c1ff10e
commit 7eeae7fe82
3 changed files with 74 additions and 20 deletions

View file

@ -98,6 +98,8 @@ public class SimpleTextView extends View implements Drawable.Callback {
private int textHeight;
public int rightDrawableX;
public int rightDrawableY;
public int rightDrawable2X;
public int rightDrawable2Y;
private boolean wasLayout;
private boolean leftDrawableOutside, rightDrawableOutside;
@ -128,7 +130,9 @@ public class SimpleTextView extends View implements Drawable.Callback {
private boolean canHideRightDrawable;
private boolean rightDrawableHidden;
private OnClickListener rightDrawableOnClickListener;
private OnClickListener rightDrawable2OnClickListener;
private boolean maybeClick;
private boolean maybeClick2;
private float touchDownX, touchDownY;
private AnimatedEmojiSpan.EmojiGroupedSpans emojiStack;
@ -926,6 +930,8 @@ public class SimpleTextView extends View implements Drawable.Callback {
y = getPaddingTop() + (textHeight - dh) / 2 + rightDrawableTopPadding;
}
rightDrawable2.setBounds(x, y, x + dw, y + dh);
rightDrawable2X = x + (dw >> 1);
rightDrawable2Y = y + (dh >> 1);
rightDrawable2.draw(canvas);
totalWidth += drawablePadding + dw;
}
@ -972,6 +978,8 @@ public class SimpleTextView extends View implements Drawable.Callback {
y = getPaddingTop() + (textHeight - dh) / 2 + rightDrawableTopPadding;
}
rightDrawable2.setBounds(x, y, x + dw, y + dh);
rightDrawable2X = x + (dw >> 1);
rightDrawable2Y = y + (dh >> 1);
rightDrawable2.draw(canvas);
}
}
@ -1067,6 +1075,8 @@ public class SimpleTextView extends View implements Drawable.Callback {
y = getPaddingTop() + (textHeight - dh) / 2 + rightDrawableTopPadding;
}
rightDrawable2.setBounds(x, y, x + dw, y + dh);
rightDrawable2X = x + (dw >> 1);
rightDrawable2Y = y + (dh >> 1);
rightDrawable2.draw(canvas);
totalWidth += drawablePadding + dw;
}
@ -1145,6 +1155,8 @@ public class SimpleTextView extends View implements Drawable.Callback {
y = getPaddingTop() + (textHeight - dh) / 2 + rightDrawableTopPadding;
}
rightDrawable2.setBounds(x, y, x + dw, y + dh);
rightDrawable2X = x + (dw >> 1);
rightDrawable2Y = y + (dh >> 1);
rightDrawable2.draw(canvas);
}
}
@ -1317,6 +1329,10 @@ public class SimpleTextView extends View implements Drawable.Callback {
rightDrawableOnClickListener = onClickListener;
}
public void setRightDrawable2OnClick(OnClickListener onClickListener) {
rightDrawable2OnClickListener = onClickListener;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (rightDrawableOnClickListener != null && rightDrawable != null) {
@ -1348,7 +1364,36 @@ public class SimpleTextView extends View implements Drawable.Callback {
getParent().requestDisallowInterceptTouchEvent(false);
}
}
return super.onTouchEvent(event) || maybeClick;
if (rightDrawable2OnClickListener != null && rightDrawable2 != null) {
AndroidUtilities.rectTmp.set(rightDrawable2X - dp(16), rightDrawable2Y - dp(16), rightDrawable2X + dp(16), rightDrawable2Y + dp(16));
if (event.getAction() == MotionEvent.ACTION_DOWN && AndroidUtilities.rectTmp.contains((int) event.getX(), (int) event.getY())) {
maybeClick2 = true;
touchDownX = event.getX();
touchDownY = event.getY();
getParent().requestDisallowInterceptTouchEvent(true);
if (rightDrawable2 instanceof PressableDrawable) {
((PressableDrawable) rightDrawable2).setPressed(true);
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE && maybeClick2) {
if (Math.abs(event.getX() - touchDownX) >= AndroidUtilities.touchSlop || Math.abs(event.getY() - touchDownY) >= AndroidUtilities.touchSlop) {
maybeClick2 = false;
getParent().requestDisallowInterceptTouchEvent(false);
if (rightDrawable2 instanceof PressableDrawable) {
((PressableDrawable) rightDrawable2).setPressed(false);
}
}
} else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
if (maybeClick2 && event.getAction() == MotionEvent.ACTION_UP) {
rightDrawable2OnClickListener.onClick(this);
if (rightDrawable2 instanceof PressableDrawable) {
((PressableDrawable) rightDrawable2).setPressed(false);
}
}
maybeClick2 = false;
getParent().requestDisallowInterceptTouchEvent(false);
}
}
return super.onTouchEvent(event) || maybeClick || maybeClick2;
}
public static interface PressableDrawable {

View file

@ -11568,15 +11568,15 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
} else if (getMessagesController().isDialogMuted(dialogId != 0 ? dialogId : userId, topicId)) {
nameTextView[a].setRightDrawable2(getThemedDrawable(Theme.key_drawable_muteIconDrawable));
nameTextViewRightDrawable2ContentDescription = LocaleController.getString(R.string.NotificationsMuted);
} else if (user.self && SponsorHelper.isSponsor(user.id)) {
rightIconIsSponsor = true;
nameTextView[a].setRightDrawable2(getFoxSponsorDrawable(a));
nameTextViewRightDrawable2ContentDescription = LocaleController.getString(R.string.FoxSponsorBadge);
} else {
nameTextView[a].setRightDrawable2(null);
nameTextViewRightDrawable2ContentDescription = null;
}
if (user.self && SponsorHelper.isSponsor(user.id)) {
rightIconIsSponsor = true;
nameTextView[a].setRightDrawable(getFoxSponsorDrawable(a));
nameTextViewRightDrawableContentDescription = LocaleController.getString(R.string.FoxSponsorBadge);
} else if (user != null/* && !getMessagesController().premiumFeaturesBlocked()*/ && !MessagesController.isSupportUser(user) && DialogObject.getEmojiStatusDocumentId(user.emoji_status) != 0) {
if (user != null/* && !getMessagesController().premiumFeaturesBlocked()*/ && !MessagesController.isSupportUser(user) && DialogObject.getEmojiStatusDocumentId(user.emoji_status) != 0) {
rightIconIsStatus = true;
rightIconIsPremium = false;
nameTextView[a].setRightDrawable(getEmojiStatusDrawable(user.emoji_status, false, false, a));
@ -11595,13 +11595,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
nameTextView[a].setRightDrawable2(getScamDrawable(user.scam ? 0 : 1));
} else if (user.verified) {
nameTextView[a].setRightDrawable2(getVerifiedCrossfadeDrawable(a));
} else if (user.self && SponsorHelper.isSponsor(user.id)) {
rightIconIsSponsor = true;
nameTextView[a].setRightDrawable2(getFoxSponsorDrawable(a));
} else {
nameTextView[a].setRightDrawable2(null);
}
if (user.self && SponsorHelper.isSponsor(user.id)) {
rightIconIsSponsor = true;
nameTextView[a].setRightDrawable(getFoxSponsorDrawable(a));
} else if (/*!getMessagesController().premiumFeaturesBlocked() && */user != null && !MessagesController.isSupportUser(user) && DialogObject.getEmojiStatusDocumentId(user.emoji_status) != 0) {
if (/*!getMessagesController().premiumFeaturesBlocked() && */user != null && !MessagesController.isSupportUser(user) && DialogObject.getEmojiStatusDocumentId(user.emoji_status) != 0) {
rightIconIsStatus = true;
rightIconIsPremium = false;
nameTextView[a].setRightDrawable(getEmojiStatusDrawable(user.emoji_status, true, true, a));
@ -11624,8 +11624,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
nameTextView[a].setRightDrawableOutside(true);
}
if (rightIconIsSponsor) {
nameTextView[a].setRightDrawableOnClick(v -> showSponsorInfo());
} else if (user.self && getMessagesController().isPremiumUser(user)) {
nameTextView[a].setRightDrawable2OnClick(v -> showSponsorInfo());
} else {
nameTextView[a].setRightDrawable2OnClick(null);
}
if (user.self && getMessagesController().isPremiumUser(user)) {
nameTextView[a].setRightDrawableOnClick(v -> {
showStatusSelect();
});

View file

@ -31,14 +31,18 @@ public class ShimmerHeartDrawable extends Drawable {
private int lastWidth = -1;
private int gradientWidth;
// Iridescent palette swept across the heart.
// Full rainbow spectrum swept across the heart (seamless loop).
private static final int[] COLORS = new int[] {
0xFFFF4D6D, // pink-red
0xFFFF8FA3, // light pink
0xFFFFC2D1, // pale
0xFFFF5C8A, // magenta
0xFFFF1E56, // deep red
0xFFFF4D6D, // back to start (seamless loop)
0xFFFF3B30, // red
0xFFFF9500, // orange
0xFFFFCC00, // yellow
0xFF34C759, // green
0xFF00C7BE, // teal
0xFF007AFF, // blue
0xFF5856D6, // indigo
0xFFAF52DE, // violet
0xFFFF2D55, // pink
0xFFFF3B30, // back to red (seamless loop)
};
private static final long CYCLE_MS = 2200L;
@ -54,7 +58,9 @@ public class ShimmerHeartDrawable extends Drawable {
}
private void buildGradient(int width) {
gradientWidth = width * 2;
// Span the whole rainbow across roughly the heart width so multiple
// colors are visible at once, then sweep it for the shimmer.
gradientWidth = Math.max(1, width);
gradient = new LinearGradient(0, 0, gradientWidth, 0, COLORS, null, Shader.TileMode.MIRROR);
paint.setShader(gradient);
lastWidth = width;