Ability to delete one of the scanned pages
This commit is contained in:
@@ -33,4 +33,9 @@ class ImageRepository(appFilesDir: File) {
|
|||||||
throw IllegalArgumentException("No image for id: $id")
|
throw IllegalArgumentException("No image for id: $id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun delete(id: String) {
|
||||||
|
val file = File(scanDir, id)
|
||||||
|
file.delete()
|
||||||
|
fileNames.remove(id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -116,6 +116,11 @@ class MainViewModel(
|
|||||||
_pageIds.value = imageRepository.imageIds()
|
_pageIds.value = imageRepository.imageIds()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deletePage(id: String) {
|
||||||
|
imageRepository.delete(id)
|
||||||
|
_pageIds.value = imageRepository.imageIds()
|
||||||
|
}
|
||||||
|
|
||||||
fun pageCount(): Int = pageIds.value.size
|
fun pageCount(): Int = pageIds.value.size
|
||||||
|
|
||||||
fun getBitmap(id: String): Bitmap {
|
fun getBitmap(id: String): Bitmap {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package org.mydomain.myscan.view
|
package org.mydomain.myscan.view
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
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.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
@@ -14,10 +16,12 @@ 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.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.verticalScroll
|
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
|
||||||
@@ -35,7 +39,6 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
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.layout.ContentScale
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
@@ -49,7 +52,6 @@ fun FinalizeDocumentScreen(
|
|||||||
onSavePressed: () -> Unit,
|
onSavePressed: () -> Unit,
|
||||||
onSharePressed: () -> Unit,
|
onSharePressed: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val pageIds by viewModel.pageIds.collectAsStateWithLifecycle()
|
|
||||||
Scaffold (
|
Scaffold (
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
@@ -80,18 +82,27 @@ fun FinalizeDocumentScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) { padding ->
|
) { padding -> DocumentPreview(padding, viewModel) }
|
||||||
Column(modifier = Modifier
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DocumentPreview(
|
||||||
|
padding: PaddingValues,
|
||||||
|
viewModel: MainViewModel
|
||||||
|
) {
|
||||||
|
val pageIds by viewModel.pageIds.collectAsStateWithLifecycle()
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(padding)) {
|
.padding(padding)
|
||||||
|
) {
|
||||||
Text(
|
Text(
|
||||||
"Pages",
|
"Pages",
|
||||||
modifier = Modifier.padding(start = 16.dp, top = 16.dp),
|
modifier = Modifier.padding(start = 16.dp, top = 16.dp),
|
||||||
style = MaterialTheme.typography.titleMedium
|
style = MaterialTheme.typography.titleMedium
|
||||||
)
|
)
|
||||||
FlowRow (
|
FlowRow(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
@@ -100,16 +111,28 @@ fun FinalizeDocumentScreen(
|
|||||||
) {
|
) {
|
||||||
pageIds.forEachIndexed { index, id ->
|
pageIds.forEachIndexed { index, id ->
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
// TODO Display small images rather than big ones
|
||||||
|
// TODO Make it possible to zoom on an image
|
||||||
|
Box {
|
||||||
Image(
|
Image(
|
||||||
bitmap = viewModel.getBitmap(id).asImageBitmap(),
|
bitmap = viewModel.getBitmap(id).asImageBitmap(),
|
||||||
contentDescription = "Page ${index + 1}",
|
contentDescription = "Page ${index + 1}",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(160.dp)
|
.size(160.dp)
|
||||||
|
.padding(4.dp)
|
||||||
.clip(RoundedCornerShape(8.dp))
|
.clip(RoundedCornerShape(8.dp))
|
||||||
.border(1.dp, Color.DarkGray, RoundedCornerShape(8.dp)),
|
.border(1.dp, Color.DarkGray)
|
||||||
contentScale = ContentScale.Fit
|
|
||||||
)
|
)
|
||||||
Text("Page ${index + 1}")
|
|
||||||
|
IconButton(
|
||||||
|
onClick = { viewModel.deletePage(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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,18 @@ class ImageRepositoryTest {
|
|||||||
assertThat(repo.getContent(repo.imageIds()[0])).isEqualTo(bytes)
|
assertThat(repo.getContent(repo.imageIds()[0])).isEqualTo(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun delete_image() {
|
||||||
|
val repo = repo()
|
||||||
|
val bytes = byteArrayOf(101, 102, 103)
|
||||||
|
repo.add(bytes)
|
||||||
|
assertThat(repo.imageIds()).hasSize(1)
|
||||||
|
repo.delete(repo.imageIds()[0])
|
||||||
|
assertThat(repo.imageIds()).isEmpty()
|
||||||
|
val repo2 = repo()
|
||||||
|
assertThat(repo2.imageIds()).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `should find existing files at initialization`() {
|
fun `should find existing files at initialization`() {
|
||||||
val bytes = byteArrayOf(101, 102, 103)
|
val bytes = byteArrayOf(101, 102, 103)
|
||||||
|
|||||||
Reference in New Issue
Block a user