DocumentScreen: Button to start a new document

This commit is contained in:
Pierre-Yves Nicolas
2025-06-21 18:38:10 +02:00
parent 8ed04238fb
commit ff0c3c02e6
5 changed files with 73 additions and 8 deletions

View File

@@ -52,4 +52,11 @@ class ImageRepository(appFilesDir: File) {
file.delete() file.delete()
fileNames.remove(id) fileNames.remove(id)
} }
fun clear() {
fileNames.clear()
scanDir.listFiles()?.forEach {
file -> file.delete()
}
}
} }

View File

@@ -74,6 +74,9 @@ class MainActivity : ComponentActivity() {
toCameraScreen = { viewModel.navigateTo(Screen.Camera) }, toCameraScreen = { viewModel.navigateTo(Screen.Camera) },
onSavePressed = savePdf(viewModel, context), onSavePressed = savePdf(viewModel, context),
onSharePressed = sharePdf(viewModel, context), onSharePressed = sharePdf(viewModel, context),
onStartNew = {
viewModel.startNewDocument()
viewModel.navigateTo(Screen.Camera) },
onDeleteImage = { id -> viewModel.deletePage(id) } onDeleteImage = { id -> viewModel.deletePage(id) }
) )
} }

View File

@@ -135,6 +135,13 @@ class MainViewModel(
_pageIds.value = imageRepository.imageIds() _pageIds.value = imageRepository.imageIds()
} }
fun startNewDocument() {
_pageIds.value = listOf()
viewModelScope.launch {
imageRepository.clear()
}
}
fun pageCount(): Int = pageIds.value.size fun pageCount(): Int = pageIds.value.size
fun getBitmap(id: String): Bitmap? { fun getBitmap(id: String): Bitmap? {

View File

@@ -36,10 +36,11 @@ import androidx.compose.foundation.lazy.itemsIndexed
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.Add 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.Download
import androidx.compose.material.icons.filled.RestartAlt
import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.BottomAppBar import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@@ -50,6 +51,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallFloatingActionButton import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -57,6 +59,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableIntState import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -78,9 +81,11 @@ fun DocumentScreen(
toCameraScreen: () -> Unit, toCameraScreen: () -> Unit,
onSavePressed: () -> Unit, onSavePressed: () -> Unit,
onSharePressed: () -> Unit, onSharePressed: () -> Unit,
onStartNew: () -> Unit,
onDeleteImage: (String) -> Unit, onDeleteImage: (String) -> Unit,
) { ) {
// TODO Check how often images are loaded // TODO Check how often images are loaded
var showDialog = rememberSaveable { mutableStateOf(false) }
val currentPageIndex = rememberSaveable { mutableIntStateOf(0) } val currentPageIndex = rememberSaveable { mutableIntStateOf(0) }
if (currentPageIndex.intValue >= pageIds.size) { if (currentPageIndex.intValue >= pageIds.size) {
currentPageIndex.intValue = pageIds.size - 1 currentPageIndex.intValue = pageIds.size - 1
@@ -122,14 +127,19 @@ fun DocumentScreen(
} }
}, },
floatingActionButton = { floatingActionButton = {
FloatingActionButton(onClick = toCameraScreen) { FloatingActionButton(onClick = { showDialog.value = true }) {
Icon(Icons.Default.Close, contentDescription = "Close") 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 @Composable
@@ -171,13 +181,16 @@ private fun DocumentPreview(
} }
SmallFloatingActionButton( SmallFloatingActionButton(
onClick = { onDeleteImage(imageId) }, 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") Icon(imageVector = Icons.Outlined.Delete, contentDescription = "Delete page")
} }
Text("${currentPageIndex.value + 1} / ${pageIds.size}", Text("${currentPageIndex.value + 1} / ${pageIds.size}",
color = MaterialTheme.colorScheme.inverseOnSurface, color = MaterialTheme.colorScheme.inverseOnSurface,
modifier = Modifier.align(Alignment.BottomEnd) modifier = Modifier
.align(Alignment.BottomEnd)
.padding(all = 8.dp) .padding(all = 8.dp)
.background(MaterialTheme.colorScheme.inverseSurface.copy(alpha = 0.5f)) .background(MaterialTheme.colorScheme.inverseSurface.copy(alpha = 0.5f))
.padding(all = 4.dp) .padding(all = 4.dp)
@@ -238,6 +251,28 @@ private fun PageList(
} }
} }
@Composable
fun NewDocumentDialog(onConfirm: () -> Unit, showDialog: MutableState<Boolean>) {
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 @Composable
@Preview @Preview
fun DocumentScreenPreview() { fun DocumentScreenPreview() {
@@ -253,6 +288,7 @@ fun DocumentScreenPreview() {
toCameraScreen = {}, toCameraScreen = {},
onSavePressed = {}, onSavePressed = {},
onSharePressed = {}, onSharePressed = {},
onStartNew = {},
onDeleteImage = { _ -> {} } onDeleteImage = { _ -> {} }
) )
} }

View File

@@ -77,4 +77,16 @@ class ImageRepositoryTest {
assertThat(repo.imageIds()).isEmpty() assertThat(repo.imageIds()).isEmpty()
assertThat(repo.getContent("x")).isNull() assertThat(repo.getContent("x")).isNull()
} }
@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()
}
} }