-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change rememberRetain not to retain the value of removed node #1794
Changes from all commits
019c8cc
5b279d4
4b0cc82
d769169
465f98f
24d8547
affec25
c42dd26
67d156f
ff654b4
5d30dd7
a367cbb
0e4e8e3
9fbc2df
fb672cf
b6b0cec
16cf579
ff477ad
7900ffb
df33d07
82e84a1
1e8083e
afebc7a
9714ce3
0c3c6b1
ffcf6f6
91c2fcd
b726772
28d601a
b9d1afd
ae1cd94
b267800
0eb7efb
17b40a5
6b6467e
b6bdea4
2fe5950
a9407b1
58ba1cd
32efffd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// Copyright (C) 2024 Slack Technologies, LLC | ||
// SPDX-License-Identifier: Apache-2.0 | ||
package com.slack.circuit.foundation | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.DisposableEffect | ||
import androidx.compose.runtime.key | ||
import androidx.compose.runtime.remember | ||
import com.slack.circuit.foundation.internal.withCompositionLocalProvider | ||
import com.slack.circuit.retained.CanRetainChecker | ||
import com.slack.circuit.retained.LocalCanRetainChecker | ||
import com.slack.circuit.retained.LocalRetainedStateRegistry | ||
import com.slack.circuit.retained.RetainedStateRegistry | ||
import com.slack.circuit.retained.RetainedValueProvider | ||
import com.slack.circuit.retained.rememberRetained | ||
|
||
/** Copy of [RetainedStateHolder] to return content value */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: do you think we can/should reconcile these into one API? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be good to consolidate them, but there are a few considerations:
|
||
internal interface RetainedStateHolder { | ||
|
||
@Composable fun <T> RetainedStateProvider(key: String, content: @Composable () -> T): T | ||
|
||
fun removeState(key: String) | ||
} | ||
|
||
/** Creates and remembers the instance of [RetainedStateHolder]. */ | ||
@Composable | ||
internal fun rememberRetainedStateHolderWithReturn(): RetainedStateHolder { | ||
return rememberRetained { RetainedStateHolderImpl() } | ||
} | ||
|
||
private class RetainedStateHolderImpl : RetainedStateHolder, RetainedStateRegistry { | ||
|
||
private val registry = RetainedStateRegistry() | ||
|
||
private val entries = mutableMapOf<String, Entry>() | ||
|
||
@Composable | ||
override fun <T> RetainedStateProvider(key: String, content: @Composable (() -> T)): T { | ||
return withCompositionLocalProvider(LocalRetainedStateRegistry provides registry) { | ||
key(key) { | ||
val entry = remember { Entry() } | ||
val childRegistry = rememberRetained(key = key) { RetainedStateRegistry() } | ||
withCompositionLocalProvider( | ||
LocalRetainedStateRegistry provides childRegistry, | ||
LocalCanRetainChecker provides CanRetainChecker.Always, | ||
content = content, | ||
) | ||
.also { | ||
DisposableEffect(Unit) { | ||
entries[key] = entry | ||
onDispose { | ||
if (entry.shouldSave) { | ||
registry.saveValue(key) | ||
} | ||
entries -= key | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
override fun removeState(key: String) { | ||
val entry = entries[key] | ||
if (entry != null) { | ||
entry.shouldSave = false | ||
} else { | ||
registry.consumeValue(key) | ||
} | ||
} | ||
|
||
override fun consumeValue(key: String): Any? { | ||
return registry.consumeValue(key) | ||
} | ||
|
||
override fun registerValue( | ||
key: String, | ||
valueProvider: RetainedValueProvider, | ||
): RetainedStateRegistry.Entry { | ||
return registry.registerValue(key, valueProvider) | ||
} | ||
|
||
override fun saveAll(): Map<String, List<Any?>> { | ||
return registry.saveAll() | ||
} | ||
|
||
override fun saveValue(key: String) { | ||
registry.saveValue(key) | ||
} | ||
|
||
override fun forgetUnclaimedValues() { | ||
registry.forgetUnclaimedValues() | ||
} | ||
|
||
private data class Entry(var shouldSave: Boolean = true) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great writeup!