fix(navigation): keep Home composed while article is open

Article was an AnimatedContent target: opening it disposed Home, and returning from it recreated the whole results list in a single frame. The article screen now renders as a full-screen AnimatedVisibility overlay above Home, which stays composed for the whole article session.
This commit is contained in:
OneWay committed 2026-09-25 23:59:45 +08:00
1 parent c7c080939c
commit ed4a4436b8
1 file changed
+31 -11
@@ -2,16 +2,22 @@ package com.example.research.ui.navigation
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith import androidx.compose.animation.togetherWith
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2 import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.* import androidx.compose.runtime.saveable.*
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.core.layout.WindowSizeClass.Companion.WIDTH_DP_MEDIUM_LOWER_BOUND import androidx.window.core.layout.WindowSizeClass.Companion.WIDTH_DP_MEDIUM_LOWER_BOUND
import com.example.research.feature.search.SearchAction import com.example.research.feature.search.SearchAction
@@ -101,10 +107,11 @@ fun AppNavigation(
val effectiveScreen = when { val effectiveScreen = when {
currentScreen == Screen.About -> Screen.About currentScreen == Screen.About -> Screen.About
currentScreen == Screen.Article && articleState == null -> if (shouldShowSettings) Screen.Settings else Screen.Home
shouldShowSettings -> Screen.Settings shouldShowSettings -> Screen.Settings
else -> currentScreen currentScreen == Screen.Settings -> Screen.Settings
else -> Screen.Home
} }
Box {
AnimatedContent( AnimatedContent(
targetState = effectiveScreen, targetState = effectiveScreen,
transitionSpec = { transitionSpec = {
@@ -150,7 +157,27 @@ fun AppNavigation(
onNavigateToAbout = { screenStack.add(Screen.About) } onNavigateToAbout = { screenStack.add(Screen.About) }
) )
} }
Screen.Article -> { Screen.About -> {
AboutScreen(
onNavigateBack = {
if (screenStack.size > 1) screenStack.removeAt(screenStack.lastIndex)
}
)
}
Screen.Article -> {}
}
}
AnimatedVisibility(
visible = currentScreen == Screen.Article && articleState != null,
enter = fadeIn(tween(180)) + slideInHorizontally(tween(180)) { it / 3 },
exit = fadeOut(tween(180)) + slideOutHorizontally(tween(180)) { it / 3 },
label = "articleOverlay",
) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.surface
) {
ArticleRoute( ArticleRoute(
searchViewModel = searchViewModel, searchViewModel = searchViewModel,
onNavigateBack = { onNavigateBack = {
@@ -162,13 +189,6 @@ fun AppNavigation(
} }
) )
} }
Screen.About -> { }
AboutScreen(
onNavigateBack = {
if (screenStack.size > 1) screenStack.removeAt(screenStack.lastIndex)
}
)
}
}
} }
} }