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 2f5db57ccb..627d757574 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 @@ -19,7 +19,7 @@ package im.vector.riotx.core.utils import android.os.Handler -internal class Debouncer(private val handler: Handler) { +class Debouncer(private val handler: Handler) { private val runnables = HashMap() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/JumpToBottomViewVisibilityManager.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/JumpToBottomViewVisibilityManager.kt new file mode 100644 index 0000000000..4be5502678 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/JumpToBottomViewVisibilityManager.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotx.features.home.room.detail + +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.floatingactionbutton.FloatingActionButton +import im.vector.riotx.core.utils.Debouncer +import timber.log.Timber + +/** + * Show or hide the jumpToBottomView, depending on the scrolling and if the timeline is displaying the more recent event + * - When user scrolls up (i.e. going to the past): hide + * - When user scrolls down: show if not displaying last event + * - When user stops scrolling: show if not displaying last event + */ +class JumpToBottomViewVisibilityManager( + private val jumpToBottomView: FloatingActionButton, + private val debouncer: Debouncer, + recyclerView: RecyclerView, + private val layoutManager: LinearLayoutManager) { + + init { + 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 -> { + maybeShowJumpToBottomViewVisibilityWithDelay() + } + RecyclerView.SCROLL_STATE_DRAGGING, + RecyclerView.SCROLL_STATE_SETTLING -> Unit + } + } + }) + } + + fun maybeShowJumpToBottomViewVisibilityWithDelay() { + debouncer.debounce("jump_to_bottom_visibility", 250, Runnable { + maybeShowJumpToBottomViewVisibility() + }) + } + + private fun maybeShowJumpToBottomViewVisibility() { + Timber.v("First visible: ${layoutManager.findFirstCompletelyVisibleItemPosition()}") + if (layoutManager.findFirstVisibleItemPosition() != 0) { + jumpToBottomView.show() + } else { + jumpToBottomView.hide() + } + } +} 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 4e29aa2f89..a956d0e2e9 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 @@ -181,6 +181,7 @@ class RoomDetailFragment @Inject constructor( private lateinit var sharedActionViewModel: MessageSharedActionViewModel private lateinit var layoutManager: LinearLayoutManager + private lateinit var jumpToBottomViewVisibilityManager: JumpToBottomViewVisibilityManager private var modelBuildListener: OnModelBuildFinishedListener? = null private lateinit var attachmentsHelper: AttachmentsHelper @@ -312,6 +313,13 @@ class RoomDetailFragment @Inject constructor( } } } + + jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager( + jumpToBottomView, + debouncer, + recyclerView, + layoutManager + ) } private fun setupJumpToReadMarkerView() { @@ -474,35 +482,11 @@ class RoomDetailFragment @Inject constructor( it.dispatchTo(scrollOnNewMessageCallback) it.dispatchTo(scrollOnHighlightedEventCallback) updateJumpToReadMarkerViewVisibility() - maybeShowJumpToBottomViewVisibilityWithDelay() + jumpToBottomViewVisibilityManager.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 -> { - maybeShowJumpToBottomViewVisibilityWithDelay() - } - RecyclerView.SCROLL_STATE_DRAGGING, - RecyclerView.SCROLL_STATE_SETTLING -> Unit - } - } - }) - timelineEventController.callback = this if (vectorPreferences.swipeToReplyIsEnabled()) { @@ -557,21 +541,6 @@ class RoomDetailFragment @Inject constructor( } } - private fun maybeShowJumpToBottomViewVisibilityWithDelay() { - debouncer.debounce("jump_to_bottom_visibility", 250, Runnable { - 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)