diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7f77823..cae693c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,6 +2,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) + alias(libs.plugins.ksp) } android { @@ -82,4 +83,9 @@ dependencies { //navigation implementation(libs.androidx.navigation.compose) + + // Room Database + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.room.ktx) + ksp(libs.androidx.room.compiler) } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1a27f1f..3c8b9af 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - + > + + @Query("SELECT * FROM testGroup WHERE Id = :groupId") + suspend fun getGroupById(groupId: Int): TestGroupEntity? + + @Query("SELECT * FROM testGroup WHERE Isparent = '1'") + fun getParentGroups(): Flow> + + @Query("SELECT * FROM testGroup WHERE Isparent = '0'") + fun getChildGroups(): Flow> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertGroup(group: TestGroupEntity) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertAllGroups(groups: List) + + @Query("DELETE FROM testGroup") + suspend fun deleteAllGroups() +} \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/data/local/dao/TestItemDao.kt b/app/src/main/java/com/approagency/drug/data/local/dao/TestItemDao.kt new file mode 100644 index 0000000..5740cbd --- /dev/null +++ b/app/src/main/java/com/approagency/drug/data/local/dao/TestItemDao.kt @@ -0,0 +1,36 @@ +package com.approagency.drug.data.local.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.approagency.drug.data.local.entities.TestItemEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface TestItemDao { + @Query("SELECT * FROM testItem ORDER BY Id") + fun getAllItems(): Flow> + + @Query("SELECT * FROM testItem WHERE Group_Id = :groupId ORDER BY Id") + fun getItemsByGroupId(groupId: Int): Flow> + + @Query("SELECT * FROM testItem WHERE Id = :itemId") + suspend fun getItemById(itemId: Int): TestItemEntity? + + @Query(""" + SELECT ti.* FROM testItem ti + INNER JOIN testGroup tg ON ti.Group_Id = tg.Id + WHERE tg.Isparent = '0' AND ti.Title LIKE '%' || :searchQuery || '%' + """) + fun searchTestItems(searchQuery: String): Flow> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertItem(item: TestItemEntity) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertAllItems(items: List) + + @Query("DELETE FROM testItem") + suspend fun deleteAllItems() +} \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/data/local/database/LabDatabase.kt b/app/src/main/java/com/approagency/drug/data/local/database/LabDatabase.kt new file mode 100644 index 0000000..f7f30df --- /dev/null +++ b/app/src/main/java/com/approagency/drug/data/local/database/LabDatabase.kt @@ -0,0 +1,43 @@ +package com.approagency.drug.data.local.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import com.approagency.drug.data.local.dao.TestGroupDao +import com.approagency.drug.data.local.dao.TestItemDao +import com.approagency.drug.data.local.entities.TestGroupEntity +import com.approagency.drug.data.local.entities.TestItemEntity + +@Database( + entities = [ + TestGroupEntity::class, + TestItemEntity::class + ], + version = 1, + exportSchema = false +) +abstract class LabDatabase : RoomDatabase() { + abstract fun testGroupDao(): TestGroupDao + abstract fun testItemDao(): TestItemDao + + companion object { + @Volatile + private var INSTANCE: LabDatabase? = null + + fun getInstance(context: Context): LabDatabase { + return INSTANCE ?: synchronized(this) { + val instance = Room.databaseBuilder( + context.applicationContext, + LabDatabase::class.java, + "lab_tests.db" // This will use your existing database + ) + .createFromAsset("lab_tests.db") // IMPORTANT: Copy from assets + .fallbackToDestructiveMigration() // For development only + .build() + INSTANCE = instance + instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/data/local/entities/TestGroupEntity.kt b/app/src/main/java/com/approagency/drug/data/local/entities/TestGroupEntity.kt new file mode 100644 index 0000000..a256e47 --- /dev/null +++ b/app/src/main/java/com/approagency/drug/data/local/entities/TestGroupEntity.kt @@ -0,0 +1,24 @@ +package com.approagency.drug.data.local.entities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "testGroup") +data class TestGroupEntity( + @PrimaryKey + @ColumnInfo(name = "Id") + val id: Int, + + @ColumnInfo(name = "Ename") + val ename: String?, + + @ColumnInfo(name = "Fname") + val fname: String?, + + @ColumnInfo(name = "Detail") + val detail: String?, + + @ColumnInfo(name = "Isparent") + val isParent: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/data/local/entities/TestItemEntity.kt b/app/src/main/java/com/approagency/drug/data/local/entities/TestItemEntity.kt new file mode 100644 index 0000000..e4d814f --- /dev/null +++ b/app/src/main/java/com/approagency/drug/data/local/entities/TestItemEntity.kt @@ -0,0 +1,37 @@ +package com.approagency.drug.data.local.entities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity( + tableName = "testItem", +// foreignKeys = [ +// ForeignKey( +// entity = TestGroupEntity::class, +// parentColumns = ["Id"], +// childColumns = ["Group_Id"], +// onDelete = ForeignKey.CASCADE +// ) +// ], + indices = [Index(value = ["Group_Id"])] +) +data class TestItemEntity( + @PrimaryKey + @ColumnInfo(name = "Id") + val id: Int, + + @ColumnInfo(name = "Group_Id") + val groupId: Int, + + @ColumnInfo(name = "Title") + val title: String?, + + @ColumnInfo(name = "Normal_Value") + val normalValue: String?, + + @ColumnInfo(name = "Detail") + val detail: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/data/repository/LabRepositoryImpl.kt b/app/src/main/java/com/approagency/drug/data/repository/LabRepositoryImpl.kt new file mode 100644 index 0000000..db5fd32 --- /dev/null +++ b/app/src/main/java/com/approagency/drug/data/repository/LabRepositoryImpl.kt @@ -0,0 +1,24 @@ +package com.approagency.drug.data.repository + +import com.approagency.drug.data.local.dao.TestGroupDao +import com.approagency.drug.data.local.dao.TestItemDao +import com.approagency.drug.data.local.entities.TestGroupEntity +import com.approagency.drug.data.local.entities.TestItemEntity +import kotlinx.coroutines.flow.Flow + +class LabRepositoryImpl ( + private val testGroupDao: TestGroupDao, + private val testItemDao: TestItemDao +) { + // Test Group Operations + fun getAllGroups(): Flow> = testGroupDao.getAllGroups() + fun getParentGroups(): Flow> = testGroupDao.getParentGroups() + fun getChildGroups(): Flow> = testGroupDao.getChildGroups() + suspend fun getGroupById(groupId: Int): TestGroupEntity? = testGroupDao.getGroupById(groupId) + + // Test Item Operations + fun getAllItems(): Flow> = testItemDao.getAllItems() + fun getItemsByGroupId(groupId: Int): Flow> = testItemDao.getItemsByGroupId(groupId) + suspend fun getItemById(itemId: Int): TestItemEntity? = testItemDao.getItemById(itemId) + fun searchTestItems(query: String): Flow> = testItemDao.searchTestItems(query) +} \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/di/AppModule.kt b/app/src/main/java/com/approagency/drug/di/AppModule.kt index 0399a9e..e4fb0bf 100644 --- a/app/src/main/java/com/approagency/drug/di/AppModule.kt +++ b/app/src/main/java/com/approagency/drug/di/AppModule.kt @@ -2,20 +2,32 @@ package com.approagency.drug.di import android.app.Application +import com.approagency.drug.data.local.database.LabDatabase import com.approagency.drug.data.remote.DrugApiService import com.approagency.drug.data.repository.DrugRepositoryImpl +import com.approagency.drug.data.repository.LabRepositoryImpl import com.approagency.drug.domain.repository.DrugRepository import com.approagency.drug.domain.usecase.GetDarmanUseCase import com.approagency.drug.domain.usecase.GetDrugDetailUseCase import com.approagency.drug.domain.usecase.GetDrugSearchUseCase +import com.approagency.drug.domain.usecase.GetTestGroupUseCase +import com.approagency.drug.domain.usecase.GetTestItemByGroupId import com.approagency.drug.presentation.viewModel.HomeViewModel +import com.approagency.drug.presentation.viewModel.LabViewModel import com.approagency.drug.utils.Config +import org.koin.android.ext.koin.androidContext import org.koin.core.module.dsl.viewModel import org.koin.dsl.module import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory val appModule= module { + + single { LabDatabase.getInstance(androidContext()) } + + single { get().testGroupDao() } + single { get().testItemDao() } + single { Retrofit.Builder() .baseUrl(Config.BASE_URL) @@ -47,8 +59,21 @@ val appModule= module { GetDarmanUseCase(get()) } + single { + GetTestGroupUseCase(get()) + } + + single { + GetTestItemByGroupId(get()) + } + + single { LabRepositoryImpl(get(), get()) } //view model viewModel { HomeViewModel(get() , get() , get()) } + + viewModel { + LabViewModel(get() , get()) + } } \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/domain/model/TestGroup.kt b/app/src/main/java/com/approagency/drug/domain/model/TestGroup.kt new file mode 100644 index 0000000..62f23f8 --- /dev/null +++ b/app/src/main/java/com/approagency/drug/domain/model/TestGroup.kt @@ -0,0 +1,11 @@ +package com.approagency.drug.domain.model + +data class TestGroup( + val id: Int, + val ename: String?, + val fname: String?, + val detail: String?, + val isParent: Boolean +) + + diff --git a/app/src/main/java/com/approagency/drug/domain/model/TestItem.kt b/app/src/main/java/com/approagency/drug/domain/model/TestItem.kt new file mode 100644 index 0000000..db680fa --- /dev/null +++ b/app/src/main/java/com/approagency/drug/domain/model/TestItem.kt @@ -0,0 +1,9 @@ +package com.approagency.drug.domain.model + +data class TestItem( + val id: Int, + val groupId: Int, + val title: String?, + val normalValue: String?, + val detail: String? +) diff --git a/app/src/main/java/com/approagency/drug/domain/usecase/GetTestGroupUseCase.kt b/app/src/main/java/com/approagency/drug/domain/usecase/GetTestGroupUseCase.kt new file mode 100644 index 0000000..8944e98 --- /dev/null +++ b/app/src/main/java/com/approagency/drug/domain/usecase/GetTestGroupUseCase.kt @@ -0,0 +1,24 @@ +package com.approagency.drug.domain.usecase + +import com.approagency.drug.data.repository.LabRepositoryImpl +import com.approagency.drug.domain.model.TestGroup +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class GetTestGroupUseCase ( + private val repository: LabRepositoryImpl +) { + operator fun invoke(): Flow> { + return repository.getAllGroups().map { entities -> + entities.map { entity -> + TestGroup( + id = entity.id, + ename = entity.ename, + fname = entity.fname, + detail = entity.detail, + isParent = entity.isParent == "1" + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/domain/usecase/GetTestItemByGroupId.kt b/app/src/main/java/com/approagency/drug/domain/usecase/GetTestItemByGroupId.kt new file mode 100644 index 0000000..f2b459e --- /dev/null +++ b/app/src/main/java/com/approagency/drug/domain/usecase/GetTestItemByGroupId.kt @@ -0,0 +1,26 @@ +package com.approagency.drug.domain.usecase + +import com.approagency.drug.data.local.entities.TestItemEntity +import com.approagency.drug.data.repository.LabRepositoryImpl +import com.approagency.drug.domain.model.TestItem +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class GetTestItemByGroupId ( + private val repository: LabRepositoryImpl +) { + operator fun invoke(id:Int): Flow> { + return repository.getItemsByGroupId(groupId = id).map { + entities -> entities.map { + entity -> + TestItem( + id = entity.id, + groupId = entity.groupId, + title = entity.title, + normalValue = entity.normalValue, + detail = entity.detail, + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/presentation/screens/LabScreen.kt b/app/src/main/java/com/approagency/drug/presentation/screens/LabScreen.kt index d360b0a..9db7956 100644 --- a/app/src/main/java/com/approagency/drug/presentation/screens/LabScreen.kt +++ b/app/src/main/java/com/approagency/drug/presentation/screens/LabScreen.kt @@ -1,12 +1,185 @@ package com.approagency.drug.presentation.screens +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import com.approagency.drug.presentation.viewModel.HomeViewModel +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextDirection +import androidx.compose.ui.unit.dp +import com.approagency.drug.domain.model.TestGroup +import com.approagency.drug.presentation.common.CustomBox +import com.approagency.drug.presentation.common.CustomModalDialog +import com.approagency.drug.presentation.common.Loading +import com.approagency.drug.presentation.common.PrimaryButton +import com.approagency.drug.presentation.viewModel.LabViewModel +import com.vada.caller.ui.theme.dime +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.count import org.koin.androidx.compose.koinViewModel @Composable fun LabScreen( - modifier: Modifier, - viewModel: HomeViewModel = koinViewModel() -){} \ No newline at end of file + modifier: Modifier = Modifier, + viewModel: LabViewModel = koinViewModel() +) { + val testGroupsState by viewModel.testGroups.collectAsState() + val isLoading = testGroupsState.isLoading + val error = testGroupsState.error + val testGroups = testGroupsState.testGroup + + Column(modifier = modifier.fillMaxSize()) { + if (isLoading) { + CustomModalDialog( + onDismissRequest = { /* maybe disable dismiss while loading */ }, + content = { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Loading(color = MaterialTheme.colorScheme.primary) + Spacer(modifier = Modifier.height(MaterialTheme.dime.sm)) + Text("در حال جستجو..." , textAlign = TextAlign.Right) + } + }, +// modifier = Modifier +// .matchParentSize() +// .background(MaterialTheme.colorScheme.background.copy(alpha = 0.5f)) + ) + } + else if(error != null){ + CustomBox( + child = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(MaterialTheme.dime.md) + ) { + Text( + text = "خطا در دریافت اطلاعات", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.error + ) + Text( + text = error, + style = MaterialTheme.typography.bodySmall, + modifier = Modifier.padding(vertical = 8.dp) + ) + PrimaryButton( + text = "تلاش مجدد", + height = 40, + isLoading = false, + onClick = { viewModel.loadTestGroups() } + ) + } + } + ) + } + else if (testGroups != null){ + TestGroupsList( + testGroupsFlow = testGroups, + viewModel = viewModel + ) + } else { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text("هیچ داده‌ای موجود نیست") + } + } + + } +} + +@Composable +fun TestGroupsList( + testGroupsFlow: Flow>, + viewModel: LabViewModel +) { + val testGroups by testGroupsFlow.collectAsState(initial = emptyList()) + + if (testGroups.isEmpty()) { + CustomModalDialog( + onDismissRequest = { /* maybe disable dismiss while loading */ }, + content = { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Loading(color = MaterialTheme.colorScheme.primary) + Spacer(modifier = Modifier.height(MaterialTheme.dime.sm)) + Text("در حال جستجو..." , textAlign = TextAlign.Right) + } + }, +// modifier = Modifier +// .matchParentSize() +// .background(MaterialTheme.colorScheme.background.copy(alpha = 0.5f)) + ) + } else { + LazyColumn( + modifier = Modifier.fillMaxSize() + ) { + items(testGroups) { group -> + TestGroupItem( + group = group, + onClick = { + // Navigate to test items of this group +// viewModel.loadTestItemsByGroup(group.id) + } + ) + } + } + } +} + +@Composable +fun TestGroupItem( + group: TestGroup, + onClick: () -> Unit +) { + CustomBox ( + modifier = Modifier + .padding(bottom = MaterialTheme.dime.sm) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + onClick() + }, + ) { + Column ( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.Start + ) { + Text( + text = group.fname ?: group.ename ?: "بدون نام", + style = MaterialTheme.typography.titleMedium.copy( + textAlign = TextAlign.Right, + textDirection = TextDirection.Rtl + ), + modifier = Modifier.padding(vertical = MaterialTheme.dime.xs) + ) + group.detail?.let { + Text( + text = it, + style = MaterialTheme.typography.bodySmall.copy( + textAlign = TextAlign.Right , + textDirection = TextDirection.Rtl + ), + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(horizontal = MaterialTheme.dime.lg) + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/presentation/screens/RootScreen.kt b/app/src/main/java/com/approagency/drug/presentation/screens/RootScreen.kt index fb82de9..992c7de 100644 --- a/app/src/main/java/com/approagency/drug/presentation/screens/RootScreen.kt +++ b/app/src/main/java/com/approagency/drug/presentation/screens/RootScreen.kt @@ -80,7 +80,7 @@ fun RootScreen(navHostController: NavHostController, modifier: Modifier){ containerColor = MaterialTheme.colorScheme.surface, modifier = Modifier .fillMaxWidth() - .height(110.dp).padding(bottom = 2.dp).clip(MaterialTheme.shapes.extraLarge), // 👈 کوچیک‌تر از حالت پیش‌فرض + .height(110.dp).padding(bottom = 2.dp).clip(MaterialTheme.shapes.extraLarge), tonalElevation = 8.dp, // subtle shadow windowInsets = WindowInsets.navigationBars .only(WindowInsetsSides.Bottom) @@ -114,7 +114,7 @@ fun RootScreen(navHostController: NavHostController, modifier: Modifier){ ) }, - alwaysShowLabel = true // 👈 فقط وقتی select شد label نشون بده + alwaysShowLabel = true ) } } diff --git a/app/src/main/java/com/approagency/drug/presentation/viewModel/LabViewModel.kt b/app/src/main/java/com/approagency/drug/presentation/viewModel/LabViewModel.kt new file mode 100644 index 0000000..0e1cece --- /dev/null +++ b/app/src/main/java/com/approagency/drug/presentation/viewModel/LabViewModel.kt @@ -0,0 +1,94 @@ +package com.approagency.drug.presentation.viewModel + +import android.net.http.HttpException +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.approagency.drug.data.dto.DrugListResponse +import com.approagency.drug.data.dto.DrugModels +import com.approagency.drug.domain.model.TestGroup +import com.approagency.drug.domain.model.TestItem +import com.approagency.drug.domain.usecase.GetTestGroupUseCase +import com.approagency.drug.domain.usecase.GetTestItemByGroupId +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +class LabViewModel ( + private val getTestGroupUseCase: GetTestGroupUseCase, + private val getTestItemByGroupId: GetTestItemByGroupId +) : ViewModel(){ + private val _testGroups = MutableStateFlow(TestGroupItem()) + val testGroups: StateFlow = _testGroups.asStateFlow() + + private val _testItems = MutableStateFlow(TestItemState()) + val testItems: StateFlow = _testItems.asStateFlow() + + init { + loadTestGroups() + } + + fun loadTestGroups(){ + _testGroups.update { + it.copy( + isLoading = true + ) + } + viewModelScope.launch { + try { + val result = getTestGroupUseCase.invoke(); + _testGroups.update { + it.copy( + isLoading = false, + testGroup = result, + ) + } + } catch (e:HttpException){ + handleError(e.message) + } + + } + } + + fun getItemByGroupId(id:Int){ + _testItems.update { it.copy(isLoading = true) } + viewModelScope.launch { + try { + val result = getTestItemByGroupId.invoke(id); + _testItems.update { + it.copy( + isLoading = false, + testItem = result + ) + } + } catch (e:HttpException){ + handleError(e.message) + } + } + } + private suspend fun handleError(message: String?) { + _testGroups.update { + it.copy( + isLoading = false, + testGroup = null, + error = message + ) + } + } + +} + +data class TestGroupItem( + val isLoading: Boolean = false, + val testGroup: Flow>? = null, + val error:String? = null +) + +data class TestItemState( + val isLoading: Boolean = false, + val testItem: Flow>? = null, + val error:String? = null +) + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ca186a2..fbbb379 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agp = "8.13.0" -kotlin = "2.2.10" +kotlin = "2.0.21" coreKtx = "1.10.1" junit = "4.13.2" junitVersion = "1.1.5" @@ -8,16 +8,16 @@ espressoCore = "3.5.1" lifecycleRuntimeKtx = "2.6.1" activityCompose = "1.8.0" composeBom = "2024.09.00" - -retrofit = "3.0.0" -okhttp = "5.1.0" +ksp = "2.0.21-1.0.27" +retrofit = "2.11.0" +okhttp = "4.12.0" gson = "2.13.1" coil = "2.7.0" location = "21.3.0" koinAndroid = "4.1.0" koinAndroidxCompose = "4.1.0" lifecycleViewmodelKtx = "2.9.4" - +room = "2.6.1" navigationCompose = "2.8.5" material3 = "1.4.0" @@ -51,8 +51,14 @@ location-services = { group = "com.google.android.gms", name = "play-services-lo androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" } androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" } androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } + + +androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } +androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } +androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } - +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file