diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt
index 9e7eed8d1e..2d296c66d8 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt
@@ -287,6 +287,10 @@ object BackupRepository {
AppDependencies.jobManager.add(CheckRestoreMediaLeftJob(RestoreAttachmentJob.constructQueueString(RestoreAttachmentJob.RestoreOperation.MANUAL)))
}
+ fun shouldDisplayOutOfStorageSpaceUx(): Boolean {
+ return false // TODO [message-backups] Wire into actual error handling.
+ }
+
/**
* Whether the yellow dot should be displayed on the conversation list avatar.
*/
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt
index ab247e915b..fb63a2b81a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt
@@ -79,6 +79,7 @@ class AppSettingsActivity : DSLSettingsActivity(), GooglePayComponent {
StartLocation.BACKUPS_SETTINGS -> AppSettingsFragmentDirections.actionDirectToBackupsSettingsFragment()
StartLocation.INVITE -> AppSettingsFragmentDirections.actionDirectToInviteFragment()
+ StartLocation.MANAGE_STORAGE -> AppSettingsFragmentDirections.actionDirectToStoragePreferenceFragment()
}
}
@@ -178,6 +179,8 @@ class AppSettingsActivity : DSLSettingsActivity(), GooglePayComponent {
@JvmStatic
fun manageSubscriptions(context: Context): Intent = getIntentForStartLocation(context, StartLocation.MANAGE_SUBSCRIPTIONS)
+ fun manageStorage(context: Context): Intent = getIntentForStartLocation(context, StartLocation.MANAGE_STORAGE)
+
@JvmStatic
fun notificationProfiles(context: Context): Intent = getIntentForStartLocation(context, StartLocation.NOTIFICATION_PROFILES)
@@ -255,7 +258,8 @@ class AppSettingsActivity : DSLSettingsActivity(), GooglePayComponent {
CHAT_FOLDERS(17),
CREATE_CHAT_FOLDER(18),
BACKUPS_SETTINGS(19),
- INVITE(20);
+ INVITE(20),
+ MANAGE_STORAGE(21);
companion object {
fun fromCode(code: Int?): StartLocation {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt
index b4d0d63902..17a00ee9fd 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt
@@ -250,6 +250,23 @@ private fun AppSettingsContent(
}
}
+ BackupFailureState.OUT_OF_STORAGE_SPACE -> {
+ item {
+ Dividers.Default()
+
+ Rows.TextRow(
+ text = stringResource(R.string.AppSettingsFragment__backup_storage_limit_reached),
+ icon = ImageVector.vectorResource(R.drawable.symbol_error_circle_fill_24),
+ iconTint = MaterialTheme.colorScheme.error,
+ onClick = {
+ callbacks.navigate(R.id.action_appSettingsFragment_to_remoteBackupsSettingsFragment)
+ }
+ )
+
+ Dividers.Default()
+ }
+ }
+
BackupFailureState.NONE -> Unit
}
@@ -518,7 +535,7 @@ private fun BackupsWarningRow(
icon = {
Box {
Icon(
- painter = painterResource(R.drawable.symbol_backup_24),
+ imageVector = ImageVector.vectorResource(R.drawable.symbol_backup_24),
tint = MaterialTheme.colorScheme.onSurface,
contentDescription = null
)
@@ -666,7 +683,7 @@ private fun AppSettingsContentPreview() {
showPayments = true,
showAppUpdates = true,
showBackups = true,
- backupFailureState = BackupFailureState.SUBSCRIPTION_STATE_MISMATCH
+ backupFailureState = BackupFailureState.OUT_OF_STORAGE_SPACE
),
bannerManager = BannerManager(
banners = listOf(TestBanner())
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsViewModel.kt
index 285abec305..175a9a1afc 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsViewModel.kt
@@ -74,6 +74,8 @@ class AppSettingsViewModel : ViewModel() {
private fun getBackupFailureState(): BackupFailureState {
return if (!RemoteConfig.messageBackups) {
BackupFailureState.NONE
+ } else if (BackupRepository.shouldDisplayOutOfStorageSpaceUx()) {
+ BackupFailureState.OUT_OF_STORAGE_SPACE
} else if (BackupRepository.shouldDisplayBackupFailedSettingsRow()) {
BackupFailureState.BACKUP_FAILED
} else if (BackupRepository.shouldDisplayCouldNotCompleteBackupSettingsRow()) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/BackupFailureState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/BackupFailureState.kt
index cc5749b5a9..da03faf1e6 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/BackupFailureState.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/BackupFailureState.kt
@@ -13,5 +13,6 @@ enum class BackupFailureState {
BACKUP_FAILED,
COULD_NOT_COMPLETE_BACKUP,
SUBSCRIPTION_STATE_MISMATCH,
- ALREADY_REDEEMED
+ ALREADY_REDEEMED,
+ OUT_OF_STORAGE_SPACE
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt
index 3b0539b485..e76188b4b8 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt
@@ -153,20 +153,11 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
val callbacks = remember { Callbacks() }
RemoteBackupsSettingsContent(
- backupsEnabled = state.backupsEnabled,
- lastBackupTimestamp = state.lastBackupTimestamp,
- canBackUpUsingCellular = state.canBackUpUsingCellular,
- canRestoreUsingCellular = state.canRestoreUsingCellular,
- backupsFrequency = state.backupsFrequency,
- requestedDialog = state.dialog,
- requestedSnackbar = state.snackbar,
- contentCallbacks = callbacks,
- backupProgress = backupProgress,
- backupMediaSize = state.backupMediaSize,
- backupState = state.backupState,
+ state = state,
backupRestoreState = restoreState,
backupDeleteState = deleteState,
- hasRedemptionError = state.hasRedemptionError,
+ contentCallbacks = callbacks,
+ backupProgress = backupProgress,
statusBarColorNestedScrollConnection = remember { StatusBarColorNestedScrollConnection(requireActivity()) }
)
}
@@ -282,6 +273,11 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
override fun onDisplayDownloadingBackupDialog() {
viewModel.requestDialog(RemoteBackupsSettingsState.Dialog.DOWNLOADING_YOUR_BACKUP)
}
+
+ override fun onManageStorageClick() {
+ requireActivity().finish()
+ requireActivity().startActivity(AppSettingsActivity.manageStorage(requireActivity()))
+ }
}
private fun displayBackupKey() {
@@ -370,6 +366,7 @@ private interface ContentCallbacks {
fun onRedemptionErrorDetailsClick() = Unit
fun onDisplayProgressDialog() = Unit
fun onDisplayDownloadingBackupDialog() = Unit
+ fun onManageStorageClick() = Unit
object Empty : ContentCallbacks
}
@@ -377,20 +374,11 @@ private interface ContentCallbacks {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun RemoteBackupsSettingsContent(
- backupsEnabled: Boolean,
- backupState: RemoteBackupsSettingsState.BackupState,
+ state: RemoteBackupsSettingsState,
backupRestoreState: BackupRestoreState,
backupDeleteState: DeletionState,
- lastBackupTimestamp: Long,
- canBackUpUsingCellular: Boolean,
- canRestoreUsingCellular: Boolean,
- backupsFrequency: BackupFrequency,
- requestedDialog: RemoteBackupsSettingsState.Dialog,
- requestedSnackbar: RemoteBackupsSettingsState.Snackbar,
contentCallbacks: ContentCallbacks,
backupProgress: ArchiveUploadProgressState?,
- backupMediaSize: Long,
- hasRedemptionError: Boolean,
statusBarColorNestedScrollConnection: StatusBarColorNestedScrollConnection?
) {
val snackbarHostState = remember {
@@ -443,14 +431,23 @@ private fun RemoteBackupsSettingsContent(
BetaHeader(modifier = Modifier.padding(horizontal = 16.dp))
}
- if (hasRedemptionError) {
+ if (state.isOutOfStorageSpace) {
+ item {
+ OutOfStorageSpaceBlock(
+ formattedTotalStorageSpace = state.totalAllowedStorageSpace,
+ onManageStorageClick = contentCallbacks::onManageStorageClick
+ )
+ }
+ }
+
+ if (state.isOutOfStorageSpace) {
item {
RedemptionErrorAlert(onDetailsClick = contentCallbacks::onRedemptionErrorDetailsClick)
}
}
item {
- when (backupState) {
+ when (state.backupState) {
is RemoteBackupsSettingsState.BackupState.Loading -> {
LoadingCard()
}
@@ -460,12 +457,12 @@ private fun RemoteBackupsSettingsContent(
}
is RemoteBackupsSettingsState.BackupState.Pending -> {
- PendingCard(backupState.price)
+ PendingCard(state.backupState.price)
}
is RemoteBackupsSettingsState.BackupState.SubscriptionMismatchMissingGooglePlay -> {
SubscriptionMismatchMissingGooglePlayCard(
- state = backupState,
+ state = state.backupState,
onLearnMoreClick = contentCallbacks::onLearnMoreAboutLostSubscription,
onRenewClick = contentCallbacks::onRenewLostSubscription,
isRenewEnabled = backupDeleteState != DeletionState.DELETE_BACKUPS
@@ -476,7 +473,7 @@ private fun RemoteBackupsSettingsContent(
is RemoteBackupsSettingsState.BackupState.WithTypeAndRenewalTime -> {
BackupCard(
- backupState = backupState,
+ backupState = state.backupState,
onBackupTypeActionButtonClicked = contentCallbacks::onBackupTypeActionClick,
buttonsEnabled = backupDeleteState != DeletionState.DELETE_BACKUPS
)
@@ -497,19 +494,19 @@ private fun RemoteBackupsSettingsContent(
appendBackupDeletionItems(
backupDeleteState = backupDeleteState,
backupRestoreState = backupRestoreState,
- canRestoreUsingCellular = canRestoreUsingCellular,
+ canRestoreUsingCellular = state.canRestoreUsingCellular,
contentCallbacks = contentCallbacks
)
- } else if (backupsEnabled) {
+ } else if (state.backupsEnabled) {
appendBackupDetailsItems(
- backupState = backupState,
+ backupState = state.backupState,
backupRestoreState = backupRestoreState,
backupProgress = backupProgress,
- lastBackupTimestamp = lastBackupTimestamp,
- backupMediaSize = backupMediaSize,
- backupsFrequency = backupsFrequency,
- canBackUpUsingCellular = canBackUpUsingCellular,
- canRestoreUsingCellular = canRestoreUsingCellular,
+ lastBackupTimestamp = state.lastBackupTimestamp,
+ backupMediaSize = state.backupMediaSize,
+ backupsFrequency = state.backupsFrequency,
+ canBackUpUsingCellular = state.canBackUpUsingCellular,
+ canRestoreUsingCellular = state.canRestoreUsingCellular,
contentCallbacks = contentCallbacks
)
} else {
@@ -541,7 +538,7 @@ private fun RemoteBackupsSettingsContent(
}
}
- when (requestedDialog) {
+ when (state.dialog) {
RemoteBackupsSettingsState.Dialog.NONE -> {}
RemoteBackupsSettingsState.Dialog.TURN_OFF_FAILED -> {
FailedToTurnOffBackupDialog(
@@ -558,7 +555,7 @@ private fun RemoteBackupsSettingsContent(
RemoteBackupsSettingsState.Dialog.BACKUP_FREQUENCY -> {
BackupFrequencyDialog(
- selected = backupsFrequency,
+ selected = state.backupsFrequency,
onSelected = contentCallbacks::onSelectBackupsFrequencyChange,
onDismiss = contentCallbacks::onDialogDismissed
)
@@ -584,8 +581,8 @@ private fun RemoteBackupsSettingsContent(
SkipDownloadDuringDeleteDialog()
} else {
SkipDownloadDialog(
- renewalTime = if (backupState is RemoteBackupsSettingsState.BackupState.WithTypeAndRenewalTime) {
- backupState.renewalTime
+ renewalTime = if (state.backupState is RemoteBackupsSettingsState.BackupState.WithTypeAndRenewalTime) {
+ state.backupState.renewalTime
} else {
error("Unexpected dialog display without renewal time.")
},
@@ -610,8 +607,8 @@ private fun RemoteBackupsSettingsContent(
}
}
- val snackbarMessageId = remember(requestedSnackbar) {
- when (requestedSnackbar) {
+ val snackbarMessageId = remember(state.snackbar) {
+ when (state.snackbar) {
RemoteBackupsSettingsState.Snackbar.NONE -> -1
RemoteBackupsSettingsState.Snackbar.BACKUP_DELETED_AND_TURNED_OFF -> R.string.RemoteBackupsSettingsFragment__backup_deleted_and_turned_off
RemoteBackupsSettingsState.Snackbar.BACKUP_TYPE_CHANGED_AND_SUBSCRIPTION_CANCELLED -> R.string.RemoteBackupsSettingsFragment__backup_type_changed_and_subcription_deleted
@@ -623,8 +620,8 @@ private fun RemoteBackupsSettingsContent(
val snackbarText = if (snackbarMessageId == -1) "" else stringResource(id = snackbarMessageId)
- LaunchedEffect(requestedSnackbar) {
- when (requestedSnackbar) {
+ LaunchedEffect(state.snackbar) {
+ when (state.snackbar) {
RemoteBackupsSettingsState.Snackbar.NONE -> {
snackbarHostState.currentSnackbarData?.dismiss()
}
@@ -1057,6 +1054,38 @@ private fun CallToActionButton(
}
}
+@Composable
+private fun OutOfStorageSpaceBlock(
+ formattedTotalStorageSpace: String,
+ onManageStorageClick: () -> Unit
+) {
+ Dividers.Default()
+
+ Row(
+ modifier = Modifier.horizontalGutters().padding(vertical = 12.dp)
+ ) {
+ Icon(
+ imageVector = ImageVector.vectorResource(R.drawable.symbol_error_circle_fill_24),
+ tint = MaterialTheme.colorScheme.error,
+ contentDescription = null,
+ modifier = Modifier.padding(top = 4.dp, end = 4.dp, start = 2.dp).size(20.dp)
+ )
+
+ Column {
+ Text(
+ text = stringResource(R.string.RemoteBackupsSettingsFragment__youve_reached_the_s_storage_limit, formattedTotalStorageSpace),
+ modifier = Modifier.padding(start = 12.dp)
+ )
+
+ TextButton(onClick = onManageStorageClick) {
+ Text(text = stringResource(R.string.RemoteBackupsSettingsFragment__manage_storage))
+ }
+ }
+ }
+
+ Dividers.Default()
+}
+
@Composable
private fun RedemptionErrorAlert(
onDetailsClick: () -> Unit
@@ -1678,23 +1707,26 @@ private fun getTextForFrequency(backupsFrequency: BackupFrequency): String {
private fun RemoteBackupsSettingsContentPreview() {
Previews.Preview {
RemoteBackupsSettingsContent(
- backupsEnabled = true,
- lastBackupTimestamp = -1,
- canBackUpUsingCellular = false,
- canRestoreUsingCellular = false,
- backupsFrequency = BackupFrequency.MANUAL,
- requestedDialog = RemoteBackupsSettingsState.Dialog.NONE,
- requestedSnackbar = RemoteBackupsSettingsState.Snackbar.NONE,
- contentCallbacks = ContentCallbacks.Empty,
- backupProgress = null,
- backupMediaSize = 2300000,
- backupState = RemoteBackupsSettingsState.BackupState.ActiveFree(
- messageBackupsType = MessageBackupsType.Free(mediaRetentionDays = 30)
+ state = RemoteBackupsSettingsState(
+ backupsEnabled = true,
+ lastBackupTimestamp = -1,
+ canBackUpUsingCellular = false,
+ canRestoreUsingCellular = false,
+ backupsFrequency = BackupFrequency.MANUAL,
+ dialog = RemoteBackupsSettingsState.Dialog.NONE,
+ snackbar = RemoteBackupsSettingsState.Snackbar.NONE,
+ backupMediaSize = 2300000,
+ backupState = RemoteBackupsSettingsState.BackupState.ActiveFree(
+ messageBackupsType = MessageBackupsType.Free(mediaRetentionDays = 30)
+ ),
+ hasRedemptionError = true,
+ isOutOfStorageSpace = true
),
+ statusBarColorNestedScrollConnection = null,
backupDeleteState = DeletionState.NONE,
backupRestoreState = BackupRestoreState.FromBackupStatusData(BackupStatusData.CouldNotCompleteBackup),
- hasRedemptionError = true,
- statusBarColorNestedScrollConnection = null
+ contentCallbacks = ContentCallbacks.Empty,
+ backupProgress = null
)
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsState.kt
index fde3c8961a..6cf87ef1a5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsState.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsState.kt
@@ -16,6 +16,8 @@ data class RemoteBackupsSettingsState(
val canBackUpUsingCellular: Boolean = false,
val canRestoreUsingCellular: Boolean = false,
val hasRedemptionError: Boolean = false,
+ val isOutOfStorageSpace: Boolean = false,
+ val totalAllowedStorageSpace: String = "",
val backupState: BackupState = BackupState.Loading,
val backupMediaSize: Long = 0,
val backupsFrequency: BackupFrequency = BackupFrequency.DAILY,
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsViewModel.kt
index a9a99887e6..98d9c39b0c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsViewModel.kt
@@ -240,10 +240,22 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
backupMediaSize = SignalDatabase.attachments.getEstimatedArchiveMediaSize(),
backupsFrequency = SignalStore.backup.backupFrequency,
canBackUpUsingCellular = SignalStore.backup.backupWithCellular,
- canRestoreUsingCellular = SignalStore.backup.restoreWithCellular
+ canRestoreUsingCellular = SignalStore.backup.restoreWithCellular,
+ isOutOfStorageSpace = BackupRepository.shouldDisplayOutOfStorageSpaceUx()
)
}
+ if (BackupRepository.shouldDisplayOutOfStorageSpaceUx()) {
+ val paidType = BackupRepository.getBackupsType(MessageBackupTier.PAID) as? MessageBackupsType.Paid
+ if (paidType != null) {
+ _state.update {
+ it.copy(
+ totalAllowedStorageSpace = paidType.storageAllowanceBytes.bytes.toUnitString()
+ )
+ }
+ }
+ }
+
if (lastPurchase?.state == InAppPaymentTable.State.PENDING) {
Log.d(TAG, "We have a pending subscription.")
_state.update {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbar.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbar.kt
index 82fdeec038..f2c6441c42 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbar.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbar.kt
@@ -152,6 +152,7 @@ data class MainToolbarState(
val callFilter: CallLogFilter = CallLogFilter.ALL,
val hasUnreadPayments: Boolean = false,
val hasFailedBackups: Boolean = false,
+ val isOutOfRemoteStorageSpace: Boolean = false,
val hasEnabledNotificationProfile: Boolean = false,
val showNotificationProfilesTooltip: Boolean = false,
val hasPassphrase: Boolean = false,
@@ -506,14 +507,14 @@ private fun ProxyAction(
@Composable
private fun HeadsUpIndicator(state: MainToolbarState, modifier: Modifier = Modifier) {
- if (!state.hasUnreadPayments && !state.hasFailedBackups) {
+ if (!state.hasUnreadPayments && !state.hasFailedBackups && !state.isOutOfRemoteStorageSpace) {
return
}
- val color = if (state.hasFailedBackups) {
- Color(0xFFFFCC00)
- } else {
- MaterialTheme.colorScheme.primary
+ val color = when {
+ state.isOutOfRemoteStorageSpace -> Color.Transparent
+ state.hasFailedBackups -> Color(0xFFFFCC00)
+ else -> MaterialTheme.colorScheme.primary
}
Box(
@@ -521,7 +522,13 @@ private fun HeadsUpIndicator(state: MainToolbarState, modifier: Modifier = Modif
.size(13.dp)
.background(color = color, shape = CircleShape)
) {
- // Intentionally empty
+ if (state.isOutOfRemoteStorageSpace) {
+ Icon(
+ imageVector = ImageVector.vectorResource(R.drawable.symbol_error_circle_fill_16),
+ tint = MaterialTheme.colorScheme.error,
+ contentDescription = null
+ )
+ }
}
}
@@ -736,7 +743,8 @@ private fun FullMainToolbarPreview() {
destination = MainNavigationListLocation.CHATS,
hasEnabledNotificationProfile = true,
proxyState = MainToolbarState.ProxyState.CONNECTED,
- hasFailedBackups = true
+ hasFailedBackups = true,
+ isOutOfRemoteStorageSpace = false
),
callback = object : MainToolbarCallback by MainToolbarCallback.Empty {
override fun onSearchClick() {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt
index 83d9282393..9adf0d9017 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt
@@ -46,6 +46,7 @@ class MainToolbarViewModel : ViewModel() {
internalStateFlow.update {
it.copy(
hasFailedBackups = BackupRepository.shouldDisplayBackupFailedIndicator() || BackupRepository.shouldDisplayBackupAlreadyRedeemedIndicator(),
+ isOutOfRemoteStorageSpace = BackupRepository.shouldDisplayOutOfStorageSpaceUx(),
hasPassphrase = !SignalStore.settings.passphraseDisabled
)
}
diff --git a/app/src/main/res/navigation/app_settings_with_change_number.xml b/app/src/main/res/navigation/app_settings_with_change_number.xml
index 1cc88f2e8d..561112e7e6 100644
--- a/app/src/main/res/navigation/app_settings_with_change_number.xml
+++ b/app/src/main/res/navigation/app_settings_with_change_number.xml
@@ -564,6 +564,13 @@
+
Couldn\'t complete backup
Couldn\'t redeem your backups subscription
+
+ Backup storage limit reached
Invite your friends
@@ -8238,6 +8240,10 @@
Backups have been turned off and your data has been deleted from Signal’s secure storage service.
Downloading: %1$s of %2$s (%3$d%%)
+
+ You\'ve reached the %1$s storage limit that\'s included with your backup plan. To backup new chats and media free up space.
+
+ Manage storage
diff --git a/core-ui/src/main/java/org/signal/core/ui/compose/Rows.kt b/core-ui/src/main/java/org/signal/core/ui/compose/Rows.kt
index 93e1a98eaa..cba51cfc23 100644
--- a/core-ui/src/main/java/org/signal/core/ui/compose/Rows.kt
+++ b/core-ui/src/main/java/org/signal/core/ui/compose/Rows.kt
@@ -293,6 +293,7 @@ object Rows {
iconModifier: Modifier = Modifier,
label: String? = null,
foregroundTint: Color = MaterialTheme.colorScheme.onSurface,
+ iconTint: Color = foregroundTint,
onClick: (() -> Unit)? = null,
onLongClick: (() -> Unit)? = null,
enabled: Boolean = true
@@ -311,7 +312,7 @@ object Rows {
Icon(
imageVector = icon,
contentDescription = null,
- tint = foregroundTint,
+ tint = iconTint,
modifier = iconModifier
)
}