WebContent does not allow for tab switching via Target.Tab
AllanWang opened this issue · comments
WebContent works fine for Target.SelectedTab
, but if we want to change tabs ourselves via Target.Tab
with different ids, it won't listen to changes.
This is because the portion above is only disposed on store
and lifecycleOwner
changes, and not also when the target
changes. As a result, it always tests against the first target.tabId
. Occasionally, editing compose will trigger a soft restart, which actually updates the value; this is unrelated to the issue.
Use case:
I have an app with:
- One
WebContent
for the main screen, with tabs (TabLayout
) to switch between sessions - One pop up screen, which is not always present, with its own
WebContent
At any given moment, only one session is active. The one in the main screen with the corresponding tab, or the pop up screen. However, if I show the pop up screen, I don't want the main screen to also show that tab, which is why I'm using Target.Tab
directly. Is this an appropriate use case, or is Target.Tab
incorrect? Should I be using two browser stores instead?
┆Issue is synchronized with this Jira Task
@Composable
fun WebContent(engine: Engine, store: BrowserStore, target: Target) {
val selectedTab =
target.observeAsComposableStateFrom2(
store = store,
observe = { tab ->
// Render if the tab itself changed or when the state of the linked engine session changes
arrayOf(
tab?.id,
tab?.engineState?.engineSession,
tab?.engineState?.crashed,
tab?.content?.firstContentfulPaint
)
}
)
// No changes here
}
@Composable
private fun <R> Target.observeAsComposableStateFrom2(
store: BrowserStore,
observe: (SessionState?) -> R
): State<SessionState?> {
return store.observeAsComposableState(
this,
map = { state -> lookupIn(state) },
observe = { state -> observe(lookupIn(state)) }
)
}
@Composable
private fun <S : mozilla.components.lib.state.State, A : Action, K, O, R> Store<S, A>
.observeAsComposableState(key: K, observe: (S) -> O, map: (S) -> R): State<R?> {
val lifecycleOwner = LocalLifecycleOwner.current
var lastValue = observe(state)
val state = remember { mutableStateOf<R?>(map(state)) }
DisposableEffect(this, key, lifecycleOwner) {
val subscription =
observe(lifecycleOwner) { browserState ->
val newValue = observe(browserState)
if (newValue != lastValue) {
state.value = map(browserState)
lastValue = newValue
}
}
onDispose { subscription?.unsubscribe() }
}
return state
}
This is the easiest change I could think of. Add target
as key to DisposableEffect
in observeAsComposableState
, given that changing tabs has no effect on the Store
. I imagine this means this is not the correct approach, and that I should be using SelectedTab
Moved to bugzilla: https://bugzilla.mozilla.org/show_bug.cgi?id=1794854
Change performed by the Move to Bugzilla add-on.