fix(mypage): 기능 버튼 배치와 쿠폰 분기를 정리한다
This commit is contained in:
@@ -4,11 +4,15 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.webkit.URLUtil
|
import android.webkit.URLUtil
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.load
|
||||||
@@ -20,10 +24,12 @@ import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
|||||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
import kr.co.vividnext.sodalive.common.Constants
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
import kr.co.vividnext.sodalive.common.FunctionButtonHelper
|
import kr.co.vividnext.sodalive.common.FunctionButtonHelper
|
||||||
|
import kr.co.vividnext.sodalive.common.GridSpacingItemDecoration
|
||||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||||
import kr.co.vividnext.sodalive.databinding.FragmentMyBinding
|
import kr.co.vividnext.sodalive.databinding.FragmentMyBinding
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemFunctionButtonBinding
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
@@ -52,10 +58,15 @@ import org.koin.android.ext.android.inject
|
|||||||
@UnstableApi
|
@UnstableApi
|
||||||
class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflate) {
|
class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflate) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val FUNCTION_BUTTON_SPAN_COUNT = 4
|
||||||
|
}
|
||||||
|
|
||||||
private val viewModel: MyPageViewModel by inject()
|
private val viewModel: MyPageViewModel by inject()
|
||||||
private val recentContentViewModel: RecentContentViewModel by inject()
|
private val recentContentViewModel: RecentContentViewModel by inject()
|
||||||
|
|
||||||
private lateinit var loadingDialog: LoadingDialog
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
private val functionButtonAdapter = FunctionButtonAdapter()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@@ -187,6 +198,7 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
|||||||
binding.llProfileLoginContainer.visibility = View.GONE
|
binding.llProfileLoginContainer.visibility = View.GONE
|
||||||
|
|
||||||
binding.llFunctionButtonGrid.visibility = View.VISIBLE
|
binding.llFunctionButtonGrid.visibility = View.VISIBLE
|
||||||
|
setupFunctionButtonGrid()
|
||||||
|
|
||||||
binding.ivSettings.setOnClickListener {
|
binding.ivSettings.setOnClickListener {
|
||||||
startActivity(
|
startActivity(
|
||||||
@@ -239,84 +251,6 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnStorage.root,
|
|
||||||
iconRes = R.drawable.ic_my_storage,
|
|
||||||
title = getString(R.string.screen_my_storage)
|
|
||||||
) {
|
|
||||||
startActivity(
|
|
||||||
Intent(
|
|
||||||
requireContext(),
|
|
||||||
AudioContentBoxActivity::class.java
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnBlockList.root,
|
|
||||||
iconRes = R.drawable.ic_my_block,
|
|
||||||
title = getString(R.string.screen_my_block_list)
|
|
||||||
) {
|
|
||||||
startActivity(
|
|
||||||
Intent(
|
|
||||||
requireContext(),
|
|
||||||
BlockMemberActivity::class.java
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnMorningCall.root,
|
|
||||||
iconRes = R.drawable.ic_my_alarm,
|
|
||||||
title = getString(R.string.screen_my_morning_call)
|
|
||||||
) {
|
|
||||||
startActivity(
|
|
||||||
Intent(
|
|
||||||
requireActivity(),
|
|
||||||
AlarmListActivity::class.java
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnNotice.root,
|
|
||||||
iconRes = R.drawable.ic_my_notice,
|
|
||||||
title = getString(R.string.screen_my_notice)
|
|
||||||
) {
|
|
||||||
startActivity(
|
|
||||||
Intent(
|
|
||||||
requireActivity(),
|
|
||||||
NoticeActivity::class.java
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnEvent.root,
|
|
||||||
iconRes = R.drawable.ic_my_event,
|
|
||||||
title = getString(R.string.screen_my_event)
|
|
||||||
) {
|
|
||||||
startActivity(
|
|
||||||
Intent(
|
|
||||||
requireActivity(),
|
|
||||||
EventActivity::class.java
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnCustomerService.root,
|
|
||||||
iconRes = R.drawable.ic_my_service_center,
|
|
||||||
title = getString(R.string.screen_my_customer_service)
|
|
||||||
) {
|
|
||||||
startActivity(
|
|
||||||
Intent(
|
|
||||||
requireActivity(),
|
|
||||||
ServiceCenterActivity::class.java
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SharedPreferenceManager.role == MemberRole.CREATOR.name) {
|
if (SharedPreferenceManager.role == MemberRole.CREATOR.name) {
|
||||||
binding.tvMyChannel.visibility = View.VISIBLE
|
binding.tvMyChannel.visibility = View.VISIBLE
|
||||||
binding.tvMyChannel.setOnClickListener {
|
binding.tvMyChannel.setOnClickListener {
|
||||||
@@ -335,6 +269,8 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
|||||||
} else {
|
} else {
|
||||||
binding.tvMyChannel.visibility = View.GONE
|
binding.tvMyChannel.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateFunctionButtons()
|
||||||
} else {
|
} else {
|
||||||
binding.ivSettings.visibility = View.GONE
|
binding.ivSettings.visibility = View.GONE
|
||||||
binding.llFunctionButtonGrid.visibility = View.GONE
|
binding.llFunctionButtonGrid.visibility = View.GONE
|
||||||
@@ -380,29 +316,6 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.myPageLiveData.observe(viewLifecycleOwner) {
|
viewModel.myPageLiveData.observe(viewLifecycleOwner) {
|
||||||
val isKoreanUser = SharedPreferenceManager.countryCode.ifBlank { "KR" } == "KR"
|
|
||||||
|
|
||||||
if (isKoreanUser) {
|
|
||||||
binding.btnIdentityVerification.root.visibility = View.VISIBLE
|
|
||||||
if (it.isAuth) {
|
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnIdentityVerification.root,
|
|
||||||
iconRes = R.drawable.ic_my_auth,
|
|
||||||
title = getString(R.string.screen_my_identity_verified)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnIdentityVerification.root,
|
|
||||||
iconRes = R.drawable.ic_my_auth,
|
|
||||||
title = getString(R.string.screen_my_identity_verification)
|
|
||||||
) {
|
|
||||||
showAuthDialog()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.btnIdentityVerification.root.visibility = View.INVISIBLE
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.ivProfile.load(it.profileUrl) {
|
binding.ivProfile.load(it.profileUrl) {
|
||||||
crossfade(true)
|
crossfade(true)
|
||||||
placeholder(R.drawable.ic_place_holder)
|
placeholder(R.drawable.ic_place_holder)
|
||||||
@@ -413,41 +326,75 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
|||||||
binding.tvCanAmount.text = (it.chargeCan + it.rewardCan).moneyFormat()
|
binding.tvCanAmount.text = (it.chargeCan + it.rewardCan).moneyFormat()
|
||||||
binding.tvPointAmount.text = it.point.moneyFormat()
|
binding.tvPointAmount.text = it.point.moneyFormat()
|
||||||
|
|
||||||
|
updateFunctionButtons(it.isAuth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupFunctionButtonGrid() {
|
||||||
|
binding.rvFunctionButtons.layoutManager = GridLayoutManager(
|
||||||
|
requireContext(),
|
||||||
|
FUNCTION_BUTTON_SPAN_COUNT
|
||||||
|
)
|
||||||
|
|
||||||
|
if (binding.rvFunctionButtons.itemDecorationCount == 0) {
|
||||||
|
binding.rvFunctionButtons.addItemDecoration(
|
||||||
|
GridSpacingItemDecoration(
|
||||||
|
spanCount = FUNCTION_BUTTON_SPAN_COUNT,
|
||||||
|
spacing = 16f.dpToPx().toInt(),
|
||||||
|
includeEdge = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.rvFunctionButtons.adapter = functionButtonAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateFunctionButtons(isAuth: Boolean? = null) {
|
||||||
|
val isKoreanUser = SharedPreferenceManager.countryCode.ifBlank { "KR" } == "KR"
|
||||||
|
val items = mutableListOf(
|
||||||
|
FunctionButtonItem(
|
||||||
|
iconRes = R.drawable.ic_my_storage,
|
||||||
|
title = getString(R.string.screen_my_storage)
|
||||||
|
) {
|
||||||
|
startActivity(
|
||||||
|
Intent(
|
||||||
|
requireContext(),
|
||||||
|
AudioContentBoxActivity::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
FunctionButtonItem(
|
||||||
|
iconRes = R.drawable.ic_my_block,
|
||||||
|
title = getString(R.string.screen_my_block_list)
|
||||||
|
) {
|
||||||
|
startActivity(
|
||||||
|
Intent(
|
||||||
|
requireContext(),
|
||||||
|
BlockMemberActivity::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
val shouldShowCouponButton = if (isKoreanUser) {
|
val shouldShowCouponButton = if (isKoreanUser) {
|
||||||
true
|
isAuth != null
|
||||||
} else {
|
} else {
|
||||||
SharedPreferenceManager.isAdultContentVisible
|
SharedPreferenceManager.isAdultContentVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.btnCoupon.root.visibility = if (shouldShowCouponButton) {
|
if (shouldShowCouponButton) {
|
||||||
View.VISIBLE
|
items += FunctionButtonItem(
|
||||||
} else {
|
|
||||||
View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!shouldShowCouponButton) {
|
|
||||||
return@observe
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.isAuth || !isKoreanUser) {
|
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnCoupon.root,
|
|
||||||
iconRes = R.drawable.ic_my_coupon,
|
iconRes = R.drawable.ic_my_coupon,
|
||||||
title = getString(R.string.screen_my_coupon_register)
|
title = getString(R.string.screen_my_coupon_register)
|
||||||
) {
|
) {
|
||||||
|
if ((isAuth == true) || !isKoreanUser) {
|
||||||
startActivity(
|
startActivity(
|
||||||
Intent(
|
Intent(
|
||||||
requireActivity(),
|
requireActivity(),
|
||||||
CanCouponActivity::class.java
|
CanCouponActivity::class.java
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
FunctionButtonHelper.setupFunctionButton(
|
|
||||||
buttonView = binding.btnCoupon.root,
|
|
||||||
iconRes = R.drawable.ic_my_coupon,
|
|
||||||
title = getString(R.string.screen_my_coupon_register)
|
|
||||||
) {
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
getString(R.string.screen_my_auth_required),
|
getString(R.string.screen_my_auth_required),
|
||||||
@@ -458,6 +405,70 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items += listOf(
|
||||||
|
FunctionButtonItem(
|
||||||
|
iconRes = R.drawable.ic_my_alarm,
|
||||||
|
title = getString(R.string.screen_my_morning_call)
|
||||||
|
) {
|
||||||
|
startActivity(
|
||||||
|
Intent(
|
||||||
|
requireActivity(),
|
||||||
|
AlarmListActivity::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
FunctionButtonItem(
|
||||||
|
iconRes = R.drawable.ic_my_notice,
|
||||||
|
title = getString(R.string.screen_my_notice)
|
||||||
|
) {
|
||||||
|
startActivity(
|
||||||
|
Intent(
|
||||||
|
requireActivity(),
|
||||||
|
NoticeActivity::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
FunctionButtonItem(
|
||||||
|
iconRes = R.drawable.ic_my_event,
|
||||||
|
title = getString(R.string.screen_my_event)
|
||||||
|
) {
|
||||||
|
startActivity(
|
||||||
|
Intent(
|
||||||
|
requireActivity(),
|
||||||
|
EventActivity::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
FunctionButtonItem(
|
||||||
|
iconRes = R.drawable.ic_my_service_center,
|
||||||
|
title = getString(R.string.screen_my_customer_service)
|
||||||
|
) {
|
||||||
|
startActivity(
|
||||||
|
Intent(
|
||||||
|
requireActivity(),
|
||||||
|
ServiceCenterActivity::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isKoreanUser && isAuth != null) {
|
||||||
|
items += FunctionButtonItem(
|
||||||
|
iconRes = R.drawable.ic_my_auth,
|
||||||
|
title = if (isAuth) {
|
||||||
|
getString(R.string.screen_my_identity_verified)
|
||||||
|
} else {
|
||||||
|
getString(R.string.screen_my_identity_verification)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
if (!isAuth) {
|
||||||
|
showAuthDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
functionButtonAdapter.submitList(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showAuthDialog() {
|
private fun showAuthDialog() {
|
||||||
@@ -486,3 +497,47 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class FunctionButtonItem(
|
||||||
|
@field:DrawableRes val iconRes: Int,
|
||||||
|
val title: String,
|
||||||
|
val onClick: () -> Unit
|
||||||
|
)
|
||||||
|
|
||||||
|
private class FunctionButtonAdapter : RecyclerView.Adapter<FunctionButtonAdapter.ViewHolder>() {
|
||||||
|
private val items = mutableListOf<FunctionButtonItem>()
|
||||||
|
|
||||||
|
inner class ViewHolder(
|
||||||
|
private val binding: ItemFunctionButtonBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(item: FunctionButtonItem) {
|
||||||
|
FunctionButtonHelper.setupFunctionButton(
|
||||||
|
buttonView = binding.root,
|
||||||
|
iconRes = item.iconRes,
|
||||||
|
title = item.title,
|
||||||
|
clickListener = View.OnClickListener { item.onClick() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
ItemFunctionButtonBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun submitList(newItems: List<FunctionButtonItem>) {
|
||||||
|
items.clear()
|
||||||
|
items.addAll(newItems)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -276,86 +276,13 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
|
|
||||||
<!-- First Row -->
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
<LinearLayout
|
android:id="@+id/rv_function_buttons"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="16dp"
|
android:nestedScrollingEnabled="false"
|
||||||
android:baselineAligned="false"
|
tools:itemCount="8"
|
||||||
android:orientation="horizontal">
|
tools:listitem="@layout/item_function_button" />
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/btn_storage"
|
|
||||||
layout="@layout/item_function_button"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/btn_block_list"
|
|
||||||
layout="@layout/item_function_button"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="8dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/btn_coupon"
|
|
||||||
layout="@layout/item_function_button"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="8dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/btn_morning_call"
|
|
||||||
layout="@layout/item_function_button"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<!-- Second Row -->
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:baselineAligned="false"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/btn_notice"
|
|
||||||
layout="@layout/item_function_button"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/btn_event"
|
|
||||||
layout="@layout/item_function_button"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="8dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/btn_customer_service"
|
|
||||||
layout="@layout/item_function_button"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="8dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/btn_identity_verification"
|
|
||||||
layout="@layout/item_function_button"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
## 작업 목표
|
## 작업 목표
|
||||||
- 마이페이지 `btnCoupon` 터치 시 한국 사용자는 기존처럼 본인인증이 필요하고, 한국이 아닌 사용자는 본인인증 없이 쿠폰 등록 화면으로 이동하도록 수정한다.
|
- 마이페이지 `btnCoupon` 터치 시 한국 사용자는 기존처럼 본인인증이 필요하고, 한국이 아닌 사용자는 본인인증 없이 쿠폰 등록 화면으로 이동하도록 수정한다.
|
||||||
- 마이페이지 `btnCoupon`은 한국이 아닌 사용자에 한해 민감한 콘텐츠 보기 설정이 켜져 있을 때만 화면에 보이도록 수정한다.
|
- 마이페이지 `btnCoupon`은 한국이 아닌 사용자에 한해 민감한 콘텐츠 보기 설정이 켜져 있을 때만 화면에 보이도록 수정한다.
|
||||||
|
- 마이페이지 기능 버튼 영역을 `RecyclerView` 기반 그리드로 전환해 숨겨진 버튼이 있어도 중간 빈 슬롯 없이 왼쪽부터 자연스럽게 재배치되도록 수정한다.
|
||||||
|
|
||||||
## 체크리스트
|
## 체크리스트
|
||||||
- [x] AC1: `countryCode == "KR"` 이고 `isAuth == false`인 경우 기존처럼 인증 필요 토스트와 `showAuthDialog()`가 실행된다.
|
- [x] AC1: `countryCode == "KR"` 이고 `isAuth == false`인 경우 기존처럼 인증 필요 토스트와 `showAuthDialog()`가 실행된다.
|
||||||
@@ -13,12 +14,16 @@
|
|||||||
- QA: 인증 완료 사용자의 쿠폰 등록 진입 동작 유지 코드 확인
|
- QA: 인증 완료 사용자의 쿠폰 등록 진입 동작 유지 코드 확인
|
||||||
- [x] AC4: 변경 파일 진단/검증 명령 결과를 기록한다.
|
- [x] AC4: 변경 파일 진단/검증 명령 결과를 기록한다.
|
||||||
- QA: `lsp_diagnostics`, 관련 Gradle 검증 명령 결과 기록
|
- QA: `lsp_diagnostics`, 관련 Gradle 검증 명령 결과 기록
|
||||||
- [x] AC5: `countryCode != "KR"` 이고 `SharedPreferenceManager.isAdultContentVisible == true`인 경우에만 `btnCoupon`이 화면에 보인다.
|
- [x] AC5: `countryCode != "KR"` 이고 `SharedPreferenceManager.isAdultContentVisible == true`인 경우에만 쿠폰 버튼이 기능 버튼 목록에 포함되어 화면에 보인다.
|
||||||
- QA: 비한국 사용자에서 `btnCoupon.root.visibility`가 민감한 콘텐츠 보기 설정값에 따라 제어되는지 코드 확인
|
- QA: 비한국 사용자에서 쿠폰 버튼 아이템이 민감한 콘텐츠 보기 설정값에 따라 리스트에 포함되는지 코드 확인
|
||||||
- [x] AC6: `countryCode != "KR"` 이고 `SharedPreferenceManager.isAdultContentVisible == false`인 경우 `btnCoupon`이 화면에 보이지 않는다.
|
- [x] AC6: `countryCode != "KR"` 이고 `SharedPreferenceManager.isAdultContentVisible == false`인 경우 쿠폰 버튼이 기능 버튼 목록에서 제외되어 화면에 보이지 않는다.
|
||||||
- QA: 비한국 사용자에서 쿠폰 버튼이 `View.GONE` 처리되는지 코드 확인
|
- QA: 비한국 사용자에서 쿠폰 버튼 아이템이 리스트에 추가되지 않는지 코드 확인
|
||||||
- [x] AC7: `countryCode == "KR"` 인 경우 쿠폰 버튼 노출과 기존 한국/비한국 클릭 분기는 유지된다.
|
- [x] AC7: `countryCode == "KR"` 인 경우 쿠폰 버튼 노출과 기존 한국/비한국 클릭 분기는 유지된다.
|
||||||
- QA: 한국 사용자에서는 버튼이 계속 보이고, 클릭 시 기존 인증 분기가 유지되는지 코드 확인
|
- QA: 한국 사용자에서는 버튼이 계속 보이고, 클릭 시 기존 인증 분기가 유지되는지 코드 확인
|
||||||
|
- [x] AC8: 기능 버튼 영역이 `RecyclerView` 기반으로 렌더링되고, 숨겨진 버튼은 데이터 목록에서 제외되어 남은 버튼이 좌→우/상→하로 자연스럽게 압축 배치된다.
|
||||||
|
- QA: `fragment_my.xml`이 `RecyclerView`를 사용하고, `MyPageFragment`가 쿠폰/본인인증 버튼을 조건에 따라 아이템 리스트에 포함/제외하는지 코드 확인
|
||||||
|
- [x] AC9: 쿠폰 버튼이 숨겨지는 비한국 사용자(`isAdultContentVisible == false`)에서도 기능 버튼 간 가로/세로 간격이 기존 4열 그리드와 동일하게 유지된다.
|
||||||
|
- QA: `GridLayoutManager(4)`와 `GridSpacingItemDecoration(..., 16dp, false)` 적용으로 기존 16dp 간격 패턴을 유지하는지 코드 확인
|
||||||
|
|
||||||
## 검증 기록
|
## 검증 기록
|
||||||
- 2026-04-02
|
- 2026-04-02
|
||||||
@@ -45,3 +50,24 @@
|
|||||||
- 한국 사용자는 쿠폰 버튼이 계속 노출되고, 기존 인증 기반 클릭 분기도 유지된다.
|
- 한국 사용자는 쿠폰 버튼이 계속 노출되고, 기존 인증 기반 클릭 분기도 유지된다.
|
||||||
- `.kt` 파일 대상 `lsp_diagnostics`는 현재 환경에 Kotlin LSP가 없어 실행 불가(`No LSP server configured for extension: .kt`)였다.
|
- `.kt` 파일 대상 `lsp_diagnostics`는 현재 환경에 Kotlin LSP가 없어 실행 불가(`No LSP server configured for extension: .kt`)였다.
|
||||||
- `:app:testDebugUnitTest`, `:app:assembleDebug` 실행은 `BUILD SUCCESSFUL`로 완료됐다.
|
- `:app:testDebugUnitTest`, `:app:assembleDebug` 실행은 `BUILD SUCCESSFUL`로 완료됐다.
|
||||||
|
- 2026-04-02
|
||||||
|
- 무엇/왜/어떻게: 기능 버튼 영역이 고정 2행 x 4열 `include` 구조여서 비한국 사용자에게서 쿠폰 버튼이 숨겨질 때 중간 빈칸이 남았다. `fragment_my.xml`을 `RecyclerView` 기반 4열 그리드로 바꾸고, `MyPageFragment`가 기존 버튼 순서를 유지한 채 조건에 맞는 버튼만 리스트에 담아 렌더링하도록 리팩터링했다.
|
||||||
|
- 실행 명령/도구:
|
||||||
|
- `apply_patch(app/src/main/res/layout/fragment_my.xml)`
|
||||||
|
- `apply_patch(app/src/main/res/layout/item_function_button.xml)`
|
||||||
|
- `apply_patch(app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageFragment.kt)`
|
||||||
|
- `apply_patch(docs/20260402_쿠폰등록해외사용자본인인증예외.md)`
|
||||||
|
- `read(app/src/main/res/layout/fragment_my.xml)`
|
||||||
|
- `read(app/src/main/res/layout/item_function_button.xml)`
|
||||||
|
- `read(app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageFragment.kt)`
|
||||||
|
- `lsp_diagnostics(app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageFragment.kt)`
|
||||||
|
- `lsp_diagnostics(app/src/main/res/layout/fragment_my.xml)`
|
||||||
|
- `lsp_diagnostics(app/src/main/res/layout/item_function_button.xml)`
|
||||||
|
- `./gradlew :app:testDebugUnitTest :app:assembleDebug`
|
||||||
|
- 결과:
|
||||||
|
- 쿠폰 버튼과 본인인증 버튼은 더 이상 고정 슬롯의 `visibility`로 숨기지 않고, 조건에 맞을 때만 `RecyclerView` 데이터에 포함된다.
|
||||||
|
- 비한국 사용자이면서 `SharedPreferenceManager.isAdultContentVisible == false`인 경우 쿠폰 버튼이 목록에서 빠져 나머지 기능 버튼이 좌측부터 자연스럽게 압축 배치된다.
|
||||||
|
- 가로/세로 간격은 `GridLayoutManager(4)` + `GridSpacingItemDecoration(..., 16dp, false)`로 기존 4열 레이아웃의 16dp 간격 패턴을 유지한다.
|
||||||
|
- 기존 버튼 제목, 아이콘, 클릭 액션, 한국/비한국 및 인증/민감 콘텐츠 조건은 그대로 유지됐다.
|
||||||
|
- `.kt`/`.xml` 대상 `lsp_diagnostics`는 현재 환경에 Kotlin/XML LSP가 없어 실행 불가(`No LSP server configured for extension: .kt/.xml`)였다.
|
||||||
|
- `:app:testDebugUnitTest`, `:app:assembleDebug` 실행은 `BUILD SUCCESSFUL`로 완료됐다.
|
||||||
|
|||||||
Reference in New Issue
Block a user