diff --git a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java index 7c4ff4ac4..f819786e8 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java @@ -37,10 +37,16 @@ import com.hippo.ehviewer.Settings; import com.hippo.ehviewer.client.EhUrlOpener; import com.hippo.ehviewer.client.EhUtils; import com.hippo.ehviewer.ui.scene.BaseScene; +import com.hippo.ehviewer.ui.scene.DownloadLabelScene; import com.hippo.ehviewer.ui.scene.DownloadScene; import com.hippo.ehviewer.ui.scene.FavoritesScene; +import com.hippo.ehviewer.ui.scene.GalleryCommentsScene; +import com.hippo.ehviewer.ui.scene.GalleryDetailScene; +import com.hippo.ehviewer.ui.scene.GalleryInfoScene; import com.hippo.ehviewer.ui.scene.GalleryListScene; +import com.hippo.ehviewer.ui.scene.GalleryPreviewsScene; import com.hippo.ehviewer.ui.scene.LoginScene; +import com.hippo.ehviewer.ui.scene.ProgressScene; import com.hippo.ehviewer.ui.scene.WarningScene; import com.hippo.scene.Announcer; import com.hippo.scene.SceneFragment; @@ -62,6 +68,20 @@ public final class MainActivity extends StageActivity private FrameLayout mRightDrawer; private int mNavCheckedItem = 0; + static { + registerLaunchMode(WarningScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); + registerLaunchMode(LoginScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); + registerLaunchMode(GalleryListScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TOP); + registerLaunchMode(GalleryDetailScene.class, SceneFragment.LAUNCH_MODE_STANDARD); + registerLaunchMode(GalleryInfoScene.class, SceneFragment.LAUNCH_MODE_STANDARD); + registerLaunchMode(GalleryCommentsScene.class, SceneFragment.LAUNCH_MODE_STANDARD); + registerLaunchMode(GalleryPreviewsScene.class, SceneFragment.LAUNCH_MODE_STANDARD); + registerLaunchMode(DownloadScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); + registerLaunchMode(DownloadLabelScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); + registerLaunchMode(FavoritesScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); + registerLaunchMode(ProgressScene.class, SceneFragment.LAUNCH_MODE_STANDARD); + } + @Override public int getContainerViewId() { return R.id.fragment_container; @@ -267,9 +287,8 @@ public final class MainActivity extends StageActivity if (id == R.id.nav_homepage) { Bundle args = new Bundle(); args.putString(GalleryListScene.KEY_ACTION, GalleryListScene.ACTION_HOMEPAGE); - startScene(new Announcer(GalleryListScene.class) - .setArgs(args) - .setFlag(SceneFragment.FLAG_REMOVE_ALL_THE_OTHER_SCENES)); + startSceneFirstly(new Announcer(GalleryListScene.class) + .setArgs(args)); } else if (id == R.id.nav_whats_hot) { } else if (id == R.id.nav_favourite) { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseScene.java index 70b1a06c9..232e9f440 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseScene.java @@ -27,7 +27,7 @@ import android.view.ViewGroup; import com.hippo.ehviewer.ui.MainActivity; import com.hippo.scene.SceneFragment; -public class BaseScene extends SceneFragment { +public abstract class BaseScene extends SceneFragment { private boolean mViewCreated; diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java index 44b8ab0b0..c51e6a64a 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java @@ -115,12 +115,6 @@ public class DownloadScene extends ToolbarScene @WholeLifeCircle private List mList; - // TODO Only single instance - @Override - public int getLaunchMode() { - return LAUNCH_MODE_SINGLE_TOP; - } - @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.java index 3e5c72d7b..05eadfc38 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.java @@ -160,12 +160,6 @@ public class FavoritesScene extends BaseScene implements } }; - // TODO Only single instance - @Override - public int getLaunchMode() { - return LAUNCH_MODE_SINGLE_TOP; - } - @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java index 5180455b7..556eafd55 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java @@ -43,7 +43,6 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.WindowManager; import android.widget.TextView; import android.widget.Toast; @@ -144,17 +143,6 @@ public final class GalleryListScene extends BaseScene private int mNavCheckedId = 0; - @Override - public int getLaunchMode() { - return LAUNCH_MODE_SINGLE_TOP; - } - - @Override - public int getSoftInputMode() { - return WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN | - WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - } - private void handleArgs(Bundle args) { if (args == null) { return; diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/LoginScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/LoginScene.java index 0ce5050f9..37dd36f45 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/LoginScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/LoginScene.java @@ -27,7 +27,6 @@ import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.TextView; @@ -65,12 +64,6 @@ public final class LoginScene extends BaseScene implements EditText.OnEditorActi private int mRequestId; - @Override - public int getSoftInputMode() { - return WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE | - WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - } - @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/hippo/scene/Announcer.java b/app/src/main/java/com/hippo/scene/Announcer.java index 93770205d..e850cb231 100644 --- a/app/src/main/java/com/hippo/scene/Announcer.java +++ b/app/src/main/java/com/hippo/scene/Announcer.java @@ -23,7 +23,6 @@ public final class Announcer { Class clazz; Bundle args; TransitionHelper tranHelper; - int flag; SceneFragment requestFrom; int requestCode; @@ -41,11 +40,6 @@ public final class Announcer { return this; } - public Announcer setFlag(int flag) { - this.flag = flag; - return this; - } - public Announcer setRequestCode(SceneFragment requestFrom, int requestCode) { this.requestFrom = requestFrom; this.requestCode = requestCode; diff --git a/app/src/main/java/com/hippo/scene/SceneFragment.java b/app/src/main/java/com/hippo/scene/SceneFragment.java index 8ff0fe3b9..6ed1a1022 100644 --- a/app/src/main/java/com/hippo/scene/SceneFragment.java +++ b/app/src/main/java/com/hippo/scene/SceneFragment.java @@ -35,14 +35,13 @@ import java.util.List; public class SceneFragment extends Fragment { - @IntDef({LAUNCH_MODE_STANDARD, LAUNCH_MODE_SINGLE_TOP}) + @IntDef({LAUNCH_MODE_STANDARD, LAUNCH_MODE_SINGLE_TOP, LAUNCH_MODE_SINGLE_TASK}) @Retention(RetentionPolicy.SOURCE) - private @interface LaunchMode {} + public @interface LaunchMode {} public static final int LAUNCH_MODE_STANDARD = 0; public static final int LAUNCH_MODE_SINGLE_TOP = 1; - - public static final int FLAG_REMOVE_ALL_THE_OTHER_SCENES = 0x1; + public static final int LAUNCH_MODE_SINGLE_TASK = 2; /** Standard scene result: operation canceled. */ public static final int RESULT_CANCELED = 0; @@ -55,16 +54,6 @@ public class SceneFragment extends Fragment { List mRequestSceneTagList = new ArrayList<>(0); IntList mRequestCodeList = new IntList(0); - @LaunchMode - public int getLaunchMode() { - return LAUNCH_MODE_STANDARD; - } - - public int getSoftInputMode() { - return 0; // WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED | - // WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED - } - public void onNewArguments(@NonNull Bundle args) {} public void startScene(Announcer announcer) { diff --git a/app/src/main/java/com/hippo/scene/StageActivity.java b/app/src/main/java/com/hippo/scene/StageActivity.java index 16b578ce4..83a685821 100644 --- a/app/src/main/java/com/hippo/scene/StageActivity.java +++ b/app/src/main/java/com/hippo/scene/StageActivity.java @@ -27,9 +27,12 @@ import android.text.TextUtils; import android.util.Log; import com.hippo.ehviewer.R; +import com.hippo.yorozuya.AssertUtils; import com.hippo.yorozuya.IntIdGenerator; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; public abstract class StageActivity extends AppCompatActivity { @@ -43,12 +46,22 @@ public abstract class StageActivity extends AppCompatActivity { private static final String KEY_SCENE_TAG_LIST = "stage_activity_scene_tag_list"; private static final String KEY_NEXT_ID = "stage_activity_next_id"; - // TODO ArrayList or LinkedList private ArrayList mSceneTagList = new ArrayList<>(); private final AtomicInteger mIdGenerator = new AtomicInteger(); private int mStageId = IntIdGenerator.INVALID_ID; + private static final Map, Integer> sLaunchModeMap = new HashMap<>(); + + public static void registerLaunchMode(Class clazz, @SceneFragment.LaunchMode int launchMode) { + if (launchMode != SceneFragment.LAUNCH_MODE_STANDARD && + launchMode != SceneFragment.LAUNCH_MODE_SINGLE_TOP && + launchMode != SceneFragment.LAUNCH_MODE_SINGLE_TASK) { + throw new IllegalStateException("Invalid launch mode: " + launchMode); + } + sLaunchModeMap.put(clazz, launchMode); + } + public abstract int getContainerViewId(); @Override @@ -115,6 +128,15 @@ public abstract class StageActivity extends AppCompatActivity { return mStageId; } + public int getSceneLaunchMode(Class clazz) { + Integer integer = sLaunchModeMap.get(clazz); + if (integer == null) { + throw new RuntimeException("Not register " + clazz.getName()); + } else { + return integer; + } + } + private SceneFragment newSceneInstance(Class clazz) { try { return (SceneFragment) clazz.newInstance(); @@ -132,70 +154,104 @@ public abstract class StageActivity extends AppCompatActivity { Class clazz = announcer.clazz; Bundle args = announcer.args; TransitionHelper tranHelper = announcer.tranHelper; - boolean createNewScene = true; - boolean removeAllTheOthers = (announcer.flag & SceneFragment.FLAG_REMOVE_ALL_THE_OTHER_SCENES) != 0; - FragmentManager fragmentManager = getSupportFragmentManager(); + int launchMode = getSceneLaunchMode(clazz); - // Current fragment - Fragment currentFragment = null; - if (mSceneTagList.size() > 0) { - // Get last tag - String tag = mSceneTagList.get(mSceneTagList.size() - 1); - currentFragment = fragmentManager.findFragmentByTag(tag); - } - - // Launch mode single top - if (currentFragment instanceof SceneFragment && clazz.isInstance(currentFragment)) { - SceneFragment currentScene = (SceneFragment) currentFragment; - if (currentScene.getLaunchMode() == SceneFragment.LAUNCH_MODE_SINGLE_TOP) { - createNewScene = false; - if (args != null) { - currentScene.onNewArguments(args); + // Check LAUNCH_MODE_SINGLE_TASK + if (launchMode == SceneFragment.LAUNCH_MODE_SINGLE_TASK) { + for (int i = 0, n = mSceneTagList.size(); i < n; i++) { + String tag = mSceneTagList.get(i); + Fragment fragment = fragmentManager.findFragmentByTag(tag); + if (fragment == null) { + Log.e(TAG, "Can't find fragment with tag: " + tag); + continue; } - if (!removeAllTheOthers) { - // Check request - if (announcer.requestFrom != null) { - currentScene.addRequest(announcer.requestFrom.getTag(), announcer.requestCode); + + if (clazz.isInstance(fragment)) { // Get it + FragmentTransaction transaction = fragmentManager.beginTransaction(); + + // Use default animation + transaction.setCustomAnimations(R.anim.scene_open_enter, R.anim.scene_open_exit); + + // Remove top fragments + for (int j = i + 1; j < n; j++) { + String topTag = mSceneTagList.get(j); + Fragment topFragment = fragmentManager.findFragmentByTag(topTag); + if (null == topFragment) { + Log.e(TAG, "Can't find fragment with tag: " + topTag); + continue; + } + // Clear shared element + topFragment.setSharedElementEnterTransition(null); + topFragment.setSharedElementReturnTransition(null); + topFragment.setEnterTransition(null); + topFragment.setExitTransition(null); + // Remove it + transaction.remove(topFragment); } - // Done! + + // Remove tag from index i+1 + mSceneTagList.subList(i + 1, mSceneTagList.size()).clear(); + + // Attach fragment + if (fragment.isDetached()) { + transaction.attach(fragment); + } + + // Commit + transaction.commit(); + + // New arguments + if (args != null && fragment instanceof SceneFragment) { + // TODO Call onNewArguments when view created ? + ((SceneFragment) fragment).onNewArguments(args); + } + return; } } } - SceneFragment newScene = null; - String newTag = null; - if (createNewScene) { - // Create new scene - newScene = newSceneInstance(clazz); - newScene.setArguments(args); - - // Create new scene tag - newTag = Integer.toString(mIdGenerator.getAndIncrement()); - - // Add new tag to list - mSceneTagList.add(newTag); + // Get current fragment + SceneFragment currentScene = null; + if (mSceneTagList.size() > 0) { + // Get last tag + String tag = mSceneTagList.get(mSceneTagList.size() - 1); + Fragment fragment = fragmentManager.findFragmentByTag(tag); + if (fragment != null) { + AssertUtils.assertInstanceOf(fragment, SceneFragment.class); + currentScene = (SceneFragment) fragment; + } } - // 1. createNewScene false, removeAllTheOthers false - // Will not go here - // 2. createNewScene false, removeAllTheOthers true - // Keep current scene, remove all the others, no animation - // 3. createNewScene true, removeAllTheOthers false - // Add new scene, detach current fragment, with animation if exist currentFragment - // 4. createNewScene true, removeAllTheOthers true - // Add new scene, remove all the others, with animation if exist currentFragment + // Check LAUNCH_MODE_SINGLE_TASK + if (clazz.isInstance(currentScene) && launchMode == SceneFragment.LAUNCH_MODE_SINGLE_TOP) { + if (args != null) { + currentScene.onNewArguments(args); + } + return; + } + + // Create new scene + SceneFragment newScene = newSceneInstance(clazz); + newScene.setArguments(args); + + // Create new scene tag + String newTag = Integer.toString(mIdGenerator.getAndIncrement()); + + // Add new tag to list + mSceneTagList.add(newTag); + FragmentTransaction transaction = fragmentManager.beginTransaction(); // Animation - if (newScene != null && currentFragment != null) { + if (currentScene != null) { if (tranHelper == null || !tranHelper.onTransition( - this, transaction, currentFragment, newScene)) { + this, transaction, currentScene, newScene)) { // Clear shared item - currentFragment.setSharedElementEnterTransition(null); - currentFragment.setSharedElementReturnTransition(null); - currentFragment.setEnterTransition(null); - currentFragment.setExitTransition(null); + currentScene.setSharedElementEnterTransition(null); + currentScene.setSharedElementReturnTransition(null); + currentScene.setEnterTransition(null); + currentScene.setExitTransition(null); newScene.setSharedElementEnterTransition(null); newScene.setSharedElementReturnTransition(null); newScene.setEnterTransition(null); @@ -203,43 +259,98 @@ public abstract class StageActivity extends AppCompatActivity { // Set default animation transaction.setCustomAnimations(R.anim.scene_open_enter, R.anim.scene_open_exit); } - } - // Remove scene - if (removeAllTheOthers) { - int startIndex = mSceneTagList.size() - 2; - // Remove scene - for (int i = startIndex; i >= 0; i--) { - String tag = mSceneTagList.get(i); - Fragment fragment = fragmentManager.findFragmentByTag(tag); - if (fragment != null) { - transaction.remove(fragment); - } else { - Log.d(TAG, "Can't find fragment with tag: " + tag); - } - } - // Remove scene tag - if (startIndex >= 0) { - mSceneTagList.subList(0, startIndex + 1).clear(); + // Detach current scene + if (!currentScene.isDetached()) { + transaction.detach(currentScene); + } else { + Log.e(TAG, "Current scene is detached"); } } - // Detach - if (!removeAllTheOthers && currentFragment != null) { - transaction.detach(currentFragment); - } - // Add - if (newScene != null) { - transaction.add(getContainerViewId(), newScene, newTag); - } + + // Add new scene + transaction.add(getContainerViewId(), newScene, newTag); + + // Commit transaction.commit(); // Check request - if (newScene != null && announcer.requestFrom != null) { + if (announcer.requestFrom != null) { newScene.addRequest(announcer.requestFrom.getTag(), announcer.requestCode); } + } - // Update SoftInputMode - if (newScene != null) { - getWindow().setSoftInputMode(newScene.getSoftInputMode()); + public void startSceneFirstly(Announcer announcer) { + Class clazz = announcer.clazz; + Bundle args = announcer.args; + FragmentManager fragmentManager = getSupportFragmentManager(); + int launchMode = getSceneLaunchMode(clazz); + boolean forceNewScene = launchMode == SceneFragment.LAUNCH_MODE_STANDARD; + boolean createNewScene = true; + boolean findScene = false; + SceneFragment scene = null; + + FragmentTransaction transaction = fragmentManager.beginTransaction(); + + // Set default animation + transaction.setCustomAnimations(R.anim.scene_open_enter, R.anim.scene_open_exit); + + String findSceneTag = null; + for (int i = 0, n = mSceneTagList.size(); i < n; i++) { + String tag = mSceneTagList.get(i); + Fragment fragment = fragmentManager.findFragmentByTag(tag); + if (fragment == null) { + Log.e(TAG, "Can't find fragment with tag: " + tag); + continue; + } + + // Clear shared element + fragment.setSharedElementEnterTransition(null); + fragment.setSharedElementReturnTransition(null); + fragment.setEnterTransition(null); + fragment.setExitTransition(null); + + // Check is target scene + if (!forceNewScene && !findScene && clazz.isInstance(fragment) && + (launchMode == SceneFragment.LAUNCH_MODE_SINGLE_TASK || !fragment.isDetached())) { + scene = (SceneFragment) fragment; + findScene = true; + createNewScene = false; + findSceneTag = tag; + if (fragment.isDetached()) { + transaction.attach(fragment); + } + } else { + // Remove it + transaction.remove(fragment); + } + } + + // Handle tag list + mSceneTagList.clear(); + if (null != findSceneTag) { + mSceneTagList.add(findSceneTag); + } + + if (createNewScene) { + scene = newSceneInstance(clazz); + scene.setArguments(args); + + // Create scene tag + String tag = Integer.toString(mIdGenerator.getAndIncrement()); + + // Add tag to list + mSceneTagList.add(tag); + + // Add scene + transaction.add(getContainerViewId(), scene, tag); + } + + // Commit + transaction.commit(); + + if (!createNewScene && args != null) { + // TODO Call onNewArguments when view created ? + scene.onNewArguments(args); } } @@ -325,11 +436,6 @@ public abstract class StageActivity extends AppCompatActivity { if (scene instanceof SceneFragment) { ((SceneFragment) scene).returnResult(this); } - - // Update SoftInputMode - if (next instanceof SceneFragment) { - getWindow().setSoftInputMode(((SceneFragment) next).getSoftInputMode()); - } } @Override diff --git a/yorozuya b/yorozuya index 6d4c3d943..0ae84aa55 160000 --- a/yorozuya +++ b/yorozuya @@ -1 +1 @@ -Subproject commit 6d4c3d943b8fb1567306b7df717d8aba3913371e +Subproject commit 0ae84aa55e4c67aead261423938c31c7df44ba68