@@ -23,29 +23,34 @@ import androidx.compose.foundation.layout.fillMaxSize
2323import androidx.compose.foundation.layout.fillMaxWidth
2424import androidx.compose.foundation.layout.height
2525import androidx.compose.foundation.layout.padding
26+ import androidx.compose.foundation.layout.size
2627import androidx.compose.foundation.layout.width
2728import androidx.compose.foundation.rememberScrollState
29+ import androidx.compose.foundation.shape.RoundedCornerShape
2830import androidx.compose.foundation.verticalScroll
2931import androidx.compose.material.icons.Icons
32+ import androidx.compose.material.icons.filled.DeleteOutline
3033import androidx.compose.material.icons.filled.PhotoCamera
3134import androidx.compose.material.icons.filled.PictureAsPdf
32- import androidx.compose.material3.BottomAppBar
3335import androidx.compose.material3.Button
36+ import androidx.compose.material3.ButtonDefaults
3437import androidx.compose.material3.Card
3538import androidx.compose.material3.ExperimentalMaterial3Api
3639import androidx.compose.material3.HorizontalDivider
3740import androidx.compose.material3.Icon
41+ import androidx.compose.material3.IconButton
3842import androidx.compose.material3.ListItem
3943import androidx.compose.material3.MaterialTheme
4044import androidx.compose.material3.Scaffold
45+ import androidx.compose.material3.Surface
4146import androidx.compose.material3.Text
4247import androidx.compose.material3.TopAppBar
4348import androidx.compose.runtime.Composable
44- import androidx.compose.runtime.mutableStateOf
45- import androidx.compose.runtime.saveable.rememberSaveable
4649import androidx.compose.ui.Alignment
4750import androidx.compose.ui.Modifier
51+ import androidx.compose.ui.draw.clip
4852import androidx.compose.ui.graphics.asImageBitmap
53+ import androidx.compose.ui.layout.ContentScale
4954import androidx.compose.ui.platform.LocalContext
5055import androidx.compose.ui.res.stringResource
5156import androidx.compose.ui.tooling.preview.Preview
@@ -65,11 +70,10 @@ fun HomeScreen(
6570 cameraPermission : CameraPermissionState ,
6671 currentDocument : DocumentUiModel ,
6772 navigation : Navigation ,
68- onStartNewScan : () -> Unit ,
73+ onClearScan : () -> Unit ,
6974 recentDocuments : List <RecentDocumentUiState >,
7075 onOpenPdf : (File ) -> Unit ,
7176) {
72- val showCloseDocDialog = rememberSaveable { mutableStateOf(false ) }
7377 Scaffold (
7478 topBar = {
7579 TopAppBar (
@@ -79,52 +83,38 @@ fun HomeScreen(
7983 }
8084 )
8185 },
82- bottomBar = {
83- BottomAppBar {
84- Spacer (Modifier .weight(1f ))
85- MainActionButton (
86- onClick = {
87- if (currentDocument.isEmpty()) {
88- onStartNewScan()
89- } else {
90- showCloseDocDialog.value = true
91- }
92- },
93- icon = Icons .Default .PhotoCamera ,
94- text = stringResource(R .string.start_a_new_scan),
95- modifier = Modifier
96- .padding(12 .dp)
97- .height(48 .dp),
98- )
99- }
100- }
10186 ) { padding ->
10287 Column (
10388 modifier = Modifier
10489 .padding(padding)
10590 .fillMaxSize()
10691 .verticalScroll(rememberScrollState())
10792 ) {
93+ Spacer (Modifier .weight(1f ))
94+
10895 if (! cameraPermission.isGranted) {
10996 CameraPermissionRationale (cameraPermission)
97+ } else {
98+ ScanButton (
99+ onClick = {
100+ onClearScan()
101+ navigation.toCameraScreen()
102+ },
103+ Modifier .align(Alignment .CenterHorizontally )
104+ )
110105 }
111106
112- if (! currentDocument.isEmpty()) {
113- SectionTitle (stringResource(R .string.current_document))
114- CurrentDocumentCard (currentDocument, navigation)
115- }
107+ Spacer (Modifier .weight(1f ))
116108
117- if (recentDocuments.isNotEmpty()) {
118- SectionTitle (stringResource(R .string.last_saved_documents))
109+ if (! currentDocument.isEmpty()) {
110+ OngoingScanBanner (
111+ currentDocument,
112+ onResumeScan = navigation.toDocumentScreen,
113+ onClearScan = onClearScan,
114+ )
115+ } else if (recentDocuments.isNotEmpty()) {
119116 RecentDocumentList (recentDocuments, onOpenPdf)
120117 }
121-
122- if (showCloseDocDialog.value) {
123- NewDocumentDialog (
124- onConfirm = onStartNewScan,
125- showCloseDocDialog,
126- stringResource(R .string.new_document))
127- }
128118 }
129119 }
130120}
@@ -139,44 +129,95 @@ private fun CameraPermissionRationale(cameraPermission: CameraPermissionState) {
139129 Column (Modifier .padding(16 .dp)) {
140130 Text (
141131 stringResource(R .string.camera_permission_rationale),
142- style = MaterialTheme .typography.bodyMedium
143132 )
144133 Spacer (Modifier .height(8 .dp))
145- Button (onClick = { cameraPermission.request() }) {
134+ Button (
135+ onClick = { cameraPermission.request() },
136+ modifier = Modifier .align(Alignment .CenterHorizontally )
137+ ) {
146138 Text (stringResource(R .string.grant_permission))
147139 }
148140 }
149141 }
150142}
151143
152144@Composable
153- private fun CurrentDocumentCard (
145+ fun ScanButton (onClick : () -> Unit , modifier : Modifier ) {
146+ Button (
147+ onClick = onClick,
148+ modifier = modifier.padding(32 .dp),
149+ elevation = ButtonDefaults .buttonElevation(defaultElevation = 6 .dp)
150+ ) {
151+ Icon (
152+ imageVector = Icons .Default .PhotoCamera ,
153+ contentDescription = null ,
154+ modifier = Modifier .size(48 .dp)
155+ )
156+ Spacer (Modifier .width(8 .dp))
157+ Text (
158+ text = stringResource(R .string.scan_button),
159+ style = MaterialTheme .typography.titleLarge
160+ )
161+
162+ }
163+ }
164+
165+ @Composable
166+ fun OngoingScanBanner (
154167 currentDocument : DocumentUiModel ,
155- navigation : Navigation ,
168+ onResumeScan : () -> Unit ,
169+ onClearScan : () -> Unit
156170) {
157- Card (
158- modifier = Modifier
159- .fillMaxWidth()
160- .padding(horizontal = 12 .dp, vertical = 6 .dp)
171+ Surface (
172+ tonalElevation = 2 .dp,
173+ shadowElevation = 4 .dp,
161174 ) {
162175 Row (
163- verticalAlignment = Alignment .CenterVertically ,
164- modifier = Modifier .padding(12 .dp)
176+ modifier = Modifier
177+ .fillMaxWidth()
178+ .padding(8 .dp),
179+ verticalAlignment = Alignment .CenterVertically
165180 ) {
166181 currentDocument.load(0 )?.let {
167182 Image (
168183 bitmap = it.asImageBitmap(),
169184 contentDescription = null ,
170185 modifier = Modifier
171- .height(100 .dp)
172- .padding(4 .dp)
186+ .size(60 .dp)
187+ .clip(RoundedCornerShape (4 .dp)),
188+ contentScale = ContentScale .Fit
189+ )
190+ }
191+
192+ Spacer (Modifier .width(12 .dp))
193+
194+ Column (
195+ modifier = Modifier .weight(1f )
196+ ) {
197+ Text (
198+ text = stringResource(R .string.scan_in_progress),
199+ style = MaterialTheme .typography.bodyLarge
200+ )
201+ Text (
202+ text = pageCountText(currentDocument.pageCount()),
203+ style = MaterialTheme .typography.bodyMedium,
204+ color = MaterialTheme .colorScheme.onSurface.copy(alpha = 0.7f ))
205+ }
206+
207+ IconButton (
208+ onClick = onClearScan,
209+ modifier = Modifier .size(24 .dp)
210+ ) {
211+ Icon (
212+ imageVector = Icons .Default .DeleteOutline ,
213+ contentDescription = stringResource(R .string.discard_scan),
214+ tint = MaterialTheme .colorScheme.primary
173215 )
174216 }
175217 Spacer (Modifier .width(12 .dp))
176- Column ( Modifier .weight( 1f ) ) {
177- Text (pageCountText(currentDocument.pageCount() ))
218+ Button (onClick = onResumeScan ) {
219+ Text (stringResource( R .string.resume ))
178220 }
179- MainActionButton (navigation.toDocumentScreen, stringResource(R .string.open))
180221 }
181222 }
182223}
@@ -186,8 +227,13 @@ private fun RecentDocumentList(
186227 recentDocuments : List <RecentDocumentUiState >,
187228 onOpenPdf : (File ) -> Unit
188229) {
230+ HorizontalDivider ()
231+ Text (
232+ stringResource(R .string.last_saved_documents),
233+ modifier = Modifier .padding(start = 12 .dp, top = 16 .dp, bottom = 8 .dp)
234+ )
189235 Column {
190- val maxListSize = 5
236+ val maxListSize = 3
191237 recentDocuments.subList(0 , min(maxListSize, recentDocuments.size)).forEach { doc ->
192238 ListItem (
193239 headlineContent = { Text (doc.file.name) },
@@ -202,29 +248,19 @@ private fun RecentDocumentList(
202248 },
203249 modifier = Modifier .clickable { onOpenPdf(doc.file) }
204250 )
205- HorizontalDivider ()
206251 }
207252 }
208253}
209254
210- @Composable
211- private fun SectionTitle (text : String ) {
212- Text (
213- text,
214- style = MaterialTheme .typography.titleLarge,
215- modifier = Modifier .padding(start = 12 .dp, top = 16 .dp, bottom = 8 .dp)
216- )
217- }
218-
219255@Preview
220256@Composable
221257fun HomeScreenPreviewOnFirstLaunch () {
222258 MyScanTheme {
223259 HomeScreen (
224260 cameraPermission = rememberCameraPermissionState(),
225- currentDocument = DocumentUiModel ( listOf ()) { _ -> null } ,
261+ currentDocument = fakeDocument() ,
226262 navigation = dummyNavigation(),
227- onStartNewScan = {},
263+ onClearScan = {},
228264 recentDocuments = listOf (),
229265 onOpenPdf = {},
230266 )
@@ -241,7 +277,22 @@ fun HomeScreenPreviewWithCurrentDocument() {
241277 listOf (" gallica.bnf.fr-bpt6k5530456s-1.jpg" ),
242278 LocalContext .current),
243279 navigation = dummyNavigation(),
244- onStartNewScan = {},
280+ onClearScan = {},
281+ recentDocuments = listOf (),
282+ onOpenPdf = {},
283+ )
284+ }
285+ }
286+
287+ @Preview
288+ @Composable
289+ fun HomeScreenPreviewWithLastSavedFiles () {
290+ MyScanTheme {
291+ HomeScreen (
292+ cameraPermission = rememberCameraPermissionState(),
293+ currentDocument = fakeDocument(),
294+ navigation = dummyNavigation(),
295+ onClearScan = {},
245296 recentDocuments = listOf (
246297 RecentDocumentUiState (File (" /path/my_file.pdf" ), 1755971180000 , 3 ),
247298 RecentDocumentUiState (File (" /path/scan2.pdf" ), 1755000500000 , 1 )
0 commit comments