diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 3bcb6b3b..879b3596 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -9,12 +9,6 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 17e911dc..afee0081 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,3 +1,4 @@
+
-
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5f4bd501..0dbebbaa 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -10,8 +10,8 @@ plugins {
}
android {
- compileSdk = Constants.compileSdk
+ compileSdk = Constants.compileSdk
defaultConfig {
applicationId = Constants.packageName
minSdk = Constants.minSdk
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0394a578..d0f625eb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,9 +5,7 @@
-
+
@@ -24,9 +22,12 @@
android:theme="@style/Theme.JJBAKSAAOS"
tools:replace="android:appComponentFactory"
tools:targetApi="31">
+
+ android:exported="true">
@@ -65,8 +66,7 @@
android:exported="false" />
-
+ android:exported="false">
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/JjbaksaApp.kt b/app/src/main/java/com/jjbaksa/jjbaksa/JjbaksaApp.kt
index ad513b26..ba426472 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/JjbaksaApp.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/JjbaksaApp.kt
@@ -5,7 +5,13 @@ import com.kakao.sdk.common.KakaoSdk
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
+import com.jjbaksa.data.database.PreferenceKeys
+import com.jjbaksa.data.database.userDataStore
+import com.jjbaksa.jjbaksa.util.MyInfo
import dagger.hilt.android.HiltAndroidApp
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
@HiltAndroidApp
class JjbaksaApp : Application() {
@@ -17,6 +23,9 @@ class JjbaksaApp : Application() {
super.onCreate()
KakaoSdk.init(this, BuildConfig.kakao_native_app_key)
instance = this
+ GlobalScope.launch {
+ MyInfo.id = appContext.userDataStore.data.first()[PreferenceKeys.NICKNAME] ?: ""
+ }
}
/**
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/base/BaseActivity.kt b/app/src/main/java/com/jjbaksa/jjbaksa/base/BaseActivity.kt
index 6e9c2110..c8918a4f 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/base/BaseActivity.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/base/BaseActivity.kt
@@ -30,10 +30,12 @@ abstract class BaseActivity : AppCompatActivity() {
abstract fun initView()
abstract fun subscribe()
abstract fun initEvent()
+// abstract fun initData()
open fun initState() {
initView()
initEvent()
subscribe()
+// initData()
}
fun isPermissionGranted(perm: String): Boolean {
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/dialog/ConfirmDialog.kt b/app/src/main/java/com/jjbaksa/jjbaksa/dialog/ConfirmDialog.kt
index 9f576ba5..61c8ef42 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/dialog/ConfirmDialog.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/dialog/ConfirmDialog.kt
@@ -1,6 +1,7 @@
package com.jjbaksa.jjbaksa.dialog
import android.app.Dialog
+import android.graphics.Color
import android.view.View
import com.jjbaksa.jjbaksa.R
import com.jjbaksa.jjbaksa.base.BaseDialogFragment
@@ -11,6 +12,7 @@ class ConfirmDialog(
val msg: String? = null,
val confirmText: String,
val confirmClick: (Dialog) -> Unit,
+ val titleColor: String = "#ff7f23",
val isCancel: Boolean = true
) : BaseDialogFragment() {
override val layoutResId: Int
@@ -20,6 +22,7 @@ class ConfirmDialog(
isCancelable = isCancel
with(binding) {
confirmDialogTitle.text = title
+ confirmDialogTitle.setTextColor(Color.parseColor(titleColor))
if (msg == null) {
confirmDialogMsg.visibility = View.GONE
} else {
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/dialog/MyPageBottomSheetDialog.kt b/app/src/main/java/com/jjbaksa/jjbaksa/dialog/MyPageBottomSheetDialog.kt
new file mode 100644
index 00000000..de89b7f8
--- /dev/null
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/dialog/MyPageBottomSheetDialog.kt
@@ -0,0 +1,112 @@
+package com.jjbaksa.jjbaksa.dialog
+
+import android.Manifest
+import android.app.Activity
+import android.content.Intent
+import android.view.View
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.widget.addTextChangedListener
+import androidx.fragment.app.activityViewModels
+import com.jjbaksa.jjbaksa.R
+import com.jjbaksa.jjbaksa.base.BaseBottomSheetDialogFragment
+import com.jjbaksa.jjbaksa.databinding.DialogMypageBinding
+import com.jjbaksa.jjbaksa.ui.mainpage.mypage.viewmodel.MyPageViewModel
+import dagger.hilt.android.AndroidEntryPoint
+import coil.load
+import coil.transform.CircleCropTransformation
+import com.example.imageselector.gallery.GalleryActivity
+import com.jjbaksa.jjbaksa.util.hasPermission
+
+@AndroidEntryPoint
+class MyPageBottomSheetDialog : BaseBottomSheetDialogFragment() {
+ override val layoutResId: Int
+ get() = R.layout.dialog_mypage
+ private val viewModel: MyPageViewModel by activityViewModels()
+
+ private val galleryActivityLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ if (it.resultCode == Activity.RESULT_OK) {
+ val images = it.data!!.getStringArrayListExtra("images")!!
+ viewModel.setLoadImage(images[0])
+ binding.profileImageView.load(images[0]) {
+ transformations(CircleCropTransformation())
+ }
+ }
+ }
+ private val requestPermissions = registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) {
+ if (it) {
+ val intent = Intent(requireContext(), GalleryActivity::class.java)
+ intent.putExtra("limit", 1)
+ galleryActivityLauncher.launch(intent)
+ } else {
+ }
+ }
+
+ override fun initView(view: View) {
+ binding.vm = viewModel
+ viewModel.getUserProfile()
+ this.heightPercent = 0.55f
+ this.setLayoutMaxHeight(view)
+ }
+
+ override fun initEvent() {
+ confirmProfile()
+ cancelProfile()
+ loadProfileImage()
+ setTextLength()
+ observeData()
+ }
+
+ private fun confirmProfile() {
+ binding.confirmButton.setOnClickListener {
+ if (viewModel.loadImage.value.isNullOrEmpty() || viewModel.textLength.value == "0") {
+ // todo:: empty profile image or nickname
+ } else {
+ viewModel.uploadProfileImgAndNickname(
+ viewModel.loadImage.value.toString(),
+ binding.profileNicknameEditText.text.toString()
+ )
+ }
+ }
+ }
+
+ private fun cancelProfile() {
+ binding.cancelButton.setOnClickListener {
+ dismiss()
+ }
+ }
+
+ private fun loadProfileImage() {
+ binding.addProfileImage.setOnClickListener {
+ if (requireContext().hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ val intent = Intent(requireContext(), GalleryActivity::class.java)
+ intent.putExtra("limit", 1)
+ galleryActivityLauncher.launch(intent)
+ } else {
+ requestPermissions.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ }
+ }
+ }
+
+ private fun setTextLength() {
+ binding.profileNicknameEditText.addTextChangedListener {
+ viewModel.setTextLength(it?.length.toString())
+ }
+ }
+
+ private fun observeData() {
+ viewModel.textLength.observe(viewLifecycleOwner) {
+ binding.textLengthCountTextView.text = getString(R.string.text_length, it)
+ }
+ viewModel.isResult.observe(viewLifecycleOwner) {
+ if (it) dismiss()
+ }
+ }
+
+ override fun subscribe() {
+ }
+
+ override fun initData() {
+ }
+}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/changepassword/ChangePasswordActivity.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/changepassword/ChangePasswordActivity.kt
index 180755f1..3515c0f9 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/changepassword/ChangePasswordActivity.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/changepassword/ChangePasswordActivity.kt
@@ -1,6 +1,8 @@
package com.jjbaksa.jjbaksa.ui.changepassword
+import android.graphics.drawable.Drawable
import androidx.activity.viewModels
+import androidx.core.content.ContextCompat
import com.jjbaksa.jjbaksa.R
import com.jjbaksa.jjbaksa.base.BaseActivity
import com.jjbaksa.jjbaksa.databinding.ActivityChangePasswordBinding
@@ -14,8 +16,51 @@ class ChangePasswordActivity : BaseActivity() {
get() = R.layout.activity_change_password
private val viewModel: ChangePasswordViewModel by viewModels()
+ var currentPasswordText = ""
+ var newPasswordText = ""
+ var checkPasswordText = ""
+ var isFailedCurrentPassword = false
+ var isFailedNewPassword = false
+
override fun initView() {
binding.jjAppBarContainer.setOnClickListener { finish() }
+ observeData()
+ }
+
+ private fun observeData() {
+ viewModel.currentPasswordState.observe(this) {
+ isFailedCurrentPassword = !it?.isSuccess!!
+ if (isFailedCurrentPassword) {
+ binding.currentPasswordEditText.editTextBackground = failButtonBackground()
+ showSnackBar(it?.msg.toString(), getString(R.string.cancel))
+ } else {
+ if (newPasswordText != checkPasswordText) {
+ showSnackBar(
+ getString(R.string.not_match_new_password),
+ getString(R.string.cancel)
+ )
+ binding.newPasswordEditText.editTextBackground = failButtonBackground()
+ binding.checkNewPasswordEditText.editTextBackground = failButtonBackground()
+ isFailedNewPassword = true
+ } else {
+ viewModel.setNewPassword(binding.newPasswordEditText.editTextText)
+ }
+ }
+ }
+ viewModel.newPasswordState.observe(this) {
+ if (it?.isSuccess!!) {
+ setConfirmDialog()
+ } else {
+ showSnackBar(it.msg.toString(), getString(R.string.cancel))
+ binding.newPasswordEditText.editTextBackground = failButtonBackground()
+ binding.checkNewPasswordEditText.editTextBackground = failButtonBackground()
+ isFailedNewPassword = true
+ }
+ }
+ viewModel.isEnableButton.observe(this) {
+ binding.changePasswordButton.isEnabled = it
+ binding.changePasswordButton.isSelected = it
+ }
}
override fun subscribe() {
@@ -25,29 +70,80 @@ class ChangePasswordActivity : BaseActivity() {
setCurrentPassword()
setNewPassword()
setCheckNewPassword()
+ setConfirmButton()
}
private fun setCurrentPassword() {
binding.currentPasswordEditText.also {
it.setOnFocusChangeListener { _, _ -> }
- it.addTextChangedListener { currentPassword -> }
+ it.addTextChangedListener { currentPassword ->
+ if (isFailedCurrentPassword) {
+ it.editTextBackground = comeBackButtonBackground()
+ isFailedCurrentPassword = false
+ }
+ currentPasswordText = currentPassword.toString()
+ setEditTextState()
+ }
}
}
private fun setNewPassword() {
binding.newPasswordEditText.also {
it.setOnFocusChangeListener { _, _ -> }
- it.addTextChangedListener { newPassword -> }
+ it.addTextChangedListener { newPassword ->
+ if (isFailedNewPassword) {
+ it.editTextBackground = comeBackButtonBackground()
+ binding.checkNewPasswordEditText.editTextBackground = comeBackButtonBackground()
+ isFailedNewPassword = false
+ }
+ newPasswordText = newPassword.toString()
+ setEditTextState()
+ }
}
}
private fun setCheckNewPassword() {
binding.checkNewPasswordEditText.also {
it.setOnFocusChangeListener { _, _ -> }
- it.addTextChangedListener { checkNewPassword -> }
+ it.addTextChangedListener { checkNewPassword ->
+ if (isFailedNewPassword) {
+ it.editTextBackground = comeBackButtonBackground()
+ binding.newPasswordEditText.editTextBackground = comeBackButtonBackground()
+ isFailedNewPassword = false
+ }
+ checkPasswordText = checkNewPassword.toString()
+ setEditTextState()
+ }
}
}
+ private fun isNotEmptyEditText(): Boolean =
+ currentPasswordText.isNotEmpty() && newPasswordText.isNotEmpty() && checkPasswordText.isNotEmpty()
+
+ private fun setEditTextState() {
+ if (isNotEmptyEditText()) {
+ viewModel.setEnabledButton(true)
+ } else {
+ viewModel.setEnabledButton(false)
+ }
+ }
+
+ private fun setConfirmButton() {
+ binding.changePasswordButton.setOnClickListener {
+ viewModel.checkPassword(binding.currentPasswordEditText.editTextText)
+ }
+ }
+
+ private fun failButtonBackground(): Drawable? = ContextCompat.getDrawable(
+ this,
+ R.drawable.shape_rect_eeeeee_solid_radius_100_stroke_ff7f23
+ )
+
+ private fun comeBackButtonBackground(): Drawable? = ContextCompat.getDrawable(
+ this,
+ R.drawable.shape_rect_eeeeee_solid_radius_100_padding_7_11_11_8
+ )
+
private fun setConfirmDialog() {
ConfirmDialog(
getString(R.string.success_change_password),
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/changepassword/viewmodel/ChangePasswordViewModel.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/changepassword/viewmodel/ChangePasswordViewModel.kt
index f290b421..a926b755 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/changepassword/viewmodel/ChangePasswordViewModel.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/changepassword/viewmodel/ChangePasswordViewModel.kt
@@ -1,8 +1,11 @@
package com.jjbaksa.jjbaksa.ui.changepassword.viewmodel
-import androidx.lifecycle.ViewModel
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.jjbaksa.domain.repository.UserRepository
+import com.jjbaksa.domain.resp.user.FormatResp
+import com.jjbaksa.jjbaksa.base.BaseViewModel
+import com.jjbaksa.jjbaksa.util.SingleLiveEvent
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -10,10 +13,28 @@ import javax.inject.Inject
@HiltViewModel
class ChangePasswordViewModel @Inject constructor(
val repository: UserRepository
-) : ViewModel() {
+) : BaseViewModel() {
+ var isEnableButton = MutableLiveData(false)
+
+ private val _currentPasswordState = SingleLiveEvent()
+ val currentPasswordState: SingleLiveEvent get() = _currentPasswordState
+
+ private val _newPasswordState = SingleLiveEvent()
+ val newPasswordState: SingleLiveEvent get() = _newPasswordState
+
fun checkPassword(password: String) {
- viewModelScope.launch {
- repository.checkPassword(password)
+ viewModelScope.launch(ceh) {
+ _currentPasswordState.value = repository.checkPassword(password)
+ }
+ }
+
+ fun setNewPassword(password: String) {
+ viewModelScope.launch(ceh) {
+ _newPasswordState.value = repository.setNewPassword(password)
}
}
+
+ fun setEnabledButton(enable: Boolean) {
+ isEnableButton.value = enable
+ }
}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/findid/FindIdFragment.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/findid/FindIdFragment.kt
index 127701ff..84d39274 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/findid/FindIdFragment.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/findid/FindIdFragment.kt
@@ -42,7 +42,7 @@ class FindIdFragment : BaseFragment() {
private fun sendVerificationCode() {
binding.buttonFindIdSendToVerificationCode.setOnClickListener {
- KeyboardProvider().hideKeyboard(requireContext(), binding.editTextFindIdToEmail)
+ KeyboardProvider(requireContext()).hideKeyboard(binding.editTextFindIdToEmail)
viewModel.getAuthEmail(binding.editTextFindIdToEmail.text.toString())
}
}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/findid/FindIdInputVerificationCodeFragment.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/findid/FindIdInputVerificationCodeFragment.kt
index a1b5ff25..5d7625a3 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/findid/FindIdInputVerificationCodeFragment.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/findid/FindIdInputVerificationCodeFragment.kt
@@ -68,14 +68,14 @@ class FindIdInputVerificationCodeFragment : BaseFragment() {
findNavController().navigate(R.id.action_nav_find_password_to_nav_find_password_input_code)
} else {
outlineState = true
- KeyboardProvider().hideKeyboard(requireContext(), binding.inputEmailEditText)
+ KeyboardProvider(requireContext()).hideKeyboard(binding.inputEmailEditText)
if (it.msg.toString().contains(USER)) {
showSnackBar(getString(R.string.fail_id))
changeEditTextOutlineColor(binding.inputIdEditText)
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/findpassword/FindPasswordInputCodeFragment.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/findpassword/FindPasswordInputCodeFragment.kt
index a3c3bca0..2b7793bb 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/findpassword/FindPasswordInputCodeFragment.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/findpassword/FindPasswordInputCodeFragment.kt
@@ -58,7 +58,7 @@ class FindPasswordInputCodeFragment : BaseFragment
ContextCompat.getDrawable(requireContext(), R.drawable.shape_rect_eeeeee_solid_radius_100_stroke_ff7f23)
binding.inputCheckPasswordEditText.editTextBackground =
ContextCompat.getDrawable(requireContext(), R.drawable.shape_rect_eeeeee_solid_radius_100_stroke_ff7f23)
- KeyboardProvider().hideKeyboard(requireContext(), binding.root)
+ KeyboardProvider(requireContext()).hideKeyboard(binding.root)
}
companion object {
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/login/LoginActivity.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/login/LoginActivity.kt
index bc8f8cb9..9923ea2a 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/login/LoginActivity.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/login/LoginActivity.kt
@@ -28,11 +28,11 @@ class LoginActivity : BaseActivity() {
override fun subscribe() {
with(viewModel) {
-
loginState.observe(this@LoginActivity) {
if (it != null) {
if (it.isSuccess) {
goToMainActivity()
+ viewModel.loadUserMe()
} else {
if (it.erroMessage.isNotEmpty()) {
showSnackBar(it.erroMessage, getString(R.string.cancel))
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/login/LoginViewModel.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/login/LoginViewModel.kt
index 71c92ffd..62ed1a66 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/login/LoginViewModel.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/login/LoginViewModel.kt
@@ -22,9 +22,6 @@ class LoginViewModel @Inject constructor(
private val _loginState = SingleLiveEvent()
val loginState: SingleLiveEvent get() = _loginState
- private val _autoLoginState = SingleLiveEvent()
- val autoLoginState: SingleLiveEvent get() = _autoLoginState
-
fun login(isCheckedSwitch: Boolean) {
if (!TextUtils.isEmpty(account.value) && !TextUtils.isEmpty(password.value)) {
viewModelScope.launch(ceh) {
@@ -35,15 +32,9 @@ class LoginViewModel @Inject constructor(
}
}
-// fun getAutoLoginFlag() {
-// viewModelScope.launch(ceh) {
-//
-// if (repository.getAutoLoginFlag()) {
-// isAutoLogin.value = true
-// account.value = repository.getAccount()
-// password.value = repository.getPasswrod()
-// login()
-// }
-// }
-// }
+ fun loadUserMe() {
+ viewModelScope.launch {
+ repository.me()
+ }
+ }
}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/mypage/NaviMyPageFragment.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/mypage/NaviMyPageFragment.kt
index 0729d09e..7cf35196 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/mypage/NaviMyPageFragment.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/mypage/NaviMyPageFragment.kt
@@ -3,11 +3,16 @@ package com.jjbaksa.jjbaksa.ui.mainpage.mypage
import android.content.Intent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import coil.load
+import coil.transform.CircleCropTransformation
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.jjbaksa.jjbaksa.R
import com.jjbaksa.jjbaksa.base.BaseFragment
import com.jjbaksa.jjbaksa.databinding.FragmentNaviMyPageBinding
+import com.jjbaksa.jjbaksa.dialog.MyPageBottomSheetDialog
+import com.jjbaksa.jjbaksa.ui.mainpage.mypage.viewmodel.MyPageViewModel
import com.jjbaksa.jjbaksa.ui.setting.SettingActivity
import com.jjbaksa.jjbaksa.util.setExtendView
import dagger.hilt.android.AndroidEntryPoint
@@ -16,18 +21,43 @@ import dagger.hilt.android.AndroidEntryPoint
class NaviMyPageFragment : BaseFragment() {
override val layoutId: Int
get() = R.layout.fragment_navi_my_page
+ private val viewModel: MyPageViewModel by activityViewModels()
+
private val reviewFragment by lazy { ReviewFragment() }
private val bookmarkFragment by lazy { BookmarkFragment() }
- private val settingResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
- // Handle SettingActivity result
- }
+ private val settingResult =
+ registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ // Handle SettingActivity result
+ }
override fun initView() {
requireActivity().setExtendView(binding.myPageConstraintLayout)
initFragment(reviewFragment)
setTabLayout()
+ binding.vm = viewModel
+ binding.lifecycleOwner = this
+ viewModel.getUserProfile()
+ observeData()
}
+
+ private fun observeData() {
+ viewModel.nickname.observe(viewLifecycleOwner) {
+ binding.profileNameTextView.text = it
+ }
+ viewModel.profileImage.observe(viewLifecycleOwner) {
+ if (it.isEmpty()) {
+ binding.profileImageView.load(R.drawable.baseline_supervised_user_circle_24) {
+ transformations(CircleCropTransformation())
+ }
+ } else {
+ binding.profileImageView.load(it) {
+ transformations(CircleCropTransformation())
+ }
+ }
+ }
+ }
+
private fun initFragment(fragment: Fragment) {
parentFragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment)
@@ -42,16 +72,20 @@ class NaviMyPageFragment : BaseFragment() {
1 -> initFragment(bookmarkFragment)
}
}
+
override fun onTabUnselected(tab: TabLayout.Tab?) {}
override fun onTabReselected(tab: TabLayout.Tab?) {}
})
}
override fun initEvent() {
- setSettingActivity()
+ onClickSettingImage()
+ binding.profileImageView.setOnClickListener {
+ MyPageBottomSheetDialog().show(parentFragmentManager, MY_PAGE_DIALOG_TAG)
+ }
}
- private fun setSettingActivity() {
+ private fun onClickSettingImage() {
binding.settingImageButton.setOnClickListener {
settingResult.launch(Intent(requireContext(), SettingActivity::class.java))
}
@@ -59,4 +93,8 @@ class NaviMyPageFragment : BaseFragment() {
override fun subscribe() {
}
+
+ companion object {
+ const val MY_PAGE_DIALOG_TAG = "MY_PAGE_DIALOG_TAG"
+ }
}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/mypage/viewmodel/MyPageViewModel.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/mypage/viewmodel/MyPageViewModel.kt
index 357e90e2..dbade065 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/mypage/viewmodel/MyPageViewModel.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/mypage/viewmodel/MyPageViewModel.kt
@@ -1,11 +1,59 @@
package com.jjbaksa.jjbaksa.ui.mainpage.mypage.viewmodel
-import androidx.lifecycle.ViewModel
-import com.jjbaksa.domain.repository.HomeRepository
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import com.jjbaksa.domain.base.RespResult
+import com.jjbaksa.domain.repository.UserRepository
+import com.jjbaksa.jjbaksa.base.BaseViewModel
+import com.jjbaksa.jjbaksa.util.SingleLiveEvent
import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class MyPageViewModel @Inject constructor(
- val repository: HomeRepository
-) : ViewModel()
+ val repository: UserRepository
+) : BaseViewModel() {
+ val account = MutableLiveData("")
+ val nickname = MutableLiveData("")
+ val profileFollowers = MutableLiveData(0)
+ val profileImage = MutableLiveData("")
+ val textLength = MutableLiveData("")
+
+ private val _loadImage = SingleLiveEvent()
+ val loadImage: LiveData get() = _loadImage
+
+ private val _isResult = SingleLiveEvent()
+ val isResult: LiveData get() = _isResult
+
+ fun getUserProfile() {
+ account.value = repository.getAccount()
+ nickname.value = repository.getNickname()
+ profileFollowers.value = repository.getFollowers()
+ profileImage.value = repository.getProfileImage()
+ textLength.value = repository.getNickname().length.toString()
+ }
+
+ fun setTextLength(length: String) {
+ textLength.value = length
+ }
+
+ fun setLoadImage(image: String) {
+ _loadImage.value = image
+ }
+
+ fun uploadProfileImgAndNickname(image: String, newNickname: String) {
+ viewModelScope.launch(ceh) {
+ val response = repository.editUserProfileImage(image)
+ if (response == RespResult.Success(true)) {
+ profileImage.value = repository.getProfileImage()
+ val nicknameResponse = repository.setNewNickname(newNickname)
+ if (nicknameResponse.isSuccess) {
+ nickname.value = repository.getNickname()
+ _isResult.value = true
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/viewmodel/HomeViewModel.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/viewmodel/HomeViewModel.kt
index 67e8d059..01a48883 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/viewmodel/HomeViewModel.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/mainpage/viewmodel/HomeViewModel.kt
@@ -2,7 +2,7 @@ package com.jjbaksa.jjbaksa.ui.mainpage.viewmodel
import androidx.lifecycle.viewModelScope
import com.jjbaksa.domain.model.mainpage.UserLocation
-import com.jjbaksa.domain.repository.HomeRepository
+import com.jjbaksa.domain.repository.UserRepository
import com.jjbaksa.jjbaksa.base.BaseViewModel
import com.jjbaksa.jjbaksa.ui.mainpage.sub.FusedLocationProvider
import com.jjbaksa.jjbaksa.util.SingleLiveEvent
@@ -12,7 +12,7 @@ import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(
- private val repository: HomeRepository
+ private val repository: UserRepository
) : BaseViewModel() {
lateinit var fusedLocationProvider: FusedLocationProvider
@@ -30,4 +30,10 @@ class HomeViewModel @Inject constructor(
fusedLocationProvider.startLocationUpdates()
}
}
+
+ fun getUserMe() {
+ viewModelScope.launch {
+ repository.me()
+ }
+ }
}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/setting/SettingActivity.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/setting/SettingActivity.kt
index 7d855f9e..58208493 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/setting/SettingActivity.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/setting/SettingActivity.kt
@@ -7,6 +7,7 @@ import com.jjbaksa.jjbaksa.base.BaseActivity
import com.jjbaksa.jjbaksa.databinding.ActivitySettingBinding
import com.jjbaksa.jjbaksa.ui.changepassword.ChangePasswordActivity
import com.jjbaksa.jjbaksa.ui.setting.viewmodel.SettingViewModel
+import com.jjbaksa.jjbaksa.ui.withdrawal.WithdrawalActivity
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
@@ -33,9 +34,12 @@ class SettingActivity : BaseActivity() {
fun goToChangePassword() {
startActivity(Intent(this, ChangePasswordActivity::class.java))
}
- fun goToPrivacyPolicy() { }
- fun goToNotice() { }
- fun goToInquiry() { }
- fun logout() { }
- fun withdraw() {}
+
+ fun goToPrivacyPolicy() {}
+ fun goToNotice() {}
+ fun goToInquiry() {}
+ fun logout() {}
+ fun withdraw() {
+ startActivity(Intent(this, WithdrawalActivity::class.java))
+ }
}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/splash/SplashActivity.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/splash/SplashActivity.kt
index 2b385a3a..23733661 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/ui/splash/SplashActivity.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/splash/SplashActivity.kt
@@ -28,17 +28,20 @@ class SplashActivity : BaseActivity() {
// MainPageActivity Result Handle
}
- override fun initView() {
+ override fun subscribe() {
observeData()
}
-
- override fun subscribe() {
+ override fun initView() {
+ viewModel.getAutoLogin()
}
override fun initEvent() {
- viewModel.getAutoLogin()
}
+// override fun initData() {
+// viewModel.getAutoLogin()
+// }
+
private fun observeData() {
viewModel.autoLogin.observe(this) { isLogin ->
if (isLogin) {
@@ -59,6 +62,7 @@ class SplashActivity : BaseActivity() {
finish()
}
}
+
is RespResult.Error -> {
showSnackBar(it.errorType.errorMessage, getString(R.string.cancel))
goToLoginActivity()
@@ -71,6 +75,7 @@ class SplashActivity : BaseActivity() {
private fun goToLoginActivity() {
loginResult.launch(Intent(this, LoginActivity::class.java))
}
+
private fun goToMainActivity() {
mainResult.launch(Intent(this, MainPageActivity::class.java))
}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/withdrawal/WithdrawalActivity.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/withdrawal/WithdrawalActivity.kt
new file mode 100644
index 00000000..e95135b5
--- /dev/null
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/withdrawal/WithdrawalActivity.kt
@@ -0,0 +1,139 @@
+package com.jjbaksa.jjbaksa.ui.withdrawal
+
+import android.content.Intent
+import androidx.activity.viewModels
+import androidx.core.app.ActivityCompat
+import androidx.core.widget.addTextChangedListener
+import com.jjbaksa.domain.resp.user.WithdrawalReasonReq
+import com.jjbaksa.jjbaksa.R
+import com.jjbaksa.jjbaksa.base.BaseActivity
+import com.jjbaksa.jjbaksa.databinding.ActivityWithdrawalBinding
+import com.jjbaksa.jjbaksa.dialog.ConfirmDialog
+import com.jjbaksa.jjbaksa.ui.login.LoginActivity
+import com.jjbaksa.jjbaksa.ui.withdrawal.viewmodel.WithdrawalViewModel
+import com.jjbaksa.jjbaksa.util.KeyboardProvider
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class WithdrawalActivity : BaseActivity() {
+ override val layoutId: Int
+ get() = R.layout.activity_withdrawal
+ private val viewModel: WithdrawalViewModel by viewModels()
+
+ override fun initView() {
+ KeyboardProvider(this).inputKeyboardResize(window, binding.root)
+ binding.vm = viewModel
+ binding.lifecycleOwner = this
+ viewModel.getNickname()
+ }
+
+ override fun subscribe() {
+ observeData()
+ }
+
+ private fun observeData() {
+ viewModel.saveWithdrawalReasonState.observe(this) {
+ if (it.isSuccess) {
+ viewModel.withdraw()
+ } else {
+ showSnackBar(it.message.toString(), getString(R.string.close))
+ }
+ }
+ viewModel.isWithdrawUser.observe(this) {
+ if (it) {
+ showCompleteWithdrawalDialog()
+ }
+ }
+ }
+
+ override fun initEvent() {
+ binding.jjAppBarContainer.setOnClickListener { finish() }
+ withdrawal()
+ setWithdrawalReason()
+ setFocusInputField()
+ setInputField()
+ }
+
+ private fun withdrawal() {
+ binding.withdrawalButton.setOnClickListener {
+ if (viewModel.reason.value?.isNotEmpty()!! && binding.inputEditTextField.text?.isNotEmpty()!!) {
+ val withdrawalReasonReq = WithdrawalReasonReq(
+ viewModel.reason.value.toString(),
+ binding.inputEditTextField.text.toString()
+ )
+ viewModel.saveWithdrawalReason(withdrawalReasonReq)
+ }
+ }
+ }
+
+ private fun setWithdrawalReason() {
+ binding.reasonWithdrawalRadioGroup.setOnCheckedChangeListener { group, checkedId ->
+ when (checkedId) {
+ R.id.reason_withdrawal_radio_button_1 -> {
+ viewModel.setWithdrawalReason(binding.reasonWithdrawalRadioButton1.text.toString())
+ }
+
+ R.id.reason_withdrawal_radio_button_2 -> {
+ viewModel.setWithdrawalReason(binding.reasonWithdrawalRadioButton2.text.toString())
+ }
+
+ R.id.reason_withdrawal_radio_button_3 -> {
+ viewModel.setWithdrawalReason(binding.reasonWithdrawalRadioButton3.text.toString())
+ }
+
+ R.id.reason_withdrawal_radio_button_4 -> {
+ viewModel.setWithdrawalReason(binding.reasonWithdrawalRadioButton4.text.toString())
+ }
+
+ R.id.reason_withdrawal_radio_button_5 -> {
+ viewModel.setWithdrawalReason(binding.reasonWithdrawalRadioButton5.text.toString())
+ }
+ }
+ }
+ }
+
+ private fun setFocusInputField() {
+ binding.inputEditTextField.setOnFocusChangeListener { _, hasFocus ->
+ if (hasFocus) {
+ if (binding.inputEditTextField.text.toString() == getString(R.string.free_write)) {
+ binding.inputEditTextField.text?.clear()
+ }
+ }
+ }
+ }
+
+ private fun setInputField() {
+ binding.inputEditTextField.addTextChangedListener {
+ viewModel.setInputTextLength(it?.length.toString())
+
+ if (it?.length == 150) {
+ viewModel.setMaxInputTextLength(true)
+ } else {
+ viewModel.setMaxInputTextLength(false)
+ }
+
+ if (!it.isNullOrEmpty()) {
+ viewModel.setIsEnabled(true)
+ } else {
+ viewModel.setIsEnabled(false)
+ }
+ }
+ }
+
+ private fun showCompleteWithdrawalDialog() {
+ ConfirmDialog(
+ getString(R.string.complete_withdrawal),
+ getString(R.string.complete_withdrawal_content),
+ getString(R.string.close),
+ {
+ ActivityCompat.finishAffinity(this)
+ startActivity(Intent(this, LoginActivity::class.java))
+ },
+ "#222222"
+ ).show(supportFragmentManager, WITHDRAWAL_DIALOG_TAG)
+ }
+
+ companion object {
+ const val WITHDRAWAL_DIALOG_TAG = "WITHDRAWAL_DIALOG_TAG"
+ }
+}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/withdrawal/viewmodel/WithdrawalViewModel.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/withdrawal/viewmodel/WithdrawalViewModel.kt
new file mode 100644
index 00000000..e02a0d04
--- /dev/null
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/withdrawal/viewmodel/WithdrawalViewModel.kt
@@ -0,0 +1,86 @@
+package com.jjbaksa.jjbaksa.ui.withdrawal.viewmodel
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.jjbaksa.domain.base.RespResult
+import com.jjbaksa.domain.repository.UserRepository
+import com.jjbaksa.domain.resp.user.WithdrawalReasonReq
+import com.jjbaksa.domain.resp.user.WithdrawalReasonResp
+import com.jjbaksa.jjbaksa.util.SingleLiveEvent
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class WithdrawalViewModel @Inject constructor(
+ val repository: UserRepository
+) : ViewModel() {
+ val userNickname = MutableLiveData("")
+ private val _isEnabled = SingleLiveEvent()
+ val isEnabled: LiveData get() = _isEnabled
+ val inputTextLength = MutableLiveData("0")
+ private val _maxInputTextLength = SingleLiveEvent()
+ val maxInputTextLength: LiveData get() = _maxInputTextLength
+ val reason = MutableLiveData("")
+
+ private val _saveWithdrawalReasonState = MutableLiveData()
+ val saveWithdrawalReasonState: LiveData get() = _saveWithdrawalReasonState
+ private val _isWithdrawUser = MutableLiveData()
+ val isWithdrawUser: LiveData get() = _isWithdrawUser
+
+ fun getNickname() {
+ userNickname.value = repository.getNickname()
+ }
+
+ fun setIsEnabled(enabled: Boolean) {
+ _isEnabled.value = enabled
+ }
+
+ fun setInputTextLength(length: String) {
+ inputTextLength.value = length
+ }
+
+ fun setMaxInputTextLength(maxLength: Boolean) {
+ _maxInputTextLength.value = maxLength
+ }
+
+ fun setWithdrawalReason(radioReason: String) {
+ reason.value = radioReason
+ }
+
+ fun saveWithdrawalReason(withdrawalReason: WithdrawalReasonReq) {
+ viewModelScope.launch {
+ runCatching {
+ repository.saveWithdrawalReason(withdrawalReason)
+ }.onSuccess { result ->
+ when (result) {
+ is RespResult.Success -> {
+ _saveWithdrawalReasonState.value = WithdrawalReasonResp(result.data, null)
+ }
+ is RespResult.Error -> {
+ _saveWithdrawalReasonState.value = WithdrawalReasonResp(false, result.errorType.errorMessage)
+ }
+ }
+ }.onFailure { }
+ }
+ }
+
+ fun withdraw() {
+ viewModelScope.launch {
+ runCatching {
+ repository.deleteUser()
+ }.onSuccess {
+ when (it) {
+ is RespResult.Success -> {
+ _isWithdrawUser.value = it.data!!
+ }
+ is RespResult.Error -> {
+ _isWithdrawUser.value = false
+ }
+ }
+ }.onFailure { }
+ }
+ }
+}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/util/KeyboardProvider.kt b/app/src/main/java/com/jjbaksa/jjbaksa/util/KeyboardProvider.kt
index 7c2862bd..3420fae1 100644
--- a/app/src/main/java/com/jjbaksa/jjbaksa/util/KeyboardProvider.kt
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/util/KeyboardProvider.kt
@@ -1,12 +1,33 @@
package com.jjbaksa.jjbaksa.util
import android.content.Context
+import android.os.Build
import android.view.View
+import android.view.Window
+import android.view.WindowInsets
+import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
-class KeyboardProvider() {
- fun hideKeyboard(context: Context, focusItem: View) {
+class KeyboardProvider(val context: Context) {
+ fun hideKeyboard(focusItem: View) {
val inputManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputManager.hideSoftInputFromWindow(focusItem.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
}
+
+ fun inputKeyboardResize(window: Window, view: View) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ window.setDecorFitsSystemWindows(false)
+ view.setOnApplyWindowInsetsListener { _, insets ->
+ val topInset = insets.getInsets(WindowInsets.Type.statusBars()).top
+ val imeHeight = insets.getInsets(WindowInsets.Type.ime()).bottom
+ val navigationHeight = insets.getInsets(WindowInsets.Type.navigationBars()).bottom
+ val bottomInset = if (imeHeight == 0) navigationHeight else imeHeight
+
+ view.setPadding(0, topInset, 0, bottomInset)
+ insets
+ }
+ } else {
+ window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
+ }
+ }
}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/util/MyInfo.kt b/app/src/main/java/com/jjbaksa/jjbaksa/util/MyInfo.kt
new file mode 100644
index 00000000..635ff155
--- /dev/null
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/util/MyInfo.kt
@@ -0,0 +1,5 @@
+package com.jjbaksa.jjbaksa.util
+
+object MyInfo {
+ var id: String = ""
+}
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/util/databinding/ImageDataBindingAdapter.kt b/app/src/main/java/com/jjbaksa/jjbaksa/util/databinding/ImageDataBindingAdapter.kt
new file mode 100644
index 00000000..5222eaca
--- /dev/null
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/util/databinding/ImageDataBindingAdapter.kt
@@ -0,0 +1,22 @@
+package com.jjbaksa.jjbaksa.util.databinding
+
+import android.widget.ImageView
+import androidx.databinding.BindingAdapter
+import coil.load
+import coil.transform.CircleCropTransformation
+import com.jjbaksa.jjbaksa.R
+
+@BindingAdapter("img")
+fun ImageView.setImage(image: String?) {
+ if (image == null) {
+ return
+ }
+
+ if (image.isEmpty()) {
+ load(R.drawable.baseline_supervised_user_circle_24)
+ } else {
+ load(image) {
+ transformations(CircleCropTransformation())
+ }
+ }
+}
diff --git a/app/src/main/res/drawable/baseline_supervised_user_circle_24.xml b/app/src/main/res/drawable/baseline_supervised_user_circle_24.xml
new file mode 100644
index 00000000..3ea888a6
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_supervised_user_circle_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/bg_bottom_sheet_dialog.xml b/app/src/main/res/drawable/bg_bottom_sheet_dialog.xml
new file mode 100644
index 00000000..010d9525
--- /dev/null
+++ b/app/src/main/res/drawable/bg_bottom_sheet_dialog.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_withdrawal_button.xml b/app/src/main/res/drawable/bg_withdrawal_button.xml
new file mode 100644
index 00000000..40e32955
--- /dev/null
+++ b/app/src/main/res/drawable/bg_withdrawal_button.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_circ_d9d9d9_stroke_ffffff.xml b/app/src/main/res/drawable/shape_circ_d9d9d9_stroke_ffffff.xml
new file mode 100644
index 00000000..70851a1c
--- /dev/null
+++ b/app/src/main/res/drawable/shape_circ_d9d9d9_stroke_ffffff.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_withdrawal.xml b/app/src/main/res/layout/activity_withdrawal.xml
new file mode 100644
index 00000000..d5c92551
--- /dev/null
+++ b/app/src/main/res/layout/activity_withdrawal.xml
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_mypage.xml b/app/src/main/res/layout/dialog_mypage.xml
new file mode 100644
index 00000000..c810718a
--- /dev/null
+++ b/app/src/main/res/layout/dialog_mypage.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_navi_my_page.xml b/app/src/main/res/layout/fragment_navi_my_page.xml
index aa8bbed6..de71fecb 100644
--- a/app/src/main/res/layout/fragment_navi_my_page.xml
+++ b/app/src/main/res/layout/fragment_navi_my_page.xml
@@ -8,6 +8,9 @@
+
@@ -34,6 +38,7 @@
android:textColor="@color/color_000000"
android:textSize="16dp"
android:textStyle="bold"
+ android:text="@{vm.nickname}"
app:layout_constraintStart_toEndOf="@id/profile_image_view"
app:layout_constraintTop_toTopOf="@id/profile_image_view"
tools:text="이병건이올씨다" />
@@ -42,9 +47,10 @@
android:id="@+id/follower_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="13dp"
android:textColor="@color/color_000000"
+ android:layout_marginStart="2dp"
android:textSize="14dp"
+ android:text="@{@string/my_page_followers(vm.profileFollowers)}"
app:layout_constraintBottom_toBottomOf="@id/profile_name_text_view"
app:layout_constraintStart_toEndOf="@id/profile_name_text_view"
app:layout_constraintTop_toTopOf="@id/profile_name_text_view"
@@ -56,10 +62,11 @@
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textColor="@color/color_000000"
+ android:text="@{@string/my_page_account(vm.account)}"
android:textSize="14dp"
app:layout_constraintStart_toStartOf="@id/profile_name_text_view"
app:layout_constraintTop_toBottomOf="@id/profile_name_text_view"
- tools:text="\@dangerousman" />
+ tools:text="\@dangerousman"/>
#CCFFFFFF
#E6FFFFFF
#fbfbfa
+ #d9d9d9
#595959
#666666
#989898
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b1a66ec6..b276b955 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,6 +4,8 @@
로그인
로그아웃
탈퇴하기
+ 탈퇴하기
+ 탈퇴 완료
아이디
비밀번호
자동로그인
@@ -31,6 +33,12 @@
쩝쩝박사 이용약관(필수)
쩝쩝박사 서비스 이용약관은 bcsd lab에서 서비스를 제공함에 있어, 이용자간의 관리, 의무 및 책임 사항 등을 목적으로 합니다.\n본 약관(이하 ‘본 약관’이라 함)은 쩝쩝박사 어플리케이션과 모바일 및 PC 포함 이와 관련된 웹사이트들(이하 ‘쩝쩝박사’라 함)을 통하여 제공되는 모든 제품 및 서비스(이하 ‘본 서비스’라 함)와 관련하여 본 약관에 따라 당사와 이용계약을 체결하고 본 서비스를 이용하는 고객(이하 ‘회원’이라 함)과 당사 간의 권리, 의무 및 책임사항을 규정함을 목적으로 합니다. 당사에 회원가입을 하지 않고 단순 열람을 원하는 경우, 비회원 이용자를 위한 이용정책이 적용됩니다.
전체동의
+ %s님,\n쩝쩝박사 학위를 포기하시겠어요...?
+ 계정을 삭제하시려는 이유가 궁금해요.
+ 쩝쩝박사에서 개선되면 좋을 점이나\n불편하셨던 점을 말씀해주세요!
+ 적극 반영하여 개선하도록 하겠습니다.\n쩝쩝박사의 문은 언제든 열려있으니 다시 찾아와 주세요!
+ 유의사항\n· 작성한 리뷰, 북마크, 프로필 등 모든 정보가 삭제 됩니다.\n· 추후 같은 계정으로 재가입해도 작성한 내역은 복구되지 않아요.
+ 자유롭게 작성해주세요 :)
새 비밀번호
비밀번호 확인
@@ -46,6 +54,7 @@
새 비밀번호 확인
새 비밀번호를 입력하세요.
새 비밀번호를 설정해 주세요.
+ 새 비밀번호가 일치하지 않습니다.
인증번호 보내기
인증 완료
이메일로 발송된\n인증번호를 입력해 주세요.
@@ -70,6 +79,7 @@
아이디 중복확인을 해주세요.
회원가입을 축하합니다!\n당신을 어떻게 부르면 좋을까요?
+ 다음에 또 봐요! 재가입은 탈퇴 후 일주일 후 부터 가능합니다.
다음
완료
@@ -112,4 +122,15 @@
다녀온 음식점의 리뷰를 작성해 보세요!
등록된 북마크가 없어요.
새로운 음식점을 저장해 보세요!
+ 가게 정보가 부족해요
+ 사용이 불편해요
+ 다른 앱을 더 많이 사용해요
+ 새 계정을 만들고 싶어요
+ 그 외
+
+ • 팔로우 %1$d
+ \@%s
+ %s/10
+ %s/150
+ %s님,\n프로필을 변경하시겠어요?
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 5efad671..ec9f1cca 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -14,6 +14,10 @@
- true
+
+
\ No newline at end of file
diff --git a/data/build.gradle.kts b/data/build.gradle.kts
index 14d0b4d4..39868f03 100644
--- a/data/build.gradle.kts
+++ b/data/build.gradle.kts
@@ -7,8 +7,8 @@ plugins {
}
android {
- compileSdk = Constants.compileSdk
+ compileSdk = 32
defaultConfig {
minSdk = Constants.minSdk
targetSdk = Constants.targetSdk
diff --git a/data/src/main/java/com/jjbaksa/data/api/AuthApi.kt b/data/src/main/java/com/jjbaksa/data/api/AuthApi.kt
index cd9d5eb9..8bf40654 100644
--- a/data/src/main/java/com/jjbaksa/data/api/AuthApi.kt
+++ b/data/src/main/java/com/jjbaksa/data/api/AuthApi.kt
@@ -2,9 +2,33 @@ package com.jjbaksa.data.api
import retrofit2.http.GET
import com.jjbaksa.data.model.user.UserResp
+import okhttp3.MultipartBody
import retrofit2.Response
+import com.jjbaksa.domain.resp.user.PasswordAndNicknameReq
+import com.jjbaksa.domain.resp.user.WithdrawalReasonReq
+import retrofit2.http.Body
+import retrofit2.http.DELETE
+import retrofit2.http.Multipart
+import retrofit2.http.PATCH
+import retrofit2.http.POST
+import retrofit2.http.Part
interface AuthApi {
@GET("user/me")
suspend fun userMe(): Response
+ @PATCH("user/me")
+ suspend fun setUserNickname(
+ @Body item: PasswordAndNicknameReq
+ ): Response
+ @DELETE("user/me")
+ suspend fun deleteUser(): Response
+ @Multipart
+ @PATCH("user/profile")
+ suspend fun editUserProfileImage(
+ @Part profile: MultipartBody.Part
+ ): Response
+ @POST("user/withdraw-reason")
+ suspend fun saveWithdrawalReason(
+ @Body withdrawalReason: WithdrawalReasonReq
+ ): Response
}
diff --git a/data/src/main/java/com/jjbaksa/data/database/UserPreferences.kt b/data/src/main/java/com/jjbaksa/data/database/UserPreferences.kt
index b6e7bde9..f044cba0 100644
--- a/data/src/main/java/com/jjbaksa/data/database/UserPreferences.kt
+++ b/data/src/main/java/com/jjbaksa/data/database/UserPreferences.kt
@@ -2,6 +2,7 @@ package com.jjbaksa.data.database
import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
+import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
@@ -12,6 +13,9 @@ object PreferenceKeys {
val ACCESS_TOKEN = stringPreferencesKey("ACEESS_TOKEN")
val REFRESH_TOKEN = stringPreferencesKey("REFRESH_TOKEN")
val ACCOUNT = stringPreferencesKey("ACCOUNT")
+ val NICKNAME = stringPreferencesKey("NICKNAME")
+ val FOLLOWERS = intPreferencesKey("FOLLOWERS")
+ val IMAGE = stringPreferencesKey("IMAGE")
val PASSWORD = stringPreferencesKey("PASSWORD")
var AUTO_LOGIN = booleanPreferencesKey("AUTO_LOGIN")
val AUTH_PASSWORD_TOKEN = stringPreferencesKey("AUTH_PASSWORD_TOKEN")
diff --git a/data/src/main/java/com/jjbaksa/data/datasource/UserDataSource.kt b/data/src/main/java/com/jjbaksa/data/datasource/UserDataSource.kt
index 8ffe1e9a..48b71df3 100644
--- a/data/src/main/java/com/jjbaksa/data/datasource/UserDataSource.kt
+++ b/data/src/main/java/com/jjbaksa/data/datasource/UserDataSource.kt
@@ -8,6 +8,7 @@ import com.jjbaksa.domain.resp.user.LoginReq
import com.jjbaksa.domain.resp.user.PasswordAndNicknameReq
import com.jjbaksa.domain.resp.user.SignUpReq
import com.jjbaksa.domain.resp.user.SignUpResp
+import com.jjbaksa.domain.resp.user.WithdrawalReasonReq
import retrofit2.Response
interface UserDataSource {
@@ -19,15 +20,24 @@ interface UserDataSource {
suspend fun getPasswordVerificationCode(id: String, email: String): Response
suspend fun findAccount(email: String, code: String): Response
suspend fun findPassword(findPasswordReq: FindPasswordReq): Response
+ suspend fun saveWithdrawalReason(withdrawalReason: WithdrawalReasonReq): Response
+ suspend fun deleteUser(): Response
suspend fun setNewPassword(token: String, item: PasswordAndNicknameReq): Response
+ suspend fun setNewNickname(item: PasswordAndNicknameReq): Response
suspend fun saveAccessToken(accessToken: String)
suspend fun saveAccount(account: String)
+ suspend fun saveNickname(nickname: String)
+ suspend fun saveFollowers(followers: Int)
+ suspend fun saveProfileImage(image: String)
suspend fun savePassword(password: String)
suspend fun saveRefreshToken(refreshToken: String)
suspend fun saveAutoLogin(isAutoLogin: Boolean)
suspend fun saveAuthPasswordToken(passwordToken: String)
fun getAutoLoginFlag(): Boolean
- fun getAcount(): String
+ fun getAccount(): String
+ fun getNickname(): String
+ fun getFollowers(): Int
+ fun getProfileImage(): String
fun getPassword(): String
fun getAccessToken(): String
fun getAuthPasswordToken(): String
diff --git a/data/src/main/java/com/jjbaksa/data/datasource/local/UserLocalDataSource.kt b/data/src/main/java/com/jjbaksa/data/datasource/local/UserLocalDataSource.kt
index 1442737c..3e58e540 100644
--- a/data/src/main/java/com/jjbaksa/data/datasource/local/UserLocalDataSource.kt
+++ b/data/src/main/java/com/jjbaksa/data/datasource/local/UserLocalDataSource.kt
@@ -14,6 +14,7 @@ import com.jjbaksa.domain.resp.user.LoginReq
import com.jjbaksa.domain.resp.user.PasswordAndNicknameReq
import com.jjbaksa.domain.resp.user.SignUpReq
import com.jjbaksa.domain.resp.user.SignUpResp
+import com.jjbaksa.domain.resp.user.WithdrawalReasonReq
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
@@ -61,6 +62,18 @@ class UserLocalDataSource @Inject constructor(
TODO("Not yet implemented")
}
+ override suspend fun setNewNickname(item: PasswordAndNicknameReq): Response {
+ TODO("Not yet implemented")
+ }
+
+ override suspend fun saveWithdrawalReason(withdrawalReason: WithdrawalReasonReq): Response {
+ TODO("Not yet implemented")
+ }
+
+ override suspend fun deleteUser(): Response {
+ TODO("Not yet implemented")
+ }
+
override suspend fun saveAccessToken(accessToken: String) {
dataStore.edit {
it[PreferenceKeys.ACCESS_TOKEN] = accessToken
@@ -73,6 +86,24 @@ class UserLocalDataSource @Inject constructor(
}
}
+ override suspend fun saveNickname(nickname: String) {
+ dataStore.edit {
+ it[PreferenceKeys.NICKNAME] = nickname
+ }
+ }
+
+ override suspend fun saveFollowers(followers: Int) {
+ dataStore.edit {
+ it[PreferenceKeys.FOLLOWERS] = followers
+ }
+ }
+
+ override suspend fun saveProfileImage(image: String) {
+ dataStore.edit {
+ it[PreferenceKeys.IMAGE] = image
+ }
+ }
+
override suspend fun savePassword(password: String) {
dataStore.edit {
it[PreferenceKeys.PASSWORD] = password
@@ -103,12 +134,30 @@ class UserLocalDataSource @Inject constructor(
}
}
- override fun getAcount(): String {
+ override fun getAccount(): String {
return runBlocking {
dataStore.data.first()[PreferenceKeys.ACCOUNT] ?: ""
}
}
+ override fun getNickname(): String {
+ return runBlocking {
+ dataStore.data.first()[PreferenceKeys.NICKNAME] ?: ""
+ }
+ }
+
+ override fun getFollowers(): Int {
+ return runBlocking {
+ dataStore.data.first()[PreferenceKeys.FOLLOWERS] ?: 0
+ }
+ }
+
+ override fun getProfileImage(): String {
+ return runBlocking {
+ dataStore.data.first()[PreferenceKeys.IMAGE] ?: ""
+ }
+ }
+
override fun getPassword(): String {
return runBlocking {
dataStore.data.first()[PreferenceKeys.PASSWORD] ?: ""
diff --git a/data/src/main/java/com/jjbaksa/data/datasource/remote/UserRemoteDataSource.kt b/data/src/main/java/com/jjbaksa/data/datasource/remote/UserRemoteDataSource.kt
index 89eaa5a3..2c79af58 100644
--- a/data/src/main/java/com/jjbaksa/data/datasource/remote/UserRemoteDataSource.kt
+++ b/data/src/main/java/com/jjbaksa/data/datasource/remote/UserRemoteDataSource.kt
@@ -11,6 +11,8 @@ import com.jjbaksa.domain.resp.user.LoginReq
import com.jjbaksa.domain.resp.user.PasswordAndNicknameReq
import com.jjbaksa.domain.resp.user.SignUpReq
import com.jjbaksa.domain.resp.user.SignUpResp
+import com.jjbaksa.domain.resp.user.WithdrawalReasonReq
+import okhttp3.MultipartBody
import retrofit2.Response
import javax.inject.Inject
@@ -57,12 +59,33 @@ class UserRemoteDataSource @Inject constructor(
return noAuthApi.setNewPassword(token, item)
}
+ override suspend fun setNewNickname(item: PasswordAndNicknameReq): Response {
+ return authApi.setUserNickname(item)
+ }
+
+ override suspend fun saveWithdrawalReason(withdrawalReason: WithdrawalReasonReq): Response {
+ return authApi.saveWithdrawalReason(withdrawalReason)
+ }
+
+ override suspend fun deleteUser(): Response {
+ return authApi.deleteUser()
+ }
+
override suspend fun saveAccessToken(accessToken: String) {
}
override suspend fun saveAccount(account: String) {
}
+ override suspend fun saveNickname(nickname: String) {
+ }
+
+ override suspend fun saveFollowers(followers: Int) {
+ }
+
+ override suspend fun saveProfileImage(image: String) {
+ }
+
override suspend fun savePassword(password: String) {
}
@@ -78,12 +101,27 @@ class UserRemoteDataSource @Inject constructor(
suspend fun me(): Response {
return authApi.userMe()
}
+ suspend fun editUserProfileImage(profile: MultipartBody.Part): Response {
+ return authApi.editUserProfileImage(profile)
+ }
override fun getAutoLoginFlag(): Boolean {
return false
}
- override fun getAcount(): String {
+ override fun getAccount(): String {
+ return ""
+ }
+
+ override fun getNickname(): String {
+ return ""
+ }
+
+ override fun getFollowers(): Int {
+ return 0
+ }
+
+ override fun getProfileImage(): String {
return ""
}
diff --git a/data/src/main/java/com/jjbaksa/data/mapper/FormDataUtil.kt b/data/src/main/java/com/jjbaksa/data/mapper/FormDataUtil.kt
new file mode 100644
index 00000000..51e32438
--- /dev/null
+++ b/data/src/main/java/com/jjbaksa/data/mapper/FormDataUtil.kt
@@ -0,0 +1,109 @@
+package com.jjbaksa.data.mapper
+
+import android.annotation.SuppressLint
+import android.content.ContentResolver
+import android.net.Uri
+import android.provider.OpenableColumns
+import android.util.Log
+import okhttp3.MediaType
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.MultipartBody
+import okhttp3.RequestBody
+import okhttp3.RequestBody.Companion.asRequestBody
+import okio.BufferedSink
+import okio.source
+import java.io.File
+import java.net.URLConnection
+import kotlin.math.abs
+
+object FormDataUtil {
+ val secUnit = 60L
+ val milliSec = 1000L
+
+ fun getBody(key: String, value: Any): MultipartBody.Part {
+ return MultipartBody.Part.createFormData(key, value.toString())
+ }
+
+ fun getImageBody(key: String, uri: Uri): MultipartBody.Part {
+ try {
+ return getImageBody(key, File(uri.path))
+ } catch (e: Exception) {
+ Log.e("jdm_Tag", e.message.toString())
+ throw e
+ }
+ }
+
+ fun getImageBody(key: String, file: File): MultipartBody.Part {
+ return MultipartBody.Part.createFormData(
+ name = key,
+ filename = file.name,
+ body = file.asRequestBody(
+ URLConnection.guessContentTypeFromName(file.name).toMediaType()
+ )
+ )
+ }
+
+ fun getVideoBody(key: String, file: File): MultipartBody.Part {
+ return MultipartBody.Part.createFormData(
+ name = key,
+ filename = file.name,
+ body = file.asRequestBody("video/*".toMediaType())
+ )
+ }
+
+ @SuppressLint("Range")
+ fun Uri.asMultipart(
+ key: String = "multipartFile",
+ contentResolver: ContentResolver
+ ): MultipartBody.Part? {
+ return contentResolver.query(this, null, null, null, null)?.let {
+ it.use { cursor ->
+ if (cursor.moveToNext()) {
+ val displayName = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
+ val requestBody = object : RequestBody() {
+ override fun contentType(): MediaType? {
+ return contentResolver.getType(this@asMultipart)?.toMediaType()
+ }
+
+ override fun writeTo(sink: BufferedSink) {
+ sink.writeAll(
+ contentResolver.openInputStream(this@asMultipart)?.source()!!
+ )
+ }
+ }
+ MultipartBody.Part.createFormData(key, displayName, requestBody)
+ } else {
+ null
+ }
+ }
+ }
+ }
+
+ fun secondToStringHHMMWithUnit(timeS: Long, hourText: String, minuteText: String): String {
+ val timeArr = stringArrForTimeHHMMSS(timeS, false)
+ val bNegative = timeS < 0
+ val sb = StringBuilder()
+ if (bNegative) {
+ sb.append("-")
+ }
+
+ if (timeArr[0] > 0) {
+ sb.append(String.format("%d$hourText ", timeArr[0]))
+ }
+ sb.append(String.format("%d$minuteText", timeArr[1]))
+ return sb.toString()
+ }
+
+ fun stringArrForTimeHHMMSS(time: Long, isMillis: Boolean): List {
+ val absTimeMs = abs(time)
+ val totalSeconds = if (isMillis) {
+ absTimeMs / milliSec
+ } else {
+ absTimeMs
+ }
+ val seconds = totalSeconds % secUnit
+ val minutes = totalSeconds / secUnit % secUnit
+ val hours = totalSeconds / (secUnit * secUnit)
+ return listOf(hours, minutes, seconds)
+ }
+}
diff --git a/data/src/main/java/com/jjbaksa/data/model/user/UserCountResp.kt b/data/src/main/java/com/jjbaksa/data/model/user/UserCountResp.kt
index 416a40c7..dd2979f2 100644
--- a/data/src/main/java/com/jjbaksa/data/model/user/UserCountResp.kt
+++ b/data/src/main/java/com/jjbaksa/data/model/user/UserCountResp.kt
@@ -1,7 +1,12 @@
package com.jjbaksa.data.model.user
+import com.google.gson.annotations.SerializedName
+
data class UserCountResp(
+ @SerializedName("friendCount")
var friendCount: Int,
+ @SerializedName("id")
var id: Long,
+ @SerializedName("reviewCount")
var reviewCount: Int
)
diff --git a/data/src/main/java/com/jjbaksa/data/model/user/UserProfileResp.kt b/data/src/main/java/com/jjbaksa/data/model/user/UserProfileResp.kt
new file mode 100644
index 00000000..586f27f3
--- /dev/null
+++ b/data/src/main/java/com/jjbaksa/data/model/user/UserProfileResp.kt
@@ -0,0 +1,14 @@
+package com.jjbaksa.data.model.user
+
+import com.google.gson.annotations.SerializedName
+
+data class UserProfileResp(
+ @SerializedName("id")
+ var id: Int,
+ @SerializedName("originalName")
+ var originalName: String,
+ @SerializedName("path")
+ var path: String,
+ @SerializedName("url")
+ var url: String
+)
diff --git a/data/src/main/java/com/jjbaksa/data/model/user/UserResp.kt b/data/src/main/java/com/jjbaksa/data/model/user/UserResp.kt
index 28ef221e..6e35e35a 100644
--- a/data/src/main/java/com/jjbaksa/data/model/user/UserResp.kt
+++ b/data/src/main/java/com/jjbaksa/data/model/user/UserResp.kt
@@ -1,11 +1,22 @@
package com.jjbaksa.data.model.user
+import com.google.gson.annotations.SerializedName
+
data class UserResp(
+ @SerializedName("account")
var account: String,
+ @SerializedName("email")
var email: String,
+ @SerializedName("id")
var id: Long,
+ @SerializedName("nickname")
var nickname: String,
+ @SerializedName("oauthType")
var oauthType: String,
- var userCountResp: UserCountResp,
+ @SerializedName("profileImage")
+ var profileImage: UserProfileResp,
+ @SerializedName("userCountResponse")
+ var userCountResponse: UserCountResp,
+ @SerializedName("userType")
var userType: String
)
diff --git a/data/src/main/java/com/jjbaksa/data/repository/UserRepositoryImpl.kt b/data/src/main/java/com/jjbaksa/data/repository/UserRepositoryImpl.kt
index 82a7dbcc..d9248dfd 100644
--- a/data/src/main/java/com/jjbaksa/data/repository/UserRepositoryImpl.kt
+++ b/data/src/main/java/com/jjbaksa/data/repository/UserRepositoryImpl.kt
@@ -1,9 +1,10 @@
package com.jjbaksa.data.repository
-import android.util.Log
+import android.net.Uri
import com.jjbaksa.data.SUCCESS
import com.jjbaksa.data.datasource.local.UserLocalDataSource
import com.jjbaksa.data.datasource.remote.UserRemoteDataSource
+import com.jjbaksa.data.mapper.FormDataUtil
import com.jjbaksa.data.mapper.RespMapper
import com.jjbaksa.domain.base.ErrorType
import com.jjbaksa.domain.base.RespResult
@@ -15,6 +16,7 @@ import com.jjbaksa.domain.resp.user.SignUpReq
import com.jjbaksa.domain.resp.user.SignUpResp
import com.jjbaksa.domain.resp.user.FindPasswordReq
import com.jjbaksa.domain.resp.user.PasswordAndNicknameReq
+import com.jjbaksa.domain.resp.user.WithdrawalReasonReq
import javax.inject.Inject
class UserRepositoryImpl @Inject constructor(
@@ -43,7 +45,6 @@ class UserRepositoryImpl @Inject constructor(
isAutoLogin: Boolean,
onResult: (LoginResult) -> Unit
) {
-
val response = userRemoteDataSource.postLogin(LoginReq(account, password))
if (response != null) {
@@ -71,7 +72,7 @@ class UserRepositoryImpl @Inject constructor(
override suspend fun checkAuthEmail(email: String): FormatResp {
val result = userRemoteDataSource.checkAuthEmail(email)
return if (result.isSuccessful) {
- FormatResp(result.isSuccessful, null, result.code())
+ FormatResp(result.isSuccessful, "", result.code())
} else {
val errorBodyJson = result.errorBody()!!.string()
val errorBody = RespMapper.errorMapper(errorBodyJson)
@@ -79,18 +80,17 @@ class UserRepositoryImpl @Inject constructor(
}
}
- override suspend fun checkPassword(password: String): RespResult {
+ override suspend fun checkPassword(password: String): FormatResp {
val response = userRemoteDataSource.checkPassword(
"Bearer " + userLocalDataSource.getAccessToken(),
password
)
- Log.d("로그", "response : $response")
return if (response.isSuccessful && response.code() == 200) {
- RespResult.Success(response.isSuccessful)
+ FormatResp(response.isSuccessful, "", response.code())
} else {
val errorBodyJson = response.errorBody()!!.string()
val errorBody = RespMapper.errorMapper(errorBodyJson)
- RespResult.Error(ErrorType(errorBody.errorMessage, errorBody.code))
+ FormatResp(response.isSuccessful, errorBody.errorMessage, errorBody.code)
}
}
@@ -100,7 +100,7 @@ class UserRepositoryImpl @Inject constructor(
): FormatResp {
val response = userRemoteDataSource.getPasswordVerificationCode(id, email)
return if (response.isSuccessful && response.code() == 200) {
- FormatResp(response.isSuccessful, null, response.code())
+ FormatResp(response.isSuccessful, "", response.code())
} else {
val errorBodyJson = response.errorBody()!!.string()
val errorBody = RespMapper.errorMapper(errorBodyJson)
@@ -123,7 +123,7 @@ class UserRepositoryImpl @Inject constructor(
val response = userRemoteDataSource.findPassword(user)
return if (response.isSuccessful && response.code() == 200) {
userLocalDataSource.saveAuthPasswordToken(response.body().toString())
- FormatResp(response.isSuccessful, null, response.code())
+ FormatResp(response.isSuccessful, "", response.code())
} else {
val errorBodyJson = response.errorBody()!!.string()
val errorBody = RespMapper.errorMapper(errorBodyJson)
@@ -133,12 +133,26 @@ class UserRepositoryImpl @Inject constructor(
override suspend fun setNewPassword(password: String): FormatResp {
val item = PasswordAndNicknameReq(password, null)
+ val token = userLocalDataSource.getAuthPasswordToken().ifEmpty { userLocalDataSource.getAccessToken() }
val response = userRemoteDataSource.setNewPassword(
- "Bearer " + userLocalDataSource.getAuthPasswordToken(),
+ "Bearer $token",
item
)
return if (response.isSuccessful && response.code() == 200) {
- FormatResp(response.isSuccessful, null, response.code())
+ FormatResp(response.isSuccessful, "", response.code())
+ } else {
+ val errorBodyJson = response.errorBody()!!.string()
+ val errorBody = RespMapper.errorMapper(errorBodyJson)
+ FormatResp(response.isSuccessful, errorBody.errorMessage, response.code())
+ }
+ }
+
+ override suspend fun setNewNickname(nickname: String): FormatResp {
+ val item = PasswordAndNicknameReq(null, nickname)
+ val response = userRemoteDataSource.setNewNickname(item)
+ return if (response.isSuccessful && response.code() == 200) {
+ userLocalDataSource.saveNickname(nickname)
+ FormatResp(response.isSuccessful, "", response.code())
} else {
val errorBodyJson = response.errorBody()!!.string()
val errorBody = RespMapper.errorMapper(errorBodyJson)
@@ -148,8 +162,42 @@ class UserRepositoryImpl @Inject constructor(
override suspend fun me(): RespResult {
val response = userRemoteDataSource.me()
+ return if (response.isSuccessful) {
+ userLocalDataSource.saveNickname(response.body()?.nickname ?: "")
+ userLocalDataSource.saveFollowers(response.body()?.userCountResponse?.friendCount ?: 0)
+ userLocalDataSource.saveProfileImage(response.body()?.profileImage?.path ?: "")
+ RespResult.Success(response.isSuccessful)
+ } else {
+ val errorBodyJson = response.errorBody()!!.string()
+ val errorBody = RespMapper.errorMapper(errorBodyJson)
+ RespResult.Error(ErrorType(errorBody.errorMessage, errorBody.code))
+ }
+ }
+
+ override suspend fun editUserProfileImage(profile: String): RespResult {
+ val fileBody = FormDataUtil.getImageBody("multipartFile", Uri.parse(profile))
+ val response = userRemoteDataSource.editUserProfileImage(fileBody)
+ if (response.isSuccessful) {
+ return RespResult.Success(true)
+ } else {
+ return RespResult.Success(false)
+ }
+ }
+ override suspend fun saveWithdrawalReason(withdrawalReason: WithdrawalReasonReq): RespResult {
+ val response = userRemoteDataSource.saveWithdrawalReason(withdrawalReason)
return if (response.isSuccessful) {
+ RespResult.Success(true)
+ } else {
+ val errorBodyJson = response.errorBody()!!.string()
+ val errorBody = RespMapper.errorMapper(errorBodyJson)
+ RespResult.Error(ErrorType(errorBody.errorMessage, errorBody.code))
+ }
+ }
+
+ override suspend fun deleteUser(): RespResult {
+ val response = userRemoteDataSource.deleteUser()
+ return if (response.isSuccessful && response.code() == 204) {
RespResult.Success(response.isSuccessful)
} else {
val errorBodyJson = response.errorBody()!!.string()
@@ -163,10 +211,22 @@ class UserRepositoryImpl @Inject constructor(
}
override fun getAccount(): String {
- return userLocalDataSource.getAcount()
+ return userLocalDataSource.getAccount()
+ }
+
+ override fun getNickname(): String {
+ return userLocalDataSource.getNickname()
+ }
+
+ override fun getFollowers(): Int {
+ return userLocalDataSource.getFollowers()
+ }
+
+ override fun getProfileImage(): String {
+ return userLocalDataSource.getProfileImage()
}
- override fun getPasswrod(): String {
+ override fun getPassword(): String {
return userLocalDataSource.getPassword()
}
diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts
index f06e158b..4acf5c81 100644
--- a/domain/build.gradle.kts
+++ b/domain/build.gradle.kts
@@ -5,8 +5,8 @@ plugins {
}
java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = Versions.javaVersion
+ targetCompatibility = Versions.javaVersion
}
dependencies {
diff --git a/domain/src/main/java/com/jjbaksa/domain/repository/UserRepository.kt b/domain/src/main/java/com/jjbaksa/domain/repository/UserRepository.kt
index 580cc607..7af4734c 100644
--- a/domain/src/main/java/com/jjbaksa/domain/repository/UserRepository.kt
+++ b/domain/src/main/java/com/jjbaksa/domain/repository/UserRepository.kt
@@ -6,6 +6,7 @@ import com.jjbaksa.domain.resp.user.FormatResp
import com.jjbaksa.domain.resp.user.LoginResult
import com.jjbaksa.domain.resp.user.SignUpReq
import com.jjbaksa.domain.resp.user.SignUpResp
+import com.jjbaksa.domain.resp.user.WithdrawalReasonReq
interface UserRepository {
suspend fun postSignUp(signUpReq: SignUpReq): SignUpResp?
@@ -18,14 +19,21 @@ interface UserRepository {
)
suspend fun checkAuthEmail(email: String): FormatResp
- suspend fun checkPassword(password: String): RespResult
+ suspend fun checkPassword(password: String): FormatResp
suspend fun getPasswordVerificationCode(id: String, email: String): FormatResp
suspend fun findAccount(email: String, code: String): FormatResp
suspend fun findPassword(user: FindPasswordReq): FormatResp
suspend fun setNewPassword(password: String): FormatResp
+ suspend fun setNewNickname(nickname: String): FormatResp
suspend fun me(): RespResult
+ suspend fun editUserProfileImage(photo: String): RespResult
+ suspend fun saveWithdrawalReason(withdrawalReason: WithdrawalReasonReq): RespResult
+ suspend fun deleteUser(): RespResult
fun getAutoLoginFlag(): Boolean
fun getAccount(): String
- fun getPasswrod(): String
+ fun getNickname(): String
+ fun getFollowers(): Int
+ fun getProfileImage(): String
+ fun getPassword(): String
fun getAccessToken(): String
}
diff --git a/domain/src/main/java/com/jjbaksa/domain/resp/user/FormatResp.kt b/domain/src/main/java/com/jjbaksa/domain/resp/user/FormatResp.kt
index c1c11a39..d2a5dedd 100644
--- a/domain/src/main/java/com/jjbaksa/domain/resp/user/FormatResp.kt
+++ b/domain/src/main/java/com/jjbaksa/domain/resp/user/FormatResp.kt
@@ -2,6 +2,6 @@ package com.jjbaksa.domain.resp.user
data class FormatResp(
val isSuccess: Boolean,
- val msg: String?,
+ val msg: String,
val code: Int
)
diff --git a/domain/src/main/java/com/jjbaksa/domain/resp/user/WithdrawalReasonReq.kt b/domain/src/main/java/com/jjbaksa/domain/resp/user/WithdrawalReasonReq.kt
new file mode 100644
index 00000000..178f8aab
--- /dev/null
+++ b/domain/src/main/java/com/jjbaksa/domain/resp/user/WithdrawalReasonReq.kt
@@ -0,0 +1,6 @@
+package com.jjbaksa.domain.resp.user
+
+data class WithdrawalReasonReq(
+ val reason: String,
+ val discomfort: String
+)
diff --git a/domain/src/main/java/com/jjbaksa/domain/resp/user/WithdrawalReasonResp.kt b/domain/src/main/java/com/jjbaksa/domain/resp/user/WithdrawalReasonResp.kt
new file mode 100644
index 00000000..6473bd7e
--- /dev/null
+++ b/domain/src/main/java/com/jjbaksa/domain/resp/user/WithdrawalReasonResp.kt
@@ -0,0 +1,6 @@
+package com.jjbaksa.domain.resp.user
+
+data class WithdrawalReasonResp(
+ val isSuccess: Boolean,
+ val message: String?
+)
diff --git a/image_selector/src/main/java/com/example/imageselector/gallery/GalleryActivity.kt b/image_selector/src/main/java/com/example/imageselector/gallery/GalleryActivity.kt
index 73e9dd83..6084a3f3 100644
--- a/image_selector/src/main/java/com/example/imageselector/gallery/GalleryActivity.kt
+++ b/image_selector/src/main/java/com/example/imageselector/gallery/GalleryActivity.kt
@@ -4,6 +4,7 @@ import android.Manifest
import android.content.Intent
import android.graphics.Color
import android.os.Build
+import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
@@ -11,6 +12,7 @@ import androidx.recyclerview.widget.GridLayoutManager
import com.example.imageselector.R
import com.example.imageselector.base.BaseActivity
import com.example.imageselector.databinding.ActivityGalleryBinding
+import com.example.imageselector.model.Image
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
@@ -20,11 +22,9 @@ class GalleryActivity : BaseActivity() {
val viewModel: GalleryViewModel by viewModels()
var maxNum = 10
private val galleryAdapter: GalleryAdapter by lazy {
- GalleryAdapter(this, viewModel.getSelectedImageList(), viewModel.getUriArr(), maxNum) {
- viewModel.selectImage(viewModel.getUriArr()[it])
- galleryAdapter.notifyDataSetChanged()
- }
+ GalleryAdapter(this)
}
+
private val requestPermission =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
when (isGranted) {
@@ -49,23 +49,22 @@ class GalleryActivity : BaseActivity() {
}
}
- private fun sendImageData() {
- val intent = Intent()
- val list = ArrayList()
- list.addAll(viewModel.getSelectedImageUri())
- intent.putStringArrayListExtra("images", list)
- setResult(RESULT_OK, intent)
- finish()
- }
-
private fun getAllPhotos() {
viewModel.getAllPhotos()
+ galleryAdapter.submitList(viewModel.getSelectedImages())
with(binding) {
recyclerView.layoutManager = GridLayoutManager(this@GalleryActivity, 3)
recyclerView.adapter = galleryAdapter
}
}
+ override fun initView() {
+ checkPermission()
+ binding.viewmodel = viewModel
+ binding.lifecycleOwner = this
+ getIntentData()
+ }
+
private fun checkPermission() {
val permissionList = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
@@ -78,14 +77,17 @@ class GalleryActivity : BaseActivity() {
}
}
- override fun initView() {
- checkPermission()
- binding.viewmodel = viewModel
- binding.lifecycleOwner = this
- getIntentData()
+ private fun getIntentData() {
+ if (intent.hasExtra("limit")) {
+ maxNum = intent.getIntExtra("limit", 10)
+ }
}
override fun subscribe() {
+ observeData()
+ }
+
+ private fun observeData() {
viewModel.currentValue.observe(this) {
if (it >= maxNum) {
binding.textViewSelectedPictureCount.setTextColor(Color.parseColor("#c4c4c4"))
@@ -96,19 +98,59 @@ class GalleryActivity : BaseActivity() {
}
override fun initEvent() {
- with(binding) {
- textViewSendSelectedImage.setOnClickListener {
- sendImageData()
- }
- imageButtonPreviousArrow.setOnClickListener {
- finish()
+ backToPreviousScreen()
+ selectImages()
+ sendToImage()
+ }
+
+ private fun backToPreviousScreen() {
+ binding.imageButtonPreviousArrow.setOnClickListener {
+ finish()
+ }
+ }
+
+ private fun selectImages() {
+ galleryAdapter.onClickImageListener = object : GalleryAdapter.OnClickImageListener {
+ override fun onImageClick(image: Image, position: Int) {
+ if (viewModel.getSelectedImageUri().size < maxNum) {
+ updateImages(position)
+ } else {
+ if (viewModel.getSelectedImageUri().contains(image.uri)) {
+ updateImages(position)
+ }
+ }
}
}
}
- fun getIntentData() {
- if (intent.hasExtra("limit")) {
- maxNum = intent.getIntExtra("limit", 10)
+ private fun updateImages(position: Int) {
+ viewModel.selectImage(viewModel.getUriArr()[position])
+ val updatedImages =
+ viewModel.getSelectedImages().map { Image(it.uri, it.index, it.isSelected) }
+ galleryAdapter.submitList(updatedImages)
+ }
+
+ private fun sendToImage() {
+ binding.textViewSendSelectedImage.setOnClickListener {
+ sendImageData()
+ }
+ }
+
+ private fun sendImageData() {
+ val intent = Intent()
+ val list = ArrayList()
+ list.addAll(viewModel.getSelectedImageUri())
+ if (list.isNullOrEmpty()) {
+ Toast.makeText(this, "이미지를 선택해주세요.", Toast.LENGTH_SHORT).show()
+ } else {
+ intent.putStringArrayListExtra("images", list)
+ setResult(RESULT_OK, intent)
+ finish()
}
}
+
+ override fun onDestroy() {
+ viewModel.clearData()
+ super.onDestroy()
+ }
}
diff --git a/image_selector/src/main/java/com/example/imageselector/gallery/GalleryAdapter.kt b/image_selector/src/main/java/com/example/imageselector/gallery/GalleryAdapter.kt
index b69da504..4dad8b9b 100644
--- a/image_selector/src/main/java/com/example/imageselector/gallery/GalleryAdapter.kt
+++ b/image_selector/src/main/java/com/example/imageselector/gallery/GalleryAdapter.kt
@@ -1,70 +1,64 @@
package com.example.imageselector.gallery
import android.content.Context
+import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.LinearLayout
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.imageselector.model.Image
import com.example.imageselector.databinding.ItemLayoutBinding
class GalleryAdapter(
- val context: Context,
- private val imageList: ArrayList,
- private val uriArr: ArrayList,
- private val maxNum: Int,
- val onClick: (Int) -> Unit,
-) : RecyclerView.Adapter() {
- private val selectedImages = ArrayList()
+ val context: Context
+) : ListAdapter(diffUtil){
- class ViewHolder(
- private val binding: ItemLayoutBinding,
- ) :
- RecyclerView.ViewHolder(binding.root) {
- val galleryView = binding.galleryView
- val item = binding.item
+ var onClickImageListener: OnClickImageListener? = null
- fun bind(image: Image) {
- binding.selectedImage = image
- }
+ interface OnClickImageListener {
+ fun onImageClick(image: Image, position: Int)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val binding = ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
- return ViewHolder(binding)
+ return ViewHolder(ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val display = context.resources.displayMetrics
- holder.galleryView.layoutParams =
- LinearLayout.LayoutParams(display.widthPixels / 3 - 6, display.widthPixels / 3 - 6)
+ holder.bind(currentList[position], position)
+ }
- Glide.with(context)
- .load(uriArr[position])
- .into(holder.galleryView)
+ inner class ViewHolder(private val binding: ItemLayoutBinding): RecyclerView.ViewHolder(binding.root) {
+ private val display = context.resources.displayMetrics
+ fun bind(image: Image, position: Int) {
+ binding.selectedImage = image
- holder.itemView.setOnClickListener {
- if (selectedImages.size < maxNum) {
- if (!selectedImages.contains(position)) {
- selectedImages.add(position)
- onClick(position)
- } else {
- selectedImages.remove(position)
- onClick(position)
- }
- } else {
- if (selectedImages.contains(position)) {
- selectedImages.remove(position)
- onClick(position)
- }
+ binding.galleryView.also { galleryImage ->
+ galleryImage.layoutParams =
+ LinearLayout.LayoutParams(display.widthPixels / 3 - 6, display.widthPixels / 3 - 6)
+ Glide.with(context)
+ .load(image.uri)
+ .into(galleryImage)
+ }
+
+ binding.root.setOnClickListener {
+ onClickImageListener?.onImageClick(image, position)
}
- }
- holder.bind(imageList[position])
+ }
}
+ companion object {
+ val diffUtil = object: DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: Image, newItem: Image): Boolean {
+ return oldItem === newItem
+ }
- override fun getItemCount(): Int {
- return imageList.size
+ override fun areContentsTheSame(oldItem: Image, newItem: Image): Boolean {
+ return oldItem == newItem
+ }
+ }
}
}
+
diff --git a/image_selector/src/main/java/com/example/imageselector/gallery/GalleryViewModel.kt b/image_selector/src/main/java/com/example/imageselector/gallery/GalleryViewModel.kt
index b20d1258..b5c6f802 100644
--- a/image_selector/src/main/java/com/example/imageselector/gallery/GalleryViewModel.kt
+++ b/image_selector/src/main/java/com/example/imageselector/gallery/GalleryViewModel.kt
@@ -14,9 +14,8 @@ import javax.inject.Inject
class GalleryViewModel @Inject constructor(
private val repository: ImageRepository,
) : ViewModel() {
- val currentValue: LiveData
- get() = _currentValue
private val _currentValue = MutableLiveData()
+ val currentValue: LiveData get() = _currentValue
fun getAllPhotos() {
repository.getAllPhotos()
@@ -39,15 +38,17 @@ class GalleryViewModel @Inject constructor(
return repository.getUriArr()
}
- fun getSelectedImageList(): ArrayList {
- return repository.getSelectedImageList()
+ fun getSelectedImages(): ArrayList {
+ return repository.getSelectedImages()
}
-}
-object DataBindingAdapterUtil {
- @JvmStatic
- @BindingAdapter("select")
- fun select(view: View, b: Boolean) {
- view.isSelected = b
+ fun clearData() {
+ with(repository) {
+ getUriArr().clear()
+ getSelectedImages().clear()
+ getSelectedImageUri().clear()
+ }
}
}
+
+
diff --git a/image_selector/src/main/java/com/example/imageselector/repository/ImageRepository.kt b/image_selector/src/main/java/com/example/imageselector/repository/ImageRepository.kt
index 7d43b789..852bf812 100644
--- a/image_selector/src/main/java/com/example/imageselector/repository/ImageRepository.kt
+++ b/image_selector/src/main/java/com/example/imageselector/repository/ImageRepository.kt
@@ -8,5 +8,5 @@ interface ImageRepository {
fun refreshSelectList()
fun getSelectedImageUri(): ArrayList
fun getUriArr(): ArrayList
- fun getSelectedImageList(): ArrayList
+ fun getSelectedImages(): ArrayList
}
diff --git a/image_selector/src/main/java/com/example/imageselector/repository/ImageRepositoryImpl.kt b/image_selector/src/main/java/com/example/imageselector/repository/ImageRepositoryImpl.kt
index 165fc8b1..d0a653d6 100644
--- a/image_selector/src/main/java/com/example/imageselector/repository/ImageRepositoryImpl.kt
+++ b/image_selector/src/main/java/com/example/imageselector/repository/ImageRepositoryImpl.kt
@@ -2,6 +2,7 @@ package com.example.imageselector.repository
import android.content.ContentResolver
import android.provider.MediaStore
+import android.util.Log
import com.example.imageselector.model.Image
import javax.inject.Inject
@@ -9,7 +10,7 @@ class ImageRepositoryImpl @Inject constructor(
private val contentResolver: ContentResolver,
) : ImageRepository {
- private val selectedImage = ArrayList()
+ private val selectedImages = ArrayList()
private val selectedImageUri = ArrayList()
private val uriArr = ArrayList()
@@ -21,7 +22,6 @@ class ImageRepositoryImpl @Inject constructor(
null,
MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC"
)
- val imageList = ArrayList()
if (cursor != null) {
while (cursor.moveToNext()) {
val uri =
@@ -31,8 +31,7 @@ class ImageRepositoryImpl @Inject constructor(
cursor.close()
}
for (uri in uriArr) {
- selectedImage.add(Image(uri, 0, false))
- imageList.add(Image(uri, 0, false))
+ selectedImages.add(Image(uri, 0, false))
}
}
@@ -46,14 +45,14 @@ class ImageRepositoryImpl @Inject constructor(
}
override fun refreshSelectList() {
- for (data in selectedImage) {
+ for (data in selectedImages) {
data.index = 0
data.isSelected = false
}
for (i in 0 until selectedImageUri.size) {
val path = selectedImageUri[i]
- for (data in selectedImage) {
+ for (data in selectedImages) {
if (data.uri.equals(path)) {
data.index = i + 1
data.isSelected = true
@@ -71,7 +70,7 @@ class ImageRepositoryImpl @Inject constructor(
return uriArr
}
- override fun getSelectedImageList(): ArrayList {
- return selectedImage
+ override fun getSelectedImages(): ArrayList {
+ return selectedImages
}
}
diff --git a/image_selector/src/main/java/com/example/imageselector/utils/DataBindingAdapter.kt b/image_selector/src/main/java/com/example/imageselector/utils/DataBindingAdapter.kt
new file mode 100644
index 00000000..f7cf0ff2
--- /dev/null
+++ b/image_selector/src/main/java/com/example/imageselector/utils/DataBindingAdapter.kt
@@ -0,0 +1,12 @@
+package com.example.imageselector.utils
+
+import android.view.View
+import androidx.databinding.BindingAdapter
+
+object DataBindingAdapterUtil {
+ @JvmStatic
+ @BindingAdapter("select")
+ fun select(view: View, b: Boolean) {
+ view.isSelected = b
+ }
+}
diff --git a/image_selector/src/main/res/layout/item_layout.xml b/image_selector/src/main/res/layout/item_layout.xml
index da7f62d3..d48de532 100644
--- a/image_selector/src/main/res/layout/item_layout.xml
+++ b/image_selector/src/main/res/layout/item_layout.xml
@@ -7,6 +7,7 @@
+