From 7575cb286ed9056469a2962e3e80a29e992f0902 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 8 Jan 2020 14:49:26 +0100 Subject: [PATCH] Show skip to bottom FAB while scrolling down (#752) --- CHANGES.md | 1 + .../im/vector/riotx/core/utils/Debouncer.kt | 16 +++++--- .../home/room/detail/RoomDetailFragment.kt | 38 +++++++++++++------ 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index bb132982d8..3087b7405c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ Improvements 🙌: - Improve devices list screen - Add settings for rageshake sensibility - Fix autocompletion issues and add support for rooms, groups, and emoji (#780) + - Show skip to bottom FAB while scrolling down (#752) Other changes: - Change the way RiotX identifies a session to allow the SDK to support several sessions with the same user (#800) diff --git a/vector/src/main/java/im/vector/riotx/core/utils/Debouncer.kt b/vector/src/main/java/im/vector/riotx/core/utils/Debouncer.kt index b02e3c9366..2f5db57ccb 100644 --- a/vector/src/main/java/im/vector/riotx/core/utils/Debouncer.kt +++ b/vector/src/main/java/im/vector/riotx/core/utils/Debouncer.kt @@ -24,11 +24,9 @@ internal class Debouncer(private val handler: Handler) { private val runnables = HashMap() fun debounce(identifier: String, millis: Long, r: Runnable): Boolean { - if (runnables.containsKey(identifier)) { - // debounce - val old = runnables[identifier] - handler.removeCallbacks(old) - } + // debounce + cancel(identifier) + insertRunnable(identifier, r, millis) return true } @@ -37,6 +35,14 @@ internal class Debouncer(private val handler: Handler) { handler.removeCallbacksAndMessages(null) } + fun cancel(identifier: String) { + if (runnables.containsKey(identifier)) { + val old = runnables[identifier] + handler.removeCallbacks(old) + runnables.remove(identifier) + } + } + private fun insertRunnable(identifier: String, r: Runnable, millis: Long) { val chained = Runnable { handler.post(r) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 4414c48205..4e29aa2f89 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -474,21 +474,31 @@ class RoomDetailFragment @Inject constructor( it.dispatchTo(scrollOnNewMessageCallback) it.dispatchTo(scrollOnHighlightedEventCallback) updateJumpToReadMarkerViewVisibility() - updateJumpToBottomViewVisibility() + maybeShowJumpToBottomViewVisibilityWithDelay() } timelineEventController.addModelBuildListener(modelBuildListener) recyclerView.adapter = timelineEventController.adapter recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + debouncer.cancel("jump_to_bottom_visibility") + + val scrollingToPast = dy < 0 + + if (scrollingToPast) { + jumpToBottomView.hide() + } else { + maybeShowJumpToBottomViewVisibility() + } + } + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { when (newState) { RecyclerView.SCROLL_STATE_IDLE -> { - updateJumpToBottomViewVisibility() + maybeShowJumpToBottomViewVisibilityWithDelay() } RecyclerView.SCROLL_STATE_DRAGGING, - RecyclerView.SCROLL_STATE_SETTLING -> { - jumpToBottomView.hide() - } + RecyclerView.SCROLL_STATE_SETTLING -> Unit } } }) @@ -547,17 +557,21 @@ class RoomDetailFragment @Inject constructor( } } - private fun updateJumpToBottomViewVisibility() { + private fun maybeShowJumpToBottomViewVisibilityWithDelay() { debouncer.debounce("jump_to_bottom_visibility", 250, Runnable { - Timber.v("First visible: ${layoutManager.findFirstCompletelyVisibleItemPosition()}") - if (layoutManager.findFirstVisibleItemPosition() != 0) { - jumpToBottomView.show() - } else { - jumpToBottomView.hide() - } + maybeShowJumpToBottomViewVisibility() }) } + private fun maybeShowJumpToBottomViewVisibility() { + Timber.v("First visible: ${layoutManager.findFirstCompletelyVisibleItemPosition()}") + if (layoutManager.findFirstVisibleItemPosition() != 0) { + jumpToBottomView.show() + } else { + jumpToBottomView.hide() + } + } + private fun setupComposer() { autoCompleter.setup(composerLayout.composerEditText, this)