Skip to content

Commit

Permalink
refactor: Remove recipients from navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinBoulongne committed Jan 14, 2025
1 parent c5bf40c commit c716756
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,27 +103,25 @@ sealed class NewTransferNavigation : NavigationDestination() {
data object ImportFilesDestination : NewTransferNavigation()

@Serializable
data class ValidateUserEmailDestination(val userEmail: String, val recipients: List<String>) : NewTransferNavigation()
data class ValidateUserEmailDestination(val userEmail: String) : NewTransferNavigation()

@Serializable
data class UploadProgressDestination(
val transferType: TransferTypeUi,
val totalSize: Long,
val recipients: List<String>,
) : NewTransferNavigation()

@Serializable
data class UploadSuccessDestination(
val transferType: TransferTypeUi,
val transferUuid: String,
val transferUrl: String,
val recipients: List<String>,
) : NewTransferNavigation()

@Serializable
data class UploadErrorDestination(
val transferType: TransferTypeUi,
val totalSize: Long,
val recipients: List<String>,
) : NewTransferNavigation()

@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,11 @@ fun NewTransferNavHost(
ImportFilesScreen(
importFilesViewModel = hiltViewModel<ImportFilesViewModel>(it),
closeActivity = closeActivity,
navigateToUploadProgress = { transferType, totalSize, recipients ->
navController.navigate(UploadProgressDestination(transferType, totalSize, recipients))
navigateToUploadProgress = { transferType, totalSize ->
navController.navigate(UploadProgressDestination(transferType, totalSize))
},
navigateToEmailValidation = { email, recipients ->
navController.navigate(ValidateUserEmailDestination(email, recipients))
},
navigateToFilesDetails = {
navController.navigate(NewTransferFilesDetailsDestination)
}
navigateToEmailValidation = { email -> navController.navigate(ValidateUserEmailDestination(email)) },
navigateToFilesDetails = { navController.navigate(NewTransferFilesDetailsDestination) },
)
}
composable<ValidateUserEmailDestination> {
Expand All @@ -65,7 +61,7 @@ fun NewTransferNavHost(
closeActivity = closeActivityAndPromptForValidation,
navigateBack = { navController.popBackStack() },
navigateToUploadInProgress = { totalSize ->
navController.navigate(UploadProgressDestination(TransferTypeUi.Mail, totalSize, args.recipients))
navController.navigate(UploadProgressDestination(TransferTypeUi.Mail, totalSize))
},
emailToValidate = args.userEmail,
)
Expand All @@ -74,23 +70,19 @@ fun NewTransferNavHost(
val args = it.toRoute<UploadProgressDestination>()
UploadProgressScreen(
totalSizeInBytes = args.totalSize,
navigateToUploadSuccess = { transferUrl ->
navController.navigate(UploadSuccessDestination(args.transferType, transferUrl, args.recipients))
},
navigateToUploadError = {
navController.navigate(
UploadErrorDestination(args.transferType, args.totalSize, args.recipients),
)
navigateToUploadSuccess = { transferUuid, transferUrl ->
navController.navigate(UploadSuccessDestination(args.transferType, transferUuid, transferUrl))
},
navigateToUploadError = { navController.navigate(UploadErrorDestination(args.transferType, args.totalSize)) },
navigateBackToImportFiles = { navController.popBackStack(route = ImportFilesDestination, inclusive = false) },
)
}
composable<UploadSuccessDestination> {
val args = it.toRoute<UploadSuccessDestination>()
UploadSuccessScreen(
transferType = args.transferType,
transferUuid = args.transferUuid,
transferUrl = args.transferUrl,
recipients = args.recipients,
closeActivity = closeActivity,
)
}
Expand All @@ -99,18 +91,17 @@ fun NewTransferNavHost(
UploadErrorScreen(
navigateBackToUploadProgress = {
val hasPoppedBack = navController.popBackStack(
route = UploadProgressDestination(args.transferType, args.totalSize, args.recipients),
route = UploadProgressDestination(args.transferType, args.totalSize),
inclusive = false,
)
if (!hasPoppedBack) {
navController.navigate(UploadProgressDestination(args.transferType, args.totalSize, args.recipients))
navController.navigate(UploadProgressDestination(args.transferType, args.totalSize))
Sentry.captureMessage(
"PopBackStack to retry transfer after error has failed",
SentryLevel.ERROR,
) { scope ->
scope.setExtra("transferType", args.transferType.toString())
scope.setExtra("totalSize", args.totalSize.toString())
scope.setExtra("recipients.count", args.recipients.count().toString())
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ private val HORIZONTAL_PADDING = Margin.Medium
fun ImportFilesScreen(
importFilesViewModel: ImportFilesViewModel,
closeActivity: () -> Unit,
navigateToUploadProgress: (transferType: TransferTypeUi, totalSize: Long, recipients: List<String>) -> Unit,
navigateToEmailValidation: (email: String, recipients: List<String>) -> Unit,
navigateToUploadProgress: (transferType: TransferTypeUi, totalSize: Long) -> Unit,
navigateToEmailValidation: (email: String) -> Unit,
navigateToFilesDetails: () -> Unit,
) {

Expand All @@ -85,18 +85,9 @@ fun ImportFilesScreen(
snackbarHostState = snackbarHostState,
sendStatus = { sendStatus },
navigateToUploadProgress = { totalSize ->
navigateToUploadProgress(
selectedTransferType,
totalSize,
emailTextFieldCallbacks.validatedRecipientsEmails.get().toList(),
)
},
navigateToEmailValidation = {
navigateToEmailValidation(
emailTextFieldCallbacks.transferAuthorEmail.get(),
emailTextFieldCallbacks.validatedRecipientsEmails.get().toList(),
)
navigateToUploadProgress(selectedTransferType, totalSize)
},
navigateToEmailValidation = { navigateToEmailValidation(emailTextFieldCallbacks.transferAuthorEmail.get()) },
resetSendActionResult = importFilesViewModel::resetSendActionResult,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import com.infomaniak.core2.R as RCore2
@Composable
fun UploadProgressScreen(
totalSizeInBytes: Long,
navigateToUploadSuccess: (String) -> Unit,
navigateToUploadSuccess: (String, String) -> Unit,
navigateToUploadError: () -> Unit,
navigateBackToImportFiles: () -> Unit,
uploadProgressViewModel: UploadProgressViewModel = hiltViewModel<UploadProgressViewModel>(),
Expand Down Expand Up @@ -81,14 +81,14 @@ fun UploadProgressScreen(
@Composable
private fun HandleProgressState(
uiState: () -> UploadProgressUiState,
navigateToUploadSuccess: (String) -> Unit,
navigateToUploadSuccess: (String, String) -> Unit,
navigateToUploadError: () -> Unit,
navigateBackToImportFiles: () -> Unit,
) {
val currentUiState = uiState()
LaunchedEffect(uiState()) {
when (currentUiState) {
is UploadProgressUiState.Success -> navigateToUploadSuccess(currentUiState.transferUrl)
is UploadProgressUiState.Success -> navigateToUploadSuccess(currentUiState.transferUuid, currentUiState.transferUrl)
is UploadProgressUiState.Error -> navigateToUploadError()
is UploadProgressUiState.Cancel -> navigateBackToImportFiles()
else -> Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.infomaniak.swisstransfer.R
import com.infomaniak.swisstransfer.ui.components.*
import com.infomaniak.swisstransfer.ui.images.AppImages.AppIllus
Expand All @@ -39,7 +42,20 @@ import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
import com.infomaniak.swisstransfer.ui.utils.PreviewAllWindows

@Composable
fun UploadSuccessEmailScreen(emails: List<String>, closeActivity: () -> Unit) {
fun UploadSuccessEmailScreen(
transferUuid: String,
closeActivity: () -> Unit,
uploadSuccessViewModel: UploadSuccessViewModel = hiltViewModel<UploadSuccessViewModel>(),
) {
val emails by uploadSuccessViewModel.recipients.collectAsStateWithLifecycle()
uploadSuccessViewModel.fetchTransfer(transferUuid)
UploadSuccessEmailScreen({ emails }, closeActivity)
}

// TODO: It looks like we are losing the emails somewhere, probably in KMP?
// (They are still there in the UploadSession in Realm, but not in the Transfer object.)
@Composable
fun UploadSuccessEmailScreen(emails: () -> List<String>, closeActivity: () -> Unit) {
BottomStickyButtonScaffold(
topBar = { BrandTopAppBar() },
bottomButton = {
Expand All @@ -62,13 +78,13 @@ fun UploadSuccessEmailScreen(emails: List<String>, closeActivity: () -> Unit) {
IllustratedMessageBlock(
icon = AppIllus.Beers.image(),
title = TransferTypeUi.Mail.titleRes,
description = pluralStringResource(TransferTypeUi.Mail.descriptionRes!!, emails.count()),
description = pluralStringResource(TransferTypeUi.Mail.descriptionRes!!, emails().count()),
)

Spacer(Modifier.height(Margin.Medium))

EmailsFlowRow(
emails = emails,
emails = emails(),
modifier = Modifier.widthIn(max = 800.dp),
horizontalArrangement = Arrangement.Center,
)
Expand All @@ -81,7 +97,7 @@ fun UploadSuccessEmailScreen(emails: List<String>, closeActivity: () -> Unit) {
private fun UploadSuccessEmailScreenPreview(@PreviewParameter(EmailsPreviewParameter::class) emails: List<String>) {
SwissTransferTheme {
Surface {
UploadSuccessEmailScreen(emails) {}
UploadSuccessEmailScreen({ emails }, {})
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ import com.infomaniak.swisstransfer.ui.utils.PreviewAllWindows
@Composable
fun UploadSuccessScreen(
transferType: TransferTypeUi,
transferUuid: String,
transferUrl: String,
recipients: List<String>,
closeActivity: () -> Unit,
) {
BackHandler(onBack = closeActivity)

if (transferType == TransferTypeUi.Mail) {
UploadSuccessEmailScreen(emails = recipients, closeActivity = closeActivity)
UploadSuccessEmailScreen(transferUuid, closeActivity)
} else {
UploadSuccessQrScreen(transferType, transferUrl, closeActivity)
}
Expand All @@ -48,7 +48,7 @@ private fun UploadSuccessScreenPreview() {
UploadSuccessScreen(
transferType = TransferTypeUi.QrCode,
transferUrl = "https://chk.me/83azQOl",
recipients = emptyList(),
transferUuid = "",
closeActivity = {},
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Infomaniak SwissTransfer - Android
* Copyright (C) 2025 Infomaniak Network SA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.infomaniak.swisstransfer.ui.screen.newtransfer.upload

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.infomaniak.multiplatform_swisstransfer.managers.TransferManager
import com.infomaniak.swisstransfer.di.IoDispatcher
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class UploadSuccessViewModel @Inject constructor(
private val transferManager: TransferManager,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher,
) : ViewModel() {

private val _transferUuidFlow = MutableSharedFlow<String>()

@OptIn(ExperimentalCoroutinesApi::class)
val recipients = _transferUuidFlow.flatMapLatest { transferUuid ->
transferManager.getTransferFlow(transferUuid).map { it?.recipients?.toList() ?: emptyList() }.flowOn(ioDispatcher)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = emptyList(),
)

fun fetchTransfer(transferUuid: String) {
viewModelScope.launch(ioDispatcher) { _transferUuidFlow.emit(transferUuid) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import androidx.work.*
import androidx.work.WorkInfo.State
import com.infomaniak.core2.sentry.SentryLog
import com.infomaniak.multiplatform_swisstransfer.SharedApiUrlCreator
import com.infomaniak.multiplatform_swisstransfer.managers.AppSettingsManager
import com.infomaniak.multiplatform_swisstransfer.managers.UploadManager
import com.infomaniak.multiplatform_swisstransfer.utils.FileUtils
import com.infomaniak.swisstransfer.ui.screen.newtransfer.ImportLocalStorage
import com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components.TransferTypeUi.Companion.toTransferTypeUi
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.ExperimentalCoroutinesApi
Expand All @@ -40,6 +42,7 @@ import javax.inject.Singleton
class UploadWorker @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted params: WorkerParameters,
private val appSettingsManager: AppSettingsManager,
private val importLocalStorage: ImportLocalStorage,
private val uploadManager: UploadManager,
) : BaseCoroutineWorker(appContext, params) {
Expand All @@ -51,13 +54,16 @@ class UploadWorker @AssistedInject constructor(
maxChunkCount = MAX_CHUNK_COUNT,
)
}

private val uploadFileTask by lazy {
UploadFileTask(uploadManager, fileChunkSizeManager)
}

private var uploadedBytes = 0L
private var lastUpdateTime = 0L

private val transferType by lazy { appSettingsManager.getAppSettings()!!.lastTransferType.toTransferTypeUi().name }

override suspend fun launchWork(): Result {
SentryLog.i(TAG, "Work launched")

Expand All @@ -82,7 +88,13 @@ class UploadWorker @AssistedInject constructor(
val transferUuid = uploadManager.finishUploadSession(uploadSession.uuid)
importLocalStorage.removeImportFolder()

return Result.success(workDataOf(TRANSFER_UUID_TAG to transferUuid, UPLOADED_BYTES_TAG to totalSize))
return Result.success(
workDataOf(
UPLOADED_BYTES_TAG to totalSize,
TRANSFER_TYPE_TAG to transferType,
TRANSFER_UUID_TAG to transferUuid,
)
)
}

override fun onFinish() {
Expand Down Expand Up @@ -147,11 +159,18 @@ class UploadWorker @AssistedInject constructor(
}

@Immutable
data class Success(override val uploadedSize: Long, val transferUrl: String) : UploadProgressUiState(uploadedSize) {
data class Success(
override val uploadedSize: Long,
val transferType: String,
val transferUuid: String,
val transferUrl: String,
) : UploadProgressUiState(uploadedSize) {
companion object {
fun create(outputData: Data, sharedApiUrlCreator: SharedApiUrlCreator): Success? {
return Success(
uploadedSize = outputData.getLong(UPLOADED_BYTES_TAG, 0L),
transferType = outputData.getString(TRANSFER_TYPE_TAG) ?: return null,
transferUuid = outputData.getString(TRANSFER_UUID_TAG) ?: return null,
transferUrl = outputData.getString(TRANSFER_UUID_TAG)
?.let { transferUuid -> sharedApiUrlCreator.shareTransferUrl(transferUuid) } ?: return null,
)
Expand All @@ -172,6 +191,7 @@ class UploadWorker @AssistedInject constructor(
private const val MAX_CHUNK_COUNT = (FileUtils.MAX_FILES_SIZE / EXPECTED_CHUNK_SIZE).toInt()

private const val UPLOADED_BYTES_TAG = "uploaded_bytes_tag"
private const val TRANSFER_TYPE_TAG = "transfer_type_tag"
private const val TRANSFER_UUID_TAG = "transfer_uuid_tag"

private const val PROGRESS_ELAPSED_TIME = 50
Expand Down

0 comments on commit c716756

Please sign in to comment.