Skip to content

Commit

Permalink
feat: Add custom Saver for RevealState (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
svenjacobs authored Dec 27, 2022
1 parent 4ac6ecb commit 91f73cc
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fun MainScreen(modifier: Modifier = Modifier) {
val revealState = rememberRevealState()

LaunchedEffect(Unit) {
if (revealState.isVisible) return@LaunchedEffect
delay(2.seconds)
revealState.reveal(Keys.Fab)
}
Expand Down
56 changes: 51 additions & 5 deletions reveal-core/src/main/kotlin/com/svenjacobs/reveal/RevealState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,87 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.autoSaver
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import com.svenjacobs.reveal.internal.revealable.Revealable
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

@Stable
public class RevealState {
public class RevealState internal constructor(
visible: Boolean = false,
private val restoreRevealableKey: Key? = null,
) {

private val mutex = Mutex()
private var didRestoreCurrentRevealable = false

internal var visible by mutableStateOf(false)
internal var visible by mutableStateOf(visible)
private set
internal var currentRevealable by mutableStateOf<Revealable?>(null)
private set
private val revealables: MutableMap<Key, Revealable> = mutableMapOf()

public val isVisible: Boolean
get() = visible

public val currentRevealableKey: Key?
get() = currentRevealable?.key

public suspend fun reveal(key: Key) {
require(revealables.containsKey(key)) { "Revealable with key \"$key\" not found" }
mutex.withLock {
// TODO: hide when key was not found?
currentRevealable = revealables[key]
visible = true
}
}

public suspend fun hide() {
mutex.withLock {
currentRevealable = null
visible = false
}
}

internal fun putRevealable(revealable: Revealable) {
revealables[revealable.key] = revealable

if (!didRestoreCurrentRevealable && restoreRevealableKey == revealable.key) {
currentRevealable = revealable
didRestoreCurrentRevealable = true
}
}

internal companion object {

internal fun newSaver(keySaver: Saver<Key, Any>): Saver<RevealState, *> = listSaver(
save = {
listOf(
it.isVisible,
it.currentRevealableKey?.let { key -> with(keySaver) { save(key) } },
)
},
restore = {
RevealState(
visible = it[0] as Boolean,
restoreRevealableKey = it[1]?.let { keySaveable -> keySaver.restore(keySaveable) },
)
},
)
}
}

/**
* Creates a [RevealState] that is remembered across compositions.
*
* If a custom type is used for revealable keys which cannot be saved automatically by Compose,
* a custom saver must be specified via [keySaver].
*
* @param keySaver Custom saver for revealable keys
*/
@Composable
public fun rememberRevealState(): RevealState = remember { RevealState() }
public fun rememberRevealState(keySaver: Saver<Key, Any> = autoSaver()): RevealState =
rememberSaveable(saver = RevealState.newSaver(keySaver)) { RevealState() }

0 comments on commit 91f73cc

Please sign in to comment.