@@ -27,14 +27,18 @@ import androidx.compose.foundation.clickable
2727import androidx.compose.foundation.interaction.MutableInteractionSource
2828import androidx.compose.foundation.layout.Arrangement
2929import androidx.compose.foundation.layout.Box
30+ import androidx.compose.foundation.layout.Column
3031import androidx.compose.foundation.layout.Row
3132import androidx.compose.foundation.layout.fillMaxSize
3233import androidx.compose.foundation.layout.fillMaxWidth
3334import androidx.compose.foundation.layout.height
3435import androidx.compose.foundation.layout.padding
3536import androidx.compose.foundation.layout.size
3637import androidx.compose.foundation.layout.width
38+ import androidx.compose.foundation.lazy.LazyRow
39+ import androidx.compose.foundation.lazy.itemsIndexed
3740import androidx.compose.foundation.shape.CircleShape
41+ import androidx.compose.foundation.shape.RoundedCornerShape
3842import androidx.compose.material3.Button
3943import androidx.compose.material3.MaterialTheme
4044import androidx.compose.material3.Surface
@@ -48,6 +52,7 @@ import androidx.compose.runtime.remember
4852import androidx.compose.runtime.setValue
4953import androidx.compose.ui.Alignment
5054import androidx.compose.ui.Modifier
55+ import androidx.compose.ui.draw.clip
5156import androidx.compose.ui.graphics.Color
5257import androidx.compose.ui.graphics.asImageBitmap
5358import androidx.compose.ui.platform.LocalConfiguration
@@ -70,6 +75,7 @@ fun CameraScreen(
7075 modifier : Modifier ,
7176) {
7277 var previewView by remember { mutableStateOf<PreviewView ?>(null ) }
78+ val pageIds by viewModel.pageIds.collectAsStateWithLifecycle()
7379
7480 val captureController = remember { CameraCaptureController () }
7581 DisposableEffect (Unit ) {
@@ -92,7 +98,8 @@ fun CameraScreen(
9298 captureController = captureController,
9399 onPreviewViewReady = { view -> previewView = view }
94100 ) },
95- pageCount = viewModel.pageCount(),
101+ pageIds = pageIds,
102+ imageLoader = { id -> viewModel.getBitmap(id) },
96103 liveAnalysisState = liveAnalysisState,
97104 onCapture = {
98105 Log .i(" MyScan" , " Pressed <Capture>" )
@@ -110,7 +117,8 @@ fun CameraScreen(
110117private fun CameraScreenContent (
111118 modifier : Modifier ,
112119 cameraPreview : @Composable () -> Unit ,
113- pageCount : Int ,
120+ pageIds : List <String >,
121+ imageLoader : (String ) -> Bitmap ? ,
114122 liveAnalysisState : LiveAnalysisState ,
115123 onCapture : () -> Unit ,
116124 onFinalizePressed : () -> Unit ,
@@ -120,17 +128,20 @@ private fun CameraScreenContent(
120128 CameraPreviewWithOverlay (cameraPreview, liveAnalysisState, captureState)
121129 MessageBox (liveAnalysisState.inferenceTime)
122130
123- CaptureButton (
124- onClick = onCapture,
125- modifier = Modifier
126- .align(Alignment .BottomCenter )
127- .padding(bottom = 96 .dp)
128- )
129- CameraScreenFooter (
130- pageCount = pageCount,
131- onFinalizePressed = onFinalizePressed,
132- modifier = Modifier .align(Alignment .BottomCenter )
133- )
131+ Column (Modifier .align(Alignment .BottomCenter )) {
132+ CaptureButton (
133+ onClick = onCapture,
134+ modifier = Modifier
135+ .align(Alignment .CenterHorizontally )
136+ .padding(16 .dp)
137+ )
138+ CameraScreenFooter (
139+ pageIds = pageIds,
140+ imageLoader = imageLoader,
141+ onFinalizePressed = onFinalizePressed,
142+ modifier = Modifier ,
143+ )
144+ }
134145 captureState.processedImage?.let {
135146 Surface (
136147 color = Color .Black .copy(alpha = 0.3f ),
@@ -213,37 +224,83 @@ fun MessageBox(inferenceTime: Long) {
213224
214225@Composable
215226fun CameraScreenFooter (
216- pageCount : Int ,
227+ pageIds : List <String >,
228+ imageLoader : (String ) -> Bitmap ? ,
217229 onFinalizePressed : () -> Unit ,
218230 modifier : Modifier ,
219231) {
232+ val pageCount = pageIds.size
220233 Surface (
221234 color = MaterialTheme .colorScheme.inverseOnSurface,
222235 tonalElevation = 4 .dp,
223- modifier = modifier.fillMaxWidth().height(56 .dp)
236+ modifier = modifier
237+ .fillMaxWidth()
238+ .height(180 .dp)
224239 ) {
225- Row (
226- modifier = Modifier
227- .padding(horizontal = 16 .dp, vertical = 8 .dp)
228- .fillMaxWidth(),
229- verticalAlignment = Alignment .CenterVertically ,
230- horizontalArrangement = Arrangement .SpaceBetween
231- ) {
232- Text (
233- text = " Pages : $pageCount " ,
234- style = MaterialTheme .typography.bodyMedium
240+ Column {
241+ CameraCapturedPagesRow (
242+ pageIds = pageIds,
243+ imageLoader = imageLoader
235244 )
236-
237- Button (
238- onClick = onFinalizePressed,
239- enabled = pageCount > 0
245+ Row (
246+ modifier = Modifier
247+ .padding(horizontal = 16 .dp, vertical = 8 .dp)
248+ .fillMaxWidth(),
249+ verticalAlignment = Alignment .CenterVertically ,
250+ horizontalArrangement = Arrangement .SpaceBetween
240251 ) {
241- Text (" Finish" )
252+ Text (
253+ text = " $pageCount pages" ,
254+ style = MaterialTheme .typography.bodyMedium
255+ )
256+
257+ Button (
258+ onClick = onFinalizePressed,
259+ enabled = pageCount > 0
260+ ) {
261+ Text (" Finish" )
262+ }
263+ }
264+ }
265+ }
266+ }
267+
268+ @Composable
269+ fun CameraCapturedPagesRow (
270+ pageIds : List <String >,
271+ imageLoader : (String ) -> Bitmap ?
272+ ) {
273+ if (pageIds.isEmpty()) return
274+
275+ LazyRow (
276+ modifier = Modifier
277+ .fillMaxWidth()
278+ .padding(horizontal = 8 .dp, vertical = 4 .dp),
279+ horizontalArrangement = Arrangement .spacedBy(8 .dp)
280+ ) {
281+ itemsIndexed(pageIds) { index, id ->
282+ val image = imageLoader(id)
283+ if (image != null ) {
284+ Box {
285+ val bitmap = image.asImageBitmap()
286+ val modifier =
287+ if (bitmap.height > bitmap.width)
288+ Modifier .height(120 .dp)
289+ else
290+ Modifier .width(120 .dp)
291+ Image (
292+ bitmap = bitmap,
293+ contentDescription = " Page ${index + 1 } " ,
294+ modifier = modifier
295+ .clip(RoundedCornerShape (4 .dp))
296+ )
297+ }
242298 }
243299 }
244300 }
245301}
246302
303+
247304@Preview(showBackground = true )
248305@Composable
249306fun CameraScreenPreview () {
@@ -258,6 +315,7 @@ fun CameraScreenPreviewWithProcessedImage() {
258315
259316@Composable
260317private fun ScreenPreview (captureState : CaptureState ) {
318+ val context = LocalContext .current
261319 MyScanTheme {
262320 CameraScreenContent (
263321 modifier = Modifier ,
@@ -274,7 +332,12 @@ private fun ScreenPreview(captureState: CaptureState) {
274332 )
275333 }
276334 },
277- pageCount = 3 ,
335+ pageIds = listOf (1 , 2 , 2 , 2 ).map { " gallica.bnf.fr-bpt6k5530456s-$it .jpg" },
336+ imageLoader = { id ->
337+ context.assets.open(id).use { input ->
338+ BitmapFactory .decodeStream(input)
339+ }
340+ },
278341 liveAnalysisState = LiveAnalysisState (),
279342 onCapture = {},
280343 onFinalizePressed = {},
0 commit comments