mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-27 04:04:43 +01:00
Add "Backups Subscription not found" states.
This commit is contained in:
@@ -11,10 +11,12 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.absoluteOffset
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -26,6 +28,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.res.colorResource
|
||||
@@ -119,7 +122,7 @@ class AppSettingsFragment : ComposeFragment(), Callbacks {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.refreshExpiredGiftBadge()
|
||||
viewModel.refresh()
|
||||
viewModel.refreshDeprecatedOrUnregistered()
|
||||
}
|
||||
|
||||
@@ -184,6 +187,44 @@ private fun AppSettingsContent(
|
||||
)
|
||||
}
|
||||
|
||||
if (state.backupFailureState != BackupFailureState.NONE) {
|
||||
item {
|
||||
Dividers.Default()
|
||||
}
|
||||
|
||||
item {
|
||||
Rows.TextRow(
|
||||
text = {
|
||||
Text(text = stringResource(R.string.AppSettingsFragment__renew_your_signal_backups_subscription))
|
||||
},
|
||||
icon = {
|
||||
Box {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.symbol_backup_24),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
contentDescription = null
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.absoluteOffset(3.dp, (-2).dp)
|
||||
.background(color = Color(0xFFFFCC00), shape = CircleShape)
|
||||
.size(12.dp)
|
||||
.align(Alignment.TopEnd)
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
callbacks.navigate(R.id.action_appSettingsFragment_to_remoteBackupsSettingsFragment)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Dividers.Default()
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Rows.TextRow(
|
||||
text = stringResource(R.string.AccountSettingsFragment__account),
|
||||
@@ -555,7 +596,8 @@ private fun AppSettingsContentPreview() {
|
||||
showInternalPreferences = true,
|
||||
showPayments = true,
|
||||
showAppUpdates = true,
|
||||
showBackups = true
|
||||
showBackups = true,
|
||||
backupFailureState = BackupFailureState.SUBSCRIPTION_STATE_MISMATCH
|
||||
),
|
||||
bannerManager = BannerManager(
|
||||
banners = listOf(TestBanner())
|
||||
|
||||
@@ -15,7 +15,8 @@ data class AppSettingsState(
|
||||
val showInternalPreferences: Boolean = RemoteConfig.internalUser,
|
||||
val showPayments: Boolean = SignalStore.payments.paymentsAvailability.showPaymentsMenu(),
|
||||
val showAppUpdates: Boolean = Environment.IS_NIGHTLY,
|
||||
val showBackups: Boolean = RemoteConfig.messageBackups
|
||||
val showBackups: Boolean = RemoteConfig.messageBackups,
|
||||
val backupFailureState: BackupFailureState = BackupFailureState.NONE
|
||||
) {
|
||||
fun isRegisteredAndUpToDate(): Boolean {
|
||||
return !userUnregistered && !clientDeprecated
|
||||
|
||||
@@ -60,7 +60,20 @@ class AppSettingsViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshExpiredGiftBadge() {
|
||||
store.update { it.copy(hasExpiredGiftBadge = SignalStore.inAppPayments.getExpiredGiftBadge() != null) }
|
||||
fun refresh() {
|
||||
store.update {
|
||||
it.copy(
|
||||
hasExpiredGiftBadge = SignalStore.inAppPayments.getExpiredGiftBadge() != null,
|
||||
backupFailureState = getBackupFailureState()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBackupFailureState(): BackupFailureState {
|
||||
return if (SignalStore.backup.subscriptionStateMismatchDetected) {
|
||||
BackupFailureState.SUBSCRIPTION_STATE_MISMATCH
|
||||
} else {
|
||||
BackupFailureState.NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.settings.app
|
||||
|
||||
/**
|
||||
* Describes the current backup failure state.
|
||||
*/
|
||||
enum class BackupFailureState {
|
||||
NONE,
|
||||
SUBSCRIPTION_STATE_MISMATCH
|
||||
}
|
||||
@@ -14,7 +14,9 @@ import androidx.biometric.BiometricPrompt
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -26,6 +28,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
@@ -45,8 +48,10 @@ import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
@@ -94,6 +99,8 @@ import org.thoughtcrime.securesms.util.viewModel
|
||||
import java.math.BigDecimal
|
||||
import java.util.Currency
|
||||
import java.util.Locale
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
/**
|
||||
@@ -199,6 +206,18 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
|
||||
override fun onSkipMediaRestore() {
|
||||
// TODO - [backups] Skip media restoration
|
||||
}
|
||||
|
||||
override fun onLearnMoreAboutLostSubscription() {
|
||||
viewModel.requestDialog(RemoteBackupsSettingsState.Dialog.SUBSCRIPTION_NOT_FOUND)
|
||||
}
|
||||
|
||||
override fun onRenewLostSubscription() {
|
||||
// TODO - [backups] Need process here (cancel first?)
|
||||
}
|
||||
|
||||
override fun onContactSupport() {
|
||||
// TODO - [backups] Need to contact support.
|
||||
}
|
||||
}
|
||||
|
||||
private fun displayBackupKey() {
|
||||
@@ -275,6 +294,9 @@ private interface ContentCallbacks {
|
||||
fun onViewBackupKeyClick() = Unit
|
||||
fun onSkipMediaRestore() = Unit
|
||||
fun onCancelMediaRestore() = Unit
|
||||
fun onRenewLostSubscription() = Unit
|
||||
fun onLearnMoreAboutLostSubscription() = Unit
|
||||
fun onContactSupport() = Unit
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -313,13 +335,23 @@ private fun RemoteBackupsSettingsContent(
|
||||
is RemoteBackupsSettingsState.BackupState.Loading -> {
|
||||
LoadingCard()
|
||||
}
|
||||
|
||||
is RemoteBackupsSettingsState.BackupState.Error -> {
|
||||
ErrorCard()
|
||||
}
|
||||
|
||||
is RemoteBackupsSettingsState.BackupState.Pending -> {
|
||||
PendingCard(state.price)
|
||||
}
|
||||
|
||||
is RemoteBackupsSettingsState.BackupState.SubscriptionMismatchMissingGooglePlay -> {
|
||||
SubscriptionMismatchMissingGooglePlayCard(
|
||||
state = state,
|
||||
onLearnMoreClick = contentCallbacks::onLearnMoreAboutLostSubscription,
|
||||
onRenewClick = contentCallbacks::onRenewLostSubscription
|
||||
)
|
||||
}
|
||||
|
||||
RemoteBackupsSettingsState.BackupState.None -> Unit
|
||||
|
||||
is RemoteBackupsSettingsState.BackupState.WithTypeAndRenewalTime -> {
|
||||
@@ -404,6 +436,13 @@ private fun RemoteBackupsSettingsContent(
|
||||
RemoteBackupsSettingsState.Dialog.DOWNLOADING_YOUR_BACKUP -> {
|
||||
DownloadingYourBackupDialog(onDismiss = contentCallbacks::onDialogDismissed)
|
||||
}
|
||||
|
||||
RemoteBackupsSettingsState.Dialog.SUBSCRIPTION_NOT_FOUND -> {
|
||||
SubscriptionNotFoundBottomSheet(
|
||||
onDismiss = contentCallbacks::onDialogDismissed,
|
||||
onContactSupport = contentCallbacks::onContactSupport
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val snackbarMessageId = remember(requestedSnackbar) {
|
||||
@@ -727,6 +766,85 @@ private fun PendingCard(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SubscriptionMismatchMissingGooglePlayCard(
|
||||
state: RemoteBackupsSettingsState.BackupState.SubscriptionMismatchMissingGooglePlay,
|
||||
onRenewClick: () -> Unit = {},
|
||||
onLearnMoreClick: () -> Unit = {}
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp)
|
||||
.background(color = SignalTheme.colors.colorSurface2, shape = RoundedCornerShape(12.dp))
|
||||
.padding(24.dp)
|
||||
) {
|
||||
val days by rememberUpdatedState((state.renewalTime - System.currentTimeMillis().milliseconds).inWholeDays)
|
||||
|
||||
Row {
|
||||
Text(
|
||||
text = pluralStringResource(R.plurals.RemoteBackupsSettingsFragment__your_subscription_on_this_device_is_valid, days.toInt(), days),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(end = 13.dp)
|
||||
)
|
||||
|
||||
Box {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.image_signal_backups),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(64.dp)
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(22.dp)
|
||||
.background(
|
||||
color = Color(0xFFFFCC00),
|
||||
shape = CircleShape
|
||||
)
|
||||
.border(5.dp, color = SignalTheme.colors.colorSurface2, shape = CircleShape)
|
||||
.align(Alignment.TopEnd)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
horizontalArrangement = spacedBy(16.dp)
|
||||
) {
|
||||
Buttons.LargeTonal(
|
||||
onClick = onRenewClick,
|
||||
colors = ButtonDefaults.filledTonalButtonColors().copy(
|
||||
containerColor = SignalTheme.colors.colorTransparent5,
|
||||
contentColor = colorResource(R.color.signal_light_colorOnSurface)
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(top = 24.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.RemoteBackupsSettingsFragment__renew)
|
||||
)
|
||||
}
|
||||
|
||||
Buttons.LargeTonal(
|
||||
onClick = onLearnMoreClick,
|
||||
colors = ButtonDefaults.filledTonalButtonColors().copy(
|
||||
containerColor = SignalTheme.colors.colorTransparent5,
|
||||
contentColor = colorResource(R.color.signal_light_colorOnSurface)
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(top = 24.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.RemoteBackupsSettingsFragment__learn_more)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InProgressBackupRow(
|
||||
progress: Int?,
|
||||
@@ -995,6 +1113,22 @@ private fun PendingCardPreview() {
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun SubscriptionMismatchMissingGooglePlayCardPreview() {
|
||||
Previews.Preview {
|
||||
SubscriptionMismatchMissingGooglePlayCard(
|
||||
state = RemoteBackupsSettingsState.BackupState.SubscriptionMismatchMissingGooglePlay(
|
||||
messageBackupsType = MessageBackupsType.Paid(
|
||||
pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")),
|
||||
storageAllowanceBytes = 100_000_000
|
||||
),
|
||||
renewalTime = System.currentTimeMillis().milliseconds + 30.days
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun BackupCardPreview() {
|
||||
|
||||
@@ -91,6 +91,14 @@ data class RemoteBackupsSettingsState(
|
||||
override val renewalTime: Duration
|
||||
) : WithTypeAndRenewalTime
|
||||
|
||||
/**
|
||||
* Subscription mismatch detected.
|
||||
*/
|
||||
data class SubscriptionMismatchMissingGooglePlay(
|
||||
override val messageBackupsType: MessageBackupsType,
|
||||
override val renewalTime: Duration
|
||||
) : WithTypeAndRenewalTime
|
||||
|
||||
/**
|
||||
* An error occurred retrieving the network state
|
||||
*/
|
||||
@@ -103,7 +111,8 @@ data class RemoteBackupsSettingsState(
|
||||
BACKUP_FREQUENCY,
|
||||
PROGRESS_SPINNER,
|
||||
DOWNLOADING_YOUR_BACKUP,
|
||||
TURN_OFF_FAILED
|
||||
TURN_OFF_FAILED,
|
||||
SUBSCRIPTION_NOT_FOUND
|
||||
}
|
||||
|
||||
enum class Snackbar {
|
||||
|
||||
@@ -20,6 +20,7 @@ import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.reactive.asFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.signal.core.util.billing.BillingPurchaseResult
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.money.FiatMoney
|
||||
import org.signal.donations.InAppPaymentType
|
||||
@@ -153,6 +154,44 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
|
||||
return
|
||||
}
|
||||
|
||||
if (SignalStore.backup.subscriptionStateMismatchDetected) {
|
||||
Log.d(TAG, "[subscriptionStateMismatchDetected] A mismatch was detected.")
|
||||
|
||||
val hasActiveGooglePlayBillingSubscription = when (val purchaseResult = AppDependencies.billingApi.queryPurchases()) {
|
||||
is BillingPurchaseResult.Success -> purchaseResult.isAcknowledged && purchaseResult.isWithinTheLastMonth()
|
||||
else -> false
|
||||
}
|
||||
|
||||
Log.d(TAG, "[subscriptionStateMismatchDetected] hasActiveGooglePlayBillingSubscription: $hasActiveGooglePlayBillingSubscription")
|
||||
|
||||
val activeSubscription = withContext(Dispatchers.IO) {
|
||||
RecurringInAppPaymentRepository.getActiveSubscriptionSync(InAppPaymentSubscriberRecord.Type.BACKUP).getOrNull()
|
||||
}
|
||||
|
||||
val hasActiveSignalSubscription = activeSubscription?.isActive == true
|
||||
|
||||
Log.d(TAG, "[subscriptionStateMismatchDetected] hasActiveSignalSubscription: $hasActiveSignalSubscription")
|
||||
|
||||
val type = withContext(Dispatchers.IO) {
|
||||
BackupRepository.getBackupsType(MessageBackupTier.PAID) as MessageBackupsType.Paid
|
||||
}
|
||||
|
||||
if (hasActiveSignalSubscription && !hasActiveGooglePlayBillingSubscription) {
|
||||
_state.update {
|
||||
it.copy(
|
||||
backupState = RemoteBackupsSettingsState.BackupState.SubscriptionMismatchMissingGooglePlay(
|
||||
messageBackupsType = type,
|
||||
renewalTime = activeSubscription!!.activeSubscription.endOfCurrentPeriod.seconds
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO [backups] - handle other cases.
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
when (tier) {
|
||||
MessageBackupTier.PAID -> {
|
||||
Log.d(TAG, "Attempting to retrieve subscription details for active PAID backup.")
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.settings.app.backups.remote
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.core.ui.BottomSheets
|
||||
import org.signal.core.ui.Buttons
|
||||
import org.signal.core.ui.Previews
|
||||
import org.signal.core.ui.SignalPreview
|
||||
import org.signal.core.ui.horizontalGutters
|
||||
import org.signal.core.ui.theme.SignalTheme
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
/**
|
||||
* Displayed after user taps "Learn more" when being notified that their subscription
|
||||
* could not be found. This state is entered when a user has a Signal service backups
|
||||
* subscription that is active but no on-device (Google Play Billing) subscription.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SubscriptionNotFoundBottomSheet(
|
||||
onDismiss: () -> Unit,
|
||||
onContactSupport: () -> Unit
|
||||
) {
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
|
||||
ModalBottomSheet(
|
||||
sheetState = sheetState,
|
||||
onDismissRequest = onDismiss,
|
||||
dragHandle = { BottomSheets.Handle() }
|
||||
) {
|
||||
SubscriptionNotFoundContent(
|
||||
onDismiss = onDismiss,
|
||||
onContactSupport = onContactSupport
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ColumnScope.SubscriptionNotFoundContent(
|
||||
onDismiss: () -> Unit = {},
|
||||
onContactSupport: () -> Unit = {}
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.SubscriptionNotFoundBottomSheet__subscription_not_found),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.padding(top = 28.dp)
|
||||
.horizontalGutters()
|
||||
.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.SubscriptionNotFoundBottomSheet__your_subscription_couldnt_be_restored),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.padding(top = 12.dp)
|
||||
.horizontalGutters()
|
||||
.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.SubscriptionNotFoundBottomSheet__this_could_happen_if),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.horizontalGutters()
|
||||
.padding(bottom = 12.dp)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
|
||||
SubscriptionNotFoundReason(stringResource(R.string.SubscriptionNotFoundBottomSheet__youre_signed_into_the_play_store_with_a_different_google_account))
|
||||
|
||||
SubscriptionNotFoundReason(stringResource(R.string.SubscriptionNotFoundBottomSheet__you_transferred_from_an_iphone))
|
||||
|
||||
SubscriptionNotFoundReason(stringResource(R.string.SubscriptionNotFoundBottomSheet__your_subscription_recently_expired))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.SubscriptionNotFoundBottomSheet__if_you_have_an_active_subscription_on),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.padding(top = 24.dp)
|
||||
.horizontalGutters()
|
||||
.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
|
||||
Buttons.LargeTonal(
|
||||
onClick = onDismiss,
|
||||
modifier = Modifier
|
||||
.defaultMinSize(minWidth = 220.dp)
|
||||
.padding(top = 36.dp)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
) {
|
||||
Text(text = stringResource(R.string.SubscriptionNotFoundBottomSheet__got_it))
|
||||
}
|
||||
|
||||
TextButton(
|
||||
onClick = onContactSupport,
|
||||
modifier = Modifier
|
||||
.defaultMinSize(minWidth = 220.dp)
|
||||
.padding(top = 16.dp, bottom = 48.dp)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.SubscriptionNotFoundBottomSheet__contact_support)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SubscriptionNotFoundReason(text: String) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(IntrinsicSize.Min)
|
||||
.padding(horizontal = 36.dp)
|
||||
.padding(top = 12.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(end = 12.dp)
|
||||
.fillMaxHeight()
|
||||
.padding(vertical = 2.dp)
|
||||
.width(4.dp)
|
||||
.background(
|
||||
color = SignalTheme.colors.colorTransparentInverse2,
|
||||
shape = RoundedCornerShape(2.dp)
|
||||
)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = text,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun SubscriptionNotFoundContentPreview() {
|
||||
Previews.BottomSheetPreview {
|
||||
Column {
|
||||
SubscriptionNotFoundContent()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user