This commit is contained in:
seven332 committed 2015-02-28 15:52:04 +08:00
1 parent 7375b1ca24
commit 3d71e08272
21 files changed
+919 -276

No files matched your search

@@ -15,11 +15,10 @@
package com.hippo.ehviewer;
import android.app.Application;
import com.hippo.scene.SceneApplication;
import com.hippo.util.UiUtils;
public class EhApplication extends Application {
public class EhApplication extends SceneApplication {
@Override
public void onCreate() {
@@ -18,8 +18,8 @@ package com.hippo.ehviewer.client;
import com.hippo.ehviewer.data.GalleryInfo;
import com.hippo.ehviewer.data.LofiGalleryInfo;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.util.AssertException;
import com.hippo.util.AssertUtils;
import com.hippo.util.NotEqualsException;
import com.hippo.util.Utils;
import java.util.ArrayList;
@@ -224,10 +224,9 @@ public class ListParser {
private static final String PAU_SPACER = " by ";
private void getPostedAndUploader(String raw, String[] pau)
throws NotEqualsException {
private void getPostedAndUploader(String raw, String[] pau) throws AssertException {
int index = raw.indexOf(PAU_SPACER);
AssertUtils.assertEquals("Can not parse posted and uploader", index, -1);
AssertUtils.assertEqualsEx("Can not parse posted and uploader", index, -1);
pau[0] = raw.substring(0, index);
pau[1] = raw.substring(index + PAU_SPACER.length());
}
@@ -21,6 +21,7 @@ import android.support.v4.widget.DrawerLayout;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.ui.scene.GalleryListScene;
import com.hippo.ehviewer.widget.ContentLayout;
import com.hippo.scene.StageActivity;
import com.hippo.scene.StageLayout;
@@ -29,7 +30,7 @@ public class ContentActivity extends StageActivity {
private Resources mResources;
private DrawerLayout mDrawerLayout;
private StageLayout mStage;
private ContentLayout mContentLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -39,15 +40,21 @@ public class ContentActivity extends StageActivity {
mResources = getResources();
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
mStage = (StageLayout) mDrawerLayout.findViewById(R.id.stage);
mContentLayout = (ContentLayout) mDrawerLayout.findViewById(R.id.stage);
mDrawerLayout.setStatusBarBackground(R.color.theme_primary_dark);
startFirstScene(GalleryListScene.class);
if (savedInstanceState == null) {
startScene(GalleryListScene.class, null);
}
}
public int getFitPaddingBottom() {
return mContentLayout.getFitPaddingBottom();
}
@Override
public StageLayout getStageView() {
return mStage;
public StageLayout getStageLayout() {
return mContentLayout;
}
}
@@ -30,6 +30,7 @@ import android.view.ViewGroup;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.data.ListUrlBuilder;
import com.hippo.ehviewer.ui.ContentActivity;
import com.hippo.ehviewer.widget.SearchLayout;
import com.hippo.scene.Scene;
@@ -38,7 +39,7 @@ public class SearchFragment extends Fragment implements SearchLayout.SearhLayout
private static final String VIEW_STATE_TAG = "android:view_state";
private Activity mActivity;
private ContentActivity mActivity;
private View mRootView;
private SearchLayout mSearchLayout;
@@ -69,13 +70,19 @@ public class SearchFragment extends Fragment implements SearchLayout.SearhLayout
public View onCreateView(LayoutInflater inflater,ViewGroup container,
Bundle savedInstanceState) {
mActivity = getActivity();
mActivity = (ContentActivity) getActivity();
mRootView = inflater.inflate(R.layout.fragment_search, container, false);
mSearchLayout = (SearchLayout) mRootView.findViewById(R.id.search_layout);
mSearchLayout.setHelper(this);
// Set fit padding bottom
int fixPaddingBottom = mActivity.getFitPaddingBottom();
if (fixPaddingBottom != -1) {
mSearchLayout.setFitPaddingBottom(mActivity.getFitPaddingBottom());
}
return mRootView;
}
@@ -15,28 +15,8 @@
package com.hippo.ehviewer.ui.scene;
import com.hippo.ehviewer.R;
import com.hippo.scene.Scene;
public class GalleryDetailScene extends Scene {
@Override
public void onCreate() {
setContentView(R.layout.scene_gallery_detail);
}
@Override
public void onResume() {
// Empty
}
@Override
public void onPause() {
dispatchRemove();
}
@Override
public void onDestroy() {
dispatchRemove();
}
}
@@ -21,16 +21,21 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.data.ListUrlBuilder;
import com.hippo.ehviewer.ui.fragment.GalleryListFragment;
import com.hippo.ehviewer.ui.fragment.SearchFragment;
import com.hippo.scene.Scene;
import com.hippo.scene.StageActivity;
import com.hippo.widget.Appbar;
import org.jetbrains.annotations.NotNull;
public class GalleryListScene extends Scene implements SearchFragment.OnSearchListener {
private StageActivity mActivity;
private Resources mResources;
private Appbar mAppbar;
@@ -39,13 +44,16 @@ public class GalleryListScene extends Scene implements SearchFragment.OnSearchLi
private GalleryListPagerAdapter mAdapter;
@Override
public void onCreate() {
setContentView(R.layout.scene_gallery_list);
public void onCreate(Bundle savedInstanceState) {
mActivity = getStageActivity();
mResources = mActivity.getResources();
}
mResources = getStageActivity().getResources();
mAppbar = (Appbar) findViewById(R.id.appbar);
mViewPager = (ViewPager) findViewById(R.id.viewPager);
@Override
public View onCreateSceneView(Bundle savedInstanceState) {
View sceneView = mActivity.getLayoutInflater().inflate(R.layout.scene_gallery_list, null);
mAppbar = (Appbar) sceneView.findViewById(R.id.appbar);
mViewPager = (ViewPager) sceneView.findViewById(R.id.viewPager);
mAdapter = new GalleryListPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mAdapter);
@@ -54,6 +62,8 @@ public class GalleryListScene extends Scene implements SearchFragment.OnSearchLi
SearchFragment.setScene(this);
SearchFragment.setOnSearchListener(this);
return sceneView;
}
@Override
@@ -63,13 +73,10 @@ public class GalleryListScene extends Scene implements SearchFragment.OnSearchLi
@Override
public void onPause() {
dispatchRemove();
}
@Override
public void onDestroy() {
dispatchRemove();
SearchFragment.setScene(null);
SearchFragment.setOnSearchListener(null);
}
@@ -85,7 +92,7 @@ public class GalleryListScene extends Scene implements SearchFragment.OnSearchLi
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
protected void onRestoreInstanceState(@NotNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
@@ -0,0 +1,91 @@
/*
* 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.ehviewer.widget;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import com.hippo.scene.StageLayout;
import org.jetbrains.annotations.NotNull;
public class ContentLayout extends StageLayout {
private OnGetPaddingListener mOnGetPaddingListener;
private int mFitPaddingLeft = -1;
private int mFitPaddingTop = -1;
private int mFitPaddingRight = -1;
private int mFitPaddingBottom = -1;
public ContentLayout(Context context) {
super(context);
}
public ContentLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ContentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ContentLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@SuppressWarnings("deprecation")
@Override
protected boolean fitSystemWindows(@NotNull Rect insets) {
mFitPaddingLeft = insets.left;
mFitPaddingTop = 0;
mFitPaddingRight = insets.right;
mFitPaddingBottom = insets.bottom;
if (mOnGetPaddingListener != null) {
mOnGetPaddingListener.onGetPadding(mFitPaddingLeft, mFitPaddingTop,
mFitPaddingRight, mFitPaddingBottom);
}
insets.set(0, insets.top, 0, 0);
return super.fitSystemWindows(insets);
}
public void setOnGetPaddingListener(OnGetPaddingListener listener) {
mOnGetPaddingListener = listener;
}
public int getFitPaddingLeft() {
return mFitPaddingLeft;
}
public int getFitPaddingTop() {
return mFitPaddingTop;
}
public int getFitPaddingRight() {
return mFitPaddingRight;
}
public int getFitPaddingBottom() {
return mFitPaddingBottom;
}
public interface OnGetPaddingListener {
public void onGetPadding(int l, int t, int r, int b);
}
}
@@ -0,0 +1,19 @@
/*
* 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.ehviewer.widget;
public class GalleryListView {
}
@@ -146,6 +146,15 @@ public class SearchLayout extends FrameLayout implements CompoundButton.OnChecke
mFab.setOnClickListener(this);
}
public void setFitPaddingBottom(int paddingBottom) {
mSearchContainer.setClipToPadding(false);
mSearchContainer.setPadding(
mSearchContainer.getPaddingLeft(),
mSearchContainer.getPaddingTop(),
mSearchContainer.getPaddingRight(),
paddingBottom);
}
public void setHelper(SearhLayoutHelper helper) {
mHelper = helper;
}
@@ -0,0 +1,356 @@
/*
* 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.os.Bundle;
import android.os.Parcelable;
import java.io.Serializable;
public class Announcer {
private Bundle mExtras;
public boolean getBooleanExtra(String name, boolean defaultValue) {
return mExtras == null ? defaultValue :
mExtras.getBoolean(name, defaultValue);
}
public byte getByteExtra(String name, byte defaultValue) {
return mExtras == null ? defaultValue :
mExtras.getByte(name, defaultValue);
}
public short getShortExtra(String name, short defaultValue) {
return mExtras == null ? defaultValue :
mExtras.getShort(name, defaultValue);
}
public char getCharExtra(String name, char defaultValue) {
return mExtras == null ? defaultValue :
mExtras.getChar(name, defaultValue);
}
public int getIntExtra(String name, int defaultValue) {
return mExtras == null ? defaultValue :
mExtras.getInt(name, defaultValue);
}
public long getLongExtra(String name, long defaultValue) {
return mExtras == null ? defaultValue :
mExtras.getLong(name, defaultValue);
}
public float getFloatExtra(String name, float defaultValue) {
return mExtras == null ? defaultValue :
mExtras.getFloat(name, defaultValue);
}
public double getDoubleExtra(String name, double defaultValue) {
return mExtras == null ? defaultValue :
mExtras.getDouble(name, defaultValue);
}
public String getStringExtra(String name) {
return mExtras == null ? null : mExtras.getString(name);
}
public CharSequence getCharSequenceExtra(String name) {
return mExtras == null ? null : mExtras.getCharSequence(name);
}
public <T extends Parcelable> T getParcelableExtra(String name) {
return mExtras == null ? null : mExtras.<T>getParcelable(name);
}
public Parcelable[] getParcelableArrayExtra(String name) {
return mExtras == null ? null : mExtras.getParcelableArray(name);
}
public Serializable getSerializableExtra(String name) {
return mExtras == null ? null : mExtras.getSerializable(name);
}
public boolean[] getBooleanArrayExtra(String name) {
return mExtras == null ? null : mExtras.getBooleanArray(name);
}
public byte[] getByteArrayExtra(String name) {
return mExtras == null ? null : mExtras.getByteArray(name);
}
public short[] getShortArrayExtra(String name) {
return mExtras == null ? null : mExtras.getShortArray(name);
}
public char[] getCharArrayExtra(String name) {
return mExtras == null ? null : mExtras.getCharArray(name);
}
public int[] getIntArrayExtra(String name) {
return mExtras == null ? null : mExtras.getIntArray(name);
}
public long[] getLongArrayExtra(String name) {
return mExtras == null ? null : mExtras.getLongArray(name);
}
public float[] getFloatArrayExtra(String name) {
return mExtras == null ? null : mExtras.getFloatArray(name);
}
public double[] getDoubleArrayExtra(String name) {
return mExtras == null ? null : mExtras.getDoubleArray(name);
}
public String[] getStringArrayExtra(String name) {
return mExtras == null ? null : mExtras.getStringArray(name);
}
public CharSequence[] getCharSequenceArrayExtra(String name) {
return mExtras == null ? null : mExtras.getCharSequenceArray(name);
}
public Bundle getBundleExtra(String name) {
return mExtras == null ? null : mExtras.getBundle(name);
}
public Bundle getExtras() {
return (mExtras != null)
? new Bundle(mExtras)
: null;
}
public Announcer putExtra(String name, boolean value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putBoolean(name, value);
return this;
}
public Announcer putExtra(String name, byte value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putByte(name, value);
return this;
}
public Announcer putExtra(String name, char value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putChar(name, value);
return this;
}
public Announcer putExtra(String name, short value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putShort(name, value);
return this;
}
public Announcer putExtra(String name, int value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putInt(name, value);
return this;
}
public Announcer putExtra(String name, long value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putLong(name, value);
return this;
}
public Announcer putExtra(String name, float value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putFloat(name, value);
return this;
}
public Announcer putExtra(String name, double value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putDouble(name, value);
return this;
}
public Announcer putExtra(String name, String value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putString(name, value);
return this;
}
public Announcer putExtra(String name, CharSequence value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putCharSequence(name, value);
return this;
}
public Announcer putExtra(String name, Parcelable value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putParcelable(name, value);
return this;
}
public Announcer putExtra(String name, Parcelable[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putParcelableArray(name, value);
return this;
}
public Announcer putExtra(String name, Serializable value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putSerializable(name, value);
return this;
}
public Announcer putExtra(String name, boolean[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putBooleanArray(name, value);
return this;
}
public Announcer putExtra(String name, byte[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putByteArray(name, value);
return this;
}
public Announcer putExtra(String name, short[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putShortArray(name, value);
return this;
}
public Announcer putExtra(String name, char[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putCharArray(name, value);
return this;
}
public Announcer putExtra(String name, int[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putIntArray(name, value);
return this;
}
public Announcer putExtra(String name, long[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putLongArray(name, value);
return this;
}
public Announcer putExtra(String name, float[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putFloatArray(name, value);
return this;
}
public Announcer putExtra(String name, double[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putDoubleArray(name, value);
return this;
}
public Announcer putExtra(String name, String[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putStringArray(name, value);
return this;
}
public Announcer putExtra(String name, CharSequence[] value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putCharSequenceArray(name, value);
return this;
}
public Announcer putExtra(String name, Bundle value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putBundle(name, value);
return this;
}
public Announcer putExtras(Announcer src) {
if (src.mExtras != null) {
if (mExtras == null) {
mExtras = new Bundle(src.mExtras);
} else {
mExtras.putAll(src.mExtras);
}
}
return this;
}
public Announcer putExtras(Bundle extras) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putAll(extras);
return this;
}
public void removeExtra(String name) {
if (mExtras != null) {
mExtras.remove(name);
if (mExtras.size() == 0) {
mExtras = null;
}
}
}
}
@@ -0,0 +1,19 @@
/*
* 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;
public class Curtain {
}
+117 -58
View File
@@ -21,9 +21,13 @@ import android.os.Parcelable;
import android.support.v4.app.FragmentManager;
import android.util.SparseArray;
import android.view.View;
import android.widget.FrameLayout;
import android.view.ViewParent;
import com.hippo.util.AssertUtils;
import com.hippo.util.Log;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* {@link com.hippo.scene.Scene} is a {@code Activity} of {@link android.app.Activity}.
@@ -33,60 +37,43 @@ import com.hippo.util.AssertUtils;
*/
public abstract class Scene {
private StageActivity mStageActivity;
private FrameLayout mStageView;
private View mRootView;
private @Nullable View mSceneView;
void setStageActivity(StageActivity stageActivity) {
mStageActivity = stageActivity;
mStageView = stageActivity.getStageView();
}
private static SceneManager sSceneManager;
public void setContentView(int layoutResID) {
mRootView = mStageActivity.getLayoutInflater()
.inflate(layoutResID, mStageView, false);
}
public void setContentView(View view) {
mRootView = view;
}
public View findViewById(int id) {
AssertUtils.assertNotNull("Call setContentView before findViewById",
mRootView);
return mRootView.findViewById(id);
}
View getRootView() {
return mRootView;
static void setSceneManager(SceneManager sceneManager) {
sSceneManager = sceneManager;
}
// If there is no StageActivity for SceneManager, yout will get AssertError
public StageActivity getStageActivity() {
return mStageActivity;
StageActivity stageActivity = sSceneManager.getStageActivity();
AssertUtils.assertNotNull("StageActivity is null", stageActivity);
return stageActivity;
}
public void startScene(Class sceneClass) {
mStageActivity.startScene(this, sceneClass);
View getSceneView() {
return mSceneView;
}
public void startScene(@NotNull Class sceneClass, @Nullable Announcer announcer) {
sSceneManager.startScene(sceneClass, announcer);
}
public final void finish() {
mStageActivity.finishScene(this);
sSceneManager.finishScene(this);
}
void create() {
onCreate();
void create(Bundle savedInstanceState) {
onCreate(savedInstanceState);
mSceneView = onCreateSceneView(savedInstanceState);
AssertUtils.assertNotNull("You have to call setContentView in onCreate",
mRootView);
mStageActivity.addSceneView(this);
// Make sure scene view is attach from stage
attachToStage();
}
void resume() {
onResume();
mStageActivity.addSceneView(this);
}
void pause() {
@@ -95,46 +82,118 @@ public abstract class Scene {
void destroy() {
onDestroy();
// Make sure scene view is detached from stage
detachFromeStage();
}
/**
* You have to call setContentView in it.
* It is called when scene is created
*
* @param savedInstanceState null for first time, non null for recrearte
*/
public abstract void onCreate();
public abstract void onResume();
public abstract void onPause();
public abstract void onDestroy();
protected void onCreate(Bundle savedInstanceState) {
}
/**
* This method should be called to remove when it need to remove
* It is called after {@link #onCreate(android.os.Bundle)}.
* Create view of the scene.
*
* @param savedInstanceState null for first time, non null for recrearte
* @return the view of the scene
*/
public final void dispatchRemove() {
mStageActivity.stopSceneRetain(this);
protected @Nullable View onCreateSceneView(Bundle savedInstanceState) {
return null;
}
protected void onResume() {
}
protected void onPause() {
}
protected void onDestroy() {
}
/**
* Is scene view attached to stage
*
* @return if scene view is null, always return false;
*/
public boolean isInStage() {
if (mSceneView == null) {
return false;
} else {
ViewParent parent = mSceneView.getParent();
if (parent == null) {
return false;
} else if (parent == getStageActivity().getStageLayout()) {
return true;
} else {
throw new IllegalStateException("Scene view should only be the child of stage layout");
}
}
}
// Add scene view to stage layout
void attachToStage() {
if (mSceneView != null && !isInStage()) {
Log.d("doAttachToStage();");
doAttachToStage();
}
}
void attachToStageAsPreScene() {
// TODO
}
// Remove scene view from stage layout
void detachFromeStage() {
if (mSceneView != null && isInStage()) {
doDetachFromeStage();
}
}
void doAttachToStage() {
getStageActivity().attachSceneToStage(this);
}
void doAttachToStageAsPreScene() {
getStageActivity().attachSceneToStageAsPreScene(this);
}
void doDetachFromeStage() {
getStageActivity().detachSceneFromStage(this);
}
public void onBackPressed() {
finish();
}
protected void onSaveInstanceState(Bundle outState) {
SparseArray<Parcelable> states = new SparseArray<>();
mRootView.saveHierarchyState(states);
outState.putSparseParcelableArray(Integer.toHexString(hashCode()), states);
// It is constant
private String getStateKey() {
return "scene:" + Integer.toHexString(hashCode());
}
protected void onRestoreInstanceState(Bundle savedInstanceState) {
protected void onSaveInstanceState(Bundle outState) {
SparseArray<Parcelable> states = new SparseArray<>();
mSceneView.saveHierarchyState(states);
outState.putSparseParcelableArray(getStateKey(), states);
}
protected void onRestoreInstanceState(@NotNull Bundle savedInstanceState) {
SparseArray<Parcelable> savedStates
= savedInstanceState.getSparseParcelableArray(Integer.toHexString(hashCode()));
= savedInstanceState.getSparseParcelableArray(getStateKey());
if (savedStates != null) {
mRootView.restoreHierarchyState(savedStates);
mSceneView.restoreHierarchyState(savedStates);
}
}
public void startActivityForResult(Intent intent, ActivityResultListener listener) {
mStageActivity.startActivityForResult(intent, listener);
getStageActivity().startActivityForResult(intent, listener);
}
/**
@@ -142,7 +201,7 @@ public abstract class Scene {
* with StageActivity.
*/
public FragmentManager getSupportFragmentManager() {
return mStageActivity.getSupportFragmentManager();
return getStageActivity().getSupportFragmentManager();
}
public interface ActivityResultListener {
@@ -0,0 +1,34 @@
/*
* 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.app.Application;
public class SceneApplication extends Application {
private SceneManager mSceneManager;
@Override
public void onCreate() {
mSceneManager = new SceneManager();
StageActivity.setSceneManager(mSceneManager);
Scene.setSceneManager(mSceneManager);
}
public SceneManager getSceneManager() {
return mSceneManager;
}
}
@@ -0,0 +1,120 @@
/*
* 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.os.Bundle;
import com.hippo.util.Log;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Stack;
class SceneManager {
private static final String TAG = SceneManager.class.getSimpleName();
private Stack<Scene> mSceneStack = new Stack<>();
private StageActivity mStageActivity;
// Should only be called by SceneApplication
SceneManager() {
}
void setStageActivity(StageActivity stageActivity) {
mStageActivity = stageActivity;
}
StageActivity getStageActivity() {
return mStageActivity;
}
void startScene(@NotNull Class sceneClass, @Nullable Announcer announcer) {
Scene scene;
try {
scene = (Scene) sceneClass.newInstance();
} catch (InstantiationException e) {
throw new IllegalStateException("Can't instance " + sceneClass.getName());
} catch (IllegalAccessException e) {
throw new IllegalStateException("The constructor of " +
sceneClass.getName() + " is not visible");
} catch (ClassCastException e) {
throw new IllegalStateException(sceneClass.getName() + " can not cast to scene");
}
Scene topScene = getTopState();
if (topScene != null) {
topScene.pause();
}
mSceneStack.push(scene);
scene.create(null);
scene.resume();
}
void finishScene(@NotNull Scene scene) {
if (mSceneStack.remove(scene)) {
scene.destroy();
} else {
Log.e(TAG, "The scene is not in stage");
}
}
boolean onBackPressed() {
Scene scene = getTopState();
if (scene != null) {
scene.onBackPressed();
return true;
} else {
Log.w(TAG, "There is no scene in the stage");
return false;
}
}
private Scene getTopState() {
if (!mSceneStack.isEmpty()) {
return mSceneStack.peek();
} else {
return null;
}
}
private Scene getSecondTopState() {
int secondTopIndex = mSceneStack.size() - 2;
if (secondTopIndex >= 0) {
return mSceneStack.get(secondTopIndex);
} else {
return null;
}
}
protected void onSaveInstanceState(Bundle outState) {
for (Scene scene : mSceneStack) {
scene.onSaveInstanceState(outState);
}
}
protected void onRestoreInstanceState(@NotNull Bundle savedInstanceState) {
for (Scene scene : mSceneStack) {
// Recreate
scene.create(savedInstanceState);
scene.resume();
scene.onRestoreInstanceState(savedInstanceState);
}
}
}
@@ -22,138 +22,60 @@ import android.util.SparseArray;
import com.hippo.ehviewer.ui.AbsActionBarActivity;
import com.hippo.util.IntIdGenerator;
import java.util.LinkedList;
import java.util.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class StageActivity extends AbsActionBarActivity {
private Stack<Scene> mSceneStack = new Stack<>();
private LinkedList<SceneAction> mScenseActionQueue = new LinkedList<>();
private Scene mCurrentScene = null;
private Scene mRetainedScene = null;
private IntIdGenerator mActivityResultIdGenerator = IntIdGenerator.create();
private SparseArray<Scene.ActivityResultListener> mActivityResultListenerMap =
new SparseArray<>();
public abstract StageLayout getStageView();
private static SceneManager sSceneManager;
private void pushScene(Class sceneClass) {
Scene scene = null;
try {
scene = (Scene) sceneClass.newInstance();
} catch (InstantiationException e) {
throw new IllegalStateException("Can't instance " + sceneClass.getName());
} catch (IllegalAccessException e) {
throw new IllegalStateException("The constructor of " +
sceneClass.getName() + " is not vivible");
} catch (ClassCastException e) {
throw new IllegalStateException(sceneClass.getName() + " can not cast to scene");
}
scene.setStageActivity(this);
Scene lastScene = mCurrentScene;
mCurrentScene = scene;
mCurrentScene.create();
if (lastScene != null) {
// It is not the first scense
mSceneStack.push(lastScene);
mRetainedScene = lastScene;
lastScene.pause();
}
static void setSceneManager(SceneManager sceneManager) {
sSceneManager = sceneManager;
}
private void popScense() {
if (mSceneStack.isEmpty()) {
// It is the last scene
mRetainedScene = mCurrentScene;
mCurrentScene.destroy();
} else {
Scene previousScene = mCurrentScene;
mCurrentScene = mSceneStack.pop();
mRetainedScene = previousScene;
public abstract StageLayout getStageLayout();
mCurrentScene.resume();
previousScene.destroy();
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((SceneApplication) getApplication()).getSceneManager().setStageActivity(this);
}
void addSceneView(Scene scene) {
if (scene != mCurrentScene) {
throw new IllegalStateException("This scene should be current scene.");
}
@Override
protected void onDestroy() {
super.onDestroy();
getStageView().addView(scene.getRootView());
((SceneApplication) getApplication()).getSceneManager().setStageActivity(null);
}
void stopSceneRetain(Scene scene) {
if (mRetainedScene == null) {
throw new IllegalStateException("Do not call dispatchRemove more than " +
"once.");
}
if (mRetainedScene != scene) {
throw new IllegalStateException("Only call dispatchRemove in onPause " +
"and onDestroy");
}
Scene retainScene = mRetainedScene;
mRetainedScene = null;
getStageView().removeView(scene.getRootView());
if (retainScene == mCurrentScene) {
// No need to handle scene action
mScenseActionQueue.clear();
// It is the last scene, let's finish the activity.
finish();
} else {
// Handle SceneAction
if (!mScenseActionQueue.isEmpty()) {
mScenseActionQueue.poll().doAction();
}
}
void attachSceneToStage(Scene scene) {
getStageLayout().addView(scene.getSceneView());
}
protected void startFirstScene(Class sceneClass) {
if (mCurrentScene != null) {
throw new IllegalStateException("Only call startFirstScene to start " +
"first scene.");
}
pushScene(sceneClass);
void attachSceneToStageAsPreScene(Scene scene) {
StageLayout stageLayout = getStageLayout();
stageLayout.addView(scene.getSceneView(), stageLayout.getChildCount() - 1);
}
void startScene(Scene fromScene, Class sceneClass) {
if (mRetainedScene == null) {
// No retained scene, no animation
if (fromScene == mCurrentScene) {
// Only current scene can start new scene.
// If not, just miss it.
pushScene(sceneClass);
}
} else {
mScenseActionQueue.offer(new StartSceneAction(fromScene, sceneClass));
}
void detachSceneFromStage(Scene scene) {
getStageLayout().removeView(scene.getSceneView());
}
void finishScene(Scene scene) {
if (scene != mRetainedScene && scene != mCurrentScene) {
if (mSceneStack.contains(scene)) {
// Remove without animation
getStageView().removeView(scene.getRootView());
mSceneStack.remove(scene);
}
} else {
if (mRetainedScene == null) {
// Because scene can't be null, so scene == mCurrentScene
popScense();
} else {
mScenseActionQueue.offer(new FinishSceneAction(scene));
}
}
public void startScene(@NotNull Class sceneClass, @Nullable Announcer announcer) {
sSceneManager.startScene(sceneClass, announcer);
}
/**
* Start new Activity for result to listener
*
* @param intent the intent for new Activity
* @param listener callback
*/
public void startActivityForResult(Intent intent, Scene.ActivityResultListener listener) {
int id = mActivityResultIdGenerator.nextId();
mActivityResultListenerMap.put(id, listener);
@@ -173,8 +95,8 @@ public abstract class StageActivity extends AbsActionBarActivity {
@Override
public void onBackPressed() {
if (mCurrentScene != null) {
mCurrentScene.onBackPressed();
if (!sSceneManager.onBackPressed()) {
super.onBackPressed();
}
}
@@ -182,56 +104,13 @@ public abstract class StageActivity extends AbsActionBarActivity {
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
for (Scene scene : mSceneStack) {
scene.onSaveInstanceState(outState);
}
if (mCurrentScene != null) {
mCurrentScene.onSaveInstanceState(outState);
}
sSceneManager.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
protected void onRestoreInstanceState(@NotNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
for (Scene scene : mSceneStack) {
scene.onRestoreInstanceState(savedInstanceState);
}
if (mCurrentScene != null) {
mCurrentScene.onRestoreInstanceState(savedInstanceState);
}
sSceneManager.onRestoreInstanceState(savedInstanceState);
}
interface SceneAction {
public void doAction();
}
class StartSceneAction implements SceneAction {
private Scene mFromScene;
private Class mSceneClass;
public StartSceneAction(Scene fromScene, Class sceneClass) {
mFromScene = fromScene;
mSceneClass = sceneClass;
}
@Override
public void doAction() {
startScene(mFromScene, mSceneClass);
}
}
class FinishSceneAction implements SceneAction {
private Scene mScene;
public FinishSceneAction(Scene scene) {
mScene = scene;
}
@Override
public void doAction() {
finishScene(mScene);
}
}
}
@@ -23,6 +23,8 @@ import android.util.AttributeSet;
import android.util.SparseArray;
import android.widget.FrameLayout;
import org.jetbrains.annotations.NotNull;
public class StageLayout extends FrameLayout {
public StageLayout(Context context) {
@@ -43,12 +45,12 @@ public class StageLayout extends FrameLayout {
}
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
protected void dispatchSaveInstanceState(@NotNull SparseArray<Parcelable> container) {
// Do nothing
}
@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
protected void dispatchRestoreInstanceState(@NotNull SparseArray<Parcelable> container) {
// Do nothing
}
}
@@ -15,9 +15,9 @@
package com.hippo.util;
public class NotEqualsException extends Exception {
public class AssertError extends Error {
public NotEqualsException(String detailMessage) {
public AssertError(String detailMessage) {
super(detailMessage);
}
}
@@ -0,0 +1,23 @@
/*
* 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.util;
public class AssertException extends Exception {
public AssertException(String detailMessage) {
super(detailMessage);
}
}
@@ -17,22 +17,29 @@ package com.hippo.util;
public class AssertUtils {
public static void assertNotNull(Object object) throws NullPointerException {
assertNotNull(null, object);
}
public static void assertNotNull(String message, Object object)
throws NullPointerException {
public static void assertNotNull(String message, Object object) {
if (object == null) {
throw new NullPointerException(message);
throw new AssertError(message);
}
}
public static void assertEquals(String message, int expected, int actual)
throws NotEqualsException {
public static void assertEquals(String message, int expected, int actual) {
if (expected != actual) {
throw new NotEqualsException(message);
throw new AssertError(message);
}
}
public static void assertNotNullEx(String message, Object object)
throws AssertException {
if (object == null) {
throw new AssertException(message);
}
}
public static void assertEqualsEx(String message, int expected, int actual)
throws AssertException {
if (expected != actual) {
throw new AssertException(message);
}
}
}
@@ -33,6 +33,11 @@ public class DrawerFrameLayout extends FrameLayout {
private OnGetPaddingListener mOnGetPaddingListener;
private int mFitPaddingLeft = -1;
private int mFitPaddingTop = -1;
private int mFitPaddingRight = -1;
private int mFitPaddingBottom = -1;
public DrawerFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0, 0);
@@ -72,9 +77,13 @@ public class DrawerFrameLayout extends FrameLayout {
@SuppressWarnings("deprecation")
@Override
protected boolean fitSystemWindows(@NotNull Rect insets) {
mFitPaddingLeft = insets.left;
mFitPaddingTop = insets.top;
mFitPaddingRight = insets.right;
mFitPaddingBottom = insets.bottom;
if (mOnGetPaddingListener != null) {
mOnGetPaddingListener.onGetPadding(insets.left, insets.top,
insets.right, insets.bottom);
mOnGetPaddingListener.onGetPadding(mFitPaddingLeft, mFitPaddingTop,
mFitPaddingRight, mFitPaddingBottom);
}
insets.set(0, 0, 0, 0);
@@ -86,6 +95,22 @@ public class DrawerFrameLayout extends FrameLayout {
mOnGetPaddingListener = listener;
}
public int getFitPaddingLeft() {
return mFitPaddingLeft;
}
public int getFitPaddingTop() {
return mFitPaddingTop;
}
public int getFitPaddingRight() {
return mFitPaddingRight;
}
public int getFitPaddingBottom() {
return mFitPaddingBottom;
}
public interface OnGetPaddingListener {
public void onGetPadding(int l, int t, int r, int b);
}