diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a2c7d4b..f4af81b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -95,7 +95,13 @@
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
android:theme="@style/LicenseTheme" />
-
+
+
diff --git a/app/src/main/java/com/teamfillin/fillin/data/response/ResponseUpdateUser.kt b/app/src/main/java/com/teamfillin/fillin/data/response/ResponseUpdateUser.kt
new file mode 100644
index 0000000..0a5201f
--- /dev/null
+++ b/app/src/main/java/com/teamfillin/fillin/data/response/ResponseUpdateUser.kt
@@ -0,0 +1,20 @@
+package com.teamfillin.fillin.data.response
+
+data class ResponseUpdateUser(
+ val updateUser: UpdateUserDto
+) {
+ data class UpdateUserDto(
+ val id: Int,
+ val social: String,
+ val nickname: String,
+ val imageUrl: String,
+ val refreshToken: String,
+ val isDeleted: Boolean,
+ val updatedAt: String,
+ val email: String,
+ val createdAt: String,
+ val idKey: String,
+ val camera: List
+ )
+}
+
diff --git a/app/src/main/java/com/teamfillin/fillin/data/service/AuthService.kt b/app/src/main/java/com/teamfillin/fillin/data/service/AuthService.kt
index 72a9f29..dcfab98 100644
--- a/app/src/main/java/com/teamfillin/fillin/data/service/AuthService.kt
+++ b/app/src/main/java/com/teamfillin/fillin/data/service/AuthService.kt
@@ -4,6 +4,9 @@ import com.teamfillin.fillin.core.converter.JsonConverter
import com.teamfillin.fillin.data.response.BaseResponse
import com.teamfillin.fillin.data.response.ResponseAuth
import com.teamfillin.fillin.data.response.ResponseRefresh
+import com.teamfillin.fillin.data.response.ResponseUpdateUser
+import okhttp3.MultipartBody
+import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.http.*
@@ -22,4 +25,11 @@ interface AuthService {
@Header("accesstoken") accessToken: String,
@Header("refreshtoken") refreshToken: String
): Call>
+
+ @Multipart
+ @PUT("user/edit")
+ suspend fun putUser(
+ @Part media: MultipartBody.Part?,
+ @PartMap body: HashMap
+ ): BaseResponse
}
\ No newline at end of file
diff --git a/app/src/main/java/com/teamfillin/fillin/presentation/my/MyPageActivity.kt b/app/src/main/java/com/teamfillin/fillin/presentation/my/MyPageActivity.kt
index 7d63c9e..30dfb75 100644
--- a/app/src/main/java/com/teamfillin/fillin/presentation/my/MyPageActivity.kt
+++ b/app/src/main/java/com/teamfillin/fillin/presentation/my/MyPageActivity.kt
@@ -24,6 +24,7 @@ import com.teamfillin.fillin.databinding.ActivityMyPageBinding
import com.teamfillin.fillin.presentation.dialog.PhotoDialogFragment
import com.teamfillin.fillin.presentation.map.SpaceDecoration
import com.teamfillin.fillin.presentation.my.terms.TermsActivity
+import com.teamfillin.fillin.presentation.my.update.ProfileUpdateActivity
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -69,6 +70,12 @@ class MyPageActivity : BindingActivity(R.layout.activity_
finish()
}
+ binding.ivEdit.setOnSingleClickListener {
+ Intent(this, ProfileUpdateActivity::class.java).apply {
+ startActivity(this)
+ }
+ }
+
binding.ivUp.setOnSingleClickListener {
binding.rvMyPage.isVisible = !binding.rvMyPage.isVisible
imageRotation(binding.ivUp, binding.rvMyPage.isVisible)
diff --git a/app/src/main/java/com/teamfillin/fillin/presentation/my/update/ProfileUpdateActivity.kt b/app/src/main/java/com/teamfillin/fillin/presentation/my/update/ProfileUpdateActivity.kt
new file mode 100644
index 0000000..78cd05a
--- /dev/null
+++ b/app/src/main/java/com/teamfillin/fillin/presentation/my/update/ProfileUpdateActivity.kt
@@ -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(R.layout.activity_profile_update) {
+ private val viewModel by viewModels()
+ 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 =
+ 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")
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/teamfillin/fillin/presentation/my/update/ProfileUpdateViewModel.kt b/app/src/main/java/com/teamfillin/fillin/presentation/my/update/ProfileUpdateViewModel.kt
new file mode 100644
index 0000000..189d2af
--- /dev/null
+++ b/app/src/main/java/com/teamfillin/fillin/presentation/my/update/ProfileUpdateViewModel.kt
@@ -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 = nickname.map { it.isNotBlank() }
+
+ val cameraName = MutableStateFlow("")
+
+ private val _updateUser = MutableStateFlow>(UiState.Loading)
+ val updateUser: StateFlow> = _updateUser
+
+ private var imageBitmap: Bitmap? = null
+
+ fun setImageBitmap(bitmap: Bitmap) {
+ imageBitmap = bitmap
+ }
+
+ fun putUser() {
+ val textHashMap = hashMapOf()
+ 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프로 압축
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_clear.xml b/app/src/main/res/drawable/ic_clear.xml
new file mode 100644
index 0000000..056196c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_clear.xml
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_profile_update.xml b/app/src/main/res/layout/activity_profile_update.xml
new file mode 100644
index 0000000..21c734d
--- /dev/null
+++ b/app/src/main/res/layout/activity_profile_update.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3706bc3..b105d56 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,7 +1,13 @@
FILL-IN
찰칵찰칵 필린이
+ 닉네임
+ 닉네임을 입력해주세요. (10자 이하)
+ 프로필 사진 바꾸기
+ 프로필 변경
Fuji film X 1200
+ 카메라
+ 사용중 카메라 이름을 입력해주세요.
사용중인 카메라를 입력해주세요.
좋아요
내 현상소