Split MainViewModel: extract HomeViewModel
This commit is contained in:
committed by
pynicolas
parent
7c53dcface
commit
d4a3c78c23
@@ -53,7 +53,7 @@ import org.fairscan.app.ui.Screen
|
||||
import org.fairscan.app.ui.components.rememberCameraPermissionState
|
||||
import org.fairscan.app.ui.screens.AboutScreen
|
||||
import org.fairscan.app.ui.screens.DocumentScreen
|
||||
import org.fairscan.app.ui.screens.HomeScreen
|
||||
import org.fairscan.app.ui.screens.home.HomeScreen
|
||||
import org.fairscan.app.ui.screens.LibrariesScreen
|
||||
import org.fairscan.app.ui.screens.camera.CameraEvent
|
||||
import org.fairscan.app.ui.screens.camera.CameraScreen
|
||||
@@ -61,6 +61,7 @@ import org.fairscan.app.ui.screens.camera.CameraViewModel
|
||||
import org.fairscan.app.ui.screens.export.ExportScreenWrapper
|
||||
import org.fairscan.app.ui.screens.export.ExportViewModel
|
||||
import org.fairscan.app.ui.screens.export.PdfGenerationActions
|
||||
import org.fairscan.app.ui.screens.home.HomeViewModel
|
||||
import org.fairscan.app.ui.theme.FairScanTheme
|
||||
import org.opencv.android.OpenCVLoader
|
||||
|
||||
@@ -72,6 +73,7 @@ class MainActivity : ComponentActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
initLibraries()
|
||||
val viewModel: MainViewModel by viewModels { MainViewModel.getFactory(this) }
|
||||
val homeViewModel: HomeViewModel by viewModels { HomeViewModel.getFactory(this) }
|
||||
val cameraViewModel: CameraViewModel by viewModels { CameraViewModel.getFactory(this) }
|
||||
val exportViewModel: ExportViewModel by viewModels { ExportViewModel.getFactory(this) }
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
@@ -91,7 +93,7 @@ class MainActivity : ComponentActivity() {
|
||||
val liveAnalysisState by cameraViewModel.liveAnalysisState.collectAsStateWithLifecycle()
|
||||
val document by viewModel.documentUiModel.collectAsStateWithLifecycle()
|
||||
val cameraPermission = rememberCameraPermissionState()
|
||||
val savePdf = { savePdf(exportViewModel.getFinalPdf(), viewModel, exportViewModel) }
|
||||
val savePdf = { savePdf(exportViewModel.getFinalPdf(), homeViewModel, exportViewModel) }
|
||||
val storagePermissionLauncher = rememberLauncherForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted ->
|
||||
@@ -114,7 +116,7 @@ class MainActivity : ComponentActivity() {
|
||||
)
|
||||
when (val screen = currentScreen) {
|
||||
is Screen.Main.Home -> {
|
||||
val recentDocs by viewModel.recentDocuments.collectAsStateWithLifecycle()
|
||||
val recentDocs by homeViewModel.recentDocuments.collectAsStateWithLifecycle()
|
||||
HomeScreen(
|
||||
cameraPermission = cameraPermission,
|
||||
currentDocument = document,
|
||||
@@ -210,7 +212,7 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
private fun savePdf(
|
||||
generatedPdf: GeneratedPdf?,
|
||||
viewModel: MainViewModel,
|
||||
homeViewModel: HomeViewModel,
|
||||
exportViewModel: ExportViewModel
|
||||
) {
|
||||
if (generatedPdf == null)
|
||||
@@ -220,7 +222,7 @@ class MainActivity : ComponentActivity() {
|
||||
appScope.launch {
|
||||
try {
|
||||
val targetFile = exportViewModel.saveFile(generatedPdf.file)
|
||||
viewModel.addRecentDocument(targetFile.absolutePath, generatedPdf.pageCount)
|
||||
homeViewModel.addRecentDocument(targetFile.absolutePath, generatedPdf.pageCount)
|
||||
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
MediaScannerConnection.scanFile(
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.fairscan.app
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@@ -31,16 +30,12 @@ import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.fairscan.app.data.ImageRepository
|
||||
import org.fairscan.app.data.recentDocumentsDataStore
|
||||
import org.fairscan.app.ui.NavigationState
|
||||
import org.fairscan.app.ui.Screen
|
||||
import org.fairscan.app.ui.state.DocumentUiModel
|
||||
import org.fairscan.app.ui.state.RecentDocumentUiState
|
||||
import java.io.File
|
||||
|
||||
class MainViewModel(
|
||||
private val imageRepository: ImageRepository,
|
||||
private val recentDocumentsDataStore: DataStore<RecentDocuments>,
|
||||
private val imageRepository: ImageRepository
|
||||
): ViewModel() {
|
||||
|
||||
companion object {
|
||||
@@ -48,10 +43,7 @@ class MainViewModel(
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
|
||||
val app = context.applicationContext as FairScanApp
|
||||
return MainViewModel(
|
||||
app.appContainer.imageRepository,
|
||||
context.recentDocumentsDataStore,
|
||||
) as T
|
||||
return MainViewModel(app.appContainer.imageRepository) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,41 +108,6 @@ class MainViewModel(
|
||||
return bytes?.let { BitmapFactory.decodeByteArray(it, 0, it.size) }
|
||||
}
|
||||
|
||||
val recentDocuments: StateFlow<List<RecentDocumentUiState>> =
|
||||
recentDocumentsDataStore.data.map {
|
||||
it.documentsList.map {
|
||||
doc ->
|
||||
RecentDocumentUiState(
|
||||
file = File(doc.filePath),
|
||||
saveTimestamp = doc.createdAt,
|
||||
pageCount = doc.pageCount,
|
||||
)
|
||||
}.filter { doc -> doc.file.exists() }
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5_000),
|
||||
initialValue = emptyList(),
|
||||
)
|
||||
fun addRecentDocument(filePath: String, pageCount: Int) {
|
||||
viewModelScope.launch {
|
||||
recentDocumentsDataStore.updateData { current ->
|
||||
val newDoc = RecentDocument.newBuilder()
|
||||
.setFilePath(filePath)
|
||||
.setPageCount(pageCount)
|
||||
.setCreatedAt(System.currentTimeMillis())
|
||||
.build()
|
||||
current.toBuilder()
|
||||
.addDocuments(0, newDoc)
|
||||
.also { builder ->
|
||||
while (builder.documentsCount > 3) {
|
||||
builder.removeDocuments(builder.documentsCount - 1)
|
||||
}
|
||||
}
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun handleImageCaptured(jpegBytes: ByteArray) {
|
||||
imageRepository.add(jpegBytes)
|
||||
_pageIds.value = imageRepository.imageIds()
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.fairscan.app.ui.screens
|
||||
package org.fairscan.app.ui.screens.home
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2025 Pierre-Yves Nicolas
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.fairscan.app.ui.screens.home
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.CreationExtras
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.fairscan.app.RecentDocument
|
||||
import org.fairscan.app.RecentDocuments
|
||||
import org.fairscan.app.data.recentDocumentsDataStore
|
||||
import org.fairscan.app.ui.state.RecentDocumentUiState
|
||||
import java.io.File
|
||||
|
||||
class HomeViewModel(private val recentDocumentsDataStore: DataStore<RecentDocuments>): ViewModel() {
|
||||
|
||||
companion object {
|
||||
fun getFactory(context: Context) = object : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
|
||||
return HomeViewModel(context.recentDocumentsDataStore) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val recentDocuments: StateFlow<List<RecentDocumentUiState>> =
|
||||
recentDocumentsDataStore.data.map {
|
||||
it.documentsList.map {
|
||||
doc ->
|
||||
RecentDocumentUiState(
|
||||
file = File(doc.filePath),
|
||||
saveTimestamp = doc.createdAt,
|
||||
pageCount = doc.pageCount,
|
||||
)
|
||||
}.filter { doc -> doc.file.exists() }
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5_000),
|
||||
initialValue = emptyList(),
|
||||
)
|
||||
fun addRecentDocument(filePath: String, pageCount: Int) {
|
||||
viewModelScope.launch {
|
||||
recentDocumentsDataStore.updateData { current ->
|
||||
val newDoc = RecentDocument.newBuilder()
|
||||
.setFilePath(filePath)
|
||||
.setPageCount(pageCount)
|
||||
.setCreatedAt(System.currentTimeMillis())
|
||||
.build()
|
||||
current.toBuilder()
|
||||
.addDocuments(0, newDoc)
|
||||
.also { builder ->
|
||||
while (builder.documentsCount > 3) {
|
||||
builder.removeDocuments(builder.documentsCount - 1)
|
||||
}
|
||||
}
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user