diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/storage/ManageStorageSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/storage/ManageStorageSettingsFragment.kt index 70291e5e8a..149a6462d8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/storage/ManageStorageSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/storage/ManageStorageSettingsFragment.kt @@ -116,7 +116,9 @@ class ManageStorageSettingsFragment : ComposeFragment() { onSyncTrimThreadDeletes = { viewModel.setSyncTrimDeletes(it) }, onDeleteChatHistory = { navController.navigate("confirm-delete-chat-history") }, onToggleOnDeviceStorageOptimization = { enabled -> - if (state.onDeviceStorageOptimizationState == ManageStorageSettingsViewModel.OnDeviceStorageOptimizationState.REQUIRES_PAID_TIER) { + if (state.isPaidTierPending) { + navController.navigate("paid-tier-pending") + } else if (state.onDeviceStorageOptimizationState == ManageStorageSettingsViewModel.OnDeviceStorageOptimizationState.REQUIRES_PAID_TIER) { UpgradeToEnableOptimizedStorageSheet().show(parentFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) } else { viewModel.setOptimizeStorage(enabled) @@ -237,6 +239,19 @@ class ManageStorageSettingsFragment : ComposeFragment() { onDismiss = { navController.popBackStack() } ) } + + dialog( + route = "paid-tier-pending" + ) { + // TODO [backups] Finalized copy + Dialogs.SimpleAlertDialog( + title = "Paid tier pending", + body = "TODO", + confirm = stringResource(android.R.string.ok), + onConfirm = {}, + onDismiss = { navController.popBackStack() } + ) + } } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/storage/ManageStorageSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/storage/ManageStorageSettingsViewModel.kt index 4ed36e596c..d8f7464f0d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/storage/ManageStorageSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/storage/ManageStorageSettingsViewModel.kt @@ -8,12 +8,16 @@ package org.thoughtcrime.securesms.components.settings.app.storage import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.signal.core.util.concurrent.SignalExecutors import org.thoughtcrime.securesms.backup.v2.MessageBackupTier +import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository +import org.thoughtcrime.securesms.database.InAppPaymentTable import org.thoughtcrime.securesms.database.MediaTable import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.SignalDatabase.Companion.media @@ -37,6 +41,17 @@ class ManageStorageSettingsViewModel : ViewModel() { ) val state = store.asStateFlow() + init { + if (RemoteConfig.messageBackups) { + viewModelScope.launch(Dispatchers.IO) { + InAppPaymentsRepository.observeLatestBackupPayment() + .collectLatest { payment -> + store.update { it.copy(isPaidTierPending = payment.state == InAppPaymentTable.State.PENDING) } + } + } + } + } + fun refresh() { viewModelScope.launch { val breakdown: MediaTable.StorageBreakdown = media.getStorageBreakdown() @@ -158,7 +173,8 @@ class ManageStorageSettingsViewModel : ViewModel() { val syncTrimDeletes: Boolean, val breakdown: MediaTable.StorageBreakdown? = null, val onDeviceStorageOptimizationState: OnDeviceStorageOptimizationState, - val storageOptimizationStateChanged: Boolean = false + val storageOptimizationStateChanged: Boolean = false, + val isPaidTierPending: Boolean = false ) { companion object { const val NO_LIMIT = 0 diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/InAppPaymentsRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/InAppPaymentsRepository.kt index c4b888887d..11a81978e2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/InAppPaymentsRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/InAppPaymentsRepository.kt @@ -14,6 +14,12 @@ import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.processors.PublishProcessor import io.reactivex.rxjava3.schedulers.Schedulers +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.channels.trySendBlocking +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.distinctUntilChanged import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.logging.Log import org.signal.donations.InAppPaymentType @@ -78,6 +84,28 @@ object InAppPaymentsRepository { }.subscribeOn(Schedulers.io()) } + /** + * Returns a flow of InAppPayment objects for the latest RECURRING_BACKUP object. + */ + fun observeLatestBackupPayment(): Flow { + return callbackFlow { + fun refresh() { + val latest = SignalDatabase.inAppPayments.getLatestInAppPaymentByType(InAppPaymentType.RECURRING_BACKUP) + if (latest != null) { + trySendBlocking(latest) + } + } + + val observer = InAppPaymentObserver { + refresh() + } + AppDependencies.databaseObserver.registerInAppPaymentObserver(observer) + awaitClose { + AppDependencies.databaseObserver.unregisterObserver(observer) + } + }.conflate().distinctUntilChanged() + } + /** * Common logic for handling errors coming from the Rx chains that handle payments. These errors * are analyzed and then either written to the database or dispatched to the temporary error processor.