Add "Ready to download" state and clear out a few TODOs.
This commit is contained in:
parent
21c359f919
commit
7e93e15a9b
9 changed files with 234 additions and 23 deletions
|
@ -20,6 +20,8 @@ import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
|
@ -126,12 +126,16 @@ private fun BackupsSettingsContent(
|
||||||
when (backupsSettingsState.enabledState) {
|
when (backupsSettingsState.enabledState) {
|
||||||
BackupsSettingsState.EnabledState.Loading -> {
|
BackupsSettingsState.EnabledState.Loading -> {
|
||||||
LoadingBackupsRow()
|
LoadingBackupsRow()
|
||||||
|
|
||||||
|
OtherWaysToBackUpHeading()
|
||||||
}
|
}
|
||||||
|
|
||||||
BackupsSettingsState.EnabledState.Inactive -> {
|
BackupsSettingsState.EnabledState.Inactive -> {
|
||||||
InactiveBackupsRow(
|
InactiveBackupsRow(
|
||||||
onBackupsRowClick = onBackupsRowClick
|
onBackupsRowClick = onBackupsRowClick
|
||||||
)
|
)
|
||||||
|
|
||||||
|
OtherWaysToBackUpHeading()
|
||||||
}
|
}
|
||||||
|
|
||||||
is BackupsSettingsState.EnabledState.Active -> {
|
is BackupsSettingsState.EnabledState.Active -> {
|
||||||
|
@ -139,29 +143,28 @@ private fun BackupsSettingsContent(
|
||||||
enabledState = backupsSettingsState.enabledState,
|
enabledState = backupsSettingsState.enabledState,
|
||||||
onBackupsRowClick = onBackupsRowClick
|
onBackupsRowClick = onBackupsRowClick
|
||||||
)
|
)
|
||||||
|
|
||||||
|
OtherWaysToBackUpHeading()
|
||||||
}
|
}
|
||||||
|
|
||||||
BackupsSettingsState.EnabledState.Never -> {
|
BackupsSettingsState.EnabledState.Never -> {
|
||||||
NeverEnabledBackupsRow(
|
NeverEnabledBackupsRow(
|
||||||
onBackupsRowClick = onBackupsRowClick
|
onBackupsRowClick = onBackupsRowClick
|
||||||
)
|
)
|
||||||
|
|
||||||
|
OtherWaysToBackUpHeading()
|
||||||
}
|
}
|
||||||
|
|
||||||
BackupsSettingsState.EnabledState.Failed -> {
|
BackupsSettingsState.EnabledState.Failed -> {
|
||||||
Text(text = "TODO")
|
WaitingForNetworkRow()
|
||||||
|
OtherWaysToBackUpHeading()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BackupsSettingsState.EnabledState.NotAvailable -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
Dividers.Default()
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
Texts.SectionHeader(
|
|
||||||
text = stringResource(R.string.RemoteBackupsSettingsFragment__other_ways_to_backup)
|
|
||||||
)
|
|
||||||
|
|
||||||
Rows.TextRow(
|
Rows.TextRow(
|
||||||
text = stringResource(R.string.RemoteBackupsSettingsFragment__on_device_backups),
|
text = stringResource(R.string.RemoteBackupsSettingsFragment__on_device_backups),
|
||||||
label = stringResource(R.string.RemoteBackupsSettingsFragment__save_your_backups_to),
|
label = stringResource(R.string.RemoteBackupsSettingsFragment__save_your_backups_to),
|
||||||
|
@ -172,6 +175,15 @@ private fun BackupsSettingsContent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun OtherWaysToBackUpHeading() {
|
||||||
|
Dividers.Default()
|
||||||
|
|
||||||
|
Texts.SectionHeader(
|
||||||
|
text = stringResource(R.string.RemoteBackupsSettingsFragment__other_ways_to_backup)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NeverEnabledBackupsRow(
|
private fun NeverEnabledBackupsRow(
|
||||||
onBackupsRowClick: () -> Unit = {}
|
onBackupsRowClick: () -> Unit = {}
|
||||||
|
@ -215,6 +227,18 @@ private fun NeverEnabledBackupsRow(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun WaitingForNetworkRow() {
|
||||||
|
Rows.TextRow(
|
||||||
|
text = {
|
||||||
|
Text(text = stringResource(R.string.RemoteBackupsSettingsFragment__waiting_for_network))
|
||||||
|
},
|
||||||
|
icon = {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun InactiveBackupsRow(
|
private fun InactiveBackupsRow(
|
||||||
onBackupsRowClick: () -> Unit = {}
|
onBackupsRowClick: () -> Unit = {}
|
||||||
|
@ -327,6 +351,26 @@ private fun BackupsSettingsContentPreview() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SignalPreview
|
||||||
|
@Composable
|
||||||
|
private fun BackupsSettingsContentNotAvailablePreview() {
|
||||||
|
Previews.Preview {
|
||||||
|
BackupsSettingsContent(
|
||||||
|
backupsSettingsState = BackupsSettingsState(
|
||||||
|
enabledState = BackupsSettingsState.EnabledState.NotAvailable
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SignalPreview
|
||||||
|
@Composable
|
||||||
|
private fun WaitingForNetworkRowPreview() {
|
||||||
|
Previews.Preview {
|
||||||
|
WaitingForNetworkRow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SignalPreview
|
@SignalPreview
|
||||||
@Composable
|
@Composable
|
||||||
private fun InactiveBackupsRowPreview() {
|
private fun InactiveBackupsRowPreview() {
|
||||||
|
|
|
@ -23,6 +23,11 @@ data class BackupsSettingsState(
|
||||||
*/
|
*/
|
||||||
data object Loading : EnabledState
|
data object Loading : EnabledState
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Google Play Billing is not available on this device
|
||||||
|
*/
|
||||||
|
data object NotAvailable : EnabledState
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backups have never been enabled.
|
* Backups have never been enabled.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,8 +23,10 @@ import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
||||||
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType
|
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType
|
||||||
import org.thoughtcrime.securesms.components.settings.app.subscription.RecurringInAppPaymentRepository
|
import org.thoughtcrime.securesms.components.settings.app.subscription.RecurringInAppPaymentRepository
|
||||||
import org.thoughtcrime.securesms.database.model.InAppPaymentSubscriberRecord
|
import org.thoughtcrime.securesms.database.model.InAppPaymentSubscriberRecord
|
||||||
|
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.util.InternetConnectionObserver
|
import org.thoughtcrime.securesms.util.InternetConnectionObserver
|
||||||
|
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||||
import java.util.Currency
|
import java.util.Currency
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
@ -58,6 +60,11 @@ class BackupsSettingsViewModel : ViewModel() {
|
||||||
|
|
||||||
private fun loadEnabledState() {
|
private fun loadEnabledState() {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
if (!RemoteConfig.messageBackups || !AppDependencies.billingApi.isApiAvailable()) {
|
||||||
|
internalStateFlow.update { it.copy(enabledState = BackupsSettingsState.EnabledState.NotAvailable) }
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
|
||||||
val enabledState = when (SignalStore.backup.backupTier) {
|
val enabledState = when (SignalStore.backup.backupTier) {
|
||||||
MessageBackupTier.FREE -> getEnabledStateForFreeTier()
|
MessageBackupTier.FREE -> getEnabledStateForFreeTier()
|
||||||
MessageBackupTier.PAID -> getEnabledStateForPaidTier()
|
MessageBackupTier.PAID -> getEnabledStateForPaidTier()
|
||||||
|
|
|
@ -10,7 +10,12 @@ import org.thoughtcrime.securesms.backup.v2.ui.status.BackupStatusData
|
||||||
/**
|
/**
|
||||||
* State container for BackupStatusData, including the enabled state.
|
* State container for BackupStatusData, including the enabled state.
|
||||||
*/
|
*/
|
||||||
data class BackupRestoreState(
|
sealed interface BackupRestoreState {
|
||||||
val enabled: Boolean,
|
data object None : BackupRestoreState
|
||||||
val backupStatusData: BackupStatusData
|
data class Ready(
|
||||||
)
|
val bytes: String
|
||||||
|
) : BackupRestoreState
|
||||||
|
data class FromBackupStatusData(
|
||||||
|
val backupStatusData: BackupStatusData
|
||||||
|
) : BackupRestoreState
|
||||||
|
}
|
||||||
|
|
|
@ -58,7 +58,9 @@ import androidx.compose.ui.res.dimensionResource
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.buildAnnotatedString
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
|
@ -99,6 +101,7 @@ import org.thoughtcrime.securesms.util.viewModel
|
||||||
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
|
||||||
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 kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
@ -199,12 +202,20 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStartMediaRestore() {
|
||||||
|
// TODO - [backups] Begin media restore.
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCancelMediaRestore() {
|
override fun onCancelMediaRestore() {
|
||||||
// TODO - [backups] Cancel media restoration
|
// TODO - [backups] Cancel in-progress media restoration
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisplaySkipMediaRestoreProtectionDialog() {
|
||||||
|
viewModel.requestDialog(RemoteBackupsSettingsState.Dialog.SKIP_MEDIA_RESTORE_PROTECTION)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSkipMediaRestore() {
|
override fun onSkipMediaRestore() {
|
||||||
// TODO - [backups] Skip media restoration
|
// TODO - [backups] Skip disk-full media restoration
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLearnMoreAboutLostSubscription() {
|
override fun onLearnMoreAboutLostSubscription() {
|
||||||
|
@ -292,6 +303,8 @@ private interface ContentCallbacks {
|
||||||
fun onSelectBackupsFrequencyChange(newFrequency: BackupFrequency) = Unit
|
fun onSelectBackupsFrequencyChange(newFrequency: BackupFrequency) = Unit
|
||||||
fun onTurnOffAndDeleteBackupsConfirm() = Unit
|
fun onTurnOffAndDeleteBackupsConfirm() = Unit
|
||||||
fun onViewBackupKeyClick() = Unit
|
fun onViewBackupKeyClick() = Unit
|
||||||
|
fun onStartMediaRestore() = Unit
|
||||||
|
fun onDisplaySkipMediaRestoreProtectionDialog() = Unit
|
||||||
fun onSkipMediaRestore() = Unit
|
fun onSkipMediaRestore() = Unit
|
||||||
fun onCancelMediaRestore() = Unit
|
fun onCancelMediaRestore() = Unit
|
||||||
fun onRenewLostSubscription() = Unit
|
fun onRenewLostSubscription() = Unit
|
||||||
|
@ -365,6 +378,30 @@ private fun RemoteBackupsSettingsContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backupsEnabled) {
|
if (backupsEnabled) {
|
||||||
|
if (backupRestoreState !is BackupRestoreState.None) {
|
||||||
|
item {
|
||||||
|
Dividers.Default()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backupRestoreState is BackupRestoreState.FromBackupStatusData) {
|
||||||
|
item {
|
||||||
|
BackupStatusRow(
|
||||||
|
backupStatusData = backupRestoreState.backupStatusData,
|
||||||
|
onCancelClick = contentCallbacks::onCancelMediaRestore,
|
||||||
|
onSkipClick = contentCallbacks::onSkipMediaRestore
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if (backupRestoreState is BackupRestoreState.Ready && backupState is RemoteBackupsSettingsState.BackupState.Canceled) {
|
||||||
|
item {
|
||||||
|
BackupReadyToDownloadRow(
|
||||||
|
ready = backupRestoreState,
|
||||||
|
endOfSubscription = backupState.renewalTime,
|
||||||
|
onDownloadClick = contentCallbacks::onStartMediaRestore
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
appendBackupDetailsItems(
|
appendBackupDetailsItems(
|
||||||
backupProgress = backupProgress,
|
backupProgress = backupProgress,
|
||||||
lastBackupTimestamp = lastBackupTimestamp,
|
lastBackupTimestamp = lastBackupTimestamp,
|
||||||
|
@ -374,7 +411,7 @@ private fun RemoteBackupsSettingsContent(
|
||||||
contentCallbacks = contentCallbacks
|
contentCallbacks = contentCallbacks
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if (backupRestoreState.enabled) {
|
if (backupRestoreState is BackupRestoreState.FromBackupStatusData) {
|
||||||
item {
|
item {
|
||||||
BackupStatusRow(
|
BackupStatusRow(
|
||||||
backupStatusData = backupRestoreState.backupStatusData,
|
backupStatusData = backupRestoreState.backupStatusData,
|
||||||
|
@ -443,6 +480,18 @@ private fun RemoteBackupsSettingsContent(
|
||||||
onContactSupport = contentCallbacks::onContactSupport
|
onContactSupport = contentCallbacks::onContactSupport
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemoteBackupsSettingsState.Dialog.SKIP_MEDIA_RESTORE_PROTECTION -> {
|
||||||
|
SkipDownloadDialog(
|
||||||
|
renewalTime = if (backupState is RemoteBackupsSettingsState.BackupState.WithTypeAndRenewalTime) {
|
||||||
|
backupState.renewalTime
|
||||||
|
} else {
|
||||||
|
error("Unexpected dialog display without renewal time.")
|
||||||
|
},
|
||||||
|
onDismiss = contentCallbacks::onDialogDismissed,
|
||||||
|
onSkipClick = contentCallbacks::onSkipMediaRestore
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val snackbarMessageId = remember(requestedSnackbar) {
|
val snackbarMessageId = remember(requestedSnackbar) {
|
||||||
|
@ -931,8 +980,8 @@ private fun FailedToTurnOffBackupDialog(
|
||||||
onDismiss: () -> Unit
|
onDismiss: () -> Unit
|
||||||
) {
|
) {
|
||||||
Dialogs.SimpleAlertDialog(
|
Dialogs.SimpleAlertDialog(
|
||||||
title = "TODO",
|
title = stringResource(R.string.RemoteBackupsSettingsFragment__couldnt_turn_off_and_delete_backups),
|
||||||
body = "TODO",
|
body = stringResource(R.string.RemoteBackupsSettingsFragment__a_network_error_occurred),
|
||||||
confirm = stringResource(id = android.R.string.ok),
|
confirm = stringResource(id = android.R.string.ok),
|
||||||
onConfirm = {},
|
onConfirm = {},
|
||||||
onDismiss = onDismiss
|
onDismiss = onDismiss
|
||||||
|
@ -968,6 +1017,25 @@ private fun DownloadingYourBackupDialog(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SkipDownloadDialog(
|
||||||
|
renewalTime: Duration,
|
||||||
|
onSkipClick: () -> Unit = {},
|
||||||
|
onDismiss: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
val days = (renewalTime - System.currentTimeMillis().milliseconds).inWholeDays.toInt()
|
||||||
|
|
||||||
|
Dialogs.SimpleAlertDialog(
|
||||||
|
title = stringResource(R.string.RemoteBackupsSettingsFragment__skip_download_question),
|
||||||
|
body = pluralStringResource(R.plurals.RemoteBackupsSettingsFragment__if_you_skip_downloading, days, days),
|
||||||
|
confirm = stringResource(R.string.RemoteBackupsSettingsFragment__skip),
|
||||||
|
dismiss = stringResource(android.R.string.cancel),
|
||||||
|
confirmColor = MaterialTheme.colorScheme.error,
|
||||||
|
onConfirm = onSkipClick,
|
||||||
|
onDismiss = onDismiss
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun CircularProgressDialog(
|
private fun CircularProgressDialog(
|
||||||
|
@ -1055,6 +1123,38 @@ private fun BackupFrequencyDialog(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun BackupReadyToDownloadRow(
|
||||||
|
ready: BackupRestoreState.Ready,
|
||||||
|
endOfSubscription: Duration,
|
||||||
|
onDownloadClick: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
val days = (endOfSubscription - System.currentTimeMillis().milliseconds).inWholeDays.toInt()
|
||||||
|
val string = pluralStringResource(R.plurals.RemoteBackupsSettingsFragment__you_have_s_of_backup_data, days, ready.bytes, days)
|
||||||
|
val annotated = buildAnnotatedString {
|
||||||
|
append(string)
|
||||||
|
val startIndex = string.indexOf(ready.bytes)
|
||||||
|
val endIndex = startIndex + ready.bytes.length
|
||||||
|
|
||||||
|
addStyle(SpanStyle(fontWeight = FontWeight.Bold), startIndex, endIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = annotated,
|
||||||
|
modifier = Modifier
|
||||||
|
.horizontalGutters()
|
||||||
|
.padding(vertical = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Rows.TextRow(
|
||||||
|
text = stringResource(R.string.RemoteBackupsSettingsFragment__download),
|
||||||
|
icon = painterResource(R.drawable.symbol_arrow_circle_down_24),
|
||||||
|
onClick = onDownloadClick
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getTextForFrequency(backupsFrequency: BackupFrequency): String {
|
private fun getTextForFrequency(backupsFrequency: BackupFrequency): String {
|
||||||
return when (backupsFrequency) {
|
return when (backupsFrequency) {
|
||||||
|
@ -1082,7 +1182,7 @@ private fun RemoteBackupsSettingsContentPreview() {
|
||||||
backupState = RemoteBackupsSettingsState.BackupState.ActiveFree(
|
backupState = RemoteBackupsSettingsState.BackupState.ActiveFree(
|
||||||
messageBackupsType = MessageBackupsType.Free(mediaRetentionDays = 30)
|
messageBackupsType = MessageBackupsType.Free(mediaRetentionDays = 30)
|
||||||
),
|
),
|
||||||
backupRestoreState = BackupRestoreState(false, BackupStatusData.CouldNotCompleteBackup)
|
backupRestoreState = BackupRestoreState.FromBackupStatusData(BackupStatusData.CouldNotCompleteBackup)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1187,6 +1287,17 @@ private fun BackupCardPreview() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SignalPreview
|
||||||
|
@Composable
|
||||||
|
private fun BackupReadyToDownloadPreview() {
|
||||||
|
Previews.Preview {
|
||||||
|
BackupReadyToDownloadRow(
|
||||||
|
ready = BackupRestoreState.Ready("12GB"),
|
||||||
|
endOfSubscription = System.currentTimeMillis().milliseconds + 30.days
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SignalPreview
|
@SignalPreview
|
||||||
@Composable
|
@Composable
|
||||||
private fun LastBackupRowPreview() {
|
private fun LastBackupRowPreview() {
|
||||||
|
@ -1237,6 +1348,16 @@ private fun DownloadingYourBackupDialogPreview() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SignalPreview
|
||||||
|
@Composable
|
||||||
|
private fun SkipDownloadDialogPreview() {
|
||||||
|
Previews.Preview {
|
||||||
|
SkipDownloadDialog(
|
||||||
|
renewalTime = System.currentTimeMillis().milliseconds + 30.days
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SignalPreview
|
@SignalPreview
|
||||||
@Composable
|
@Composable
|
||||||
private fun CircularProgressDialogPreview() {
|
private fun CircularProgressDialogPreview() {
|
||||||
|
|
|
@ -112,7 +112,8 @@ data class RemoteBackupsSettingsState(
|
||||||
PROGRESS_SPINNER,
|
PROGRESS_SPINNER,
|
||||||
DOWNLOADING_YOUR_BACKUP,
|
DOWNLOADING_YOUR_BACKUP,
|
||||||
TURN_OFF_FAILED,
|
TURN_OFF_FAILED,
|
||||||
SUBSCRIPTION_NOT_FOUND
|
SUBSCRIPTION_NOT_FOUND,
|
||||||
|
SKIP_MEDIA_RESTORE_PROTECTION
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Snackbar {
|
enum class Snackbar {
|
||||||
|
|
|
@ -21,13 +21,13 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.reactive.asFlow
|
import kotlinx.coroutines.reactive.asFlow
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.signal.core.util.billing.BillingPurchaseResult
|
import org.signal.core.util.billing.BillingPurchaseResult
|
||||||
|
import org.signal.core.util.bytes
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.signal.core.util.money.FiatMoney
|
import org.signal.core.util.money.FiatMoney
|
||||||
import org.signal.donations.InAppPaymentType
|
import org.signal.donations.InAppPaymentType
|
||||||
import org.thoughtcrime.securesms.backup.v2.BackupFrequency
|
import org.thoughtcrime.securesms.backup.v2.BackupFrequency
|
||||||
import org.thoughtcrime.securesms.backup.v2.BackupRepository
|
import org.thoughtcrime.securesms.backup.v2.BackupRepository
|
||||||
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
||||||
import org.thoughtcrime.securesms.backup.v2.ui.status.BackupStatusData
|
|
||||||
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType
|
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType
|
||||||
import org.thoughtcrime.securesms.banner.banners.MediaRestoreProgressBanner
|
import org.thoughtcrime.securesms.banner.banners.MediaRestoreProgressBanner
|
||||||
import org.thoughtcrime.securesms.components.settings.app.subscription.DonationSerializationHelper.toFiatMoney
|
import org.thoughtcrime.securesms.components.settings.app.subscription.DonationSerializationHelper.toFiatMoney
|
||||||
|
@ -64,7 +64,7 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val _restoreState: MutableStateFlow<BackupRestoreState> = MutableStateFlow(BackupRestoreState(false, BackupStatusData.RestoringMedia()))
|
private val _restoreState: MutableStateFlow<BackupRestoreState> = MutableStateFlow(BackupRestoreState.None)
|
||||||
private val latestPurchaseId = MutableSharedFlow<InAppPaymentTable.InAppPaymentId>()
|
private val latestPurchaseId = MutableSharedFlow<InAppPaymentTable.InAppPaymentId>()
|
||||||
|
|
||||||
val state: StateFlow<RemoteBackupsSettingsState> = _state
|
val state: StateFlow<RemoteBackupsSettingsState> = _state
|
||||||
|
@ -86,8 +86,12 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
|
||||||
if (restoreProgress.enabled) {
|
if (restoreProgress.enabled) {
|
||||||
Log.d(TAG, "Backup is being restored. Collecting updates.")
|
Log.d(TAG, "Backup is being restored. Collecting updates.")
|
||||||
restoreProgress.dataFlow.collectLatest { latest ->
|
restoreProgress.dataFlow.collectLatest { latest ->
|
||||||
_restoreState.update { BackupRestoreState(restoreProgress.enabled, latest) }
|
_restoreState.update { BackupRestoreState.FromBackupStatusData(latest) }
|
||||||
}
|
}
|
||||||
|
} else if (SignalStore.backup.totalRestorableAttachmentSize > 0L) {
|
||||||
|
_restoreState.update { BackupRestoreState.Ready(SignalStore.backup.totalRestorableAttachmentSize.bytes.toUnitString()) }
|
||||||
|
} else {
|
||||||
|
_restoreState.update { BackupRestoreState.None }
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(1.seconds)
|
delay(1.seconds)
|
||||||
|
@ -218,10 +222,12 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
|
||||||
price = FiatMoney.fromSignalNetworkAmount(subscription.amount, Currency.getInstance(subscription.currency)),
|
price = FiatMoney.fromSignalNetworkAmount(subscription.amount, Currency.getInstance(subscription.currency)),
|
||||||
renewalTime = subscription.endOfCurrentPeriod.seconds
|
renewalTime = subscription.endOfCurrentPeriod.seconds
|
||||||
)
|
)
|
||||||
|
|
||||||
subscription.isCanceled -> RemoteBackupsSettingsState.BackupState.Canceled(
|
subscription.isCanceled -> RemoteBackupsSettingsState.BackupState.Canceled(
|
||||||
messageBackupsType = type,
|
messageBackupsType = type,
|
||||||
renewalTime = subscription.endOfCurrentPeriod.seconds
|
renewalTime = subscription.endOfCurrentPeriod.seconds
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> RemoteBackupsSettingsState.BackupState.Inactive(
|
else -> RemoteBackupsSettingsState.BackupState.Inactive(
|
||||||
messageBackupsType = type,
|
messageBackupsType = type,
|
||||||
renewalTime = subscription.endOfCurrentPeriod.seconds
|
renewalTime = subscription.endOfCurrentPeriod.seconds
|
||||||
|
|
|
@ -7694,6 +7694,26 @@
|
||||||
<string name="RemoteBackupsSettingsFragment__renew">Renew</string>
|
<string name="RemoteBackupsSettingsFragment__renew">Renew</string>
|
||||||
<!-- Button label to learn more about why subscription disappeared -->
|
<!-- Button label to learn more about why subscription disappeared -->
|
||||||
<string name="RemoteBackupsSettingsFragment__learn_more">Learn more</string>
|
<string name="RemoteBackupsSettingsFragment__learn_more">Learn more</string>
|
||||||
|
<!-- Displayed in row when backup is available for download and users subscription has expired. First placeholder is data size e.g. 12MB, second is days before expiration -->
|
||||||
|
<plurals name="RemoteBackupsSettingsFragment__you_have_s_of_backup_data">
|
||||||
|
<item quantity="one">You have %1$s of backup data that’s not on this device. Your backup will be deleted when your subscription ends in %2$d day.</item>
|
||||||
|
<item quantity="other">You have %1$s of backup data that’s not on this device. Your backup will be deleted when your subscription ends in %2$d days.</item>
|
||||||
|
</plurals>
|
||||||
|
<!-- Displayed in row when backup is available for download to let user start download -->
|
||||||
|
<string name="RemoteBackupsSettingsFragment__download">Download</string>
|
||||||
|
<!-- Dialog title for skipping download of backed up media -->
|
||||||
|
<string name="RemoteBackupsSettingsFragment__skip_download_question">Skip download?</string>
|
||||||
|
<!-- Dialog body for skiping download of backed up media -->
|
||||||
|
<plurals name="RemoteBackupsSettingsFragment__if_you_skip_downloading">
|
||||||
|
<item quantity="one">If you skip downloading the remaining media and attachments in your backup will be deleted in %1$d day.</item>
|
||||||
|
<item quantity="other">If you skip downloading the remaining media and attachments in your backup will be deleted in %1$d days.</item>
|
||||||
|
</plurals>
|
||||||
|
<!-- Positive dialog action to skip download -->
|
||||||
|
<string name="RemoteBackupsSettingsFragment__skip">Skip</string>
|
||||||
|
<!-- Dialog title for network error while trying to disable backups -->
|
||||||
|
<string name="RemoteBackupsSettingsFragment__couldnt_turn_off_and_delete_backups">Couldn\'t turn off and delete backups</string>
|
||||||
|
<!-- Dialog body for network error while trying to disable backups -->
|
||||||
|
<string name="RemoteBackupsSettingsFragment__a_network_error_occurred">A network error occurred. Please check your internet connection and try again.</string>
|
||||||
|
|
||||||
<!-- SubscriptionNotFoundBottomSheet -->
|
<!-- SubscriptionNotFoundBottomSheet -->
|
||||||
<!-- Displayed as a bottom sheet title -->
|
<!-- Displayed as a bottom sheet title -->
|
||||||
|
|
Loading…
Add table
Reference in a new issue