Lazy Mode: Automatically scroll down the recyclerview in PostFragment to view posts without using hands.

This commit is contained in:
Alex Ning 2019-06-08 08:01:31 +08:00
parent d7a90b5397
commit 7cfc4296a0
6 changed files with 161 additions and 24 deletions

View File

@ -2,4 +2,6 @@ package ml.docilealligator.infinityforreddit;
interface FragmentCommunicator {
void refresh();
default void startLazyMode() {};
default void stopLazyMode() {};
}

View File

@ -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,24 +361,50 @@ 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) {
if (mFragment instanceof FragmentCommunicator) {
switch (item.getItemId()) {
case R.id.action_refresh_main_activity:
if (mFragment instanceof FragmentCommunicator) {
((FragmentCommunicator) mFragment).refresh();
mFetchUserInfoSuccess = false;
mInsertSuccess = false;
loadUserData();
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);
}
}

View File

@ -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);

View File

@ -12,6 +12,7 @@
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout_main_activity"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:titleEnabled="false"

View File

@ -3,17 +3,22 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="ml.docilealligator.infinityforreddit.MainActivity">
<item
android:id="@+id/action_refresh_main_activity"
android:orderInCategory="2"
android:title="@string/action_refresh"
android:icon="@drawable/ic_refresh_white_24dp"
app:showAsAction="never" />
<item
android:id="@+id/action_search_main_activity"
android:orderInCategory="1"
android:title="@string/action_search"
android:icon="@drawable/ic_search_white_24dp"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_refresh_main_activity"
android:orderInCategory="2"
android:title="@string/action_refresh"
app:showAsAction="never" />
<item
android:id="@+id/action_lazy_mode_main_activity"
android:orderInCategory="3"
android:title="@string/action_start_lazy_mode"
app:showAsAction="never" />
</menu>

View File

@ -10,6 +10,8 @@
<string name="action_download">Download</string>
<string name="action_refresh">Refresh</string>
<string name="action_search">Search</string>
<string name="action_start_lazy_mode">Start Lazy Mode</string>
<string name="action_stop_lazy_mode">Stop Lazy Mode</string>
<string name="tap_to_retry">Error loading image. Tap to retry.</string>
<string name="load_posts_error">Error loading posts.\nTap to retry.</string>
@ -63,4 +65,7 @@
<string name="app_label">Infinity</string>
<string name="search_hint">Search anything</string>
<string name="lazy_mode_start">Lazy Mode starts in %1$fs</string>
<string name="lazy_mode_stop">Lazy Mode stopped</string>
</resources>