diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..c4e4683
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+BCSD_Android_2025-1
\ No newline at end of file
diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml
new file mode 100644
index 0000000..4a53bee
--- /dev/null
+++ b/.idea/AndroidProjectSystem.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b86273d
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..b268ef3
--- /dev/null
+++ b/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..639c779
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..c224ad5
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/migrations.xml b/.idea/migrations.xml
new file mode 100644
index 0000000..f8051a6
--- /dev/null
+++ b/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..02a7102
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..16660f1
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5791375..0e47b96 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,6 +1,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
+ id("kotlin-kapt")
}
android {
@@ -17,6 +18,14 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
+ buildFeatures {
+ dataBinding = true
+ }
+
+ kapt {
+ correctErrorTypes = true
+ }
+
buildTypes {
release {
isMinifyEnabled = false
@@ -36,12 +45,18 @@ android {
}
dependencies {
-
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
+ implementation(libs.androidx.lifecycle.viewmodel.ktx)
+ implementation(libs.kotlinx.coroutines.android)
+ implementation(libs.androidx.room.runtime)
+ implementation("com.github.bumptech.glide:glide:4.16.0")
+ kapt ("com.github.bumptech.glide:compiler:4.16.0")
+ implementation(libs.androidx.room.ktx)
+ kapt(libs.androidx.room.compiler)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4c80941..47ea6b5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,9 @@
+
+
+
+
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt b/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt
deleted file mode 100644
index 3ffa0eb..0000000
--- a/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.example.bcsd_android_2025_1
-
-import android.os.Bundle
-import androidx.activity.enableEdgeToEdge
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowInsetsCompat
-
-class MainActivity : AppCompatActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/app/AddEditActivity.kt b/app/src/main/java/com/example/bcsd_android_2025_1/app/AddEditActivity.kt
new file mode 100644
index 0000000..9bff1ed
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/app/AddEditActivity.kt
@@ -0,0 +1,82 @@
+package com.example.bcsd_android_2025_1
+
+import android.app.Activity
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import com.bumptech.glide.Glide
+import com.example.bcsd_android_2025_1.databinding.ActivityAddEditBinding
+
+class AddEditActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityAddEditBinding
+ private val viewModel: WordViewModel by viewModels()
+
+ private var imageUri: String? = null
+ private var wordId: Int? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityAddEditBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ val editWordText = intent.getStringExtra(MainActivity.wordTextKey)
+ val editMeaning = intent.getStringExtra(MainActivity.wordMeaningKey)
+ wordId = intent.getIntExtra(MainActivity.wordIdKey, -1).takeIf { it != -1 }
+
+ val image = intent.getStringExtra(MainActivity.wordImageKey)
+ imageUri = image
+
+ if (!imageUri.isNullOrEmpty()) {
+ Glide.with(this).load(imageUri).into(binding.addImageImageview)
+ } else {
+ binding.addImageImageview.setImageDrawable(null)
+ }
+
+ binding.wordEdittext.setText(editWordText)
+ binding.meaningEdittext.setText(editMeaning)
+
+ binding.addImageButton.setOnClickListener {
+ imagePickerLauncher.launch("image/*")
+ }
+
+ binding.addButton.setOnClickListener {
+ val wordText = binding.wordEdittext.text.toString()
+ val meaning = binding.meaningEdittext.text.toString()
+ if (wordText.isNotBlank() && meaning.isNotBlank()) {
+ val word = WordListData(wordId ?: 0, wordText, meaning, imageUri)
+ if (wordId != null) {
+ viewModel.update(word)
+ binding.wordEdittext.setText("")
+ binding.meaningEdittext.setText("")
+ binding.addImageImageview.setImageDrawable(null)
+ imageUri = null
+ val resultIntent = Intent().apply {
+ putExtra(MainActivity.editedWordKey, word.word)
+ putExtra(MainActivity.editedMeaningKey, word.meaning)
+ putExtra(MainActivity.editedImageKey, word.imageUri)
+ }
+ setResult(Activity.RESULT_OK, resultIntent)
+ finish()
+
+ } else {
+ viewModel.insert(word)
+ }
+ finish()
+ }
+ }
+ }
+
+ private val imagePickerLauncher =
+ registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
+ if (uri != null) {
+ imageUri = uri.toString()
+ Glide.with(this).load(uri).into(binding.addImageImageview)
+ } else {
+ imageUri = null
+ binding.addImageImageview.setImageDrawable(null)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/app/MainActivity.kt b/app/src/main/java/com/example/bcsd_android_2025_1/app/MainActivity.kt
new file mode 100644
index 0000000..cf43ad2
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/app/MainActivity.kt
@@ -0,0 +1,138 @@
+package com.example.bcsd_android_2025_1
+
+import android.app.Activity
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.widget.Toast
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.bumptech.glide.Glide
+import com.example.bcsd_android_2025_1.databinding.ActivityMainBinding
+
+
+
+class MainActivity : AppCompatActivity() {
+ companion object{
+ const val wordIdKey = "word_id"
+ const val wordTextKey = "word_text"
+ const val wordMeaningKey = "word_meaning"
+ const val wordImageKey = "word_imageUri"
+ const val editedWordKey = "edited_word"
+ const val editedMeaningKey = "edited_meaning"
+ const val editedImageKey = "edited_image"
+ }
+
+ private lateinit var binding: ActivityMainBinding
+ private val viewModel: WordViewModel by viewModels()
+ private lateinit var editActivityLauncher: ActivityResultLauncher
+
+
+ private val adapter by lazy {
+ WordAdapter(onTopClick = { viewModel.setTopWord(it) })
+ }
+
+ private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
+ if (isGranted) {
+ startAddEditActivity()
+ } else {
+ Toast.makeText(this, R.string.need_image_permission, Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ private fun checkPermissionAndStart() {
+ val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ android.Manifest.permission.READ_MEDIA_IMAGES
+ } else {
+ android.Manifest.permission.READ_EXTERNAL_STORAGE
+ }
+ when {
+ ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED -> {
+ startAddEditActivity()
+ }
+ shouldShowRequestPermissionRationale(permission) -> {
+ requestPermissionLauncher.launch(permission)
+ }
+ else -> {
+ requestPermissionLauncher.launch(permission)
+ }
+ }
+ }
+
+ private fun startAddEditActivity() {
+ val intent = Intent(this, AddEditActivity::class.java)
+ editActivityLauncher.launch(intent)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ editActivityLauncher =
+ registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+ if (result.resultCode == Activity.RESULT_OK) {
+ val data = result.data
+ val editedWord = data?.getStringExtra(editedWordKey) ?: ""
+ val editedMeaning = data?.getStringExtra(editedMeaningKey) ?: ""
+ val editedImage = data?.getStringExtra(editedImageKey)
+
+ binding.wordTextview.text = editedWord
+ binding.meaningTextview.text = editedMeaning
+
+ if(!editedImage.isNullOrEmpty()){
+ Glide.with(this).load(editedImage).into(binding.wordImageview)
+ }else{
+ binding.wordImageview.setImageDrawable(null)
+ }
+ }
+ }
+
+ binding.recyclerView.adapter = adapter
+ binding.recyclerView.layoutManager = LinearLayoutManager(this)
+
+ binding.editButton.setOnClickListener {
+ viewModel.topWord.value?.let {
+ val intent = Intent(this, AddEditActivity::class.java).apply {
+ putExtra(wordIdKey, it.id)
+ putExtra(wordTextKey, it.word)
+ putExtra(wordMeaningKey, it.meaning)
+ putExtra(wordImageKey, it.imageUri)
+ }
+ editActivityLauncher.launch(intent)
+ }
+ }
+
+ binding.deleteButton.setOnClickListener {
+ viewModel.topWord.value?.let {
+ viewModel.delete(it)
+ binding.wordTextview.text = ""
+ binding.meaningTextview.text = ""
+ binding.wordImageview.setImageDrawable(null)
+ }
+ }
+
+ viewModel.allWords.observe(this) {
+ adapter.submitList(it)
+ }
+
+ viewModel.topWord.observe(this) {
+ binding.wordTextview.text = it?.word ?: ""
+ binding.meaningTextview.text = it?.meaning ?: ""
+ if (!it?.imageUri.isNullOrEmpty()) {
+ Glide.with(this).load(it?.imageUri).into(binding.wordImageview)
+ } else {
+ binding.wordImageview.setImageDrawable(null)
+ }
+ }
+
+ binding.floatingButton.setOnClickListener {
+ checkPermissionAndStart()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/app/WordAdapter.kt b/app/src/main/java/com/example/bcsd_android_2025_1/app/WordAdapter.kt
new file mode 100644
index 0000000..8b0ef10
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/app/WordAdapter.kt
@@ -0,0 +1,43 @@
+package com.example.bcsd_android_2025_1
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.example.bcsd_android_2025_1.databinding.ItemWordBinding
+
+class WordAdapter (
+ private val onTopClick: (WordListData) ->Unit
+) : ListAdapter(DiffCallback()){
+
+ inner class WordViewHolder(private val binding: ItemWordBinding): RecyclerView.ViewHolder(binding.root) {
+ fun bind(word: WordListData) {
+ binding.word = word
+ if (!word.imageUri.isNullOrEmpty()) {
+ Glide.with(binding.recyclerviewImageview.context)
+ .load(word.imageUri)
+ .into(binding.recyclerviewImageview)
+ } else {
+ binding.recyclerviewImageview.setImageDrawable(null)
+ }
+ binding.root.setOnClickListener { onTopClick(word) }
+ binding.executePendingBindings()
+ }
+ }
+
+ override fun onCreateViewHolder(parent:ViewGroup, viewType: Int):WordViewHolder{
+ val binding = ItemWordBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ return WordViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: WordViewHolder, position:Int){
+ holder.bind(getItem(position))
+ }
+
+ class DiffCallback: DiffUtil.ItemCallback(){
+ override fun areItemsTheSame(oldItem:WordListData, newItem:WordListData):Boolean = oldItem.id ==newItem.id
+ override fun areContentsTheSame(oldItem: WordListData, newItem: WordListData): Boolean = oldItem == newItem
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/app/WordViewModel.kt b/app/src/main/java/com/example/bcsd_android_2025_1/app/WordViewModel.kt
new file mode 100644
index 0000000..18d445c
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/app/WordViewModel.kt
@@ -0,0 +1,24 @@
+package com.example.bcsd_android_2025_1
+
+import android.app.Application
+import androidx.lifecycle.*
+import kotlinx.coroutines.launch
+
+
+class WordViewModel(application: Application) : AndroidViewModel(application) {
+ private val repository: WordRepository
+ val allWords: LiveData>
+ private val _topWord = MutableLiveData()
+ val topWord: LiveData get() = _topWord
+
+ init {
+ val wordDao = WordDatabase.getDatabase(application).wordDao()
+ repository = WordRepository(wordDao)
+ allWords = repository.allWords
+ }
+
+ fun insert(word:WordListData) = viewModelScope.launch { repository.insert(word)}
+ fun update(word:WordListData) = viewModelScope.launch { repository.update(word)}
+ fun delete(word:WordListData) = viewModelScope.launch { repository.delete(word)}
+ fun setTopWord(word: WordListData) {_topWord.value = word}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/data/WordDao.kt b/app/src/main/java/com/example/bcsd_android_2025_1/data/WordDao.kt
new file mode 100644
index 0000000..27eb462
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/data/WordDao.kt
@@ -0,0 +1,20 @@
+package com.example.bcsd_android_2025_1
+
+import androidx.lifecycle.LiveData
+import androidx.room.*
+
+@Dao
+interface WordDao {
+ @Query("SELECT * FROM word_table ORDER BY id DESC")
+ fun getAllwords(): LiveData>
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insert(word: WordListData)
+
+ @Update
+ suspend fun update(word: WordListData)
+
+ @Delete
+ suspend fun delete(wordListData: WordListData)
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/data/WordDatabase.kt b/app/src/main/java/com/example/bcsd_android_2025_1/data/WordDatabase.kt
new file mode 100644
index 0000000..6b1be58
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/data/WordDatabase.kt
@@ -0,0 +1,28 @@
+package com.example.bcsd_android_2025_1
+
+import android.content.Context
+import androidx.room.Room
+import androidx.room.Database
+import androidx.room.RoomDatabase
+
+@Database(entities = [WordListData::class], version = 2, exportSchema = false)
+abstract class WordDatabase : RoomDatabase() {
+ abstract fun wordDao(): WordDao
+
+ companion object{
+ @Volatile private var INSTANCE: WordDatabase?=null
+
+ fun getDatabase(context: Context): WordDatabase{
+ return INSTANCE ?: synchronized(this) {
+ val instance = Room.databaseBuilder(
+ context.applicationContext, WordDatabase::class.java,
+ "word_database"
+ )
+ .fallbackToDestructiveMigration()
+ .build()
+ INSTANCE = instance
+ instance
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/data/WordRepository.kt b/app/src/main/java/com/example/bcsd_android_2025_1/data/WordRepository.kt
new file mode 100644
index 0000000..6235632
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/data/WordRepository.kt
@@ -0,0 +1,11 @@
+package com.example.bcsd_android_2025_1
+
+import androidx.lifecycle.LiveData
+
+class WordRepository(private val wordDao: WordDao) {
+ val allWords: LiveData> = wordDao.getAllwords()
+
+ suspend fun insert(word: WordListData) = wordDao.insert(word)
+ suspend fun update(word: WordListData) = wordDao.update(word)
+ suspend fun delete(word: WordListData) = wordDao.delete(word)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/domain/WordListData.kt b/app/src/main/java/com/example/bcsd_android_2025_1/domain/WordListData.kt
new file mode 100644
index 0000000..d729faf
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/domain/WordListData.kt
@@ -0,0 +1,13 @@
+package com.example.bcsd_android_2025_1
+
+import androidx.room.PrimaryKey
+import androidx.room.Entity
+
+@Entity(tableName = "word_table")
+data class WordListData (
+ @PrimaryKey(autoGenerate = true)
+ val id: Int = 0,
+ var word: String,
+ var meaning: String,
+ val imageUri: String? = null
+)
\ No newline at end of file
diff --git a/app/src/main/res/drawable/delete_icon.png b/app/src/main/res/drawable/delete_icon.png
new file mode 100644
index 0000000..6f67376
Binary files /dev/null and b/app/src/main/res/drawable/delete_icon.png differ
diff --git a/app/src/main/res/drawable/edit_icon.png b/app/src/main/res/drawable/edit_icon.png
new file mode 100644
index 0000000..bb9a087
Binary files /dev/null and b/app/src/main/res/drawable/edit_icon.png differ
diff --git a/app/src/main/res/layout/activity_add_edit.xml b/app/src/main/res/layout/activity_add_edit.xml
new file mode 100644
index 0000000..2aef5bf
--- /dev/null
+++ b/app/src/main/res/layout/activity_add_edit.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 311f3cb..3a9e645 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,19 +1,82 @@
-
-
-
-
-
\ No newline at end of file
+ xmlns:tools="http://schemas.android.com/tools">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_word.xml b/app/src/main/res/layout/item_word.xml
new file mode 100644
index 0000000..e7dfeb3
--- /dev/null
+++ b/app/src/main/res/layout/item_word.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c6c4daf..c570f3d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,11 @@
BCSD_Android_2025-1
+ 추가
+ 단어
+ 뜻
+ 단어 추가
+ 이미지 추가
+ 이미지 접근 권한 필요
+
+
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 283fec9..ba0ef47 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -9,8 +9,15 @@ appcompat = "1.7.0"
material = "1.12.0"
activity = "1.9.3"
constraintlayout = "2.2.1"
+roomCommonJvm = "2.7.2"
+roomRuntimeAndroid = "2.7.2"
+lifecycle = "2.7.0"
+coroutines = "1.7.3"
+room = "2.7.2"
[libraries]
+androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
+kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
@@ -19,6 +26,10 @@ androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version
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" }
+androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
+androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
+androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
+
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 6ddf3b7..f659462 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,5 +1,6 @@
pluginManagement {
repositories {
+ gradlePluginPortal()
google {
content {
includeGroupByRegex("com\\.android.*")