| <selectionStates> | <selectionStates> | ||||
| <SelectionState runConfigName="app"> | <SelectionState runConfigName="app"> | ||||
| <option name="selectionMode" value="DROPDOWN" /> | <option name="selectionMode" value="DROPDOWN" /> | ||||
| <DropdownSelection timestamp="2026-07-17T13:14:43.254466300Z"> | |||||
| <DropdownSelection timestamp="2026-07-19T12:56:18.942399300Z"> | |||||
| <Target type="DEFAULT_BOOT"> | <Target type="DEFAULT_BOOT"> | ||||
| <handle> | <handle> | ||||
| <DeviceId pluginId="PhysicalDevice" identifier="serial=5C060DLCH002WX" /> | <DeviceId pluginId="PhysicalDevice" identifier="serial=5C060DLCH002WX" /> |
| implementation(libs.androidx.compose.ui.graphics) | implementation(libs.androidx.compose.ui.graphics) | ||||
| implementation(libs.androidx.compose.ui.tooling.preview) | implementation(libs.androidx.compose.ui.tooling.preview) | ||||
| implementation(libs.androidx.core.ktx) | implementation(libs.androidx.core.ktx) | ||||
| implementation(libs.androidx.core.splashscreen) | |||||
| implementation(libs.androidx.datastore.preferences) | implementation(libs.androidx.datastore.preferences) | ||||
| implementation(libs.androidx.lifecycle.runtime.compose) | implementation(libs.androidx.lifecycle.runtime.compose) | ||||
| implementation(libs.androidx.lifecycle.runtime.ktx) | implementation(libs.androidx.lifecycle.runtime.ktx) |
| android:name=".MainActivity" | android:name=".MainActivity" | ||||
| android:exported="true" | android:exported="true" | ||||
| android:label="@string/app_name" | android:label="@string/app_name" | ||||
| android:theme="@style/Theme.LEDLampControl" | |||||
| android:theme="@style/Theme.App.Starting" | |||||
| android:windowSoftInputMode="adjustResize"> | android:windowSoftInputMode="adjustResize"> | ||||
| <intent-filter> | <intent-filter> | ||||
| <action android:name="android.intent.action.MAIN" /> | <action android:name="android.intent.action.MAIN" /> |
| package ch.spherIC.ledlampcontrol | package ch.spherIC.ledlampcontrol | ||||
| import android.Manifest | |||||
| import android.os.Bundle | import android.os.Bundle | ||||
| import androidx.activity.ComponentActivity | import androidx.activity.ComponentActivity | ||||
| import androidx.activity.compose.setContent | import androidx.activity.compose.setContent | ||||
| import androidx.activity.enableEdgeToEdge | import androidx.activity.enableEdgeToEdge | ||||
| import androidx.activity.result.contract.ActivityResultContracts | |||||
| import androidx.compose.foundation.Image | |||||
| import androidx.compose.foundation.isSystemInDarkTheme | |||||
| import androidx.compose.foundation.layout.* | |||||
| import androidx.compose.runtime.Composable | |||||
| import androidx.compose.runtime.LaunchedEffect | |||||
| import androidx.compose.runtime.collectAsState | |||||
| import androidx.compose.runtime.getValue | |||||
| import androidx.compose.runtime.mutableStateOf | |||||
| import androidx.compose.runtime.remember | |||||
| import androidx.compose.runtime.setValue | |||||
| import androidx.compose.ui.Alignment | |||||
| import androidx.compose.ui.Modifier | |||||
| import androidx.compose.ui.layout.ContentScale | |||||
| import androidx.compose.ui.res.painterResource | |||||
| import androidx.compose.ui.unit.dp | |||||
| import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen | |||||
| import androidx.lifecycle.ViewModel | |||||
| import androidx.lifecycle.ViewModelProvider | |||||
| import androidx.lifecycle.viewmodel.compose.viewModel | import androidx.lifecycle.viewmodel.compose.viewModel | ||||
| import ch.spherIC.ledlampcontrol.data.network.LedWebSocketManager | |||||
| import ch.spherIC.ledlampcontrol.data.network.LedDiscoveryManager | import ch.spherIC.ledlampcontrol.data.network.LedDiscoveryManager | ||||
| import ch.spherIC.ledlampcontrol.data.network.LedWebSocketManager | |||||
| import ch.spherIC.ledlampcontrol.data.repository.LedRepository | import ch.spherIC.ledlampcontrol.data.repository.LedRepository | ||||
| import ch.spherIC.ledlampcontrol.data.repository.SettingsRepository | import ch.spherIC.ledlampcontrol.data.repository.SettingsRepository | ||||
| import ch.spherIC.ledlampcontrol.ui.dashboard.DashboardScreen | import ch.spherIC.ledlampcontrol.ui.dashboard.DashboardScreen | ||||
| import ch.spherIC.ledlampcontrol.ui.theme.LEDLampControlTheme | import ch.spherIC.ledlampcontrol.ui.theme.LEDLampControlTheme | ||||
| import ch.spherIC.ledlampcontrol.ui.viewmodel.LedViewModel | import ch.spherIC.ledlampcontrol.ui.viewmodel.LedViewModel | ||||
| import okhttp3.OkHttpClient | import okhttp3.OkHttpClient | ||||
| import androidx.lifecycle.ViewModel | |||||
| import androidx.lifecycle.ViewModelProvider | |||||
| import androidx.compose.foundation.isSystemInDarkTheme | |||||
| import androidx.compose.runtime.collectAsState | |||||
| import androidx.compose.runtime.getValue | |||||
| import androidx.activity.result.contract.ActivityResultContracts | |||||
| import android.Manifest | |||||
| import java.util.concurrent.TimeUnit | import java.util.concurrent.TimeUnit | ||||
| class MainActivity : ComponentActivity() { | class MainActivity : ComponentActivity() { | ||||
| ) { } | ) { } | ||||
| override fun onCreate(savedInstanceState: Bundle?) { | override fun onCreate(savedInstanceState: Bundle?) { | ||||
| installSplashScreen() | |||||
| super.onCreate(savedInstanceState) | super.onCreate(savedInstanceState) | ||||
| enableEdgeToEdge() | enableEdgeToEdge() | ||||
| darkTheme = darkTheme, | darkTheme = darkTheme, | ||||
| dynamicColor = dynamicColor | dynamicColor = dynamicColor | ||||
| ) { | ) { | ||||
| DashboardScreen(viewModel = viewModel) | |||||
| var showSplashScreen by remember { mutableStateOf(true) } | |||||
| if (showSplashScreen) { | |||||
| CustomSplashScreen(onFinished = { showSplashScreen = false }) | |||||
| } else { | |||||
| DashboardScreen(viewModel = viewModel) | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| webSocketManager.disconnect() | webSocketManager.disconnect() | ||||
| } | } | ||||
| } | } | ||||
| @Composable | |||||
| fun CustomSplashScreen(onFinished: () -> Unit) { | |||||
| LaunchedEffect(Unit) { | |||||
| kotlinx.coroutines.delay(3000) // Show for 3 seconds | |||||
| onFinished() | |||||
| } | |||||
| Box(modifier = Modifier.fillMaxSize()) { | |||||
| // 1. Background Image (LED on Grid) | |||||
| Image( | |||||
| painter = painterResource(id = R.drawable.led_on_grid), | |||||
| contentDescription = null, | |||||
| modifier = Modifier.fillMaxSize(), | |||||
| contentScale = ContentScale.Crop | |||||
| ) | |||||
| // Group Icon and Logo at the bottom area | |||||
| Column( | |||||
| modifier = Modifier | |||||
| .align(Alignment.BottomCenter) | |||||
| .padding(bottom = 96.dp), | |||||
| horizontalAlignment = Alignment.CenterHorizontally | |||||
| ) { | |||||
| // 2. Real App Icon | |||||
| Image( | |||||
| painter = painterResource(id = R.drawable.app_icon), | |||||
| contentDescription = null, | |||||
| modifier = Modifier.size(200.dp), | |||||
| contentScale = ContentScale.Fit | |||||
| ) | |||||
| Spacer(modifier = Modifier.height(24.dp)) | |||||
| // 3. Spheric Logo | |||||
| Image( | |||||
| painter = painterResource(id = R.drawable.ic_spheric_logo), | |||||
| contentDescription = null, | |||||
| modifier = Modifier.width(200.dp), | |||||
| contentScale = ContentScale.Fit | |||||
| ) | |||||
| } | |||||
| } | |||||
| } |
| <path | <path | ||||
| android:pathData="m69.11,49.3q-1.59,0 -2.72,0.97 -1.11,0.95 -1.11,2.31v2.45q0,1.36 1.11,2.33 1.13,0.95 2.72,0.95h7.65q0.66,0 1.06,0.34 0.39,0.34 0.39,0.9v2.06q0,0.56 -0.41,0.91 -0.39,0.34 -1.06,0.34L65.99,62.87v2.44h11.25q1.59,0 2.71,-0.95 1.13,-0.95 1.13,-2.31L81.08,59.23q0,-1.36 -1.13,-2.31 -1.11,-0.97 -2.71,-0.97h-7.63q-0.66,0 -1.07,-0.34 -0.39,-0.36 -0.39,-0.91L68.14,53.01q0,-0.56 0.39,-0.9 0.41,-0.36 1.07,-0.36 7.08,-0.02 10.03,-0.02v-2.44z" | android:pathData="m69.11,49.3q-1.59,0 -2.72,0.97 -1.11,0.95 -1.11,2.31v2.45q0,1.36 1.11,2.33 1.13,0.95 2.72,0.95h7.65q0.66,0 1.06,0.34 0.39,0.34 0.39,0.9v2.06q0,0.56 -0.41,0.91 -0.39,0.34 -1.06,0.34L65.99,62.87v2.44h11.25q1.59,0 2.71,-0.95 1.13,-0.95 1.13,-2.31L81.08,59.23q0,-1.36 -1.13,-2.31 -1.11,-0.97 -2.71,-0.97h-7.63q-0.66,0 -1.07,-0.34 -0.39,-0.36 -0.39,-0.91L68.14,53.01q0,-0.56 0.39,-0.9 0.41,-0.36 1.07,-0.36 7.08,-0.02 10.03,-0.02v-2.44z" | ||||
| android:strokeWidth="0.26458332" | android:strokeWidth="0.26458332" | ||||
| android:fillColor="#000000" | |||||
| android:strokeColor="#00000000"/> | |||||
| android:fillColor="#ffffff" | |||||
| android:strokeColor="#ffffffff"/> | |||||
| <path | <path | ||||
| android:pathData="M83.08,70.98L83.08,49.3h11.52q1.97,0 3.35,1.25 1.4,1.24 1.4,2.99v7.51q0,1.76 -1.4,3.01 -1.38,1.24 -3.35,1.24h-8.63v5.68zM94.21,62.72q0.97,0 1.61,-0.68 0.64,-0.68 0.64,-1.61v-6.27q0,-0.97 -0.72,-1.61 -0.72,-0.64 -1.81,-0.64h-7.97v10.8l7.24,0.02h-0.73q0.29,0 1.74,0z" | android:pathData="M83.08,70.98L83.08,49.3h11.52q1.97,0 3.35,1.25 1.4,1.24 1.4,2.99v7.51q0,1.76 -1.4,3.01 -1.38,1.24 -3.35,1.24h-8.63v5.68zM94.21,62.72q0.97,0 1.61,-0.68 0.64,-0.68 0.64,-1.61v-6.27q0,-0.97 -0.72,-1.61 -0.72,-0.64 -1.81,-0.64h-7.97v10.8l7.24,0.02h-0.73q0.29,0 1.74,0z" | ||||
| android:strokeWidth="0.26458332" | android:strokeWidth="0.26458332" | ||||
| android:fillColor="#000000" | |||||
| android:strokeColor="#00000000"/> | |||||
| android:fillColor="#ffffff" | |||||
| android:strokeColor="#ffffffff"/> | |||||
| <path | <path | ||||
| android:pathData="m101.36,43.62v21.68h2.88L104.24,51.92q1.49,-0.02 8.24,-0.02 0.97,0 1.61,0.68 0.64,0.66 0.64,1.59L114.74,65.3h2.88L117.62,53.57q0,-1.76 -1.4,-2.99 -1.38,-1.25 -3.35,-1.25h-8.63v-5.7z" | android:pathData="m101.36,43.62v21.68h2.88L104.24,51.92q1.49,-0.02 8.24,-0.02 0.97,0 1.61,0.68 0.64,0.66 0.64,1.59L114.74,65.3h2.88L117.62,53.57q0,-1.76 -1.4,-2.99 -1.38,-1.25 -3.35,-1.25h-8.63v-5.7z" | ||||
| android:strokeWidth="0.26458332" | android:strokeWidth="0.26458332" | ||||
| android:fillColor="#000000" | |||||
| android:strokeColor="#00000000"/> | |||||
| android:fillColor="#ffffff" | |||||
| android:strokeColor="#ffffffff"/> | |||||
| <path | <path | ||||
| android:pathData="m124.16,49.32q-1.95,0 -3.33,1.25 -1.38,1.24 -1.38,2.99v5.23,3.24q0,1.36 1.11,2.31 1.13,0.95 2.72,0.95h11L134.28,62.81h-10.5q-0.63,0 -1.06,-0.3 -0.41,-0.3 -0.41,-0.79v-2.92h13.4L135.72,53.57q0,-1.76 -1.38,-2.99 -1.38,-1.25 -3.33,-1.25zM124.84,51.92h5.48q1.07,0 1.77,0.64 0.72,0.63 0.73,1.61v2.04h-10.52v-2.04q0,-0.97 0.72,-1.61 0.73,-0.64 1.81,-0.64z" | android:pathData="m124.16,49.32q-1.95,0 -3.33,1.25 -1.38,1.24 -1.38,2.99v5.23,3.24q0,1.36 1.11,2.31 1.13,0.95 2.72,0.95h11L134.28,62.81h-10.5q-0.63,0 -1.06,-0.3 -0.41,-0.3 -0.41,-0.79v-2.92h13.4L135.72,53.57q0,-1.76 -1.38,-2.99 -1.38,-1.25 -3.33,-1.25zM124.84,51.92h5.48q1.07,0 1.77,0.64 0.72,0.63 0.73,1.61v2.04h-10.52v-2.04q0,-0.97 0.72,-1.61 0.73,-0.64 1.81,-0.64z" | ||||
| android:strokeWidth="0.26458332" | android:strokeWidth="0.26458332" | ||||
| android:fillColor="#000000" | |||||
| android:strokeColor="#00000000"/> | |||||
| android:fillColor="#ffffff" | |||||
| android:strokeColor="#ffffffff"/> | |||||
| <path | <path | ||||
| android:pathData="m142.22,49.3q-1.95,0 -3.33,1.25 -1.38,1.24 -1.38,2.99L137.51,65.28h2.88L140.39,54.16q0,-0.99 0.72,-1.63 0.72,-0.64 1.79,-0.64h6.54v-2.58z" | android:pathData="m142.22,49.3q-1.95,0 -3.33,1.25 -1.38,1.24 -1.38,2.99L137.51,65.28h2.88L140.39,54.16q0,-0.99 0.72,-1.63 0.72,-0.64 1.79,-0.64h6.54v-2.58z" | ||||
| android:strokeWidth="0.26458332" | android:strokeWidth="0.26458332" | ||||
| android:fillColor="#000000" | |||||
| android:strokeColor="#00000000"/> | |||||
| android:fillColor="#ffffff" | |||||
| android:strokeColor="#ffffffff"/> | |||||
| <path | <path | ||||
| android:pathData="m151.77,43.62h2.97v21.68h-2.97z" | android:pathData="m151.77,43.62h2.97v21.68h-2.97z" | ||||
| android:strokeWidth="0.26458332" | android:strokeWidth="0.26458332" | ||||
| android:fillColor="#000000" | |||||
| android:strokeColor="#00000000"/> | |||||
| android:fillColor="#ffffff" | |||||
| android:strokeColor="#ffffffff"/> | |||||
| <path | <path | ||||
| android:pathData="m161.83,43.62q-2.02,0 -3.48,1.43 -1.43,1.43 -1.43,3.46v11.9q0,2.02 1.43,3.46 1.45,1.43 3.48,1.43h15.8L177.63,62.61h-15.1q-1.13,0 -1.88,-0.73 -0.73,-0.75 -0.73,-1.86L159.92,48.91q0,-1.11 0.73,-1.86 0.75,-0.75 1.88,-0.75h15.1v-2.67z" | android:pathData="m161.83,43.62q-2.02,0 -3.48,1.43 -1.43,1.43 -1.43,3.46v11.9q0,2.02 1.43,3.46 1.45,1.43 3.48,1.43h15.8L177.63,62.61h-15.1q-1.13,0 -1.88,-0.73 -0.73,-0.75 -0.73,-1.86L159.92,48.91q0,-1.11 0.73,-1.86 0.75,-0.75 1.88,-0.75h15.1v-2.67z" | ||||
| android:strokeWidth="0.26458332" | android:strokeWidth="0.26458332" | ||||
| android:fillColor="#000000" | |||||
| android:strokeColor="#00000000"/> | |||||
| android:fillColor="#ffffff" | |||||
| android:strokeColor="#ffffffff"/> | |||||
| </vector> | </vector> |
| <color name="teal_700">#FF018786</color> | <color name="teal_700">#FF018786</color> | ||||
| <color name="black">#FF000000</color> | <color name="black">#FF000000</color> | ||||
| <color name="white">#FFFFFFFF</color> | <color name="white">#FFFFFFFF</color> | ||||
| <color name="splash_background">#FF1C1B1F</color> | |||||
| </resources> | </resources> |
| <resources> | <resources> | ||||
| <!-- Base application theme. --> | |||||
| <style name="Theme.LEDLampControl" parent="Theme.AppCompat.DayNight.NoActionBar"> | |||||
| <!-- Customize your theme here. --> | |||||
| </style> | |||||
| <style name="Theme.LEDLampControl" parent="Theme.MaterialComponents.Light" /> | |||||
| <!-- Splash Screen theme --> | |||||
| <style name="Theme.App.Starting" parent="Theme.SplashScreen"> | |||||
| <item name="windowSplashScreenBackground">@color/splash_background</item> | |||||
| <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item> | |||||
| <item name="postSplashScreenTheme">@style/Theme.LEDLampControl</item> | |||||
| </style> | |||||
| </resources> | </resources> |
| moshiKotlin = "1.15.2" | moshiKotlin = "1.15.2" | ||||
| moshiKotlinCodegen = "1.15.2" | moshiKotlinCodegen = "1.15.2" | ||||
| material = "1.4.0" | material = "1.4.0" | ||||
| coreSplashscreen = "1.0.1" | |||||
| [libraries] | [libraries] | ||||
| androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } | androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } | ||||
| moshi-kotlin-codegen = { group = "com.squareup.moshi", name = "moshi-kotlin-codegen", version.ref = "moshiKotlinCodegen" } | moshi-kotlin-codegen = { group = "com.squareup.moshi", name = "moshi-kotlin-codegen", version.ref = "moshiKotlinCodegen" } | ||||
| androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" } | androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" } | ||||
| material = { group = "com.google.android.material", name = "material", version.ref = "material" } | material = { group = "com.google.android.material", name = "material", version.ref = "material" } | ||||
| androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "coreSplashscreen" } | |||||
| [plugins] | [plugins] | ||||
| android-application = { id = "com.android.application", version.ref = "agp" } | android-application = { id = "com.android.application", version.ref = "agp" } |