fix(nav): preserve screen state across overlay navigation

RootContent now stays composed when overlays are shown, preventing
search results and other state from being destroyed on navigation.
Overlay wrapped in opaque Surface to cover root content visually.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
nrobi144
2026-03-12 13:32:05 +02:00
parent 5a437ed5ac
commit 327bb1efc8
2 changed files with 73 additions and 60 deletions
@@ -27,6 +27,8 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@@ -120,37 +122,42 @@ fun DeckColumnContainer(
Box(
modifier = Modifier.fillMaxSize().padding(12.dp),
) {
// Always keep RootContent composed so state (e.g. search results) survives navigation
RootContent(
columnType = column.type,
relayManager = relayManager,
localCache = localCache,
accountManager = accountManager,
account = account,
nwcConnection = nwcConnection,
subscriptionsCoordinator = subscriptionsCoordinator,
appScope = appScope,
onShowComposeDialog = onShowComposeDialog,
onShowReplyDialog = onShowReplyDialog,
onZapFeedback = onZapFeedback,
onNavigateToProfile = { navState.push(DesktopScreen.UserProfile(it)) },
onNavigateToThread = { navState.push(DesktopScreen.Thread(it)) },
)
if (currentOverlay != null) {
OverlayContent(
screen = currentOverlay,
relayManager = relayManager,
localCache = localCache,
account = account,
nwcConnection = nwcConnection,
subscriptionsCoordinator = subscriptionsCoordinator,
onShowComposeDialog = onShowComposeDialog,
onShowReplyDialog = onShowReplyDialog,
onZapFeedback = onZapFeedback,
onNavigateToProfile = { navState.push(DesktopScreen.UserProfile(it)) },
onNavigateToThread = { navState.push(DesktopScreen.Thread(it)) },
onBack = { navState.pop() },
)
} else {
RootContent(
columnType = column.type,
relayManager = relayManager,
localCache = localCache,
accountManager = accountManager,
account = account,
nwcConnection = nwcConnection,
subscriptionsCoordinator = subscriptionsCoordinator,
appScope = appScope,
onShowComposeDialog = onShowComposeDialog,
onShowReplyDialog = onShowReplyDialog,
onZapFeedback = onZapFeedback,
onNavigateToProfile = { navState.push(DesktopScreen.UserProfile(it)) },
onNavigateToThread = { navState.push(DesktopScreen.Thread(it)) },
)
Surface(
color = MaterialTheme.colorScheme.background,
modifier = Modifier.fillMaxSize(),
) {
OverlayContent(
screen = currentOverlay,
relayManager = relayManager,
localCache = localCache,
account = account,
nwcConnection = nwcConnection,
subscriptionsCoordinator = subscriptionsCoordinator,
onShowComposeDialog = onShowComposeDialog,
onShowReplyDialog = onShowReplyDialog,
onZapFeedback = onZapFeedback,
onNavigateToProfile = { navState.push(DesktopScreen.UserProfile(it)) },
onNavigateToThread = { navState.push(DesktopScreen.Thread(it)) },
onBack = { navState.pop() },
)
}
}
}
}
@@ -43,6 +43,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationRail
import androidx.compose.material3.NavigationRailItem
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
@@ -152,37 +153,42 @@ fun SinglePaneLayout(
Box(
modifier = Modifier.fillMaxSize().padding(12.dp),
) {
// Always keep RootContent composed so state (e.g. search results) survives navigation
RootContent(
columnType = currentColumnType,
relayManager = relayManager,
localCache = localCache,
accountManager = accountManager,
account = account,
nwcConnection = nwcConnection,
subscriptionsCoordinator = subscriptionsCoordinator,
appScope = appScope,
onShowComposeDialog = onShowComposeDialog,
onShowReplyDialog = onShowReplyDialog,
onZapFeedback = onZapFeedback,
onNavigateToProfile = { navState.push(DesktopScreen.UserProfile(it)) },
onNavigateToThread = { navState.push(DesktopScreen.Thread(it)) },
)
if (currentOverlay != null) {
OverlayContent(
screen = currentOverlay,
relayManager = relayManager,
localCache = localCache,
account = account,
nwcConnection = nwcConnection,
subscriptionsCoordinator = subscriptionsCoordinator,
onShowComposeDialog = onShowComposeDialog,
onShowReplyDialog = onShowReplyDialog,
onZapFeedback = onZapFeedback,
onNavigateToProfile = { navState.push(DesktopScreen.UserProfile(it)) },
onNavigateToThread = { navState.push(DesktopScreen.Thread(it)) },
onBack = { navState.pop() },
)
} else {
RootContent(
columnType = currentColumnType,
relayManager = relayManager,
localCache = localCache,
accountManager = accountManager,
account = account,
nwcConnection = nwcConnection,
subscriptionsCoordinator = subscriptionsCoordinator,
appScope = appScope,
onShowComposeDialog = onShowComposeDialog,
onShowReplyDialog = onShowReplyDialog,
onZapFeedback = onZapFeedback,
onNavigateToProfile = { navState.push(DesktopScreen.UserProfile(it)) },
onNavigateToThread = { navState.push(DesktopScreen.Thread(it)) },
)
Surface(
color = MaterialTheme.colorScheme.background,
modifier = Modifier.fillMaxSize(),
) {
OverlayContent(
screen = currentOverlay,
relayManager = relayManager,
localCache = localCache,
account = account,
nwcConnection = nwcConnection,
subscriptionsCoordinator = subscriptionsCoordinator,
onShowComposeDialog = onShowComposeDialog,
onShowReplyDialog = onShowReplyDialog,
onZapFeedback = onZapFeedback,
onNavigateToProfile = { navState.push(DesktopScreen.UserProfile(it)) },
onNavigateToThread = { navState.push(DesktopScreen.Thread(it)) },
onBack = { navState.pop() },
)
}
}
}
}