Skip to content

Commit

Permalink
feat: Merge transfer send states in SendTransferManager
Browse files Browse the repository at this point in the history
  • Loading branch information
LunarX committed Dec 20, 2024
1 parent 0de9e51 commit edf14bd
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -136,11 +135,7 @@ class ImportFilesViewModel @Inject constructor(
}

fun resetSendActionResult() {
transferSendManager.resetSendActionResult()
}

fun resetIntegrityCheckResult() {
transferSendManager.resetIntegrityCheckResult()
transferSendManager.resetSendStatus()
}

private suspend fun removeOldData() {
Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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?>(SendActionResult.NotStarted)
val sendActionResult = _sendActionResult.asStateFlow()

private val _integrityCheckResult = MutableStateFlow(AppIntegrityResult.Idle)
val integrityCheckResult = _integrityCheckResult.asStateFlow()
private val _sendStatus = MutableStateFlow<SendStatus>(SendStatus.Default)
val sendStatus = _sendStatus.asStateFlow()

suspend fun sendNewTransfer(newUploadSession: NewUploadSession) {
val uploadSession = uploadManager.createAndGetUpload(newUploadSession)
Expand All @@ -67,39 +62,36 @@ 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) {
SentryLog.e(TAG, "Integrity token received an exception", exception)
} 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 }
}
}

Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -142,52 +135,38 @@ fun ImportFilesScreen(
transferOptionsCallbacks = transferOptionsCallbacks,
addFiles = importFilesViewModel::importFiles,
closeActivity = closeActivity,
integrityCheckResult = { integrityCheckResult },
sendStatus = { sendStatus },
sendTransfer = importFilesViewModel::sendTransfer,
shouldStartByPromptingUserForFiles = true,
isTransferStarted = { sendActionResult != SendActionResult.NotStarted },
snackbarHostState = snackbarHostState,
)
}

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

@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<FileUi>,
Expand All @@ -200,9 +179,8 @@ private fun ImportFilesScreen(
addFiles: (List<Uri>) -> Unit,
closeActivity: () -> Unit,
shouldStartByPromptingUserForFiles: Boolean,
integrityCheckResult: () -> AppIntegrityResult,
sendStatus: () -> SendStatus,
sendTransfer: () -> Unit,
isTransferStarted: () -> Boolean,
snackbarHostState: SnackbarHostState? = null,
) {

Expand All @@ -224,9 +202,8 @@ private fun ImportFilesScreen(
importedFiles = files,
shouldShowEmailAddressesFields = { shouldShowEmailAddressesFields },
transferAuthorEmail = transferAuthorEmail,
integrityCheckResult = integrityCheckResult,
sendStatus = sendStatus,
sendTransfer = sendTransfer,
isTransferStarted = isTransferStarted,
)
},
content = {
Expand Down Expand Up @@ -404,9 +381,8 @@ private fun SendButton(
importedFiles: () -> List<FileUi>,
shouldShowEmailAddressesFields: () -> Boolean,
transferAuthorEmail: GetSetCallbacks<String>,
integrityCheckResult: () -> AppIntegrityResult,
sendStatus: () -> SendStatus,
sendTransfer: () -> Unit,
isTransferStarted: () -> Boolean,
) {
val remainingFilesCount = filesToImportCount()
val isImporting by remember(remainingFilesCount) { derivedStateOf { remainingFilesCount > 0 } }
Expand All @@ -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<TransferOptionState>,
val onTransferOptionValueSelected: (SettingOption) -> Unit,
Expand Down Expand Up @@ -496,9 +478,8 @@ private fun Preview(@PreviewParameter(FileUiListPreviewParameter::class) files:
addFiles = {},
closeActivity = {},
shouldStartByPromptingUserForFiles = false,
integrityCheckResult = { AppIntegrityResult.Idle },
sendStatus = { SendStatus.Default },
sendTransfer = {},
isTransferStarted = { false },
)
}
}

0 comments on commit edf14bd

Please sign in to comment.