-
Notifications
You must be signed in to change notification settings - Fork 1
[김예란_Android] 8주차 과제 제출 #8
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.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package data | ||
|
|
||
| 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>> | ||
|
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.
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package data | ||
|
|
||
| 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,13 @@ | ||
| package data | ||
|
|
||
| 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, | ||
| val imagePath: String | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| package presentation | ||
|
|
||
| import android.content.Intent | ||
| import android.os.Bundle | ||
| import android.view.View | ||
| 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 coil.load | ||
| import com.example.android_25_2.R | ||
| import com.example.android_25_2.databinding.ActivityMainBinding | ||
| import data.WordEntity | ||
|
|
||
| class MainActivity : AppCompatActivity() { | ||
|
|
||
| private lateinit var activityBinding: ActivityMainBinding | ||
| private lateinit var wordViewModel: WordViewModel | ||
| private lateinit var adapter: WordAdapter | ||
| companion object { | ||
| const val EXTRA_WORD_ID = "WORD_ID" | ||
| const val EXTRA_WORD = "WORD" | ||
| const val EXTRA_MEANING = "MEANING" | ||
| const val EXTRA_IMAGE_PATH = "IMAGE_PATH" | ||
| } | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| enableEdgeToEdge() | ||
| 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) { | ||
| showSelectedWord(word) | ||
| } | ||
|
|
||
| override fun onEditButtonClick(word: WordEntity) { | ||
| val intent = Intent(this@MainActivity, SecondActivity::class.java) | ||
| intent.putExtra(EXTRA_WORD_ID, word.id) | ||
| intent.putExtra(EXTRA_WORD, word.word) | ||
| intent.putExtra(EXTRA_MEANING, word.meaning) | ||
| intent.putExtra(EXTRA_IMAGE_PATH, word.imagePath) | ||
| startActivity(intent) | ||
|
Comment on lines
+60
to
+64
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. Bundle을 사용하지 않은 이유가 있을까요? |
||
| } | ||
|
|
||
| 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) | ||
| } | ||
| } | ||
| private fun showSelectedWord(word: WordEntity) { | ||
| activityBinding.textViewSelectedWord.visibility = View.VISIBLE | ||
| activityBinding.textViewSelectedMeaning.visibility = View.VISIBLE | ||
|
|
||
| activityBinding.textViewSelectedWord.text = word.word | ||
| activityBinding.textViewSelectedMeaning.text = word.meaning | ||
|
|
||
| word.imagePath.let { | ||
| activityBinding.imageViewSelected.load(it) | ||
| activityBinding.imageViewSelected.visibility = View.VISIBLE | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| package presentation | ||
|
|
||
| import android.content.Intent | ||
| import android.content.pm.PackageManager | ||
| import android.net.Uri | ||
| import android.os.Build | ||
| import android.os.Bundle | ||
| import android.provider.Settings | ||
| import android.widget.Toast | ||
| import androidx.activity.result.ActivityResultLauncher | ||
| import androidx.activity.result.contract.ActivityResultContracts | ||
| import androidx.appcompat.app.AppCompatActivity | ||
| import androidx.core.app.ActivityCompat | ||
| import androidx.core.content.ContextCompat | ||
| import androidx.databinding.DataBindingUtil | ||
| import androidx.lifecycle.ViewModelProvider | ||
| import coil.load | ||
| import com.example.android_25_2.databinding.ActivitySecondBinding | ||
| import androidx.core.net.toUri | ||
| import android.Manifest | ||
| import com.example.android_25_2.R | ||
| import data.WordEntity | ||
|
|
||
| class SecondActivity : AppCompatActivity() { | ||
|
|
||
| private lateinit var activityBinding: ActivitySecondBinding | ||
| private lateinit var wordViewModel: WordViewModel | ||
| private var wordId: Int? = null | ||
| private var selectedImageUri: Uri? = null | ||
| lateinit var pickImage: ActivityResultLauncher<String> | ||
|
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. private 처리해주세요 |
||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| activityBinding = DataBindingUtil.setContentView(this, R.layout.activity_second) | ||
|
|
||
| pickImage = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> | ||
| uri?.let { | ||
| selectedImageUri = it | ||
| activityBinding.imageViewPreview.load(it) | ||
| } | ||
| } | ||
|
|
||
| wordViewModel = ViewModelProvider(this)[WordViewModel::class.java] | ||
|
|
||
| wordId = intent.getIntExtra(MainActivity.EXTRA_WORD_ID, -1) | ||
| val existingWord = intent.getStringExtra(MainActivity.EXTRA_WORD) | ||
| val existingMeaning = intent.getStringExtra(MainActivity.EXTRA_MEANING) | ||
| val existingImagePath = intent.getStringExtra(MainActivity.EXTRA_IMAGE_PATH) | ||
|
|
||
| if (wordId != null) { | ||
| activityBinding.editTextWord.setText(existingWord) | ||
| activityBinding.editTextMeaning.setText(existingMeaning) | ||
| existingImagePath?.let { | ||
| activityBinding.imageViewPreview.load(it) | ||
| } | ||
| } | ||
|
|
||
| activityBinding.buttonSelectImage.setOnClickListener { | ||
| permissionCheck() | ||
| } | ||
|
|
||
| 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 | ||
| } | ||
|
|
||
| val imagePath: String = when { | ||
| selectedImageUri != null -> selectedImageUri.toString() | ||
| existingImagePath != null -> existingImagePath | ||
| else -> "" | ||
| } | ||
|
|
||
| if (wordId != null && wordId != -1) { | ||
| val wordEntity = WordEntity( | ||
| id = wordId!!, | ||
|
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.
|
||
| word = word, | ||
| meaning = meaning, | ||
| imagePath = imagePath | ||
| ) | ||
| wordViewModel.update(wordEntity) | ||
| } else { | ||
| val wordEntity = WordEntity( | ||
| word = word, | ||
| meaning = meaning, | ||
| imagePath = imagePath | ||
| ) | ||
| wordViewModel.insert(wordEntity) | ||
| } | ||
| finish() | ||
| } | ||
| } | ||
| private fun permissionCheck() { | ||
| val mediaPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | ||
| Manifest.permission.READ_MEDIA_IMAGES | ||
| } else { | ||
| Manifest.permission.READ_EXTERNAL_STORAGE | ||
| } | ||
|
|
||
| if (ContextCompat.checkSelfPermission(this, mediaPermission) | ||
| != PackageManager.PERMISSION_GRANTED) { | ||
| ActivityCompat.requestPermissions( | ||
| this, arrayOf(mediaPermission), 1000 | ||
| ) | ||
|
|
||
| if (!ActivityCompat.shouldShowRequestPermissionRationale(this, mediaPermission)) { | ||
| val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) | ||
| .setData("package:${packageName}".toUri()) | ||
| startActivity(intent) | ||
| } | ||
| } else { | ||
| pickImage.launch("image/*") | ||
| } | ||
| } | ||
|
|
||
| override fun onRequestPermissionsResult( | ||
| requestCode: Int, | ||
| permissions: Array<out String>, | ||
| grantResults: IntArray | ||
| ) { | ||
| super.onRequestPermissionsResult(requestCode, permissions, grantResults) | ||
| if (requestCode == 1000) { | ||
| if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||
| pickImage.launch("image/*") | ||
| } | ||
| } | ||
| } | ||
| } | ||
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.
여기서 질문! viewBinding과 dataBinding은 무슨 차이일까요?