diff options
6 files changed, 287 insertions, 19 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewPostDetailActivity.java index 9b34f58f..475d0001 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewPostDetailActivity.java @@ -1,10 +1,16 @@ package ml.docilealligator.infinityforreddit.Activity; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.os.VibrationEffect; +import android.os.Vibrator; import android.util.DisplayMetrics; import android.view.KeyEvent; import android.view.Menu; @@ -21,7 +27,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.content.res.ResourcesCompat; import androidx.core.graphics.drawable.DrawableCompat; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView; @@ -93,6 +101,7 @@ import ml.docilealligator.infinityforreddit.SortType; import ml.docilealligator.infinityforreddit.SortTypeSelectionCallback; import ml.docilealligator.infinityforreddit.Utils.APIUtils; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; +import ml.docilealligator.infinityforreddit.Utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -211,6 +220,12 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS private SlidrInterface mSlidrInterface; private Drawable mSavedIcon; private Drawable mUnsavedIcon; + private ColorDrawable backgroundLeft; + private ColorDrawable backgroundRight; + private Drawable drawableLeft; + private Drawable drawableRight; + private float swipeActionThreshold = 0.3f; + private ItemTouchHelper touchHelper; @Override protected void onCreate(Bundle savedInstanceState) { @@ -279,6 +294,7 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS mExpandChildren = !mSharedPreferences.getBoolean(SharedPreferencesUtils.SHOW_TOP_LEVEL_COMMENTS_FIRST, false); mGlide = Glide.with(this); + Resources resources = getResources(); mLocale = getResources().getConfiguration().locale; mLinearLayoutManager = new LinearLayoutManager(this); @@ -362,6 +378,115 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS }); } + boolean enableSwipeAction = mSharedPreferences.getBoolean(SharedPreferencesUtils.ENABLE_SWIPE_ACTION, false); + boolean vibrateWhenActionTriggered = mSharedPreferences.getBoolean(SharedPreferencesUtils.VIBRATE_WHEN_ACTION_TRIGGERED, true); + Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); + backgroundLeft = new ColorDrawable(mCustomThemeWrapper.getDownvoted()); + backgroundRight = new ColorDrawable(mCustomThemeWrapper.getUpvoted()); + drawableLeft = ResourcesCompat.getDrawable(resources, R.drawable.ic_arrow_downward_black_24dp, null); + drawableRight = ResourcesCompat.getDrawable(resources, R.drawable.ic_arrow_upward_black_24dp, null); + touchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() { + boolean exceedThreshold = false; + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + if (!(viewHolder instanceof CommentAndPostRecyclerViewAdapter.PostDetailBaseViewHolder) && + !(viewHolder instanceof CommentAndPostRecyclerViewAdapter.CommentViewHolder)) { + return makeMovementFlags(0, 0); + } + int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; + return makeMovementFlags(0, swipeFlags); + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() { + return true; + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + if (touchHelper != null) { + touchHelper.attachToRecyclerView(null); + touchHelper.attachToRecyclerView(mRecyclerView); + if (mAdapter != null) { + mAdapter.onItemSwipe(viewHolder, direction); + } + } + } + + @Override + public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + + View itemView = viewHolder.itemView; + int horizontalOffset = (int) Utils.convertDpToPixel(16, ViewPostDetailActivity.this); + if (dX > 0) { + if (dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { + if (!exceedThreshold) { + exceedThreshold = true; + if (vibrateWhenActionTriggered && v != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + v.vibrate(VibrationEffect.createOneShot(10, 175)); + } else { + //deprecated in API 26 + v.vibrate(10); + } + } + } + backgroundLeft.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + } else { + exceedThreshold = false; + backgroundLeft.setBounds(0, 0, 0, 0); + } + + drawableLeft.setBounds(itemView.getLeft() + ((int) dX) - horizontalOffset - drawableLeft.getIntrinsicWidth(), + (itemView.getBottom() + itemView.getTop() - drawableLeft.getIntrinsicHeight()) / 2, + itemView.getLeft() + ((int) dX) - horizontalOffset, + (itemView.getBottom() + itemView.getTop() + drawableLeft.getIntrinsicHeight()) / 2); + backgroundLeft.draw(c); + drawableLeft.draw(c); + } else if (dX < 0) { + if (-dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { + if (!exceedThreshold) { + exceedThreshold = true; + if (vibrateWhenActionTriggered && v != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + v.vibrate(VibrationEffect.createOneShot(10, 175)); + } else { + //deprecated in API 26 + v.vibrate(10); + } + } + } + backgroundRight.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + } else { + exceedThreshold = false; + backgroundRight.setBounds(0, 0, 0, 0); + } + drawableRight.setBounds(itemView.getRight() + ((int) dX) + horizontalOffset, + (itemView.getBottom() + itemView.getTop() - drawableRight.getIntrinsicHeight()) / 2, + itemView.getRight() + ((int) dX) + horizontalOffset + drawableRight.getIntrinsicWidth(), + (itemView.getBottom() + itemView.getTop() + drawableRight.getIntrinsicHeight()) / 2); + backgroundRight.draw(c); + drawableRight.draw(c); + } + } + + @Override + public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { + return swipeActionThreshold; + } + }); + + if (enableSwipeAction) { + touchHelper.attachToRecyclerView(mRecyclerView); + } + mSwipeRefreshLayout.setOnRefreshListener(() -> refresh(true, true)); mSmoothScroller = new LinearSmoothScroller(this) { @@ -383,7 +508,7 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS mNewAccountName = getIntent().getStringExtra(EXTRA_NEW_ACCOUNT_NAME); } - orientation = getResources().getConfiguration().orientation; + orientation = resources.getConfiguration().orientation; if (!mNullAccessToken && mAccessToken == null) { getCurrentAccountAndBindView(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java index 67447e0d..4874dd31 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java @@ -37,6 +37,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; import androidx.core.graphics.drawable.DrawableCompat; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -1783,6 +1784,22 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy mAutoplay = autoplay; } + public void onItemSwipe(RecyclerView.ViewHolder viewHolder, int direction) { + if (viewHolder instanceof PostDetailBaseViewHolder) { + if (direction == ItemTouchHelper.LEFT || direction == ItemTouchHelper.START) { + ((PostDetailBaseViewHolder) viewHolder).mUpvoteButton.performClick(); + } else { + ((PostDetailBaseViewHolder) viewHolder).mDownvoteButton.performClick(); + } + } else if (viewHolder instanceof CommentViewHolder) { + if (direction == ItemTouchHelper.LEFT || direction == ItemTouchHelper.START) { + ((CommentViewHolder) viewHolder).upvoteButton.performClick(); + } else { + ((CommentViewHolder) viewHolder).downvoteButton.performClick(); + } + } + } + @Override public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { if (holder instanceof CommentViewHolder) { @@ -1879,7 +1896,7 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy void retryFetchingMoreComments(); } - class PostDetailBaseViewHolder extends RecyclerView.ViewHolder { + public class PostDetailBaseViewHolder extends RecyclerView.ViewHolder { AspectRatioGifImageView mIconGifImageView; TextView mSubredditTextView; TextView mUserTextView; @@ -3109,7 +3126,7 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy } } - class CommentViewHolder extends RecyclerView.ViewHolder { + public class CommentViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.linear_layout_item_comment) LinearLayout linearLayout; @BindView(R.id.author_text_view_item_post_comment) diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentsListingRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentsListingRecyclerViewAdapter.java index eb37f28a..ded4c662 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentsListingRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentsListingRecyclerViewAdapter.java @@ -30,6 +30,7 @@ import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; import androidx.paging.PagedListAdapter; import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView; import java.util.Locale; @@ -528,11 +529,21 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment } } + public void onItemSwipe(RecyclerView.ViewHolder viewHolder, int direction) { + if (viewHolder instanceof CommentViewHolder) { + if (direction == ItemTouchHelper.LEFT || direction == ItemTouchHelper.START) { + ((CommentViewHolder) viewHolder).upvoteButton.performClick(); + } else { + ((CommentViewHolder) viewHolder).downvoteButton.performClick(); + } + } + } + public interface RetryLoadingMoreCallback { void retryLoadingMore(); } - class CommentViewHolder extends RecyclerView.ViewHolder { + public class CommentViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.linear_layout_item_comment) LinearLayout linearLayout; @BindView(R.id.vertical_block_item_post_comment) diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java index d9b3da20..74ac57cc 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java @@ -1298,22 +1298,16 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView public void onItemSwipe(RecyclerView.ViewHolder viewHolder, int direction) { if (viewHolder instanceof PostBaseViewHolder) { - Post post = getItem(viewHolder.getAdapterPosition()); - if (post != null) { - if (direction == ItemTouchHelper.LEFT || direction == ItemTouchHelper.START) { - ((PostBaseViewHolder) viewHolder).upvoteButton.performClick(); - } else { - ((PostBaseViewHolder) viewHolder).downvoteButton.performClick(); - } + if (direction == ItemTouchHelper.LEFT || direction == ItemTouchHelper.START) { + ((PostBaseViewHolder) viewHolder).upvoteButton.performClick(); + } else { + ((PostBaseViewHolder) viewHolder).downvoteButton.performClick(); } } else if (viewHolder instanceof PostCompactBaseViewHolder) { - Post post = getItem(viewHolder.getAdapterPosition()); - if (post != null) { - if (direction == ItemTouchHelper.LEFT || direction == ItemTouchHelper.START) { - ((PostCompactBaseViewHolder) viewHolder).upvoteButton.performClick(); - } else { - ((PostCompactBaseViewHolder) viewHolder).downvoteButton.performClick(); - } + if (direction == ItemTouchHelper.LEFT || direction == ItemTouchHelper.START) { + ((PostCompactBaseViewHolder) viewHolder).upvoteButton.performClick(); + } else { + ((PostCompactBaseViewHolder) viewHolder).downvoteButton.performClick(); } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/CommentsListingFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/CommentsListingFragment.java index 6a866fef..5be5e0ca 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/CommentsListingFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/CommentsListingFragment.java @@ -5,8 +5,13 @@ import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.os.VibrationEffect; +import android.os.Vibrator; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -16,8 +21,10 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.content.res.ResourcesCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -42,6 +49,7 @@ import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; import ml.docilealligator.infinityforreddit.SortType; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; +import ml.docilealligator.infinityforreddit.Utils.Utils; import retrofit2.Retrofit; @@ -97,6 +105,12 @@ public class CommentsListingFragment extends Fragment implements FragmentCommuni private LinearLayoutManager mLinearLayoutManager; private CommentsListingRecyclerViewAdapter mAdapter; private SortType sortType; + private ColorDrawable backgroundLeft; + private ColorDrawable backgroundRight; + private Drawable drawableLeft; + private Drawable drawableRight; + private float swipeActionThreshold = 0.3f; + private ItemTouchHelper touchHelper; public CommentsListingFragment() { // Required empty public constructor @@ -128,6 +142,114 @@ public class CommentsListingFragment extends Fragment implements FragmentCommuni } } + boolean enableSwipeAction = mSharedPreferences.getBoolean(SharedPreferencesUtils.ENABLE_SWIPE_ACTION, false); + boolean vibrateWhenActionTriggered = mSharedPreferences.getBoolean(SharedPreferencesUtils.VIBRATE_WHEN_ACTION_TRIGGERED, true); + Vibrator v = (Vibrator) mActivity.getSystemService(Context.VIBRATOR_SERVICE); + backgroundLeft = new ColorDrawable(customThemeWrapper.getDownvoted()); + backgroundRight = new ColorDrawable(customThemeWrapper.getUpvoted()); + drawableLeft = ResourcesCompat.getDrawable(resources, R.drawable.ic_arrow_downward_black_24dp, null); + drawableRight = ResourcesCompat.getDrawable(resources, R.drawable.ic_arrow_upward_black_24dp, null); + touchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() { + boolean exceedThreshold = false; + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + if (!(viewHolder instanceof CommentsListingRecyclerViewAdapter.CommentViewHolder)) { + return makeMovementFlags(0, 0); + } + int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; + return makeMovementFlags(0, swipeFlags); + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() { + return true; + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + if (touchHelper != null) { + touchHelper.attachToRecyclerView(null); + touchHelper.attachToRecyclerView(mCommentRecyclerView); + if (mAdapter != null) { + mAdapter.onItemSwipe(viewHolder, direction); + } + } + } + + @Override + public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + + View itemView = viewHolder.itemView; + int horizontalOffset = (int) Utils.convertDpToPixel(16, mActivity); + if (dX > 0) { + if (dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { + if (!exceedThreshold) { + exceedThreshold = true; + if (vibrateWhenActionTriggered && v != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + v.vibrate(VibrationEffect.createOneShot(10, 175)); + } else { + //deprecated in API 26 + v.vibrate(10); + } + } + } + backgroundLeft.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + } else { + exceedThreshold = false; + backgroundLeft.setBounds(0, 0, 0, 0); + } + + drawableLeft.setBounds(itemView.getLeft() + ((int) dX) - horizontalOffset - drawableLeft.getIntrinsicWidth(), + (itemView.getBottom() + itemView.getTop() - drawableLeft.getIntrinsicHeight()) / 2, + itemView.getLeft() + ((int) dX) - horizontalOffset, + (itemView.getBottom() + itemView.getTop() + drawableLeft.getIntrinsicHeight()) / 2); + backgroundLeft.draw(c); + drawableLeft.draw(c); + } else if (dX < 0) { + if (-dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { + if (!exceedThreshold) { + exceedThreshold = true; + if (vibrateWhenActionTriggered && v != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + v.vibrate(VibrationEffect.createOneShot(10, 175)); + } else { + //deprecated in API 26 + v.vibrate(10); + } + } + } + backgroundRight.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + } else { + exceedThreshold = false; + backgroundRight.setBounds(0, 0, 0, 0); + } + drawableRight.setBounds(itemView.getRight() + ((int) dX) + horizontalOffset, + (itemView.getBottom() + itemView.getTop() - drawableRight.getIntrinsicHeight()) / 2, + itemView.getRight() + ((int) dX) + horizontalOffset + drawableRight.getIntrinsicWidth(), + (itemView.getBottom() + itemView.getTop() + drawableRight.getIntrinsicHeight()) / 2); + backgroundRight.draw(c); + drawableRight.draw(c); + } + } + + @Override + public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { + return swipeActionThreshold; + } + }); + + if (enableSwipeAction) { + touchHelper.attachToRecyclerView(mCommentRecyclerView); + } + if (savedInstanceState == null) { getCurrentAccountAndBindView(resources); } else { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/PostFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/PostFragment.java index 37264783..f6361088 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/PostFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/PostFragment.java @@ -635,7 +635,6 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } Vibrator v = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); - // Vibrate for 500 milliseconds backgroundLeft = new ColorDrawable(customThemeWrapper.getDownvoted()); backgroundRight = new ColorDrawable(customThemeWrapper.getUpvoted()); drawableLeft = ResourcesCompat.getDrawable(activity.getResources(), R.drawable.ic_arrow_downward_black_24dp, null); |