Export screen: add thumbnail

This commit is contained in:
Pierre-Yves Nicolas
2026-02-01 10:48:26 +01:00
parent 88e5a701fa
commit a4822d3c9e
3 changed files with 71 additions and 30 deletions

View File

@@ -183,6 +183,7 @@ class MainActivity : ComponentActivity() {
ExportScreenWrapper( ExportScreenWrapper(
navigation = navigation, navigation = navigation,
uiState = exportUiState, uiState = exportUiState,
currentDocument = document,
pdfActions = ExportActions( pdfActions = ExportActions(
initializeExportScreen = exportViewModel::initializeExportScreen, initializeExportScreen = exportViewModel::initializeExportScreen,
setFilename = exportViewModel::setFilename, setFilename = exportViewModel::setFilename,

View File

@@ -21,8 +21,10 @@ import android.text.format.Formatter
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@@ -30,9 +32,11 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.OpenInNew import androidx.compose.material.icons.automirrored.filled.OpenInNew
@@ -43,6 +47,8 @@ import androidx.compose.material.icons.filled.Download
import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@@ -65,6 +71,7 @@ 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
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@@ -74,7 +81,9 @@ import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.net.toUri import androidx.core.net.toUri
import kotlinx.collections.immutable.persistentListOf
import org.fairscan.app.R import org.fairscan.app.R
import org.fairscan.app.THUMBNAIL_SIZE_DP
import org.fairscan.app.ui.Navigation import org.fairscan.app.ui.Navigation
import org.fairscan.app.ui.components.AppOverflowMenu import org.fairscan.app.ui.components.AppOverflowMenu
import org.fairscan.app.ui.components.BackButton import org.fairscan.app.ui.components.BackButton
@@ -83,7 +92,9 @@ import org.fairscan.app.ui.components.NewDocumentDialog
import org.fairscan.app.ui.components.isLandscape import org.fairscan.app.ui.components.isLandscape
import org.fairscan.app.ui.components.pageCountText import org.fairscan.app.ui.components.pageCountText
import org.fairscan.app.ui.dummyNavigation import org.fairscan.app.ui.dummyNavigation
import org.fairscan.app.ui.fakeDocument
import org.fairscan.app.ui.screens.settings.ExportFormat.PDF import org.fairscan.app.ui.screens.settings.ExportFormat.PDF
import org.fairscan.app.ui.state.DocumentUiModel
import org.fairscan.app.ui.theme.FairScanTheme import org.fairscan.app.ui.theme.FairScanTheme
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@@ -95,6 +106,7 @@ import java.util.Locale
fun ExportScreenWrapper( fun ExportScreenWrapper(
navigation: Navigation, navigation: Navigation,
uiState: ExportUiState, uiState: ExportUiState,
currentDocument: DocumentUiModel,
pdfActions: ExportActions, pdfActions: ExportActions,
onCloseScan: () -> Unit, onCloseScan: () -> Unit,
) { ) {
@@ -122,6 +134,7 @@ fun ExportScreenWrapper(
filename = filename, filename = filename,
onFilenameChange = onFilenameChange, onFilenameChange = onFilenameChange,
uiState = uiState, uiState = uiState,
currentDocument = currentDocument,
navigation = navigation, navigation = navigation,
onShare = { onShare = {
if (!uiState.isSaving) { if (!uiState.isSaving) {
@@ -157,6 +170,7 @@ fun ExportScreen(
filename: MutableState<String>, filename: MutableState<String>,
onFilenameChange: (String) -> Unit, onFilenameChange: (String) -> Unit,
uiState: ExportUiState, uiState: ExportUiState,
currentDocument: DocumentUiModel,
navigation: Navigation, navigation: Navigation,
onShare: () -> Unit, onShare: () -> Unit,
onSave: () -> Unit, onSave: () -> Unit,
@@ -182,7 +196,8 @@ fun ExportScreen(
modifier = containerModifier.fillMaxSize(), modifier = containerModifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
TextFieldAndPdfInfos(filename, onFilenameChange, uiState, onOpen) TextFieldAndPdfInfos(filename, onFilenameChange, uiState, currentDocument, onOpen,
onThumbnailClick = navigation.toDocumentScreen)
Spacer(Modifier.weight(1f)) // push buttons down Spacer(Modifier.weight(1f)) // push buttons down
MainActions(uiState, onShare, onSave, onCloseScan) MainActions(uiState, onShare, onSave, onCloseScan)
} }
@@ -195,7 +210,8 @@ fun ExportScreen(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
TextFieldAndPdfInfos(filename, onFilenameChange, uiState, onOpen) TextFieldAndPdfInfos(filename, onFilenameChange, uiState, currentDocument, onOpen,
onThumbnailClick = navigation.toDocumentScreen)
} }
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
MainActions(uiState, onShare, onSave, onCloseScan) MainActions(uiState, onShare, onSave, onCloseScan)
@@ -211,12 +227,31 @@ private fun TextFieldAndPdfInfos(
filename: MutableState<String>, filename: MutableState<String>,
onFilenameChange: (String) -> Unit, onFilenameChange: (String) -> Unit,
uiState: ExportUiState, uiState: ExportUiState,
currentDocument: DocumentUiModel,
onOpen: (SavedItem) -> Unit, onOpen: (SavedItem) -> Unit,
onThumbnailClick: () -> Unit,
) { ) {
FilenameTextField(filename, onFilenameChange) FilenameTextField(filename, onFilenameChange)
val result = uiState.result val result = uiState.result
Row (horizontalArrangement = Arrangement.spacedBy(16.dp)) {
val thumbnail = currentDocument.loadThumbnail(0)
thumbnail?.let {
Card(
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
shape = RoundedCornerShape(6.dp),
modifier = Modifier.padding(4.dp)
.heightIn(max = THUMBNAIL_SIZE_DP.dp)
.widthIn(max = THUMBNAIL_SIZE_DP.dp)
) {
Image(
bitmap = thumbnail.asImageBitmap(),
contentDescription = null,
modifier = Modifier.clickable { onThumbnailClick() }
)
}
}
// PDF infos // PDF infos
Column( Column(
verticalArrangement = Arrangement.spacedBy(4.dp) verticalArrangement = Arrangement.spacedBy(4.dp)
@@ -248,6 +283,7 @@ private fun TextFieldAndPdfInfos(
) )
} }
} }
}
SaveStatusBar(uiState, onOpen) SaveStatusBar(uiState, onOpen)
if (uiState.error != null) { if (uiState.error != null) {
ErrorBar(uiState.error) ErrorBar(uiState.error)
@@ -609,8 +645,12 @@ fun ExportPreviewToCustomize(uiState: ExportUiState) {
ExportScreen( ExportScreen(
filename = remember { mutableStateOf("Scan 2025-07-02 17.40.42") }, filename = remember { mutableStateOf("Scan 2025-07-02 17.40.42") },
onFilenameChange = {_->}, onFilenameChange = {_->},
navigation = dummyNavigation(),
uiState = uiState, uiState = uiState,
currentDocument = fakeDocument(
persistentListOf("gallica.bnf.fr-bpt6k5530456s-1"),
LocalContext.current
),
navigation = dummyNavigation(),
onShare = {}, onShare = {},
onSave = {}, onSave = {},
onOpen = {}, onOpen = {},

View File

@@ -290,7 +290,7 @@ fun HomeScreenPreviewWithCurrentDocument() {
HomeScreen( HomeScreen(
cameraPermission = rememberCameraPermissionState(), cameraPermission = rememberCameraPermissionState(),
currentDocument = fakeDocument( currentDocument = fakeDocument(
persistentListOf("gallica.bnf.fr-bpt6k5530456s-1.jpg"), persistentListOf("gallica.bnf.fr-bpt6k5530456s-1"),
LocalContext.current LocalContext.current
), ),
navigation = dummyNavigation(), navigation = dummyNavigation(),