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