diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 0cbf6f4..ab17602 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -61,6 +61,7 @@ dependencies {
implementation(project(":core:common"))
implementation(project(":core:network"))
implementation(project(":core:database"))
+ implementation(project(":core:config"))
implementation(project(":feature:schedule"))
implementation(project(":feature:progress"))
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5ebf391..ae495cc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,7 +5,7 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/java/ru/fincode/tsudesk/App.kt b/app/src/main/java/ru/fincode/tsudesk/App.kt
index fcd2b04..bff88ab 100644
--- a/app/src/main/java/ru/fincode/tsudesk/App.kt
+++ b/app/src/main/java/ru/fincode/tsudesk/App.kt
@@ -1,7 +1,24 @@
package ru.fincode.tsudesk
import android.app.Application
+import android.util.Log
import dagger.hilt.android.HiltAndroidApp
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+import ru.fincode.tsudesk.core.config.domain.usecase.GetConfigUseCase
+import ru.fincode.tsudesk.core.common.model.DataResult
+import javax.inject.Inject
+
+const val LOG_TAG = "NETWORK_DEBUG"
@HiltAndroidApp
-class App : Application()
+class TSUDeskApp : Application() {
+
+ private val appScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
+
+ override fun onCreate() {
+ super.onCreate()
+ }
+}
diff --git a/app/src/main/java/ru/fincode/tsudesk/MainActivity.kt b/app/src/main/java/ru/fincode/tsudesk/MainActivity.kt
index 0e07fca..58b0339 100644
--- a/app/src/main/java/ru/fincode/tsudesk/MainActivity.kt
+++ b/app/src/main/java/ru/fincode/tsudesk/MainActivity.kt
@@ -11,7 +11,6 @@ import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleType
import ru.fincode.tsudesk.feature.schedule.domain.usecase.GetScheduleUseCase
import javax.inject.Inject
-private const val LOG_TAG = "NETWORK_DEBUG"
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
diff --git a/app/src/main/java/ru/fincode/tsudesk/SplashScreenActivity.kt b/app/src/main/java/ru/fincode/tsudesk/SplashScreenActivity.kt
new file mode 100644
index 0000000..bc356db
--- /dev/null
+++ b/app/src/main/java/ru/fincode/tsudesk/SplashScreenActivity.kt
@@ -0,0 +1,44 @@
+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() }
+
+ 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/core/common/src/main/java/ru/fincode/tsudesk/core/common/model/DataResult.kt b/core/common/src/main/java/ru/fincode/tsudesk/core/common/model/DataResult.kt
index 75d97c1..ce7da49 100644
--- a/core/common/src/main/java/ru/fincode/tsudesk/core/common/model/DataResult.kt
+++ b/core/common/src/main/java/ru/fincode/tsudesk/core/common/model/DataResult.kt
@@ -1,6 +1,12 @@
package ru.fincode.tsudesk.core.common.model
sealed interface DataResult {
- data class Data(val data: T, val refreshedFromNetwork: Boolean) : DataResult
- data class Error(val error: AppError, val cause: Throwable? = null) : DataResult
-}
\ No newline at end of file
+
+ data class Data(
+ val data: T, val refreshedFromNetwork: Boolean
+ ) : DataResult
+
+ data class Error(
+ val error: AppError, val data: T? = null, val cause: Throwable? = null
+ ) : DataResult
+}
diff --git a/core/config/build.gradle.kts b/core/config/build.gradle.kts
new file mode 100644
index 0000000..9618eb3
--- /dev/null
+++ b/core/config/build.gradle.kts
@@ -0,0 +1,38 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.kotlin.kapt)
+ alias(libs.plugins.hilt)
+
+ alias(libs.plugins.kotlin.serialization)
+}
+
+android {
+ namespace = "ru.fincode.tsudesk.core.config"
+ compileSdk = libs.versions.compileSdk.get().toInt()
+
+ defaultConfig {
+ minSdk = libs.versions.minSdk.get().toInt()
+ }
+ val jvm = JavaVersion.toVersion(libs.versions.jvmTarget.get())
+ compileOptions {
+ sourceCompatibility = jvm
+ targetCompatibility = jvm
+ }
+ kotlinOptions {
+ jvmTarget = jvm.toString()
+ }
+}
+kapt {
+ correctErrorTypes = true
+}
+dependencies {
+ kapt(libs.hilt.compiler)
+ implementation(libs.hilt.android)
+
+ // Kotlin Serialization
+ implementation(libs.kotlinx.serialization.json)
+
+ implementation(project(":core:network"))
+ implementation(project(":core:common"))
+}
\ No newline at end of file
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/ConfigRepositoryImpl.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/ConfigRepositoryImpl.kt
new file mode 100644
index 0000000..39cd3a9
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/ConfigRepositoryImpl.kt
@@ -0,0 +1,63 @@
+package ru.fincode.tsudesk.core.config.data
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+import ru.fincode.tsudesk.core.common.model.DataResult
+import ru.fincode.tsudesk.core.config.data.datasource.ConfigRemoteDataSource
+import ru.fincode.tsudesk.core.config.domain.ConfigRepository
+import ru.fincode.tsudesk.core.config.domain.model.AppConfig
+import ru.fincode.tsudesk.core.network.model.NetworkResult
+import javax.inject.Inject
+
+class ConfigRepositoryImpl @Inject constructor(
+ private val remoteDataSource: ConfigRemoteDataSource
+) : ConfigRepository {
+
+ private val defaultConfig = AppConfig()
+
+ override suspend fun fetchConfig(): DataResult {
+ return when (val res = remoteDataSource.load()) {
+ is NetworkResult.Success -> {
+ val dto = res.data
+ DataResult.Data(
+ data = AppConfig(
+ newsEnabled = dto.newsEnabled ?: defaultConfig.newsEnabled,
+ scheduleEnabled = dto.scheduleEnabled ?: defaultConfig.scheduleEnabled,
+ gradesEnabled = dto.gradesEnabled ?: defaultConfig.gradesEnabled
+ ),
+ refreshedFromNetwork = true
+ )
+ }
+
+ is NetworkResult.Error -> {
+ DataResult.Error(
+ error = res.error.toAppError(), data = defaultConfig
+ )
+ }
+ }
+ }
+
+
+ override fun getConfig(): Flow> = flow {
+ when (val result = remoteDataSource.load()) {
+ is NetworkResult.Success -> {
+ val dto = result.data
+ val appConfig = AppConfig(
+ newsEnabled = dto.newsEnabled ?: defaultConfig.newsEnabled,
+ scheduleEnabled = dto.scheduleEnabled ?: defaultConfig.scheduleEnabled,
+ gradesEnabled = dto.gradesEnabled ?: defaultConfig.gradesEnabled
+ )
+ emit(DataResult.Data(data = appConfig, refreshedFromNetwork = true))
+ }
+
+ is NetworkResult.Error -> {
+ emit(
+ DataResult.Error(
+ error = result.error.toAppError(),
+ data = defaultConfig
+ )
+ )
+ }
+ }
+ }
+}
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/datasource/ConfigRemoteDataSource.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/datasource/ConfigRemoteDataSource.kt
new file mode 100644
index 0000000..81ad315
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/datasource/ConfigRemoteDataSource.kt
@@ -0,0 +1,8 @@
+package ru.fincode.tsudesk.core.config.data.datasource
+
+import ru.fincode.tsudesk.core.config.data.remote.dto.RemoteConfigDto
+import ru.fincode.tsudesk.core.network.model.NetworkResult
+
+interface ConfigRemoteDataSource {
+ suspend fun load(): NetworkResult
+}
\ No newline at end of file
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/datasource/ConfigRemoteDataSourceImpl.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/datasource/ConfigRemoteDataSourceImpl.kt
new file mode 100644
index 0000000..327f670
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/datasource/ConfigRemoteDataSourceImpl.kt
@@ -0,0 +1,15 @@
+package ru.fincode.tsudesk.core.config.data.datasource
+
+import ru.fincode.tsudesk.core.config.data.remote.api.ConfigApi
+import ru.fincode.tsudesk.core.config.data.remote.dto.RemoteConfigDto
+import ru.fincode.tsudesk.core.network.apiCall
+import ru.fincode.tsudesk.core.network.model.NetworkResult
+import javax.inject.Inject
+
+class ConfigRemoteDataSourceImpl @Inject constructor(
+ private val api: ConfigApi
+) : ConfigRemoteDataSource {
+
+ override suspend fun load(): NetworkResult =
+ apiCall { api.getConfig() }
+}
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/model/RemoteConfigDto.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/model/RemoteConfigDto.kt
new file mode 100644
index 0000000..30768e7
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/model/RemoteConfigDto.kt
@@ -0,0 +1,7 @@
+package ru.fincode.tsudesk.core.config.data.model
+
+data class RemoteConfig(
+ val newsEnabled: Boolean,
+ val scheduleEnabled: Boolean,
+ val gradesEnabled: Boolean
+)
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/remote/ConfigApiContract.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/remote/ConfigApiContract.kt
new file mode 100644
index 0000000..a7e12cb
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/remote/ConfigApiContract.kt
@@ -0,0 +1,10 @@
+package ru.fincode.tsudesk.core.config.data.remote
+
+object ConfigApiContract {
+
+ const val CONFIG_BASE_URL = "https://scherbatykh.ru/app/tsudesk/"
+
+ object Path {
+ const val GET_CONFIG_METHOD = "config.json"
+ }
+}
\ No newline at end of file
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/remote/api/ConfigApi.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/remote/api/ConfigApi.kt
new file mode 100644
index 0000000..331dfd8
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/remote/api/ConfigApi.kt
@@ -0,0 +1,12 @@
+package ru.fincode.tsudesk.core.config.data.remote.api
+
+import retrofit2.Response
+import retrofit2.http.GET
+import ru.fincode.tsudesk.core.config.data.remote.ConfigApiContract.Path.GET_CONFIG_METHOD
+import ru.fincode.tsudesk.core.config.data.remote.dto.RemoteConfigDto
+
+interface ConfigApi {
+
+ @GET(GET_CONFIG_METHOD)
+ suspend fun getConfig(): Response
+}
\ No newline at end of file
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/remote/dto/RemoteConfigDto.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/remote/dto/RemoteConfigDto.kt
new file mode 100644
index 0000000..4c5192f
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/data/remote/dto/RemoteConfigDto.kt
@@ -0,0 +1,10 @@
+package ru.fincode.tsudesk.core.config.data.remote.dto
+
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class RemoteConfigDto(
+ val newsEnabled: Boolean? = null,
+ val scheduleEnabled: Boolean? = null,
+ val gradesEnabled: Boolean? = null
+)
\ No newline at end of file
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/di/ConfigNetworkModule.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/di/ConfigNetworkModule.kt
new file mode 100644
index 0000000..f6a223f
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/di/ConfigNetworkModule.kt
@@ -0,0 +1,35 @@
+package ru.fincode.tsudesk.core.config.di
+
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import okhttp3.OkHttpClient
+import retrofit2.Retrofit
+import ru.fincode.tsudesk.core.config.data.remote.ConfigApiContract.CONFIG_BASE_URL
+import ru.fincode.tsudesk.core.network.RetrofitFactory
+import ru.fincode.tsudesk.core.config.data.remote.api.ConfigApi
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object ConfigNetworkModule {
+ @Provides
+ @Singleton
+ @ConfigRetrofit
+ fun provideConfigRetrofit(
+ factory: RetrofitFactory,
+ client: OkHttpClient
+ ): Retrofit =
+ factory.create(
+ baseUrl = CONFIG_BASE_URL,
+ client = client
+ )
+
+ @Provides
+ @Singleton
+ fun provideConfigApi(
+ @ConfigRetrofit retrofit: Retrofit
+ ): ConfigApi =
+ retrofit.create(ConfigApi::class.java)
+}
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/di/ConfigRepositoryModule.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/di/ConfigRepositoryModule.kt
new file mode 100644
index 0000000..ac2f156
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/di/ConfigRepositoryModule.kt
@@ -0,0 +1,28 @@
+package ru.fincode.tsudesk.core.config.di
+
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import ru.fincode.tsudesk.core.config.data.ConfigRepositoryImpl
+import ru.fincode.tsudesk.core.config.data.datasource.ConfigRemoteDataSource
+import ru.fincode.tsudesk.core.config.data.datasource.ConfigRemoteDataSourceImpl
+import ru.fincode.tsudesk.core.config.domain.ConfigRepository
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class ConfigRepositoryModule {
+
+ @Binds
+ @Singleton
+ abstract fun bindRemoteDataSource(
+ impl: ConfigRemoteDataSourceImpl
+ ): ConfigRemoteDataSource
+
+ @Binds
+ @Singleton
+ abstract fun bindRepository(
+ impl: ConfigRepositoryImpl
+ ): ConfigRepository
+}
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/di/ConfigRetrofit.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/di/ConfigRetrofit.kt
new file mode 100644
index 0000000..1b5ca0f
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/di/ConfigRetrofit.kt
@@ -0,0 +1,7 @@
+package ru.fincode.tsudesk.core.config.di
+
+import javax.inject.Qualifier
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class ConfigRetrofit
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/domain/ConfigRepository.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/domain/ConfigRepository.kt
new file mode 100644
index 0000000..07a18e1
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/domain/ConfigRepository.kt
@@ -0,0 +1,10 @@
+package ru.fincode.tsudesk.core.config.domain
+
+import kotlinx.coroutines.flow.Flow
+import ru.fincode.tsudesk.core.common.model.DataResult
+import ru.fincode.tsudesk.core.config.domain.model.AppConfig
+
+interface ConfigRepository {
+ suspend fun fetchConfig(): DataResult
+ fun getConfig(): Flow>
+}
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/domain/model/AppConfig.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/domain/model/AppConfig.kt
new file mode 100644
index 0000000..e79629f
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/domain/model/AppConfig.kt
@@ -0,0 +1,7 @@
+package ru.fincode.tsudesk.core.config.domain.model
+
+data class AppConfig(
+ val newsEnabled: Boolean = false,
+ val scheduleEnabled: Boolean = false,
+ val gradesEnabled: Boolean = false
+)
diff --git a/core/config/src/main/java/ru/fincode/tsudesk/core/config/domain/usecase/GetConfigUseCase.kt b/core/config/src/main/java/ru/fincode/tsudesk/core/config/domain/usecase/GetConfigUseCase.kt
new file mode 100644
index 0000000..170777c
--- /dev/null
+++ b/core/config/src/main/java/ru/fincode/tsudesk/core/config/domain/usecase/GetConfigUseCase.kt
@@ -0,0 +1,13 @@
+package ru.fincode.tsudesk.core.config.domain.usecase
+
+import kotlinx.coroutines.flow.Flow
+import ru.fincode.tsudesk.core.common.model.DataResult
+import ru.fincode.tsudesk.core.config.domain.ConfigRepository
+import ru.fincode.tsudesk.core.config.domain.model.AppConfig
+import javax.inject.Inject
+
+class GetConfigUseCase @Inject constructor(
+ private val repository: ConfigRepository
+) {
+ suspend operator fun invoke(): DataResult = repository.fetchConfig()
+}
\ No newline at end of file
diff --git a/core/database/src/main/java/ru/fincode/tsudesk/core/database/AppDatabase.kt b/core/database/src/main/java/ru/fincode/tsudesk/core/database/AppDatabase.kt
index 75f3f7d..dd2306c 100644
--- a/core/database/src/main/java/ru/fincode/tsudesk/core/database/AppDatabase.kt
+++ b/core/database/src/main/java/ru/fincode/tsudesk/core/database/AppDatabase.kt
@@ -18,7 +18,7 @@ import ru.fincode.tsudesk.core.database.schedule.ScheduleDao
// NewsEntity::class,
// GradeEntity::class,
],
- version = 1,
+ version = 2,
exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts
index de595ad..3559670 100644
--- a/core/network/build.gradle.kts
+++ b/core/network/build.gradle.kts
@@ -13,7 +13,9 @@ android {
minSdk = libs.versions.minSdk.get().toInt()
consumerProguardFiles("consumer-rules.pro")
}
-
+ buildFeatures {
+ buildConfig = true
+ }
buildTypes {
release {
isMinifyEnabled = false
@@ -32,7 +34,9 @@ android {
jvmTarget = jvm.toString()
}
}
-
+kapt {
+ correctErrorTypes = true
+}
dependencies {
kapt(libs.hilt.compiler)
implementation(libs.hilt.android)
diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts
index c36b5c9..ab480b6 100644
--- a/core/ui/build.gradle.kts
+++ b/core/ui/build.gradle.kts
@@ -31,7 +31,6 @@ android {
jvmTarget = jvm.toString()
}
}
-
dependencies {
implementation(libs.core.ktx)
implementation(libs.androidx.appcompat)
diff --git a/feature/news/build.gradle.kts b/feature/news/build.gradle.kts
index 162762f..20dfbeb 100644
--- a/feature/news/build.gradle.kts
+++ b/feature/news/build.gradle.kts
@@ -11,7 +11,6 @@ android {
minSdk = libs.versions.minSdk.get().toInt()
consumerProguardFiles("consumer-rules.pro")
}
-
buildTypes {
release {
isMinifyEnabled = false
diff --git a/feature/progress/build.gradle.kts b/feature/progress/build.gradle.kts
index 4ef843d..f80ec86 100644
--- a/feature/progress/build.gradle.kts
+++ b/feature/progress/build.gradle.kts
@@ -30,7 +30,6 @@ android {
jvmTarget = jvm.toString()
}
}
-
dependencies {
implementation(libs.core.ktx)
implementation(libs.androidx.appcompat)
diff --git a/feature/schedule/build.gradle.kts b/feature/schedule/build.gradle.kts
index 693694c..4a21b08 100644
--- a/feature/schedule/build.gradle.kts
+++ b/feature/schedule/build.gradle.kts
@@ -33,7 +33,9 @@ android {
jvmTarget = jvm.toString()
}
}
-
+kapt {
+ correctErrorTypes = true
+}
dependencies {
implementation(libs.androidx.appcompat)
implementation(libs.material)
diff --git a/feature/schedule/src/main/java/ru/fincode/tsudesk/feature/schedule/data/ScheduleRepositoryImpl.kt b/feature/schedule/src/main/java/ru/fincode/tsudesk/feature/schedule/data/ScheduleRepositoryImpl.kt
index caa4496..16c5938 100644
--- a/feature/schedule/src/main/java/ru/fincode/tsudesk/feature/schedule/data/ScheduleRepositoryImpl.kt
+++ b/feature/schedule/src/main/java/ru/fincode/tsudesk/feature/schedule/data/ScheduleRepositoryImpl.kt
@@ -1,7 +1,6 @@
package ru.fincode.tsudesk.feature.schedule.data
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import ru.fincode.tsudesk.core.common.model.DataResult
@@ -23,18 +22,29 @@ class ScheduleRepositoryImpl @Inject constructor(
) : ScheduleRepository {
override fun observeSchedule(type: ScheduleType): Flow> = flow {
- val key = when (type) {
- is ScheduleType.Group -> ScheduleCacheKey.group(type.number)
- is ScheduleType.Teacher -> ScheduleCacheKey.teacher(type.name)
+ val scheduleKey = type.toCacheKey()
+ val cached = local.observeSchedule(scheduleKey).first()
+ cached?.let {
+ emit(DataResult.Data(it, refreshedFromNetwork = false))
}
- val cached: ScheduleEntity? = local.observeSchedule(key).first()
- if (cached != null) {
- emit(DataResult.Data(cached, refreshedFromNetwork = false))
+ val networkResult = loadSchedule(type)
+ if (networkResult is NetworkResult.Error) {
+ emit(DataResult.Error(networkResult.error.toAppError()))
+ return@flow
}
- // if (cached?.timestamp != updated.timestamp) { ... }
- val networkResult: NetworkResult = when (type) {
+ val networkSchedule = (networkResult as NetworkResult.Success).data
+ local.saveSchedule(scheduleKey, networkSchedule)
+
+ val updated = local.loadSchedule(scheduleKey)
+ if (updated != null && cached?.timestamp != updated.timestamp) {
+ emit(DataResult.Data(updated, refreshedFromNetwork = true))
+ }
+ }
+
+ private suspend fun loadSchedule(type: ScheduleType): NetworkResult =
+ when (type) {
is ScheduleType.Group ->
remote.loadScheduleByGroup(type.number).map(mapper::invoke)
@@ -42,18 +52,4 @@ class ScheduleRepositoryImpl @Inject constructor(
remote.loadScheduleByTeacher(type.name).map(mapper::invoke)
}
- when (networkResult) {
- is NetworkResult.Success -> {
- local.saveSchedule(key, networkResult.data)
- }
-
- is NetworkResult.Error -> {
- emit(DataResult.Error(networkResult.error.toAppError()))
- return@flow
- }
- }
- val updated: ScheduleEntity = local.observeSchedule(key).filterNotNull().first()
- val refreshedFromNetwork = cached?.timestamp != updated.timestamp
- emit(DataResult.Data(updated, refreshedFromNetwork))
- }
}
diff --git a/feature/schedule/src/main/java/ru/fincode/tsudesk/feature/schedule/domain/model/ScheduleType.kt b/feature/schedule/src/main/java/ru/fincode/tsudesk/feature/schedule/domain/model/ScheduleType.kt
index 805d53f..3f8fd9c 100644
--- a/feature/schedule/src/main/java/ru/fincode/tsudesk/feature/schedule/domain/model/ScheduleType.kt
+++ b/feature/schedule/src/main/java/ru/fincode/tsudesk/feature/schedule/domain/model/ScheduleType.kt
@@ -1,6 +1,18 @@
package ru.fincode.tsudesk.feature.schedule.domain.model
+import ru.fincode.tsudesk.feature.schedule.data.local.ScheduleCacheKey
+
sealed interface ScheduleType {
- data class Group(val number: String) : ScheduleType
- data class Teacher(val name: String) : ScheduleType
-}
\ No newline at end of file
+
+ fun toCacheKey(): String
+
+ data class Group(val number: String) : ScheduleType {
+ override fun toCacheKey(): String =
+ ScheduleCacheKey.group(number)
+ }
+
+ data class Teacher(val name: String) : ScheduleType {
+ override fun toCacheKey(): String =
+ ScheduleCacheKey.teacher(name)
+ }
+}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index ce166c1..08ecb9c 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -8,6 +8,7 @@ versionCode = "1"
agp = "8.12.0"
kotlin = "1.9.24"
jvmTarget = "17"
+serilization = "1.6.3"
coreKtx = "1.10.1"
appcompat = "1.6.1"
@@ -24,12 +25,16 @@ lifecycle = "2.7.0"
coroutines = "1.8.1"
room = "2.6.1"
+junit = "4.13.2"
+junitVersion = "1.1.5"
+espressoCore = "3.5.1"
[libraries]
# Android
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serilization" }
# UI: AndroidX, Jetpack Compose
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
@@ -51,11 +56,15 @@ core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx"
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
[plugins]
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
+kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index c7b07ce..61a06ef 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -27,6 +27,7 @@ include(":core:common")
include(":core:ui")
include(":core:network")
include(":core:database")
+include(":core:config")
include(":feature:schedule")
include(":feature:news")