diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/ImportFilesViewModel.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/ImportFilesViewModel.kt index 448fb27315..fd7eec5814 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/ImportFilesViewModel.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/ImportFilesViewModel.kt @@ -65,8 +65,7 @@ class ImportFilesViewModel @Inject constructor( @IoDispatcher private val ioDispatcher: CoroutineDispatcher, ) : ViewModel() { - val sendActionResult by transferSendManager::sendActionResult - val integrityCheckResult by transferSendManager::integrityCheckResult + val sendStatus by transferSendManager::sendStatus @OptIn(FlowPreview::class) val importedFilesDebounced = importationFilesManager.importedFiles @@ -136,11 +135,7 @@ class ImportFilesViewModel @Inject constructor( } fun resetSendActionResult() { - transferSendManager.resetSendActionResult() - } - - fun resetIntegrityCheckResult() { - transferSendManager.resetIntegrityCheckResult() + transferSendManager.resetSendStatus() } private suspend fun removeOldData() { @@ -255,17 +250,6 @@ class ImportFilesViewModel @Inject constructor( } //endregion - sealed class SendActionResult { - data object NotStarted : SendActionResult() - data object Pending : SendActionResult() - data class Success(val totalSize: Long) : SendActionResult() - data object Failure : SendActionResult() - } - - enum class AppIntegrityResult { - Idle, Ongoing, Success, Fail - } - companion object { private val TAG = ImportFilesViewModel::class.java.simpleName diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferSendManager.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferSendManager.kt index 2e23735439..984c838f59 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferSendManager.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferSendManager.kt @@ -25,8 +25,6 @@ import com.infomaniak.multiplatform_swisstransfer.data.NewUploadSession import com.infomaniak.multiplatform_swisstransfer.managers.UploadManager import com.infomaniak.sentry.SentryLog import com.infomaniak.swisstransfer.BuildConfig -import com.infomaniak.swisstransfer.ui.screen.newtransfer.ImportFilesViewModel.AppIntegrityResult -import com.infomaniak.swisstransfer.ui.screen.newtransfer.ImportFilesViewModel.SendActionResult import com.infomaniak.swisstransfer.workers.UploadWorker import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.CancellationException @@ -47,11 +45,8 @@ class TransferSendManager @Inject constructor( ) { // TODO: Merge these two UI states in a single one for the whole flow of logic - private val _sendActionResult = MutableStateFlow(SendActionResult.NotStarted) - val sendActionResult = _sendActionResult.asStateFlow() - - private val _integrityCheckResult = MutableStateFlow(AppIntegrityResult.Idle) - val integrityCheckResult = _integrityCheckResult.asStateFlow() + private val _sendStatus = MutableStateFlow(SendStatus.Default) + val sendStatus = _sendStatus.asStateFlow() suspend fun sendNewTransfer(newUploadSession: NewUploadSession) { val uploadSession = uploadManager.createAndGetUpload(newUploadSession) @@ -67,26 +62,23 @@ class TransferSendManager @Inject constructor( } private suspend fun sendTransfer(uploadSessionUuid: String) { - runCatching { - _integrityCheckResult.value = AppIntegrityResult.Ongoing + _sendStatus.value = SendStatus.Pending + runCatching { withIntegrityToken( onSuccess = { attestationToken -> - _integrityCheckResult.value = AppIntegrityResult.Success - _sendActionResult.update { SendActionResult.Pending } - uploadManager.initUploadSession( attestationHeaderName = AppIntegrityManager.ATTESTATION_TOKEN_HEADER, attestationToken = attestationToken, )!! // TODO: Handle ContainerErrorsException here uploadWorkerScheduler.scheduleWork(uploadSessionUuid) - _sendActionResult.update { + _sendStatus.update { val totalSize = importationFilesManager.importedFiles.value.sumOf { it.fileSize } - SendActionResult.Success(totalSize) + SendStatus.Success(totalSize) } }, onRefused = { - _integrityCheckResult.value = AppIntegrityResult.Fail + _sendStatus.value = SendStatus.Refused }, onFailure = { exception -> if (exception !is CancellationException) { @@ -94,12 +86,12 @@ class TransferSendManager @Inject constructor( } else { SentryLog.i(TAG, "Integrity token received an exception", exception) } - _sendActionResult.update { SendActionResult.Failure } + _sendStatus.update { SendStatus.Failure } }, ) }.onFailure { exception -> SentryLog.e(TAG, "Failed to start the upload", exception) - _sendActionResult.update { SendActionResult.Failure } + _sendStatus.update { SendStatus.Failure } } } @@ -158,14 +150,18 @@ class TransferSendManager @Inject constructor( return token } + //endregion - fun resetIntegrityCheckResult() { - _integrityCheckResult.value = AppIntegrityResult.Idle + fun resetSendStatus() { + _sendStatus.value = SendStatus.Default } - //endregion - fun resetSendActionResult() { - _sendActionResult.value = SendActionResult.NotStarted + sealed class SendStatus { + data object Default : SendStatus() + data object Pending : SendStatus() + data class Success(val totalSize: Long) : SendStatus() + data object Refused : SendStatus() + data object Failure : SendStatus() } companion object { diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/ImportFilesScreen.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/ImportFilesScreen.kt index 4178ce1cec..7cf2c74e6e 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/ImportFilesScreen.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/ImportFilesScreen.kt @@ -31,6 +31,7 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.PreviewParameter @@ -46,8 +47,7 @@ import com.infomaniak.swisstransfer.ui.screen.main.settings.EmailLanguageOption import com.infomaniak.swisstransfer.ui.screen.main.settings.ValidityPeriodOption import com.infomaniak.swisstransfer.ui.screen.main.settings.components.SettingOption import com.infomaniak.swisstransfer.ui.screen.newtransfer.ImportFilesViewModel -import com.infomaniak.swisstransfer.ui.screen.newtransfer.ImportFilesViewModel.AppIntegrityResult -import com.infomaniak.swisstransfer.ui.screen.newtransfer.ImportFilesViewModel.SendActionResult +import com.infomaniak.swisstransfer.ui.screen.newtransfer.TransferSendManager.SendStatus import com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components.* import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme @@ -74,20 +74,13 @@ fun ImportFilesScreen( val passwordOptionState by importFilesViewModel.selectedPasswordOption.collectAsStateWithLifecycle() val emailLanguageState by importFilesViewModel.selectedLanguageOption.collectAsStateWithLifecycle() - val sendActionResult by importFilesViewModel.sendActionResult.collectAsStateWithLifecycle() - val integrityCheckResult by importFilesViewModel.integrityCheckResult.collectAsStateWithLifecycle() + val sendStatus by importFilesViewModel.sendStatus.collectAsStateWithLifecycle() val snackbarHostState = remember { SnackbarHostState() } - HandleIntegrityCheckResult( - snackbarHostState = snackbarHostState, - integrityCheckResult = { integrityCheckResult }, - resetResult = { importFilesViewModel.resetIntegrityCheckResult() }, - ) - HandleSendActionResult( snackbarHostState = snackbarHostState, - getSendActionResult = { sendActionResult }, + sendStatus = { sendStatus }, transferType = { selectedTransferType }, navigateToUploadProgress = navigateToUploadProgress, resetSendActionResult = importFilesViewModel::resetSendActionResult, @@ -142,10 +135,9 @@ fun ImportFilesScreen( transferOptionsCallbacks = transferOptionsCallbacks, addFiles = importFilesViewModel::importFiles, closeActivity = closeActivity, - integrityCheckResult = { integrityCheckResult }, + sendStatus = { sendStatus }, sendTransfer = importFilesViewModel::sendTransfer, shouldStartByPromptingUserForFiles = true, - isTransferStarted = { sendActionResult != SendActionResult.NotStarted }, snackbarHostState = snackbarHostState, ) } @@ -153,17 +145,21 @@ fun ImportFilesScreen( @Composable private fun HandleSendActionResult( snackbarHostState: SnackbarHostState, - getSendActionResult: () -> SendActionResult?, + sendStatus: () -> SendStatus, transferType: () -> TransferTypeUi, navigateToUploadProgress: (transferType: TransferTypeUi, totalSize: Long) -> Unit, resetSendActionResult: () -> Unit, ) { - val errorMessage = stringResource(R.string.errorUnknown) - LaunchedEffect(getSendActionResult()) { - when (val actionResult = getSendActionResult()) { - is SendActionResult.Success -> navigateToUploadProgress(transferType(), actionResult.totalSize) - is SendActionResult.Failure -> { - snackbarHostState.showSnackbar(errorMessage) + val context = LocalContext.current + + LaunchedEffect(sendStatus()) { + when (val actionResult = sendStatus()) { + is SendStatus.Success -> navigateToUploadProgress(transferType(), actionResult.totalSize) + is SendStatus.Refused -> { + snackbarHostState.showSnackbar(context.getString(R.string.errorAppIntegrity)) + } + is SendStatus.Failure -> { + snackbarHostState.showSnackbar(context.getString(R.string.errorUnknown)) resetSendActionResult() } else -> Unit @@ -171,23 +167,6 @@ private fun HandleSendActionResult( } } -@Composable -private fun HandleIntegrityCheckResult( - snackbarHostState: SnackbarHostState, - integrityCheckResult: () -> AppIntegrityResult, - resetResult: () -> Unit, -) { - val result = integrityCheckResult() - val errorMessage = stringResource(R.string.errorAppIntegrity) - - LaunchedEffect(result == AppIntegrityResult.Success || result == AppIntegrityResult.Fail) { - if (integrityCheckResult() == AppIntegrityResult.Fail) { // TODO: Better error management - snackbarHostState.showSnackbar(errorMessage) - } - resetResult() - } -} - @Composable private fun ImportFilesScreen( files: () -> List, @@ -200,9 +179,8 @@ private fun ImportFilesScreen( addFiles: (List) -> Unit, closeActivity: () -> Unit, shouldStartByPromptingUserForFiles: Boolean, - integrityCheckResult: () -> AppIntegrityResult, + sendStatus: () -> SendStatus, sendTransfer: () -> Unit, - isTransferStarted: () -> Boolean, snackbarHostState: SnackbarHostState? = null, ) { @@ -224,9 +202,8 @@ private fun ImportFilesScreen( importedFiles = files, shouldShowEmailAddressesFields = { shouldShowEmailAddressesFields }, transferAuthorEmail = transferAuthorEmail, - integrityCheckResult = integrityCheckResult, + sendStatus = sendStatus, sendTransfer = sendTransfer, - isTransferStarted = isTransferStarted, ) }, content = { @@ -404,9 +381,8 @@ private fun SendButton( importedFiles: () -> List, shouldShowEmailAddressesFields: () -> Boolean, transferAuthorEmail: GetSetCallbacks, - integrityCheckResult: () -> AppIntegrityResult, + sendStatus: () -> SendStatus, sendTransfer: () -> Unit, - isTransferStarted: () -> Boolean, ) { val remainingFilesCount = filesToImportCount() val isImporting by remember(remainingFilesCount) { derivedStateOf { remainingFilesCount > 0 } } @@ -427,13 +403,19 @@ private fun SendButton( modifier = modifier, title = stringResource(R.string.transferSendButton), style = ButtonType.PRIMARY, - showIndeterminateProgress = { integrityCheckResult() == AppIntegrityResult.Ongoing || isTransferStarted() }, - enabled = { importedFiles().isNotEmpty() && !isImporting && isSenderEmailCorrect && !isTransferStarted() }, + showIndeterminateProgress = { sendStatus() == SendStatus.Pending }, + enabled = { importedFiles().isNotEmpty() && !isImporting && isSenderEmailCorrect && sendStatus().canEnableButton() }, progress = progress, onClick = { sendTransfer() }, ) } +private fun SendStatus.canEnableButton(): Boolean = when (this) { + SendStatus.Default, + SendStatus.Refused -> true + else -> false +} + data class TransferOptionsCallbacks( val transferOptionsStates: () -> List, val onTransferOptionValueSelected: (SettingOption) -> Unit, @@ -496,9 +478,8 @@ private fun Preview(@PreviewParameter(FileUiListPreviewParameter::class) files: addFiles = {}, closeActivity = {}, shouldStartByPromptingUserForFiles = false, - integrityCheckResult = { AppIntegrityResult.Idle }, + sendStatus = { SendStatus.Default }, sendTransfer = {}, - isTransferStarted = { false }, ) } }