diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
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/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..97626ba
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ 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/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..74dd639
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ 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..35eb1dd
--- /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..8b7827d 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("org.jetbrains.kotlin.kapt")
}
android {
@@ -16,6 +17,10 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
+ buildFeatures {
+ dataBinding = true
+ viewBinding = true
+ }
buildTypes {
release {
@@ -37,6 +42,10 @@ android {
dependencies {
+ implementation(libs.androidx.room.runtime)
+ implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0")
+ implementation(libs.androidx.room.ktx)
+ kapt(libs.androidx.room.compiler)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4c80941..13fa638 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,6 +21,7 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/AddEditWordActivity.kt b/app/src/main/java/com/example/bcsd_android_2025_1/AddEditWordActivity.kt
new file mode 100644
index 0000000..fd84cc0
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/AddEditWordActivity.kt
@@ -0,0 +1,39 @@
+package com.example.bcsd_android_2025_1
+import android.content.Intent
+import android.os.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import com.example.bcsd_android_2025_1.databinding.ActivityAddEditWordBinding
+
+class AddEditWordActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityAddEditWordBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityAddEditWordBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ val existingWord = intent.getSerializableExtra("word") as? Word
+
+ if (existingWord != null) {
+ binding.etWord.setText(existingWord.word)
+ binding.etMeaning.setText(existingWord.meaning)
+ }
+
+ binding.btnSave.setOnClickListener {
+ val word = binding.etWord.text.toString()
+ val meaning = binding.etMeaning.text.toString()
+ if (word.isNotBlank() && meaning.isNotBlank()) {
+ val result = Word(
+ id = existingWord?.id ?: 0,
+ word = word,
+ meaning = meaning
+ )
+ setResult(RESULT_OK, Intent().putExtra("result", result))
+ finish()
+ } else {
+ Toast.makeText(this, R.string.toast_msg, Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+}
\ No newline at end of file
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
index 3ffa0eb..96d5605 100644
--- 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
@@ -1,14 +1,56 @@
package com.example.bcsd_android_2025_1
+import android.content.Intent
import android.os.Bundle
-import androidx.activity.enableEdgeToEdge
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowInsetsCompat
+import androidx.lifecycle.ViewModelProvider
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.example.bcsd_android_2025_1.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
+ private lateinit var viewModel: WordViewModel
+ private lateinit var adapter: WordAdapter
+
+ private val launcher =
+ registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+ if (result.resultCode == RESULT_OK) {
+ val word = result.data?.getSerializableExtra("result") as? Word
+ word?.let {
+ if (it.id == 0) viewModel.insert(it) else viewModel.update(it)
+ }
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
+ val binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ viewModel = ViewModelProvider(this)[WordViewModel::class.java]
+ binding.viewModel = viewModel
+ binding.lifecycleOwner = this
+
+ adapter = WordAdapter(
+ onItemClick = { word -> viewModel.selectWord(word) },
+ onEditClick = { word ->
+ val intent = Intent(this, AddEditWordActivity::class.java)
+ intent.putExtra("word", word)
+ launcher.launch(intent)
+ },
+ onDeleteClick = { word -> viewModel.delete(word) }
+ )
+
+ binding.recyclerView.layoutManager = LinearLayoutManager(this)
+ binding.recyclerView.adapter = adapter
+
+ viewModel.allWords.observe(this) {
+ adapter.submitList(it)
+ }
+
+ binding.fab.setOnClickListener {
+ val intent = Intent(this, AddEditWordActivity::class.java)
+ launcher.launch(intent)
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/Word.kt b/app/src/main/java/com/example/bcsd_android_2025_1/Word.kt
new file mode 100644
index 0000000..9e2484c
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/Word.kt
@@ -0,0 +1,13 @@
+package com.example.bcsd_android_2025_1
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import java.io.Serializable
+
+@Entity(tableName = "word_table")
+
+data class Word(
+ @PrimaryKey(autoGenerate = true) val id : Int = 0,
+ val word: String,
+ val meaning: String
+) : Serializable
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/WordAdapter.kt b/app/src/main/java/com/example/bcsd_android_2025_1/WordAdapter.kt
new file mode 100644
index 0000000..962d66f
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/WordAdapter.kt
@@ -0,0 +1,41 @@
+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.example.bcsd_android_2025_1.databinding.ItemWordBinding
+
+class WordAdapter(
+ private val onItemClick: (Word) -> Unit,
+ private val onEditClick: (Word) -> Unit,
+ private val onDeleteClick: (Word) -> Unit
+) : ListAdapter(DiffCallback()){
+
+ inner class WordViewHolder(private val binding: ItemWordBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+ fun bind(word: Word) {
+ binding.word = word
+ binding.root.setOnClickListener { onItemClick(word) }
+ binding.btnEdit.setOnClickListener { onEditClick(word) }
+ binding.btnDelete.setOnClickListener { onDeleteClick(word) }
+ binding.executePendingBindings()
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WordViewHolder {
+ val inflater = LayoutInflater.from(parent.context)
+ val binding = ItemWordBinding.inflate(inflater, parent, false)
+ return WordViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: WordViewHolder, position: Int) {
+ holder.bind(getItem(position))
+ }
+
+ class DiffCallback : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: Word, newItem: Word) = oldItem.id == newItem.id
+ override fun areContentsTheSame(oldItem: Word, newItem: Word) = oldItem == newItem
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/WordDao.kt b/app/src/main/java/com/example/bcsd_android_2025_1/WordDao.kt
new file mode 100644
index 0000000..3e08961
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/WordDao.kt
@@ -0,0 +1,19 @@
+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: Word)
+
+ @Update
+ suspend fun update(word: Word)
+
+ @Delete
+ suspend fun delete(word: Word)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/WordDatabase.kt b/app/src/main/java/com/example/bcsd_android_2025_1/WordDatabase.kt
new file mode 100644
index 0000000..dec457e
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/WordDatabase.kt
@@ -0,0 +1,28 @@
+package com.example.bcsd_android_2025_1
+
+import android.content.Context
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+
+@Database(entities = [Word::class], version = 1)
+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"
+ ).build()
+ INSTANCE = instance
+ instance
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/WordRepository.kt b/app/src/main/java/com/example/bcsd_android_2025_1/WordRepository.kt
new file mode 100644
index 0000000..847169e
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/WordRepository.kt
@@ -0,0 +1,11 @@
+package com.example.bcsd_android_2025_1
+
+import androidx.lifecycle.LiveData
+
+class WordRepository(private val dao: WordDao) {
+ val allWords : LiveData> = dao.getAllWords()
+
+ suspend fun insert(word: Word) = dao.insert(word)
+ suspend fun update(word: Word) = dao.update(word)
+ suspend fun delete(word: Word) = dao.delete(word)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/WordViewModel.kt b/app/src/main/java/com/example/bcsd_android_2025_1/WordViewModel.kt
new file mode 100644
index 0000000..127afaf
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/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 _selectedWord = MutableLiveData()
+ val selectedWord: LiveData get() = _selectedWord
+
+ init {
+ val dao = WordDatabase.getDatabase(application).wordDao()
+ repository = WordRepository(dao)
+ allWords = repository.allWords
+ }
+ fun insert(word: Word) = viewModelScope.launch { repository.insert(word) }
+ fun update(word: Word) = viewModelScope.launch { repository.update(word) }
+ fun delete(word: Word) = viewModelScope.launch { repository.delete(word) }
+ fun selectWord(word: Word) {
+ _selectedWord.value = word
+ }
+}
diff --git a/app/src/main/res/drawable/add_icon.xml b/app/src/main/res/drawable/add_icon.xml
new file mode 100644
index 0000000..9f83b8f
--- /dev/null
+++ b/app/src/main/res/drawable/add_icon.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/delete_icon.xml b/app/src/main/res/drawable/delete_icon.xml
new file mode 100644
index 0000000..883bcaa
--- /dev/null
+++ b/app/src/main/res/drawable/delete_icon.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/edit_icon.xml b/app/src/main/res/drawable/edit_icon.xml
new file mode 100644
index 0000000..3c53db7
--- /dev/null
+++ b/app/src/main/res/drawable/edit_icon.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_add_edit__word.xml b/app/src/main/res/layout/activity_add_edit__word.xml
new file mode 100644
index 0000000..726b467
--- /dev/null
+++ b/app/src/main/res/layout/activity_add_edit__word.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..23400c3 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,19 +1,58 @@
-
-
+
-
+
+
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..c3739e6
--- /dev/null
+++ b/app/src/main/res/layout/item_word.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..0f77594 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,7 @@
BCSD_Android_2025-1
+ 단어 추가
+ 단어
+ 뜻
+ 내용을 입력하세요
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 283fec9..a083807 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,9 @@ 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.*")