From 7cfc4296a0c6e429a07a8cc8cdc32489220cb04b Mon Sep 17 00:00:00 2001 From: Alex Ning Date: Sat, 8 Jun 2019 08:01:31 +0800 Subject: [PATCH] Lazy Mode: Automatically scroll down the recyclerview in PostFragment to view posts without using hands. --- .../FragmentCommunicator.java | 2 + .../infinityforreddit/MainActivity.java | 75 +++++++++++++---- .../infinityforreddit/PostFragment.java | 83 +++++++++++++++++++ app/src/main/res/layout/app_bar_main.xml | 1 + app/src/main/res/menu/main_activity.xml | 19 +++-- app/src/main/res/values/strings.xml | 5 ++ 6 files changed, 161 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FragmentCommunicator.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FragmentCommunicator.java index 019a6f0d..58707c1a 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/FragmentCommunicator.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FragmentCommunicator.java @@ -2,4 +2,6 @@ package ml.docilealligator.infinityforreddit; interface FragmentCommunicator { void refresh(); + default void startLazyMode() {}; + default void stopLazyMode() {}; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java index 012c1503..0192acea 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java @@ -12,10 +12,23 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.bumptech.glide.Glide; import com.bumptech.glide.RequestManager; import com.bumptech.glide.request.RequestOptions; import com.ferfalk.simplesearchview.SimpleSearchView; +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.CollapsingToolbarLayout; import java.util.ArrayList; @@ -30,15 +43,6 @@ import SubscribedSubredditDatabase.SubscribedSubredditViewModel; import SubscribedUserDatabase.SubscribedUserData; import SubscribedUserDatabase.SubscribedUserRoomDatabase; import SubscribedUserDatabase.SubscribedUserViewModel; -import androidx.appcompat.app.ActionBarDrawerToggle; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import androidx.core.view.GravityCompat; -import androidx.drawerlayout.widget.DrawerLayout; -import androidx.fragment.app.Fragment; -import androidx.lifecycle.ViewModelProviders; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; import butterknife.ButterKnife; import jp.wasabeef.glide.transformations.RoundedCornersTransformation; @@ -50,10 +54,12 @@ public class MainActivity extends AppCompatActivity { private static final String FRAGMENT_OUT_STATE = "FOS"; private static final String FETCH_USER_INFO_STATE = "FUIS"; private static final String INSERT_SUBSCRIBED_SUBREDDIT_STATE = "ISSS"; + private static final String IS_IN_LAZY_MODE_STATE = "IILMS"; private static final int LOGIN_ACTIVITY_REQUEST_CODE = 0; @BindView(R.id.drawer_layout) DrawerLayout drawer; + @BindView(R.id.collapsing_toolbar_layout_main_activity) CollapsingToolbarLayout collapsingToolbarLayout; @BindView(R.id.search_view_main_activity) SimpleSearchView simpleSearchView; @BindView(R.id.transparent_overlay_main_activity) View transparentOverlay; @BindView(R.id.subscribed_subreddit_recycler_view_main_activity) RecyclerView subscribedSubredditRecyclerView; @@ -69,6 +75,7 @@ public class MainActivity extends AppCompatActivity { private Fragment mFragment; private RequestManager glide; + private AppBarLayout.LayoutParams params; private String mName; private String mProfileImageUrl; @@ -77,9 +84,13 @@ public class MainActivity extends AppCompatActivity { private boolean mFetchUserInfoSuccess = false; private boolean mInsertSuccess = false; + private Menu mMenu; + private SubscribedSubredditViewModel mSubscribedSubredditViewModel; private SubscribedUserViewModel mSubscribedUserViewModel; + private boolean isInLazyMode = false; + @Inject @Named("user_info") SharedPreferences mUserInfoSharedPreferences; @@ -109,6 +120,8 @@ public class MainActivity extends AppCompatActivity { drawer.addDrawerListener(toggle); toggle.syncState(); + params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams(); + transparentOverlay.setOnClickListener(view -> simpleSearchView.onBackPressed()); simpleSearchView.setOnQueryTextListener(new SimpleSearchView.OnQueryTextListener() { @@ -170,6 +183,7 @@ public class MainActivity extends AppCompatActivity { mFetchUserInfoSuccess = savedInstanceState.getBoolean(FETCH_USER_INFO_STATE); mInsertSuccess = savedInstanceState.getBoolean(INSERT_SUBSCRIBED_SUBREDDIT_STATE); + isInLazyMode = savedInstanceState.getBoolean(IS_IN_LAZY_MODE_STATE); } glide = Glide.with(this); @@ -347,23 +361,49 @@ public class MainActivity extends AppCompatActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_activity, menu); - - simpleSearchView.setMenuItem(menu.findItem(R.id.action_search_main_activity)); + mMenu = menu; + simpleSearchView.setMenuItem(mMenu.findItem(R.id.action_search_main_activity)); + MenuItem lazyModeItem = mMenu.findItem(R.id.action_lazy_mode_main_activity); + if(isInLazyMode) { + lazyModeItem.setTitle(R.string.action_stop_lazy_mode); + params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL); + collapsingToolbarLayout.setLayoutParams(params); + } else { + lazyModeItem.setTitle(R.string.action_start_lazy_mode); + params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); + collapsingToolbarLayout.setLayoutParams(params); + } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_refresh_main_activity: - if (mFragment instanceof FragmentCommunicator) { + if (mFragment instanceof FragmentCommunicator) { + switch (item.getItemId()) { + case R.id.action_refresh_main_activity: ((FragmentCommunicator) mFragment).refresh(); mFetchUserInfoSuccess = false; mInsertSuccess = false; loadUserData(); - } - return true; + return true; + case R.id.action_lazy_mode_main_activity: + MenuItem lazyModeItem = mMenu.findItem(R.id.action_lazy_mode_main_activity); + if(isInLazyMode) { + isInLazyMode = false; + ((FragmentCommunicator) mFragment).stopLazyMode(); + lazyModeItem.setTitle(R.string.action_start_lazy_mode); + params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); + collapsingToolbarLayout.setLayoutParams(params); + } else { + isInLazyMode = true; + ((FragmentCommunicator) mFragment).startLazyMode(); + lazyModeItem.setTitle(R.string.action_stop_lazy_mode); + params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL); + collapsingToolbarLayout.setLayoutParams(params); + } + return true; + } } return false; } @@ -383,7 +423,7 @@ public class MainActivity extends AppCompatActivity { } @Override - protected void onSaveInstanceState(Bundle outState) { + protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); if (mFragment != null) { getSupportFragmentManager().putFragment(outState, FRAGMENT_OUT_STATE, mFragment); @@ -391,5 +431,6 @@ public class MainActivity extends AppCompatActivity { outState.putBoolean(FETCH_USER_INFO_STATE, mFetchUserInfoSuccess); outState.putBoolean(INSERT_SUBSCRIBED_SUBREDDIT_STATE, mInsertSuccess); + outState.putBoolean(IS_IN_LAZY_MODE_STATE, isInLazyMode); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java index 2d286377..50878fdd 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java @@ -4,18 +4,23 @@ package ml.docilealligator.infinityforreddit; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; +import android.os.Handler; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProviders; import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; @@ -39,6 +44,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { static final String NAME_KEY = "NK"; static final String POST_TYPE_KEY = "PTK"; + private static final String IS_IN_LAZY_MODE_STATE = "IILMS"; @BindView(R.id.coordinator_layout_post_fragment) CoordinatorLayout mCoordinatorLayout; @BindView(R.id.recycler_view_post_fragment) RecyclerView mPostRecyclerView; @@ -51,11 +57,17 @@ public class PostFragment extends Fragment implements FragmentCommunicator { private String mName; private int mPostType; + private boolean isInLazyMode = false; private PostRecyclerViewAdapter mAdapter; + private RecyclerView.SmoothScroller smoothScroller; PostViewModel mPostViewModel; + private Window window; + private Handler lazyModeHandler; + private Runnable lazyModeRunnable; + @Inject @Named("no_oauth") Retrofit mRetrofit; @@ -89,6 +101,24 @@ public class PostFragment extends Fragment implements FragmentCommunicator { EventBus.getDefault().register(this); + lazyModeHandler = new Handler(); + + smoothScroller = new LinearSmoothScroller(getActivity()) { + @Override + protected int getVerticalSnapPreference() { + return LinearSmoothScroller.SNAP_TO_START; + } + }; + + window = getActivity().getWindow(); + + if(savedInstanceState != null) { + isInLazyMode = savedInstanceState.getBoolean(IS_IN_LAZY_MODE_STATE); + if(isInLazyMode) { + startLazyMode(); + } + } + mLinearLayoutManager = new LinearLayoutManager(getActivity()); mPostRecyclerView.setLayoutManager(mLinearLayoutManager); @@ -165,6 +195,12 @@ public class PostFragment extends Fragment implements FragmentCommunicator { return rootView; } + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(IS_IN_LAZY_MODE_STATE, isInLazyMode); + } + @Override public void refresh() { mPostViewModel.refresh(); @@ -179,6 +215,36 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } } + @Override + public void startLazyMode() { + Toast.makeText(getActivity(), getString(R.string.lazy_mode_start, 2.5), Toast.LENGTH_SHORT).show(); + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + isInLazyMode = true; + lazyModeRunnable = new Runnable() { + @Override + public void run() { + int nPosts = mAdapter.getItemCount(); + int firstVisiblePosition = mLinearLayoutManager.findFirstVisibleItemPosition(); + if(firstVisiblePosition != RecyclerView.NO_POSITION && nPosts > firstVisiblePosition) { + smoothScroller.setTargetPosition(firstVisiblePosition + 1); + mLinearLayoutManager.startSmoothScroll(smoothScroller); + } + if(isInLazyMode) { + lazyModeHandler.postDelayed(this, 2500); + } + } + }; + lazyModeHandler.postDelayed(lazyModeRunnable, 2500); + } + + @Override + public void stopLazyMode() { + lazyModeHandler.removeCallbacks(lazyModeRunnable); + window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + isInLazyMode = false; + Toast.makeText(getActivity(), getString(R.string.lazy_mode_stop), Toast.LENGTH_SHORT).show(); + } + @Subscribe public void onPostUpdateEvent(PostUpdateEventToPostList event) { Post post = mAdapter.getCurrentList().get(event.positionInList); @@ -190,6 +256,23 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } } + @Override + public void onStart() { + super.onStart(); + if(isInLazyMode) { + startLazyMode(); + } + } + + @Override + public void onStop() { + super.onStop(); + if(isInLazyMode) { + stopLazyMode(); + } + isInLazyMode = true; + } + @Override public void onDestroy() { EventBus.getDefault().unregister(this); diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index 483a7e55..f7efde6c 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -12,6 +12,7 @@ android:theme="@style/AppTheme.AppBarOverlay"> - - + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bf1a320d..0d23c7ca 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -10,6 +10,8 @@ Download Refresh Search + Start Lazy Mode + Stop Lazy Mode Error loading image. Tap to retry. Error loading posts.\nTap to retry. @@ -63,4 +65,7 @@ Infinity Search anything + Lazy Mode starts in %1$fs + Lazy Mode stopped +