Skip to content

Commit

Permalink
[feature/#92] 프로필 수정 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
kkk5474096 committed Jan 5, 2023
1 parent aa5a06e commit 48bd8a1
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 1 deletion.
8 changes: 7 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,13 @@
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
android:theme="@style/LicenseTheme" />

<activity android:name=".presentation.my.terms.TermsActivity"
<activity
android:name=".presentation.my.terms.TermsActivity"
android:exported="false"
android:screenOrientation="portrait" />

<activity
android:name=".presentation.my.update.ProfileUpdateActivity"
android:exported="false"
android:screenOrientation="portrait" />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package com.teamfillin.fillin.presentation.my.update

import android.content.Intent
import android.graphics.Color
import android.graphics.ImageDecoder
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.teamfillin.fillin.R
import com.teamfillin.fillin.core.base.BindingActivity
import com.teamfillin.fillin.core.context.colorOf
import com.teamfillin.fillin.core.context.toast
import com.teamfillin.fillin.core.view.UiState
import com.teamfillin.fillin.databinding.ActivityProfileUpdateBinding
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import java.io.IOException

@AndroidEntryPoint
class ProfileUpdateActivity :
BindingActivity<ActivityProfileUpdateBinding>(R.layout.activity_profile_update) {
private val viewModel by viewModels<ProfileUpdateViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding.viewModel = viewModel
initView()
initEvent()
observe()
}

private fun initView() {
binding.etNickname.doAfterTextChanged {
editTextNameBlankCheck()
}

binding.etCamera.doAfterTextChanged {
editTextCameraBlankCheck()
}
}

private fun initEvent() {
binding.ivNicknameClear.setOnClickListener {
viewModel.nickname.value = ""
}

binding.ivCameraClear.setOnClickListener {
viewModel.cameraName.value = ""
}

binding.ivProfile.setOnClickListener {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
filterActivityLauncher.launch(intent)
}

binding.btnAddPhoto.setOnClickListener {
toast("asdf")
viewModel.putUser()
}
}

private fun observe() {
viewModel.isClickable.flowWithLifecycle(lifecycle)
.onEach {
with(binding.btnAddPhoto) {
isClickable = it
setBackgroundColor(
if (it) colorOf(R.color.fillin_red) else Color.parseColor("#474645")
)
setTextColor(
if (it) colorOf(R.color.fillin_black) else Color.parseColor("#6F6F6F")
)
}
}.launchIn(lifecycleScope)

viewModel.updateUser.flowWithLifecycle(lifecycle)
.onEach {
when (it) {
is UiState.Success -> {
toast("프로필 수정이 완료되었습니다.")
finish()
}
is UiState.Failure -> {
toast(it.msg)
}
else -> {}
}
}
}

private fun editTextNameBlankCheck() {
binding.ivNicknameClear.isVisible = !binding.etNickname.text.isNullOrEmpty()
}

private fun editTextCameraBlankCheck() {
binding.ivCameraClear.isVisible = !binding.etCamera.text.isNullOrEmpty()
}

private val filterActivityLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK && it.data != null) {
val imageUri = it.data?.data
try {
imageUri?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
viewModel.setImageBitmap(ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, imageUri)))
} else {
viewModel.setImageBitmap(MediaStore.Images.Media.getBitmap(contentResolver, imageUri))
}
}
} catch (e: IOException) {
e.printStackTrace()
}

Glide.with(this).load(imageUri).circleCrop().into(binding.ivProfile)
} else if (it.resultCode == RESULT_CANCELED) {
toast("사진 선택 취소")
} else {
Log.d("ActivityResult", "something wrong")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.teamfillin.fillin.presentation.my.update

import android.graphics.Bitmap
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.teamfillin.fillin.core.view.UiState
import com.teamfillin.fillin.data.response.ResponseUpdateUser
import com.teamfillin.fillin.data.service.AuthService
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okio.BufferedSink
import javax.inject.Inject

@HiltViewModel
class ProfileUpdateViewModel @Inject constructor(
private val service: AuthService
): ViewModel() {
val nickname = MutableStateFlow("")
val isClickable: Flow<Boolean> = nickname.map { it.isNotBlank() }

val cameraName = MutableStateFlow("")

private val _updateUser = MutableStateFlow<UiState<ResponseUpdateUser>>(UiState.Loading)
val updateUser: StateFlow<UiState<ResponseUpdateUser>> = _updateUser

private var imageBitmap: Bitmap? = null

fun setImageBitmap(bitmap: Bitmap) {
imageBitmap = bitmap
}

fun putUser() {
val textHashMap = hashMapOf<String, RequestBody>()
textHashMap["nickname"] = nickname.value.toRequestBody("text/plain".toMediaTypeOrNull())
textHashMap["camera"] = cameraName.value.toRequestBody("text/plain".toMediaTypeOrNull())
val bitmapRequestBody = imageBitmap?.let { BitmapRequestBody(it) }
val bitmapMultipartBody = bitmapRequestBody?.let { MultipartBody.Part.createFormData("imageUrl", "imageUrl", it) }

viewModelScope.launch {
runCatching {
service.putUser(bitmapMultipartBody, textHashMap)
}.onSuccess {
_updateUser.value = UiState.Success(it.data)
}.onFailure {
_updateUser.value = UiState.Failure("서버 통신 오류 : $it")
}
}
}

companion object {
class BitmapRequestBody(private val bitmap: Bitmap) : RequestBody() {
override fun contentType(): MediaType? {
return "image/png".toMediaTypeOrNull()
}

override fun writeTo(sink: BufferedSink) {
bitmap.compress(Bitmap.CompressFormat.PNG, 99, sink.outputStream()) //99프로 압축
}
}
}
}

0 comments on commit 48bd8a1

Please sign in to comment.