Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("kotlin-kapt")
}

android {
Expand All @@ -17,6 +18,11 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildFeatures {
viewBinding = true
dataBinding = true
}

buildTypes {
release {
isMinifyEnabled = false
Expand All @@ -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)
}
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:exported="false" />
</application>

</manifest>
52 changes: 51 additions & 1 deletion app/src/main/java/com/example/android_25_2/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오... 단어 클릭 시 단어 리스트에서 최상단으로 가는 게 아닌
해당 단어를 최상단에 존재하는 선택된 단어 표시 view 에 보여달라는 의미 입니다.

activityBinding.recyclerView.scrollToPosition(0)
}

override fun onEditButtonClick(word: WordEntity) {
val intent = Intent(this@MainActivity, SecondActivity::class.java)
intent.putExtra("WORD_ID", word.id)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key <=> constant

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)
}
}
}
57 changes: 57 additions & 0 deletions app/src/main/java/com/example/android_25_2/SecondActivity.kt
Original file line number Diff line number Diff line change
@@ -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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 이 곧 없음인데 굳이 null 로 한번 더 바꿀 필요는 없다고 생각합니다.

wordId = null
}
val existingWord = intent.getStringExtra("WORD")
val existingMeaning = intent.getStringExtra("MEANING")

if (wordId != null) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wordId?.let {} 의 방법도 있습니다.

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()
}
}
}
73 changes: 73 additions & 0 deletions app/src/main/java/com/example/android_25_2/WordAdapter.kt
Original file line number Diff line number Diff line change
@@ -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<WordAdapter.WordViewHolder>(){

private var words = emptyList<WordEntity>()

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<WordEntity>) {
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)
}
}
23 changes: 23 additions & 0 deletions app/src/main/java/com/example/android_25_2/WordDao.kt
Original file line number Diff line number Diff line change
@@ -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<List<WordEntity>>
}
28 changes: 28 additions & 0 deletions app/src/main/java/com/example/android_25_2/WordDatabase.kt
Original file line number Diff line number Diff line change
@@ -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
}
}
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/com/example/android_25_2/WordEntity.kt
Original file line number Diff line number Diff line change
@@ -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
)
31 changes: 31 additions & 0 deletions app/src/main/java/com/example/android_25_2/WordViewModel.kt
Original file line number Diff line number Diff line change
@@ -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<List<WordEntity>>

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)
}
}
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/id_add.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">

<path android:fillColor="@android:color/white" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>

</vector>
Loading