diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 63a6902..f29eafc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,20 +9,20 @@ val keystoreProperties = Properties () keystoreProperties . load ( FileInputStream ( rootProject . file ("keystore.properties") ) ) plugins { - id ("com.android.application") . version ("8.8.0") - id ("org.jetbrains.kotlin.android") . version ("2.1.10") - id ("org.jetbrains.kotlin.plugin.compose") . version ("2.1.10") - id ("org.jetbrains.kotlin.plugin.serialization") . version ("2.1.10") + id ("com.android.application") . version ("8.7.2") + id ("org.jetbrains.kotlin.android") . version ("2.0.0") + id ("org.jetbrains.kotlin.plugin.compose") . version ("2.0.0") + id ("org.jetbrains.kotlin.plugin.serialization") . version ("2.0.0") } android { namespace = "com.kernelmaft.zanbur" - compileSdk = 35 + compileSdk = 34 defaultConfig { applicationId = "com.kernelmaft.zanbur" - minSdk = 35 - targetSdk = 35 + minSdk = 31 + targetSdk = 34 versionCode = 1 versionName = "1.0" } @@ -47,11 +47,10 @@ android { } } compileOptions { - // Required even though we don't have any Java sources because it needs to match Kotlin's JVM version - targetCompatibility = JavaVersion . VERSION_23 + targetCompatibility = JavaVersion . VERSION_11 } kotlinOptions { - jvmTarget = "23" + jvmTarget = "11" } buildFeatures { compose = true @@ -61,18 +60,19 @@ android { dependencies { // Android runtime libraries implementation ( "com.google.android.material" , "material" , "1.12.0" ) - implementation ( "androidx.activity" , "activity-compose" , "1.10.0" ) - implementation ( "androidx.core" , "core-ktx" , "1.15.0" ) + implementation ( "androidx.activity" , "activity-compose" , "1.9.3" ) + implementation ( "androidx.core" , "core-ktx" , "1.13.1" ) implementation ( "androidx.compose.material3" , "material3" , "1.3.1" ) - implementation ( "androidx.compose.ui" , "ui" , "1.7.7" ) - implementation ( "androidx.compose.ui" , "ui-graphics" , "1.7.7" ) - debugImplementation ( "androidx.compose.ui" , "ui-tooling" , "1.7.7" ) + implementation ( "androidx.compose.ui" , "ui" , "1.7.5" ) + implementation ( "androidx.compose.ui" , "ui-graphics" , "1.7.5" ) + debugImplementation ( "androidx.compose.ui" , "ui-tooling" , "1.7.5" ) + implementation ( "androidx.datastore" , "datastore-preferences" , "1.1.1" ) implementation ( "androidx.lifecycle" , "lifecycle-runtime-ktx" , "2.8.7" ) - implementation ( "org.jetbrains.kotlinx" , "kotlinx-coroutines-android" , "1.10.1" ) - implementation ( "org.jetbrains.kotlinx" , "kotlinx-serialization-json" , "1.8.0" ) + implementation ( "org.jetbrains.kotlinx" , "kotlinx-coroutines-android" , "1.9.0" ) + implementation ( "org.jetbrains.kotlinx" , "kotlinx-serialization-json" , "1.7.3" ) // Other libraries - implementation ( "io.github.davidepianca98" , "kmqtt-common" , "1.0.0" ) - implementation ( "io.github.davidepianca98" , "kmqtt-client" , "1.0.0" ) + implementation ( "io.github.davidepianca98" , "kmqtt-common" , "0.4.8" ) + implementation ( "io.github.davidepianca98" , "kmqtt-client" , "0.4.8" ) } tasks . withType ( KotlinCompile :: class ) . all { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 90a24a3..1acccf6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,14 +4,17 @@ + android:supportsRtl = "true" + android:theme = "@style/Theme.Zanbur" > + android:name = ".MainActivity" + android:exported = "true" + android:label = "@string/title_activity_main" + android:theme = "@style/Theme.Zanbur" > diff --git a/app/src/main/java/com/kernelmaft/zanbur/app-state.kt b/app/src/main/java/com/kernelmaft/zanbur/app-state.kt new file mode 100644 index 0000000..52c4991 --- /dev/null +++ b/app/src/main/java/com/kernelmaft/zanbur/app-state.kt @@ -0,0 +1,25 @@ +package com.kernelmaft.zanbur + + + +object AppState { + val groups : List get () = groupsAsMutable + private var groupsAsMutable : List = emptyList () + + private val subscribers : MutableList < ( List ) -> Unit > = mutableListOf () + + fun subscribe ( subscriber : ( List ) -> Unit ) = subscribers . add (subscriber) + + fun addGroup ( group : Group ) { + groupsAsMutable += group + subscribers . forEach { it (groups) } + } + + fun setCurrentScene ( groupId : Int , scene : Scene ) { + groupsAsMutable = groupsAsMutable . mapIndexed { index , group -> + if ( index == groupId ) group . copy ( currentScene = scene ) + else group + } + subscribers . forEach { it (groups) } + } +} diff --git a/app/src/main/java/com/kernelmaft/zanbur/common/app-state.kt b/app/src/main/java/com/kernelmaft/zanbur/common/app-state.kt deleted file mode 100644 index 6abdb42..0000000 --- a/app/src/main/java/com/kernelmaft/zanbur/common/app-state.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.kernelmaft.zanbur.common - - - -enum class ChangeSource { Local , Remote } - -typealias CurrentSceneSubscriber = ( Group , Scene , ChangeSource ) -> Unit -typealias GroupAddedSubscriber = ( Group , ChangeSource ) -> Unit - -object AppState { - private val currentSceneSubscribers : MutableList = mutableListOf () - private val groupAddedSubscribers : MutableList = mutableListOf () - - fun setCurrentScene ( group : Group , newScene : Scene , source : ChangeSource ) { - for ( subscriber in currentSceneSubscribers ) { - subscriber ( group , newScene , source ) - } - } - fun subscribeToCurrentScene ( subscriber : CurrentSceneSubscriber ) { - currentSceneSubscribers . add (subscriber) - } - - fun addGroup ( newGroup : Group , source : ChangeSource ) { - for ( subscriber in groupAddedSubscribers ) { - subscriber ( newGroup , source ) - } - } - fun subscribeToGroupAdded ( subscriber : GroupAddedSubscriber ) { - groupAddedSubscribers . add (subscriber) - } -} diff --git a/app/src/main/java/com/kernelmaft/zanbur/ui/components.kt b/app/src/main/java/com/kernelmaft/zanbur/components.kt similarity index 94% rename from app/src/main/java/com/kernelmaft/zanbur/ui/components.kt rename to app/src/main/java/com/kernelmaft/zanbur/components.kt index 03fc6ac..e2d54e9 100644 --- a/app/src/main/java/com/kernelmaft/zanbur/ui/components.kt +++ b/app/src/main/java/com/kernelmaft/zanbur/components.kt @@ -1,4 +1,4 @@ -package com.kernelmaft.zanbur.ui +package com.kernelmaft.zanbur import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Arrangement.Center @@ -9,7 +9,6 @@ import androidx.compose.material3.ButtonDefaults.shape import androidx.compose.runtime.* import androidx.compose.ui.* import androidx.compose.ui.Alignment.Companion.CenterHorizontally -import com.kernelmaft.zanbur.common.* diff --git a/app/src/main/java/com/kernelmaft/zanbur/common/config.kt b/app/src/main/java/com/kernelmaft/zanbur/config.kt similarity index 92% rename from app/src/main/java/com/kernelmaft/zanbur/common/config.kt rename to app/src/main/java/com/kernelmaft/zanbur/config.kt index 3e4ddda..ef1f384 100644 --- a/app/src/main/java/com/kernelmaft/zanbur/common/config.kt +++ b/app/src/main/java/com/kernelmaft/zanbur/config.kt @@ -1,4 +1,4 @@ -package com.kernelmaft.zanbur.common +package com.kernelmaft.zanbur diff --git a/app/src/main/java/com/kernelmaft/zanbur/main.kt b/app/src/main/java/com/kernelmaft/zanbur/main.kt new file mode 100644 index 0000000..769890f --- /dev/null +++ b/app/src/main/java/com/kernelmaft/zanbur/main.kt @@ -0,0 +1,65 @@ +package com.kernelmaft.zanbur + +import android.os.* +import androidx.activity.compose.* +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.* +import androidx.compose.ui.* +import androidx.compose.ui.unit.* +import androidx.datastore.preferences.core.* +import androidx.lifecycle.* +import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.flow.* + + + +class MainActivity : EdgeToEdgeActivity () { + override fun onCreate ( savedInstanceState : Bundle ? ) { + super . onCreate (savedInstanceState) + + Config . groups . forEach { AppState . addGroup (it) } + + var groups by mutableStateOf ( AppState . groups ) + AppState . subscribe { groups = it } + + lifecycleScope . launch (IO) { + val prefs = dataStore . data . firstOrNull () + if ( prefs != null ) { + val savedSceneName = prefs [ stringPreferencesKey ("scene") ] + if ( savedSceneName != null ) { + val savedScene = AppState . groups [0] . scenes . find { it . name == savedSceneName } + if ( savedScene != null ) { + AppState . setCurrentScene ( 0 , savedScene ) + } + } + } + } + + setContent { + AppFrame { + Column ( Modifier . width ( 300 . dp ) ) { + groups . forEach { group -> + SceneSwitcher (group) { + AppState . setCurrentScene ( group . id , it ) + publishSceneChange ( group , it ) + } + } + } + } + } + + MqttClient . run (lifecycleScope) + } + + override fun onStop () { + super . onStop () + + val currentScene = AppState . groups [0] . currentScene + if ( currentScene != null ) lifecycleScope . launch (IO) { + applicationContext . dataStore . edit { + it [ stringPreferencesKey ("scene") ] = currentScene . name + } + } + } +} diff --git a/app/src/main/java/com/kernelmaft/zanbur/network/mqtt.kt b/app/src/main/java/com/kernelmaft/zanbur/mqtt.kt similarity index 70% rename from app/src/main/java/com/kernelmaft/zanbur/network/mqtt.kt rename to app/src/main/java/com/kernelmaft/zanbur/mqtt.kt index 212d73a..5d633ac 100644 --- a/app/src/main/java/com/kernelmaft/zanbur/network/mqtt.kt +++ b/app/src/main/java/com/kernelmaft/zanbur/mqtt.kt @@ -1,16 +1,16 @@ -package com.kernelmaft.zanbur.network +package com.kernelmaft.zanbur -import com.kernelmaft.zanbur.common.Config.MQTT_SERVER_HOST -import com.kernelmaft.zanbur.common.Config.MQTT_SERVER_PORT -import com.kernelmaft.zanbur.common.Config.MQTT_TOPIC -import io.github.davidepianca98.* -import io.github.davidepianca98.mqtt.* -import io.github.davidepianca98.mqtt.MQTTVersion.* -import io.github.davidepianca98.mqtt.packets.Qos.* -import io.github.davidepianca98.mqtt.packets.mqtt.* +import MQTTClient +import com.kernelmaft.zanbur.Config.MQTT_SERVER_HOST +import com.kernelmaft.zanbur.Config.MQTT_SERVER_PORT +import com.kernelmaft.zanbur.Config.MQTT_TOPIC import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.serialization.json.* +import mqtt.* +import mqtt.MQTTVersion.* +import mqtt.packets.Qos.* +import mqtt.packets.mqtt.* diff --git a/app/src/main/java/com/kernelmaft/zanbur/common/ontology.kt b/app/src/main/java/com/kernelmaft/zanbur/ontology.kt similarity index 83% rename from app/src/main/java/com/kernelmaft/zanbur/common/ontology.kt rename to app/src/main/java/com/kernelmaft/zanbur/ontology.kt index 86e8a1c..4bec33e 100644 --- a/app/src/main/java/com/kernelmaft/zanbur/common/ontology.kt +++ b/app/src/main/java/com/kernelmaft/zanbur/ontology.kt @@ -1,4 +1,4 @@ -package com.kernelmaft.zanbur.common +package com.kernelmaft.zanbur diff --git a/app/src/main/java/com/kernelmaft/zanbur/persistence.kt b/app/src/main/java/com/kernelmaft/zanbur/persistence.kt new file mode 100644 index 0000000..9110f71 --- /dev/null +++ b/app/src/main/java/com/kernelmaft/zanbur/persistence.kt @@ -0,0 +1,10 @@ +package com.kernelmaft.zanbur + +import android.content.* +import androidx.datastore.core.* +import androidx.datastore.preferences.* +import androidx.datastore.preferences.core.* + + + +val Context . dataStore : DataStore by preferencesDataStore ("state") diff --git a/app/src/main/java/com/kernelmaft/zanbur/ui/theme.kt b/app/src/main/java/com/kernelmaft/zanbur/theme.kt similarity index 94% rename from app/src/main/java/com/kernelmaft/zanbur/ui/theme.kt rename to app/src/main/java/com/kernelmaft/zanbur/theme.kt index 0da4c53..8a95cbc 100644 --- a/app/src/main/java/com/kernelmaft/zanbur/ui/theme.kt +++ b/app/src/main/java/com/kernelmaft/zanbur/theme.kt @@ -1,4 +1,4 @@ -package com.kernelmaft.zanbur.ui +package com.kernelmaft.zanbur import android.os.* import androidx.activity.* @@ -29,6 +29,7 @@ open class EdgeToEdgeActivity : ComponentActivity () { override fun onCreate ( savedInstanceState : Bundle ? ) { super . onCreate (savedInstanceState) + enableEdgeToEdge () actionBar ?. hide () } } diff --git a/app/src/main/java/com/kernelmaft/zanbur/ui/compose-state.kt b/app/src/main/java/com/kernelmaft/zanbur/ui/compose-state.kt deleted file mode 100644 index 212f254..0000000 --- a/app/src/main/java/com/kernelmaft/zanbur/ui/compose-state.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.kernelmaft.zanbur.ui - -import androidx.compose.runtime.* -import com.kernelmaft.zanbur.common.* - - - -fun createGroupsComposeState () : MutableState < List > { - val groups : MutableState < List > = 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 -} diff --git a/app/src/main/java/com/kernelmaft/zanbur/ui/main-activity.kt b/app/src/main/java/com/kernelmaft/zanbur/ui/main-activity.kt deleted file mode 100644 index 147fd0c..0000000 --- a/app/src/main/java/com/kernelmaft/zanbur/ui/main-activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.kernelmaft.zanbur.ui - -import android.os.* -import androidx.activity.compose.* -import androidx.compose.foundation.layout.* -import androidx.compose.ui.* -import androidx.compose.ui.unit.* -import androidx.lifecycle.* -import com.kernelmaft.zanbur.common.* -import com.kernelmaft.zanbur.common.ChangeSource.* -import com.kernelmaft.zanbur.network.* - - - -class MainActivity : EdgeToEdgeActivity () { - override fun onCreate ( savedInstanceState : Bundle ? ) { - super . onCreate (savedInstanceState) - - val groups = createGroupsComposeState () - - AppState . subscribeToCurrentScene { group , newScene , source -> - if ( source == Local ) { - publishSceneChange ( group , newScene ) - } - } - - Config . groups . forEach { AppState . addGroup ( it , Remote ) } - - setContent { - AppFrame { - Column ( Modifier . width ( 300 . dp ) ) { - groups . value . forEach { group -> - SceneSwitcher (group) { newScene -> - AppState . setCurrentScene ( group , newScene , Local ) - } - } - } - } - } - - MqttClient . run (lifecycleScope) - } -} diff --git a/app/src/main/java/com/kernelmaft/zanbur/network/zigbee2mqtt.kt b/app/src/main/java/com/kernelmaft/zanbur/zigbee2mqtt.kt similarity index 77% rename from app/src/main/java/com/kernelmaft/zanbur/network/zigbee2mqtt.kt rename to app/src/main/java/com/kernelmaft/zanbur/zigbee2mqtt.kt index e59269f..0dc2d88 100644 --- a/app/src/main/java/com/kernelmaft/zanbur/network/zigbee2mqtt.kt +++ b/app/src/main/java/com/kernelmaft/zanbur/zigbee2mqtt.kt @@ -1,7 +1,6 @@ -package com.kernelmaft.zanbur.network +package com.kernelmaft.zanbur -import com.kernelmaft.zanbur.common.* -import com.kernelmaft.zanbur.common.Config.MQTT_TOPIC +import com.kernelmaft.zanbur.Config.MQTT_TOPIC import kotlinx.serialization.* import kotlinx.serialization.json.* diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..30feaa0 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + Zanbur + Zanbur + + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..ced7955 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,8 @@ + + + + +