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..c22b6fa
--- /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..2cdc89a
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ 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/shelf/Uncommitted_changes_before_Checkout_at_2025-07-13__8_26__Changes_.xml b/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-07-13__8_26__Changes_.xml
new file mode 100644
index 0000000..9984e75
--- /dev/null
+++ b/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-07-13__8_26__Changes_.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git "a/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-07-13_\354\230\244\355\233\204_8_26_[Changes]/shelved.patch" "b/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-07-13_\354\230\244\355\233\204_8_26_[Changes]/shelved.patch"
new file mode 100644
index 0000000..2ad04a8
--- /dev/null
+++ "b/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-07-13_\354\230\244\355\233\204_8_26_[Changes]/shelved.patch"
@@ -0,0 +1,49 @@
+Index: app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
+<+>package com.example.bcsd_android_2025_1\r\nimport android.os.Bundle\r\nimport android.widget.Button\r\nimport android.widget.TextView\r\nimport androidx.appcompat.app.AppCompatActivity\r\nimport androidx.lifecycle.lifecycleScope\r\nimport androidx.recyclerview.widget.LinearLayoutManager\r\nimport androidx.recyclerview.widget.RecyclerView\r\nimport kotlinx.coroutines.Job\r\nimport kotlinx.coroutines.delay\r\nimport kotlinx.coroutines.isActive\r\nimport kotlinx.coroutines.launch\r\n\r\nclass MainActivity : AppCompatActivity() {\r\n\r\n private lateinit var tvTimer : TextView\r\n private lateinit var btnLap : Button\r\n private lateinit var btnStart : Button\r\n private lateinit var btnStop : Button\r\n\r\n private lateinit var rvRecord : RecyclerView\r\n private lateinit var lapAdapter: LapAdapter\r\n\r\n private var isRunning = false\r\n private var runningTime = 0L\r\n private var job: Job? = null\r\n\r\n override fun onCreate(savedInstanceState: Bundle?) {\r\n super.onCreate(savedInstanceState)\r\n setContentView(R.layout.activity_main)\r\n\r\n tvTimer = findViewById(R.id.tv_main_timer)\r\n btnLap = findViewById(R.id.btn_main_lap)\r\n btnStart = findViewById(R.id.btn_main_start)\r\n btnStop = findViewById(R.id.btn_main_stop)\r\n rvRecord = findViewById(R.id.rv_main_record)\r\n rvRecord.layoutManager = LinearLayoutManager(this)\r\n lapAdapter = LapAdapter()\r\n rvRecord.adapter = lapAdapter\r\n\r\n btnStart.setOnClickListener {\r\n if (isRunning) {\r\n pauseTimer()\r\n } else {\r\n startTimer()\r\n }\r\n }\r\n\r\n btnStop.setOnClickListener {\r\n stopTimer()\r\n }\r\n\r\n btnLap.setOnClickListener {\r\n if (isRunning) {\r\n lapAdapter.addLap(formatTime(runningTime))\r\n }\r\n }\r\n }\r\n\r\n private fun startTimer() {\r\n val startTime = System.currentTimeMillis() - runningTime\r\n job = lifecycleScope.launch {\r\n while (isActive) {\r\n runningTime = System.currentTimeMillis() - startTime\r\n tvTimer.text = formatTime(runningTime)\r\n delay(10)\r\n }\r\n }\r\n isRunning = true\r\n btnStart.text = getString(R.string.btn_pause)\r\n }\r\n\r\n private fun pauseTimer() {\r\n job?.cancel()\r\n isRunning = false\r\n btnStart.text = getString(R.string.btn_start)\r\n }\r\n\r\n private fun stopTimer() {\r\n job?.cancel()\r\n runningTime = 0L\r\n isRunning = false\r\n tvTimer.text = getString(R.string.tv_time)\r\n btnStart.text = getString(R.string.btn_start)\r\n lapAdapter.clear()\r\n }\r\n\r\n private fun formatTime(ms: Long): String {\r\n val min = (ms/1000)/60\r\n val sec = (ms/1000)%60\r\n val millisec = (ms%1000) / 10\r\n return String.format(\"%02d:%02d:%02d\", min, sec, millisec)\r\n }\r\n\r\n\r\n}\r\n\r\n
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+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
+--- a/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt (revision a566fccc5cae9f9de481ed1c810a31555d2dca50)
++++ b/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt (date 1751870590293)
+@@ -10,6 +10,7 @@
+ import kotlinx.coroutines.delay
+ import kotlinx.coroutines.isActive
+ import kotlinx.coroutines.launch
++import java.util.Locale
+
+ class MainActivity : AppCompatActivity() {
+
+@@ -89,7 +90,7 @@
+ val min = (ms/1000)/60
+ val sec = (ms/1000)%60
+ val millisec = (ms%1000) / 10
+- return String.format("%02d:%02d:%02d", min, sec, millisec)
++ return String.format(Locale.getDefault(),"%02d:%02d:%02d", min, sec, millisec)
+ }
+
+
+Index: app/src/main/res/layout/item.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
+<+>\r\n\r\n\r\n \r\n \r\n\r\n\r\n
+===================================================================
+diff --git a/app/src/main/res/layout/item.xml b/app/src/main/res/layout/item.xml
+--- a/app/src/main/res/layout/item.xml (revision a566fccc5cae9f9de481ed1c810a31555d2dca50)
++++ b/app/src/main/res/layout/item.xml (date 1752170182341)
+@@ -1,5 +1,6 @@
+
+
+
+@@ -18,4 +19,5 @@
+ android:layout_marginStart="5dp"/>
+
+
++
+
+\ No newline at end of file
diff --git "a/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-07-13_\354\230\244\355\233\204_8_26_[Changes]1/shelved.patch" "b/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-07-13_\354\230\244\355\233\204_8_26_[Changes]1/shelved.patch"
new file mode 100644
index 0000000..e69de29
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/.kotlin/errors/errors-1752480219597.log b/.kotlin/errors/errors-1752480219597.log
new file mode 100644
index 0000000..a44172d
--- /dev/null
+++ b/.kotlin/errors/errors-1752480219597.log
@@ -0,0 +1,57 @@
+kotlin version: 2.1.10
+error message: java.lang.IncompatibleClassChangeError: class com.google.devtools.ksp.common.PersistentMap cannot inherit from final class org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap
+ at java.base/java.lang.ClassLoader.defineClass1(Native Method)
+ at java.base/java.lang.ClassLoader.defineClass(Unknown Source)
+ at java.base/java.security.SecureClassLoader.defineClass(Unknown Source)
+ at java.base/java.net.URLClassLoader.defineClass(Unknown Source)
+ at java.base/java.net.URLClassLoader$1.run(Unknown Source)
+ at java.base/java.net.URLClassLoader$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.base/java.net.URLClassLoader.findClass(Unknown Source)
+ at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
+ at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
+ at java.base/java.lang.ClassLoader.defineClass1(Native Method)
+ at java.base/java.lang.ClassLoader.defineClass(Unknown Source)
+ at java.base/java.security.SecureClassLoader.defineClass(Unknown Source)
+ at java.base/java.net.URLClassLoader.defineClass(Unknown Source)
+ at java.base/java.net.URLClassLoader$1.run(Unknown Source)
+ at java.base/java.net.URLClassLoader$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.base/java.net.URLClassLoader.findClass(Unknown Source)
+ at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
+ at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
+ at com.google.devtools.ksp.common.IncrementalContextBase.(IncrementalContextBase.kt:103)
+ at com.google.devtools.ksp.IncrementalContext.(IncrementalContext.kt:64)
+ at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$2.invoke(KotlinSymbolProcessingExtension.kt:192)
+ at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$2.invoke(KotlinSymbolProcessingExtension.kt:189)
+ at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.handleException(KotlinSymbolProcessingExtension.kt:414)
+ at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.doAnalysis(KotlinSymbolProcessingExtension.kt:189)
+ at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:112)
+ at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:75)
+ at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze$lambda$9(KotlinToJVMBytecodeCompiler.kt:356)
+ at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:112)
+ at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:347)
+ at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.runFrontendAndGenerateIrUsingClassicFrontend(KotlinToJVMBytecodeCompiler.kt:177)
+ at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:102)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:169)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:102)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.exec(CLICompiler.kt:316)
+ at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1706)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
+ at java.base/java.lang.reflect.Method.invoke(Unknown Source)
+ at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+ at java.base/java.lang.Thread.run(Unknown Source)
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5791375..fa454ae 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,22 +1,34 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
+ id("com.google.devtools.ksp") version "2.1.10-1.0.29"
+
+
}
+apply(plugin = "kotlin-kapt")
+
android {
namespace = "com.example.bcsd_android_2025_1"
- compileSdk = 34
+ compileSdk = 35
defaultConfig {
applicationId = "com.example.bcsd_android_2025_1"
minSdk = 26
- targetSdk = 34
+ targetSdk = 35
versionCode = 1
versionName = "1.0"
+ multiDexEnabled = true
+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
+ buildFeatures {
+ dataBinding = true
+ }
+
+
buildTypes {
release {
isMinifyEnabled = false
@@ -33,10 +45,10 @@ android {
kotlinOptions {
jvmTarget = "11"
}
+
}
dependencies {
-
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
@@ -45,4 +57,16 @@ dependencies {
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
+
+ implementation(libs.androidx.room.runtime)
+ implementation(libs.androidx.room.ktx)
+ ksp(libs.androidx.room.compiler)
+
+ implementation(libs.androidx.lifecycle.viewmodel.ktx)
+ implementation(libs.androidx.lifecycle.livedata.ktx)
+ implementation(libs.androidx.lifecycle.runtime.ktx)
+ implementation(libs.androidx.lifecycle.viewmodel.savedstate)
+
+ implementation(libs.kotlinx.coroutines.android)
+ ksp("androidx.room:room-compiler:2.7.2")
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4c80941..67a4a40 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -12,6 +12,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.BCSD_Android_20251"
tools:targetApi="31">
+
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/AddEditActivity.kt b/app/src/main/java/com/example/bcsd_android_2025_1/AddEditActivity.kt
new file mode 100644
index 0000000..9c89a26
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/AddEditActivity.kt
@@ -0,0 +1,49 @@
+package com.example.bcsd_android_2025_1
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModelProvider
+import com.example.bcsd_android_2025_1.databinding.ActivityAddEditBinding
+
+class AddEditActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityAddEditBinding
+ private var originalWord: Word? = null
+ private lateinit var wordViewModel: WordViewModel
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityAddEditBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ wordViewModel = ViewModelProvider(this)[WordViewModel::class.java]
+
+ originalWord = intent.getSerializableExtra("word_to_edit") as? Word
+ originalWord?.let {
+ binding.editTvAddWord.setText(it.word)
+ binding.editTvAddMean.setText(it.meaning)
+ }
+
+ binding.button.setOnClickListener {
+ val word = binding.editTvAddWord.text.toString()
+ val mean = binding.editTvAddMean.text.toString()
+
+ if (word.isBlank() || mean.isBlank()) {
+ return@setOnClickListener
+ }
+
+ if (originalWord != null) {
+ val updated = originalWord!!.copy(word = word, meaning = mean)
+ val result = Intent().apply {
+ putExtra("updated_word", updated)
+ }
+ setResult(RESULT_OK, result)
+ finish()
+ } else {
+ wordViewModel.insert(Word(word = word, meaning = mean))
+ finish()
+ }
+
+ }
+ }
+}
\ 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..6a2f320 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,81 @@
package com.example.bcsd_android_2025_1
+import android.content.Intent
+import android.os.Build
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 binding: ActivityMainBinding
+ private lateinit var wordViewModel: WordViewModel
+ private lateinit var wordAdapter: WordAdapter
+
+ private var selectedWord: Word? = null
+
+ private val editWordLauncher = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) { result ->
+ if (result.resultCode == RESULT_OK) {
+ val updateWord = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ result.data?.getSerializableExtra("updated_word", Word::class.java)
+ } else {
+ intent.getSerializableExtra("updated_word") as? Word
+ }
+ updateWord?.let {
+ wordViewModel.update(it)
+ selectedWord = it
+ showSelectedWord(it)
+ }
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ wordViewModel = ViewModelProvider(this)[WordViewModel::class.java]
+
+ wordAdapter = WordAdapter { word ->
+ selectedWord = word
+ showSelectedWord(word)
+ }
+
+ binding.recyclerviewMain.adapter = wordAdapter
+ binding.recyclerviewMain.layoutManager = LinearLayoutManager(this)
+
+ wordViewModel.allWords.observe(this) { words ->
+ wordAdapter.submitList(words)
+ }
+
+ binding.imageBtnMainDelete.setOnClickListener{
+ selectedWord?.let{
+ wordViewModel.delete(it)
+ clearSelectedWord()
+ }
+ }
+ binding.imageBtnMainEdit.setOnClickListener {
+ selectedWord?.let{
+ val intent = Intent(this, AddEditActivity::class.java)
+ intent.putExtra("word_to_edit",it)
+ editWordLauncher.launch(intent)
+ }
+ }
+ binding.imageBtnMainPlus.setOnClickListener {
+ startActivity(Intent(this, AddEditActivity::class.java))
+ }
+ }
+ private fun showSelectedWord(word: Word) {
+ binding.tvMainWord.text = word.word
+ binding.tvMainMean.text = word.meaning
+ }
+ private fun clearSelectedWord() {
+ binding.tvMainWord.text = getString(R.string.tv_main_note_word)
+ binding.tvMainMean.text = getString(R.string.tv_main_note_mean)
+ selectedWord = null
}
}
\ 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..872749e
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/Word.kt
@@ -0,0 +1,12 @@
+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..a01b81c
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/WordAdapter.kt
@@ -0,0 +1,35 @@
+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
+) : ListAdapter(DiffCallback()){
+ inner class WordViewHolder(private val binding: ItemWordBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+ fun bind(word: Word) {
+ binding.itemTvWord.text = word.word
+ binding.itemTvMean.text = word.meaning
+ binding.root.setOnClickListener { onItemClick(word) }
+ }
+ }
+
+ 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: 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/WordDatabase.kt b/app/src/main/java/com/example/bcsd_android_2025_1/WordDatabase.kt
new file mode 100644
index 0000000..e49b56c
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/WordDatabase.kt
@@ -0,0 +1,27 @@
+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 wordRoom(): WordRoom
+
+ 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..bb72254
--- /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: WordRoom) {
+ 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/WordRoom.kt b/app/src/main/java/com/example/bcsd_android_2025_1/WordRoom.kt
new file mode 100644
index 0000000..a79c462
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/WordRoom.kt
@@ -0,0 +1,24 @@
+package com.example.bcsd_android_2025_1
+
+import androidx.lifecycle.LiveData
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import androidx.room.Update
+
+@Dao
+interface WordRoom{
+ @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/WordViewModel.kt b/app/src/main/java/com/example/bcsd_android_2025_1/WordViewModel.kt
new file mode 100644
index 0000000..20cd00d
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/WordViewModel.kt
@@ -0,0 +1,28 @@
+package com.example.bcsd_android_2025_1
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.launch
+
+class WordViewModel(application: Application) : AndroidViewModel(application){
+ private val repository: WordRepository
+ val allWords: LiveData>
+
+ init {
+ val dao = WordDatabase.getDatabase(application).wordRoom()
+ 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)
+ }
+}
\ No newline at end of file
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..04b3643
--- /dev/null
+++ b/app/src/main/res/layout/activity_add_edit.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..b553103 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,19 +1,75 @@
-
-
-
-
-
\ 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..1bd4d0d
--- /dev/null
+++ b/app/src/main/res/layout/item_word.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..a877d16 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,19 @@
BCSD_Android_2025-1
+ 기본 메모 제목
+ 기본 메모 내용
+ 삭제 버튼
+ 수정 버튼
+ 추가 버튼
+
+ 단어 추가
+ 단어
+ 뜻
+ 추가
+
+ 단어를 입력하세요
+ 뜻을 입력하세요
+
+ 단어
+ 뜻
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 922f551..1503fc2 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -2,4 +2,12 @@
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
+}
+
+buildscript {
+
+ dependencies {
+ classpath(libs.gradle)
+ classpath(libs.kotlin.gradle.plugin)
+ }
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 283fec9..6f623a4 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,26 +1,47 @@
[versions]
-agp = "8.9.0"
-kotlin = "2.0.21"
-coreKtx = "1.13.1"
+agp = "8.9.3"
+gradle = "8.2.2"
+kotlin = "2.1.10"
+coreKtx = "1.16.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
-appcompat = "1.7.0"
+appcompat = "1.7.1"
+kotlinGradlePlugin = "1.9.0"
material = "1.12.0"
-activity = "1.9.3"
+activity = "1.10.1"
constraintlayout = "2.2.1"
+room = "2.7.2"
+lifecycle = "2.9.1"
+kotlinx-coroutines = "1.7.3"
+ksp = "2.0.0-1.0.20"
+
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+gradle = { module = "com.android.tools.build:gradle", version.ref = "gradle" }
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" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlinGradlePlugin" }
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-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"}
+
+androidx-lifecycle-viewmodel-ktx = {module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle"}
+androidx-lifecycle-livedata-ktx = {module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycle"}
+androidx-lifecycle-runtime-ktx = {module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle"}
+androidx-lifecycle-viewmodel-savedstate = {module = "androidx.lifecycle:lifecycle-viewmodel-savedstate", version.ref = "lifecycle"}
+
+kotlinx-coroutines-android = {module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines"}
+
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
-
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.*")