That fuck shit the fascists are using
at master 145 lines 5.3 kB view raw
1package org.tm.archive.components; 2 3import android.graphics.Canvas; 4import android.graphics.ColorFilter; 5import android.graphics.LinearGradient; 6import android.graphics.Paint; 7import android.graphics.PixelFormat; 8import android.graphics.Point; 9import android.graphics.Rect; 10import android.graphics.Shader; 11import android.graphics.Xfermode; 12import android.graphics.drawable.Drawable; 13 14import androidx.annotation.NonNull; 15import androidx.annotation.Nullable; 16 17import java.util.Arrays; 18 19import kotlin.jvm.functions.Function2; 20 21/** 22 * Drawable which renders a gradient at a specified angle. Note that this drawable does 23 * not implement drawable state, and all the baggage that comes with a normal Drawable 24 * override, so this may not work in every scenario. 25 * 26 * Essentially, this drawable creates a LinearGradient shader using the given colors and 27 * positions, but makes it larger than the bounds, such that it can be rotated and still 28 * fill the bounds with a gradient. 29 * 30 * If you wish to apply clipping to this drawable, it is recommended to either use it with 31 * a MaterialCardView or utilize {@link org.tm.archive.util.CustomDrawWrapperKt#customizeOnDraw(Drawable, Function2)} 32 */ 33public final class RotatableGradientDrawable extends Drawable { 34 35 /** 36 * From investigation into how Gradients are rendered vs how they are rendered in 37 * designs, in order to match spec, we need to rotate gradients by 225 degrees. (180 + 45) 38 * 39 * This puts 0 at the bottom (0, -1) of the surface area. 40 */ 41 private static final float DEGREE_OFFSET = 225f; 42 43 private final float degrees; 44 private final int[] colors; 45 private final float[] positions; 46 47 private final Rect fillRect = new Rect(); 48 private final Paint fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); 49 50 /** 51 * @param degrees Gradient rotation in degrees, relative to a vector pointed from the center to bottom center 52 * @param colors The colors of the gradient 53 * @param positions The positions of the colors. Values should be between 0f and 1f and this array should be the 54 * same length as colors. 55 */ 56 public RotatableGradientDrawable(float degrees, int[] colors, @Nullable float[] positions) { 57 this.degrees = degrees + DEGREE_OFFSET; 58 this.colors = colors; 59 this.positions = positions; 60 } 61 62 @Override 63 public void setBounds(int left, int top, int right, int bottom) { 64 super.setBounds(left, top, right, bottom); 65 66 Point topLeft = new Point(left, top); 67 Point topRight = new Point(right, top); 68 Point bottomLeft = new Point(left, bottom); 69 Point bottomRight = new Point(right, bottom); 70 Point origin = new Point(getBounds().width() / 2, getBounds().height() / 2); 71 72 Point rotationTopLeft = cornerPrime(origin, topLeft, degrees); 73 Point rotationTopRight = cornerPrime(origin, topRight, degrees); 74 Point rotationBottomLeft = cornerPrime(origin, bottomLeft, degrees); 75 Point rotationBottomRight = cornerPrime(origin, bottomRight, degrees); 76 77 fillRect.left = Integer.MAX_VALUE; 78 fillRect.top = Integer.MAX_VALUE; 79 fillRect.right = Integer.MIN_VALUE; 80 fillRect.bottom = Integer.MIN_VALUE; 81 82 for (Point point : Arrays.asList(topLeft, topRight, bottomLeft, bottomRight, rotationTopLeft, rotationTopRight, rotationBottomLeft, rotationBottomRight)) { 83 if (point.x < fillRect.left) { 84 fillRect.left = point.x; 85 } 86 87 if (point.x > fillRect.right) { 88 fillRect.right = point.x; 89 } 90 91 if (point.y < fillRect.top) { 92 fillRect.top = point.y; 93 } 94 95 if (point.y > fillRect.bottom) { 96 fillRect.bottom = point.y; 97 } 98 } 99 100 fillPaint.setShader(new LinearGradient(fillRect.left, fillRect.top, fillRect.right, fillRect.bottom, colors, positions, Shader.TileMode.CLAMP)); 101 } 102 103 public void setXfermode(@NonNull Xfermode xfermode) { 104 fillPaint.setXfermode(xfermode); 105 } 106 107 private static Point cornerPrime(@NonNull Point origin, @NonNull Point corner, float degrees) { 108 return new Point(xPrime(origin, corner, Math.toRadians(degrees)), yPrime(origin, corner, Math.toRadians(degrees))); 109 } 110 111 private static int xPrime(@NonNull Point origin, @NonNull Point corner, double theta) { 112 return (int) Math.ceil(((corner.x - origin.x) * Math.cos(theta)) - ((corner.y - origin.y) * Math.sin(theta)) + origin.x); 113 } 114 115 private static int yPrime(@NonNull Point origin, @NonNull Point corner, double theta) { 116 return (int) Math.ceil(((corner.x - origin.x) * Math.sin(theta)) + ((corner.y - origin.y) * Math.cos(theta)) + origin.y); 117 } 118 119 @Override 120 public void draw(Canvas canvas) { 121 int save = canvas.save(); 122 canvas.rotate(degrees, getBounds().width() / 2f, getBounds().height() / 2f); 123 124 int height = fillRect.height(); 125 int width = fillRect.width(); 126 canvas.drawRect(fillRect.left - width, fillRect.top - height, fillRect.right + width, fillRect.bottom + height, fillPaint); 127 128 canvas.restoreToCount(save); 129 } 130 131 @Override 132 public void setAlpha(int alpha) { 133 // Not supported 134 } 135 136 @Override 137 public void setColorFilter(@Nullable ColorFilter colorFilter) { 138 // Not supported 139 } 140 141 @Override 142 public int getOpacity() { 143 return PixelFormat.OPAQUE; 144 } 145}