Skip to content

Commit

Permalink
Add StateSource (#221)
Browse files Browse the repository at this point in the history
  • Loading branch information
eygraber authored Dec 30, 2024
1 parent 9dd09b6 commit 226858f
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 15 deletions.
64 changes: 58 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,19 +173,71 @@ in order to create the `ViewState`.

There are several implementations provided by VICE that cover common use cases.

### StateSource

`StateSource` simply makes `ViceSource` implement Compose's `State` type, and by default provides [currentState]
with its value.

`StateSource` can be used instead of the other `State` based sources if the stricter rules of an `abstract class` aren't needed.

```kotlin
internal sealed interface MyFeatureDialogState {
data object None : MyFeatureDialogState
data class Error(val message: String) : MyFeatureDialogState
}

internal class MyFeatureDialogSource : StateSource<MyFeatureDialogState> {
override var value: MyFeatureDialogState by mutableStateOf(MyFeatureDialogState.None)
private set

fun clearError() {
value = MyFeatureDialogState.None
}

fun showError(message: String) {
value = MyFeatureDialogState.Error(message)
}
}
```

`StateSource` can also be used to define a custom interface, and abstract
implementors of it (e.g. `MutableStateSource`, etc...) can be used to provide the implementation.

```kotlin
internal sealed interface MyFeatureDialogState {
data object None : MyFeatureDialogState
data class Error(val message: String) : MyFeatureDialogState
}

internal interface MyFeatureDialogSource : StateSource<MyFeatureDialogState>

internal class RealMyFeatureDialogSource : MyFeatureDialogSource, MutableStateSource<MyFeatureDialogState>() {
override val initial = MyFeatureDialogState.None

fun clearError() {
update(MyFeatureDialogState.None)
}

fun showError(message: String) {
update(
MyFeatureDialogState.Error(message)
)
}
}
```

### MutableStateSource

`MutableStateSource` wraps a `MutableState`, and provides an `update` function for implementations to
mutate it. Useful for encapsulating behavior around the `MutableState` instead of managing it in the `ViceCompositor`.


```kotlin
internal sealed interface MyFeatureDialogState {
data object None : MyFeatureDialogState
data class Error(val message: String) : MyFeatureDialogState
}

internal class MyFeatureDialogSource : MutableStateSource<MyFeatureDialogState> {
internal class MyFeatureDialogSource : MutableStateSource<MyFeatureDialogState>() {
override val initial = MyFeatureDialogState.None

fun clearError() {
Expand All @@ -207,7 +259,7 @@ internal class MyFeatureDialogSource : MutableStateSource<MyFeatureDialogState>


```kotlin
internal class MyCounterSource : SaveableMutableStateSource<Int> {
internal class MyCounterSource : SaveableMutableStateSource<Int>() {
override val initial = 0

fun reset() {
Expand All @@ -227,7 +279,7 @@ internal class MyCounterSource : SaveableMutableStateSource<Int> {
```kotlin
internal class MyDerivedStateSource(
private val fastChangingStateSource: FastChangingStateSource,
) : DerivedStateSource<MyDerivedState> {
) : DerivedStateSource<MyDerivedState>() {
override fun deriveState(): MyDerivedState {
val fastChangingState by fastChangingStateSource

Expand All @@ -247,7 +299,7 @@ internal class MyDerivedStateSource(
```kotlin
internal class MyFlowSource(
private val featureRepo: MyFeatureRepository,
) : FlowSource<List<MyFeatureData>> {
) : FlowSource<List<MyFeatureData>>() {
override val initial = emptyList()

override val flow = featureRepo
Expand Down Expand Up @@ -323,7 +375,7 @@ fun TodoListView(
allows you to modify the `StateFlow` (which is usually implemented as a `MutableStateFlow`).

```kotlin
internal class TimerFlowSource : StateFlowSource<Int> {
internal class TimerFlowSource : StateFlowSource<Int>() {
override val flow = MutableStateFlow(0)

override suspend fun onAttached(scope: CoroutineScope) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ package com.eygraber.vice.sources

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.snapshotFlow
import com.eygraber.vice.ViceSource
import kotlinx.coroutines.flow.Flow

public abstract class DerivedStateSource<T> : ViceSource<T>, State<T> {
public abstract class DerivedStateSource<T> : StateSource<T> {
protected abstract fun deriveState(): T

private val state by lazy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ package com.eygraber.vice.sources

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.snapshotFlow
import com.eygraber.vice.ViceSource
import kotlinx.coroutines.flow.Flow

public abstract class MutableStateSource<T> : ViceSource<T>, State<T> {
public abstract class MutableStateSource<T> : StateSource<T> {
private val state by lazy {
mutableStateOf(initial)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package com.eygraber.vice.sources

import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.snapshotFlow
import com.eygraber.vice.ViceSource
import kotlinx.coroutines.flow.Flow

public abstract class SaveableMutableStateSource<T : Any>(
private val saver: Saver<T, out Any>? = null,
) : ViceSource<T>, State<T> {
) : StateSource<T> {
private val state by lazy {
mutableStateOf(initial)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.eygraber.vice.sources

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.State
import com.eygraber.vice.ViceSource

public interface StateSource<T> : ViceSource<T>, State<T> {
@Composable
@ReadOnlyComposable
override fun currentState(): T = value
}

0 comments on commit 226858f

Please sign in to comment.