From e2f2ceb26dd3da66a276fac43a030af2f766e592 Mon Sep 17 00:00:00 2001 From: instant992 Date: Tue, 9 Jun 2026 12:59:35 +0400 Subject: [PATCH] Sponsor heart: airbrushed multicolor blend matching sponsor.png Replace the hard gloss streak with soft overlapping color blobs (violet top-left, blue center, orange/coral right and bottom) that drift slightly for a subtle shimmer, matching the GhostCloud sponsor.png reference. --- .../helpers/ShimmerHeartDrawable.java | 134 +++++++----------- 1 file changed, 49 insertions(+), 85 deletions(-) diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/ShimmerHeartDrawable.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/ShimmerHeartDrawable.java index 73a93b7b..b70cbc69 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/ShimmerHeartDrawable.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/ShimmerHeartDrawable.java @@ -1,9 +1,7 @@ package tw.nekomimi.nekogram.helpers; -import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.ColorFilter; -import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; @@ -17,9 +15,10 @@ import androidx.annotation.NonNull; import org.telegram.messenger.AndroidUtilities; /** - * A glossy 3D-looking heart badge with a soft multicolor gradient (purple → - * blue → orange) and a thin curved glossy streak ("blik") that slowly sweeps - * diagonally across it, like light reflecting off a shiny sticker. + * A soft, airbrushed 3D heart badge matching the GhostCloud "sponsor.png": + * violet in the upper-left, blue through the centre, warm orange/coral on the + * right and bottom, all blended smoothly with a gentle glossy highlight. The + * colour blobs drift slightly so the badge subtly shimmers. * * It self-invalidates each frame, so when attached to a view via * {@code setRightDrawable(...)} / {@code setRightDrawable2(...)} the host keeps @@ -29,17 +28,14 @@ import org.telegram.messenger.AndroidUtilities; public class ShimmerHeartDrawable extends Drawable { private final Paint basePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Paint tintPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Paint shadePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Paint glossDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Paint streakPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint blobPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint highlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Path heart = new Path(); - private final Path streak = new Path(); private int lastWidth = -1; private int lastHeight = -1; - private static final long CYCLE_MS = 3600L; + private static final long CYCLE_MS = 5200L; private final int size; public ShimmerHeartDrawable() { @@ -49,11 +45,8 @@ public class ShimmerHeartDrawable extends Drawable { public ShimmerHeartDrawable(int sizePx) { this.size = sizePx; basePaint.setStyle(Paint.Style.FILL); - tintPaint.setStyle(Paint.Style.FILL); - shadePaint.setStyle(Paint.Style.FILL); - glossDotPaint.setStyle(Paint.Style.FILL); - streakPaint.setStyle(Paint.Style.STROKE); - streakPaint.setStrokeCap(Paint.Cap.ROUND); + blobPaint.setStyle(Paint.Style.FILL); + highlightPaint.setStyle(Paint.Style.FILL); } private void buildHeart(Rect b) { @@ -71,50 +64,22 @@ public class ShimmerHeartDrawable extends Drawable { heart.close(); } - private void buildShaders(Rect b) { - float w = b.width(); - float h = b.height(); - float l = b.left; - float t = b.top; - - // Base diagonal gradient matching the reference: violet (top-left) → - // blue → cyan → warm orange (bottom-right). - basePaint.setShader(new LinearGradient( - l + w * 0.15f, t, l + w * 0.9f, t + h, - new int[]{0xFF8E2DE2, 0xFF5B5BFF, 0xFF2F9BFF, 0xFFFFB24D, 0xFFFF8A3D}, - new float[]{0f, 0.30f, 0.55f, 0.85f, 1f}, + /** A soft circular blob of one colour fading to transparent. */ + private void drawBlob(Canvas canvas, float cx, float cy, float r, int color) { + blobPaint.setShader(new RadialGradient( + cx, cy, Math.max(1f, r), + new int[]{color, color & 0x00FFFFFF}, + new float[]{0f, 1f}, Shader.TileMode.CLAMP)); - - // Soft violet glow on the upper-left lobe for depth. - tintPaint.setShader(new RadialGradient( - l + w * 0.32f, t + h * 0.28f, w * 0.6f, - new int[]{0x999B30FF, 0x00000000}, - null, Shader.TileMode.CLAMP)); - - // Inner shade at the bottom tip for a rounded 3D feel. - shadePaint.setShader(new RadialGradient( - l + w * 0.55f, t + h * 0.92f, w * 0.55f, - new int[]{0x55401E7A, 0x00000000}, - null, Shader.TileMode.CLAMP)); - - // Fixed small specular dot, top-left (glossy sticker look). - glossDotPaint.setShader(new RadialGradient( - l + w * 0.33f, t + h * 0.27f, w * 0.16f, - new int[]{0xE6FFFFFF, 0x00FFFFFF}, - null, Shader.TileMode.CLAMP)); - - streakPaint.setStrokeWidth(Math.max(1f, w * 0.10f)); - streakPaint.setMaskFilter(new BlurMaskFilter(Math.max(1f, w * 0.06f), BlurMaskFilter.Blur.NORMAL)); - - lastWidth = b.width(); - lastHeight = b.height(); + canvas.drawRect(getBounds(), blobPaint); } @Override protected void onBoundsChange(@NonNull Rect bounds) { super.onBoundsChange(bounds); buildHeart(bounds); - buildShaders(bounds); + lastWidth = bounds.width(); + lastHeight = bounds.height(); } @Override @@ -125,7 +90,8 @@ public class ShimmerHeartDrawable extends Drawable { } if (lastWidth != b.width() || lastHeight != b.height()) { buildHeart(b); - buildShaders(b); + lastWidth = b.width(); + lastHeight = b.height(); } float w = b.width(); @@ -133,43 +99,41 @@ public class ShimmerHeartDrawable extends Drawable { float l = b.left; float t = b.top; + // Subtle drift so the colours softly shimmer. + float phase = (System.currentTimeMillis() % CYCLE_MS) / (float) CYCLE_MS; + double a = phase * 2 * Math.PI; + float dx = (float) Math.cos(a) * w * 0.05f; + float dy = (float) Math.sin(a) * h * 0.05f; + int save = canvas.save(); canvas.clipPath(heart); - // Base colors + violet glow + bottom shade. - canvas.drawPath(heart, basePaint); - canvas.drawPath(heart, tintPaint); - canvas.drawPath(heart, shadePaint); + // Light lavender base so blends stay airy. + basePaint.setShader(null); + basePaint.setColor(0xFFB9A8F0); + canvas.drawRect(b, basePaint); - // Moving curved glossy streak sweeping diagonally across the heart. - float phase = (System.currentTimeMillis() % CYCLE_MS) / (float) CYCLE_MS; - // travel from top-left (off-screen) to bottom-right (off-screen) - float p = -0.4f + phase * 1.8f; - float dx = w * p; // horizontal offset of the streak - streak.reset(); - // A gently curved (bowed) vertical-ish line, slanted diagonally. - float x0 = l + dx + w * 0.10f; - float y0 = t - h * 0.10f; - float xc = l + dx + w * 0.45f; - float yc = t + h * 0.50f; - float x1 = l + dx + w * 0.30f; - float y1 = t + h * 1.10f; - streak.moveTo(x0, y0); - streak.quadTo(xc, yc, x1, y1); + // Soft overlapping colour blobs (airbrushed look). + // Violet — upper-left. + drawBlob(canvas, l + w * (0.30f) + dx, t + h * (0.28f) + dy, w * 0.62f, 0xFF7A2FE0); + // Blue — centre-left. + drawBlob(canvas, l + w * (0.40f) - dx, t + h * (0.55f) + dy, w * 0.55f, 0xFF4F6BFF); + // Cyan/blue glow — centre. + drawBlob(canvas, l + w * (0.52f) + dy, t + h * (0.45f) - dx, w * 0.42f, 0xCC59B7FF); + // Warm orange — right. + drawBlob(canvas, l + w * (0.82f) - dx, t + h * (0.40f) - dy, w * 0.60f, 0xFFFF9A3D); + // Coral/pink — bottom-right. + drawBlob(canvas, l + w * (0.70f) + dx, t + h * (0.80f) + dy, w * 0.55f, 0xFFFF7E5A); + // Deep violet — bottom-left corner for contrast. + drawBlob(canvas, l + w * (0.22f) + dx, t + h * (0.82f) - dy, w * 0.45f, 0xCC6A2BC8); - // Fade the streak in/out at the edges of the sweep. - float edge = Math.min(1f, Math.min(phase, 1f - phase) * 3f); - int alpha = (int) (200 * Math.max(0f, edge)); - int whiteCore = (alpha << 24) | 0x00FFFFFF; - streakPaint.setShader(new LinearGradient( - x0, y0, x1, y1, - new int[]{0x00FFFFFF, whiteCore, 0x00FFFFFF}, - new float[]{0f, 0.5f, 1f}, + // Gentle glossy highlight, upper-centre. + highlightPaint.setShader(new RadialGradient( + l + w * 0.45f + dx, t + h * 0.30f + dy, w * 0.40f, + new int[]{0x80FFFFFF, 0x00FFFFFF}, + new float[]{0f, 1f}, Shader.TileMode.CLAMP)); - canvas.drawPath(streak, streakPaint); - - // Fixed specular dot. - canvas.drawPath(heart, glossDotPaint); + canvas.drawRect(b, highlightPaint); canvas.restoreToCount(save);