Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] 계정관리, 이용약관 #105

Merged
merged 11 commits into from
Sep 7, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.polzzak_android.presentation.common.item

import com.polzzak_android.R
import com.polzzak_android.databinding.ItemFullLoadingBinding
import com.polzzak_android.presentation.common.util.BindableItem

class FullLoadingItem : BindableItem<ItemFullLoadingBinding>() {
override val layoutRes: Int = R.layout.item_full_loading

override fun areItemsTheSame(other: BindableItem<*>): Boolean = other is FullLoadingItem

override fun areContentsTheSame(other: BindableItem<*>): Boolean = other is FullLoadingItem

override fun bind(binding: ItemFullLoadingBinding, position: Int) {
//do nothing
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.polzzak_android.presentation.common.util

import android.content.Context
import android.util.DisplayMetrics
import java.time.Duration
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.Period
import java.time.format.DateTimeFormatter

const val SERVER_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS"
Expand All @@ -31,4 +31,22 @@ fun LocalDateTime.getRemainingSeconds(): Int {
.between(LocalDateTime.now(), endTime)
.seconds
.toInt()
}
}

/**
* 날짜 규칙
* 3달 미만의 공지: O월.O일 (ex. 06.24)
* 3개월 이상 1년 미만의 공지: O개월 전 (ex. 3개월 전 ~ 11개월 전)
* 1년 이상이 지난 공지: 1년 단위로 카운팅(ex. 1년 전, 2년 전)
*/
fun LocalDate.toPublishedDateString(): String {
val nowDate = LocalDate.now()
val diff = Period.between(this, nowDate)
val getDateStr = { date: Int -> String.format("%02d", date) }
return when {
this.isAfter(nowDate.minusMonths(3)) -> "${getDateStr(this.monthValue)}.${getDateStr(this.dayOfMonth)}"
this.isBefore(nowDate.minusYears(1)) || this.isEqual(nowDate.minusYears(1)) -> "${diff.years}년 전"
else -> "${diff.months}개월 전"
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@ class PermissionManager(private val activity: AppCompatActivity) {
permission
) != PackageManager.PERMISSION_GRANTED
}) return true

val dialogTitleSpannable = SpannableBuilder.build(activity) {
span(text = dialogTitle, textColor = R.color.gray_700, style = R.style.subtitle_18_600)
}
CommonDialogHelper.getInstance(
content = CommonDialogModel(
type = DialogStyleType.ALERT,
content = CommonDialogContent(title = dialogTitle),
content = CommonDialogContent(title = dialogTitleSpannable),
button = CommonButtonModel(
buttonCount = ButtonCount.TWO,
negativeButtonText = activity.getString(R.string.permission_manager_dialog_btn_negative_text),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import com.polzzak_android.presentation.common.model.ModelState
import com.polzzak_android.presentation.common.util.PermissionManager
import com.polzzak_android.presentation.common.util.getPermissionManagerOrNull
import com.polzzak_android.presentation.common.util.hideKeyboard
import com.polzzak_android.presentation.feature.term.TermDetailFragment
import com.polzzak_android.presentation.feature.term.model.TermType
import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
import javax.inject.Inject
Expand Down Expand Up @@ -240,35 +242,19 @@ class SignUpFragment : BaseFragment<FragmentSignupBinding>() {
}
ivBtnServiceDetail.setOnClickListener {
val detailDataBundle = Bundle().apply {
putString(
SignUpTermDetailFragment.ARGUMENT_TITLE_KEY,
getString(R.string.signup_terms_of_service_detail_service_title)
)
//TODO 약관 url 추가
putString(
SignUpTermDetailFragment.ARGUMENT_URL_KEY,
"http://google.co.kr"
)
putParcelable(TermDetailFragment.ARGUMENT_TYPE_KEY, TermType.SERVICE)
}
findNavController().navigate(
R.id.action_signUpFragment_to_signUpTermDetailFragment,
R.id.action_signUpFragment_to_termDetailFragment,
detailDataBundle
)
}
ivBtnPrivacyDetail.setOnClickListener {
val detailDataBundle = Bundle().apply {
putString(
SignUpTermDetailFragment.ARGUMENT_TITLE_KEY,
getString(R.string.signup_terms_of_service_detail_privacy_title)
)
//TODO 약관 url 추가
putString(
SignUpTermDetailFragment.ARGUMENT_URL_KEY,
"http://naver.com"
)
putParcelable(TermDetailFragment.ARGUMENT_TYPE_KEY, TermType.PRIVACY)
}
findNavController().navigate(
R.id.action_signUpFragment_to_signUpTermDetailFragment,
R.id.action_signUpFragment_to_termDetailFragment,
detailDataBundle
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package com.polzzak_android.presentation.feature.myPage.accountmanagement

import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import com.polzzak_android.R
import com.polzzak_android.databinding.FragmentMyAccountDeleteBinding
import com.polzzak_android.presentation.common.model.ButtonCount
import com.polzzak_android.presentation.common.model.CommonButtonModel
import com.polzzak_android.presentation.common.model.ModelState
import com.polzzak_android.presentation.common.util.SpannableBuilder
import com.polzzak_android.presentation.component.dialog.CommonDialogContent
import com.polzzak_android.presentation.component.dialog.CommonDialogHelper
import com.polzzak_android.presentation.component.dialog.CommonDialogModel
import com.polzzak_android.presentation.component.dialog.DialogStyleType
import com.polzzak_android.presentation.component.dialog.OnButtonClickListener
import com.polzzak_android.presentation.component.toolbar.ToolbarData
import com.polzzak_android.presentation.component.toolbar.ToolbarHelper
import com.polzzak_android.presentation.feature.myPage.accountmanagement.MyAccountManagementFragment.Companion.ARGUMENT_NICKNAME_KEY
import com.polzzak_android.presentation.feature.myPage.accountmanagement.base.BaseMyAccountFragment
import timber.log.Timber

class MyAccountDeleteFragment : BaseMyAccountFragment<FragmentMyAccountDeleteBinding>() {
override val layoutResId: Int = R.layout.fragment_my_account_delete

private val myAccountDeleteViewModel by viewModels<MyAccountDeleteViewModel>()

private var currentDialog: DialogFragment? = null

override fun initView() {
super.initView()
initToolbar()
with(binding) {
val nickName = arguments?.getString(ARGUMENT_NICKNAME_KEY) ?: ""
tvTitle.text = getString(R.string.my_account_management_delete_title, nickName)
with(inMenuDeleteLink) {
tvContent.text =
getText(R.string.my_account_management_delete_menu_delete_link)
root.setOnClickListener {
myAccountDeleteViewModel.toggleDeleteLink()
}
}
with(inMenuDeletePoint) {
tvContent.text =
getText(R.string.my_account_management_delete_menu_delete_point)
root.setOnClickListener {
myAccountDeleteViewModel.toggleDeletePoint()
}
}
with(inMenuDeleteSocialAccountData) {
tvContent.text =
getText(R.string.my_account_management_delete_menu_delete_social_account_data)
root.setOnClickListener {
myAccountDeleteViewModel.toggleDeleteSocialAccountData()
}
}
with(inMenuDeleteStampAndCoupon) {
tvContent.text =
getText(R.string.my_account_management_delete_menu_delete_stamp_and_coupon)
root.setOnClickListener {
myAccountDeleteViewModel.toggleDeleteStampAndCoupon()
}
}
tvBtnDeleteAccount.setOnClickListener {
val context = context ?: return@setOnClickListener
val dialogTitleSpannable = SpannableBuilder.build(context) {
span(
text = getString(R.string.my_account_management_delete_dialog_title),
style = R.style.subtitle_18_600,
textColor = R.color.gray_700
)
}
val dialog = CommonDialogHelper.getInstance(
content = CommonDialogModel(
type = DialogStyleType.ALERT,
content = CommonDialogContent(title = dialogTitleSpannable),
button = CommonButtonModel(
buttonCount = ButtonCount.TWO,
positiveButtonText = getString(R.string.my_account_management_delete_dialog_btn_positive),
negativeButtonText = getString(R.string.my_account_management_delete_dialog_btn_negative)
)
),
onConfirmListener = {
object : OnButtonClickListener {
override fun setBusinessLogic() {
myAccountDeleteViewModel.deleteAccount()
}

override fun getReturnValue(value: Any) {
//do nothing
}
}
}
)
showDialog(dialogFragment = dialog)
}
}
}

private fun initToolbar() {
ToolbarHelper(
data = ToolbarData(
popStack = findNavController(),
titleText = getString(R.string.my_account_management)
),
toolbar = binding.inToolbar
).set()
}

override fun initObserver() {
super.initObserver()
myAccountDeleteViewModel.myAccountMenuLiveData.observe(viewLifecycleOwner) {
with(binding) {
inMenuDeleteLink.ivBtnCheck.isSelected = it.isCheckedDeleteLink
inMenuDeletePoint.ivBtnCheck.isSelected = it.isCheckedDeletePoint
inMenuDeleteSocialAccountData.ivBtnCheck.isSelected =
it.isCheckedDeleteSocialAccountData
inMenuDeleteStampAndCoupon.ivBtnCheck.isSelected = it.isCheckedDeleteStampAndCoupon
tvBtnDeleteAccount.isEnabled = it.isAllChecked()
}
}

myAccountDeleteViewModel.deleteAccountLiveData.observe(viewLifecycleOwner) {
val context = context ?: return@observe
when (it) {
is ModelState.Loading -> {
val dialogTitleSpannable = SpannableBuilder.build(context) {
span(
text = getString(R.string.my_account_management_delete_dialog_title),
style = R.style.subtitle_18_600,
textColor = R.color.gray_700
)
}
val loadingDialog = CommonDialogHelper.getInstance(
content = CommonDialogModel(
type = DialogStyleType.LOADING,
content = CommonDialogContent(title = dialogTitleSpannable),
button = CommonButtonModel(ButtonCount.ZERO)
)
)
showDialog(dialogFragment = loadingDialog)
}

is ModelState.Success -> {
dismissCurrentDialog()
Timber.d("회원탈퇴")
findRootNavigationOwner()?.backToTheLoginFragment()
}

is ModelState.Error -> {
//TODO error handling
}
}
}
}

private fun showDialog(dialogFragment: DialogFragment) {
currentDialog?.dismiss()
currentDialog = dialogFragment
dialogFragment.show(childFragmentManager, null)
}

private fun dismissCurrentDialog() {
currentDialog?.dismiss()
currentDialog = null
}

override fun onPause() {
super.onPause()
currentDialog?.dismiss()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.polzzak_android.presentation.feature.myPage.accountmanagement

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.polzzak_android.presentation.common.model.ModelState
import com.polzzak_android.presentation.feature.myPage.accountmanagement.model.MyAccountDeleteMenuModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class MyAccountDeleteViewModel : ViewModel() {
private val _myAccountMenuLiveData = MutableLiveData<MyAccountDeleteMenuModel>()
val myAccountMenuLiveData: LiveData<MyAccountDeleteMenuModel> = _myAccountMenuLiveData

private val _deleteAccountLiveData = MutableLiveData<ModelState<Unit>>()
val deleteAccountLiveData: LiveData<ModelState<Unit>> = _deleteAccountLiveData
private var deleteAccountJob: Job? = null

fun toggleDeleteSocialAccountData() {
_myAccountMenuLiveData.value =
(myAccountMenuLiveData.value ?: MyAccountDeleteMenuModel()).run {
copy(isCheckedDeleteSocialAccountData = !isCheckedDeleteSocialAccountData)
}
}

fun toggleDeleteLink() {
_myAccountMenuLiveData.value =
(myAccountMenuLiveData.value ?: MyAccountDeleteMenuModel()).run {
copy(isCheckedDeleteLink = !isCheckedDeleteLink)
}
}

fun toggleDeletePoint() {
_myAccountMenuLiveData.value =
(myAccountMenuLiveData.value ?: MyAccountDeleteMenuModel()).run {
copy(isCheckedDeletePoint = !isCheckedDeletePoint)
}
}

fun toggleDeleteStampAndCoupon() {
_myAccountMenuLiveData.value =
(myAccountMenuLiveData.value ?: MyAccountDeleteMenuModel()).run {
copy(isCheckedDeleteStampAndCoupon = !isCheckedDeleteStampAndCoupon)
}
}

fun deleteAccount() {
if (deleteAccountJob?.isCompleted == false) return
deleteAccountJob = viewModelScope.launch {
//TODO 회원탈퇴 API 호출
_deleteAccountLiveData.value = ModelState.Loading()
delay(2000)
//onSuccess
_deleteAccountLiveData.value = ModelState.Success(Unit)
}

}
}
Loading