From 215f57bb7454d61543415537004519e6546ea931 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Nicolas <6371790+pynicolas@users.noreply.github.com> Date: Wed, 1 Apr 2026 10:17:57 +0200 Subject: [PATCH] Avoid resolution of current page in DocumentScreen --- .../java/org/fairscan/app/MainActivity.kt | 7 ++- .../java/org/fairscan/app/MainViewModel.kt | 32 ++++++++----- .../app/ui/screens/document/DocumentScreen.kt | 45 +++++++++---------- .../ui/screens/document/DocumentUiState.kt | 7 +-- .../fairscan/app/ui/state/DocumentUiModel.kt | 3 -- 5 files changed, 49 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/org/fairscan/app/MainActivity.kt b/app/src/main/java/org/fairscan/app/MainActivity.kt index 59e63c0..950d304 100644 --- a/app/src/main/java/org/fairscan/app/MainActivity.kt +++ b/app/src/main/java/org/fairscan/app/MainActivity.kt @@ -62,7 +62,6 @@ import org.fairscan.app.ui.screens.about.createEmailWithImageIntent import org.fairscan.app.ui.screens.camera.CameraEvent import org.fairscan.app.ui.screens.camera.CameraScreen import org.fairscan.app.ui.screens.camera.CameraViewModel -import org.fairscan.app.ui.screens.document.DocumentUiState import org.fairscan.app.ui.screens.export.ExportActions import org.fairscan.app.ui.screens.export.ExportEvent import org.fairscan.app.ui.screens.export.ExportResult @@ -182,9 +181,9 @@ class MainActivity : ComponentActivity() { uiState = documentUiState, navigation = navigation, onExportClick = onExportClick, - onDeleteImage = { id -> viewModel.deletePage(id) }, - onRotateImage = { id, clockwise -> viewModel.rotateImage(id, clockwise) }, - onToggleColorMode = { id -> viewModel.togglePageColorMode(id) }, + onDeleteImage = { viewModel.deleteCurrentPage() }, + onRotateImage = { clockwise -> viewModel.rotateCurrentPage(clockwise) }, + onToggleColorMode = { viewModel.toggleCurrentPageColorMode() }, onPageReorder = { id, newIndex -> viewModel.movePage(id, newIndex) }, onPageSelected = viewModel::onPageSelected ) diff --git a/app/src/main/java/org/fairscan/app/MainViewModel.kt b/app/src/main/java/org/fairscan/app/MainViewModel.kt index 9b683dd..cf2c36c 100644 --- a/app/src/main/java/org/fairscan/app/MainViewModel.kt +++ b/app/src/main/java/org/fairscan/app/MainViewModel.kt @@ -14,7 +14,6 @@ */ package org.fairscan.app -import android.graphics.Bitmap import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.collections.immutable.persistentListOf @@ -43,6 +42,7 @@ import org.fairscan.app.ui.screens.document.DocumentUiState import org.fairscan.app.ui.state.DocumentUiModel import org.fairscan.app.ui.state.PageThumbnail import org.fairscan.imageprocessing.ColorMode +import java.lang.IllegalStateException import kotlin.math.min @OptIn(ExperimentalCoroutinesApi::class) @@ -77,15 +77,16 @@ class MainViewModel(val imageRepository: ImageRepository, launchMode: LaunchMode private val _currentPageIndex = MutableStateFlow(0) - val currentPageUiState: Flow = + private val currentPageUiState: Flow = combine(_currentPageIndex, _pages) { index, pages -> pages.getOrNull(index) } .mapLatest { page -> page?.let { CurrentPageUiState( + page.id, imageRepository.jpegBytes(it.key())?.toBitmap(), page.colorMode ) - } ?: CurrentPageUiState() + } } .flowOn(Dispatchers.IO) @@ -95,7 +96,7 @@ class MainViewModel(val imageRepository: ImageRepository, launchMode: LaunchMode } .stateIn( viewModelScope, SharingStarted.Eagerly, - DocumentUiState(0, CurrentPageUiState(), DocumentUiModel()) + DocumentUiState(0, null, DocumentUiModel()) ) fun onPageSelected(index: Int) { @@ -116,10 +117,10 @@ class MainViewModel(val imageRepository: ImageRepository, launchMode: LaunchMode _navigationState.update { stack -> stack.navigateBack() } } - fun rotateImage(id: String, clockwise: Boolean) { + fun rotateCurrentPage(clockwise: Boolean) { viewModelScope.launch { val pages = withContext(Dispatchers.IO) { - imageRepository.rotate(id, clockwise) + imageRepository.rotate(currentPage().id, clockwise) imageRepository.pages() } _pages.value = pages @@ -136,10 +137,10 @@ class MainViewModel(val imageRepository: ImageRepository, launchMode: LaunchMode } } - fun deletePage(id: String) { + fun deleteCurrentPage() { viewModelScope.launch { val pages = withContext(Dispatchers.IO) { - imageRepository.delete(id) + imageRepository.delete(currentPage().id) imageRepository.pages() } @@ -153,14 +154,14 @@ class MainViewModel(val imageRepository: ImageRepository, launchMode: LaunchMode } } - fun togglePageColorMode(id: String) { + fun toggleCurrentPageColorMode() { viewModelScope.launch { - val currentColorMode = _pages.value.find { p -> p.id == id }?.colorMode - currentColorMode?.let { + val currentPage = currentPage() + currentPage.colorMode?.let { val newColorMode = if (it == ColorMode.COLOR) ColorMode.GRAYSCALE else ColorMode.COLOR val pages = withContext(Dispatchers.IO) { - imageRepository.setColorMode(id, newColorMode) + imageRepository.setColorMode(currentPage.id, newColorMode) imageRepository.pages() } _pages.value = pages @@ -168,6 +169,13 @@ class MainViewModel(val imageRepository: ImageRepository, launchMode: LaunchMode } } + private fun currentPage(): ScanPage { + val index = _currentPageIndex.value + val pages = _pages.value + return pages.getOrNull(index) ?: throw IllegalStateException( + "No current page for index $index (${pages.size} pages)") + } + fun startNewDocument() { _pages.value = persistentListOf() viewModelScope.launch { diff --git a/app/src/main/java/org/fairscan/app/ui/screens/document/DocumentScreen.kt b/app/src/main/java/org/fairscan/app/ui/screens/document/DocumentScreen.kt index 24c2cb0..1c4f9fa 100644 --- a/app/src/main/java/org/fairscan/app/ui/screens/document/DocumentScreen.kt +++ b/app/src/main/java/org/fairscan/app/ui/screens/document/DocumentScreen.kt @@ -86,9 +86,9 @@ fun DocumentScreen( uiState: DocumentUiState, navigation: Navigation, onExportClick: () -> Unit, - onDeleteImage: (String) -> Unit, - onRotateImage: (String, Boolean) -> Unit, - onToggleColorMode: (String) -> Unit, + onDeleteImage: () -> Unit, + onRotateImage: (Boolean) -> Unit, + onToggleColorMode: () -> Unit, onPageReorder: (String, Int) -> Unit, onPageSelected: (Int) -> Unit, ) { @@ -130,7 +130,7 @@ fun DocumentScreen( title = stringResource(R.string.delete_page), message = stringResource(R.string.delete_page_warning), showDialog = showDeletePageDialog - ) { onDeleteImage(document.pageId(currentPageIndex)) } + ) { onDeleteImage() } } } } @@ -138,14 +138,13 @@ fun DocumentScreen( @Composable private fun DocumentPreview( uiState: DocumentUiState, - onDeleteImage: (String) -> Unit, - onRotateImage: (String, Boolean) -> Unit, - onToggleColorMode: (String) -> Unit, + onDeleteImage: () -> Unit, + onRotateImage: (Boolean) -> Unit, + onToggleColorMode: () -> Unit, modifier: Modifier, ) { val currentPageIndex = uiState.currentPageIndex val document = uiState.document - val imageId = document.pageId(currentPageIndex) Column ( modifier = modifier .background(MaterialTheme.colorScheme.surfaceContainerLow) @@ -153,10 +152,11 @@ private fun DocumentPreview( Box ( modifier = Modifier.fillMaxSize() ) { - val bitmap = uiState.currentPage.bitmap - if (bitmap != null) { + val bitmap = uiState.currentPage?.bitmap + val pageId = uiState.currentPage?.id + if (bitmap != null && pageId != null) { val imageBitmap = bitmap.asImageBitmap() - val zoomState = remember(imageId) { + val zoomState = remember(pageId) { ZoomState( contentSize = Size(bitmap.width.toFloat(), bitmap.height.toFloat()) ) @@ -175,20 +175,20 @@ private fun DocumentPreview( ) } } - uiState.currentPage.colorMode?.let { + uiState.currentPage?.colorMode?.let { ColorModeButton( currentColorMode = it, - onToggle = { onToggleColorMode(imageId) }, + onToggle = { onToggleColorMode() }, modifier = Modifier .align(Alignment.BottomStart) .padding(8.dp) ) } - RotationButtons(imageId, onRotateImage, Modifier.align(Alignment.BottomCenter)) + RotationButtons(onRotateImage, Modifier.align(Alignment.BottomCenter)) SecondaryActionButton( Icons.Outlined.Delete, contentDescription = stringResource(R.string.delete_page), - onClick = { onDeleteImage(imageId) }, + onClick = { onDeleteImage() }, modifier = Modifier .align(Alignment.BottomEnd) .padding(8.dp) @@ -210,8 +210,7 @@ private fun DocumentPreview( @Composable fun RotationButtons( - imageId: String, - onRotateImage: (String, Boolean) -> Unit, + onRotateImage: (Boolean) -> Unit, modifier: Modifier = Modifier ) { // RotateLeft on the left, RotateRight on the right: for both LTR and RTL languages @@ -222,14 +221,14 @@ fun RotationButtons( SecondaryActionButton( icon = Icons.Default.RotateLeft, contentDescription = stringResource(R.string.rotate_left), - onClick = { onRotateImage(imageId, false) } + onClick = { onRotateImage(false) } ) Spacer(Modifier.width(8.dp)) @Suppress("DEPRECATION") SecondaryActionButton( icon = Icons.Default.RotateRight, contentDescription = stringResource(R.string.rotate_right), - onClick = { onRotateImage(imageId, true) } + onClick = { onRotateImage(true) } ) } } @@ -307,12 +306,12 @@ fun DocumentScreenPreview() { LocalContext.current ) DocumentScreen( - uiState = DocumentUiState(1, CurrentPageUiState(image, COLOR), document), + uiState = DocumentUiState(1, CurrentPageUiState("123",image, COLOR), document), navigation = dummyNavigation(), onExportClick = {}, - onDeleteImage = { _ -> }, - onRotateImage = { _,_ -> }, - onToggleColorMode = { _ -> }, + onDeleteImage = { }, + onRotateImage = { _ -> }, + onToggleColorMode = { }, onPageReorder = { _,_ -> }, onPageSelected = { _ -> }, ) diff --git a/app/src/main/java/org/fairscan/app/ui/screens/document/DocumentUiState.kt b/app/src/main/java/org/fairscan/app/ui/screens/document/DocumentUiState.kt index 7c5ea6d..086633c 100644 --- a/app/src/main/java/org/fairscan/app/ui/screens/document/DocumentUiState.kt +++ b/app/src/main/java/org/fairscan/app/ui/screens/document/DocumentUiState.kt @@ -20,11 +20,12 @@ import org.fairscan.imageprocessing.ColorMode data class DocumentUiState( val currentPageIndex: Int, - val currentPage: CurrentPageUiState, + val currentPage: CurrentPageUiState?, val document: DocumentUiModel, ) data class CurrentPageUiState( - val bitmap: Bitmap? = null, - val colorMode: ColorMode? = null, + val id: String, + val bitmap: Bitmap?, + val colorMode: ColorMode?, ) diff --git a/app/src/main/java/org/fairscan/app/ui/state/DocumentUiModel.kt b/app/src/main/java/org/fairscan/app/ui/state/DocumentUiModel.kt index 93a69e3..1a47814 100644 --- a/app/src/main/java/org/fairscan/app/ui/state/DocumentUiModel.kt +++ b/app/src/main/java/org/fairscan/app/ui/state/DocumentUiModel.kt @@ -25,9 +25,6 @@ data class DocumentUiModel( fun pageCount(): Int { return pages.size } - fun pageId(index: Int): String { - return pages[index].key.pageId - } fun isEmpty(): Boolean { return pages.isEmpty() }