Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -466,13 +466,14 @@ private fun MainScreenContent(
appearance = configuration.appearance,
localization = configuration.localization,
onPurchaseSelect = { purchase ->
// Only allow selection if there are multiple purchases
if (state.purchases.size > 1) {
// Only allow selection if there are multiple purchases and the purchase has actions
if (state.purchases.size > 1 && purchase in state.purchasesWithActions) {
Comment on lines +565 to +566
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What purchase would have no actions at all? 🤔

I wonder if this check is necessary. In iOS we always navigate, even if there are no actions.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A purchase can have no detail-screen actions when it's a non-Google subscription (no Cancel/Resubscribe from our config), or it's expired with no Resubscribe path, or the management screen only has general paths (e.g. Restore, Contact support) and no subscription specific paths for that purchase. In those cases the detail screen would be empty.

The check avoids navigating to an empty detail view and only shows the caret when there’s at least one action (e.g. Cancel/Resubscribe). If we want to align with iOS and always navigate even when the detail is empty, we can remove the check but I think this is nicer? Idk

onAction(CustomerCenterAction.SelectPurchase(purchase))
}
},
onAction = onAction,
purchases = state.purchases,
purchasesWithActions = state.purchasesWithActions,
)
} ?: run {
// Handle missing management screen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ internal sealed class CustomerCenterState(
),
@get:JvmSynthetic override val navigationButtonType: NavigationButtonType = NavigationButtonType.CLOSE,
@get:JvmSynthetic val virtualCurrencies: VirtualCurrencies? = null,
@get:JvmSynthetic val purchasesWithActions: Set<PurchaseInformation> = emptySet(),
) : CustomerCenterState(navigationButtonType) {
val currentDestination: CustomerCenterDestination
get() = navigationState.currentDestination
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,22 +244,24 @@ internal class CustomerCenterViewModelImpl(
if (currentState is CustomerCenterState.Success) {
val screen = currentState.customerCenterConfigData.getManagementScreen()
if (screen != null) {
val baseSupportedPaths = supportedPaths(
val detailSupportedPaths = computeDetailScreenPaths(
purchase,
screen,
currentState.customerCenterConfigData.localization,
)

// For detail screen: only show subscription-specific actions
val detailSupportedPaths = PathUtils.filterSubscriptionSpecificPaths(baseSupportedPaths)

currentState.copy(
navigationState = currentState.navigationState.push(
CustomerCenterDestination.SelectedPurchaseDetail(purchase, screen.title),
),
navigationButtonType = CustomerCenterState.NavigationButtonType.BACK,
detailScreenPaths = detailSupportedPaths,
)
// Only navigate if there are actions available in the detail view
if (detailSupportedPaths.isNotEmpty()) {
currentState.copy(
navigationState = currentState.navigationState.push(
CustomerCenterDestination.SelectedPurchaseDetail(purchase, screen.title),
),
navigationButtonType = CustomerCenterState.NavigationButtonType.BACK,
detailScreenPaths = detailSupportedPaths,
)
} else {
currentState
}
} else {
Logger.e("No management screen available in the customer center config data")
CustomerCenterState.Error(
Expand All @@ -275,6 +277,20 @@ internal class CustomerCenterViewModelImpl(
}
}

private fun computeDetailScreenPaths(
purchase: PurchaseInformation,
screen: CustomerCenterConfigData.Screen,
localization: CustomerCenterConfigData.Localization,
): List<HelpPath> {
val baseSupportedPaths = supportedPaths(
purchase,
screen,
localization,
)
// For detail screen: only show subscription-specific actions
return PathUtils.filterSubscriptionSpecificPaths(baseSupportedPaths)
}

override fun onCustomActionSelected(customActionData: CustomActionData) {
notifyListenersForCustomActionSelected(customActionData)
}
Expand Down Expand Up @@ -523,6 +539,19 @@ internal class CustomerCenterViewModelImpl(
}
}

private fun computePurchasesWithActions(state: CustomerCenterState.Success): Set<PurchaseInformation> {
val screen = state.customerCenterConfigData.getManagementScreen() ?: return emptySet()

return state.purchases.filter { purchase ->
val detailPaths = computeDetailScreenPaths(
purchase,
screen,
state.customerCenterConfigData.localization,
)
detailPaths.isNotEmpty()
}.toSet()
}

private suspend fun loadPurchases(
dateFormatter: DateFormatter,
locale: Locale,
Expand Down Expand Up @@ -846,11 +875,16 @@ internal class CustomerCenterViewModelImpl(
detailScreenPaths = emptyList(), // Will be computed when a purchase is selected
noActiveScreenOffering = noActiveScreenOffering,
virtualCurrencies = virtualCurrencies,
purchasesWithActions = emptySet(), // Will be computed below
)
val mainScreenPaths = computeMainScreenPaths(successState)
val purchasesWithActions = computePurchasesWithActions(successState)

_state.update {
successState.copy(mainScreenPaths = mainScreenPaths)
successState.copy(
mainScreenPaths = mainScreenPaths,
purchasesWithActions = purchasesWithActions,
)
}
} catch (e: PurchasesException) {
_state.update {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,14 @@ internal fun PurchaseInformationCardView(
modifier = Modifier.weight(1f),
)
when {
!purchaseInformation.isSubscription && !isDetailedView -> {
onCardClick != null && !isDetailedView -> {
Row(
horizontalArrangement = Arrangement.spacedBy(
CustomerCenterConstants.Card.BADGE_HORIZONTAL_PADDING,
),
verticalAlignment = Alignment.CenterVertically,
) {
if (purchaseInformation.isLifetime) {
PurchaseStatusBadge(purchaseInformation, localization)
}
PurchaseStatusBadge(purchaseInformation, localization)
Icon(
imageVector = KeyboardArrowRight,
contentDescription = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ internal fun RelevantPurchasesListView(
onAction: (CustomerCenterAction) -> Unit,
modifier: Modifier = Modifier,
purchases: List<PurchaseInformation> = emptyList(),
purchasesWithActions: Set<PurchaseInformation> = emptySet(),
) {
Column(
modifier = modifier
Expand All @@ -52,6 +53,7 @@ internal fun RelevantPurchasesListView(
localization = localization,
totalPurchaseCount = purchases.size,
onPurchaseSelect = onPurchaseSelect,
purchasesWithActions = purchasesWithActions,
)

if (nonSubscriptions.isNotEmpty()) {
Expand All @@ -74,6 +76,7 @@ internal fun RelevantPurchasesListView(
localization = localization,
totalPurchaseCount = purchases.size,
onPurchaseSelect = onPurchaseSelect,
purchasesWithActions = purchasesWithActions,
)
}

Expand Down Expand Up @@ -113,9 +116,10 @@ private fun PurchaseListSection(
localization: CustomerCenterConfigData.Localization,
totalPurchaseCount: Int,
onPurchaseSelect: (PurchaseInformation) -> Unit,
purchasesWithActions: Set<PurchaseInformation>,
) {
if (purchases.isNotEmpty()) {
purchases.forEachIndexed { index, info ->
purchases.forEachIndexed { index, purchase ->
if (index > 0) {
Spacer(modifier = Modifier.size(CustomerCenterConstants.Layout.ITEMS_SPACING))
}
Expand All @@ -127,15 +131,15 @@ private fun PurchaseListSection(
else -> ButtonPosition.MIDDLE
}
PurchaseInformationCardView(
purchaseInformation = info,
purchaseInformation = purchase,
localization = localization,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = CustomerCenterConstants.Layout.HORIZONTAL_PADDING),
position = position,
isDetailedView = totalPurchaseCount == 1,
onCardClick = if (totalPurchaseCount > 1) {
{ onPurchaseSelect(info) }
onCardClick = if (totalPurchaseCount > 1 && purchase in purchasesWithActions) {
{ onPurchaseSelect(purchase) }
} else {
null
},
Expand Down
Loading