diff --git a/app/src/main/assets/updatelog.fy b/app/src/main/assets/updatelog.fy index 528d152..31ff725 100644 --- a/app/src/main/assets/updatelog.fy +++ b/app/src/main/assets/updatelog.fy @@ -2,6 +2,7 @@ 风月读书v2.3.2 更新内容: 1、修复MIUI13阅读界面切换日夜间闪退的问题 +2、 2021.12.11 风月读书v2.2.8 diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java index 9baa6d9..bbd443a 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java @@ -318,9 +318,8 @@ public class SearchBookActivity extends BaseActivity { public void onDelete(TagGroup tagGroup, String tag, int pos) { if (mCurHistories.get(pos) != null) { mSearchHistoryService.deleteHistory(mCurHistories.get(pos)); + mSearchHistories.remove(mCurHistories.get(pos)); } - needReGetHistory = true; - initHistoryList(); } }); @@ -587,8 +586,7 @@ public class SearchBookActivity extends BaseActivity { hisDis.dispose(); } Single.create((SingleOnSubscribe) emitter -> { - if (needReGetHistory) - mSearchHistories = mSearchHistoryService.findAllSearchHistory(); + mSearchHistories = mSearchHistoryService.findAllSearchHistory(); mHistoryNames.clear(); mCurHistories.clear(); if (mSearchHistories == null || mSearchHistories.size() == 0) { diff --git a/app/src/main/java/xyz/fycz/myreader/widget/TagGroup.java b/app/src/main/java/xyz/fycz/myreader/widget/TagGroup.java index 6a27148..638ec6c 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/TagGroup.java +++ b/app/src/main/java/xyz/fycz/myreader/widget/TagGroup.java @@ -1,5 +1,6 @@ package xyz.fycz.myreader.widget; +import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; @@ -32,6 +33,7 @@ import java.util.ArrayList; import java.util.List; import xyz.fycz.myreader.R; +import xyz.fycz.myreader.widget.explosion_field.ExplosionField; /** * A TagGroup is a special layout with a set of tags. @@ -139,6 +141,8 @@ public class TagGroup extends ViewGroup { /** Listener used to handle tag click event. */ private InternalTagClickListener mInternalTagClickListener = new InternalTagClickListener(); + private ExplosionField mExplosionField; + public TagGroup(Context context) { this(context, null); } @@ -197,6 +201,18 @@ public class TagGroup extends ViewGroup { } } + @Override + protected void onAttachedToWindow() { + mExplosionField = ExplosionField.attach2Window((Activity) getContext()); + super.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + mExplosionField.clear(); + super.onDetachedFromWindow(); + } + /** * Call this to submit the INPUT tag. */ @@ -559,6 +575,7 @@ public class TagGroup extends ViewGroup { } protected void deleteTag(TagView tagView) { + mExplosionField.explode(tagView); removeView(tagView); if (mOnTagChangeListener != null) { mOnTagChangeListener.onDelete(TagGroup.this, tagView.getText().toString(), tagView.pos); @@ -1034,6 +1051,7 @@ public class TagGroup extends ViewGroup { } break; } + case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: { isPressed = false; invalidatePaint(); diff --git a/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/ExplosionAnimator.java b/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/ExplosionAnimator.java new file mode 100644 index 0000000..91da4d2 --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/ExplosionAnimator.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2015 tyrantgit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package xyz.fycz.myreader.widget.explosion_field; + +import android.animation.ValueAnimator; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.Interpolator; + +import java.util.Random; + +public class ExplosionAnimator extends ValueAnimator { + + static long DEFAULT_DURATION = 0x400; + private static final Interpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator(0.6f); + private static final float END_VALUE = 1.4f; + private static final float X = Utils.dp2Px(5); + private static final float Y = Utils.dp2Px(20); + private static final float V = Utils.dp2Px(2); + private static final float W = Utils.dp2Px(1); + private Paint mPaint; + private Particle[] mParticles; + private Rect mBound; + private View mContainer; + + public ExplosionAnimator(View container, Bitmap bitmap, Rect bound) { + mPaint = new Paint(); + mBound = new Rect(bound); + int partLen = 15; + mParticles = new Particle[partLen * partLen]; + Random random = new Random(System.currentTimeMillis()); + int w = bitmap.getWidth() / (partLen + 2); + int h = bitmap.getHeight() / (partLen + 2); + for (int i = 0; i < partLen; i++) { + for (int j = 0; j < partLen; j++) { + mParticles[(i * partLen) + j] = generateParticle(bitmap.getPixel((j + 1) * w, (i + 1) * h), random); + } + } + mContainer = container; + setFloatValues(0f, END_VALUE); + setInterpolator(DEFAULT_INTERPOLATOR); + setDuration(DEFAULT_DURATION); + } + + private Particle generateParticle(int color, Random random) { + Particle particle = new Particle(); + particle.color = color; + particle.radius = V; + if (random.nextFloat() < 0.2f) { + particle.baseRadius = V + ((X - V) * random.nextFloat()); + } else { + particle.baseRadius = W + ((V - W) * random.nextFloat()); + } + float nextFloat = random.nextFloat(); + particle.top = mBound.height() * ((0.18f * random.nextFloat()) + 0.2f); + particle.top = nextFloat < 0.2f ? particle.top : particle.top + ((particle.top * 0.2f) * random.nextFloat()); + particle.bottom = (mBound.height() * (random.nextFloat() - 0.5f)) * 1.8f; + float f = nextFloat < 0.2f ? particle.bottom : nextFloat < 0.8f ? particle.bottom * 0.6f : particle.bottom * 0.3f; + particle.bottom = f; + particle.mag = 4.0f * particle.top / particle.bottom; + particle.neg = (-particle.mag) / particle.bottom; + f = mBound.centerX() + (Y * (random.nextFloat() - 0.5f)); + particle.baseCx = f; + particle.cx = f; + f = mBound.centerY() + (Y * (random.nextFloat() - 0.5f)); + particle.baseCy = f; + particle.cy = f; + particle.life = END_VALUE / 10 * random.nextFloat(); + particle.overflow = 0.4f * random.nextFloat(); + particle.alpha = 1f; + return particle; + } + + public boolean draw(Canvas canvas) { + if (!isStarted()) { + return false; + } + for (Particle particle : mParticles) { + particle.advance((float) getAnimatedValue()); + if (particle.alpha > 0f) { + mPaint.setColor(particle.color); + mPaint.setAlpha((int) (Color.alpha(particle.color) * particle.alpha)); + canvas.drawCircle(particle.cx, particle.cy, particle.radius, mPaint); + } + } + mContainer.invalidate(); + return true; + } + + @Override + public void start() { + super.start(); + mContainer.invalidate(mBound); + } + + private class Particle { + float alpha; + int color; + float cx; + float cy; + float radius; + float baseCx; + float baseCy; + float baseRadius; + float top; + float bottom; + float mag; + float neg; + float life; + float overflow; + + + public void advance(float factor) { + float f = 0f; + float normalization = factor / END_VALUE; + if (normalization < life || normalization > 1f - overflow) { + alpha = 0f; + return; + } + normalization = (normalization - life) / (1f - life - overflow); + float f2 = normalization * END_VALUE; + if (normalization >= 0.7f) { + f = (normalization - 0.7f) / 0.3f; + } + alpha = 1f - f; + f = bottom * f2; + cx = baseCx + f; + cy = (float) (baseCy - this.neg * Math.pow(f, 2.0)) - f * mag; + radius = V + (baseRadius - V) * f2; + } + } +} diff --git a/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/ExplosionField.java b/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/ExplosionField.java new file mode 100644 index 0000000..9597026 --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/ExplosionField.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2015 tyrantgit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package xyz.fycz.myreader.widget.explosion_field; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.media.MediaPlayer; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + + +public class ExplosionField extends View { + + private long customDuration = ExplosionAnimator.DEFAULT_DURATION; + private int idPlayAnimationEffect = 0; + private OnAnimatorListener mZAnimatorListener; + private OnClickListener mOnClickListener; + + private List mExplosions = new ArrayList<>(); + private int[] mExpandInset = new int[2]; + + public ExplosionField(Context context) { + super(context); + init(); + } + + public ExplosionField(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public ExplosionField(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + + Arrays.fill(mExpandInset, Utils.dp2Px(32)); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + for (ExplosionAnimator explosion : mExplosions) { + explosion.draw(canvas); + } + } + + public void playSoundAnimationEffect(int id) { + this.idPlayAnimationEffect = id; + } + + public void setCustomDuration(long customDuration) { + this.customDuration = customDuration; + } + + public void addActionEvent(OnAnimatorListener ievents) { + this.mZAnimatorListener = ievents; + } + + + public void expandExplosionBound(int dx, int dy) { + mExpandInset[0] = dx; + mExpandInset[1] = dy; + } + + public void explode(Bitmap bitmap, Rect bound, long startDelay) { + explode(bitmap, bound, startDelay, null); + } + + public void explode(Bitmap bitmap, Rect bound, long startDelay, final View view) { + long currentDuration = customDuration; + final ExplosionAnimator explosion = new ExplosionAnimator(this, bitmap, bound); + explosion.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mExplosions.remove(animation); + if (view != null) { + view.setScaleX(1); + view.setScaleY(1); + view.setAlpha(1); + view.setOnClickListener(mOnClickListener);//set event + + } + } + }); + explosion.setStartDelay(startDelay); + explosion.setDuration(currentDuration); + mExplosions.add(explosion); + explosion.start(); + } + + public void explode(View view) { + explode(view, false); + } + + public void explode(final View view, Boolean restartState) { + + Rect r = new Rect(); + view.getGlobalVisibleRect(r); + int[] location = new int[2]; + getLocationOnScreen(location); +// getLocationInWindow(location); +// view.getLocationInWindow(location); + r.offset(-location[0], -location[1]); + r.inset(-mExpandInset[0], -mExpandInset[1]); + int startDelay = 100; + ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(150); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + + Random random = new Random(); + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + view.setTranslationX((random.nextFloat() - 0.5f) * view.getWidth() * 0.05f); + view.setTranslationY((random.nextFloat() - 0.5f) * view.getHeight() * 0.05f); + } + }); + + animator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animator) { + if (idPlayAnimationEffect != 0) + MediaPlayer.create(getContext(), idPlayAnimationEffect).start(); + } + + @Override + public void onAnimationEnd(Animator animator) { + if (mZAnimatorListener != null) { + mZAnimatorListener.onAnimationEnd(animator, ExplosionField.this); + } + } + + @Override + public void onAnimationCancel(Animator animator) { + Log.i("PRUEBA", "CANCEL"); + } + + @Override + public void onAnimationRepeat(Animator animator) { + Log.i("PRUEBA", "REPEAT"); + } + }); + + animator.start(); + view.animate().setDuration(150).setStartDelay(startDelay).scaleX(0f).scaleY(0f).alpha(0f).start(); + if (restartState) + explode(Utils.createBitmapFromView(view), r, startDelay, view); + else + explode(Utils.createBitmapFromView(view), r, startDelay); + + } + + public void clear() { + mExplosions.clear(); + invalidate(); + } + + public static ExplosionField attach2Window(Activity activity) { + ViewGroup rootView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT); + ExplosionField explosionField = new ExplosionField(activity); + rootView.addView(explosionField, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + return explosionField; + } + + public void setOnClickListener(OnClickListener mOnClickListener) { + this.mOnClickListener = mOnClickListener; + } + + +} diff --git a/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/OnAnimatorListener.java b/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/OnAnimatorListener.java new file mode 100644 index 0000000..571c2c9 --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/OnAnimatorListener.java @@ -0,0 +1,8 @@ +package xyz.fycz.myreader.widget.explosion_field; + +import android.animation.Animator; +import android.view.View; + +public interface OnAnimatorListener { + void onAnimationEnd(Animator animator, View view); +} diff --git a/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/Utils.java b/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/Utils.java new file mode 100644 index 0000000..f41bbb6 --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/widget/explosion_field/Utils.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 tyrantgit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package xyz.fycz.myreader.widget.explosion_field; + + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.ImageView; + +public class Utils { + + private Utils() { + } + + private static final float DENSITY = Resources.getSystem().getDisplayMetrics().density; + private static final Canvas sCanvas = new Canvas(); + + public static int dp2Px(int dp) { + return Math.round(dp * DENSITY); + } + + public static Bitmap createBitmapFromView(View view) { + if (view instanceof ImageView) { + Drawable drawable = ((ImageView) view).getDrawable(); + if (drawable != null && drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap(); + } + } + view.clearFocus(); + Bitmap bitmap = createBitmapSafely(view.getWidth(), + view.getHeight(), Bitmap.Config.ARGB_8888, 1); + if (bitmap != null) { + synchronized (sCanvas) { + Canvas canvas = sCanvas; + canvas.setBitmap(bitmap); + view.draw(canvas); + canvas.setBitmap(null); + } + } + return bitmap; + } + + public static Bitmap createBitmapSafely(int width, int height, Bitmap.Config config, int retryCount) { + try { + return Bitmap.createBitmap(width, height, config); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + if (retryCount > 0) { + System.gc(); + return createBitmapSafely(width, height, config, retryCount - 1); + } + return null; + } + } +}