Prefer staying scrolled to the bottom while composer is open

Change-Id: I962ce6850c0bb7e62b81f5620d56442afb7245f4
This commit is contained in:
SpiritCroc 2021-11-15 18:02:58 +01:00
parent ebd1592131
commit 3f448b48c7

View File

@ -881,7 +881,7 @@ class RoomDetailFragment @Inject constructor(
}
private fun navigateToEvent(action: RoomDetailViewEvents.NavigateToEvent) {
scrollOnNewMessageCallback.initialForceScroll = true
setInitialForceScrollEnabled(true)
scrollOnNewMessageCallback.initialForceScrollEventId = action.eventId
val scrollPosition = timelineEventController.searchPositionOfEvent(action.eventId)
if (scrollPosition == null) {
@ -1226,11 +1226,11 @@ class RoomDetailFragment @Inject constructor(
jumpToBottomViewVisibilityManager.maybeShowJumpToBottomViewVisibilityWithDelay()
}
}
layoutManager.setPreferredAnchorPlacement(1f - TARGET_SCROLL_OUT_FACTOR)
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
scrollOnNewMessageCallback = ScrollOnNewMessageCallback(layoutManager, timelineEventController, views.timelineRecyclerView)
// Force scroll until the user has scrolled to address the bug where the list would jump during initial loading
scrollOnNewMessageCallback.initialForceScroll = true
// Force scroll until the user has scrolled so we ensure that the targeted events are at a meaningful position when the timeline is loaded.
// This also sets the preferred anchor position which ensures a nicer expand direction of re-measuring views (e.g. due to url-previews).
setInitialForceScrollEnabled(true)
scrollOnHighlightedEventCallback = ScrollOnHighlightedEventCallback(views.timelineRecyclerView, layoutManager, timelineEventController)
views.timelineRecyclerView.layoutManager = layoutManager
views.timelineRecyclerView.itemAnimator = null
@ -1245,8 +1245,12 @@ class RoomDetailFragment @Inject constructor(
views.timelineRecyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (dy != 0) {
// User has scrolled, stop force scrolling
scrollOnNewMessageCallback.initialForceScroll = false
// User has scrolled, stop force scrolling.
// Also, restore the preferred anchor placement in case it has been temporarily disabled while the composer view is open.
setInitialForceScrollEnabled(false, stickToBottom = false)
// If we do not clear the focus manually, it will keep it forever?
// We want to listen to new focus events to re-enable the stickToBottom though.
views.composerLayout.views.composerEditText.clearFocus()
}
super.onScrolled(recyclerView, dx, dy)
}
@ -1408,6 +1412,11 @@ class RoomDetailFragment @Inject constructor(
views.composerLayout.views.composerEditText.focusChanges()
.subscribe {
if (it) {
// Prioritize staying scrolled at the bottom compared to keeping the unread messages line at the fixed position
setInitialForceScrollEnabled(false, stickToBottom = true)
}
roomDetailViewModel.handle(RoomDetailAction.ComposerFocusChange(it))
}
.disposeOnDestroyView()
@ -2244,4 +2253,14 @@ class RoomDetailFragment @Inject constructor(
}
}
}
private fun setInitialForceScrollEnabled(enabled: Boolean, stickToBottom: Boolean = false) {
scrollOnNewMessageCallback.initialForceScroll = enabled
if (stickToBottom) {
layoutManager.disablePreferredAnchorPlacement()
} else {
// (Re-) Enable preferred anchor placement
layoutManager.setPreferredAnchorPlacement(1f - TARGET_SCROLL_OUT_FACTOR)
}
}
}