Keep shell state reads safe in read-only snapshots
All checks were successful
review/code-claude Hotfix verified on the real Xiaomi box (B3 runs, no crash across Home/Discover/Movies/Shows/title/Settings/Requests); 5-file delta read by firstmate: ShellState.rememberedView no longer writes on read, 3 regression tests incl. snapshotFlow and an audit
All checks were successful
review/code-claude Hotfix verified on the real Xiaomi box (B3 runs, no crash across Home/Discover/Movies/Shows/title/Settings/Requests); 5-file delta read by firstmate: ShellState.rememberedView no longer writes on read, 3 regression tests incl. snapshotFlow and an audit
This commit is contained in:
parent
e9a92eba49
commit
4e6377b628
5 changed files with 199 additions and 3 deletions
|
|
@ -57,6 +57,7 @@ class ShellState(
|
|||
people = value
|
||||
if (selected != null) person = selected
|
||||
pickerIndex = people.indexOf(person).coerceAtLeast(0)
|
||||
preparePersonMemory()
|
||||
}
|
||||
var person by mutableStateOf(people.firstOrNull { it.key == initialPerson } ?: people.first())
|
||||
private set
|
||||
|
|
@ -73,7 +74,7 @@ class ShellState(
|
|||
var requestsVisible by mutableStateOf(false)
|
||||
var toast by mutableStateOf<String?>(null)
|
||||
private val personRequests = mutableMapOf<String, ComingInState>()
|
||||
val requests: ComingInState get() = personRequests.getOrPut(person.key) { ComingInState() }
|
||||
val requests: ComingInState get() = personRequests.getValue(person.key)
|
||||
private var requestReturnRoute: String? = null
|
||||
var handOff by mutableStateOf<String?>(null)
|
||||
var settingsRow by mutableStateOf(0)
|
||||
|
|
@ -85,17 +86,30 @@ class ShellState(
|
|||
var contentFocus: ShellContentFocus? = null
|
||||
var inputRevision = 0L
|
||||
private set
|
||||
|
||||
init { preparePersonMemory() }
|
||||
|
||||
private fun preparePersonMemory() {
|
||||
personRequests.getOrPut(person.key) { ComingInState() }
|
||||
tabs.forEach(::retainView)
|
||||
retainView(route)
|
||||
}
|
||||
|
||||
private fun retainView(destination: String) {
|
||||
views.getOrPut(person.key to destination) { RememberedView() }
|
||||
}
|
||||
val tabs: List<String> get() = if (person.hasAnime) ANIME_TABS else BASE_TABS
|
||||
val currentTab: Int get() = tabs.indexOf(rootRoute).coerceAtLeast(0)
|
||||
val view: RememberedView get() = rememberedView(route)
|
||||
val navSavedAt: String? get() = if (requestsVisible && requests.snapshot.status == ComingInStatus.Unavailable) requests.snapshot.savedAt ?: view.savedAt else view.savedAt
|
||||
|
||||
/** Screen options share the same per-person memory as their root's focus and scroller. */
|
||||
/** Reads never register defaults: snapshotFlow evaluates accessors in a read-only snapshot. */
|
||||
fun rememberedView(destination: String): RememberedView =
|
||||
views.getOrPut(person.key to destination) { RememberedView() }
|
||||
views[person.key to destination] ?: RememberedView()
|
||||
|
||||
/** External intents and upstream pops remain authoritative over the screen. */
|
||||
fun enterDestination(destination: String) {
|
||||
retainView(destination)
|
||||
route = destination
|
||||
if (destination in tabs) rootRoute = destination
|
||||
handOff = null
|
||||
|
|
@ -159,6 +173,7 @@ class ShellState(
|
|||
pickerVisible = false
|
||||
navFocused = false
|
||||
settingsRow = 0
|
||||
retainView("settings")
|
||||
route = "settings"
|
||||
onAction(ShellAction.Destination(route))
|
||||
}
|
||||
|
|
@ -187,6 +202,7 @@ class ShellState(
|
|||
rootRoute = "home"
|
||||
requestReturnRoute = null
|
||||
requestsVisible = false
|
||||
preparePersonMemory()
|
||||
views[person.key to route] = RememberedView()
|
||||
onAction(ShellAction.Person(selected))
|
||||
}
|
||||
|
|
@ -226,6 +242,7 @@ class ShellState(
|
|||
} else {
|
||||
val target = tabs[navIndex]
|
||||
requestReturnRoute = null
|
||||
retainView(target)
|
||||
if (target == route) views[person.key to target] = RememberedView()
|
||||
route = target
|
||||
rootRoute = target
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue