diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index ab17602..896c041 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -63,6 +63,7 @@ dependencies {
implementation(project(":core:database"))
implementation(project(":core:config"))
+ implementation(project(":feature:splash"))
implementation(project(":feature:schedule"))
implementation(project(":feature:progress"))
implementation(project(":feature:news"))
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ae495cc..3d5f9c7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,7 +13,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.TSUDesk">
@@ -21,6 +21,5 @@
-
\ No newline at end of file
diff --git a/app/src/main/java/ru/fincode/tsudesk/SplashScreenActivity.kt b/app/src/main/java/ru/fincode/tsudesk/SplashScreenActivity.kt
deleted file mode 100644
index beef5b7..0000000
--- a/app/src/main/java/ru/fincode/tsudesk/SplashScreenActivity.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package ru.fincode.tsudesk
-
-import android.content.Intent
-import android.os.Bundle
-import android.util.Log
-import androidx.activity.ComponentActivity
-import androidx.lifecycle.lifecycleScope
-import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import ru.fincode.tsudesk.core.common.model.DataResult
-import ru.fincode.tsudesk.core.config.domain.usecase.GetConfigUseCase
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class SplashScreenActivity : ComponentActivity() {
-
- @Inject
- lateinit var fetchConfigUseCase: GetConfigUseCase
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- lifecycleScope.launchWhenCreated {
-// val result = withContext(Dispatchers.IO) { fetchConfigUseCase() }
- val result = fetchConfigUseCase()
- when (result) {
- is DataResult.Data -> {
- Log.d(LOG_TAG, "SUCCESS: config=${result.data}")
- }
-
- is DataResult.Error -> {
- Log.e(
- LOG_TAG,
- "ERROR: ${result.error}, fallback=${result.data}",
- result.cause
- )
- }
- }
-
- startActivity(Intent(this@SplashScreenActivity, MainActivity::class.java))
- finish()
- }
- }
-}
diff --git a/feature/splash/build.gradle.kts b/feature/splash/build.gradle.kts
new file mode 100644
index 0000000..6d79624
--- /dev/null
+++ b/feature/splash/build.gradle.kts
@@ -0,0 +1,57 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+
+ alias(libs.plugins.kotlin.kapt)
+ alias(libs.plugins.hilt)
+}
+
+android {
+ namespace = "ru.fincode.tsudesk.feature.splash"
+ buildFeatures { compose = true }
+
+ compileSdk = libs.versions.compileSdk.get().toInt()
+ defaultConfig {
+ minSdk = libs.versions.minSdk.get().toInt()
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
+ )
+ }
+ }
+
+ val jvm = JavaVersion.toVersion(libs.versions.jvmTarget.get())
+ compileOptions {
+ sourceCompatibility = jvm
+ targetCompatibility = jvm
+ }
+ kotlinOptions {
+ jvmTarget = jvm.toString()
+ }
+}
+kapt {
+ correctErrorTypes = true
+}
+dependencies {
+ implementation(libs.androidx.appcompat)
+ implementation(libs.material)
+
+ implementation(platform(libs.compose.bom))
+ implementation(libs.compose.ui)
+ implementation(libs.compose.foundation)
+ implementation(libs.compose.material3)
+
+ kapt(libs.hilt.compiler)
+ implementation(libs.hilt.android)
+ implementation(libs.hilt.navigation.compose)
+
+ implementation(project(":core:network"))
+ implementation(project(":core:common"))
+ implementation(project(":core:config"))
+ implementation(project(":core:ui"))
+}
\ No newline at end of file
diff --git a/feature/splash/consumer-rules.pro b/feature/splash/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/feature/splash/proguard-rules.pro b/feature/splash/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/feature/splash/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/splash/src/androidTest/java/ru/fincode/tsudesk/feature/splash/ExampleInstrumentedTest.kt b/feature/splash/src/androidTest/java/ru/fincode/tsudesk/feature/splash/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..fe0b316
--- /dev/null
+++ b/feature/splash/src/androidTest/java/ru/fincode/tsudesk/feature/splash/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package ru.fincode.tsudesk.feature.splash
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("ru.fincode.tsudesk.feature.splash.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/feature/splash/src/main/AndroidManifest.xml b/feature/splash/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a5918e6
--- /dev/null
+++ b/feature/splash/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashEffect.kt b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashEffect.kt
new file mode 100644
index 0000000..e8e9e35
--- /dev/null
+++ b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashEffect.kt
@@ -0,0 +1,5 @@
+package ru.fincode.tsudesk.feature.splash.ui
+
+sealed interface SplashEffect {
+ data object OpenMain : SplashEffect
+}
diff --git a/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashRoute.kt b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashRoute.kt
new file mode 100644
index 0000000..9dc475d
--- /dev/null
+++ b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashRoute.kt
@@ -0,0 +1,21 @@
+package ru.fincode.tsudesk.feature.splash.ui
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+
+@Composable
+fun SplashRoute(
+ onOpenMain: () -> Unit, vm: SplashViewModel = hiltViewModel()
+) {
+ val state = vm.state.collectAsStateWithLifecycle().value
+ SplashScreen(state)
+ LaunchedEffect(vm) {
+ vm.effects.collect { effect ->
+ when (effect) {
+ SplashEffect.OpenMain -> onOpenMain()
+ }
+ }
+ }
+}
diff --git a/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashScreen.kt b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashScreen.kt
new file mode 100644
index 0000000..65a6a36
--- /dev/null
+++ b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashScreen.kt
@@ -0,0 +1,27 @@
+package ru.fincode.tsudesk.feature.splash.ui
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun SplashScreen(state: SplashUiState) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color.Black),
+ contentAlignment = Alignment.Center
+ ) {
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
+ if (state.isLoading) {
+ Spacer(Modifier.height(16.dp))
+ CircularProgressIndicator()
+ }
+ }
+ }
+}
diff --git a/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashUiState.kt b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashUiState.kt
new file mode 100644
index 0000000..0f9fa97
--- /dev/null
+++ b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashUiState.kt
@@ -0,0 +1,6 @@
+package ru.fincode.tsudesk.feature.splash.ui
+
+data class SplashUiState(
+ val isLoading: Boolean = true,
+ val errorMessage: String? = null
+)
diff --git a/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashViewModel.kt b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashViewModel.kt
new file mode 100644
index 0000000..2d901f0
--- /dev/null
+++ b/feature/splash/src/main/java/ru/fincode/tsudesk/feature/splash/ui/SplashViewModel.kt
@@ -0,0 +1,44 @@
+package ru.fincode.tsudesk.feature.splash.ui
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+import ru.fincode.tsudesk.core.common.model.DataResult
+import ru.fincode.tsudesk.core.config.domain.usecase.GetConfigUseCase
+import javax.inject.Inject
+
+@HiltViewModel
+class SplashViewModel @Inject constructor(
+ private val getConfigUseCase: GetConfigUseCase
+) : ViewModel() {
+
+ private val _state = MutableStateFlow(SplashUiState(isLoading = true))
+ val state: StateFlow = _state
+
+ private val _effects = MutableSharedFlow(extraBufferCapacity = 1)
+ val effects: SharedFlow = _effects
+
+ init {
+ viewModelScope.launch {
+ when (val result = getConfigUseCase()) {
+ is DataResult.Data -> {
+ _state.value = SplashUiState(isLoading = false)
+ _effects.tryEmit(SplashEffect.OpenMain)
+ }
+
+ is DataResult.Error -> {
+ _state.value = SplashUiState(
+ isLoading = false,
+ errorMessage = result.error.toString()
+ )
+ _effects.tryEmit(SplashEffect.OpenMain)
+ }
+ }
+ }
+ }
+}
diff --git a/feature/splash/src/test/java/ru/fincode/tsudesk/feature/splash/ExampleUnitTest.kt b/feature/splash/src/test/java/ru/fincode/tsudesk/feature/splash/ExampleUnitTest.kt
new file mode 100644
index 0000000..d1b17c4
--- /dev/null
+++ b/feature/splash/src/test/java/ru/fincode/tsudesk/feature/splash/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package ru.fincode.tsudesk.feature.splash
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 08ecb9c..f699b54 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -15,6 +15,8 @@ appcompat = "1.6.1"
material = "1.10.0"
activity = "1.8.0"
constraintlayout = "2.1.4"
+compose-bom = "2024.10.00"
+hilt-nav-compose = "1.2.0"
hilt = "2.50"
retrofit = "2.11.0"
@@ -39,6 +41,12 @@ kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
+hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hilt-nav-compose" }
+# Compose UI
+compose-ui = { group = "androidx.compose.ui", name = "ui" }
+compose-foundation = { group = "androidx.compose.foundation", name = "foundation" }
+compose-material3 = { group = "androidx.compose.material3", name = "material3" }
# Network: okhhtp3+retrofit2
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 61a06ef..e2597a0 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -34,3 +34,4 @@ include(":feature:news")
include(":feature:progress")
+include(":feature:splash")