Add MediaTTL to subscriptions configuration and wire in.

This commit is contained in:
Alex Hart
2024-11-14 10:38:28 -04:00
committed by Greyson Parrelli
parent bf3012bd8a
commit 61f91d6b83
8 changed files with 51 additions and 20 deletions

View File

@@ -99,6 +99,7 @@ import java.io.OutputStream
import java.time.ZonedDateTime import java.time.ZonedDateTime
import java.util.Locale import java.util.Locale
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
import org.signal.libsignal.messagebackup.MessageBackupKey as LibSignalMessageBackupKey import org.signal.libsignal.messagebackup.MessageBackupKey as LibSignalMessageBackupKey
@@ -1147,10 +1148,12 @@ object BackupRepository {
private suspend fun getPaidType(): MessageBackupsType? { private suspend fun getPaidType(): MessageBackupsType? {
val config = getSubscriptionsConfiguration() val config = getSubscriptionsConfiguration()
val product = AppDependencies.billingApi.queryProduct() ?: return null val product = AppDependencies.billingApi.queryProduct() ?: return null
val backupLevelConfiguration = config.backupConfiguration.backupLevelConfigurationMap[SubscriptionsConfiguration.BACKUPS_LEVEL] ?: return null
return MessageBackupsType.Paid( return MessageBackupsType.Paid(
pricePerMonth = product.price, pricePerMonth = product.price,
storageAllowanceBytes = config.backupConfiguration.backupLevelConfigurationMap[SubscriptionsConfiguration.BACKUPS_LEVEL]!!.storageAllowanceBytes storageAllowanceBytes = backupLevelConfiguration.storageAllowanceBytes,
mediaTtl = backupLevelConfiguration.mediaTtlDays.days
) )
} }

View File

@@ -57,6 +57,7 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.jobs.BackupMessagesJob import org.thoughtcrime.securesms.jobs.BackupMessagesJob
import org.thoughtcrime.securesms.jobs.BackupRestoreMediaJob import org.thoughtcrime.securesms.jobs.BackupRestoreMediaJob
import org.thoughtcrime.securesms.payments.FiatMoneyUtil import org.thoughtcrime.securesms.payments.FiatMoneyUtil
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
import org.signal.core.ui.R as CoreUiR import org.signal.core.ui.R as CoreUiR
@@ -102,6 +103,7 @@ class BackupAlertBottomSheet : UpgradeToPaidTierBottomSheet() {
BackupAlertSheetContent( BackupAlertSheetContent(
backupAlert = backupAlert, backupAlert = backupAlert,
isSubscribeEnabled = isSubscribeEnabled, isSubscribeEnabled = isSubscribeEnabled,
mediaTtl = paidBackupType.mediaTtl,
onPrimaryActionClick = performPrimaryAction, onPrimaryActionClick = performPrimaryAction,
onSecondaryActionClick = this::performSecondaryAction onSecondaryActionClick = this::performSecondaryAction
) )
@@ -195,6 +197,7 @@ private fun BackupAlertSheetContent(
backupAlert: BackupAlert, backupAlert: BackupAlert,
pricePerMonth: String = "", pricePerMonth: String = "",
isSubscribeEnabled: Boolean = true, isSubscribeEnabled: Boolean = true,
mediaTtl: Duration,
onPrimaryActionClick: () -> Unit = {}, onPrimaryActionClick: () -> Unit = {},
onSecondaryActionClick: () -> Unit = {} onSecondaryActionClick: () -> Unit = {}
) { ) {
@@ -254,7 +257,7 @@ private fun BackupAlertSheetContent(
) )
BackupAlert.FailedToRenew -> PaymentProcessingBody() BackupAlert.FailedToRenew -> PaymentProcessingBody()
is BackupAlert.MediaBackupsAreOff -> MediaBackupsAreOffBody(backupAlert.endOfPeriodSeconds) is BackupAlert.MediaBackupsAreOff -> MediaBackupsAreOffBody(backupAlert.endOfPeriodSeconds, mediaTtl)
BackupAlert.MediaWillBeDeletedToday -> MediaWillBeDeletedTodayBody() BackupAlert.MediaWillBeDeletedToday -> MediaWillBeDeletedTodayBody()
is BackupAlert.DiskFull -> DiskFullBody(requiredSpace = backupAlert.requiredSpace) is BackupAlert.DiskFull -> DiskFullBody(requiredSpace = backupAlert.requiredSpace)
} }
@@ -308,10 +311,10 @@ private fun PaymentProcessingBody() {
@Composable @Composable
private fun MediaBackupsAreOffBody( private fun MediaBackupsAreOffBody(
endOfPeriodSeconds: Long endOfPeriodSeconds: Long,
mediaTtl: Duration
) { ) {
// TODO [backups] Get value from config to calculate days until deletion. val daysUntilDeletion = remember { endOfPeriodSeconds.days + mediaTtl }.inWholeDays.toInt()
val daysUntilDeletion = remember { endOfPeriodSeconds.days + 60.days }.inWholeDays.toInt()
Text( Text(
text = pluralStringResource(id = R.plurals.BackupAlertBottomSheet__your_backup_plan_has_expired, daysUntilDeletion, daysUntilDeletion), text = pluralStringResource(id = R.plurals.BackupAlertBottomSheet__your_backup_plan_has_expired, daysUntilDeletion, daysUntilDeletion),
@@ -416,7 +419,8 @@ private fun rememberSecondaryActionResource(backupAlert: BackupAlert): Int {
private fun BackupAlertSheetContentPreviewGeneric() { private fun BackupAlertSheetContentPreviewGeneric() {
Previews.BottomSheetPreview { Previews.BottomSheetPreview {
BackupAlertSheetContent( BackupAlertSheetContent(
backupAlert = BackupAlert.CouldNotCompleteBackup(daysSinceLastBackup = 7) backupAlert = BackupAlert.CouldNotCompleteBackup(daysSinceLastBackup = 7),
mediaTtl = 60.days
) )
} }
} }
@@ -426,7 +430,8 @@ private fun BackupAlertSheetContentPreviewGeneric() {
private fun BackupAlertSheetContentPreviewPayment() { private fun BackupAlertSheetContentPreviewPayment() {
Previews.BottomSheetPreview { Previews.BottomSheetPreview {
BackupAlertSheetContent( BackupAlertSheetContent(
backupAlert = BackupAlert.FailedToRenew backupAlert = BackupAlert.FailedToRenew,
mediaTtl = 60.days
) )
} }
} }
@@ -437,7 +442,8 @@ private fun BackupAlertSheetContentPreviewMedia() {
Previews.BottomSheetPreview { Previews.BottomSheetPreview {
BackupAlertSheetContent( BackupAlertSheetContent(
backupAlert = BackupAlert.MediaBackupsAreOff(endOfPeriodSeconds = System.currentTimeMillis().milliseconds.inWholeSeconds), backupAlert = BackupAlert.MediaBackupsAreOff(endOfPeriodSeconds = System.currentTimeMillis().milliseconds.inWholeSeconds),
pricePerMonth = "$2.99" pricePerMonth = "$2.99",
mediaTtl = 60.days
) )
} }
} }
@@ -447,7 +453,8 @@ private fun BackupAlertSheetContentPreviewMedia() {
private fun BackupAlertSheetContentPreviewDelete() { private fun BackupAlertSheetContentPreviewDelete() {
Previews.BottomSheetPreview { Previews.BottomSheetPreview {
BackupAlertSheetContent( BackupAlertSheetContent(
backupAlert = BackupAlert.MediaWillBeDeletedToday backupAlert = BackupAlert.MediaWillBeDeletedToday,
mediaTtl = 60.days
) )
} }
} }
@@ -457,7 +464,8 @@ private fun BackupAlertSheetContentPreviewDelete() {
private fun BackupAlertSheetContentPreviewDiskFull() { private fun BackupAlertSheetContentPreviewDiskFull() {
Previews.BottomSheetPreview { Previews.BottomSheetPreview {
BackupAlertSheetContent( BackupAlertSheetContent(
backupAlert = BackupAlert.DiskFull(requiredSpace = "12GB") backupAlert = BackupAlert.DiskFull(requiredSpace = "12GB"),
mediaTtl = 60.days
) )
} }
} }

View File

@@ -8,6 +8,7 @@ package org.thoughtcrime.securesms.backup.v2.ui.subscription
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import org.signal.core.util.money.FiatMoney import org.signal.core.util.money.FiatMoney
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
import kotlin.time.Duration
/** /**
* Represents a type of backup a user can select. * Represents a type of backup a user can select.
@@ -19,7 +20,8 @@ sealed interface MessageBackupsType {
data class Paid( data class Paid(
val pricePerMonth: FiatMoney, val pricePerMonth: FiatMoney,
val storageAllowanceBytes: Long val storageAllowanceBytes: Long,
val mediaTtl: Duration
) : MessageBackupsType { ) : MessageBackupsType {
override val tier: MessageBackupTier = MessageBackupTier.PAID override val tier: MessageBackupTier = MessageBackupTier.PAID
} }

View File

@@ -59,6 +59,7 @@ import org.thoughtcrime.securesms.payments.FiatMoneyUtil
import org.thoughtcrime.securesms.util.ByteUnit import org.thoughtcrime.securesms.util.ByteUnit
import java.math.BigDecimal import java.math.BigDecimal
import java.util.Currency import java.util.Currency
import kotlin.time.Duration.Companion.days
import org.signal.core.ui.R as CoreUiR import org.signal.core.ui.R as CoreUiR
/** /**
@@ -369,7 +370,8 @@ fun testBackupTypes(): List<MessageBackupsType> {
), ),
MessageBackupsType.Paid( MessageBackupsType.Paid(
pricePerMonth = FiatMoney(BigDecimal.ONE, Currency.getInstance("USD")), pricePerMonth = FiatMoney(BigDecimal.ONE, Currency.getInstance("USD")),
storageAllowanceBytes = 107374182400 storageAllowanceBytes = 107374182400,
mediaTtl = 30.days
) )
) )
} }

View File

@@ -51,6 +51,7 @@ import org.thoughtcrime.securesms.util.navigation.safeNavigate
import java.math.BigDecimal import java.math.BigDecimal
import java.util.Currency import java.util.Currency
import java.util.Locale import java.util.Locale
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import org.signal.core.ui.R as CoreUiR import org.signal.core.ui.R as CoreUiR
@@ -342,7 +343,8 @@ private fun BackupsSettingsContentPreview() {
enabledState = BackupsSettingsState.EnabledState.Active( enabledState = BackupsSettingsState.EnabledState.Active(
type = MessageBackupsType.Paid( type = MessageBackupsType.Paid(
pricePerMonth = FiatMoney(BigDecimal.valueOf(4), Currency.getInstance("CAD")), pricePerMonth = FiatMoney(BigDecimal.valueOf(4), Currency.getInstance("CAD")),
storageAllowanceBytes = 1_000_000 storageAllowanceBytes = 1_000_000,
mediaTtl = 30.days
), ),
expiresAt = 0.seconds, expiresAt = 0.seconds,
lastBackupAt = 0.seconds lastBackupAt = 0.seconds
@@ -388,7 +390,8 @@ private fun ActivePaidBackupsRowPreview() {
enabledState = BackupsSettingsState.EnabledState.Active( enabledState = BackupsSettingsState.EnabledState.Active(
type = MessageBackupsType.Paid( type = MessageBackupsType.Paid(
pricePerMonth = FiatMoney(BigDecimal.valueOf(4), Currency.getInstance("CAD")), pricePerMonth = FiatMoney(BigDecimal.valueOf(4), Currency.getInstance("CAD")),
storageAllowanceBytes = 1_000_000 storageAllowanceBytes = 1_000_000,
mediaTtl = 30.days
), ),
expiresAt = 0.seconds, expiresAt = 0.seconds,
lastBackupAt = 0.seconds lastBackupAt = 0.seconds

View File

@@ -101,7 +101,8 @@ class BackupsSettingsViewModel : ViewModel() {
activeSubscription.activeSubscription.amount, activeSubscription.activeSubscription.amount,
Currency.getInstance(activeSubscription.activeSubscription.currency) Currency.getInstance(activeSubscription.activeSubscription.currency)
), ),
storageAllowanceBytes = backupType.storageAllowanceBytes storageAllowanceBytes = backupType.storageAllowanceBytes,
mediaTtl = backupType.mediaTtl
) )
) )
} else { } else {

View File

@@ -1225,7 +1225,8 @@ private fun SubscriptionMismatchMissingGooglePlayCardPreview() {
state = RemoteBackupsSettingsState.BackupState.SubscriptionMismatchMissingGooglePlay( state = RemoteBackupsSettingsState.BackupState.SubscriptionMismatchMissingGooglePlay(
messageBackupsType = MessageBackupsType.Paid( messageBackupsType = MessageBackupsType.Paid(
pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")), pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")),
storageAllowanceBytes = 100_000_000 storageAllowanceBytes = 100_000_000,
mediaTtl = 30.days
), ),
renewalTime = System.currentTimeMillis().milliseconds + 30.days renewalTime = System.currentTimeMillis().milliseconds + 30.days
) )
@@ -1242,7 +1243,8 @@ private fun BackupCardPreview() {
backupState = RemoteBackupsSettingsState.BackupState.ActivePaid( backupState = RemoteBackupsSettingsState.BackupState.ActivePaid(
messageBackupsType = MessageBackupsType.Paid( messageBackupsType = MessageBackupsType.Paid(
pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")), pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")),
storageAllowanceBytes = 100_000_000 storageAllowanceBytes = 100_000_000,
mediaTtl = 30.days
), ),
renewalTime = 1727193018.seconds, renewalTime = 1727193018.seconds,
price = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")) price = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD"))
@@ -1253,7 +1255,8 @@ private fun BackupCardPreview() {
backupState = RemoteBackupsSettingsState.BackupState.Canceled( backupState = RemoteBackupsSettingsState.BackupState.Canceled(
messageBackupsType = MessageBackupsType.Paid( messageBackupsType = MessageBackupsType.Paid(
pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")), pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")),
storageAllowanceBytes = 100_000_000 storageAllowanceBytes = 100_000_000,
mediaTtl = 30.days
), ),
renewalTime = 1727193018.seconds renewalTime = 1727193018.seconds
) )
@@ -1263,7 +1266,8 @@ private fun BackupCardPreview() {
backupState = RemoteBackupsSettingsState.BackupState.Inactive( backupState = RemoteBackupsSettingsState.BackupState.Inactive(
messageBackupsType = MessageBackupsType.Paid( messageBackupsType = MessageBackupsType.Paid(
pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")), pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")),
storageAllowanceBytes = 100_000_000 storageAllowanceBytes = 100_000_000,
mediaTtl = 30.days
), ),
renewalTime = 1727193018.seconds renewalTime = 1727193018.seconds
) )
@@ -1273,7 +1277,8 @@ private fun BackupCardPreview() {
backupState = RemoteBackupsSettingsState.BackupState.ActivePaid( backupState = RemoteBackupsSettingsState.BackupState.ActivePaid(
messageBackupsType = MessageBackupsType.Paid( messageBackupsType = MessageBackupsType.Paid(
pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")), pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")),
storageAllowanceBytes = 100_000_000 storageAllowanceBytes = 100_000_000,
mediaTtl = 30.days
), ),
renewalTime = 1727193018.seconds, renewalTime = 1727193018.seconds,
price = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD")) price = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("CAD"))

View File

@@ -108,6 +108,9 @@ public class SubscriptionsConfiguration {
@JsonProperty("playProductId") @JsonProperty("playProductId")
private String playProductId; private String playProductId;
@JsonProperty("mediaTtlDays")
private long mediaTtlDays;
public long getStorageAllowanceBytes() { public long getStorageAllowanceBytes() {
return storageAllowanceBytes; return storageAllowanceBytes;
} }
@@ -115,6 +118,10 @@ public class SubscriptionsConfiguration {
public String getPlayProductId() { public String getPlayProductId() {
return playProductId; return playProductId;
} }
public long getMediaTtlDays() {
return mediaTtlDays;
}
} }
public Map<String, CurrencyConfiguration> getCurrencies() { public Map<String, CurrencyConfiguration> getCurrencies() {