From ff0c3c02e6e1224d1d8d0616874b211b2c8ae13f Mon Sep 17 00:00:00 2001 From: Pierre-Yves Nicolas <6371790+pynicolas@users.noreply.github.com> Date: Sat, 21 Jun 2025 18:38:10 +0200 Subject: [PATCH] DocumentScreen: Button to start a new document --- .../org/mydomain/myscan/ImageRepository.kt | 9 +++- .../java/org/mydomain/myscan/MainActivity.kt | 3 ++ .../java/org/mydomain/myscan/MainViewModel.kt | 7 +++ .../mydomain/myscan/view/DocumentScreen.kt | 48 ++++++++++++++++--- .../mydomain/myscan/ImageRepositoryTest.kt | 14 +++++- 5 files changed, 73 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/mydomain/myscan/ImageRepository.kt b/app/src/main/java/org/mydomain/myscan/ImageRepository.kt index 882e3e1..f2bfaf2 100644 --- a/app/src/main/java/org/mydomain/myscan/ImageRepository.kt +++ b/app/src/main/java/org/mydomain/myscan/ImageRepository.kt @@ -52,4 +52,11 @@ class ImageRepository(appFilesDir: File) { file.delete() fileNames.remove(id) } -} \ No newline at end of file + + fun clear() { + fileNames.clear() + scanDir.listFiles()?.forEach { + file -> file.delete() + } + } +} diff --git a/app/src/main/java/org/mydomain/myscan/MainActivity.kt b/app/src/main/java/org/mydomain/myscan/MainActivity.kt index bb299c3..dd71619 100644 --- a/app/src/main/java/org/mydomain/myscan/MainActivity.kt +++ b/app/src/main/java/org/mydomain/myscan/MainActivity.kt @@ -74,6 +74,9 @@ class MainActivity : ComponentActivity() { toCameraScreen = { viewModel.navigateTo(Screen.Camera) }, onSavePressed = savePdf(viewModel, context), onSharePressed = sharePdf(viewModel, context), + onStartNew = { + viewModel.startNewDocument() + viewModel.navigateTo(Screen.Camera) }, onDeleteImage = { id -> viewModel.deletePage(id) } ) } diff --git a/app/src/main/java/org/mydomain/myscan/MainViewModel.kt b/app/src/main/java/org/mydomain/myscan/MainViewModel.kt index 78383e3..2a81946 100644 --- a/app/src/main/java/org/mydomain/myscan/MainViewModel.kt +++ b/app/src/main/java/org/mydomain/myscan/MainViewModel.kt @@ -135,6 +135,13 @@ class MainViewModel( _pageIds.value = imageRepository.imageIds() } + fun startNewDocument() { + _pageIds.value = listOf() + viewModelScope.launch { + imageRepository.clear() + } + } + fun pageCount(): Int = pageIds.value.size fun getBitmap(id: String): Bitmap? { diff --git a/app/src/main/java/org/mydomain/myscan/view/DocumentScreen.kt b/app/src/main/java/org/mydomain/myscan/view/DocumentScreen.kt index 8ad0cb3..b7d3084 100644 --- a/app/src/main/java/org/mydomain/myscan/view/DocumentScreen.kt +++ b/app/src/main/java/org/mydomain/myscan/view/DocumentScreen.kt @@ -36,10 +36,11 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Add -import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Download +import androidx.compose.material.icons.filled.RestartAlt import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.outlined.Delete +import androidx.compose.material3.AlertDialog import androidx.compose.material3.BottomAppBar import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api @@ -50,6 +51,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SmallFloatingActionButton import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable @@ -57,6 +59,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableIntState import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -78,9 +81,11 @@ fun DocumentScreen( toCameraScreen: () -> Unit, onSavePressed: () -> Unit, onSharePressed: () -> Unit, + onStartNew: () -> Unit, onDeleteImage: (String) -> Unit, ) { // TODO Check how often images are loaded + var showDialog = rememberSaveable { mutableStateOf(false) } val currentPageIndex = rememberSaveable { mutableIntStateOf(0) } if (currentPageIndex.intValue >= pageIds.size) { currentPageIndex.intValue = pageIds.size - 1 @@ -122,14 +127,19 @@ fun DocumentScreen( } }, floatingActionButton = { - FloatingActionButton(onClick = toCameraScreen) { - Icon(Icons.Default.Close, contentDescription = "Close") + FloatingActionButton(onClick = { showDialog.value = true }) { + Icon(Icons.Default.RestartAlt, contentDescription = "Close") } } ) } } - ) { padding -> DocumentPreview(pageIds, imageLoader, currentPageIndex, onDeleteImage, padding) } + ) { padding -> + DocumentPreview(pageIds, imageLoader, currentPageIndex, onDeleteImage, padding) + if (showDialog.value) { + NewDocumentDialog(onConfirm = onStartNew, showDialog) + } + } } @Composable @@ -171,13 +181,16 @@ private fun DocumentPreview( } SmallFloatingActionButton( onClick = { onDeleteImage(imageId) }, - modifier = Modifier.align(Alignment.TopEnd).padding(4.dp) + modifier = Modifier + .align(Alignment.TopEnd) + .padding(4.dp) ) { Icon(imageVector = Icons.Outlined.Delete, contentDescription = "Delete page") } Text("${currentPageIndex.value + 1} / ${pageIds.size}", color = MaterialTheme.colorScheme.inverseOnSurface, - modifier = Modifier.align(Alignment.BottomEnd) + modifier = Modifier + .align(Alignment.BottomEnd) .padding(all = 8.dp) .background(MaterialTheme.colorScheme.inverseSurface.copy(alpha = 0.5f)) .padding(all = 4.dp) @@ -238,6 +251,28 @@ private fun PageList( } } +@Composable +fun NewDocumentDialog(onConfirm: () -> Unit, showDialog: MutableState) { + AlertDialog( + title = { Text("New document") }, + text = { Text("The current document will be lost if you haven't saved it. Do you want to continue?") }, + confirmButton = { + TextButton (onClick = { + showDialog.value = false + onConfirm() + }) { + Text("Yes") + } + }, + dismissButton = { + TextButton(onClick = { showDialog.value = false }) { + Text("Cancel") + } + }, + onDismissRequest = { showDialog.value = false }, + ) +} + @Composable @Preview fun DocumentScreenPreview() { @@ -253,6 +288,7 @@ fun DocumentScreenPreview() { toCameraScreen = {}, onSavePressed = {}, onSharePressed = {}, + onStartNew = {}, onDeleteImage = { _ -> {} } ) } diff --git a/app/src/test/java/org/mydomain/myscan/ImageRepositoryTest.kt b/app/src/test/java/org/mydomain/myscan/ImageRepositoryTest.kt index 0b81e6a..0540d52 100644 --- a/app/src/test/java/org/mydomain/myscan/ImageRepositoryTest.kt +++ b/app/src/test/java/org/mydomain/myscan/ImageRepositoryTest.kt @@ -77,4 +77,16 @@ class ImageRepositoryTest { assertThat(repo.imageIds()).isEmpty() assertThat(repo.getContent("x")).isNull() } -} \ No newline at end of file + + @Test + fun `clear should delete pages`() { + val bytes = byteArrayOf(101, 102, 103) + val repo1 = repo() + repo1.add(bytes) + assertThat(repo1.imageIds()).isNotEmpty() + repo1.clear() + assertThat(repo1.imageIds()).isEmpty() + val repo2 = repo() + assertThat(repo2.imageIds()).isEmpty() + } +}