mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 04:58:45 +00:00
Fix incorrect read state causing stale notifications and tweak scroll to bottom behavior.
This commit is contained in:
@@ -373,6 +373,11 @@ class ConversationFragment :
|
||||
adapter.unregisterAdapterDataObserver(it)
|
||||
}
|
||||
|
||||
scrollListener?.let {
|
||||
_binding.conversationItemRecycler.removeOnScrollListener(it)
|
||||
}
|
||||
scrollListener = null
|
||||
|
||||
_binding.conversationItemRecycler.adapter = null
|
||||
|
||||
textDraftSaveDebouncer.clear()
|
||||
@@ -473,6 +478,7 @@ class ConversationFragment :
|
||||
private var composeTextEventsListener: ComposeTextEventsListener? = null
|
||||
private var dataObserver: DataObserver? = null
|
||||
private var menuProvider: ConversationOptionsMenu.Provider? = null
|
||||
private var scrollListener: ScrollListener? = null
|
||||
|
||||
private val jumpAndPulseScrollStrategy = object : ScrollToPositionDelegate.ScrollStrategy {
|
||||
override fun performScroll(recyclerView: RecyclerView, layoutManager: LinearLayoutManager, position: Int, smooth: Boolean) {
|
||||
@@ -830,10 +836,6 @@ class ConversationFragment :
|
||||
.distinctUntilChanged { r1, r2 -> r1 === r2 || r1.hasSameContent(r2) }
|
||||
.subscribeBy(onNext = this::onRecipientChanged)
|
||||
|
||||
disposables += viewModel.markReadRequests
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeBy(onNext = markReadHelper::onViewsRevealed)
|
||||
|
||||
disposables += viewModel.scrollButtonState
|
||||
.subscribeBy(onNext = this::presentScrollButtons)
|
||||
|
||||
@@ -1448,7 +1450,8 @@ class ConversationFragment :
|
||||
layoutManager = ConversationLayoutManager(requireContext())
|
||||
binding.conversationItemRecycler.setHasFixedSize(false)
|
||||
binding.conversationItemRecycler.layoutManager = layoutManager
|
||||
binding.conversationItemRecycler.addOnScrollListener(ScrollListener())
|
||||
scrollListener = ScrollListener()
|
||||
binding.conversationItemRecycler.addOnScrollListener(scrollListener!!)
|
||||
|
||||
adapter = ConversationAdapterV2(
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
@@ -2248,6 +2251,10 @@ class ConversationFragment :
|
||||
return layoutManager.findFirstCompletelyVisibleItemPosition() > 4
|
||||
}
|
||||
|
||||
private fun shouldScrollToBottom(): Boolean {
|
||||
return isScrolledToBottom() || layoutManager.findFirstVisibleItemPosition() <= 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls animation and visibility of the scrollDateHeader.
|
||||
*/
|
||||
@@ -2308,9 +2315,11 @@ class ConversationFragment :
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
if (isScrolledToBottom()) {
|
||||
viewModel.setShowScrollButtons(false)
|
||||
viewModel.setShowScrollButtonsForScrollPosition(showScrollButtons = false, willScrollToBottomOnNewMessage = true)
|
||||
} else if (isScrolledPastButtonThreshold()) {
|
||||
viewModel.setShowScrollButtons(true)
|
||||
viewModel.setShowScrollButtonsForScrollPosition(showScrollButtons = true, willScrollToBottomOnNewMessage = false)
|
||||
} else {
|
||||
viewModel.setShowScrollButtonsForScrollPosition(showScrollButtons = false, willScrollToBottomOnNewMessage = shouldScrollToBottom())
|
||||
}
|
||||
|
||||
presentComposeDivider()
|
||||
@@ -2344,10 +2353,9 @@ class ConversationFragment :
|
||||
|
||||
private inner class DataObserver : RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||
Log.d(TAG, "onItemRangeInserted $positionStart $itemCount")
|
||||
if (positionStart == 0 && itemCount == 1 && !binding.conversationItemRecycler.canScrollVertically(1)) {
|
||||
Log.d(TAG, "Requesting scroll to bottom.")
|
||||
if (positionStart == 0 && itemCount == 1 && shouldScrollToBottom()) {
|
||||
layoutManager.scrollToPositionWithOffset(0, 0)
|
||||
scrollListener?.onScrolled(binding.conversationItemRecycler, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2369,6 +2377,10 @@ class ConversationFragment :
|
||||
actionMode?.setTitle(calculateSelectedItemCount())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
|
||||
scrollListener?.onScrolled(binding.conversationItemRecycler, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
//endregion Scroll Handling
|
||||
@@ -2820,10 +2832,7 @@ class ConversationFragment :
|
||||
|
||||
ViewUtil.hideKeyboard(requireContext(), itemView)
|
||||
|
||||
val showScrollButtons = viewModel.showScrollButtonsSnapshot
|
||||
if (showScrollButtons) {
|
||||
viewModel.setShowScrollButtons(false)
|
||||
}
|
||||
viewModel.setHideScrollButtonsForReactionOverlay(true)
|
||||
|
||||
val targetViews: InteractiveConversationElement = target
|
||||
handleReaction(
|
||||
@@ -2861,9 +2870,7 @@ class ConversationFragment :
|
||||
ViewUtil.fadeIn(targetViews.quotedIndicatorView!!, 150)
|
||||
}
|
||||
|
||||
if (showScrollButtons) {
|
||||
viewModel.setShowScrollButtons(true)
|
||||
}
|
||||
viewModel.setHideScrollButtonsForReactionOverlay(false)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -288,15 +288,14 @@ class ConversationRepository(
|
||||
}
|
||||
|
||||
fun getMessageCounts(threadId: Long): Flowable<MessageCounts> {
|
||||
return RxDatabaseObserver.conversationList
|
||||
return RxDatabaseObserver.conversation(threadId)
|
||||
.map { getUnreadCount(threadId) }
|
||||
.distinctUntilChanged()
|
||||
.map { MessageCounts(it, getUnreadMentionsCount(threadId)) }
|
||||
}
|
||||
|
||||
private fun getUnreadCount(threadId: Long): Int {
|
||||
val threadRecord = SignalDatabase.threads.getThreadRecord(threadId)
|
||||
return threadRecord?.unreadCount ?: 0
|
||||
return SignalDatabase.messages.getUnreadCount(threadId)
|
||||
}
|
||||
|
||||
private fun getUnreadMentionsCount(threadId: Long): Int {
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.conversation.v2
|
||||
|
||||
/**
|
||||
* State information used to display the scroll to next mention and scroll to bottom buttons.
|
||||
*/
|
||||
data class ConversationScrollButtonState(
|
||||
val showScrollButtons: Boolean = false,
|
||||
val hideScrollButtonsForReactionOverlay: Boolean = false,
|
||||
val showScrollButtonsForScrollPosition: Boolean = false,
|
||||
val willScrollToBottomOnNewMessage: Boolean = true,
|
||||
val unreadCount: Int = 0,
|
||||
val hasMentions: Boolean = false
|
||||
)
|
||||
) {
|
||||
val showScrollButtons: Boolean
|
||||
get() = !hideScrollButtonsForReactionOverlay && (showScrollButtonsForScrollPosition || (!willScrollToBottomOnNewMessage && unreadCount > 0))
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.addTo
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||
import io.reactivex.rxjava3.processors.PublishProcessor
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
@@ -98,11 +97,6 @@ class ConversationViewModel(
|
||||
private val _conversationThreadState: Subject<ConversationThreadState> = BehaviorSubject.create()
|
||||
val conversationThreadState: Single<ConversationThreadState> = _conversationThreadState.firstOrError()
|
||||
|
||||
private val _markReadProcessor: PublishProcessor<Long> = PublishProcessor.create()
|
||||
val markReadRequests: Flowable<Long> = _markReadProcessor
|
||||
.onBackpressureBuffer()
|
||||
.distinct()
|
||||
|
||||
val pagingController = ProxyPagingController<ConversationElementKey>()
|
||||
|
||||
val groupMemberServiceIds: Observable<List<ServiceId>> = recipientRepository
|
||||
@@ -249,9 +243,18 @@ class ConversationViewModel(
|
||||
disposables.clear()
|
||||
}
|
||||
|
||||
fun setShowScrollButtons(showScrollButtons: Boolean) {
|
||||
fun setShowScrollButtonsForScrollPosition(showScrollButtons: Boolean, willScrollToBottomOnNewMessage: Boolean) {
|
||||
scrollButtonStateStore.update {
|
||||
it.copy(showScrollButtons = showScrollButtons)
|
||||
it.copy(
|
||||
showScrollButtonsForScrollPosition = showScrollButtons,
|
||||
willScrollToBottomOnNewMessage = willScrollToBottomOnNewMessage
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setHideScrollButtonsForReactionOverlay(hide: Boolean) {
|
||||
scrollButtonStateStore.update {
|
||||
it.copy(hideScrollButtonsForReactionOverlay = hide)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,12 @@ object RxDatabaseObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fun conversation(threadId: Long): Flowable<Unit> {
|
||||
return databaseFlowable { listener ->
|
||||
ApplicationDependencies.getDatabaseObserver().registerVerboseConversationObserver(threadId, listener)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("RedundantUnitExpression")
|
||||
private fun notificationProfilesFlowable(): Flowable<Unit> {
|
||||
return Flowable.combineLatest(
|
||||
|
||||
Reference in New Issue
Block a user