From dd23537302c2760d62a5020de3b941df2f03fc3c Mon Sep 17 00:00:00 2001 From: seven332 Date: Mon, 27 Apr 2015 23:51:33 +0800 Subject: [PATCH] Add simple dialog curtain --- .../hippo/ehviewer/widget/SearchLayout.java | 19 +- .../java/com/hippo/scene/SceneDialog.java | 2 +- .../java/com/hippo/scene/SimpleDialog.java | 72 ++++++- .../com/hippo/scene/SimpleDialogCurtain.java | 200 ++++++++++++++++++ .../com/hippo/scene/SimpleDialogFrame.java | 63 ++++++ .../com/hippo/scene/SimpleDialogView.java | 4 +- .../main/java/com/hippo/util/AssertUtils.java | 13 ++ app/src/main/res/layout/search_normal.xml | 1 + .../main/res/layout/simple_dialog_frame.xml | 22 ++ app/src/main/res/values-zh-rCN/strings.xml | 2 + app/src/main/res/values/dimens.xml | 2 +- app/src/main/res/values/strings.xml | 2 + 12 files changed, 386 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/com/hippo/scene/SimpleDialogCurtain.java create mode 100644 app/src/main/res/layout/simple_dialog_frame.xml diff --git a/app/src/main/java/com/hippo/ehviewer/widget/SearchLayout.java b/app/src/main/java/com/hippo/ehviewer/widget/SearchLayout.java index 1918df294..1999124f4 100644 --- a/app/src/main/java/com/hippo/ehviewer/widget/SearchLayout.java +++ b/app/src/main/java/com/hippo/ehviewer/widget/SearchLayout.java @@ -38,6 +38,7 @@ import android.widget.TextView; import com.hippo.effect.ripple.RippleSalon; import com.hippo.ehviewer.R; import com.hippo.ehviewer.data.ListUrlBuilder; +import com.hippo.scene.SimpleDialog; import com.hippo.util.ViewUtils; import com.hippo.widget.FloatLabelEditText; import com.hippo.widget.FloatingActionButton; @@ -82,6 +83,8 @@ public class SearchLayout extends FrameLayout implements CompoundButton.OnChecke private View mNormalView; private CategoryTable mTableCategory; private CheckBox mCheckSpecifyAuthor; + private CheckBox mCheckSpecifyTag; + private View mSearchTagHelp; private SwitchCompat mSwitchEnableAdvance; private View mAdvanceView; @@ -157,12 +160,7 @@ public class SearchLayout extends FrameLayout implements CompoundButton.OnChecke } public void setFitPaddingTop(int fitPaddingTop) { - mSearchContainer.setPadding( - mSearchContainer.getPaddingLeft(), - mSearchPaddingTopOrigin + fitPaddingTop, - mSearchContainer.getPaddingRight(), - mSearchContainer.getPaddingBottom() - ); + mSearchContainer.setPadding(mSearchContainer.getPaddingLeft(), mSearchPaddingTopOrigin + fitPaddingTop, mSearchContainer.getPaddingRight(), mSearchContainer.getPaddingBottom()); } public void setFitPaddingBottom(int fitPaddingBottom) { @@ -260,6 +258,12 @@ public class SearchLayout extends FrameLayout implements CompoundButton.OnChecke if (mHelper != null) { mHelper.onRequestSearch(getListUrlBuilder(null)); } + } else if (v == mSearchTagHelp) { + int[] location = new int [2]; + ViewUtils.getLocationInAncestor(mSearchTagHelp, location, R.id.stage); + new SimpleDialog.Builder(getContext()).setTitle(R.string.search_specify_tag) + .setMessage(R.string.search_tag_help) + .setStartPoint(location[0], location[1]).show(); } } @@ -404,6 +408,8 @@ public class SearchLayout extends FrameLayout implements CompoundButton.OnChecke mNormalView = holder.content.getChildAt(0); mTableCategory = (CategoryTable) mNormalView.findViewById(R.id.search_category_table); mCheckSpecifyAuthor = (CheckBox) mNormalView.findViewById(R.id.search_specify_author); + mCheckSpecifyTag = (CheckBox) mNormalView.findViewById(R.id.search_specify_tag); + mSearchTagHelp = mNormalView.findViewById(R.id.search_tag_help); mSwitchEnableAdvance = (SwitchCompat) mNormalView.findViewById(R.id.search_enable_advance); // Restore state @@ -412,6 +418,7 @@ public class SearchLayout extends FrameLayout implements CompoundButton.OnChecke } mCheckSpecifyAuthor.setOnCheckedChangeListener(SearchLayout.this); + mSearchTagHelp.setOnClickListener(SearchLayout.this); mSwitchEnableAdvance.setOnCheckedChangeListener(SearchLayout.this); mSwitchEnableAdvance.setSwitchPadding(mResources.getDimensionPixelSize(R.dimen.switch_padding)); } else { diff --git a/app/src/main/java/com/hippo/scene/SceneDialog.java b/app/src/main/java/com/hippo/scene/SceneDialog.java index 11d91d912..8a974aa53 100644 --- a/app/src/main/java/com/hippo/scene/SceneDialog.java +++ b/app/src/main/java/com/hippo/scene/SceneDialog.java @@ -20,7 +20,7 @@ import android.support.annotation.Nullable; public abstract class SceneDialog extends Scene { public void show() { - sSceneManager.showDialog(this, null); + show(null); } public void show(@Nullable Curtain curtain) { diff --git a/app/src/main/java/com/hippo/scene/SimpleDialog.java b/app/src/main/java/com/hippo/scene/SimpleDialog.java index c94cb30b4..28dbf012f 100644 --- a/app/src/main/java/com/hippo/scene/SimpleDialog.java +++ b/app/src/main/java/com/hippo/scene/SimpleDialog.java @@ -38,7 +38,7 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener, private StageActivity mActivity; - private SimpleDialogView mSimpleImageView; + private SimpleDialogView mSimpleDialogView; private SimpleDialogFrame mFrame; private View mBody; private TextView mTitle; @@ -50,6 +50,7 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener, private View mSpacePositiveNegative; private TextView mPositiveButton; + private int mFitPaddingBottom; private SimpleDialog(@NonNull Builder builder) { mBuilder = builder; @@ -64,12 +65,12 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener, mActivity = getStageActivity(); - mFrame = new SimpleDialogFrame(mActivity); - setContentView(mFrame); + setContentView(R.layout.simple_dialog_frame); + mFrame = (SimpleDialogFrame) findViewById(R.id.simple_dialog_frame); mActivity.getLayoutInflater().inflate(R.layout.simple_dialog, mFrame); - mSimpleImageView = (SimpleDialogView) getSceneView(); + mSimpleDialogView = (SimpleDialogView) getSceneView(); mBody = findViewById(R.id.body); mTitle = (TextView) mBody.findViewById(R.id.title); mSpaceTitleContent = (Space) mBody.findViewById(R.id.space_title_content); @@ -122,7 +123,7 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener, } } - mSimpleImageView.setOnClickOutOfDialogListener(this); + mSimpleDialogView.setOnClickOutOfDialogListener(this); } @Override @@ -132,9 +133,52 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener, @Override protected void onGetFitPaddingBottom(int b) { + mFitPaddingBottom = b; mFrame.setFitPaddingBottom(b); } + public SimpleDialogFrame getFrame() { + return mFrame; + } + + public void getCenterLocation(int[] location) { + if (location == null || location.length < 2) { + throw new IllegalArgumentException("location must be an array of two integers"); + } + + if (mSimpleDialogView == null) { + location[0] = 0; + location[1] = 0; + } else { + location[0] = mSimpleDialogView.getWidth() / 2; + location[1] = (mSimpleDialogView.getHeight() - mFitPaddingBottom) / 2; + } + } + + public int getWidth() { + if (mFrame == null) { + return 0; + } else { + return mFrame.getWidth(); + } + } + + public int getHeight() { + if (mFrame == null) { + return 0; + } else { + return mFrame.getHeight(); + } + } + + public int getStartX() { + return mBuilder.mStartX; + } + + public int getStartY() { + return mBuilder.mStartY; + } + @Override public void onClick(View v) { if (v == mPositiveButton) { @@ -162,6 +206,9 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener, private boolean mCancelable = true; + private int mStartX; + private int mStartY; + public Builder(Context context) { mContext = context; } @@ -207,12 +254,25 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener, return this; } + public Builder setStartPoint(int startX, int startY) { + mStartX = startX; + mStartY = startY; + return this; + } + public @NonNull SceneDialog build() { return new SimpleDialog(this); } public void show() { - new SimpleDialog(this).show(); + show(null); + } + + public void show(Curtain curtain) { + if (curtain == null) { + curtain = new SimpleDialogCurtain(mStartX, mStartY); + } + new SimpleDialog(this).show(curtain); } } } diff --git a/app/src/main/java/com/hippo/scene/SimpleDialogCurtain.java b/app/src/main/java/com/hippo/scene/SimpleDialogCurtain.java new file mode 100644 index 000000000..b9ae0b161 --- /dev/null +++ b/app/src/main/java/com/hippo/scene/SimpleDialogCurtain.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2015 Hippo Seven + * + * 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 + * 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 com.hippo.scene; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.support.annotation.NonNull; +import android.view.View; +import android.view.ViewTreeObserver; + +import com.hippo.animation.ArgbEvaluator; +import com.hippo.animation.SimpleAnimatorListener; +import com.hippo.util.AssertUtils; +import com.hippo.util.ViewUtils; + +import java.util.HashSet; +import java.util.Set; + +public class SimpleDialogCurtain extends Curtain { + + private static long ANIMATE_TIME = 500L; + + private int mStartX; + private int mStartY; + + private AnimatorSet mAnimatorSet; + + public SimpleDialogCurtain() { + this(0, 0); + } + + public SimpleDialogCurtain(int startX, int startY) { + mStartX = startX; + mStartY = startY; + } + + @Override + public void open(@NonNull final Scene enter, @NonNull final Scene exit) { + AssertUtils.assertInstanceof("SimpleDialogCurtain should only use for SimpleDialog.", enter, SimpleDialog.class); + final SimpleDialog enterDialog = (SimpleDialog) enter; + + final Set animatorCollection = new HashSet<>(); + + // Handle background + int bgColor = enter.getBackgroundColor(); + int startBgColor = bgColor & 0xffffff; + enter.setBackgroundColor(startBgColor); + ObjectAnimator colorAnim = ObjectAnimator.ofInt(enter, "backgroundColor", bgColor); + colorAnim.setEvaluator(ArgbEvaluator.getInstance()); + colorAnim.setDuration(ANIMATE_TIME); + animatorCollection.add(colorAnim); + + final View mFrame = enterDialog.getFrame(); + AssertUtils.assertNotNull("Frame view must not be null.", mFrame); + + ViewUtils.setVisibility(mFrame, View.INVISIBLE); + + mFrame.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + ViewUtils.removeOnGlobalLayoutListener(mFrame.getViewTreeObserver(), this); + + int endLeft = mFrame.getLeft(); + int endTop = mFrame.getTop(); + int endRight = mFrame.getRight(); + int endBottom = mFrame.getBottom(); + int startLeft; + int startTop; + int startRight; + int startBottom; + if (mStartX == 0 && mStartY == 0) { + int[] center = new int[2]; + enterDialog.getCenterLocation(center); + startLeft = center[0]; + startTop = center[1]; + startRight = center[0]; + startBottom = center[1]; + } else { + startLeft = mStartX; + startTop = mStartY; + startRight = mStartX; + startBottom = mStartY; + } + // TODO should start from frame edge when it is out of frame + + PropertyValuesHolder leftPvh = PropertyValuesHolder.ofInt("drawLeft", startLeft, endLeft); + PropertyValuesHolder topPvh = PropertyValuesHolder.ofInt("drawTop", startTop, endTop); + PropertyValuesHolder rightPvh = PropertyValuesHolder.ofInt("drawRight", startRight, endRight); + PropertyValuesHolder bottomPvh = PropertyValuesHolder.ofInt("drawBottom", startBottom, endBottom); + ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(mFrame, leftPvh, topPvh, rightPvh, bottomPvh); + anim.setDuration(ANIMATE_TIME); + + animatorCollection.add(anim); + + mAnimatorSet = new AnimatorSet(); + mAnimatorSet.playTogether(animatorCollection); + mAnimatorSet.addListener(new SimpleAnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + ViewUtils.setVisibility(mFrame, View.VISIBLE); + } + @Override + public void onAnimationEnd(Animator animation) { + dispatchOpenFinished(enter, exit); + mAnimatorSet = null; + } + }); + mAnimatorSet.start(); + } + }); + } + + @Override + public void close(@NonNull final Scene enter, @NonNull final Scene exit) { + AssertUtils.assertInstanceof("SimpleDialogCurtain should only use for SimpleDialog.", exit, SimpleDialog.class); + final SimpleDialog exitDialog = (SimpleDialog) exit; + + final Set animatorCollection = new HashSet<>(); + + // Handle background + int bgColor = enter.getBackgroundColor(); + int endBgColor = bgColor & 0xffffff; + ObjectAnimator colorAnim = ObjectAnimator.ofInt(exit, "backgroundColor", endBgColor); + colorAnim.setEvaluator(ArgbEvaluator.getInstance()); + colorAnim.setDuration(ANIMATE_TIME); + animatorCollection.add(colorAnim); + + final View mFrame = exitDialog.getFrame(); + AssertUtils.assertNotNull("Frame view must not be null.", mFrame); + + int startLeft = mFrame.getLeft(); + int startTop = mFrame.getTop(); + int startRight = mFrame.getRight(); + int startBottom = mFrame.getBottom(); + int endLeft; + int endTop; + int endRight; + int endBottom; + if (mStartX == 0 && mStartY == 0) { + int[] center = new int[2]; + exitDialog.getCenterLocation(center); + endLeft = center[0]; + endTop = center[1]; + endRight = center[0]; + endBottom = center[1]; + } else { + endLeft = mStartX; + endTop = mStartY; + endRight = mStartX; + endBottom = mStartY; + } + + PropertyValuesHolder leftPvh = PropertyValuesHolder.ofInt("drawLeft", startLeft, endLeft); + PropertyValuesHolder topPvh = PropertyValuesHolder.ofInt("drawTop", startTop, endTop); + PropertyValuesHolder rightPvh = PropertyValuesHolder.ofInt("drawRight", startRight, endRight); + PropertyValuesHolder bottomPvh = PropertyValuesHolder.ofInt("drawBottom", startBottom, endBottom); + ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(mFrame, leftPvh, topPvh, rightPvh, bottomPvh); + anim.setDuration(ANIMATE_TIME); + + animatorCollection.add(anim); + + mAnimatorSet = new AnimatorSet(); + mAnimatorSet.playTogether(animatorCollection); + mAnimatorSet.addListener(new SimpleAnimatorListener() { + @Override + public void onAnimationEnd(Animator animation) { + dispatchCloseFinished(enter, exit); + mAnimatorSet = null; + } + }); + mAnimatorSet.start(); + } + + @Override + public void endAnimation() { + if (mAnimatorSet != null) { + mAnimatorSet.end(); + } + } + + @Override + public boolean isInAnimation() { + return mAnimatorSet != null; + } +} diff --git a/app/src/main/java/com/hippo/scene/SimpleDialogFrame.java b/app/src/main/java/com/hippo/scene/SimpleDialogFrame.java index c04463e77..f13174024 100644 --- a/app/src/main/java/com/hippo/scene/SimpleDialogFrame.java +++ b/app/src/main/java/com/hippo/scene/SimpleDialogFrame.java @@ -32,6 +32,11 @@ public class SimpleDialogFrame extends CardView { private float mFixedHeightPercent; private int mFitPaddingBottom; + private int mOriginLeft; + private int mOriginTop; + private int mDrawLeft; + private int mDrawTop; + public SimpleDialogFrame(Context context) { super(context); init(context); @@ -88,4 +93,62 @@ public class SimpleDialogFrame extends CardView { lp.x = (originalWidth - width) / 2; lp.y = (originalHeight - mFitPaddingBottom - height) / 2; } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + mDrawLeft = mOriginLeft = left; + mDrawTop = mOriginTop = top; + } + + /** + * I want to set left, but draw start from origin left. + */ + @SuppressWarnings("unused") + public void setDrawLeft(int drawLeft) { + mDrawLeft = drawLeft; + setLeft(drawLeft); + setScrollX(drawLeft - mOriginLeft); + } + + @SuppressWarnings("unused") + public int getDrawLeft() { + return mDrawLeft; + } + + /** + * I want to set top, but draw start from origin top. + */ + @SuppressWarnings("unused") + public void setDrawTop(int drawTop) { + mDrawTop = drawTop; + setTop(drawTop); + setScrollY((drawTop - mOriginTop)); + } + + @SuppressWarnings("unused") + public int getDrawTop() { + return mDrawTop; + } + + @SuppressWarnings("unused") + public void setDrawRight(int drawRight) { + setRight(drawRight); + } + + @SuppressWarnings("unused") + public int getDrawRight() { + return getRight(); + } + + @SuppressWarnings("unused") + public void setDrawBottom(int drawBottom) { + setBottom(drawBottom); + } + + @SuppressWarnings("unused") + public int getDrawBottom() { + return getBottom(); + } } diff --git a/app/src/main/java/com/hippo/scene/SimpleDialogView.java b/app/src/main/java/com/hippo/scene/SimpleDialogView.java index 82c136a08..a1d4de893 100644 --- a/app/src/main/java/com/hippo/scene/SimpleDialogView.java +++ b/app/src/main/java/com/hippo/scene/SimpleDialogView.java @@ -72,8 +72,8 @@ public class SimpleDialogView extends SceneView implements View.OnClickListener, @Override public void onClick(View v) { - if (v == this && !ViewUtils.isViewUnder(getChildAt(0), (int) mHostpotX, (int) mHostpotY) && - mOnClickOutOfDialogListener != null) { + if (v == this && !ViewUtils.isViewUnder(getChildAt(0), (int) mHostpotX, + (int) mHostpotY) && mOnClickOutOfDialogListener != null) { mOnClickOutOfDialogListener.onClickOutOfDialog(); } } diff --git a/app/src/main/java/com/hippo/util/AssertUtils.java b/app/src/main/java/com/hippo/util/AssertUtils.java index 51aeb382e..929e186a2 100644 --- a/app/src/main/java/com/hippo/util/AssertUtils.java +++ b/app/src/main/java/com/hippo/util/AssertUtils.java @@ -35,6 +35,12 @@ public class AssertUtils { } } + public static void assertInstanceof(String message, Object obj, Class clazz) { + if (!clazz.isInstance(obj)) { + throw new AssertError(message); + } + } + public static void assertNullEx(String message, Object object) throws AssertException { if (object != null) { @@ -55,4 +61,11 @@ public class AssertUtils { throw new AssertException(message); } } + + public static void assertInstanceofEx(String message, Object obj, Class clazz) + throws AssertException { + if (!clazz.isInstance(obj)) { + throw new AssertException(message); + } + } } diff --git a/app/src/main/res/layout/search_normal.xml b/app/src/main/res/layout/search_normal.xml index be59b2244..fb3c721c0 100644 --- a/app/src/main/res/layout/search_normal.xml +++ b/app/src/main/res/layout/search_normal.xml @@ -46,6 +46,7 @@ android:text="@string/search_specify_tag"/> + + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 3bdd398f6..2c01fe765 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -45,6 +45,8 @@ 添加 模式 + 指定标签会使通过标签搜索出来的结果更精确。每次只允许搜索一个标签。其搜索格式为 <tag> 或 <namespace>:<tag> 。当勾选指定标签时,其他搜索选项会被忽略。 + 2 星 3 星 diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 8cc90ed74..b55e94a62 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -21,7 +21,7 @@ 24dp 24dp 24dp - 18dp + 20dp 18dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 49c75a52d..fe21be186 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -63,6 +63,8 @@ Add Mode + Searching via specify tag is precise. One tag each searching. Searching format is <tag> or <namespace>:<tag>. Other searching options will be ignored when specify tag is checked. + 2 stars 3 stars