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 ) }