Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Merge send transfer states #280

Merged
merged 4 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.coroutineScope
Expand All @@ -46,11 +44,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.Initial)
val sendStatus = _sendStatus.asStateFlow()

suspend fun sendNewTransfer(newUploadSession: NewUploadSession) {
val uploadSession = uploadManager.createAndGetUpload(newUploadSession)
Expand All @@ -66,29 +61,26 @@ class TransferSendManager @Inject constructor(
}

private suspend fun sendTransfer(uploadSessionUuid: String) {
_integrityCheckResult.value = AppIntegrityResult.Ongoing
_sendStatus.value = SendStatus.Pending

withIntegrityToken(
onSuccess = { attestationToken ->
runCatching {
_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)
}
}.onFailure { exception ->
SentryLog.e(TAG, "Failed to start the upload", exception)
_sendActionResult.update { SendActionResult.Failure }
_sendStatus.update { SendStatus.Failure }
}
},
onRefused = { _integrityCheckResult.value = AppIntegrityResult.Fail },
onRefused = { _sendStatus.update { SendStatus.Refused } },
)
}

Expand Down Expand Up @@ -139,14 +131,18 @@ class TransferSendManager @Inject constructor(

return token
}
//endregion

fun resetIntegrityCheckResult() {
_integrityCheckResult.value = AppIntegrityResult.Idle
fun resetSendStatus() {
_sendStatus.value = SendStatus.Initial
}
//endregion

fun resetSendActionResult() {
_sendActionResult.value = SendActionResult.NotStarted
sealed class SendStatus {
data object Initial : 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,42 @@ 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)
resetSendActionResult()
}
is SendStatus.Refused -> {
snackbarHostState.showSnackbar(context.getString(R.string.errorAppIntegrity))
resetSendActionResult()
}
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 +183,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 +206,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 +385,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 +407,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.Initial,
SendStatus.Refused -> true
else -> false
}

data class TransferOptionsCallbacks(
val transferOptionsStates: () -> List<TransferOptionState>,
val onTransferOptionValueSelected: (SettingOption) -> Unit,
Expand Down Expand Up @@ -496,9 +482,8 @@ private fun Preview(@PreviewParameter(FileUiListPreviewParameter::class) files:
addFiles = {},
closeActivity = {},
shouldStartByPromptingUserForFiles = false,
integrityCheckResult = { AppIntegrityResult.Idle },
sendStatus = { SendStatus.Initial },
sendTransfer = {},
isTransferStarted = { false },
)
}
}
Loading