Export screen: add a spinner during the save operation
This commit is contained in:
@@ -56,6 +56,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -117,19 +118,25 @@ fun ExportScreenWrapper(
|
||||
uiState = uiState,
|
||||
navigation = navigation,
|
||||
onShare = {
|
||||
if (!uiState.isSaving) {
|
||||
ensureCorrectFileName()
|
||||
pdfActions.share()
|
||||
}
|
||||
},
|
||||
onSave = {
|
||||
if (!uiState.isSaving) {
|
||||
ensureCorrectFileName()
|
||||
pdfActions.save()
|
||||
}
|
||||
},
|
||||
onOpen = pdfActions.open,
|
||||
onCloseScan = {
|
||||
if (!uiState.isSaving) {
|
||||
if (uiState.hasSavedOrShared)
|
||||
onCloseScan()
|
||||
else
|
||||
showConfirmationDialog.value = true
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -235,15 +242,32 @@ private fun TextFieldAndPdfInfos(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.savedBundle != null) {
|
||||
SaveInfoBar(uiState.savedBundle, onOpen)
|
||||
}
|
||||
SaveStatusBar(uiState, onOpen)
|
||||
if (uiState.errorMessage != null) {
|
||||
ErrorBar(uiState.errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SaveStatusBar(
|
||||
uiState: ExportUiState,
|
||||
onOpen: (SavedItem) -> Unit,
|
||||
) {
|
||||
when {
|
||||
uiState.isSaving -> {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(16.dp),
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
}
|
||||
}
|
||||
uiState.savedBundle != null -> {
|
||||
SaveInfoBar(uiState.savedBundle, onOpen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FilenameTextField(
|
||||
filename: MutableState<String>,
|
||||
@@ -299,7 +323,7 @@ private fun MainActions(
|
||||
isPrimary = !uiState.hasSavedOrShared,
|
||||
icon = Icons.Default.Download,
|
||||
text = stringResource(R.string.save),
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f).alpha(if (uiState.isSaving) 0.6f else 1f)
|
||||
)
|
||||
}
|
||||
ExportButton(
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.fairscan.app.ui.screens.settings.ExportFormat
|
||||
data class ExportUiState(
|
||||
val format: ExportFormat = ExportFormat.PDF,
|
||||
val isGenerating: Boolean = false,
|
||||
val isSaving: Boolean = false,
|
||||
val result: ExportResult? = null,
|
||||
val savedBundle: SavedBundle? = null,
|
||||
val hasShared: Boolean = false,
|
||||
|
||||
@@ -193,6 +193,7 @@ class ExportViewModel(container: AppContainer, val imageRepository: ImageReposit
|
||||
|
||||
fun onRequestSave(context: Context) {
|
||||
viewModelScope.launch {
|
||||
_uiState.update {it.copy(isSaving = true, errorMessage = null, savedBundle = null) }
|
||||
try {
|
||||
// Must not run on the main thread: some SAF providers (e.g. Nextcloud)
|
||||
// may perform network I/O
|
||||
@@ -208,6 +209,8 @@ class ExportViewModel(container: AppContainer, val imageRepository: ImageReposit
|
||||
} catch (e: Exception) {
|
||||
logger.e("FairScan", "Failed to save PDF", e)
|
||||
_events.emit(ExportEvent.SaveError)
|
||||
} finally {
|
||||
_uiState.update { it.copy(isSaving = false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user