diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index 148fdd2..bb44937 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 2a4bbd8..61d8a23 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,11 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
+ buildFeatures {
+ viewBinding = true
+ dataBinding = true
+ }
+
buildTypes {
release {
isMinifyEnabled = false
@@ -42,7 +48,14 @@ dependencies {
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
+ implementation(libs.androidx.room.common.jvm)
+ implementation(libs.androidx.room.runtime.android)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
+ implementation(libs.androidx.room.runtime)
+ implementation(libs.androidx.room.ktx)
+ implementation(libs.androidx.lifecycle.viewmodel.ktx)
+ implementation(libs.androidx.lifecycle.livedata.ktx)
+ kapt(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 398b755..e018814 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,6 +20,9 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android_25_2/MainActivity.kt b/app/src/main/java/com/example/android_25_2/MainActivity.kt
index aed359b..f0f684f 100644
--- a/app/src/main/java/com/example/android_25_2/MainActivity.kt
+++ b/app/src/main/java/com/example/android_25_2/MainActivity.kt
@@ -1,20 +1,70 @@
package com.example.android_25_2
+import android.content.Intent
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
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.android_25_2.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
+
+ private lateinit var activityBinding: ActivityMainBinding
+ private lateinit var wordViewModel: WordViewModel
+ private lateinit var adapter: WordAdapter
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
- setContentView(R.layout.activity_main)
+ activityBinding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(activityBinding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
+
+ wordViewModel = ViewModelProvider(this)[WordViewModel::class.java]
+ adapter = WordAdapter()
+ activityBinding.recyclerView.adapter = adapter
+ activityBinding.recyclerView.layoutManager = LinearLayoutManager(this)
+
+ activityBinding.buttonAdd.setOnClickListener {
+ startActivity(Intent(this, SecondActivity::class.java))
+ }
+
+ wordViewModel.allWords.observe(this) { words ->
+ adapter.setWords(words)
+ }
+
+ adapter.setOnWordItemClickListener(object : WordAdapter.OnWordItemClickListener{
+ override fun onWordItemClick(position: Int, word: WordEntity) {
+ adapter.moveToTop(position)
+ activityBinding.recyclerView.scrollToPosition(0)
+ }
+
+ override fun onEditButtonClick(word: WordEntity) {
+ val intent = Intent(this@MainActivity, SecondActivity::class.java)
+ intent.putExtra("WORD_ID", word.id)
+ intent.putExtra("WORD", word.word)
+ intent.putExtra("MEANING", word.meaning)
+ startActivity(intent)
+ }
+
+ override fun onDeleteButtonClick(word: WordEntity) {
+ wordViewModel.delete(word)
+ }
+ })
+
+ activityBinding.buttonAdd.setOnClickListener{
+ startActivity(Intent(this, SecondActivity::class.java))
+ }
+
+ wordViewModel.allWords.observe(this) {words ->
+ adapter.setWords(words)
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android_25_2/SecondActivity.kt b/app/src/main/java/com/example/android_25_2/SecondActivity.kt
new file mode 100644
index 0000000..a666afc
--- /dev/null
+++ b/app/src/main/java/com/example/android_25_2/SecondActivity.kt
@@ -0,0 +1,57 @@
+package com.example.android_25_2
+
+import android.os.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import androidx.databinding.DataBindingUtil
+import androidx.lifecycle.ViewModelProvider
+import com.example.android_25_2.databinding.ActivitySecondBinding
+
+class SecondActivity : AppCompatActivity() {
+
+ private lateinit var activityBinding: ActivitySecondBinding
+ private lateinit var wordViewModel: WordViewModel
+ private var wordId: Int? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ activityBinding = DataBindingUtil.setContentView(this, R.layout.activity_second)
+
+ wordViewModel = ViewModelProvider(this)[WordViewModel::class.java]
+
+ wordId = intent.getIntExtra("WORD_ID", -1)
+ if (wordId == -1) {
+ wordId = null
+ }
+ val existingWord = intent.getStringExtra("WORD")
+ val existingMeaning = intent.getStringExtra("MEANING")
+
+ if (wordId != null) {
+ activityBinding.editTextWord.setText(existingWord)
+ activityBinding.editTextMeaning.setText(existingMeaning)
+ }
+ activityBinding.buttonSave.setOnClickListener {
+ val word = activityBinding.editTextWord.text.toString()
+ val meaning = activityBinding.editTextMeaning.text.toString()
+
+ if (word.isEmpty() || meaning.isEmpty()) {
+ Toast.makeText(this, R.string.empty_message, Toast.LENGTH_SHORT).show()
+ return@setOnClickListener
+ }
+
+ if (wordId != null) {
+ val wordEntity = WordEntity(
+ id = wordId!!,
+ word = word,
+ meaning = meaning
+ )
+ wordViewModel.update(wordEntity)
+ } else {
+ val wordEntity = WordEntity(word = word, meaning = meaning)
+ wordViewModel.insert(wordEntity)
+ }
+
+ finish()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android_25_2/WordAdapter.kt b/app/src/main/java/com/example/android_25_2/WordAdapter.kt
new file mode 100644
index 0000000..d9bf17f
--- /dev/null
+++ b/app/src/main/java/com/example/android_25_2/WordAdapter.kt
@@ -0,0 +1,73 @@
+package com.example.android_25_2
+
+import android.view.ViewGroup
+import android.view.LayoutInflater
+import androidx.recyclerview.widget.RecyclerView
+import com.example.android_25_2.databinding.ItemBinding
+
+class WordAdapter: RecyclerView.Adapter(){
+
+ private var words = emptyList()
+
+ interface OnWordItemClickListener {
+ fun onWordItemClick(position: Int, word: WordEntity)
+ fun onEditButtonClick(word: WordEntity)
+ fun onDeleteButtonClick(word: WordEntity)
+ }
+
+ private var listener: OnWordItemClickListener? = null
+ fun setOnWordItemClickListener(listener: OnWordItemClickListener) {
+ this.listener = listener
+ }
+
+ inner class WordViewHolder(val binding: ItemBinding) :
+ RecyclerView.ViewHolder(binding.root)
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WordAdapter.WordViewHolder {
+ val binding = ItemBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+ return WordViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: WordAdapter.WordViewHolder, position: Int) {
+ val word = words[position]
+ holder.binding.word = word
+ holder.binding.executePendingBindings()
+
+ holder.binding.root.setOnClickListener {
+ listener?.onWordItemClick(holder.adapterPosition, word)
+ }
+
+ holder.binding.buttonEdit.setOnClickListener {
+ listener?.onEditButtonClick(word)
+ }
+
+ holder.binding.buttonDelete.setOnClickListener {
+ listener?.onDeleteButtonClick(word)
+ }
+ }
+
+ override fun getItemCount() = words.size
+
+ fun setWords(newWords: List) {
+ this.words = newWords
+ notifyDataSetChanged()
+ }
+
+ fun getWord(position: Int): WordEntity {
+ return words[position]
+ }
+
+ fun moveToTop(position: Int) {
+ val word = words[position]
+ val currentList = words.toMutableList()
+ currentList.removeAt(position)
+ currentList.add(0, word)
+ words = currentList
+
+ notifyItemMoved(position, 0)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android_25_2/WordDao.kt b/app/src/main/java/com/example/android_25_2/WordDao.kt
new file mode 100644
index 0000000..8ee2800
--- /dev/null
+++ b/app/src/main/java/com/example/android_25_2/WordDao.kt
@@ -0,0 +1,23 @@
+package com.example.android_25_2
+
+import androidx.lifecycle.LiveData
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Query
+import androidx.room.Update
+
+@Dao
+interface WordDao {
+ @Insert
+ suspend fun insert(vararg word: WordEntity)
+
+ @Update
+ suspend fun update(word: WordEntity)
+
+ @Delete
+ suspend fun delete(word: WordEntity)
+
+ @Query("SELECT * FROM word_table")
+ fun getAll(): LiveData>
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android_25_2/WordDatabase.kt b/app/src/main/java/com/example/android_25_2/WordDatabase.kt
new file mode 100644
index 0000000..52c2185
--- /dev/null
+++ b/app/src/main/java/com/example/android_25_2/WordDatabase.kt
@@ -0,0 +1,28 @@
+package com.example.android_25_2
+
+import android.content.Context
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+
+@Database(entities = [WordEntity::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/android_25_2/WordEntity.kt b/app/src/main/java/com/example/android_25_2/WordEntity.kt
new file mode 100644
index 0000000..413cc1f
--- /dev/null
+++ b/app/src/main/java/com/example/android_25_2/WordEntity.kt
@@ -0,0 +1,12 @@
+package com.example.android_25_2
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity (tableName = "word_table")
+data class WordEntity(
+ @PrimaryKey (autoGenerate = true)
+ val id: Int = 0,
+ val word: String,
+ val meaning: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android_25_2/WordViewModel.kt b/app/src/main/java/com/example/android_25_2/WordViewModel.kt
new file mode 100644
index 0000000..c957f06
--- /dev/null
+++ b/app/src/main/java/com/example/android_25_2/WordViewModel.kt
@@ -0,0 +1,31 @@
+package com.example.android_25_2
+
+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 wordDao: WordDao
+ val allWords: LiveData>
+
+ init {
+ val database = WordDatabase.getDatabase(application)
+ wordDao = database.wordDao()
+ allWords = wordDao.getAll()
+ }
+
+ fun insert(word: WordEntity) = viewModelScope.launch {
+ wordDao.insert(word)
+ }
+
+ fun update(word: WordEntity) = viewModelScope.launch {
+ wordDao.update(word)
+ }
+
+ fun delete(word: WordEntity) = viewModelScope.launch {
+ wordDao.delete(word)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/id_add.xml b/app/src/main/res/drawable/id_add.xml
new file mode 100644
index 0000000..9f83b8f
--- /dev/null
+++ b/app/src/main/res/drawable/id_add.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 9affce0..df630de 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,10 +1,30 @@
-
+ xmlns:tools="http://schemas.android.com/tools">
-
\ No newline at end of file
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_second.xml b/app/src/main/res/layout/activity_second.xml
new file mode 100644
index 0000000..edf745f
--- /dev/null
+++ b/app/src/main/res/layout/activity_second.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item.xml b/app/src/main/res/layout/item.xml
new file mode 100644
index 0000000..2624818
--- /dev/null
+++ b/app/src/main/res/layout/item.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index f8c6127..17b8aeb 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -7,4 +7,8 @@
#FF018786
#FF000000
#FFFFFFFF
+ #FACC00
+ #F99E14
+ #E9ECEF
+ #F5F5F5
\ 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 13379b4..76e4703 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,10 @@
Android_25-2
+ edit
+ delete
+ add word
+ word
+ meaning
+ save
+ Please enter both the word and its meaning
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 8162ca2..3555a03 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,17 +1,25 @@
[versions]
agp = "8.9.1"
-kotlin = "1.9.24"
+kotlin = "2.1.0"
coreKtx = "1.17.0"
junit = "4.13.2"
junitVersion = "1.3.0"
espressoCore = "3.7.0"
appcompat = "1.7.1"
+lifecycleLivedataKtx = "2.10.0"
material = "1.12.0"
activity = "1.11.0"
constraintlayout = "2.2.1"
+roomCommonJvm = "2.8.4"
+roomRuntimeAndroid = "2.8.4"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+androidx-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
+androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleLivedataKtx" }
+androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomCommonJvm" }
+androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomCommonJvm" }
+androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomCommonJvm" }
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" }
@@ -19,6 +27,8 @@ 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-common-jvm = { group = "androidx.room", name = "room-common-jvm", version.ref = "roomCommonJvm" }
+androidx-room-runtime-android = { group = "androidx.room", name = "room-runtime-android", version.ref = "roomRuntimeAndroid" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }