Skip to content

Commit 8abf720

Browse files
committed
fix: Restore ability to cancel an in-progress upload
1 parent 8aa3764 commit 8abf720

File tree

2 files changed

+35
-12
lines changed

2 files changed

+35
-12
lines changed

app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/upload/UploadViewModel.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,26 +45,27 @@ class UploadViewModel @Inject constructor() : ViewModel() {
4545
val abandonUploadRequest = CallableState<Unit>()
4646

4747
init {
48+
viewModelScope.launch { handleCancellationRequests() }
4849
viewModelScope.launch {
4950
UploadForegroundService.uploadStateFlow.collectLatest { uploadState ->
5051
if (uploadState is UploadState.Retry) handleRetryRequests()
5152
}
5253
}
5354
}
5455

56+
private suspend fun handleCancellationRequests(): Nothing = repeatWhileActive {
57+
abandonUploadRequest.awaitOneCall()
58+
UploadForegroundService.cancelUpload()
59+
}
60+
5561
private suspend fun handleRetryRequests(): Nothing = repeatWhileActive {
5662
val shouldRetry = raceOf(
5763
{ retryRequest.awaitOneCall(); true },
5864
{ editRequest.awaitOneCall(); false },
59-
{ abandonUploadRequest.awaitOneCall(); null },
6065
)
6166
when (shouldRetry) {
6267
true -> UploadForegroundService.retry()
6368
false -> UploadForegroundService.giveUp()
64-
null -> {
65-
UploadForegroundService.removeAllFiles()
66-
UploadForegroundService.giveUp()
67-
}
6869
}
6970
}
7071
}

app/src/main/java/com/infomaniak/swisstransfer/upload/UploadForegroundService.kt

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import dagger.hilt.android.AndroidEntryPoint
4040
import kotlinx.coroutines.*
4141
import kotlinx.coroutines.channels.Channel
4242
import kotlinx.coroutines.flow.*
43+
import splitties.coroutines.raceOf
4344
import splitties.coroutines.repeatWhileActive
4445
import splitties.experimental.ExperimentalSplittiesApi
4546
import splitties.init.appCtx
@@ -60,6 +61,7 @@ class UploadForegroundService : ForegroundService(Companion, redeliverIntentIfKi
6061

6162
private val startSignal = Channel<StartUploadRequest>()
6263

64+
private val cancelTransferSignals = Channel<Unit>()
6365
private val shouldRetrySignals = Channel<Boolean>()
6466

6567
private val pickedFilesExtractor: PickedFilesExtractor = PickedFilesExtractorImpl().also {
@@ -123,6 +125,10 @@ class UploadForegroundService : ForegroundService(Companion, redeliverIntentIfKi
123125
shouldRetrySignals.send(false)
124126
}
125127

128+
suspend fun cancelUpload() {
129+
cancelTransferSignals.send(Unit)
130+
}
131+
126132
private fun keepServiceRunningWhileNeeded() {
127133
val needsToKeepFileUris = isHandlingPickedFilesFlow.transformLatest { isHandlingFiles ->
128134
if (isHandlingFiles) emit(true)
@@ -202,21 +208,24 @@ class UploadForegroundService : ForegroundService(Companion, redeliverIntentIfKi
202208
)
203209

204210
//TODO[UL-retry]: Once we support resuming the upload:
205-
// 1. Remove this big `isInternetConnectedFlow` thing and move it to just the uploader part.
211+
// 1. Remove `isInternetConnectedFlow.mapLatest` from `tryCompletingWithInternetUnlessCancelled`,
212+
// and move it to just the uploader part.
206213
// 2. Remove the loop (repeatWhileActive) below.
207214
// 3. In the uploader, use a function named `uploadAllRemainingWithRetries` or something.
208-
val transferUuid = isInternetConnectedFlow.mapLatest { isInternetConnected ->
209-
if (isInternetConnected.not()) {
215+
val transferUuid = tryCompletingWithInternetUnlessCancelled(
216+
valueIfCancelled = null,
217+
withoutInternet = {
210218
currentState = uploadStateFlow.filterIsInstance<UploadState.Ongoing>().first().copy(
211219
status = Status.WaitingForInternet
212220
)
213221
awaitCancellation()
214222
}
223+
) {
215224
repeatWhileActive retryLoop@{
216225
val result = startUploadSession(
217226
startRequest = startRequest,
218227
updateState = { currentState = it }
219-
) ?: return@mapLatest null
228+
) ?: return@tryCompletingWithInternetUnlessCancelled null
220229
val uploader = TransferUploader(
221230
uploadManager = uploadManager,
222231
fileChunkSizeManager = fileChunkSizeManager,
@@ -242,11 +251,11 @@ class UploadForegroundService : ForegroundService(Companion, redeliverIntentIfKi
242251
if (shouldRetry()) {
243252
return@retryLoop
244253
} else {
245-
return@mapLatest null
254+
return@tryCompletingWithInternetUnlessCancelled null
246255
}
247-
}.onSuccess { uuid -> return@mapLatest uuid }
256+
}.onSuccess { uuid -> return@tryCompletingWithInternetUnlessCancelled uuid }
248257
}
249-
}.first()
258+
}
250259
currentState = if (transferUuid != null) {
251260
val url = sharedApiUrlCreator.shareTransferUrl(transferUuid)
252261
val transferType = startRequest.info.type
@@ -268,6 +277,19 @@ class UploadForegroundService : ForegroundService(Companion, redeliverIntentIfKi
268277
}
269278
}
270279

280+
private suspend fun <R> tryCompletingWithInternetUnlessCancelled(
281+
valueIfCancelled: R,
282+
withoutInternet: suspend () -> R,
283+
block: suspend () -> R
284+
): R? = raceOf({
285+
isInternetConnectedFlow.mapLatest { isInternetConnected ->
286+
if (isInternetConnected) block() else withoutInternet()
287+
}.first()
288+
}, {
289+
cancelTransferSignals.receive()
290+
valueIfCancelled
291+
})
292+
271293
private suspend fun shouldRetry(): Boolean = shouldRetrySignals.receive()
272294

273295
private suspend fun startUploadSession(

0 commit comments

Comments
 (0)