Show skip to bottom FAB while scrolling down (#752)

This commit is contained in:
Benoit Marty 2020-01-08 14:49:26 +01:00
parent 8ef5c60e2e
commit 7575cb286e
3 changed files with 38 additions and 17 deletions

View File

@ -12,6 +12,7 @@ Improvements 🙌:
- Improve devices list screen - Improve devices list screen
- Add settings for rageshake sensibility - Add settings for rageshake sensibility
- Fix autocompletion issues and add support for rooms, groups, and emoji (#780) - Fix autocompletion issues and add support for rooms, groups, and emoji (#780)
- Show skip to bottom FAB while scrolling down (#752)
Other changes: Other changes:
- Change the way RiotX identifies a session to allow the SDK to support several sessions with the same user (#800) - Change the way RiotX identifies a session to allow the SDK to support several sessions with the same user (#800)

View File

@ -24,11 +24,9 @@ internal class Debouncer(private val handler: Handler) {
private val runnables = HashMap<String, Runnable>() private val runnables = HashMap<String, Runnable>()
fun debounce(identifier: String, millis: Long, r: Runnable): Boolean { fun debounce(identifier: String, millis: Long, r: Runnable): Boolean {
if (runnables.containsKey(identifier)) {
// debounce // debounce
val old = runnables[identifier] cancel(identifier)
handler.removeCallbacks(old)
}
insertRunnable(identifier, r, millis) insertRunnable(identifier, r, millis)
return true return true
} }
@ -37,6 +35,14 @@ internal class Debouncer(private val handler: Handler) {
handler.removeCallbacksAndMessages(null) 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) { private fun insertRunnable(identifier: String, r: Runnable, millis: Long) {
val chained = Runnable { val chained = Runnable {
handler.post(r) handler.post(r)

View File

@ -474,21 +474,31 @@ class RoomDetailFragment @Inject constructor(
it.dispatchTo(scrollOnNewMessageCallback) it.dispatchTo(scrollOnNewMessageCallback)
it.dispatchTo(scrollOnHighlightedEventCallback) it.dispatchTo(scrollOnHighlightedEventCallback)
updateJumpToReadMarkerViewVisibility() updateJumpToReadMarkerViewVisibility()
updateJumpToBottomViewVisibility() maybeShowJumpToBottomViewVisibilityWithDelay()
} }
timelineEventController.addModelBuildListener(modelBuildListener) timelineEventController.addModelBuildListener(modelBuildListener)
recyclerView.adapter = timelineEventController.adapter recyclerView.adapter = timelineEventController.adapter
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { 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) { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
when (newState) { when (newState) {
RecyclerView.SCROLL_STATE_IDLE -> { RecyclerView.SCROLL_STATE_IDLE -> {
updateJumpToBottomViewVisibility() maybeShowJumpToBottomViewVisibilityWithDelay()
} }
RecyclerView.SCROLL_STATE_DRAGGING, RecyclerView.SCROLL_STATE_DRAGGING,
RecyclerView.SCROLL_STATE_SETTLING -> { RecyclerView.SCROLL_STATE_SETTLING -> Unit
jumpToBottomView.hide()
}
} }
} }
}) })
@ -547,15 +557,19 @@ class RoomDetailFragment @Inject constructor(
} }
} }
private fun updateJumpToBottomViewVisibility() { private fun maybeShowJumpToBottomViewVisibilityWithDelay() {
debouncer.debounce("jump_to_bottom_visibility", 250, Runnable { debouncer.debounce("jump_to_bottom_visibility", 250, Runnable {
maybeShowJumpToBottomViewVisibility()
})
}
private fun maybeShowJumpToBottomViewVisibility() {
Timber.v("First visible: ${layoutManager.findFirstCompletelyVisibleItemPosition()}") Timber.v("First visible: ${layoutManager.findFirstCompletelyVisibleItemPosition()}")
if (layoutManager.findFirstVisibleItemPosition() != 0) { if (layoutManager.findFirstVisibleItemPosition() != 0) {
jumpToBottomView.show() jumpToBottomView.show()
} else { } else {
jumpToBottomView.hide() jumpToBottomView.hide()
} }
})
} }
private fun setupComposer() { private fun setupComposer() {