address review: replay one dismissal so a recreated screen still sees it

A notification tap can fire the dismissal before the route's collector
subscribes (activity recreated with a restored options sheet), and a
replay-zero broadcast drops it. Replaying one is a no-op on default state
and the new ContextMenuHost test guards it.
This commit is contained in:
austinried
2026-10-04 00:56:53 +00:00
parent af6979459b
commit dbb6745b7b
3 changed files with 23 additions and 1 deletions
@@ -151,7 +151,9 @@ class ContextMenuHost {
var actions by mutableStateOf(ItemActions())
private set
private val transientDismissals = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
// Replay one so a screen recreated by the notification (whose collector subscribes after the
// event fires) still sees the dismissal; every onDismiss is a harmless no-op on default state.
private val transientDismissals = MutableSharedFlow<Unit>(replay = 1)
// Fires when an external event (opening now playing) should close menu-like UI the host does
// not own, such as the library's list options sheet.
@@ -420,6 +420,7 @@ fun LibraryScreen(
var searchActive by rememberSaveable { mutableStateOf(false) }
val searchFocus = remember { FocusRequester() }
// Search mode is left open so the typed query survives; MainNavigation dismisses the keyboard.
DismissOnRequest(dismissals) { showOptions = false }
LaunchedEffect(pagerState) {
@@ -0,0 +1,19 @@
package com.subtracks.ui.components
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.withTimeoutOrNull
import org.junit.Assert.assertEquals
import org.junit.Test
class ContextMenuHostTest {
@Test
fun aDismissalBeforeCollectionIsStillDelivered() =
runTest {
val host = ContextMenuHost()
host.dismissTransients()
assertEquals(Unit, withTimeoutOrNull(1_000) { host.dismissals.first() })
}
}