Introduce subscription-based state, remove DataStore stopgap

This commit is contained in:
Reinout Meliesie 2024-12-19 18:49:22 +01:00
parent 8413cf7ae7
commit 87eb947936
Signed by: zedfrigg
GPG key ID: 3AFCC06481308BC6
4 changed files with 49 additions and 44 deletions

View file

@ -66,7 +66,6 @@ dependencies {
implementation ( "androidx.compose.ui" , "ui" , "1.7.6" ) implementation ( "androidx.compose.ui" , "ui" , "1.7.6" )
implementation ( "androidx.compose.ui" , "ui-graphics" , "1.7.6" ) implementation ( "androidx.compose.ui" , "ui-graphics" , "1.7.6" )
debugImplementation ( "androidx.compose.ui" , "ui-tooling" , "1.7.6" ) debugImplementation ( "androidx.compose.ui" , "ui-tooling" , "1.7.6" )
implementation ( "androidx.datastore" , "datastore-preferences" , "1.1.1" )
implementation ( "androidx.lifecycle" , "lifecycle-runtime-ktx" , "2.8.7" ) implementation ( "androidx.lifecycle" , "lifecycle-runtime-ktx" , "2.8.7" )
implementation ( "org.jetbrains.kotlinx" , "kotlinx-coroutines-android" , "1.9.0" ) implementation ( "org.jetbrains.kotlinx" , "kotlinx-coroutines-android" , "1.9.0" )
implementation ( "org.jetbrains.kotlinx" , "kotlinx-serialization-json" , "1.7.3" ) implementation ( "org.jetbrains.kotlinx" , "kotlinx-serialization-json" , "1.7.3" )

View file

@ -1,26 +1,31 @@
package com.kernelmaft.zanbur package com.kernelmaft.zanbur
import androidx.compose.runtime.*
enum class ChangeSource { Local , Remote }
typealias CurrentSceneSubscriber = ( Group , Scene , ChangeSource ) -> Unit
typealias GroupAddedSubscriber = ( Group , ChangeSource ) -> Unit
object AppState { object AppState {
// The index of a group in this list is always equal to its ID private val currentSceneSubscribers : MutableList <CurrentSceneSubscriber> = mutableListOf ()
val groups : State < List <Group> > get () = groupsAsMutable private val groupAddedSubscribers : MutableList <GroupAddedSubscriber> = mutableListOf ()
private val groupsAsMutable : MutableState < List <Group> > = mutableStateOf ( emptyList () )
fun setCurrentScene ( groupId : Int , scene : Scene ) { fun setCurrentScene ( group : Group , newScene : Scene , source : ChangeSource ) {
groupsAsMutable . value = groupsAsMutable . value . mapIndexed { index , group -> for ( subscriber in currentSceneSubscribers ) {
if ( index == groupId ) group . copy ( currentScene = scene ) subscriber ( group , newScene , source )
else group
} }
} }
fun subscribeToCurrentScene ( subscriber : CurrentSceneSubscriber ) {
currentSceneSubscribers . add (subscriber)
}
fun addGroup ( group : Group ) { fun addGroup ( newGroup : Group , source : ChangeSource ) {
val newGroups = groupsAsMutable . value . toMutableList () for ( subscriber in groupAddedSubscribers ) {
// Wow this is sooo much better than Java subscriber ( newGroup , source )
if ( newGroups . getOrNull ( group . id ) != null ) newGroups . removeAt ( group . id ) }
newGroups . add ( group . id , group ) }
groupsAsMutable . value = newGroups fun subscribeToGroupAdded ( subscriber : GroupAddedSubscriber ) {
groupAddedSubscribers . add (subscriber)
} }
} }

View file

@ -0,0 +1,21 @@
package com.kernelmaft.zanbur
import androidx.compose.runtime.*
fun createGroupsComposeState () : MutableState < List <Group> > {
val groups : MutableState < List <Group> > = mutableStateOf ( emptyList () )
AppState . subscribeToGroupAdded { newGroup , _ ->
groups . value = groups . value . plus (newGroup)
}
AppState . subscribeToCurrentScene { group , newScene , source ->
groups . value = groups . value . map { when ( it . id ) {
group . id -> it . copy ( currentScene = newScene )
else -> it
} }
}
return groups
}

View file

@ -5,40 +5,31 @@ import androidx.activity.compose.*
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.ui.* import androidx.compose.ui.*
import androidx.compose.ui.unit.* import androidx.compose.ui.unit.*
import androidx.datastore.preferences.*
import androidx.datastore.preferences.core.*
import androidx.lifecycle.* import androidx.lifecycle.*
import kotlinx.coroutines.* import com.kernelmaft.zanbur.ChangeSource.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.flow.*
class MainActivity : EdgeToEdgeActivity () { class MainActivity : EdgeToEdgeActivity () {
val dataStore = PreferenceDataStoreFactory . create { preferencesDataStoreFile ("state") }
override fun onCreate ( savedInstanceState : Bundle ? ) { override fun onCreate ( savedInstanceState : Bundle ? ) {
super . onCreate (savedInstanceState) super . onCreate (savedInstanceState)
Config . groups . forEach { AppState . addGroup (it) } val groups = createGroupsComposeState ()
lifecycleScope . launch (IO) { AppState . subscribeToCurrentScene { group , newScene , source ->
val prefs = dataStore . data . firstOrNull () if ( source == Local ) {
val savedSceneName = prefs ?. get ( stringPreferencesKey ("scene") ) publishSceneChange ( group , newScene )
if ( savedSceneName != null ) {
val savedScene = AppState . groups . value [0] . scenes
. find { it . name == savedSceneName }
savedScene ?. let { AppState . setCurrentScene ( 0 , it ) }
} }
} }
Config . groups . forEach { AppState . addGroup ( it , Remote ) }
setContent { setContent {
AppFrame { AppFrame {
Column ( Modifier . width ( 300 . dp ) ) { Column ( Modifier . width ( 300 . dp ) ) {
AppState . groups . value . forEach { group -> groups . value . forEach { group ->
SceneSwitcher (group) { newScene -> SceneSwitcher (group) { newScene ->
AppState . setCurrentScene ( group . id , newScene ) AppState . setCurrentScene ( group , newScene , Local )
publishSceneChange ( group , newScene )
} }
} }
} }
@ -47,15 +38,4 @@ class MainActivity : EdgeToEdgeActivity () {
MqttClient . run (lifecycleScope) MqttClient . run (lifecycleScope)
} }
override fun onStop () {
super . onStop ()
val currentScene = AppState . groups . value [0] . currentScene
if ( currentScene != null ) lifecycleScope . launch (IO) {
dataStore . edit {
it [ stringPreferencesKey ("scene") ] = currentScene . name
}
}
}
} }