From 73e058522c2b7e819878eea425994292dd3f363c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mehmedalija=20Kari=C5=A1ik?= Date: Tue, 4 Feb 2025 10:26:22 +0100 Subject: [PATCH] Implement new support us footer on PremiumHome screen (#296) --- .../api/model/MembershipStatusResponse.kt | 1 + .../premium/domain/PremiumMembership.kt | 1 + .../android/premium/home/PremiumHomeScreen.kt | 98 +++++++++++++++---- .../premium/home/PremiumHomeViewModel.kt | 3 +- .../premium/repository/PremiumRepository.kt | 1 + .../android/premium/ui/PrimalPremiumTable.kt | 14 +-- app/src/main/res/values/strings.xml | 33 ++++--- 7 files changed, 108 insertions(+), 43 deletions(-) diff --git a/app/src/main/kotlin/net/primal/android/premium/api/model/MembershipStatusResponse.kt b/app/src/main/kotlin/net/primal/android/premium/api/model/MembershipStatusResponse.kt index 1aaf02939..73c49e982 100644 --- a/app/src/main/kotlin/net/primal/android/premium/api/model/MembershipStatusResponse.kt +++ b/app/src/main/kotlin/net/primal/android/premium/api/model/MembershipStatusResponse.kt @@ -20,4 +20,5 @@ data class MembershipStatusResponse( @SerialName("renews_on") val renewsOn: Long? = null, @SerialName("origin") val origin: String? = null, @SerialName("edited_shoutout") val editedShoutout: String? = null, + @SerialName("donated_btc") val donatedBtc: String? = null, ) diff --git a/app/src/main/kotlin/net/primal/android/premium/domain/PremiumMembership.kt b/app/src/main/kotlin/net/primal/android/premium/domain/PremiumMembership.kt index d54ba7254..fc8ad136e 100644 --- a/app/src/main/kotlin/net/primal/android/premium/domain/PremiumMembership.kt +++ b/app/src/main/kotlin/net/primal/android/premium/domain/PremiumMembership.kt @@ -20,6 +20,7 @@ data class PremiumMembership( val renewsOn: Long? = null, val origin: String? = null, val editedShoutout: String? = null, + val donatedBtc: String? = null, ) { fun isExpired() = expiresOn != null && Clock.System.now().epochSeconds > expiresOn } diff --git a/app/src/main/kotlin/net/primal/android/premium/home/PremiumHomeScreen.kt b/app/src/main/kotlin/net/primal/android/premium/home/PremiumHomeScreen.kt index 932dff5ae..a1f8ba050 100644 --- a/app/src/main/kotlin/net/primal/android/premium/home/PremiumHomeScreen.kt +++ b/app/src/main/kotlin/net/primal/android/premium/home/PremiumHomeScreen.kt @@ -45,7 +45,9 @@ import net.primal.android.premium.ui.PremiumBadge import net.primal.android.premium.ui.PrimalPremiumTable import net.primal.android.premium.ui.toHumanReadableString import net.primal.android.premium.utils.isPremiumFreeTier +import net.primal.android.premium.utils.isPrimalLegendTier import net.primal.android.theme.AppTheme +import net.primal.android.wallet.utils.CurrencyConversionUtils.toSats @Composable fun PremiumHomeScreen( @@ -97,7 +99,7 @@ private fun PremiumHomeScreen( Scaffold( topBar = { PrimalTopAppBar( - title = stringResource(id = R.string.premium_member_title), + title = stringResource(id = R.string.premium_home_member_title), navigationIcon = PrimalIcons.ArrowBack, onNavigationIconClick = onClose, showDivider = false, @@ -106,14 +108,14 @@ private fun PremiumHomeScreen( bottomBar = { if (state.membership?.isExpired() == true) { BottomBarButton( - text = stringResource(id = R.string.premium_renew_subscription), + text = stringResource(id = R.string.premium_home_renew_subscription), onClick = { onRenewSubscription(state.membership.premiumName) }, ) } else { BottomBarButton( - text = stringResource(id = R.string.premium_manage_premium_button), + text = stringResource(id = R.string.premium_home_premium_button), onClick = onManagePremium, ) } @@ -164,7 +166,7 @@ private fun PremiumHomeScreen( if (state.membership.isPremiumFreeTier()) { Text( modifier = Modifier.padding(horizontal = 36.dp), - text = stringResource(id = R.string.premium_member_early_primal_user), + text = stringResource(id = R.string.premium_home_member_early_primal_user), color = AppTheme.extraColorScheme.onSurfaceVariantAlt2, style = AppTheme.typography.bodyMedium, textAlign = TextAlign.Center, @@ -186,17 +188,26 @@ private fun PremiumHomeScreen( state.membership.isExpired() -> { Text( color = AppTheme.extraColorScheme.onSurfaceVariantAlt2, - text = stringResource(id = R.string.premium_expired_subscription_notice), + text = stringResource(id = R.string.premium_home_expired_subscription_notice), style = AppTheme.typography.bodyMedium, textAlign = TextAlign.Center, ) } else -> { - SupportUsNotice( - visible = state.showSupportUsNotice, - onSupportPrimal = onSupportPrimal, - ) + if (state.showSupportUsNotice) { + if (state.membership.isPrimalLegendTier()) { + SupportUsNoticeLegend( + visible = state.membership.donatedBtc != null, + donatedSats = state.membership.donatedBtc?.toSats()?.toLong() ?: 0L, + onSupportPrimal = onSupportPrimal, + ) + } else { + SupportUsNoticePremium( + onSupportPrimal = onSupportPrimal, + ) + } + } } } } @@ -230,30 +241,26 @@ private fun BottomBarButton( } @Composable -private fun SupportUsNotice(visible: Boolean, onSupportPrimal: () -> Unit) { +private fun SupportUsNoticePremium(onSupportPrimal: () -> Unit) { Column( - modifier = Modifier.alpha(if (visible) 1.0f else 0.0f), + modifier = Modifier, verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterVertically), horizontalAlignment = Alignment.CenterHorizontally, ) { Text( color = AppTheme.extraColorScheme.onSurfaceVariantAlt2, - text = stringResource(id = R.string.premium_enjoying_primal), + text = stringResource(id = R.string.premium_home_enjoying_primal), style = AppTheme.typography.bodyMedium, textAlign = TextAlign.Center, ) Row { Text( color = AppTheme.extraColorScheme.onSurfaceVariantAlt2, - text = stringResource(id = R.string.premium_enjoying_primal_if_so) + " ", + text = stringResource(id = R.string.premium_home_enjoying_primal_if_so) + " ", style = AppTheme.typography.bodyMedium, ) Text( - modifier = Modifier - .clickable( - enabled = visible, - onClick = onSupportPrimal, - ), + modifier = Modifier.clickable(onClick = onSupportPrimal), style = AppTheme.typography.bodyMedium, text = buildAnnotatedString { withStyle( @@ -261,7 +268,7 @@ private fun SupportUsNotice(visible: Boolean, onSupportPrimal: () -> Unit) { color = AppTheme.colorScheme.secondary, ), ) { - append(stringResource(id = R.string.premium_support_us)) + append(stringResource(id = R.string.premium_home_support_us)) } withStyle( style = SpanStyle( @@ -275,3 +282,56 @@ private fun SupportUsNotice(visible: Boolean, onSupportPrimal: () -> Unit) { } } } + +@Composable +private fun SupportUsNoticeLegend( + visible: Boolean, + donatedSats: Long, + onSupportPrimal: () -> Unit, +) { + Column( + modifier = Modifier.alpha(if (visible) 1.0f else 0.0f), + verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Row { + Text( + color = AppTheme.extraColorScheme.onSurfaceVariantAlt2, + text = stringResource(id = R.string.premium_home_legend_contribution_title) + " ", + style = AppTheme.typography.bodyMedium, + ) + Text( + modifier = Modifier.clickable(onClick = onSupportPrimal), + style = AppTheme.typography.bodyMedium, + fontWeight = FontWeight.SemiBold, + text = buildAnnotatedString { + withStyle( + style = SpanStyle( + color = AppTheme.colorScheme.onBackground, + ), + ) { + append(donatedSats.let { "%,d sats".format(it) }) + } + }, + ) + } + if (donatedSats > 0L) { + Text( + color = AppTheme.extraColorScheme.onSurfaceVariantAlt2, + text = stringResource(id = R.string.premium_home_legend_support_appreciation), + style = AppTheme.typography.bodyMedium, + textAlign = TextAlign.Center, + ) + } + Text( + modifier = Modifier + .clickable( + onClick = onSupportPrimal, + ), + color = AppTheme.colorScheme.secondary, + text = stringResource(id = R.string.premium_home_legend_contribute_more), + style = AppTheme.typography.bodyMedium, + textAlign = TextAlign.Center, + ) + } +} diff --git a/app/src/main/kotlin/net/primal/android/premium/home/PremiumHomeViewModel.kt b/app/src/main/kotlin/net/primal/android/premium/home/PremiumHomeViewModel.kt index 9281870fc..1ae67073e 100644 --- a/app/src/main/kotlin/net/primal/android/premium/home/PremiumHomeViewModel.kt +++ b/app/src/main/kotlin/net/primal/android/premium/home/PremiumHomeViewModel.kt @@ -16,7 +16,6 @@ import net.primal.android.premium.home.PremiumHomeContract.UiEvent import net.primal.android.premium.home.PremiumHomeContract.UiState import net.primal.android.premium.legend.domain.asLegendaryCustomization import net.primal.android.premium.repository.PremiumRepository -import net.primal.android.premium.utils.isPrimalLegendTier import net.primal.android.profile.repository.ProfileRepository import net.primal.android.user.accounts.active.ActiveAccountStore import net.primal.android.user.repository.UserRepository @@ -131,7 +130,7 @@ class PremiumHomeViewModel @Inject constructor( val clientConfigShowSupport = premiumRepository.shouldShowSupportUsNotice() setState { copy( - showSupportUsNotice = clientConfigShowSupport && !membership.isPrimalLegendTier(), + showSupportUsNotice = clientConfigShowSupport, ) } } catch (error: WssException) { diff --git a/app/src/main/kotlin/net/primal/android/premium/repository/PremiumRepository.kt b/app/src/main/kotlin/net/primal/android/premium/repository/PremiumRepository.kt index 40c257ea4..8fcce6b5c 100644 --- a/app/src/main/kotlin/net/primal/android/premium/repository/PremiumRepository.kt +++ b/app/src/main/kotlin/net/primal/android/premium/repository/PremiumRepository.kt @@ -156,6 +156,7 @@ class PremiumRepository @Inject constructor( recurring = this.recurring, origin = this.origin, editedShoutout = this.editedShoutout, + donatedBtc = this.donatedBtc, ) } } diff --git a/app/src/main/kotlin/net/primal/android/premium/ui/PrimalPremiumTable.kt b/app/src/main/kotlin/net/primal/android/premium/ui/PrimalPremiumTable.kt index 02b13142d..576f6a49c 100644 --- a/app/src/main/kotlin/net/primal/android/premium/ui/PrimalPremiumTable.kt +++ b/app/src/main/kotlin/net/primal/android/premium/ui/PrimalPremiumTable.kt @@ -61,16 +61,16 @@ fun PrimalPremiumTable( PrimalDivider() if (premiumMembership.isPrimalLegendTier()) { PrimalPremiumTableRow( - key = stringResource(id = R.string.premium_table_expires), - value = stringResource(id = R.string.premium_table_never), + key = stringResource(id = R.string.premium_home_table_expires), + value = stringResource(id = R.string.premium_home_table_never), alwaysHideApply = true, ) } else { PrimalPremiumTableRow( key = when { - premiumMembership.isExpired() -> stringResource(id = R.string.premium_table_expired_on) - premiumMembership.recurring -> stringResource(id = R.string.premium_table_renews_on) - else -> stringResource(id = R.string.premium_table_expires_on) + premiumMembership.isExpired() -> stringResource(id = R.string.premium_home_table_expired_on) + premiumMembership.recurring -> stringResource(id = R.string.premium_home_table_renews_on) + else -> stringResource(id = R.string.premium_home_table_expires_on) }, value = when { premiumMembership.recurring && premiumMembership.renewsOn != null -> @@ -80,7 +80,7 @@ fun PrimalPremiumTable( premiumMembership.expiresOn != null -> Instant.ofEpochSecond(premiumMembership.expiresOn) .formatToDefaultDateFormat(FormatStyle.LONG) - else -> stringResource(R.string.premium_table_never) + else -> stringResource(R.string.premium_home_table_never) }, alwaysHideApply = true, ) @@ -148,7 +148,7 @@ private fun PrimalPremiumTableRow( } Text( modifier = Modifier.clickable { onApplyClick?.invoke() }, - text = stringResource(id = R.string.premium_table_apply), + text = stringResource(id = R.string.premium_home_table_apply), color = AppTheme.colorScheme.secondary, style = AppTheme.typography.bodyMedium, ) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 42f0ffce6..28cb5e02c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -160,21 +160,24 @@ Apply Promo Code Cancel - Premium - Hey there! You are an early Primal user who interacted with our team, so we gave you 6 months of Primal Premium for free. ♥\uFE0F\uD83E\uDEC2 - Manage Premium - Renew Subscription - Extend Subscription - Are you enjoying Primal? - If so, see how you can - support us - Expires - Never - Renews on - Expires on - Expired on - apply - Your Primal Premium subscription has expired.\nYou can renew it below: + Premium + Hey there! You are an early Primal user who interacted with our team, so we gave you 6 months of Primal Premium for free. ♥\uFE0F\uD83E\uDEC2 + Manage Premium + Renew Subscription + Extend Subscription + Are you enjoying Primal? + If so, see how you can + support us + Expires + Never + Renews on + Expires on + Expired on + apply + Your Primal Premium subscription has expired.\nYou can renew it below: + Your contribution to Primal: + Thank you for your support! 💜🫂 + Want to contribute more? Support Primal