-
Notifications
You must be signed in to change notification settings - Fork 1
[김예란_Android] 7주차 과제 제출 #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| 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) | ||
| activityBinding.recyclerView.scrollToPosition(0) | ||
| } | ||
|
|
||
| override fun onEditButtonClick(word: WordEntity) { | ||
| val intent = Intent(this@MainActivity, SecondActivity::class.java) | ||
| intent.putExtra("WORD_ID", word.id) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
| } | ||
| } | ||
| } | ||
| 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) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
| } | ||
| } | ||
| } | ||
| 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) | ||
| } | ||
| } |
| 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>> | ||
| } |
| 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 | ||
| } | ||
| } | ||
| } | ||
| } |
| 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 | ||
| ) |
| 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) | ||
| } | ||
| } |
| 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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오... 단어 클릭 시 단어 리스트에서 최상단으로 가는 게 아닌
해당 단어를 최상단에 존재하는 선택된 단어 표시 view 에 보여달라는 의미 입니다.