Use state to support back pressed callback.

This commit is contained in:
Alex Hart
2025-04-02 14:26:14 -03:00
committed by Michelle Tang
parent fcc6032ee0
commit cc346351f7
3 changed files with 50 additions and 15 deletions

View File

@@ -47,10 +47,6 @@ public final class ConversationReactionDelegate {
overlayStub.get().hide(); overlayStub.get().hide();
} }
public void hideForReactWithAny() {
overlayStub.get().hideForReactWithAny();
}
public void setOnReactionSelectedListener(@NonNull ConversationReactionOverlay.OnReactionSelectedListener onReactionSelectedListener) { public void setOnReactionSelectedListener(@NonNull ConversationReactionOverlay.OnReactionSelectedListener onReactionSelectedListener) {
this.onReactionSelectedListener = onReactionSelectedListener; this.onReactionSelectedListener = onReactionSelectedListener;

View File

@@ -86,6 +86,7 @@ import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.kotlin.subscribeBy import io.reactivex.rxjava3.kotlin.subscribeBy
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -511,13 +512,18 @@ class ConversationFragment :
private lateinit var threadHeaderMarginDecoration: ThreadHeaderMarginDecoration private lateinit var threadHeaderMarginDecoration: ThreadHeaderMarginDecoration
private lateinit var conversationItemDecorations: ConversationItemDecorations private lateinit var conversationItemDecorations: ConversationItemDecorations
private lateinit var optionsMenuCallback: ConversationOptionsMenuCallback private lateinit var optionsMenuCallback: ConversationOptionsMenuCallback
private lateinit var backPressedCallback: BackPressedDelegate
private var animationsAllowed = false private var animationsAllowed = false
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private var pinnedShortcutReceiver: BroadcastReceiver? = null private var pinnedShortcutReceiver: BroadcastReceiver? = null
private var searchMenuItem: MenuItem? = null private var searchMenuItem: MenuItem? = null
private var isSearchRequested: Boolean = false private var isSearchRequested: Boolean = false
set(value) {
field = value
viewModel.setIsSearchRequested(value)
}
private var previousPage: KeyboardPage? = null private var previousPage: KeyboardPage? = null
private var previousPages: Set<KeyboardPage>? = null private var previousPages: Set<KeyboardPage>? = null
private var reShowScheduleMessagesBar: Boolean = false private var reShowScheduleMessagesBar: Boolean = false
@@ -939,8 +945,16 @@ class ConversationFragment :
activity?.supportStartPostponedEnterTransition() activity?.supportStartPostponedEnterTransition()
backPressedCallback = BackPressedDelegate() val backPressedDelegate = BackPressedDelegate()
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backPressedCallback) requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backPressedDelegate)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
viewModel.backPressedState.collectLatest {
backPressedDelegate.isEnabled = it.shouldHandleBackPressed()
}
}
}
menuProvider?.afterFirstRenderMode = true menuProvider?.afterFirstRenderMode = true
@@ -2217,6 +2231,7 @@ class ConversationFragment :
reactionDelegate.setOnActionSelectedListener(onActionSelectedListener) reactionDelegate.setOnActionSelectedListener(onActionSelectedListener)
reactionDelegate.setOnHideListener(onHideListener) reactionDelegate.setOnHideListener(onHideListener)
reactionDelegate.show(requireActivity(), viewModel.recipientSnapshot!!, conversationMessage, conversationGroupViewModel.isNonAdminInAnnouncementGroup(), selectedConversationModel) reactionDelegate.show(requireActivity(), viewModel.recipientSnapshot!!, conversationMessage, conversationGroupViewModel.isNonAdminInAnnouncementGroup(), selectedConversationModel)
viewModel.setIsReactionDelegateShowing(true)
composeText.clearFocus() composeText.clearFocus()
} }
@@ -2344,18 +2359,15 @@ class ConversationFragment :
} }
} }
private inner class BackPressedDelegate : OnBackPressedCallback(true) { private inner class BackPressedDelegate : OnBackPressedCallback(false) {
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
Log.d(TAG, "onBackPressed()") Log.d(TAG, "onBackPressed()")
if (reactionDelegate.isShowing) { val state = viewModel.backPressedState.value
if (state.isReactionDelegateShowing) {
reactionDelegate.hide() reactionDelegate.hide()
} else if (isSearchRequested) { } else if (state.isSearchRequested) {
searchMenuItem?.collapseActionView() searchMenuItem?.collapseActionView()
} else if (args.conversationScreenType.isInBubble) {
isEnabled = false
requireActivity().onBackPressed()
} else {
requireActivity().finish()
} }
} }
} }
@@ -3255,6 +3267,8 @@ class ConversationFragment :
} }
override fun onHide() { override fun onHide() {
viewModel.setIsReactionDelegateShowing(false)
if (!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) || activity == null || activity?.isFinishing == true) { if (!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) || activity == null || activity?.isFinishing == true) {
return return
} }

View File

@@ -32,11 +32,14 @@ import io.reactivex.rxjava3.subjects.PublishSubject
import io.reactivex.rxjava3.subjects.Subject import io.reactivex.rxjava3.subjects.Subject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.rx3.asFlow import kotlinx.coroutines.rx3.asFlow
import org.signal.core.util.orNull import org.signal.core.util.orNull
@@ -191,6 +194,9 @@ class ConversationViewModel(
val jumpToDateValidator: JumpToDateValidator val jumpToDateValidator: JumpToDateValidator
get() = _jumpToDateValidator get() = _jumpToDateValidator
private val internalBackPressedState = MutableStateFlow(BackPressedState())
val backPressedState: StateFlow<BackPressedState> = internalBackPressedState
init { init {
disposables += recipient disposables += recipient
.subscribeBy { .subscribeBy {
@@ -604,4 +610,23 @@ class ConversationViewModel(
.getEarliestMessageSentDate(threadId) .getEarliestMessageSentDate(threadId)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
} }
fun setIsReactionDelegateShowing(isReactionDelegateShowing: Boolean) {
internalBackPressedState.update {
it.copy(isReactionDelegateShowing = isReactionDelegateShowing)
}
}
fun setIsSearchRequested(isSearchRequested: Boolean) {
internalBackPressedState.update {
it.copy(isSearchRequested = isSearchRequested)
}
}
data class BackPressedState(
val isReactionDelegateShowing: Boolean = false,
val isSearchRequested: Boolean = false
) {
fun shouldHandleBackPressed() = isSearchRequested || isReactionDelegateShowing
}
} }