That fuck shit the fascists are using
at master 223 lines 6.6 kB view raw
1package org.tm.archive.components; 2 3import android.content.Context; 4import android.content.res.TypedArray; 5import android.graphics.Color; 6import android.graphics.PorterDuff; 7import android.os.Bundle; 8import android.os.Parcelable; 9import android.util.AttributeSet; 10import android.view.View; 11import android.view.animation.Animation; 12import android.view.animation.LinearInterpolator; 13import android.view.animation.RotateAnimation; 14 15import androidx.annotation.Nullable; 16import androidx.annotation.StringRes; 17import androidx.appcompat.widget.AppCompatImageView; 18 19import org.signal.core.util.DimensionUnit; 20import org.tm.archive.R; 21import org.tm.archive.util.ViewUtil; 22 23/** 24 * View responsible for displaying the delivery status (NONE, PENDING, SENT, DELIVERED, READ) of a given outgoing message. 25 * <p> 26 * This view manipulates its start / end padding to properly place the corresponding icon, and also performs a rotation 27 * animation on itself in the pending mode. Thus, users should be aware that padding values set in XML will be overwritten. 28 * <p> 29 * If you need to control the horizontal spacing of this view, utilize margins instead. 30 */ 31public class DeliveryStatusView extends AppCompatImageView { 32 33 private static final String STATE_KEY = "DeliveryStatusView.STATE"; 34 private static final String ROOT_KEY = "DeliveryStatusView.ROOT"; 35 36 private final int horizontalPadding = (int) DimensionUnit.DP.toPixels(2); 37 38 private RotateAnimation rotationAnimation; 39 40 private State state = State.NONE; 41 42 public DeliveryStatusView(Context context) { 43 this(context, null); 44 } 45 46 public DeliveryStatusView(Context context, AttributeSet attrs) { 47 this(context, attrs, 0); 48 } 49 50 public DeliveryStatusView(final Context context, AttributeSet attrs, int defStyle) { 51 super(context, attrs, defStyle); 52 53 if (attrs != null) { 54 TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DeliveryStatusView, 0, 0); 55 setTint(typedArray.getColor(R.styleable.DeliveryStatusView_iconColor, getResources().getColor(R.color.core_white))); 56 typedArray.recycle(); 57 } 58 59 setNone(); 60 } 61 62 @Override 63 protected void onRestoreInstanceState(Parcelable state) { 64 if (state instanceof Bundle) { 65 Bundle stateBundle = (Bundle) state; 66 State s = State.fromCode(stateBundle.getInt(STATE_KEY, State.NONE.code)); 67 68 switch (s) { 69 case NONE: 70 setNone(); 71 break; 72 case PENDING: 73 setPending(); 74 break; 75 case SENT: 76 setSent(); 77 break; 78 case DELIVERED: 79 setDelivered(); 80 break; 81 case READ: 82 setRead(); 83 break; 84 } 85 86 Parcelable root = stateBundle.getParcelable(ROOT_KEY); 87 super.onRestoreInstanceState(root); 88 } else { 89 super.onRestoreInstanceState(state); 90 } 91 } 92 93 @Override 94 protected @Nullable Parcelable onSaveInstanceState() { 95 Parcelable root = super.onSaveInstanceState(); 96 Bundle stateBundle = new Bundle(); 97 98 stateBundle.putParcelable(ROOT_KEY, root); 99 stateBundle.putInt(STATE_KEY, state.code); 100 101 return stateBundle; 102 } 103 104 @Override 105 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 106 if (state == State.PENDING && rotationAnimation == null) { 107 final float pivotXValue; 108 if (ViewUtil.isLtr(this)) { 109 pivotXValue = (w - getPaddingEnd()) / 2f; 110 } else { 111 pivotXValue = ((w - getPaddingEnd()) / 2f) + getPaddingEnd(); 112 } 113 114 final float pivotYValue = (h - getPaddingTop() - getPaddingBottom()) / 2f; 115 116 rotationAnimation = new RotateAnimation(0, 360f, 117 Animation.ABSOLUTE, pivotXValue, 118 Animation.ABSOLUTE, pivotYValue); 119 120 rotationAnimation.setInterpolator(new LinearInterpolator()); 121 rotationAnimation.setDuration(1500); 122 rotationAnimation.setRepeatCount(Animation.INFINITE); 123 124 startAnimation(rotationAnimation); 125 } 126 } 127 128 @Override 129 public void clearAnimation() { 130 super.clearAnimation(); 131 rotationAnimation = null; 132 } 133 134 public void setNone() { 135 state = State.NONE; 136 clearAnimation(); 137 setVisibility(View.GONE); 138 updateContentDescription(); 139 } 140 141 public boolean isPending() { 142 return state == State.PENDING; 143 } 144 145 public void setPending() { 146 state = State.PENDING; 147 setVisibility(View.VISIBLE); 148 ViewUtil.setPaddingStart(this, 0); 149 ViewUtil.setPaddingEnd(this, horizontalPadding); 150 setImageResource(R.drawable.symbol_messagestatus_sending_24); 151 updateContentDescription(); 152 } 153 154 public void setSent() { 155 state = State.SENT; 156 setVisibility(View.VISIBLE); 157 ViewUtil.setPaddingStart(this, horizontalPadding); 158 ViewUtil.setPaddingEnd(this, 0); 159 clearAnimation(); 160 setImageResource(R.drawable.symbol_messagestatus_sent_24); 161 updateContentDescription(); 162 } 163 164 public void setDelivered() { 165 state = State.DELIVERED; 166 setVisibility(View.VISIBLE); 167 ViewUtil.setPaddingStart(this, horizontalPadding); 168 ViewUtil.setPaddingEnd(this, 0); 169 clearAnimation(); 170 setImageResource(R.drawable.symbol_messagestatus_delivered_24); 171 updateContentDescription(); 172 } 173 174 public void setRead() { 175 state = State.READ; 176 setVisibility(View.VISIBLE); 177 ViewUtil.setPaddingStart(this, horizontalPadding); 178 ViewUtil.setPaddingEnd(this, 0); 179 clearAnimation(); 180 setImageResource(R.drawable.symbol_messagestatus_read_24); 181 updateContentDescription(); 182 } 183 184 public void setTint(int color) { 185 setColorFilter(color, PorterDuff.Mode.SRC_IN); 186 } 187 188 private void updateContentDescription() { 189 if (state.contentDescription == -1) { 190 setContentDescription(null); 191 } else { 192 setContentDescription(getContext().getString(state.contentDescription)); 193 } 194 } 195 196 private enum State { 197 NONE(0, -1), 198 PENDING(1, R.string.message_details_recipient_header__pending_send), 199 SENT(2, R.string.message_details_header_sent), 200 DELIVERED(3, R.string.conversation_item_sent__delivered_description), 201 READ(4, R.string.conversation_item_sent__message_read); 202 203 final int code; 204 205 @StringRes 206 final int contentDescription; 207 208 State(int code, @StringRes int contentDescription) { 209 this.code = code; 210 this.contentDescription = contentDescription; 211 } 212 213 static State fromCode(int code) { 214 for (State state : State.values()) { 215 if (state.code == code) { 216 return state; 217 } 218 } 219 220 return NONE; 221 } 222 } 223}