Skip to content

Commit 16dad12

Browse files
committed
✨ 닉네임 수정 기능 구현
1 parent a68d9c6 commit 16dad12

File tree

8 files changed

+117
-40
lines changed

8 files changed

+117
-40
lines changed

data/src/main/java/com/whyranoid/data/account/AccountDataSource.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ import kotlinx.coroutines.flow.Flow
55
interface AccountDataSource {
66
fun getUserNickName(): Flow<String>
77
fun getUserProfileImgUri(): Flow<String>
8+
suspend fun updateUserNickName(newNickName: String): Result<String>
89
}

data/src/main/java/com/whyranoid/data/account/AccountDataSourceImpl.kt

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,77 @@ package com.whyranoid.data.account
22

33
import androidx.datastore.core.DataStore
44
import androidx.datastore.preferences.core.Preferences
5+
import androidx.datastore.preferences.core.edit
56
import androidx.datastore.preferences.core.stringPreferencesKey
7+
import com.google.firebase.firestore.FirebaseFirestore
68
import com.whyranoid.data.account.AccountDataSourceImpl.PreferenceKeys.nickName
79
import com.whyranoid.data.account.AccountDataSourceImpl.PreferenceKeys.profileImgUri
10+
import com.whyranoid.data.account.AccountDataSourceImpl.PreferenceKeys.uid
11+
import kotlinx.coroutines.CoroutineScope
12+
import kotlinx.coroutines.Dispatchers
13+
import kotlinx.coroutines.flow.launchIn
814
import kotlinx.coroutines.flow.map
15+
import kotlinx.coroutines.flow.onEach
916
import javax.inject.Inject
1017

1118
class AccountDataSourceImpl @Inject constructor(
12-
private val dataStoreDb: DataStore<Preferences>
19+
private val dataStoreDb: DataStore<Preferences>,
20+
private val fireBaseDb: FirebaseFirestore
1321
) : AccountDataSource {
22+
23+
init {
24+
getUid()
25+
}
26+
27+
private var userUid = EMPTY_STRING
28+
1429
private object PreferenceKeys {
1530
val uid = stringPreferencesKey(UID_KEY)
1631
val email = stringPreferencesKey(EMAIL_KEY)
1732
val nickName = stringPreferencesKey(NICK_NAME_KEY)
1833
val profileImgUri = stringPreferencesKey(PROFILE_IMG_URI)
1934
}
2035

36+
// TODO : flow -> suspend로 변경해야 함.
2137
override fun getUserNickName() = dataStoreDb.data
2238
.map { preferences ->
2339
preferences[nickName] ?: EMPTY_STRING
2440
}
2541

42+
// TODO : flow -> suspend로 변경해야 함.
2643
override fun getUserProfileImgUri() = dataStoreDb.data
2744
.map { preferences ->
2845
preferences[profileImgUri] ?: EMPTY_STRING
2946
}
3047

48+
// TODO : flow -> suspend로 변경해야 함.
49+
private fun getUid() = dataStoreDb.data
50+
.map { preferences ->
51+
preferences[uid]
52+
}.onEach {
53+
userUid = it ?: EMPTY_STRING
54+
}.launchIn(CoroutineScope(Dispatchers.IO))
55+
56+
override suspend fun updateUserNickName(newNickName: String) = runCatching {
57+
// 로컬에 업데이트
58+
dataStoreDb.edit { preferences ->
59+
preferences[nickName] = newNickName
60+
}
61+
62+
// 리모트에 업데이트
63+
fireBaseDb.collection(USER_COLLECTION_PATH)
64+
.document(userUid).update(USER_FIELD_NICK_NAME, newNickName)
65+
66+
newNickName
67+
}
68+
3169
companion object {
3270
private const val UID_KEY = "uid"
3371
private const val EMAIL_KEY = "email"
3472
private const val NICK_NAME_KEY = "nick_name"
3573
private const val PROFILE_IMG_URI = "profile_img_uri"
3674
private const val EMPTY_STRING = ""
75+
private const val USER_COLLECTION_PATH = "Users"
76+
private const val USER_FIELD_NICK_NAME = "name"
3777
}
3878
}

data/src/main/java/com/whyranoid/data/account/AccountRepositoryImpl.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ class AccountRepositoryImpl @Inject constructor(
2525
return accountDataSource.getUserNickName()
2626
}
2727

28-
override suspend fun updateNickname(newNickname: String): Boolean {
29-
return true
28+
override suspend fun updateNickname(newNickName: String): Result<String> {
29+
return accountDataSource.updateUserNickName(newNickName)
3030
}
3131

3232
override suspend fun getProfileUri(): Flow<String> {

domain/src/main/java/com/whyranoid/domain/repository/AccountRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ interface AccountRepository {
1919

2020
// 닉네임 수정, 서버에 먼저 보내고 성공하면 로컬에 반영
2121
// 실패하면 실패 사용자에게 알리기
22-
suspend fun updateNickname(newNickname: String): Boolean
22+
suspend fun updateNickname(newNickName: String): Result<String>
2323

2424
// 데이터스토어에서 프로필 이미지 가져오기
2525
suspend fun getProfileUri(): Flow<String>

domain/src/main/java/com/whyranoid/domain/usecase/UpdateNicknameUseCase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.whyranoid.domain.repository.AccountRepository
44
import javax.inject.Inject
55

66
class UpdateNicknameUseCase @Inject constructor(private val accountRepository: AccountRepository) {
7-
suspend operator fun invoke(newNickname: String): Boolean {
7+
suspend operator fun invoke(newNickname: String): Result<String> {
88
return accountRepository.updateNickname(newNickname)
99
}
1010
}

presentation/src/main/java/com/whyranoid/presentation/myrun/MyRunFragment.kt

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package com.whyranoid.presentation.myrun
22

33
import android.os.Bundle
4+
import android.view.LayoutInflater
45
import android.view.View
6+
import android.view.ViewGroup
57
import androidx.appcompat.app.AlertDialog
8+
import androidx.databinding.DataBindingUtil
69
import androidx.fragment.app.viewModels
710
import com.whyranoid.presentation.R
811
import com.whyranoid.presentation.base.BaseFragment
12+
import com.whyranoid.presentation.databinding.DialogEditNickNameBinding
913
import com.whyranoid.presentation.databinding.FragmentMyRunBinding
1014
import com.whyranoid.presentation.util.loadImage
1115
import dagger.hilt.android.AndroidEntryPoint
@@ -14,6 +18,17 @@ import dagger.hilt.android.AndroidEntryPoint
1418
internal class MyRunFragment : BaseFragment<FragmentMyRunBinding>(R.layout.fragment_my_run) {
1519

1620
private val viewModel by viewModels<MyRunViewModel>()
21+
private lateinit var dialogViewBinding: DialogEditNickNameBinding
22+
23+
override fun onCreateView(
24+
inflater: LayoutInflater,
25+
container: ViewGroup?,
26+
savedInstanceState: Bundle?
27+
): View? {
28+
dialogViewBinding =
29+
DataBindingUtil.inflate(inflater, R.layout.dialog_edit_nick_name, container, false)
30+
return super.onCreateView(inflater, container, savedInstanceState)
31+
}
1732

1833
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
1934
super.onViewCreated(view, savedInstanceState)
@@ -41,18 +56,21 @@ internal class MyRunFragment : BaseFragment<FragmentMyRunBinding>(R.layout.fragm
4156
}
4257

4358
private fun popUpEditNickNameDialog() {
44-
val builder = AlertDialog.Builder(requireActivity())
45-
.setView(R.layout.dialog_edit_nick_name)
59+
val newNickName = dialogViewBinding.etChangeNickName
60+
61+
val builder = AlertDialog.Builder(requireContext())
62+
.setView(dialogViewBinding.root)
4663
.setPositiveButton(
4764
getString(R.string.my_run_edit_nick_name_dialog_positive)
48-
) { dialog, id ->
49-
// 닉네임 변경 로직
65+
) { _, _ ->
66+
viewModel.updateNickName(newNickName.text.toString())
5067
}
5168
.setNegativeButton(
5269
getString(R.string.my_run_edit_nick_name_dialog_negative)
5370
) { dialog, _ ->
5471
dialog.dismiss()
5572
}
73+
5674
builder.show()
5775
}
5876
}

presentation/src/main/java/com/whyranoid/presentation/myrun/MyRunViewModel.kt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ import androidx.lifecycle.ViewModel
66
import androidx.lifecycle.viewModelScope
77
import com.whyranoid.domain.usecase.GetNicknameUseCase
88
import com.whyranoid.domain.usecase.GetProfileUriUseCase
9+
import com.whyranoid.domain.usecase.UpdateNicknameUseCase
910
import dagger.hilt.android.lifecycle.HiltViewModel
1011
import kotlinx.coroutines.launch
11-
import timber.log.Timber
1212
import javax.inject.Inject
1313

1414
@HiltViewModel
1515
class MyRunViewModel @Inject constructor(
1616
private val getNicknameUseCase: GetNicknameUseCase,
17-
private val getProfileUriUseCase: GetProfileUriUseCase
17+
private val getProfileUriUseCase: GetProfileUriUseCase,
18+
private val updateNickNameUseCase: UpdateNicknameUseCase
1819
) : ViewModel() {
20+
1921
private val _nickName = MutableLiveData<String>()
2022
val nickName: LiveData<String>
2123
get() = _nickName
@@ -27,7 +29,6 @@ class MyRunViewModel @Inject constructor(
2729
fun getNickName() {
2830
viewModelScope.launch {
2931
getNicknameUseCase().collect {
30-
Timber.d("유저 닉네임 불러오기 $it")
3132
_nickName.value = it
3233
}
3334
}
@@ -40,4 +41,14 @@ class MyRunViewModel @Inject constructor(
4041
}
4142
}
4243
}
44+
45+
fun updateNickName(newNickName: String) {
46+
viewModelScope.launch {
47+
updateNickNameUseCase(newNickName).onSuccess {
48+
_nickName.value = it
49+
}.onFailure {
50+
// TODO 닉네임 변경 실패시
51+
}
52+
}
53+
}
4354
}
Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3-
xmlns:app="http://schemas.android.com/apk/res-auto"
4-
android:layout_width="match_parent"
5-
android:layout_height="wrap_content">
2+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto">
64

7-
<TextView
8-
android:id="@+id/tv_dialog_description"
9-
android:layout_width="wrap_content"
10-
android:layout_height="wrap_content"
11-
android:layout_marginTop="20dp"
12-
android:text="@string/my_run_edit_nick_name_dialog_description"
13-
app:layout_constraintEnd_toEndOf="parent"
14-
app:layout_constraintStart_toStartOf="parent"
15-
app:layout_constraintTop_toTopOf="parent" />
5+
<data>
166

17-
<EditText
18-
android:id="@+id/et_change_nick_name"
19-
android:layout_width="0dp"
20-
android:layout_height="wrap_content"
21-
android:layout_marginHorizontal="20dp"
22-
android:layout_marginTop="20dp"
23-
android:autofillHints="name"
24-
android:hint="@string/my_run_edit_nick_name_dialog_hint"
25-
android:inputType="textPersonName"
26-
android:maxLength="20"
27-
android:maxLines="1"
28-
app:layout_constraintEnd_toEndOf="parent"
29-
app:layout_constraintStart_toStartOf="parent"
30-
app:layout_constraintTop_toBottomOf="@id/tv_dialog_description" />
7+
</data>
318

32-
</androidx.constraintlayout.widget.ConstraintLayout>
9+
<androidx.constraintlayout.widget.ConstraintLayout
10+
android:layout_width="match_parent"
11+
android:layout_height="wrap_content">
12+
13+
<TextView
14+
android:id="@+id/tv_dialog_description"
15+
android:layout_width="wrap_content"
16+
android:layout_height="wrap_content"
17+
android:layout_marginTop="20dp"
18+
android:text="@string/my_run_edit_nick_name_dialog_description"
19+
app:layout_constraintEnd_toEndOf="parent"
20+
app:layout_constraintStart_toStartOf="parent"
21+
app:layout_constraintTop_toTopOf="parent" />
22+
23+
<EditText
24+
android:id="@+id/et_change_nick_name"
25+
android:layout_width="0dp"
26+
android:layout_height="wrap_content"
27+
android:layout_marginHorizontal="20dp"
28+
android:layout_marginTop="20dp"
29+
android:autofillHints="name"
30+
android:hint="@string/my_run_edit_nick_name_dialog_hint"
31+
android:inputType="textPersonName"
32+
android:maxLength="20"
33+
android:maxLines="1"
34+
app:layout_constraintEnd_toEndOf="parent"
35+
app:layout_constraintStart_toStartOf="parent"
36+
app:layout_constraintTop_toBottomOf="@id/tv_dialog_description" />
37+
38+
</androidx.constraintlayout.widget.ConstraintLayout>
39+
</layout>

0 commit comments

Comments
 (0)