Skip to content

Commit

Permalink
Merge pull request #17 from gmerinojimenez/state-flow
Browse files Browse the repository at this point in the history
State flow instead of flow
  • Loading branch information
gmerinojimenez authored Nov 24, 2021
2 parents e53d1fb + c4f277c commit c4e375a
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,40 @@ import android.app.Application
import android.widget.Toast
import com.gmerinojimenez.tweaks.Tweaks
import com.gmerinojimenez.tweaks.domain.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch

class TweakDemoApplication : Application() {
override fun onCreate() {
super.onCreate()
Tweaks.init(this@TweakDemoApplication, demoTweakGraph())
}

var counter = 0
var timestampState = MutableStateFlow("0")

init {
CoroutineScope(Dispatchers.Default).launch {
while (true) {
timestampState.value = "${System.currentTimeMillis() / 1000}"
delay(1000)
}
}
}

private fun demoTweakGraph() = tweaksGraph {
cover("Tweaks Demo") {
label("cover-key", "Current user ID:") { flow { emit("1")} }
label("cover-key", "Current user ID:") { MutableStateFlow("1") }
}
category("Screen 1") {
group("Group 1") {
label(
key = "timestamp",
name = "Current timestamp",
) {
flow {
while (true) {
emit("${System.currentTimeMillis() / 1000}")
delay(1000)
}
}
timestampState
}
editableString(
key = "value1",
Expand All @@ -40,17 +47,6 @@ class TweakDemoApplication : Application() {
key = "value2",
name = "Value 2",
)
editableInt(
key = "value3",
name = "Value 3",
defaultValue = flow {
while (true) {
counter += 1
emit(counter)
delay(1000)
}
}
)
editableLong(
key = "value4",
name = "Value 4",
Expand Down
6 changes: 3 additions & 3 deletions library/src/enabled/java/com/gmerinojimenez/tweaks/Tweaks.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import com.gmerinojimenez.tweaks.domain.TweaksGraph
import com.gmerinojimenez.tweaks.ui.TweaksCategoryScreen
import com.gmerinojimenez.tweaks.ui.TweaksScreen
import com.squareup.seismic.ShakeDetector
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject


Expand All @@ -39,9 +39,9 @@ class Tweaks {
@Inject
internal lateinit var tweaksBusinessLogic: TweaksBusinessLogic

fun <T>getTweakValue(key: String): Flow<T?> = tweaksBusinessLogic.getValue(key)
fun <T>getTweakValue(key: String): StateFlow<T?> = tweaksBusinessLogic.getValue(key)

fun <T> getTweakValue(entry: TweakEntry<T>): Flow<T?> = tweaksBusinessLogic.getValue(entry)
fun <T> getTweakValue(entry: TweakEntry<T>): StateFlow<T?> = tweaksBusinessLogic.getValue(entry)

private fun initializeGraph(tweaksGraph: TweaksGraph) {
tweaksBusinessLogic.initialize(tweaksGraph)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.gmerinojimenez.tweaks.domain

import androidx.datastore.preferences.core.*
import com.gmerinojimenez.tweaks.data.TweaksDataStore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
import javax.inject.Inject
Expand Down Expand Up @@ -48,24 +50,29 @@ class TweaksBusinessLogic @Inject constructor(
}

@Suppress("UNCHECKED_CAST")
fun <T> getValue(key: String): Flow<T?> {
fun <T> getValue(key: String): StateFlow<T?> {
val tweakEntry = keyToEntryValueMap[key] as TweakEntry<T>
return getValue(tweakEntry)
}

fun <T> getValue(entry: TweakEntry<T>): Flow<T?> = when (entry as Modifiable) {
fun <T> getValue(entry: TweakEntry<T>): StateFlow<T?> = when (entry as Modifiable) {
is ReadOnly<*> -> (entry as ReadOnly<T>).value
is Editable<*> -> getEditableValue(entry)
}

@OptIn(ExperimentalCoroutinesApi::class)
private fun <T> getEditableValue(entry: TweakEntry<T>): Flow<T?> {
private fun <T> getEditableValue(entry: TweakEntry<T>): StateFlow<T?> {
val editableCasted = entry as Editable<T>
val defaultValue = editableCasted.defaultValue
return defaultValue?.combine(getFromStorage(entry)) { default, storage ->
storage ?: default
}
?: getFromStorage(entry)
val defaultValueFlow: StateFlow<T>? = editableCasted.defaultValue
val initialValue = defaultValueFlow?.value

val mergedFlow: Flow<T?> = if (defaultValueFlow != null) merge(getFromStorage(entry), defaultValueFlow) else getFromStorage(entry)

return mergedFlow.stateIn(
scope = CoroutineScope(Dispatchers.Default),
started = SharingStarted.Lazily,
initialValue = initialValue
)
}

private fun <T> getFromStorage(entry: TweakEntry<T>) =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.gmerinojimenez.tweaks.domain

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flow

fun tweaksGraph(block: TweaksGraph.Builder.() -> Unit): TweaksGraph {
Expand Down Expand Up @@ -76,15 +78,15 @@ data class TweakGroup(val title: String, val entries: List<TweakEntry<*>>) {
fun label(
key: String,
name: String,
value: () -> Flow<String>,
value: () -> StateFlow<String>,
) {
tweak(ReadOnlyStringTweakEntry(key, name, value()))
}

fun editableString(
key: String,
name: String,
defaultValue: Flow<String>? = null,
defaultValue: StateFlow<String>? = null,
) {
tweak(EditableStringTweakEntry(key, name, defaultValue))
}
Expand All @@ -100,7 +102,7 @@ data class TweakGroup(val title: String, val entries: List<TweakEntry<*>>) {
fun editableBoolean(
key: String,
name: String,
defaultValue: Flow<Boolean>? = null,
defaultValue: StateFlow<Boolean>? = null,
) {
tweak(EditableBooleanTweakEntry(key, name, defaultValue))
}
Expand All @@ -116,7 +118,7 @@ data class TweakGroup(val title: String, val entries: List<TweakEntry<*>>) {
fun editableInt(
key: String,
name: String,
defaultValue: Flow<Int>? = null,
defaultValue: StateFlow<Int>? = null,
) {
tweak(EditableIntTweakEntry(key, name, defaultValue))
}
Expand All @@ -132,7 +134,7 @@ data class TweakGroup(val title: String, val entries: List<TweakEntry<*>>) {
fun editableLong(
key: String,
name: String,
defaultValue: Flow<Long>? = null,
defaultValue: StateFlow<Long>? = null,
) {
tweak(EditableLongTweakEntry(key, name, defaultValue))
}
Expand Down Expand Up @@ -160,68 +162,68 @@ class RouteButtonTweakEntry(key: String, name: String, val route: String) :
TweakEntry<Unit>(key, name)

/** A non editable entry */
class ReadOnlyStringTweakEntry(key: String, name: String, override val value: Flow<String>) :
class ReadOnlyStringTweakEntry(key: String, name: String, override val value: StateFlow<String>) :
TweakEntry<String>(key, name), ReadOnly<String>

/** An editable entry. It can be modified by using long-press*/
class EditableStringTweakEntry(
key: String,
name: String,
override val defaultValue: Flow<String>? = null,
override val defaultValue: StateFlow<String>? = null,
) : TweakEntry<String>(key, name), Editable<String> {
constructor(
key: String,
name: String,
defaultUniqueValue: String,
) : this(key, name, flow { emit(defaultUniqueValue) })
) : this(key, name, MutableStateFlow(defaultUniqueValue))
}

/** An editable entry. It can be modified by using long-press*/
class EditableBooleanTweakEntry(
key: String,
name: String,
override val defaultValue: Flow<Boolean>? = null,
override val defaultValue: StateFlow<Boolean>? = null,
) : TweakEntry<Boolean>(key, name), Editable<Boolean> {
constructor(
key: String,
name: String,
defaultUniqueValue: Boolean,
) : this(key, name, flow { emit(defaultUniqueValue) })
) : this(key, name, MutableStateFlow(defaultUniqueValue))
}

/** An editable entry. It can be modified by using long-press*/
class EditableIntTweakEntry(
key: String,
name: String,
override val defaultValue: Flow<Int>? = null,
override val defaultValue: StateFlow<Int>? = null,
) : TweakEntry<Int>(key, name), Editable<Int> {
constructor(
key: String,
name: String,
defaultUniqueValue: Int,
) : this(key, name, flow { emit(defaultUniqueValue) })
) : this(key, name, MutableStateFlow(defaultUniqueValue))
}

/** An editable entry. It can be modified by using long-press*/
class EditableLongTweakEntry(
key: String,
name: String,
override val defaultValue: Flow<Long>? = null,
override val defaultValue: StateFlow<Long>? = null,
) : TweakEntry<Long>(key, name), Editable<Long> {
constructor(
key: String,
name: String,
defaultUniqueValue: Long,
) : this(key, name, flow { emit(defaultUniqueValue) })
) : this(key, name, MutableStateFlow(defaultUniqueValue))
}

sealed interface Modifiable
interface Editable<T> : Modifiable {
val defaultValue: Flow<T>?
val defaultValue: StateFlow<T>?
}

interface ReadOnly<T> : Modifiable {
val value: Flow<T>
val value: StateFlow<T>
}

internal object Constants {
Expand Down

0 comments on commit c4e375a

Please sign in to comment.