From 207163b098d5064223003beccb12f86de8074620 Mon Sep 17 00:00:00 2001 From: mangbaam Date: Fri, 19 Jul 2024 22:45:56 +0900 Subject: [PATCH 01/27] =?UTF-8?q?#89=20feat:=20=EC=9D=B4=EC=9A=A9=EA=B6=8C?= =?UTF-8?q?=20=EA=B5=AC=EB=A7=A4,=20=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/UserSubscriptionStatusDto.kt | 13 +++-- .../nextroom/domain/model/Subscribe.kt | 12 ++-- .../ui/adminmain/AdminMainFragment.kt | 26 +++++---- .../ui/adminmain/AdminMainState.kt | 3 +- .../presentation/ui/mypage/MypageFragment.kt | 4 +- .../ui/purchase/PurchaseFragment.kt | 30 ++++------ .../presentation/ui/purchase/PurchaseState.kt | 2 +- .../ui/purchase/PurchaseViewModel.kt | 2 +- .../main/res/layout/fragment_admin_main.xml | 56 +++++++++---------- .../src/main/res/navigation/nav_graph.xml | 2 +- presentation/src/main/res/values/strings.xml | 2 + 11 files changed, 74 insertions(+), 78 deletions(-) diff --git a/data/src/main/java/com/nextroom/nextroom/data/network/response/UserSubscriptionStatusDto.kt b/data/src/main/java/com/nextroom/nextroom/data/network/response/UserSubscriptionStatusDto.kt index 697ca959..b047a3b7 100644 --- a/data/src/main/java/com/nextroom/nextroom/data/network/response/UserSubscriptionStatusDto.kt +++ b/data/src/main/java/com/nextroom/nextroom/data/network/response/UserSubscriptionStatusDto.kt @@ -16,12 +16,13 @@ data class UserSubscriptionStatusDto( ) { fun toDomain(): UserSubscribeStatus { val subsStatus = when (status.trim().uppercase()) { - "FREE" -> SubscribeStatus.Free - "HOLD" -> SubscribeStatus.Hold - "EXPIRATION" -> SubscribeStatus.Expiration - "SUBSCRIPTION" -> SubscribeStatus.Subscription - "SUBSCRIPTION_EXPIRATION" -> SubscribeStatus.SubscriptionExpiration - else -> SubscribeStatus.None +// "FREE" -> SubscribeStatus.Free +// "HOLD" -> SubscribeStatus.Hold +// "EXPIRATION" -> SubscribeStatus.Expiration +// "SUBSCRIPTION" -> SubscribeStatus.Subscription +// "SUBSCRIPTION_EXPIRATION" -> SubscribeStatus.SubscriptionExpiration +// else -> SubscribeStatus.None + else -> SubscribeStatus.Default } return UserSubscribeStatus( subscriptionId = id, diff --git a/domain/src/main/java/com/nextroom/nextroom/domain/model/Subscribe.kt b/domain/src/main/java/com/nextroom/nextroom/domain/model/Subscribe.kt index 42d6a355..40c36eae 100644 --- a/domain/src/main/java/com/nextroom/nextroom/domain/model/Subscribe.kt +++ b/domain/src/main/java/com/nextroom/nextroom/domain/model/Subscribe.kt @@ -31,19 +31,15 @@ data class SubscribeItem( */ data class UserSubscribeStatus( val subscriptionId: Long = 0L, - val subscribeStatus: SubscribeStatus = SubscribeStatus.None, + val subscribeStatus: SubscribeStatus = SubscribeStatus.Default, val expiryDate: String = "", val createdAt: String = "", ) /** - * @property None 아무것도 아닌 상태 (현재 사용하지 않음) - * @property Free 무료 체험 - * @property Hold 유예 기간 (무료 체험 끝) - * @property Expiration 유예 기간 만료 - * @property Subscription 구독 - * @property SubscriptionExpiration 구독 만료 + * @property Default 아무것도 구독하지 않은 상태 + * @property Subscribed 구독 중 상태 */ enum class SubscribeStatus { - None, Free, Hold, Expiration, Subscription, SubscriptionExpiration + Default, Subscribed } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt index bc548a13..75bb09d0 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt @@ -8,10 +8,10 @@ import androidx.core.view.isVisible import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController +import com.nextroom.nextroom.domain.model.SubscribeStatus import com.nextroom.nextroom.domain.repository.StatisticsRepository import com.nextroom.nextroom.presentation.R import com.nextroom.nextroom.presentation.base.BaseFragment -import com.nextroom.nextroom.presentation.common.NRTwoButtonDialog import com.nextroom.nextroom.presentation.databinding.FragmentAdminMainBinding import com.nextroom.nextroom.presentation.extension.addMargin import com.nextroom.nextroom.presentation.extension.safeNavigate @@ -39,6 +39,8 @@ class AdminMainFragment : onClickUpdate = viewModel::updateTheme, ) } + private val state: AdminMainState + get() = viewModel.container.stateFlow.value override fun onAttach(context: Context) { super.onAttach(context) @@ -76,13 +78,15 @@ class AdminMainFragment : private fun initViews() = with(binding) { updateSystemPadding(statusBar = false, navigationBar = true) + ivMyButton.addMargin(top = requireContext().statusBarHeight) + rvThemes.adapter = adapter -// tvPurchaseTicketButton.setOnClickListener { -// goToPurchase() -// } -// ivMyButton.setOnClickListener { -// goToMyPage() -// } + tvPurchaseButton.setOnClickListener { + goToPurchase() + } + ivMyButton.setOnClickListener { + goToMyPage() + } // tvLogoutButton.apply { // addMargin(top = requireContext().statusBarHeight) // setOnClickListener { logout() } @@ -90,7 +94,7 @@ class AdminMainFragment : srlTheme.setOnRefreshListener { viewModel.loadData() } - tvResignButton.addMargin(top = requireContext().statusBarHeight) + /*tvResignButton.addMargin(top = requireContext().statusBarHeight) tvResignButton.setOnClickListener { AdminMainFragmentDirections .actionGlobalNrTwoButtonDialog( @@ -103,7 +107,7 @@ class AdminMainFragment : ) ) .also { findNavController().safeNavigate(it) } - } + }*/ } private fun setFragmentResultListeners() { @@ -144,10 +148,10 @@ class AdminMainFragment : } } - /*private fun goToPurchase(subscribeStatus: SubscribeStatus = state.userSubscribeStatus.subscribeStatus) { + private fun goToPurchase(subscribeStatus: SubscribeStatus = state.userSubscribeStatus.subscribeStatus) { val action = AdminMainFragmentDirections.actionAdminMainFragmentToPurchaseFragment(subscribeStatus) findNavController().safeNavigate(action) - }*/ + } private fun goToMyPage() { val action = AdminMainFragmentDirections.actionAdminMainFragmentToMypageFragment() diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt index 4583b37c..1b78fb6f 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt @@ -1,10 +1,11 @@ package com.nextroom.nextroom.presentation.ui.adminmain +import com.nextroom.nextroom.domain.model.UserSubscribeStatus import com.nextroom.nextroom.presentation.model.ThemeInfoPresentation data class AdminMainState( val loading: Boolean = false, -// val userSubscribeStatus: UserSubscribeStatus = UserSubscribeStatus(), + val userSubscribeStatus: UserSubscribeStatus = UserSubscribeStatus(), val showName: String = "", val themes: List = emptyList(), ) { diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt index fe19b51e..3b4c4f46 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt @@ -42,11 +42,11 @@ class MypageFragment : BaseFragment(FragmentMypageBinding groupRemoteData.isVisible = !state.loading tvShopName.text = state.shopName - tvPurchaseTicketButton.text = if (state.userSubscribeStatus.subscribeStatus == SubscribeStatus.Subscription) { + /*tvPurchaseTicketButton.text = if (state.userSubscribeStatus.subscribeStatus == SubscribeStatus.Subscription) { getString(R.string.purchase_change_ticket) } else { getString(R.string.purchase_ticket) - } + }*/ tvSubsName.text = state.userSubscription?.type?.name ?: "" tvSubsPeriod.text = state.period } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt index 6bf22eb3..b7c5f182 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt @@ -50,24 +50,10 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB } private fun render(state: PurchaseState) = with(binding) { - tbPurchase.root.isInvisible = state.subscribeStatus in listOf(SubscribeStatus.Hold, SubscribeStatus.SubscriptionExpiration) - tbPurchase.tvTitle.text = when (state.subscribeStatus) { - SubscribeStatus.Free -> getString(R.string.purchase_ticket) - SubscribeStatus.Subscription -> getString(R.string.purchase_change_ticket) - else -> "" - } - tvMainLabel.text = when (state.subscribeStatus) { - SubscribeStatus.Free -> getString(R.string.purchase_main_label_normal) - SubscribeStatus.Hold -> getString(R.string.purchase_main_label_free_end) - SubscribeStatus.Subscription -> getString(R.string.purchase_main_label_normal) - SubscribeStatus.SubscriptionExpiration -> getString(R.string.purchase_main_label_subscribe_end) - else -> "" - } - tvSubLabel.text = when (state.subscribeStatus) { - SubscribeStatus.Hold -> getString(R.string.purchase_sub_label_free_end) - SubscribeStatus.SubscriptionExpiration -> getString(R.string.purchase_sub_label_subscribe_end) - else -> "" - } + tbPurchase.root.isInvisible = state.subscribeStatus != SubscribeStatus.Subscribed + tbPurchase.tvTitle.text = getString(R.string.purchase_ticket) + tvMainLabel.text = getString(R.string.purchase_title) + tvSubLabel.text = getString(R.string.purchase_description) adapter.submitList(state.ticketsForUi) } @@ -94,7 +80,13 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB findNavController().safeNavigate(it) } } - is BillingEvent.PurchaseFailed -> toast(getString(R.string.purchase_error_message, event.purchaseState)) + + is BillingEvent.PurchaseFailed -> toast( + getString( + R.string.purchase_error_message, + event.purchaseState + ) + ) } } } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseState.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseState.kt index 767176d6..894d4aad 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseState.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseState.kt @@ -5,7 +5,7 @@ import com.nextroom.nextroom.domain.model.Ticket import com.nextroom.nextroom.domain.model.UserSubscription data class PurchaseState( - val subscribeStatus: SubscribeStatus = SubscribeStatus.None, + val subscribeStatus: SubscribeStatus = SubscribeStatus.Default, val userSubscription: UserSubscription? = UserSubscription(), private val tickets: List = emptyList(), ) { diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt index a06fe5bf..b45ba3fb 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt @@ -23,7 +23,7 @@ class PurchaseViewModel @Inject constructor( ) : BaseViewModel() { override val container: Container = container( PurchaseState( - subscribeStatus = savedStateHandle["subscribeStatus"] ?: SubscribeStatus.None, + subscribeStatus = savedStateHandle["subscribeStatus"] ?: SubscribeStatus.Default, userSubscription = UserSubscription(SubscribeItem(id = "", name = "미니")), ), ) diff --git a/presentation/src/main/res/layout/fragment_admin_main.xml b/presentation/src/main/res/layout/fragment_admin_main.xml index b41038be..35fc99be 100644 --- a/presentation/src/main/res/layout/fragment_admin_main.xml +++ b/presentation/src/main/res/layout/fragment_admin_main.xml @@ -29,7 +29,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintTop_toTopOf="parent" />--> - - - - - - - - - - - - - - - + - - - - - - - - - - - + 이용권 구매 이용권 변경 방탈출 1인 가격보다,\n최저시급보다 저렴하게 + 멤버십 회원을 위한 기능이 업데이트 될 예정입니다 + 새로운 기능이 생기기 전까지 넥스트룸 운영을 위해 후원해주세요 구독이 만료되었어요 무료 체험기간이 끝났어요 다시 구독하시면 저장하신 정보 그대로 사용할 수 있어요! From 31a6d3293d4a752b32b2fddc7946f67bbb0aed3c Mon Sep 17 00:00:00 2001 From: mangbaam Date: Fri, 19 Jul 2024 23:40:25 +0900 Subject: [PATCH 02/27] =?UTF-8?q?#89=20feat:=20MainActivity=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=20=EA=B4=80=EB=A0=A8=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextroom/presentation/ui/MainActivity.kt | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/MainActivity.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/MainActivity.kt index 406cda2d..92f31957 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/MainActivity.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/MainActivity.kt @@ -15,9 +15,12 @@ import com.nextroom.nextroom.presentation.common.NRDialog import com.nextroom.nextroom.presentation.databinding.ActivityMainBinding import com.nextroom.nextroom.presentation.extension.repeatOn import com.nextroom.nextroom.presentation.extension.repeatOnStarted +import com.nextroom.nextroom.presentation.ui.billing.BillingViewModel +import com.nextroom.nextroom.presentation.util.BillingClientLifecycle import com.nextroom.nextroom.presentation.util.WindowInsetsManager import com.nextroom.nextroom.presentation.util.WindowInsetsManagerImpl import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class MainActivity : @@ -26,10 +29,10 @@ class MainActivity : private lateinit var binding: ActivityMainBinding private val viewModel: MainViewModel by viewModels() -// private val billingViewModel: BillingViewModel by viewModels() + private val billingViewModel: BillingViewModel by viewModels() -// @Inject -// lateinit var billingClientLifecycle: BillingClientLifecycle + @Inject + lateinit var billingClientLifecycle: BillingClientLifecycle override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge( @@ -42,7 +45,7 @@ class MainActivity : binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) -// lifecycle.addObserver(billingClientLifecycle) + lifecycle.addObserver(billingClientLifecycle) repeatOnStarted { viewModel.event.collect(::observe) @@ -52,11 +55,11 @@ class MainActivity : if (!loggedIn) viewModel.logout() } } -// repeatOnStarted { -// billingViewModel.buyEvent.collect { -// billingClientLifecycle.launchBillingFlow(this@MainActivity, it) -// } -// } + repeatOnStarted { + billingViewModel.buyEvent.collect { + billingClientLifecycle.launchBillingFlow(this@MainActivity, it) + } + } } private fun observe(event: MainEvent) { From 90ef7f0b993424910ff011f0793e0a1add202df3 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sat, 20 Jul 2024 01:10:33 +0900 Subject: [PATCH 03/27] =?UTF-8?q?#89=20feat:=20mini,=20medium,=20large=20?= =?UTF-8?q?=EC=84=B8=20=EC=A2=85=EB=A5=98=EB=A1=9C=20=EB=82=98=EB=89=98?= =?UTF-8?q?=EB=8D=98=20=EC=9A=94=EA=B8=88=EC=A0=9C=EB=A5=BC=20membership?= =?UTF-8?q?=20=ED=95=9C=EA=B0=9C=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextroom/presentation/ui/Constants.kt | 4 +--- .../presentation/ui/billing/BillingViewModel.kt | 16 ++++------------ .../presentation/util/BillingClientLifecycle.kt | 16 ++++------------ 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/Constants.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/Constants.kt index 48af4132..f392bdad 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/Constants.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/Constants.kt @@ -1,7 +1,5 @@ package com.nextroom.nextroom.presentation.ui object Constants { - const val MINI_PRODUCT = "mini_subscription" - const val MEDIUM_PRODUCT = "medium_subscription" - const val LARGE_PRODUCT = "large_subscription" + const val MEMBERSHIP_PRODUCT = "membership_subscription" } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/billing/BillingViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/billing/BillingViewModel.kt index 81163503..6f4c9741 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/billing/BillingViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/billing/BillingViewModel.kt @@ -24,9 +24,7 @@ class BillingViewModel private val purchases = billingClientLifecycle.subscriptionPurchases // 콘솔에 등록된 상품들 정보 - private val largeSubProductWithProductDetails = billingClientLifecycle.largeSubProductWithProductDetails - private val mediumSubProductWithProductDetails = billingClientLifecycle.mediumSubProductWithProductDetails - private val miniSubProductWithProductDetails = billingClientLifecycle.miniSubProductWithProductDetails + private val membershipProductWithProductDetails = billingClientLifecycle.membershipProductWithProductDetails private val _buyEvent = MutableSharedFlow() val buyEvent = _buyEvent.asSharedFlow() @@ -186,9 +184,7 @@ class BillingViewModel } when (productId) { - Constants.LARGE_PRODUCT -> largeSubProductWithProductDetails.value - Constants.MEDIUM_PRODUCT -> mediumSubProductWithProductDetails.value - Constants.MINI_PRODUCT -> miniSubProductWithProductDetails.value + Constants.MEMBERSHIP_PRODUCT -> membershipProductWithProductDetails.value else -> null }?.also { productDetails -> productDetails.subscriptionOfferDetails?.let { offerDetailsList -> @@ -212,9 +208,7 @@ class BillingViewModel productDetails: ProductDetails, ) { val currentSubscriptionPurchaseCount = purchases.value.count { - it.products.contains(Constants.MINI_PRODUCT) || - it.products.contains(Constants.MEDIUM_PRODUCT) || - it.products.contains(Constants.LARGE_PRODUCT) + it.products.contains(Constants.MEMBERSHIP_PRODUCT) } if (currentSubscriptionPurchaseCount > EXPECTED_SUBSCRIPTION_PURCHASE_LIST_SIZE) { Timber.e("There are more than one subscription purchases on the device.") @@ -227,9 +221,7 @@ class BillingViewModel } val oldToken = purchases.value.filter { - it.products.contains(Constants.MINI_PRODUCT) || - it.products.contains(Constants.MEDIUM_PRODUCT) || - it.products.contains(Constants.LARGE_PRODUCT) + it.products.contains(Constants.MEMBERSHIP_PRODUCT) }.firstOrNull { it.purchaseToken.isNotEmpty() }?.purchaseToken ?: "" val billingParams: BillingFlowParams = if (upDowngrade) { diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/util/BillingClientLifecycle.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/util/BillingClientLifecycle.kt index cb45e331..aba8436a 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/util/BillingClientLifecycle.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/util/BillingClientLifecycle.kt @@ -56,9 +56,7 @@ class BillingClientLifecycle private constructor( private var cachedPurchasesList: List? = null // 콘솔에 등록된 상품들 정보 - val largeSubProductWithProductDetails = MutableLiveData() - val mediumSubProductWithProductDetails = MutableLiveData() - val miniSubProductWithProductDetails = MutableLiveData() + val membershipProductWithProductDetails = MutableLiveData() private val _uiEvent = MutableSharedFlow() val uiEvent = _uiEvent.asSharedFlow() @@ -169,9 +167,7 @@ class BillingClientLifecycle private constructor( when (productDetails.productType) { BillingClient.ProductType.SUBS -> { when (productDetails.productId) { - Constants.LARGE_PRODUCT -> largeSubProductWithProductDetails.postValue(productDetails) - Constants.MEDIUM_PRODUCT -> mediumSubProductWithProductDetails.postValue(productDetails) - Constants.MINI_PRODUCT -> miniSubProductWithProductDetails.postValue(productDetails) + Constants.MEMBERSHIP_PRODUCT -> membershipProductWithProductDetails.postValue(productDetails) } } } @@ -252,7 +248,7 @@ class BillingClientLifecycle private constructor( externalScope.launch { val subscriptionPurchaseList = list.filter { purchase -> purchase.products.any { product -> - product in listOf(Constants.LARGE_PRODUCT, Constants.MEDIUM_PRODUCT, Constants.MINI_PRODUCT) + product in listOf(Constants.MEMBERSHIP_PRODUCT) } } @@ -372,11 +368,7 @@ class BillingClientLifecycle private constructor( private const val TAG = "BillingLifecycle" private const val MAX_RETRY_ATTEMPT = 3 - private val LIST_OF_SUBSCRIPTION_PRODUCTS = listOf( - Constants.MINI_PRODUCT, - Constants.MEDIUM_PRODUCT, - Constants.LARGE_PRODUCT, - ) + private val LIST_OF_SUBSCRIPTION_PRODUCTS = listOf(Constants.MEMBERSHIP_PRODUCT) @Volatile private var INSTANCE: BillingClientLifecycle? = null From 45fc55456f1507bb4e230a9e447f3d7df17ce653 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sat, 10 Aug 2024 22:07:24 +0900 Subject: [PATCH 04/27] =?UTF-8?q?#89=20feat:=20=EC=9A=94=EA=B8=88=EC=A0=9C?= =?UTF-8?q?=20=EC=A0=95=EB=B3=B4=20api=20=EC=88=98=EC=A0=95=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 변경된 response 모델에 맞게 수정함 --- .../data/network/response/TicketDto.kt | 12 ++++++++++-- .../nextroom/nextroom/domain/model/Ticket.kt | 6 +++++- .../presentation/ui/purchase/TicketAdapter.kt | 2 +- .../presentation/ui/purchase/TicketUiModel.kt | 18 +++++++++++++++--- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/data/src/main/java/com/nextroom/nextroom/data/network/response/TicketDto.kt b/data/src/main/java/com/nextroom/nextroom/data/network/response/TicketDto.kt index 5b36f7c9..5f1efaf7 100644 --- a/data/src/main/java/com/nextroom/nextroom/data/network/response/TicketDto.kt +++ b/data/src/main/java/com/nextroom/nextroom/data/network/response/TicketDto.kt @@ -5,18 +5,26 @@ import com.nextroom.nextroom.domain.model.Ticket data class TicketDto( @SerializedName("id") val id: String, - @SerializedName("plan") val plan: String, + @SerializedName("subscriptionProductId") val subscriptionProductId: String, + @SerializedName("planId") val planId: String, + @SerializedName("productName") val productName: String, @SerializedName("description") val description: String, + @SerializedName("subDescription") val subDescription: String, @SerializedName("originPrice") val originPrice: Int?, @SerializedName("sellPrice") val sellPrice: Int, + @SerializedName("discountRate") val discountRate: Int, ) { fun toDomain(): Ticket { return Ticket( id = id, - plan = plan, + subscriptionProductId = subscriptionProductId, + planId = planId, + productName = productName, description = description, + subDescription = subDescription, originPrice = originPrice, sellPrice = sellPrice, + discountRate = discountRate, ) } } diff --git a/domain/src/main/java/com/nextroom/nextroom/domain/model/Ticket.kt b/domain/src/main/java/com/nextroom/nextroom/domain/model/Ticket.kt index 4ae6d017..5d4d2351 100644 --- a/domain/src/main/java/com/nextroom/nextroom/domain/model/Ticket.kt +++ b/domain/src/main/java/com/nextroom/nextroom/domain/model/Ticket.kt @@ -2,8 +2,12 @@ package com.nextroom.nextroom.domain.model data class Ticket( val id: String, - val plan: String, + val subscriptionProductId: String, + val planId: String, + val productName: String, val description: String, + val subDescription: String, val originPrice: Int?, val sellPrice: Int, + val discountRate: Int, ) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketAdapter.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketAdapter.kt index 6148a26b..e05fbdab 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketAdapter.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketAdapter.kt @@ -33,7 +33,7 @@ class TicketAdapter( fun bind(ticket: TicketUiModel) = with(binding) { item = ticket - tvName.text = ticket.plan + tvName.text = ticket.productName tvDescription.text = ticket.description tvOriginPrice.isVisible = ticket.originPrice != null ticket.originPrice?.let { diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketUiModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketUiModel.kt index 0e0342f5..42194615 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketUiModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketUiModel.kt @@ -4,19 +4,27 @@ import com.nextroom.nextroom.domain.model.Ticket data class TicketUiModel( val id: String, - val plan: String, + val subscriptionProductId: String, + val planId: String, + val productName: String, val description: String, + val subDescription: String, val originPrice: Int?, val sellPrice: Int, + val discountRate: Int, val subscribing: Boolean, ) { fun toDomain(): Ticket { return Ticket( id = id, - plan = plan, + subscriptionProductId = subscriptionProductId, + planId = planId, + productName = productName, description = description, + subDescription = subDescription, originPrice = originPrice, sellPrice = sellPrice, + discountRate = discountRate, ) } } @@ -24,10 +32,14 @@ data class TicketUiModel( fun Ticket.toPresentation(subscribing: Boolean): TicketUiModel { return TicketUiModel( id = id, - plan = plan, + subscriptionProductId = subscriptionProductId, + planId = planId, + productName = productName, description = description, + subDescription = subDescription, originPrice = originPrice, sellPrice = sellPrice, + discountRate = discountRate, subscribing = subscribing, ) } From c2145f954dc53818227e993cfdb36474525743a4 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Thu, 15 Aug 2024 23:05:27 +0900 Subject: [PATCH 05/27] =?UTF-8?q?#89=20feat:=20=EA=B5=AC=EB=8F=85=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20api=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 변경된 response 모델에 맞게 수정함 기존에 사용하고 있는 UserSubscription는 다른곳에서도 쓰이고 있어서 일단 그대로 두었고 /mypage 에서 사용하는 모델을 따로 만들었음 일단 이름을 api path에 따라 mypage로 정했으나 path부터 해서 이름을 수정할 필요가 있어보임 todo로 달아놓았고 추후에 수정하면 좋을듯함 --- .../data/datasource/SubscriptionDataSource.kt | 4 +-- .../data/network/response/MypageDto.kt | 24 +++++++++----- .../data/repository/AdminRepositoryImpl.kt | 4 +-- .../nextroom/nextroom/domain/model/Mypage.kt | 10 ++++++ .../nextroom/domain/model/Subscribe.kt | 13 ++++++-- .../domain/repository/AdminRepository.kt | 4 +-- .../presentation/ui/mypage/MypageViewModel.kt | 33 +++++++++---------- 7 files changed, 57 insertions(+), 35 deletions(-) create mode 100644 domain/src/main/java/com/nextroom/nextroom/domain/model/Mypage.kt diff --git a/data/src/main/java/com/nextroom/nextroom/data/datasource/SubscriptionDataSource.kt b/data/src/main/java/com/nextroom/nextroom/data/datasource/SubscriptionDataSource.kt index ad743845..9a3109e5 100644 --- a/data/src/main/java/com/nextroom/nextroom/data/datasource/SubscriptionDataSource.kt +++ b/data/src/main/java/com/nextroom/nextroom/data/datasource/SubscriptionDataSource.kt @@ -1,10 +1,10 @@ package com.nextroom.nextroom.data.datasource import com.nextroom.nextroom.data.network.ApiService +import com.nextroom.nextroom.domain.model.Mypage import com.nextroom.nextroom.domain.model.Result import com.nextroom.nextroom.domain.model.Ticket import com.nextroom.nextroom.domain.model.UserSubscribeStatus -import com.nextroom.nextroom.domain.model.UserSubscription import com.nextroom.nextroom.domain.model.mapOnSuccess import javax.inject.Inject @@ -17,7 +17,7 @@ class SubscriptionDataSource @Inject constructor( } } - suspend fun getUserSubscription(): Result { + suspend fun getUserSubscription(): Result { return apiService.getMypageInfo().mapOnSuccess { it.data.toDomain() } } diff --git a/data/src/main/java/com/nextroom/nextroom/data/network/response/MypageDto.kt b/data/src/main/java/com/nextroom/nextroom/data/network/response/MypageDto.kt index 70100c80..c3e87f97 100644 --- a/data/src/main/java/com/nextroom/nextroom/data/network/response/MypageDto.kt +++ b/data/src/main/java/com/nextroom/nextroom/data/network/response/MypageDto.kt @@ -1,20 +1,26 @@ package com.nextroom.nextroom.data.network.response import com.google.gson.annotations.SerializedName -import com.nextroom.nextroom.domain.model.SubscribeItem -import com.nextroom.nextroom.domain.model.UserSubscription +import com.nextroom.nextroom.domain.model.Mypage +import com.nextroom.nextroom.domain.model.SubscribeStatus +// TODO JH: 이름 변경 고려해보기 data class MypageDto( @SerializedName("id") val id: String, - @SerializedName("subStatus") val subsName: String, // LARGE - @SerializedName("createdAt") val createdAt: String, // 2023-10-24 02:29:57 - @SerializedName("expiryDate") val expiryDate: String, // 2023-11-23 + @SerializedName("name") val name: String, // xx이스케이프 xx점 + @SerializedName("status") val status: String, // FREE or SUBSCRIPTION + @SerializedName("startDate") val startDate: String?, // 2023-10-24 02:29:57 + @SerializedName("expiryDate") val expiryDate: String?, // 2023-11-23 + @SerializedName("createdAt") val createdAt: String, // 2023-11-23 ) { - fun toDomain(): UserSubscription { - return UserSubscription( - type = SubscribeItem(id = id, name = subsName), - createdAt = createdAt, + fun toDomain(): Mypage { + return Mypage( + id = id, + name = name, + status = SubscribeStatus.ofValue(status), + startDate = startDate, expiryDate = expiryDate, + createdAt = createdAt, ) } } diff --git a/data/src/main/java/com/nextroom/nextroom/data/repository/AdminRepositoryImpl.kt b/data/src/main/java/com/nextroom/nextroom/data/repository/AdminRepositoryImpl.kt index f8f009fc..39299698 100644 --- a/data/src/main/java/com/nextroom/nextroom/data/repository/AdminRepositoryImpl.kt +++ b/data/src/main/java/com/nextroom/nextroom/data/repository/AdminRepositoryImpl.kt @@ -6,9 +6,9 @@ import com.nextroom.nextroom.data.datasource.SubscriptionDataSource import com.nextroom.nextroom.data.datasource.TokenDataSource import com.nextroom.nextroom.data.datasource.UserDataSource import com.nextroom.nextroom.domain.model.LoginInfo +import com.nextroom.nextroom.domain.model.Mypage import com.nextroom.nextroom.domain.model.Result import com.nextroom.nextroom.domain.model.UserSubscribeStatus -import com.nextroom.nextroom.domain.model.UserSubscription import com.nextroom.nextroom.domain.model.onSuccess import com.nextroom.nextroom.domain.repository.AdminRepository import kotlinx.coroutines.flow.Flow @@ -51,7 +51,7 @@ class AdminRepositoryImpl @Inject constructor( return subscriptionDataSource.getUserSubscriptionStatus() } - override suspend fun getUserSubscribe(): Result { + override suspend fun getUserSubscribe(): Result { return subscriptionDataSource.getUserSubscription() } } diff --git a/domain/src/main/java/com/nextroom/nextroom/domain/model/Mypage.kt b/domain/src/main/java/com/nextroom/nextroom/domain/model/Mypage.kt new file mode 100644 index 00000000..014389c4 --- /dev/null +++ b/domain/src/main/java/com/nextroom/nextroom/domain/model/Mypage.kt @@ -0,0 +1,10 @@ +package com.nextroom.nextroom.domain.model + +data class Mypage( + val id: String, + val name: String, + val status: SubscribeStatus, + val startDate: String?, + val expiryDate: String?, + val createdAt: String, +) \ No newline at end of file diff --git a/domain/src/main/java/com/nextroom/nextroom/domain/model/Subscribe.kt b/domain/src/main/java/com/nextroom/nextroom/domain/model/Subscribe.kt index 40c36eae..501c4b03 100644 --- a/domain/src/main/java/com/nextroom/nextroom/domain/model/Subscribe.kt +++ b/domain/src/main/java/com/nextroom/nextroom/domain/model/Subscribe.kt @@ -40,6 +40,13 @@ data class UserSubscribeStatus( * @property Default 아무것도 구독하지 않은 상태 * @property Subscribed 구독 중 상태 */ -enum class SubscribeStatus { - Default, Subscribed -} +enum class SubscribeStatus(val value: String) { + Default("FREE"), + Subscribed("SUBSCRIPTION"); + + companion object { + fun ofValue(value: String): SubscribeStatus { + return entries.find { it.value.uppercase() == value.uppercase() } ?: Default + } + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/nextroom/nextroom/domain/repository/AdminRepository.kt b/domain/src/main/java/com/nextroom/nextroom/domain/repository/AdminRepository.kt index 3b6eb90f..28819fe2 100644 --- a/domain/src/main/java/com/nextroom/nextroom/domain/repository/AdminRepository.kt +++ b/domain/src/main/java/com/nextroom/nextroom/domain/repository/AdminRepository.kt @@ -1,9 +1,9 @@ package com.nextroom.nextroom.domain.repository import com.nextroom.nextroom.domain.model.LoginInfo +import com.nextroom.nextroom.domain.model.Mypage import com.nextroom.nextroom.domain.model.Result import com.nextroom.nextroom.domain.model.UserSubscribeStatus -import com.nextroom.nextroom.domain.model.UserSubscription import kotlinx.coroutines.flow.Flow interface AdminRepository { @@ -19,5 +19,5 @@ interface AdminRepository { suspend fun resign(): Result suspend fun verifyAdminCode(code: String): Boolean suspend fun getUserSubscribeStatus(): Result - suspend fun getUserSubscribe(): Result + suspend fun getUserSubscribe(): Result } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt index 1a50ea76..90a37148 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt @@ -1,7 +1,5 @@ package com.nextroom.nextroom.presentation.ui.mypage -import com.nextroom.nextroom.domain.model.onFinally -import com.nextroom.nextroom.domain.model.suspendConcatMap import com.nextroom.nextroom.domain.repository.AdminRepository import com.nextroom.nextroom.presentation.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel @@ -35,20 +33,21 @@ class MypageViewModel @Inject constructor( private fun fetchSubsInfo() = intent { reduce { state.copy(loading = true) } - adminRepository.getUserSubscribeStatus().suspendConcatMap( - other = adminRepository.getUserSubscribe(), - ) { subsStatus, mypageInfo -> - reduce { - state.copy( - loading = false, - userSubscribeStatus = subsStatus, - userSubscription = mypageInfo, - ) - } - }.onFinally { - reduce { - state.copy(loading = false) - } - } + // TODO JH: 임시로 주석 +// adminRepository.getUserSubscribeStatus().suspendConcatMap( +// other = adminRepository.geUserSubscribe(), +// ) { subsStatus, mypageInfo -> +// reduce { +// state.copy( +// loading = false, +// userSubscribeStatus = subsStatus, +// userSubscription = mypageInfo, +// ) +// } +// }.onFinally { +// reduce { +// state.copy(loading = false) +// } +// } } } From 9bde5d71ce0242c4387d778f51018f11bd07390f Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Thu, 15 Aug 2024 23:43:18 +0900 Subject: [PATCH 06/27] =?UTF-8?q?#89=20feat:=20=EC=9D=B4=EC=9A=A9=EA=B6=8C?= =?UTF-8?q?=20=EA=B5=AC=EB=A7=A4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=94=94?= =?UTF-8?q?=EC=9E=90=EC=9D=B8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 구독 상품을 하나만 제공할거라서 리사이클러뷰를 제거함. 여러개로 늘어난다고 하더라도 그땐 어차피 디자인이나 코드가 변경되어야 해서 구버전 사용자한테는 하나의 상품만 제공하는 것이 맞을듯 함. --- .../ui/purchase/PurchaseFragment.kt | 25 +-- .../src/main/res/layout/fragment_purchase.xml | 182 ++++++++++-------- 2 files changed, 104 insertions(+), 103 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt index b7c5f182..3f6461bf 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt @@ -2,17 +2,13 @@ package com.nextroom.nextroom.presentation.ui.purchase import android.os.Bundle import android.view.View -import androidx.core.view.isInvisible import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController -import com.nextroom.nextroom.domain.model.SubscribeStatus import com.nextroom.nextroom.presentation.R import com.nextroom.nextroom.presentation.base.BaseFragment -import com.nextroom.nextroom.presentation.common.LinearSpaceDecoration import com.nextroom.nextroom.presentation.databinding.FragmentPurchaseBinding -import com.nextroom.nextroom.presentation.extension.dp import com.nextroom.nextroom.presentation.extension.repeatOnStarted import com.nextroom.nextroom.presentation.extension.safeNavigate import com.nextroom.nextroom.presentation.extension.toast @@ -26,8 +22,6 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB private val viewModel: PurchaseViewModel by viewModels() private val billingViewModel: BillingViewModel by activityViewModels() - private val adapter: TicketAdapter by lazy { TicketAdapter(viewModel::startPurchase) } - private val spacer: LinearSpaceDecoration = LinearSpaceDecoration(spaceBetween = 12.dp) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -39,22 +33,15 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB private fun initViews() = with(binding) { tbPurchase.apply { - root.isVisible = false + tvTitle.text = getString(R.string.purchase_ticket) tvButton.isVisible = false ivBack.setOnClickListener { findNavController().popBackStack() } } - rvSubscribes.apply { - adapter = this@PurchaseFragment.adapter - addItemDecoration(spacer) - } } private fun render(state: PurchaseState) = with(binding) { - tbPurchase.root.isInvisible = state.subscribeStatus != SubscribeStatus.Subscribed - tbPurchase.tvTitle.text = getString(R.string.purchase_ticket) tvMainLabel.text = getString(R.string.purchase_title) tvSubLabel.text = getString(R.string.purchase_description) - adapter.submitList(state.ticketsForUi) } private fun handleEvent(event: PurchaseEvent) { @@ -84,17 +71,11 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB is BillingEvent.PurchaseFailed -> toast( getString( R.string.purchase_error_message, - event.purchaseState - ) + event.purchaseState, + ), ) } } } } - - override fun onDestroyView() { - binding.rvSubscribes.removeItemDecoration(spacer) - binding.rvSubscribes.adapter = null - super.onDestroyView() - } } diff --git a/presentation/src/main/res/layout/fragment_purchase.xml b/presentation/src/main/res/layout/fragment_purchase.xml index c27b56c6..8d1e719a 100644 --- a/presentation/src/main/res/layout/fragment_purchase.xml +++ b/presentation/src/main/res/layout/fragment_purchase.xml @@ -8,98 +8,118 @@ + layout="@layout/common_toolbar" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintTop_toTopOf="parent" /> - + - + - + + + - + - + - + - + - - - + \ No newline at end of file From 848f9332357a75df3e7868698e064b9f0beecc47 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Fri, 16 Aug 2024 01:32:03 +0900 Subject: [PATCH 07/27] =?UTF-8?q?#89=20feat:=20=EC=83=88=EB=A1=9C=20?= =?UTF-8?q?=EB=B0=94=EB=80=90=20=EC=9A=94=EA=B8=88=EC=A0=9C=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20api=20response=EB=A1=9C=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=9D=84=20=EA=B7=B8=EB=A6=B0=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit orbit도 같이 걷어내었음 --- .../ui/purchase/PurchaseFragment.kt | 62 ++++++++----- .../ui/purchase/PurchaseViewModel.kt | 90 ++++++++++++------- presentation/src/main/res/values/strings.xml | 1 + 3 files changed, 101 insertions(+), 52 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt index 3f6461bf..fa2dc73e 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt @@ -11,11 +11,12 @@ import com.nextroom.nextroom.presentation.base.BaseFragment import com.nextroom.nextroom.presentation.databinding.FragmentPurchaseBinding import com.nextroom.nextroom.presentation.extension.repeatOnStarted import com.nextroom.nextroom.presentation.extension.safeNavigate +import com.nextroom.nextroom.presentation.extension.strikeThrow import com.nextroom.nextroom.presentation.extension.toast import com.nextroom.nextroom.presentation.ui.billing.BillingEvent import com.nextroom.nextroom.presentation.ui.billing.BillingViewModel import dagger.hilt.android.AndroidEntryPoint -import org.orbitmvi.orbit.viewmodel.observe +import kotlinx.coroutines.launch @AndroidEntryPoint class PurchaseFragment : BaseFragment(FragmentPurchaseBinding::inflate) { @@ -27,7 +28,6 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB super.onViewCreated(view, savedInstanceState) initViews() - viewModel.observe(viewLifecycleOwner, state = ::render, sideEffect = ::handleEvent) initObserve() } @@ -39,11 +39,6 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB } } - private fun render(state: PurchaseState) = with(binding) { - tvMainLabel.text = getString(R.string.purchase_title) - tvSubLabel.text = getString(R.string.purchase_description) - } - private fun handleEvent(event: PurchaseEvent) { when (event) { is PurchaseEvent.StartPurchase -> { @@ -58,24 +53,49 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB private fun initObserve() { viewLifecycleOwner.repeatOnStarted { - billingViewModel.uiEvent.collect { event -> - when (event) { - BillingEvent.PurchaseAcknowledged -> { - PurchaseFragmentDirections - .actionPurchaseFragmentToPurchaseSuccessFragment() - .also { - findNavController().safeNavigate(it) - } + launch { + viewModel.uiState.collect { state -> + when (state) { + PurchaseViewModel.UiState.Failure -> Unit // TODO JH: 처리 필요 + is PurchaseViewModel.UiState.Loaded -> updateUi(state) + PurchaseViewModel.UiState.Loading -> Unit // TODO JH: 처리 필요 } + } + } + launch { + billingViewModel.uiEvent.collect { event -> + when (event) { + BillingEvent.PurchaseAcknowledged -> { + PurchaseFragmentDirections + .actionPurchaseFragmentToPurchaseSuccessFragment() + .also { + findNavController().safeNavigate(it) + } + } - is BillingEvent.PurchaseFailed -> toast( - getString( - R.string.purchase_error_message, - event.purchaseState, - ), - ) + is BillingEvent.PurchaseFailed -> toast( + getString( + R.string.purchase_error_message, + event.purchaseState, + ), + ) + } } } } } + + private fun updateUi(loaded: PurchaseViewModel.UiState.Loaded) { + with(binding) { + with(loaded) { + tvMainLabel.text = description + tvSubLabel.text = subDescription + tvName.text = productName + tvDiscountRate.text = getString(R.string.discount_rate, discountRate) + tvOriginPrice.text = originPrice + tvOriginPrice.strikeThrow() + tvSellPrice.text = sellPrice + } + } + } } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt index b45ba3fb..0897c922 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt @@ -1,50 +1,78 @@ package com.nextroom.nextroom.presentation.ui.purchase -import androidx.lifecycle.SavedStateHandle -import com.nextroom.nextroom.domain.model.SubscribeItem -import com.nextroom.nextroom.domain.model.SubscribeStatus -import com.nextroom.nextroom.domain.model.Ticket -import com.nextroom.nextroom.domain.model.UserSubscription +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.nextroom.nextroom.domain.model.onFailure import com.nextroom.nextroom.domain.model.onSuccess import com.nextroom.nextroom.domain.repository.BillingRepository -import com.nextroom.nextroom.presentation.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel -import org.orbitmvi.orbit.Container -import org.orbitmvi.orbit.syntax.simple.intent -import org.orbitmvi.orbit.syntax.simple.postSideEffect -import org.orbitmvi.orbit.syntax.simple.reduce -import org.orbitmvi.orbit.viewmodel.container +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import java.text.DecimalFormat import javax.inject.Inject @HiltViewModel class PurchaseViewModel @Inject constructor( - savedStateHandle: SavedStateHandle, private val billingRepository: BillingRepository, -) : BaseViewModel() { - override val container: Container = container( - PurchaseState( - subscribeStatus = savedStateHandle["subscribeStatus"] ?: SubscribeStatus.Default, - userSubscription = UserSubscription(SubscribeItem(id = "", name = "미니")), - ), - ) +) : ViewModel() { + + private val _uiState = MutableStateFlow(UiState.Loading) + val uiState = _uiState.asStateFlow() init { fetchTickets() } - fun startPurchase(ticket: Ticket) = intent { - postSideEffect( - PurchaseEvent.StartPurchase( - productId = ticket.id, - tag = "", - upDowngrade = (ticket.id == container.stateFlow.value.userSubscription?.type?.id), - ), - ) - } + // TODO JH: 수정 +// fun startPurchase(ticket: Ticket) = intent { +// postSideEffect( +// PurchaseEvent.StartPurchase( +// productId = ticket.id, +// tag = "", +// upDowngrade = (ticket.id == container.stateFlow.value.userSubscription?.type?.id), +// ), +// ) +// } - private fun fetchTickets() = intent { - billingRepository.getTickets().onSuccess { tickets -> - reduce { state.copy(tickets = tickets) } + private fun fetchTickets() { + viewModelScope.launch { + billingRepository.getTickets().onSuccess { tickets -> + tickets.firstOrNull()?.let { ticket -> + UiState.Loaded( + id = ticket.id, + subscriptionProductId = ticket.subscriptionProductId, + planId = ticket.planId, + productName = ticket.productName, + description = ticket.description, + subDescription = ticket.subDescription, + originPrice = DecimalFormat("#,###원").format(ticket.originPrice), + sellPrice = DecimalFormat("#,###원").format(ticket.sellPrice), + discountRate = ticket.discountRate, + ) + }?.also { + _uiState.emit(it) + } + }.onFailure { + _uiState.emit(UiState.Failure) + } } } + + sealed interface UiState { + data object Loading : UiState + data class Loaded( + val id: String, + val subscriptionProductId: String, + val planId: String, + val productName: String, + val description: String, + val subDescription: String, + val originPrice: String, + val sellPrice: String, + val discountRate: Int, + ) : UiState + + data object Failure : UiState + } } diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index dcb32796..cbc21ce8 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -108,4 +108,5 @@ %d원 %d원/월 구독중 + %d%% \ No newline at end of file From 2454bee680c5c7959ada3baa6689a9b8dd3b5392 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Fri, 16 Aug 2024 01:36:24 +0900 Subject: [PATCH 08/27] =?UTF-8?q?#89=20feat:=20=EC=9D=B4=EC=9A=A9=EA=B6=8C?= =?UTF-8?q?=20=EA=B5=AC=EB=A7=A4=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20?= =?UTF-8?q?=EB=A1=9C=EB=94=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/purchase/PurchaseFragment.kt | 8 ++++++-- presentation/src/main/res/layout/fragment_purchase.xml | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt index fa2dc73e..5a3079d1 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt @@ -57,8 +57,12 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB viewModel.uiState.collect { state -> when (state) { PurchaseViewModel.UiState.Failure -> Unit // TODO JH: 처리 필요 - is PurchaseViewModel.UiState.Loaded -> updateUi(state) - PurchaseViewModel.UiState.Loading -> Unit // TODO JH: 처리 필요 + is PurchaseViewModel.UiState.Loaded -> { + binding.pbLoading.isVisible = false + updateUi(state) + } + + PurchaseViewModel.UiState.Loading -> binding.pbLoading.isVisible = true } } } diff --git a/presentation/src/main/res/layout/fragment_purchase.xml b/presentation/src/main/res/layout/fragment_purchase.xml index 8d1e719a..75dfa1dc 100644 --- a/presentation/src/main/res/layout/fragment_purchase.xml +++ b/presentation/src/main/res/layout/fragment_purchase.xml @@ -122,4 +122,14 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" tools:text="구독하기" /> + + \ No newline at end of file From 919d92430b04fca85c40474a8773e7625643f38a Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Fri, 16 Aug 2024 01:41:35 +0900 Subject: [PATCH 09/27] =?UTF-8?q?#89=20feat:=20=EA=B5=AC=EB=8F=85=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EB=B2=84=ED=8A=BC=EC=97=90=20=ED=81=B4=EB=A6=AD=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=EB=84=88=EB=A5=BC=20=EB=8B=A8=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존에 있던 buyPlans를 호출하도록 하였고 ivBack 리스너도 함수 역할에 맞게 initListeners 안으로 이동함 --- .../presentation/ui/purchase/PurchaseFragment.kt | 16 +++++++++------- .../ui/purchase/PurchaseViewModel.kt | 11 ----------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt index 5a3079d1..d6b8f0ce 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt @@ -28,6 +28,7 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB super.onViewCreated(view, savedInstanceState) initViews() + initListeners() initObserve() } @@ -35,17 +36,18 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB tbPurchase.apply { tvTitle.text = getString(R.string.purchase_ticket) tvButton.isVisible = false - ivBack.setOnClickListener { findNavController().popBackStack() } } } - private fun handleEvent(event: PurchaseEvent) { - when (event) { - is PurchaseEvent.StartPurchase -> { + private fun initListeners() { + binding.tbPurchase.ivBack.setOnClickListener { findNavController().popBackStack() } + + binding.btnSubscribe.setOnClickListener { + (viewModel.uiState.value as? PurchaseViewModel.UiState.Loaded)?.let { loaded -> billingViewModel.buyPlans( - productId = event.productId, - tag = event.tag, - upDowngrade = event.upDowngrade, + productId = loaded.id, + tag = "", + upDowngrade = false, ) } } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt index 0897c922..1e5e100d 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseViewModel.kt @@ -24,17 +24,6 @@ class PurchaseViewModel @Inject constructor( fetchTickets() } - // TODO JH: 수정 -// fun startPurchase(ticket: Ticket) = intent { -// postSideEffect( -// PurchaseEvent.StartPurchase( -// productId = ticket.id, -// tag = "", -// upDowngrade = (ticket.id == container.stateFlow.value.userSubscription?.type?.id), -// ), -// ) -// } - private fun fetchTickets() { viewModelScope.launch { billingRepository.getTickets().onSuccess { tickets -> From 6cbdf3f199be6cf52c980e819daafdd60b36cfcd Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Fri, 16 Aug 2024 01:47:12 +0900 Subject: [PATCH 10/27] =?UTF-8?q?#89=20feat:=20=EC=9D=B4=EC=9A=A9=EA=B6=8C?= =?UTF-8?q?=20=EA=B5=AC=EB=A7=A4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20ui=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit '구독하기' 문구 빠진거 추가하고 '/월' 표시를 추가했음 --- .../src/main/res/layout/fragment_purchase.xml | 18 ++++++++++++++---- presentation/src/main/res/values/strings.xml | 2 ++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/presentation/src/main/res/layout/fragment_purchase.xml b/presentation/src/main/res/layout/fragment_purchase.xml index 75dfa1dc..86b1e1a6 100644 --- a/presentation/src/main/res/layout/fragment_purchase.xml +++ b/presentation/src/main/res/layout/fragment_purchase.xml @@ -105,11 +105,21 @@ style="@style/Pretendard.24" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:textColor="@color/White" + app:layout_constraintBottom_toBottomOf="@id/tv_name" + app:layout_constraintEnd_toStartOf="@id/tv_month" + tools:text="9,900원" /> + + + app:layout_constraintEnd_toEndOf="@id/guide_end" /> + app:layout_constraintStart_toStartOf="parent" /> %d원 %d원/월 구독중 + 구독하기 + /월 %d%% \ No newline at end of file From 172a4d264169062cc80a194dcfa9edccfde44788 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Fri, 16 Aug 2024 02:11:26 +0900 Subject: [PATCH 11/27] =?UTF-8?q?#89=20feat:=20=EB=A7=88=EC=9D=B4=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=83=88=EB=A1=9C=20=EB=B0=94?= =?UTF-8?q?=EB=80=90=20ui=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/mypage/MypageFragment.kt | 11 +- .../main/res/drawable/ic_navigate_next.xml | 9 + .../src/main/res/layout/fragment_mypage.xml | 184 +++++++----------- presentation/src/main/res/values/strings.xml | 1 + 4 files changed, 90 insertions(+), 115 deletions(-) create mode 100644 presentation/src/main/res/drawable/ic_navigate_next.xml diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt index 3b4c4f46..c798d213 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt @@ -33,13 +33,15 @@ class MypageFragment : BaseFragment(FragmentMypageBinding tvTitle.text = getString(R.string.mypage_title) ivBack.setOnClickListener { findNavController().popBackStack() } } - tvPurchaseTicketButton.setOnClickListener { goToPurchase(state.userSubscribeStatus.subscribeStatus) } + // TODO JH: 수정 예정 +// tvPurchaseTicketButton.setOnClickListener { goToPurchase(state.userSubscribeStatus.subscribeStatus) } tvLogoutButton.setOnClickListener { viewModel.logout() } } private fun render(state: MypageState) = with(binding) { pbLoading.isVisible = state.loading - groupRemoteData.isVisible = !state.loading + // TODO JH: 수정 예정 +// groupRemoteData.isVisible = !state.loading tvShopName.text = state.shopName /*tvPurchaseTicketButton.text = if (state.userSubscribeStatus.subscribeStatus == SubscribeStatus.Subscription) { @@ -47,8 +49,9 @@ class MypageFragment : BaseFragment(FragmentMypageBinding } else { getString(R.string.purchase_ticket) }*/ - tvSubsName.text = state.userSubscription?.type?.name ?: "" - tvSubsPeriod.text = state.period + // TODO JH: 수정 예정 +// tvSubsName.text = state.userSubscription?.type?.name ?: "" +// tvSubsPeriod.text = state.period } private fun goToPurchase(subscribeStatus: SubscribeStatus) { diff --git a/presentation/src/main/res/drawable/ic_navigate_next.xml b/presentation/src/main/res/drawable/ic_navigate_next.xml new file mode 100644 index 00000000..f38dfb7f --- /dev/null +++ b/presentation/src/main/res/drawable/ic_navigate_next.xml @@ -0,0 +1,9 @@ + + + diff --git a/presentation/src/main/res/layout/fragment_mypage.xml b/presentation/src/main/res/layout/fragment_mypage.xml index 393d7b17..2eae3212 100644 --- a/presentation/src/main/res/layout/fragment_mypage.xml +++ b/presentation/src/main/res/layout/fragment_mypage.xml @@ -10,131 +10,83 @@ android:id="@+id/tb_mypage" layout="@layout/common_toolbar" /> - + android:orientation="vertical" + app:layout_constraintGuide_begin="20dp" /> - + - + - + - + - + - - - - - - - - + app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintTop_toTopOf="@id/tv_subscribe" /> + + \ No newline at end of file diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 32622afc..1297ab60 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -109,6 +109,7 @@ %d원/월 구독중 구독하기 + 구독 /월 %d%% \ No newline at end of file From a6cb181eeebfeb0ff42447a6db19d70be66507c5 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Fri, 16 Aug 2024 02:28:51 +0900 Subject: [PATCH 12/27] =?UTF-8?q?#89=20feat:=20=EB=A7=88=EC=9D=B4=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit orbit을 걷어내고 새로 바뀐 api response에 맞게 로직 변경 --- .../ui/adminmain/AdminMainFragment.kt | 5 +- .../presentation/ui/mypage/MypageFragment.kt | 57 +++++++++------- .../presentation/ui/mypage/MypageViewModel.kt | 68 ++++++++++--------- .../src/main/res/navigation/nav_graph.xml | 4 -- 4 files changed, 72 insertions(+), 62 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt index 75bb09d0..6efa45d9 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt @@ -8,7 +8,6 @@ import androidx.core.view.isVisible import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController -import com.nextroom.nextroom.domain.model.SubscribeStatus import com.nextroom.nextroom.domain.repository.StatisticsRepository import com.nextroom.nextroom.presentation.R import com.nextroom.nextroom.presentation.base.BaseFragment @@ -148,8 +147,8 @@ class AdminMainFragment : } } - private fun goToPurchase(subscribeStatus: SubscribeStatus = state.userSubscribeStatus.subscribeStatus) { - val action = AdminMainFragmentDirections.actionAdminMainFragmentToPurchaseFragment(subscribeStatus) + private fun goToPurchase() { + val action = AdminMainFragmentDirections.actionAdminMainFragmentToPurchaseFragment() findNavController().safeNavigate(action) } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt index c798d213..77bac07d 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt @@ -9,53 +9,64 @@ import com.nextroom.nextroom.domain.model.SubscribeStatus import com.nextroom.nextroom.presentation.R import com.nextroom.nextroom.presentation.base.BaseFragment import com.nextroom.nextroom.presentation.databinding.FragmentMypageBinding +import com.nextroom.nextroom.presentation.extension.repeatOnStarted import com.nextroom.nextroom.presentation.extension.safeNavigate import dagger.hilt.android.AndroidEntryPoint -import org.orbitmvi.orbit.viewmodel.observe +import kotlinx.coroutines.launch @AndroidEntryPoint class MypageFragment : BaseFragment(FragmentMypageBinding::inflate) { private val viewModel: MypageViewModel by viewModels() - private val state: MypageState - get() = viewModel.container.stateFlow.value override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initViews() - viewModel.observe(viewLifecycleOwner, state = ::render) + initListeners() + initObserve() } private fun initViews() = with(binding) { tbMypage.apply { tvButton.isVisible = false tvTitle.text = getString(R.string.mypage_title) - ivBack.setOnClickListener { findNavController().popBackStack() } } - // TODO JH: 수정 예정 -// tvPurchaseTicketButton.setOnClickListener { goToPurchase(state.userSubscribeStatus.subscribeStatus) } + } + + private fun initListeners() = with(binding) { + tbMypage.ivBack.setOnClickListener { findNavController().popBackStack() } tvLogoutButton.setOnClickListener { viewModel.logout() } + clSubscribe.setOnClickListener { + (viewModel.uiState.value as? MypageViewModel.UiState.Loaded)?.let { loaded -> + when (loaded.status) { + SubscribeStatus.Default -> goToPurchase() + SubscribeStatus.Subscribed -> Unit // TODO JH: 구독중일 때 처리 구현 + } + } + } } - private fun render(state: MypageState) = with(binding) { - pbLoading.isVisible = state.loading - // TODO JH: 수정 예정 -// groupRemoteData.isVisible = !state.loading - - tvShopName.text = state.shopName - /*tvPurchaseTicketButton.text = if (state.userSubscribeStatus.subscribeStatus == SubscribeStatus.Subscription) { - getString(R.string.purchase_change_ticket) - } else { - getString(R.string.purchase_ticket) - }*/ - // TODO JH: 수정 예정 -// tvSubsName.text = state.userSubscription?.type?.name ?: "" -// tvSubsPeriod.text = state.period + private fun initObserve() { + viewLifecycleOwner.repeatOnStarted { + launch { + viewModel.uiState.collect { state -> + when (state) { + MypageViewModel.UiState.Failure -> Unit // TODO JH: 처리 어떻게 할지 결정 + is MypageViewModel.UiState.Loaded -> { + binding.tvShopName.text = state.shopName + binding.pbLoading.isVisible = false + } + + MypageViewModel.UiState.Loading -> binding.pbLoading.isVisible = true + } + } + } + } } - private fun goToPurchase(subscribeStatus: SubscribeStatus) { - val action = MypageFragmentDirections.actionMypageFragmentToPurchaseFragment(subscribeStatus) + private fun goToPurchase() { + val action = MypageFragmentDirections.actionMypageFragmentToPurchaseFragment() findNavController().safeNavigate(action) } } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt index 90a37148..8f96f44e 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt @@ -1,53 +1,57 @@ package com.nextroom.nextroom.presentation.ui.mypage +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.nextroom.nextroom.domain.model.SubscribeStatus +import com.nextroom.nextroom.domain.model.onFailure +import com.nextroom.nextroom.domain.model.onSuccess import com.nextroom.nextroom.domain.repository.AdminRepository -import com.nextroom.nextroom.presentation.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel -import org.orbitmvi.orbit.Container -import org.orbitmvi.orbit.syntax.simple.intent -import org.orbitmvi.orbit.syntax.simple.reduce -import org.orbitmvi.orbit.viewmodel.container +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class MypageViewModel @Inject constructor( private val adminRepository: AdminRepository, -) : BaseViewModel() { +) : ViewModel() { - override val container: Container = container(MypageState(loading = true)) + private val _uiState = MutableStateFlow(UiState.Loading) + val uiState = _uiState.asStateFlow() init { - fetchShopName() - fetchSubsInfo() + fetchMyInfo() } - fun logout() = intent { - adminRepository.logout() + fun logout() { + viewModelScope.launch { + adminRepository.logout() + } } - private fun fetchShopName() = intent { - adminRepository.shopName.collect { - reduce { state.copy(shopName = it) } + private fun fetchMyInfo() { + viewModelScope.launch { + adminRepository.getUserSubscribe().onSuccess { mypage -> + UiState.Loaded( + shopName = mypage.name, + status = mypage.status, + ).also { + _uiState.emit(it) + } + }.onFailure { + _uiState.emit(UiState.Failure) + } } } - private fun fetchSubsInfo() = intent { - reduce { state.copy(loading = true) } - // TODO JH: 임시로 주석 -// adminRepository.getUserSubscribeStatus().suspendConcatMap( -// other = adminRepository.geUserSubscribe(), -// ) { subsStatus, mypageInfo -> -// reduce { -// state.copy( -// loading = false, -// userSubscribeStatus = subsStatus, -// userSubscription = mypageInfo, -// ) -// } -// }.onFinally { -// reduce { -// state.copy(loading = false) -// } -// } + sealed interface UiState { + data object Loading : UiState + data class Loaded( + val shopName: String, + val status: SubscribeStatus, + ) : UiState + + data object Failure : UiState } } diff --git a/presentation/src/main/res/navigation/nav_graph.xml b/presentation/src/main/res/navigation/nav_graph.xml index 9f9d3d53..a3cea971 100644 --- a/presentation/src/main/res/navigation/nav_graph.xml +++ b/presentation/src/main/res/navigation/nav_graph.xml @@ -154,10 +154,6 @@ android:name="com.nextroom.nextroom.presentation.ui.purchase.PurchaseFragment" android:label="PurchaseFragment" tools:layout="@layout/fragment_purchase"> - Date: Sun, 18 Aug 2024 16:57:53 +0900 Subject: [PATCH 13/27] =?UTF-8?q?#89=20feat:=20=EA=B5=AC=EB=8F=85=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20ui=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/layout/fragment_subscription_info.xml | 75 +++++++++++++++++++ presentation/src/main/res/values/strings.xml | 4 + 2 files changed, 79 insertions(+) create mode 100644 presentation/src/main/res/layout/fragment_subscription_info.xml diff --git a/presentation/src/main/res/layout/fragment_subscription_info.xml b/presentation/src/main/res/layout/fragment_subscription_info.xml new file mode 100644 index 00000000..eb506965 --- /dev/null +++ b/presentation/src/main/res/layout/fragment_subscription_info.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 1297ab60..d583672a 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -103,13 +103,17 @@ 지금 바로 넥스트룸을 사용해보세요 일시적인 오류이거나 서비스 장애입니다. 다시 시도하여도 해당 메시지가 계속 보일 경우 상태 코드와 함께 문의 바랍니다.\n상태 코드: %d 구독 기간 + 구독 상태 + 구독 정보 마이페이지 이동 My %d원 %d원/월 구독중 + 구독하지 않음 구독하기 구독 /월 %d%% + %s ~ %s \ No newline at end of file From aac16e0ed88834af00e65f407f96b76d343cfe7b Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sun, 18 Aug 2024 16:58:22 +0900 Subject: [PATCH 14/27] =?UTF-8?q?#89=20feat:=20=EA=B5=AC=EB=8F=85=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/mypage/SubscriptionInfoFragment.kt | 89 +++++++++++++++++++ .../ui/mypage/SubscriptionInfoViewModel.kt | 53 +++++++++++ 2 files changed, 142 insertions(+) create mode 100644 presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt create mode 100644 presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoViewModel.kt diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt new file mode 100644 index 00000000..69b3c54c --- /dev/null +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt @@ -0,0 +1,89 @@ +package com.nextroom.nextroom.presentation.ui.mypage + +import android.os.Bundle +import android.view.View +import androidx.core.view.isVisible +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import com.nextroom.nextroom.domain.model.SubscribeStatus +import com.nextroom.nextroom.presentation.R +import com.nextroom.nextroom.presentation.base.BaseFragment +import com.nextroom.nextroom.presentation.databinding.FragmentSubscriptionInfoBinding +import com.nextroom.nextroom.presentation.extension.repeatOnStarted +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import java.text.SimpleDateFormat +import java.util.Locale + +@AndroidEntryPoint +class SubscriptionInfoFragment : + BaseFragment(FragmentSubscriptionInfoBinding::inflate) { + private val viewModel: SubscriptionInfoViewModel by viewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + initViews() + initListeners() + initObserve() + } + + private fun initViews() = with(binding) { + tbSubscriptionInfo.apply { + tvButton.isVisible = false + tvTitle.text = getString(R.string.subscription_info) + } + } + + private fun initObserve() { + viewLifecycleOwner.repeatOnStarted { + launch { + viewModel.uiState.collect { state -> + when (state) { + SubscriptionInfoViewModel.UiState.Failure -> Unit // TODO JH: 처리 어떻게 할지 결정 + is SubscriptionInfoViewModel.UiState.Loaded -> { + binding.tvSubscriptionStatus.text = when (state.subscribeStatus) { + SubscribeStatus.Default -> getString(R.string.ticket_subscribing) + SubscribeStatus.Subscribed -> getString(R.string.ticket_not_subscribe) + } + binding.tvSubscriptionPeriod.text = getSubscriptionPeriod(state.startDate, state.endDate) + binding.pbLoading.isVisible = false + } + + SubscriptionInfoViewModel.UiState.Loading -> binding.pbLoading.isVisible = true + } + } + } + } + } + + private fun getSubscriptionPeriod(startDate: String?, endDate: String?): String { + return try { + requireNotNull(startDate) + requireNotNull(endDate) + + val inputFormat = SimpleDateFormat(apiDateFormatter, Locale.getDefault()) + val outputFormat = SimpleDateFormat(uiDateFormatter, Locale.getDefault()) + + val start = inputFormat.parse(startDate) + val end = inputFormat.parse(endDate) + + String.format( + getString(R.string.date_range_format), + outputFormat.format(start), + outputFormat.format(end), + ) + } catch (e: Exception) { + "" + } + } + + private fun initListeners() { + binding.tbSubscriptionInfo.ivBack.setOnClickListener { findNavController().popBackStack() } + } + + companion object { + const val apiDateFormatter = "yyyy-MM-dd" + const val uiDateFormatter = "yyyy.M.d" + } +} diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoViewModel.kt new file mode 100644 index 00000000..61e6badd --- /dev/null +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoViewModel.kt @@ -0,0 +1,53 @@ +package com.nextroom.nextroom.presentation.ui.mypage + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.nextroom.nextroom.domain.model.SubscribeStatus +import com.nextroom.nextroom.domain.model.onFailure +import com.nextroom.nextroom.domain.model.onSuccess +import com.nextroom.nextroom.domain.repository.AdminRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SubscriptionInfoViewModel @Inject constructor( + private val adminRepository: AdminRepository, +) : ViewModel() { + + private val _uiState = MutableStateFlow(UiState.Loading) + val uiState = _uiState.asStateFlow() + + init { + fetchMyInfo() + } + + private fun fetchMyInfo() { + viewModelScope.launch { + adminRepository.getUserSubscribe().onSuccess { mypage -> + UiState.Loaded( + subscribeStatus = mypage.status, + startDate = mypage.startDate, + endDate = mypage.expiryDate, + ).also { + _uiState.emit(it) + } + }.onFailure { + _uiState.emit(UiState.Failure) + } + } + } + + sealed interface UiState { + data object Loading : UiState + data class Loaded( + val subscribeStatus: SubscribeStatus, + val startDate: String?, + val endDate: String?, + ) : UiState + + data object Failure : UiState + } +} From 91aaf064b120b76a0f969564e9671bbf9d40e23a Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sun, 18 Aug 2024 16:59:35 +0900 Subject: [PATCH 15/27] =?UTF-8?q?#89=20feat:=20=EA=B5=AC=EB=8F=85=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=ED=8E=98=EC=9D=B4=EC=A7=80=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextroom/presentation/ui/mypage/MypageFragment.kt | 7 ++++++- presentation/src/main/res/navigation/nav_graph.xml | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt index 77bac07d..b9b475de 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt @@ -41,7 +41,7 @@ class MypageFragment : BaseFragment(FragmentMypageBinding (viewModel.uiState.value as? MypageViewModel.UiState.Loaded)?.let { loaded -> when (loaded.status) { SubscribeStatus.Default -> goToPurchase() - SubscribeStatus.Subscribed -> Unit // TODO JH: 구독중일 때 처리 구현 + SubscribeStatus.Subscribed -> goToSubscriptionInfo() } } } @@ -69,4 +69,9 @@ class MypageFragment : BaseFragment(FragmentMypageBinding val action = MypageFragmentDirections.actionMypageFragmentToPurchaseFragment() findNavController().safeNavigate(action) } + + private fun goToSubscriptionInfo() { + val action = MypageFragmentDirections.actionMypageFragmentToSubscriptionFragment() + findNavController().safeNavigate(action) + } } diff --git a/presentation/src/main/res/navigation/nav_graph.xml b/presentation/src/main/res/navigation/nav_graph.xml index a3cea971..bd7ce696 100644 --- a/presentation/src/main/res/navigation/nav_graph.xml +++ b/presentation/src/main/res/navigation/nav_graph.xml @@ -148,7 +148,14 @@ + + Date: Sun, 18 Aug 2024 18:26:21 +0900 Subject: [PATCH 16/27] =?UTF-8?q?#89=20chore:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/adminmain/AdminMainFragment.kt | 62 +-------------- .../ui/adminmain/AdminMainViewModel.kt | 17 ---- .../presentation/ui/purchase/PurchaseEvent.kt | 9 --- .../presentation/ui/purchase/PurchaseState.kt | 16 ---- .../presentation/ui/purchase/TicketAdapter.kt | 78 ------------------- .../presentation/ui/purchase/TicketUiModel.kt | 45 ----------- .../main/res/layout/fragment_admin_main.xml | 15 ---- .../src/main/res/layout/item_ticket.xml | 77 ------------------ 8 files changed, 1 insertion(+), 318 deletions(-) delete mode 100644 presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseEvent.kt delete mode 100644 presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseState.kt delete mode 100644 presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketAdapter.kt delete mode 100644 presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketUiModel.kt delete mode 100644 presentation/src/main/res/layout/item_ticket.xml diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt index 6efa45d9..651a08f0 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt @@ -5,7 +5,6 @@ import android.os.Bundle import android.view.View import androidx.activity.OnBackPressedCallback import androidx.core.view.isVisible -import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.nextroom.nextroom.domain.repository.StatisticsRepository @@ -55,7 +54,6 @@ class AdminMainFragment : super.onViewCreated(view, savedInstanceState) initViews() - setFragmentResultListeners() viewModel.observe(viewLifecycleOwner, state = ::render, sideEffect = ::handleEvent) } @@ -86,52 +84,16 @@ class AdminMainFragment : ivMyButton.setOnClickListener { goToMyPage() } -// tvLogoutButton.apply { -// addMargin(top = requireContext().statusBarHeight) -// setOnClickListener { logout() } -// } + srlTheme.setOnRefreshListener { viewModel.loadData() } - /*tvResignButton.addMargin(top = requireContext().statusBarHeight) - tvResignButton.setOnClickListener { - AdminMainFragmentDirections - .actionGlobalNrTwoButtonDialog( - NRTwoButtonDialog.NRTwoButtonArgument( - title = getString(R.string.resign_dialog_title), - message = getString(R.string.resign_dialog_message), - posBtnText = getString(R.string.resign), - negBtnText = getString(R.string.dialog_no), - dialogKey = REQUEST_KEY_RESIGN, - ) - ) - .also { findNavController().safeNavigate(it) } - }*/ - } - - private fun setFragmentResultListeners() { - setFragmentResultListener(REQUEST_KEY_RESIGN) { _, _ -> - viewModel.resign() - } } private fun render(state: AdminMainState) = with(binding) { if (state.loading) return@with // tvPurchaseTicketButton.isVisible = state.userSubscribeStatus.subscribeStatus != SubscribeStatus.Subscription -// when (state.userSubscribeStatus.subscribeStatus) { -// SubscribeStatus.Expiration -> logout() -// SubscribeStatus.Hold, SubscribeStatus.SubscriptionExpiration -> goToPurchase(state.userSubscribeStatus.subscribeStatus) -// SubscribeStatus.Free -> { -// if (viewModel.isFirstLaunchOfDay) { // 하루 최초 한 번 다이얼로그 표시 -// state.calculateDday().let { dday -> -// if (dday >= 0) showDialog(dday) -// } -// } -// } -// -// SubscribeStatus.None, SubscribeStatus.Subscription -> Unit -// } srlTheme.isRefreshing = false tvShopName.text = state.showName llEmptyThemeGuide.isVisible = state.themes.isEmpty() @@ -163,24 +125,6 @@ class AdminMainFragment : findNavController().safeNavigate(action) } - /*private fun showDialog(dDay: Int) { - NRImageDialog.Builder(requireContext()) - .setTitle(getString(R.string.dialog_free_plan_title, dDay)) - .setMessage(getString(R.string.dialog_free_plan_message)) - .setImage(R.drawable.ticket) - .setNegativeButton(getString(R.string.dialog_close)) { dialog, _ -> - dialog.dismiss() - } - .setPositiveButton(getString(R.string.dialog_subscribe_button)) { _, _ -> - goToPurchase() - } - .show(childFragmentManager) - }*/ - - private fun logout() { - viewModel.logout() - } - override fun onDestroyView() { binding.rvThemes.adapter = null super.onDestroyView() @@ -190,8 +134,4 @@ class AdminMainFragment : super.onDetach() backCallback.remove() } - - companion object { - const val REQUEST_KEY_RESIGN = "REQUEST_KEY_RESIGN" - } } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt index 9ae688f5..6d864958 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt @@ -32,9 +32,6 @@ class AdminMainViewModel @Inject constructor( override val container: Container = container(AdminMainState(loading = true)) - val isFirstLaunchOfDay: Boolean - get() = dataStoreRepository.isFirstInitOfDay - init { loadData() @@ -74,20 +71,6 @@ class AdminMainViewModel @Inject constructor( } } - fun logout() { - viewModelScope.launch { adminRepository.logout() } - } - - fun resign() = intent { - viewModelScope.launch { - adminRepository.resign().onSuccess { - postSideEffect(AdminMainEvent.OnResign) - }.onFailure { - postSideEffect(AdminMainEvent.UnknownError) - } - } - } - fun loadData() = intent { reduce { state.copy(loading = true) } /*adminRepository.getUserSubscribeStatus().suspendOnSuccess { diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseEvent.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseEvent.kt deleted file mode 100644 index 82af0f34..00000000 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseEvent.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.nextroom.nextroom.presentation.ui.purchase - -sealed interface PurchaseEvent { - data class StartPurchase( - val productId: String, - val tag: String, - val upDowngrade: Boolean, - ) : PurchaseEvent -} diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseState.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseState.kt deleted file mode 100644 index 894d4aad..00000000 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseState.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.nextroom.nextroom.presentation.ui.purchase - -import com.nextroom.nextroom.domain.model.SubscribeStatus -import com.nextroom.nextroom.domain.model.Ticket -import com.nextroom.nextroom.domain.model.UserSubscription - -data class PurchaseState( - val subscribeStatus: SubscribeStatus = SubscribeStatus.Default, - val userSubscription: UserSubscription? = UserSubscription(), - private val tickets: List = emptyList(), -) { - val ticketsForUi: List - get() = tickets.map { - it.toPresentation(it.id == userSubscription?.type?.id) - } -} diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketAdapter.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketAdapter.kt deleted file mode 100644 index e05fbdab..00000000 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketAdapter.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.nextroom.nextroom.presentation.ui.purchase - -import android.text.Spannable -import android.text.SpannableString -import android.text.style.AbsoluteSizeSpan -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.core.view.isVisible -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView.ViewHolder -import com.nextroom.nextroom.domain.model.Ticket -import com.nextroom.nextroom.presentation.databinding.ItemTicketBinding -import com.nextroom.nextroom.presentation.extension.strikeThrow -import java.text.DecimalFormat - -class TicketAdapter( - private val onClickTicket: (Ticket) -> Unit, -) : ListAdapter(diffUtil) { - - class TicketViewHolder( - private val binding: ItemTicketBinding, - private val onClickTicket: (Ticket) -> Unit, - ) : ViewHolder(binding.root) { - private lateinit var item: TicketUiModel - - init { - binding.root.setOnClickListener { - if (!item.subscribing) onClickTicket(item.toDomain()) - } - } - - fun bind(ticket: TicketUiModel) = with(binding) { - item = ticket - - tvName.text = ticket.productName - tvDescription.text = ticket.description - tvOriginPrice.isVisible = ticket.originPrice != null - ticket.originPrice?.let { - tvOriginPrice.text = DecimalFormat("#,###원").format(it) - tvOriginPrice.strikeThrow() - } - val intervalUnitText = "/월" - val sellPriceText = DecimalFormat("#,###원$intervalUnitText").format(ticket.sellPrice) - tvSellPrice.text = SpannableString(sellPriceText).apply { - val i = sellPriceText.lastIndexOf(intervalUnitText) - setSpan( - AbsoluteSizeSpan(14, true), - i, - i + intervalUnitText.length, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE, - ) - } - tvSubscribingBadge.isVisible = ticket.subscribing - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TicketViewHolder { - val binding = ItemTicketBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return TicketViewHolder(binding, ::onClickTicket.get()) - } - - override fun onBindViewHolder(holder: TicketViewHolder, position: Int) { - holder.bind(currentList[position]) - } - - companion object { - private val diffUtil = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: TicketUiModel, newItem: TicketUiModel): Boolean { - return oldItem.id == newItem.id - } - - override fun areContentsTheSame(oldItem: TicketUiModel, newItem: TicketUiModel): Boolean { - return oldItem == newItem - } - } - } -} diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketUiModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketUiModel.kt deleted file mode 100644 index 42194615..00000000 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/TicketUiModel.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.nextroom.nextroom.presentation.ui.purchase - -import com.nextroom.nextroom.domain.model.Ticket - -data class TicketUiModel( - val id: String, - val subscriptionProductId: String, - val planId: String, - val productName: String, - val description: String, - val subDescription: String, - val originPrice: Int?, - val sellPrice: Int, - val discountRate: Int, - val subscribing: Boolean, -) { - fun toDomain(): Ticket { - return Ticket( - id = id, - subscriptionProductId = subscriptionProductId, - planId = planId, - productName = productName, - description = description, - subDescription = subDescription, - originPrice = originPrice, - sellPrice = sellPrice, - discountRate = discountRate, - ) - } -} - -fun Ticket.toPresentation(subscribing: Boolean): TicketUiModel { - return TicketUiModel( - id = id, - subscriptionProductId = subscriptionProductId, - planId = planId, - productName = productName, - description = description, - subDescription = subDescription, - originPrice = originPrice, - sellPrice = sellPrice, - discountRate = discountRate, - subscribing = subscribing, - ) -} diff --git a/presentation/src/main/res/layout/fragment_admin_main.xml b/presentation/src/main/res/layout/fragment_admin_main.xml index 35fc99be..6eee2d1c 100644 --- a/presentation/src/main/res/layout/fragment_admin_main.xml +++ b/presentation/src/main/res/layout/fragment_admin_main.xml @@ -29,21 +29,6 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - - - - - - - - - - - - - - \ No newline at end of file From f0be59bb8ebad71a4967411ba835103ded679f37 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sun, 18 Aug 2024 18:41:57 +0900 Subject: [PATCH 17/27] =?UTF-8?q?#89=20feat:=20=EB=A7=88=EC=9D=B4=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20=ED=83=88=ED=87=B4=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (테마 리스트 페이지에서는 코드 제거) --- .../ui/adminmain/AdminMainEvent.kt | 1 - .../ui/adminmain/AdminMainFragment.kt | 2 - .../presentation/ui/mypage/MypageFragment.kt | 37 +++++++++++++++++++ .../presentation/ui/mypage/MypageViewModel.kt | 20 ++++++++++ .../src/main/res/layout/fragment_mypage.xml | 13 ++++++- 5 files changed, 69 insertions(+), 4 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainEvent.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainEvent.kt index 7ade6b52..11083b3f 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainEvent.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainEvent.kt @@ -4,5 +4,4 @@ sealed interface AdminMainEvent { data object NetworkError : AdminMainEvent data object UnknownError : AdminMainEvent data class ClientError(val message: String) : AdminMainEvent - data object OnResign : AdminMainEvent } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt index 651a08f0..28010a89 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt @@ -15,7 +15,6 @@ import com.nextroom.nextroom.presentation.extension.addMargin import com.nextroom.nextroom.presentation.extension.safeNavigate import com.nextroom.nextroom.presentation.extension.snackbar import com.nextroom.nextroom.presentation.extension.statusBarHeight -import com.nextroom.nextroom.presentation.extension.toast import com.nextroom.nextroom.presentation.extension.updateSystemPadding import dagger.hilt.android.AndroidEntryPoint import org.orbitmvi.orbit.viewmodel.observe @@ -105,7 +104,6 @@ class AdminMainFragment : is AdminMainEvent.NetworkError -> snackbar(R.string.error_network) is AdminMainEvent.UnknownError -> snackbar(R.string.error_something) is AdminMainEvent.ClientError -> snackbar(event.message) - is AdminMainEvent.OnResign -> toast(R.string.resign_success_message) } } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt index b9b475de..03bcf7ce 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt @@ -3,14 +3,18 @@ package com.nextroom.nextroom.presentation.ui.mypage import android.os.Bundle import android.view.View import androidx.core.view.isVisible +import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.nextroom.nextroom.domain.model.SubscribeStatus import com.nextroom.nextroom.presentation.R import com.nextroom.nextroom.presentation.base.BaseFragment +import com.nextroom.nextroom.presentation.common.NRTwoButtonDialog import com.nextroom.nextroom.presentation.databinding.FragmentMypageBinding import com.nextroom.nextroom.presentation.extension.repeatOnStarted import com.nextroom.nextroom.presentation.extension.safeNavigate +import com.nextroom.nextroom.presentation.extension.snackbar +import com.nextroom.nextroom.presentation.extension.toast import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -25,6 +29,7 @@ class MypageFragment : BaseFragment(FragmentMypageBinding initViews() initListeners() initObserve() + setFragmentResultListeners() } private fun initViews() = with(binding) { @@ -37,6 +42,7 @@ class MypageFragment : BaseFragment(FragmentMypageBinding private fun initListeners() = with(binding) { tbMypage.ivBack.setOnClickListener { findNavController().popBackStack() } tvLogoutButton.setOnClickListener { viewModel.logout() } + tvResignButton.setOnClickListener { showConfirmResignDialog() } clSubscribe.setOnClickListener { (viewModel.uiState.value as? MypageViewModel.UiState.Loaded)?.let { loaded -> when (loaded.status) { @@ -62,6 +68,20 @@ class MypageFragment : BaseFragment(FragmentMypageBinding } } } + launch { + viewModel.uiEvent.collect { event -> + when (event) { + MypageViewModel.UiEvent.ResignFail -> snackbar(R.string.error_something) + MypageViewModel.UiEvent.ResignSuccess -> toast(R.string.resign_success_message) + } + } + } + } + } + + private fun setFragmentResultListeners() { + setFragmentResultListener(REQUEST_KEY_RESIGN) { _, _ -> + viewModel.resign() } } @@ -74,4 +94,21 @@ class MypageFragment : BaseFragment(FragmentMypageBinding val action = MypageFragmentDirections.actionMypageFragmentToSubscriptionFragment() findNavController().safeNavigate(action) } + + private fun showConfirmResignDialog() { + MypageFragmentDirections + .actionGlobalNrTwoButtonDialog( + NRTwoButtonDialog.NRTwoButtonArgument( + title = getString(R.string.resign_dialog_title), + message = getString(R.string.resign_dialog_message), + posBtnText = getString(R.string.resign), + negBtnText = getString(R.string.dialog_no), + dialogKey = REQUEST_KEY_RESIGN, + ), + ).also { findNavController().safeNavigate(it) } + } + + companion object { + const val REQUEST_KEY_RESIGN = "REQUEST_KEY_RESIGN" + } } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt index 8f96f44e..0698fc6d 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt @@ -7,7 +7,9 @@ import com.nextroom.nextroom.domain.model.onFailure import com.nextroom.nextroom.domain.model.onSuccess import com.nextroom.nextroom.domain.repository.AdminRepository import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -20,6 +22,9 @@ class MypageViewModel @Inject constructor( private val _uiState = MutableStateFlow(UiState.Loading) val uiState = _uiState.asStateFlow() + private val _uiEvent = MutableSharedFlow() + val uiEvent = _uiEvent.asSharedFlow() + init { fetchMyInfo() } @@ -45,6 +50,16 @@ class MypageViewModel @Inject constructor( } } + fun resign() { + viewModelScope.launch { + adminRepository.resign().onSuccess { + _uiEvent.emit(UiEvent.ResignSuccess) + }.onFailure { + _uiEvent.emit(UiEvent.ResignFail) + } + } + } + sealed interface UiState { data object Loading : UiState data class Loaded( @@ -54,4 +69,9 @@ class MypageViewModel @Inject constructor( data object Failure : UiState } + + sealed interface UiEvent { + data object ResignSuccess : UiEvent + data object ResignFail : UiEvent + } } diff --git a/presentation/src/main/res/layout/fragment_mypage.xml b/presentation/src/main/res/layout/fragment_mypage.xml index 2eae3212..4f8a85d2 100644 --- a/presentation/src/main/res/layout/fragment_mypage.xml +++ b/presentation/src/main/res/layout/fragment_mypage.xml @@ -95,9 +95,20 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="4dp" - android:layout_marginBottom="32dp" android:padding="16dp" android:text="@string/logout_button" + app:layout_constraintBottom_toTopOf="@id/tv_resign_button" + app:layout_constraintStart_toStartOf="parent" /> + + From cb39e40e7bc163b085ccf272dcce04cd9af68d83 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sun, 18 Aug 2024 18:53:31 +0900 Subject: [PATCH 18/27] =?UTF-8?q?#89=20feat:=20=EA=B5=AC=EB=8F=85=EC=9D=84?= =?UTF-8?q?=20=ED=95=98=EA=B3=A0=20=EC=9E=88=EB=8A=94=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=EC=97=90=EA=B2=8C=EB=8A=94=20=EC=9D=B4=EC=9A=A9?= =?UTF-8?q?=EA=B6=8C=20=EA=B5=AC=EB=A7=A4=20=EB=B2=84=ED=8A=BC=EC=9D=B4=20?= =?UTF-8?q?=EB=AF=B8=EB=85=B8=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/adminmain/AdminMainFragment.kt | 3 ++- .../presentation/ui/adminmain/AdminMainState.kt | 15 +++------------ .../ui/adminmain/AdminMainViewModel.kt | 7 ++++--- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt index 28010a89..f3b3df15 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt @@ -7,6 +7,7 @@ import androidx.activity.OnBackPressedCallback import androidx.core.view.isVisible import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController +import com.nextroom.nextroom.domain.model.SubscribeStatus import com.nextroom.nextroom.domain.repository.StatisticsRepository import com.nextroom.nextroom.presentation.R import com.nextroom.nextroom.presentation.base.BaseFragment @@ -92,7 +93,7 @@ class AdminMainFragment : private fun render(state: AdminMainState) = with(binding) { if (state.loading) return@with -// tvPurchaseTicketButton.isVisible = state.userSubscribeStatus.subscribeStatus != SubscribeStatus.Subscription + tvPurchaseButton.isVisible = state.subscribeStatus != SubscribeStatus.Subscribed srlTheme.isRefreshing = false tvShopName.text = state.showName llEmptyThemeGuide.isVisible = state.themes.isEmpty() diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt index 1b78fb6f..29b299b7 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt @@ -1,20 +1,11 @@ package com.nextroom.nextroom.presentation.ui.adminmain -import com.nextroom.nextroom.domain.model.UserSubscribeStatus +import com.nextroom.nextroom.domain.model.SubscribeStatus import com.nextroom.nextroom.presentation.model.ThemeInfoPresentation data class AdminMainState( val loading: Boolean = false, - val userSubscribeStatus: UserSubscribeStatus = UserSubscribeStatus(), + val subscribeStatus: SubscribeStatus = SubscribeStatus.Default, val showName: String = "", val themes: List = emptyList(), -) { - /*private val dateTimeUtil = DateTimeUtil() - - fun calculateDday(): Int { - return when (userSubscribeStatus.subscribeStatus) { - SubscribeStatus.Free -> dateTimeUtil.stringToDate(userSubscribeStatus.expiryDate, "yyyy.MM.dd")?.calculateDday() ?: -1 - else -> -1 - } - }*/ -} +) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt index 6d864958..fb26e796 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.viewModelScope import com.nextroom.nextroom.domain.model.Result import com.nextroom.nextroom.domain.model.onFailure import com.nextroom.nextroom.domain.model.onSuccess +import com.nextroom.nextroom.domain.model.suspendOnSuccess import com.nextroom.nextroom.domain.repository.AdminRepository import com.nextroom.nextroom.domain.repository.DataStoreRepository import com.nextroom.nextroom.domain.repository.HintRepository @@ -73,8 +74,8 @@ class AdminMainViewModel @Inject constructor( fun loadData() = intent { reduce { state.copy(loading = true) } - /*adminRepository.getUserSubscribeStatus().suspendOnSuccess { - reduce { state.copy(userSubscribeStatus = it) } + adminRepository.getUserSubscribe().suspendOnSuccess { + reduce { state.copy(subscribeStatus = it.status) } themeRepository.getThemes().onSuccess { updateThemes( it.map { themeInfo -> @@ -83,7 +84,7 @@ class AdminMainViewModel @Inject constructor( }, ) } - }*/ + } themeRepository.getThemes().onSuccess { updateThemes( it.map { themeInfo -> From 2d941f1ab5d915281c9a8348b125b867bda547a7 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sun, 18 Aug 2024 18:56:43 +0900 Subject: [PATCH 19/27] =?UTF-8?q?#89=20feat:=20=ED=86=B5=EC=8B=A0=20?= =?UTF-8?q?=EC=8B=A4=ED=8C=A8=EC=8B=9C=20=EC=9D=BC=EC=8B=9C=EC=A0=81?= =?UTF-8?q?=EC=9D=B8=20=EC=98=A4=EB=A5=98=20=EC=95=88=EB=82=B4=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EB=85=B8=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt | 2 +- .../presentation/ui/mypage/SubscriptionInfoFragment.kt | 3 ++- .../nextroom/presentation/ui/purchase/PurchaseFragment.kt | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt index 03bcf7ce..8e5643ed 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt @@ -58,7 +58,7 @@ class MypageFragment : BaseFragment(FragmentMypageBinding launch { viewModel.uiState.collect { state -> when (state) { - MypageViewModel.UiState.Failure -> Unit // TODO JH: 처리 어떻게 할지 결정 + MypageViewModel.UiState.Failure -> snackbar(R.string.error_something) is MypageViewModel.UiState.Loaded -> { binding.tvShopName.text = state.shopName binding.pbLoading.isVisible = false diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt index 69b3c54c..9e2bed03 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt @@ -10,6 +10,7 @@ import com.nextroom.nextroom.presentation.R import com.nextroom.nextroom.presentation.base.BaseFragment import com.nextroom.nextroom.presentation.databinding.FragmentSubscriptionInfoBinding import com.nextroom.nextroom.presentation.extension.repeatOnStarted +import com.nextroom.nextroom.presentation.extension.snackbar import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import java.text.SimpleDateFormat @@ -40,7 +41,7 @@ class SubscriptionInfoFragment : launch { viewModel.uiState.collect { state -> when (state) { - SubscriptionInfoViewModel.UiState.Failure -> Unit // TODO JH: 처리 어떻게 할지 결정 + SubscriptionInfoViewModel.UiState.Failure -> snackbar(R.string.error_something) is SubscriptionInfoViewModel.UiState.Loaded -> { binding.tvSubscriptionStatus.text = when (state.subscribeStatus) { SubscribeStatus.Default -> getString(R.string.ticket_subscribing) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt index d6b8f0ce..50eeca9f 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt @@ -11,6 +11,7 @@ import com.nextroom.nextroom.presentation.base.BaseFragment import com.nextroom.nextroom.presentation.databinding.FragmentPurchaseBinding import com.nextroom.nextroom.presentation.extension.repeatOnStarted import com.nextroom.nextroom.presentation.extension.safeNavigate +import com.nextroom.nextroom.presentation.extension.snackbar import com.nextroom.nextroom.presentation.extension.strikeThrow import com.nextroom.nextroom.presentation.extension.toast import com.nextroom.nextroom.presentation.ui.billing.BillingEvent @@ -58,7 +59,7 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB launch { viewModel.uiState.collect { state -> when (state) { - PurchaseViewModel.UiState.Failure -> Unit // TODO JH: 처리 필요 + PurchaseViewModel.UiState.Failure -> snackbar(R.string.error_something) is PurchaseViewModel.UiState.Loaded -> { binding.pbLoading.isVisible = false updateUi(state) From 6df9e7cca9d0f29cbba9d142a2dc65f95b6a810a Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sun, 18 Aug 2024 19:02:56 +0900 Subject: [PATCH 20/27] =?UTF-8?q?#89=20feat:=20=ED=83=88=ED=87=B4=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EB=A1=9C=EC=A7=81=20=EC=88=98=ED=96=89=EC=8B=9C=20?= =?UTF-8?q?=EB=A1=9C=EB=94=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/mypage/MypageViewModel.kt | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt index 0698fc6d..55ba0d42 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt @@ -4,13 +4,16 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.nextroom.nextroom.domain.model.SubscribeStatus import com.nextroom.nextroom.domain.model.onFailure +import com.nextroom.nextroom.domain.model.onFinally import com.nextroom.nextroom.domain.model.onSuccess import com.nextroom.nextroom.domain.repository.AdminRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.asSharedFlow -import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import javax.inject.Inject @@ -19,8 +22,19 @@ class MypageViewModel @Inject constructor( private val adminRepository: AdminRepository, ) : ViewModel() { - private val _uiState = MutableStateFlow(UiState.Loading) - val uiState = _uiState.asStateFlow() + private val _myInfo = MutableStateFlow(UiState.Loading) + private val _isResignLoading = MutableStateFlow(false) + + val uiState = combine( + _myInfo, + _isResignLoading, + ) { myInfo, isResignLoading -> + if (myInfo is UiState.Loading || isResignLoading) { + UiState.Loading + } else { + myInfo + } + }.stateIn(viewModelScope, SharingStarted.Lazily, UiState.Loading) private val _uiEvent = MutableSharedFlow() val uiEvent = _uiEvent.asSharedFlow() @@ -42,20 +56,23 @@ class MypageViewModel @Inject constructor( shopName = mypage.name, status = mypage.status, ).also { - _uiState.emit(it) + _myInfo.emit(it) } }.onFailure { - _uiState.emit(UiState.Failure) + _myInfo.emit(UiState.Failure) } } } fun resign() { viewModelScope.launch { + _isResignLoading.emit(true) adminRepository.resign().onSuccess { _uiEvent.emit(UiEvent.ResignSuccess) }.onFailure { _uiEvent.emit(UiEvent.ResignFail) + }.onFinally { + _isResignLoading.emit(false) } } } From 13ef72559dd27033803ee4f95d257e05415b8482 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sun, 18 Aug 2024 19:04:51 +0900 Subject: [PATCH 21/27] =?UTF-8?q?#89=20chore:=20=EC=98=A4=ED=83=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(showName=20->=20shopName)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 코드 보다가 오타가 있길래 수정함 --- .../nextroom/presentation/ui/adminmain/AdminMainFragment.kt | 2 +- .../nextroom/presentation/ui/adminmain/AdminMainState.kt | 2 +- .../nextroom/presentation/ui/adminmain/AdminMainViewModel.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt index f3b3df15..510b8ec9 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt @@ -95,7 +95,7 @@ class AdminMainFragment : tvPurchaseButton.isVisible = state.subscribeStatus != SubscribeStatus.Subscribed srlTheme.isRefreshing = false - tvShopName.text = state.showName + tvShopName.text = state.shopName llEmptyThemeGuide.isVisible = state.themes.isEmpty() adapter.submitList(state.themes) } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt index 29b299b7..35ce9ba4 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainState.kt @@ -6,6 +6,6 @@ import com.nextroom.nextroom.presentation.model.ThemeInfoPresentation data class AdminMainState( val loading: Boolean = false, val subscribeStatus: SubscribeStatus = SubscribeStatus.Default, - val showName: String = "", + val shopName: String = "", val themes: List = emptyList(), ) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt index fb26e796..fc4a8083 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt @@ -97,7 +97,7 @@ class AdminMainViewModel @Inject constructor( } private fun updateShopInfo(shopName: String) = intent { - reduce { state.copy(showName = shopName) } + reduce { state.copy(shopName = shopName) } } private fun updateThemes(themes: List) = intent { From e44191df2dc204407abe0906f4b229c672f5a93d Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sun, 18 Aug 2024 19:28:22 +0900 Subject: [PATCH 22/27] =?UTF-8?q?#89=20feat:=20=EA=B0=9C=EB=B0=9C=EC=9E=90?= =?UTF-8?q?=20=EB=AA=A8=EB=93=9C=EB=A5=BC=20=ED=99=9C=EC=84=B1=ED=99=94=20?= =?UTF-8?q?=ED=96=88=EC=9D=84=EB=95=8C=EB=A7=8C=20=EA=B5=AC=EB=8F=85=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=EC=9D=B4=20=EB=B3=B4?= =?UTF-8?q?=EC=9D=B4=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 임시코드 입니다~ --- .../nextroom/data/repository/AdminRepositoryImpl.kt | 10 ++++++++++ .../nextroom/domain/repository/AdminRepository.kt | 4 ++++ .../presentation/ui/adminmain/AdminMainFragment.kt | 11 ++++++++++- .../presentation/ui/adminmain/AdminMainViewModel.kt | 7 +++++++ .../nextroom/presentation/ui/mypage/MypageFragment.kt | 1 + .../presentation/ui/mypage/MypageViewModel.kt | 3 +++ .../src/main/res/layout/fragment_admin_main.xml | 9 +++++++++ presentation/src/main/res/layout/fragment_mypage.xml | 4 +++- 8 files changed, 47 insertions(+), 2 deletions(-) diff --git a/data/src/main/java/com/nextroom/nextroom/data/repository/AdminRepositoryImpl.kt b/data/src/main/java/com/nextroom/nextroom/data/repository/AdminRepositoryImpl.kt index 39299698..af3c910b 100644 --- a/data/src/main/java/com/nextroom/nextroom/data/repository/AdminRepositoryImpl.kt +++ b/data/src/main/java/com/nextroom/nextroom/data/repository/AdminRepositoryImpl.kt @@ -26,6 +26,9 @@ class AdminRepositoryImpl @Inject constructor( override val shopName: Flow = settingDataSource.shopName + // TODO: 구독 서비스 정규 오픈시 삭제 + var isDeveloperMode = false + override suspend fun login(adminCode: String, password: String): Result { return authDataSource.login(adminCode, password).onSuccess { settingDataSource.saveAdminInfo(adminCode = it.adminCode, shopName = it.shopName) @@ -54,4 +57,11 @@ class AdminRepositoryImpl @Inject constructor( override suspend fun getUserSubscribe(): Result { return subscriptionDataSource.getUserSubscription() } + + // TODO: 구독 서비스 정규 오픈시 삭제 + override fun setDeveloperMode() { + isDeveloperMode = true + } + + override fun getIsDeveloperMode() = isDeveloperMode } diff --git a/domain/src/main/java/com/nextroom/nextroom/domain/repository/AdminRepository.kt b/domain/src/main/java/com/nextroom/nextroom/domain/repository/AdminRepository.kt index 28819fe2..a51bb0b1 100644 --- a/domain/src/main/java/com/nextroom/nextroom/domain/repository/AdminRepository.kt +++ b/domain/src/main/java/com/nextroom/nextroom/domain/repository/AdminRepository.kt @@ -20,4 +20,8 @@ interface AdminRepository { suspend fun verifyAdminCode(code: String): Boolean suspend fun getUserSubscribeStatus(): Result suspend fun getUserSubscribe(): Result + + // TODO: 구독 서비스 정규 오픈시 삭제 + fun setDeveloperMode() + fun getIsDeveloperMode(): Boolean } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt index 510b8ec9..6f67baec 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainFragment.kt @@ -14,8 +14,10 @@ import com.nextroom.nextroom.presentation.base.BaseFragment import com.nextroom.nextroom.presentation.databinding.FragmentAdminMainBinding import com.nextroom.nextroom.presentation.extension.addMargin import com.nextroom.nextroom.presentation.extension.safeNavigate +import com.nextroom.nextroom.presentation.extension.setOnLongClickListener import com.nextroom.nextroom.presentation.extension.snackbar import com.nextroom.nextroom.presentation.extension.statusBarHeight +import com.nextroom.nextroom.presentation.extension.toast import com.nextroom.nextroom.presentation.extension.updateSystemPadding import dagger.hilt.android.AndroidEntryPoint import org.orbitmvi.orbit.viewmodel.observe @@ -88,12 +90,19 @@ class AdminMainFragment : srlTheme.setOnRefreshListener { viewModel.loadData() } + // TODO: 구독 서비스 정규 오픈시 삭제 + tvSecretButton.setOnLongClickListener(1000L) { + toast("개발자 모드 활성화") + viewModel.setDeveloperMode() + } } private fun render(state: AdminMainState) = with(binding) { if (state.loading) return@with - tvPurchaseButton.isVisible = state.subscribeStatus != SubscribeStatus.Subscribed + // TODO: 구독 서비스 정규 오픈시 삭제 + tvPurchaseButton.isVisible = + (viewModel.getIsDeveloperMode() && state.subscribeStatus != SubscribeStatus.Subscribed) srlTheme.isRefreshing = false tvShopName.text = state.shopName llEmptyThemeGuide.isVisible = state.themes.isEmpty() diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt index fc4a8083..fd1744ab 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/adminmain/AdminMainViewModel.kt @@ -104,6 +104,13 @@ class AdminMainViewModel @Inject constructor( reduce { state.copy(themes = themes) } } + // TODO: 구독 서비스 정규 오픈시 삭제 + fun setDeveloperMode() { + adminRepository.setDeveloperMode() + } + + fun getIsDeveloperMode() = adminRepository.getIsDeveloperMode() + private fun handleError(error: Result.Failure) = intent { when (error) { is Result.Failure.NetworkError -> postSideEffect(AdminMainEvent.NetworkError) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt index 8e5643ed..61c282aa 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageFragment.kt @@ -62,6 +62,7 @@ class MypageFragment : BaseFragment(FragmentMypageBinding is MypageViewModel.UiState.Loaded -> { binding.tvShopName.text = state.shopName binding.pbLoading.isVisible = false + binding.clSubscribe.isVisible = viewModel.getIsDeveloperMode() // TODO: 구독 서비스 정규 오픈시 삭제 } MypageViewModel.UiState.Loading -> binding.pbLoading.isVisible = true diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt index 55ba0d42..81cc44a2 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/MypageViewModel.kt @@ -77,6 +77,9 @@ class MypageViewModel @Inject constructor( } } + // TODO: 구독 서비스 정규 오픈시 삭제 + fun getIsDeveloperMode() = adminRepository.getIsDeveloperMode() + sealed interface UiState { data object Loading : UiState data class Loaded( diff --git a/presentation/src/main/res/layout/fragment_admin_main.xml b/presentation/src/main/res/layout/fragment_admin_main.xml index 6eee2d1c..4034d1df 100644 --- a/presentation/src/main/res/layout/fragment_admin_main.xml +++ b/presentation/src/main/res/layout/fragment_admin_main.xml @@ -29,6 +29,14 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + app:layout_constraintTop_toBottomOf="@id/divider" + tools:visibility="visible"> Date: Sun, 18 Aug 2024 21:13:57 +0900 Subject: [PATCH 23/27] =?UTF-8?q?#89=20fix:=20=EA=B5=AC=EB=8F=85=20id?= =?UTF-8?q?=EA=B0=80=20=EC=95=84=EB=8B=8C=20=EC=9A=B0=EB=A6=AC=EC=AA=BD=20?= =?UTF-8?q?=EC=84=9C=EB=B2=84=EC=97=90=EC=84=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EB=8A=94=20id=EB=A5=BC=20=EC=9E=98=EB=AA=BB=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8A=94=20=EA=B3=B3=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextroom/presentation/ui/purchase/PurchaseFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt index 50eeca9f..ab96ebd7 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt @@ -46,7 +46,7 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB binding.btnSubscribe.setOnClickListener { (viewModel.uiState.value as? PurchaseViewModel.UiState.Loaded)?.let { loaded -> billingViewModel.buyPlans( - productId = loaded.id, + productId = loaded.subscriptionProductId, tag = "", upDowngrade = false, ) From b62f982301f3a499c8b964b3b6c23509cb96be64 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Tue, 20 Aug 2024 01:07:49 +0900 Subject: [PATCH 24/27] =?UTF-8?q?#89=20feat:=20=EC=84=9C=EB=B2=84=EB=A1=9C?= =?UTF-8?q?=20purchaseToken=20=EB=B3=B4=EB=82=B4=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/billing/BillingViewModel.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/billing/BillingViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/billing/BillingViewModel.kt index 6f4c9741..0b3bf003 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/billing/BillingViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/billing/BillingViewModel.kt @@ -5,6 +5,9 @@ import androidx.lifecycle.viewModelScope import com.android.billingclient.api.BillingFlowParams import com.android.billingclient.api.ProductDetails import com.android.billingclient.api.Purchase +import com.nextroom.nextroom.domain.model.onFailure +import com.nextroom.nextroom.domain.model.onSuccess +import com.nextroom.nextroom.domain.repository.BillingRepository import com.nextroom.nextroom.presentation.ui.Constants import com.nextroom.nextroom.presentation.util.BillingClientLifecycle import dagger.hilt.android.lifecycle.HiltViewModel @@ -18,6 +21,7 @@ import javax.inject.Inject class BillingViewModel @Inject constructor( billingClientLifecycle: BillingClientLifecycle, + billingRepository: BillingRepository, ) : ViewModel() { // 사용자의 현재 구독 상품 구매 정보 @@ -44,8 +48,14 @@ class BillingViewModel purchases.collect { it.forEach { purchase -> if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) { - // TODO JH: 서버에서 ack 로직 구현 완료시 제거 + purchaseToken 보내는 API 호출 - billingClientLifecycle.acknowledgePurchase(purchase.purchaseToken) + billingRepository + .postPurchaseToken(purchase.purchaseToken) + .onSuccess { + _uiEvent.emit(BillingEvent.PurchaseAcknowledged) + } + .onFailure { + _uiEvent.emit(BillingEvent.PurchaseFailed(purchaseState = purchase.purchaseState)) + } } else { _uiEvent.emit(BillingEvent.PurchaseFailed(purchaseState = purchase.purchaseState)) } From fe09f995987b56cadde6bb3984799afde8517e63 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Tue, 20 Aug 2024 01:08:20 +0900 Subject: [PATCH 25/27] =?UTF-8?q?#89=20feat:=20=EA=B5=AC=EB=8F=85=20?= =?UTF-8?q?=EC=A4=91=EC=9D=BC=EB=95=8C,=20=EC=8B=A4=ED=8C=A8=20=ED=96=88?= =?UTF-8?q?=EC=9D=84=20=EB=95=8C=20=EB=A1=9C=EB=94=A9=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/purchase/PurchaseFragment.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt index ab96ebd7..63e889d8 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/purchase/PurchaseFragment.kt @@ -45,6 +45,7 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB binding.btnSubscribe.setOnClickListener { (viewModel.uiState.value as? PurchaseViewModel.UiState.Loaded)?.let { loaded -> + binding.pbLoading.isVisible = true // TODO JH: 개선 billingViewModel.buyPlans( productId = loaded.subscriptionProductId, tag = "", @@ -80,12 +81,15 @@ class PurchaseFragment : BaseFragment(FragmentPurchaseB } } - is BillingEvent.PurchaseFailed -> toast( - getString( - R.string.purchase_error_message, - event.purchaseState, - ), - ) + is BillingEvent.PurchaseFailed -> { + toast( + getString( + R.string.purchase_error_message, + event.purchaseState, + ), + ) + binding.pbLoading.isVisible = false // TODO JH: 개선 + } } } } From 03b1b85643b8d8eaedab4d09ff2009294af56f32 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Tue, 20 Aug 2024 01:09:25 +0900 Subject: [PATCH 26/27] =?UTF-8?q?#89=20fix:=20=EA=B5=AC=EB=8F=85=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=9E=98?= =?UTF-8?q?=EB=AA=BB=20=EC=84=A4=EC=A0=95=ED=95=9C=EA=B1=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/mypage/SubscriptionInfoFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt index 9e2bed03..6a42cb98 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/mypage/SubscriptionInfoFragment.kt @@ -44,8 +44,8 @@ class SubscriptionInfoFragment : SubscriptionInfoViewModel.UiState.Failure -> snackbar(R.string.error_something) is SubscriptionInfoViewModel.UiState.Loaded -> { binding.tvSubscriptionStatus.text = when (state.subscribeStatus) { - SubscribeStatus.Default -> getString(R.string.ticket_subscribing) - SubscribeStatus.Subscribed -> getString(R.string.ticket_not_subscribe) + SubscribeStatus.Default -> getString(R.string.ticket_not_subscribe) + SubscribeStatus.Subscribed -> getString(R.string.ticket_subscribing) } binding.tvSubscriptionPeriod.text = getSubscriptionPeriod(state.startDate, state.endDate) binding.pbLoading.isVisible = false From f566ccd28281af7f7007356fc4140998af733ef6 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Sun, 1 Sep 2024 15:53:50 +0900 Subject: [PATCH 27/27] =?UTF-8?q?#89=20feat:=20NRLoading=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=EB=B7=B0=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?= =?UTF-8?q?=20=EC=A0=84=EC=B2=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로딩중에 터치가 되지 않도록 커스텀뷰를 제작하여 적용함 --- .../nextroom/presentation/common/NRLoading.kt | 45 +++++++++++++++++++ .../src/main/res/layout/fragment_login.xml | 8 ++-- .../src/main/res/layout/fragment_mypage.xml | 6 +-- .../src/main/res/layout/fragment_purchase.xml | 6 +-- .../res/layout/fragment_subscription_info.xml | 6 +-- 5 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 presentation/src/main/java/com/nextroom/nextroom/presentation/common/NRLoading.kt diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/common/NRLoading.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/common/NRLoading.kt new file mode 100644 index 00000000..91d8a57f --- /dev/null +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/common/NRLoading.kt @@ -0,0 +1,45 @@ +package com.nextroom.nextroom.presentation.common + +import android.content.Context +import android.util.AttributeSet +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ProgressBar +import androidx.core.content.ContextCompat + +class NRLoading @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, +) : FrameLayout(context, attrs, defStyleAttr) { + + init { + // 레이아웃의 크기를 부모의 크기로 설정 + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + ) + + // 배경을 투명하게 설정 + setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent)) + + // ProgressBar를 가운데에 배치 + val progressBar = ProgressBar(context).apply { + layoutParams = LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT, + ).apply { + // 가운데 정렬 + gravity = android.view.Gravity.CENTER + } + } + + // 로딩중에 하위 뷰 터치 막기 + setOnTouchListener { _, _ -> + true + } + + // ProgressBar를 이 뷰에 추가 + addView(progressBar) + } +} diff --git a/presentation/src/main/res/layout/fragment_login.xml b/presentation/src/main/res/layout/fragment_login.xml index b62eef1c..beecea2c 100644 --- a/presentation/src/main/res/layout/fragment_login.xml +++ b/presentation/src/main/res/layout/fragment_login.xml @@ -104,14 +104,14 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> - + tools:visibility="gone" /> \ No newline at end of file diff --git a/presentation/src/main/res/layout/fragment_mypage.xml b/presentation/src/main/res/layout/fragment_mypage.xml index 69932f4e..f34959e5 100644 --- a/presentation/src/main/res/layout/fragment_mypage.xml +++ b/presentation/src/main/res/layout/fragment_mypage.xml @@ -114,10 +114,10 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" /> - - -