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
11 changes: 11 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ android {
namespace = "com.alom.androidstudy1"
compileSdk = 34

buildFeatures {
viewBinding = true
}

defaultConfig {
applicationId = "com.alom.androidstudy1"
minSdk = 26
Expand Down Expand Up @@ -42,4 +46,11 @@ dependencies {
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

implementation(libs.lifecycle.viewmodel.ktx)
implementation(libs.lifecycle.livedata.ktx)
implementation(libs.lifecycle.runtime.ktx)

testImplementation(libs.spring.boot.starter.test)
testImplementation(libs.mockk)
}
50 changes: 41 additions & 9 deletions app/src/main/java/com/alom/androidstudy1/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,52 @@
package com.alom.androidstudy1

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.alom.androidstudy1.databinding.ActivityMainBinding
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
private lateinit var binding:ActivityMainBinding
private lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
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
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

val sharedPreference = getSharedPreferences("alom", MODE_PRIVATE)

// viewModel의 인자값으로 repository를 넘겨 줌
val repository = RepositoryImpl(sharedPreference)
val factory = ViewModelFactory(repository)

mainViewModel = ViewModelProvider(this, factory).get(MainViewModel::class.java)

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
mainViewModel.currentMemo.collect{ memo ->
binding.etMemo.setText(memo)
Log.d("MainActivity", "output memo: $memo")
}
}
}
}

binding.btnSave.setOnClickListener {
val newMemo = binding.etMemo.text.toString().trim()
if(newMemo.isEmpty()){
Toast.makeText(this, "저장할 메모를 입력해 주세요", Toast.LENGTH_SHORT).show()
}
else {
mainViewModel.updateValue(newMemo)
Toast.makeText(this, "저장됨", Toast.LENGTH_SHORT).show()
}
}
}
}
39 changes: 39 additions & 0 deletions app/src/main/java/com/alom/androidstudy1/MainViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.alom.androidstudy1

import android.annotation.SuppressLint
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class MainViewModel(private val repository: Repository): ViewModel() {
private var _currentMemo = MutableStateFlow("")

val currentMemo: StateFlow<String>
get() = _currentMemo.asStateFlow()

init {

viewModelScope.launch {
val memo = withContext(Dispatchers.IO) {
repository.getMemo()
}
_currentMemo.emit(memo)
}
}


@SuppressLint("CommitPrefEdits")
fun updateValue(input: String) {
viewModelScope.launch {
_currentMemo.emit(input)
withContext(Dispatchers.IO) {
repository.setMemo(input)
}
}
}
}
9 changes: 9 additions & 0 deletions app/src/main/java/com/alom/androidstudy1/Repository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.alom.androidstudy1

import android.content.SharedPreferences
import kotlinx.coroutines.flow.MutableStateFlow

interface Repository {
suspend fun getMemo(): String
suspend fun setMemo(input: String)
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/alom/androidstudy1/RepositoryImpl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.alom.androidstudy1

import android.content.SharedPreferences
import kotlinx.coroutines.flow.MutableStateFlow

class RepositoryImpl(private val sharedPreference: SharedPreferences): Repository {
override suspend fun getMemo(): String {
return sharedPreference.getString("memo", "").toString()
}

override suspend fun setMemo(input: String) {
sharedPreference.edit().putString("memo", input).apply()
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/alom/androidstudy1/ViewModelFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.alom.androidstudy1

import android.content.SharedPreferences
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class ViewModelFactory(private val repository: Repository): ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
return MainViewModel(repository) as T
}
throw IllegalArgumentException("ViewModel class not found")
}
}
38 changes: 35 additions & 3 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,44 @@
tools:context=".MainActivity">

<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="메모장"
android:gravity="center"
android:layout_marginTop="10dp"
/>

<EditText
android:id="@+id/et_memo"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/btn_save"
android:gravity="start|center_vertical"
android:background="#D8D8D8"
android:layout_margin="10dp"
android:text="edit text save"
android:padding="5dp"
/>

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/et_memo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginBottom="10dp"
android:text="저장"
android:textColor="@color/white"
android:background="#9281CD"
/>

</androidx.constraintlayout.widget.ConstraintLayout>
10 changes: 10 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ appcompat = "1.7.0"
material = "1.12.0"
activity = "1.9.2"
constraintlayout = "2.1.4"
lifecycleVersion = "2.8.4"
mockk = "1.12.5"


[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
Expand All @@ -20,6 +23,13 @@ material = { group = "com.google.android.material", name = "material", version.r
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }

lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleVersion"}
lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleVersion"}
lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleVersion"}

mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
Expand Down