From 7386d2d76a7964b8c8e779651d58f2ed6c4c522f Mon Sep 17 00:00:00 2001
From: NekoInverter <42698724+NekoInverter@users.noreply.github.com>
Date: Sat, 21 Nov 2020 17:48:59 +0800
Subject: [PATCH] Update CheckTextView
---
app/build.gradle | 1 -
.../hippo/ehviewer/widget/CategoryTable.java | 22 +-
.../java/com/hippo/widget/CheckTextView.java | 323 ++++++++++--------
.../drawable/check_text_view_foreground.xml | 13 +
app/src/main/res/values-night/colors.xml | 2 +-
app/src/main/res/values/attrs.xml | 4 +-
app/src/main/res/values/colors.xml | 2 +-
app/src/main/res/values/styles.xml | 2 +-
8 files changed, 205 insertions(+), 164 deletions(-)
create mode 100644 app/src/main/res/drawable/check_text_view_foreground.xml
diff --git a/app/build.gradle b/app/build.gradle
index e28121832..d2c8c1673 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -93,7 +93,6 @@ dependencies {
implementation 'com.github.seven332:glgallery:0.1.2'
implementation 'com.github.seven332:glview:0.1.0'
implementation 'com.github.seven332:glview-image:0.1.0'
- implementation 'com.github.seven332:hotspot:0.1.0'
implementation 'com.github.seven332:streampipe:0.1.0'
implementation 'com.github.seven332:tuxiang:0.1.6'
implementation 'com.github.seven332:unifile:9ec57bcd8f'
diff --git a/app/src/main/java/com/hippo/ehviewer/widget/CategoryTable.java b/app/src/main/java/com/hippo/ehviewer/widget/CategoryTable.java
index b4a1cfbc9..8fa21ad55 100644
--- a/app/src/main/java/com/hippo/ehviewer/widget/CategoryTable.java
+++ b/app/src/main/java/com/hippo/ehviewer/widget/CategoryTable.java
@@ -98,7 +98,7 @@ public class CategoryTable extends TableLayout implements View.OnLongClickListen
boolean checked = ((CheckTextView) v).isChecked();
for (CheckTextView option : mOptions) {
if (option != v) {
- option.setChecked(!checked, false);
+ option.setChecked(!checked);
}
}
}
@@ -132,16 +132,16 @@ public class CategoryTable extends TableLayout implements View.OnLongClickListen
* @param category target category
*/
public void setCategory(int category) {
- mDoujinshi.setChecked(!NumberUtils.int2boolean(category & EhConfig.DOUJINSHI), false);
- mManga.setChecked(!NumberUtils.int2boolean(category & EhConfig.MANGA), false);
- mArtistCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.ARTIST_CG), false);
- mGameCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.GAME_CG), false);
- mWestern.setChecked(!NumberUtils.int2boolean(category & EhConfig.WESTERN), false);
- mNonH.setChecked(!NumberUtils.int2boolean(category & EhConfig.NON_H), false);
- mImageSets.setChecked(!NumberUtils.int2boolean(category & EhConfig.IMAGE_SET), false);
- mCosplay.setChecked(!NumberUtils.int2boolean(category & EhConfig.COSPLAY), false);
- mAsianPorn.setChecked(!NumberUtils.int2boolean(category & EhConfig.ASIAN_PORN), false);
- mMisc.setChecked(!NumberUtils.int2boolean(category & EhConfig.MISC), false);
+ mDoujinshi.setChecked(!NumberUtils.int2boolean(category & EhConfig.DOUJINSHI));
+ mManga.setChecked(!NumberUtils.int2boolean(category & EhConfig.MANGA));
+ mArtistCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.ARTIST_CG));
+ mGameCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.GAME_CG));
+ mWestern.setChecked(!NumberUtils.int2boolean(category & EhConfig.WESTERN));
+ mNonH.setChecked(!NumberUtils.int2boolean(category & EhConfig.NON_H));
+ mImageSets.setChecked(!NumberUtils.int2boolean(category & EhConfig.IMAGE_SET));
+ mCosplay.setChecked(!NumberUtils.int2boolean(category & EhConfig.COSPLAY));
+ mAsianPorn.setChecked(!NumberUtils.int2boolean(category & EhConfig.ASIAN_PORN));
+ mMisc.setChecked(!NumberUtils.int2boolean(category & EhConfig.MISC));
}
@Override
diff --git a/app/src/main/java/com/hippo/widget/CheckTextView.java b/app/src/main/java/com/hippo/widget/CheckTextView.java
index 72a807efb..3cfa258df 100644
--- a/app/src/main/java/com/hippo/widget/CheckTextView.java
+++ b/app/src/main/java/com/hippo/widget/CheckTextView.java
@@ -16,199 +16,226 @@
package com.hippo.widget;
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.os.Bundle;
-import android.os.Parcelable;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.util.AttributeSet;
+import android.view.Gravity;
import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
-import androidx.appcompat.widget.AppCompatTextView;
+import androidx.appcompat.widget.AppCompatCheckedTextView;
import com.hippo.ehviewer.R;
-import com.hippo.hotspot.Hotspotable;
-import com.hippo.yorozuya.AnimationUtils;
-import com.hippo.yorozuya.MathUtils;
-import com.hippo.yorozuya.SimpleAnimatorListener;
-public class CheckTextView extends AppCompatTextView implements OnClickListener, Hotspotable {
+public class CheckTextView extends AppCompatCheckedTextView implements View.OnClickListener {
- private static final String STATE_KEY_SUPER = "super";
- private static final String STATE_KEY_CHECKED = "checked";
+ private Drawable mForeground;
- private static final long ANIMATION_DURATION = 200;
- Animator mAnimator;
- private final Animator.AnimatorListener mAnimatorListener = new SimpleAnimatorListener() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimator = null;
- }
- };
- private int mMaskColor;
- private boolean mChecked = false;
- private boolean mPrepareAnimator = false;
- private Paint mPaint;
- private float mRadius = 0f;
- private float mX;
- private float mY;
- private float mMaxRadius;
+ private final Rect mSelfBounds = new Rect();
+
+ private final Rect mOverlayBounds = new Rect();
+
+ private int mForegroundGravity = Gravity.FILL;
+
+ protected boolean mForegroundInPadding = true;
+
+ boolean mForegroundBoundsChanged = false;
+
+ public CheckTextView(Context context) {
+ this(context, null);
+ }
public CheckTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs);
+ this(context, attrs, 0);
}
- public CheckTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init(context, attrs);
+ public CheckTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ init(context, attrs, defStyleAttr);
}
- private void init(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckTextView);
- mMaskColor = a.getColor(R.styleable.CheckTextView_maskColor, Color.WHITE);
+ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckTextView,
+ defStyleAttr, 0);
+
+ mForegroundGravity = a.getInt(
+ R.styleable.CheckTextView_android_foregroundGravity, mForegroundGravity);
+
+ Drawable d = a.getDrawable(R.styleable.CheckTextView_android_foreground);
+ if (d != null) {
+ setForeground(d);
+ }
+
+ mForegroundInPadding = a.getBoolean(
+ R.styleable.CheckTextView_foregroundInsidePadding, true);
+
a.recycle();
-
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
- mPaint.setColor(mMaskColor);
-
setOnClickListener(this);
}
- @Override
- public void setHotspot(float x, float y) {
- mX = x;
- mY = y;
- mMaxRadius = MathUtils.coverageRadius(getWidth(), getHeight(), x, y);
+ /**
+ * Describes how the foreground is positioned.
+ *
+ * @return foreground gravity.
+ * @see #setForegroundGravity(int)
+ */
+ public int getForegroundGravity() {
+ return mForegroundGravity;
}
- @Override
- public void drawableHotspotChanged(float x, float y) {
- super.drawableHotspotChanged(x, y);
-
- mX = x;
- mY = y;
- mMaxRadius = MathUtils.coverageRadius(getWidth(), getHeight(), x, y);
- }
-
- public float getRadius() {
- return mRadius;
- }
-
- public void setRadius(float radius) {
- float bigger = Math.max(mRadius, radius);
- mRadius = radius;
- invalidate((int) (mX - bigger), (int) (mY - bigger), (int) (mX + bigger), (int) (mY + bigger));
- }
-
- public void prepareAnimations() {
- mPrepareAnimator = true;
- }
-
- private void createAnimations() {
- float startRadius;
- float endRadius;
- Interpolator interpolator;
- if (mChecked) {
- startRadius = 0;
- endRadius = mMaxRadius;
- interpolator = AnimationUtils.FAST_SLOW_INTERPOLATOR;
- } else {
- startRadius = mMaxRadius;
- endRadius = 0;
- interpolator = AnimationUtils.SLOW_FAST_INTERPOLATOR;
- }
- mRadius = startRadius;
-
- final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radius", startRadius, endRadius);
- radiusAnim.setDuration(ANIMATION_DURATION);
- radiusAnim.setInterpolator(interpolator);
- radiusAnim.addListener(mAnimatorListener);
- radiusAnim.start();
- mAnimator = radiusAnim;
- }
-
- private void cancelAnimations() {
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- }
-
- @Override
- public void onClick(View v) {
- setChecked(!mChecked);
- }
-
- @Override
- protected void onDraw(@NonNull Canvas canvas) {
- super.onDraw(canvas);
-
- if (mPrepareAnimator) {
- mPrepareAnimator = false;
- cancelAnimations();
- createAnimations();
- }
-
- if (mAnimator != null) {
- canvas.drawCircle(mX, mY, mRadius, mPaint);
- } else {
- if (mChecked) {
- canvas.drawColor(mMaskColor);
+ /**
+ * Describes how the foreground is positioned. Defaults to START and TOP.
+ *
+ * @param foregroundGravity See {@link android.view.Gravity}
+ * @see #getForegroundGravity()
+ */
+ public void setForegroundGravity(int foregroundGravity) {
+ if (mForegroundGravity != foregroundGravity) {
+ if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
+ foregroundGravity |= Gravity.START;
}
+
+ if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
+ foregroundGravity |= Gravity.TOP;
+ }
+
+ mForegroundGravity = foregroundGravity;
+
+ if (mForegroundGravity == Gravity.FILL && mForeground != null) {
+ Rect padding = new Rect();
+ mForeground.getPadding(padding);
+ }
+
+ requestLayout();
+ }
+ }
+
+ @Override
+ protected boolean verifyDrawable(@NonNull Drawable who) {
+ return super.verifyDrawable(who) || (who == mForeground);
+ }
+
+ @Override
+ public void jumpDrawablesToCurrentState() {
+ super.jumpDrawablesToCurrentState();
+ if (mForeground != null) {
+ mForeground.jumpToCurrentState();
+ }
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ if (mForeground != null && mForeground.isStateful()) {
+ mForeground.setState(getDrawableState());
}
}
/**
- * Changes the checked state of this CheckTextView.
+ * Supply a Drawable that is to be rendered on top of all of the child
+ * views in the frame layout. Any padding in the Drawable will be taken
+ * into account by ensuring that the children are inset to be placed
+ * inside of the padding area.
*
- * @param checked checked true to check the CheckTextView, false to uncheck it
- * @param animation true for show animation
+ * @param drawable The Drawable to be drawn on top of the children.
*/
- public void setChecked(boolean checked, boolean animation) {
- if (mChecked != checked) {
- mChecked = checked;
-
- if (animation) {
- prepareAnimations();
+ public void setForeground(Drawable drawable) {
+ if (mForeground != drawable) {
+ if (mForeground != null) {
+ mForeground.setCallback(null);
+ unscheduleDrawable(mForeground);
}
+
+ mForeground = drawable;
+
+ if (drawable != null) {
+ setWillNotDraw(false);
+ drawable.setCallback(this);
+ if (drawable.isStateful()) {
+ drawable.setState(getDrawableState());
+ }
+ if (mForegroundGravity == Gravity.FILL) {
+ Rect padding = new Rect();
+ drawable.getPadding(padding);
+ }
+ } else {
+ setWillNotDraw(true);
+ }
+ requestLayout();
invalidate();
}
}
/**
- * Get the checked state of it.
+ * Returns the drawable used as the foreground of this FrameLayout. The
+ * foreground drawable, if non-null, is always drawn on top of the children.
*
- * @return true is it is checked
+ * @return A Drawable or null if no foreground was set.
*/
- public boolean isChecked() {
- return mChecked;
- }
-
- public void setChecked(boolean checked) {
- setChecked(checked, true);
+ public Drawable getForeground() {
+ return mForeground;
}
@Override
- public Parcelable onSaveInstanceState() {
- final Bundle state = new Bundle();
- state.putParcelable(STATE_KEY_SUPER, super.onSaveInstanceState());
- state.putBoolean(STATE_KEY_CHECKED, mChecked);
- return state;
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ mForegroundBoundsChanged |= changed;
}
@Override
- public void onRestoreInstanceState(Parcelable state) {
- if (state instanceof Bundle) {
- final Bundle savedState = (Bundle) state;
- super.onRestoreInstanceState(savedState.getParcelable(STATE_KEY_SUPER));
- setChecked(savedState.getBoolean(STATE_KEY_CHECKED), false);
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ mForegroundBoundsChanged = true;
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ super.draw(canvas);
+
+ if (mForeground != null) {
+ final Drawable foreground = mForeground;
+
+ if (mForegroundBoundsChanged) {
+ mForegroundBoundsChanged = false;
+ final Rect selfBounds = mSelfBounds;
+ final Rect overlayBounds = mOverlayBounds;
+
+ final int w = getRight() - getLeft();
+ final int h = getBottom() - getTop();
+
+ if (mForegroundInPadding) {
+ selfBounds.set(0, 0, w, h);
+ } else {
+ selfBounds.set(getPaddingLeft(), getPaddingTop(),
+ w - getPaddingRight(), h - getPaddingBottom());
+ }
+
+ Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
+ foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
+ foreground.setBounds(overlayBounds);
+ }
+
+ foreground.draw(canvas);
}
}
+
+ @Override
+ public void drawableHotspotChanged(float x, float y) {
+ super.drawableHotspotChanged(x, y);
+ if (mForeground != null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ mForeground.setHotspot(x, y);
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ setChecked(!isChecked());
+ }
}
diff --git a/app/src/main/res/drawable/check_text_view_foreground.xml b/app/src/main/res/drawable/check_text_view_foreground.xml
new file mode 100644
index 000000000..73df9dfc7
--- /dev/null
+++ b/app/src/main/res/drawable/check_text_view_foreground.xml
@@ -0,0 +1,13 @@
+
+
+ -
+
+
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index fb24d9e5a..48c699aa9 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -90,7 +90,7 @@
@color/yellow_800
@color/deep_orange_400
- #8a000000
+ #4a000000
#fff44336
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index a071a7f71..dd780f2c3 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -97,7 +97,9 @@
-
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 22c8ce11d..7a6021ed6 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -120,7 +120,7 @@
@color/yellow_800
@color/deep_orange_400
- #8a000000
+ #4a000000
#fff44336
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 28b069355..23879700e 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -71,7 +71,7 @@
- bold
- center
- @dimen/category_table_item_height
- - @color/check_text_view_mask
+ - @drawable/check_text_view_foreground