DocumentScreen: pages in LazyColumn
This commit is contained in:
committed by
pynicolas
parent
b3d13d98bc
commit
5292f5bdb3
@@ -55,7 +55,6 @@ dependencies {
|
|||||||
implementation(libs.androidx.ui.graphics)
|
implementation(libs.androidx.ui.graphics)
|
||||||
implementation(libs.androidx.ui.tooling.preview)
|
implementation(libs.androidx.ui.tooling.preview)
|
||||||
implementation(libs.androidx.material3)
|
implementation(libs.androidx.material3)
|
||||||
implementation(libs.accompanist.flowlayout)
|
|
||||||
implementation(libs.androidx.camera.core)
|
implementation(libs.androidx.camera.core)
|
||||||
implementation(libs.androidx.camera.camera2)
|
implementation(libs.androidx.camera.camera2)
|
||||||
implementation(libs.androidx.camera.lifecycle)
|
implementation(libs.androidx.camera.lifecycle)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import androidx.core.content.FileProvider
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import org.mydomain.myscan.ui.theme.MyScanTheme
|
import org.mydomain.myscan.ui.theme.MyScanTheme
|
||||||
import org.mydomain.myscan.view.CameraScreen
|
import org.mydomain.myscan.view.CameraScreen
|
||||||
import org.mydomain.myscan.view.FinalizeDocumentScreen
|
import org.mydomain.myscan.view.DocumentScreen
|
||||||
import org.opencv.android.OpenCVLoader
|
import org.opencv.android.OpenCVLoader
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
@@ -54,17 +54,21 @@ class MainActivity : ComponentActivity() {
|
|||||||
val pageIds by viewModel.pageIds.collectAsStateWithLifecycle()
|
val pageIds by viewModel.pageIds.collectAsStateWithLifecycle()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
MyScanTheme {
|
MyScanTheme {
|
||||||
Scaffold { innerPadding ->
|
|
||||||
Column (modifier = Modifier.padding(innerPadding)) {
|
Column {
|
||||||
when (currentScreen) {
|
when (currentScreen) {
|
||||||
is Screen.Camera -> {
|
is Screen.Camera -> {
|
||||||
CameraScreen(viewModel, liveAnalysisState,
|
Scaffold { innerPadding->
|
||||||
|
CameraScreen(
|
||||||
|
viewModel, liveAnalysisState,
|
||||||
onImageAnalyzed = { image -> viewModel.segment(image) },
|
onImageAnalyzed = { image -> viewModel.segment(image) },
|
||||||
onFinalizePressed = { viewModel.navigateTo(Screen.FinalizeDocument) }
|
onFinalizePressed = { viewModel.navigateTo(Screen.FinalizeDocument) },
|
||||||
|
modifier = Modifier.padding(innerPadding)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
is Screen.FinalizeDocument -> {
|
is Screen.FinalizeDocument -> {
|
||||||
FinalizeDocumentScreen (
|
DocumentScreen (
|
||||||
pageIds,
|
pageIds,
|
||||||
imageLoader = { id -> viewModel.getBitmap(id) },
|
imageLoader = { id -> viewModel.getBitmap(id) },
|
||||||
onBackPressed = { viewModel.navigateTo(Screen.Camera) },
|
onBackPressed = { viewModel.navigateTo(Screen.Camera) },
|
||||||
@@ -78,7 +82,6 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun sharePdf(
|
private fun sharePdf(
|
||||||
viewModel: MainViewModel,
|
viewModel: MainViewModel,
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ fun CameraScreen(
|
|||||||
viewModel: MainViewModel,
|
viewModel: MainViewModel,
|
||||||
liveAnalysisState: LiveAnalysisState,
|
liveAnalysisState: LiveAnalysisState,
|
||||||
onImageAnalyzed: (ImageProxy) -> Unit,
|
onImageAnalyzed: (ImageProxy) -> Unit,
|
||||||
onFinalizePressed: () -> Unit
|
onFinalizePressed: () -> Unit,
|
||||||
|
modifier: Modifier,
|
||||||
) {
|
) {
|
||||||
// TODO pause the live analysis when displaying the PageValidationDialogs
|
// TODO pause the live analysis when displaying the PageValidationDialogs
|
||||||
val showPageDialog = rememberSaveable { mutableStateOf(false) }
|
val showPageDialog = rememberSaveable { mutableStateOf(false) }
|
||||||
@@ -112,7 +113,7 @@ fun CameraScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = modifier.fillMaxSize()) {
|
||||||
CameraPreviewWithOverlay(onImageAnalyzed, captureController, liveAnalysisState)
|
CameraPreviewWithOverlay(onImageAnalyzed, captureController, liveAnalysisState)
|
||||||
MessageBox(liveAnalysisState.inferenceTime)
|
MessageBox(liveAnalysisState.inferenceTime)
|
||||||
Button(
|
Button(
|
||||||
|
|||||||
@@ -18,11 +18,8 @@ import android.graphics.Bitmap
|
|||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
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.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
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.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.rememberScrollState
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
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.material.icons.filled.Share
|
||||||
import androidx.compose.material3.BottomAppBar
|
import androidx.compose.material3.BottomAppBar
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
@@ -48,10 +42,10 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
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.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@@ -60,7 +54,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun FinalizeDocumentScreen(
|
fun DocumentScreen(
|
||||||
pageIds: List<String>,
|
pageIds: List<String>,
|
||||||
imageLoader: (String) -> Bitmap,
|
imageLoader: (String) -> Bitmap,
|
||||||
onBackPressed: () -> Unit,
|
onBackPressed: () -> Unit,
|
||||||
@@ -71,6 +65,10 @@ fun FinalizeDocumentScreen(
|
|||||||
Scaffold (
|
Scaffold (
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||||
|
titleContentColor = MaterialTheme.colorScheme.primary,
|
||||||
|
),
|
||||||
title = { Text("Finalize document") },
|
title = { Text("Finalize document") },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBackPressed) {
|
IconButton(onClick = onBackPressed) {
|
||||||
@@ -81,7 +79,7 @@ fun FinalizeDocumentScreen(
|
|||||||
},
|
},
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
BottomAppBar(
|
BottomAppBar(
|
||||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
|
containerColor = Color.Transparent
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@@ -108,50 +106,35 @@ private fun DocumentPreview(
|
|||||||
imageLoader: (String) -> Bitmap,
|
imageLoader: (String) -> Bitmap,
|
||||||
onDeleteImage: (String) -> Unit,
|
onDeleteImage: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
Column(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(rememberScrollState())
|
.background(MaterialTheme.colorScheme.surfaceContainer)
|
||||||
.padding(padding)
|
.padding(PaddingValues(top = padding.calculateTopPadding()))
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
"Pages",
|
"${pageIds.size} pages",
|
||||||
modifier = Modifier.padding(start = 16.dp, top = 16.dp),
|
modifier = Modifier.padding(start = 16.dp, top = 16.dp).align(Alignment.TopStart),
|
||||||
style = MaterialTheme.typography.titleMedium
|
style = MaterialTheme.typography.titleMedium
|
||||||
)
|
)
|
||||||
FlowRow(
|
LazyColumn (
|
||||||
|
contentPadding = PaddingValues(20.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.fillMaxWidth(),
|
.align(Alignment.Center),
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
) {
|
) {
|
||||||
pageIds.forEachIndexed { index, id ->
|
items(pageIds) { id ->
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
|
||||||
// TODO Display small images rather than big ones
|
// TODO Display small images rather than big ones
|
||||||
// TODO Make it possible to zoom on an image
|
// TODO Make it possible to zoom on an image
|
||||||
Box {
|
val bitmap = imageLoader(id).asImageBitmap()
|
||||||
Image(
|
Image(
|
||||||
bitmap = imageLoader(id).asImageBitmap(),
|
bitmap = bitmap,
|
||||||
contentDescription = "Page ${index + 1}",
|
contentDescription = null,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(160.dp)
|
.size(200.dp)
|
||||||
.padding(4.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,7 +144,7 @@ private fun DocumentPreview(
|
|||||||
@Preview
|
@Preview
|
||||||
fun DocumentScreenPreview() {
|
fun DocumentScreenPreview() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
FinalizeDocumentScreen(
|
DocumentScreen(
|
||||||
pageIds = listOf(1, 2, 2, 2).map { "gallica.bnf.fr-bpt6k5530456s-$it.jpg" },
|
pageIds = listOf(1, 2, 2, 2).map { "gallica.bnf.fr-bpt6k5530456s-$it.jpg" },
|
||||||
imageLoader = { id ->
|
imageLoader = { id ->
|
||||||
context.assets.open(id).use { input ->
|
context.assets.open(id).use { input ->
|
||||||
@@ -12,7 +12,6 @@ composeBom = "2025.05.00"
|
|||||||
camerax = "1.4.2"
|
camerax = "1.4.2"
|
||||||
litert = "1.2.0"
|
litert = "1.2.0"
|
||||||
opencv = "4.11.0"
|
opencv = "4.11.0"
|
||||||
flowlayout = "0.36.0"
|
|
||||||
assertj = "3.27.3"
|
assertj = "3.27.3"
|
||||||
pdfbox = "2.0.27.0"
|
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-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
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-core = { group = "androidx.camera", name = "camera-core", version.ref = "camerax" }
|
||||||
androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", 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" }
|
androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }
|
||||||
|
|||||||
Reference in New Issue
Block a user