From 5292f5bdb35f1372eee9410862e48565c856a920 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Nicolas <6371790+pynicolas@users.noreply.github.com> Date: Sat, 7 Jun 2025 05:23:56 +0200 Subject: [PATCH] DocumentScreen: pages in LazyColumn --- app/build.gradle.kts | 1 - .../java/org/mydomain/myscan/MainActivity.kt | 21 +++--- .../java/org/mydomain/myscan/view/Camera.kt | 5 +- ...{FinalizeDocument.kt => DocumentScreen.kt} | 75 +++++++------------ gradle/libs.versions.toml | 2 - 5 files changed, 44 insertions(+), 60 deletions(-) rename app/src/main/java/org/mydomain/myscan/view/{FinalizeDocument.kt => DocumentScreen.kt} (68%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8568eca..68f61f0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -55,7 +55,6 @@ dependencies { implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) - implementation(libs.accompanist.flowlayout) implementation(libs.androidx.camera.core) implementation(libs.androidx.camera.camera2) implementation(libs.androidx.camera.lifecycle) diff --git a/app/src/main/java/org/mydomain/myscan/MainActivity.kt b/app/src/main/java/org/mydomain/myscan/MainActivity.kt index 4f95703..9039a0e 100644 --- a/app/src/main/java/org/mydomain/myscan/MainActivity.kt +++ b/app/src/main/java/org/mydomain/myscan/MainActivity.kt @@ -35,7 +35,7 @@ import androidx.core.content.FileProvider import androidx.lifecycle.compose.collectAsStateWithLifecycle import org.mydomain.myscan.ui.theme.MyScanTheme import org.mydomain.myscan.view.CameraScreen -import org.mydomain.myscan.view.FinalizeDocumentScreen +import org.mydomain.myscan.view.DocumentScreen import org.opencv.android.OpenCVLoader import java.io.File import java.io.FileOutputStream @@ -54,17 +54,21 @@ class MainActivity : ComponentActivity() { val pageIds by viewModel.pageIds.collectAsStateWithLifecycle() val context = LocalContext.current MyScanTheme { - Scaffold { innerPadding -> - Column (modifier = Modifier.padding(innerPadding)) { + + Column { when (currentScreen) { is Screen.Camera -> { - CameraScreen(viewModel, liveAnalysisState, - onImageAnalyzed = { image -> viewModel.segment(image) }, - onFinalizePressed = { viewModel.navigateTo(Screen.FinalizeDocument) } - ) + Scaffold { innerPadding-> + CameraScreen( + viewModel, liveAnalysisState, + onImageAnalyzed = { image -> viewModel.segment(image) }, + onFinalizePressed = { viewModel.navigateTo(Screen.FinalizeDocument) }, + modifier = Modifier.padding(innerPadding) + ) + } } is Screen.FinalizeDocument -> { - FinalizeDocumentScreen ( + DocumentScreen ( pageIds, imageLoader = { id -> viewModel.getBitmap(id) }, onBackPressed = { viewModel.navigateTo(Screen.Camera) }, @@ -75,7 +79,6 @@ class MainActivity : ComponentActivity() { } } } - } } } } diff --git a/app/src/main/java/org/mydomain/myscan/view/Camera.kt b/app/src/main/java/org/mydomain/myscan/view/Camera.kt index 8262460..fbfc3e0 100644 --- a/app/src/main/java/org/mydomain/myscan/view/Camera.kt +++ b/app/src/main/java/org/mydomain/myscan/view/Camera.kt @@ -84,7 +84,8 @@ fun CameraScreen( viewModel: MainViewModel, liveAnalysisState: LiveAnalysisState, onImageAnalyzed: (ImageProxy) -> Unit, - onFinalizePressed: () -> Unit + onFinalizePressed: () -> Unit, + modifier: Modifier, ) { // TODO pause the live analysis when displaying the PageValidationDialogs val showPageDialog = rememberSaveable { mutableStateOf(false) } @@ -112,7 +113,7 @@ fun CameraScreen( } } - Box(modifier = Modifier.fillMaxSize()) { + Box(modifier = modifier.fillMaxSize()) { CameraPreviewWithOverlay(onImageAnalyzed, captureController, liveAnalysisState) MessageBox(liveAnalysisState.inferenceTime) Button( diff --git a/app/src/main/java/org/mydomain/myscan/view/FinalizeDocument.kt b/app/src/main/java/org/mydomain/myscan/view/DocumentScreen.kt similarity index 68% rename from app/src/main/java/org/mydomain/myscan/view/FinalizeDocument.kt rename to app/src/main/java/org/mydomain/myscan/view/DocumentScreen.kt index 0b8a441..50a1885 100644 --- a/app/src/main/java/org/mydomain/myscan/view/FinalizeDocument.kt +++ b/app/src/main/java/org/mydomain/myscan/view/DocumentScreen.kt @@ -18,11 +18,8 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -31,13 +28,10 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Share import androidx.compose.material3.BottomAppBar import androidx.compose.material3.Button @@ -48,10 +42,10 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.platform.LocalContext @@ -60,7 +54,7 @@ import androidx.compose.ui.unit.dp @OptIn(ExperimentalMaterial3Api::class) @Composable -fun FinalizeDocumentScreen( +fun DocumentScreen( pageIds: List, imageLoader: (String) -> Bitmap, onBackPressed: () -> Unit, @@ -71,6 +65,10 @@ fun FinalizeDocumentScreen( Scaffold ( topBar = { TopAppBar( + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primaryContainer, + titleContentColor = MaterialTheme.colorScheme.primary, + ), title = { Text("Finalize document") }, navigationIcon = { IconButton(onClick = onBackPressed) { @@ -81,7 +79,7 @@ fun FinalizeDocumentScreen( }, bottomBar = { BottomAppBar( - contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp) + containerColor = Color.Transparent ) { Row( modifier = Modifier.fillMaxWidth(), @@ -108,50 +106,35 @@ private fun DocumentPreview( imageLoader: (String) -> Bitmap, onDeleteImage: (String) -> Unit, ) { - Column( + Box( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) - .padding(padding) + .background(MaterialTheme.colorScheme.surfaceContainer) + .padding(PaddingValues(top = padding.calculateTopPadding())) ) { Text( - "Pages", - modifier = Modifier.padding(start = 16.dp, top = 16.dp), + "${pageIds.size} pages", + modifier = Modifier.padding(start = 16.dp, top = 16.dp).align(Alignment.TopStart), style = MaterialTheme.typography.titleMedium ) - FlowRow( + LazyColumn ( + contentPadding = PaddingValues(20.dp), modifier = Modifier .padding(horizontal = 16.dp) - .fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(12.dp), + .align(Alignment.Center), verticalArrangement = Arrangement.spacedBy(12.dp) ) { - pageIds.forEachIndexed { index, id -> - Column(horizontalAlignment = Alignment.CenterHorizontally) { - // TODO Display small images rather than big ones - // TODO Make it possible to zoom on an image - Box { - Image( - bitmap = imageLoader(id).asImageBitmap(), - contentDescription = "Page ${index + 1}", - modifier = Modifier - .size(160.dp) - .padding(4.dp) - .clip(RoundedCornerShape(8.dp)) - .border(1.dp, Color.DarkGray) - ) - - IconButton( - onClick = { onDeleteImage(id) }, - modifier = Modifier - .align(Alignment.TopEnd) - .size(24.dp) - .background(Color.Black.copy(alpha = 0.5f), shape = CircleShape) - ) { - Icon(Icons.Default.Delete, contentDescription = "Delete", tint = Color.White) - } - } - } + items(pageIds) { id -> + // TODO Display small images rather than big ones + // TODO Make it possible to zoom on an image + val bitmap = imageLoader(id).asImageBitmap() + Image( + bitmap = bitmap, + contentDescription = null, + modifier = Modifier + .size(200.dp) + .padding(4.dp) + ) } } } @@ -161,7 +144,7 @@ private fun DocumentPreview( @Preview fun DocumentScreenPreview() { val context = LocalContext.current - FinalizeDocumentScreen( + DocumentScreen( pageIds = listOf(1, 2, 2, 2).map { "gallica.bnf.fr-bpt6k5530456s-$it.jpg" }, imageLoader = { id -> context.assets.open(id).use { input -> diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 195ae06..f0de909 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,6 @@ composeBom = "2025.05.00" camerax = "1.4.2" litert = "1.2.0" opencv = "4.11.0" -flowlayout = "0.36.0" assertj = "3.27.3" pdfbox = "2.0.27.0" @@ -34,7 +33,6 @@ androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-man androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } -accompanist-flowlayout = { group = "com.google.accompanist", name = "accompanist-flowlayout", version.ref = "flowlayout" } androidx-camera-core = { group = "androidx.camera", name = "camera-core", version.ref = "camerax" } androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "camerax" } androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }